我必须在我的程序中实现基本加密。我可以使用Base64它被客户拒绝了。所以我使用以下方法。我面临的问题是加密中有特殊字符会导致异常。我可以更改此代码以某种方式加密成纯文本而无需特殊字符。
protected static byte[] encrypt(String text)
{
try
{
String key = "6589745268754125";
// Create key and cipher
Key aesKey = new SecretKeySpec(key.getBytes(), "AES");
Cipher cipher = Cipher.getInstance("AES");
// encrypt the text
cipher.init(Cipher.ENCRYPT_MODE, aesKey);
byte[] encrypted = cipher.doFinal(text.getBytes());
return encrypted;
}
catch(Exception ex)
{
WriteLog("Encryption Failed");
WriteLog(ex.getMessage());
return null;
}
}
protected static String decrypt(byte[] pass)
{
try
{
String key = "6589745268754125";
// Create key and cipher
Key aesKey = new SecretKeySpec(key.getBytes(), "AES");
Cipher cipher = Cipher.getInstance("AES");
// decrypt the text
cipher.init(Cipher.DECRYPT_MODE, aesKey);
String decrypted = new String(cipher.doFinal(pass));
return decrypted;
}
catch(Exception ex)
{
WriteLog("Encryption Failed");
WriteLog(ex.getMessage());
return null;
}
}
异常消息显示“给定最终块未正确填充” javax.crypto.BadPaddingException:给定最终块未正确填充
答案 0 :(得分:1)
如果客户端不喜欢Base64,请尝试Base32或Base16(= hex)。它们不常见但是定义为Base64的替代品。
您可能还会找到客户端不希望您使用Base64的确切原因。
答案 1 :(得分:1)
所以,基本上你不了解加密并且遇到客户想要加密的问题
好的,快速抬头:编码:将输入转换为输出,该输出保存相同的信息但在另一种表示中...例如:1,2,3 - > A,B,C
正如您所看到的那样,输出看起来不同,但保留了相同的信息
请注意,编码/解码不需要任何秘密信息
加密:乍一看可能看起来很相似,但在这里你需要一些秘密...加密需要2个输入...一个秘密和输入数据
结果输出可以解密,但只有你有相应的秘密
如果您的客户希望您加密某些内容,请确保该内容可以表示为字节...加密字符串...不好...加密已转换为<在这里插入任意字节编码,例如unicode> ......好的
加密通常处理字节(让我们不关心历史密码)
当您决定使用加密/密码时,您必须知道基本上有2个不同的组:symetric和asymetric
symetric:解密需要用于加密的相同密钥(读取密钥)
不对称:密钥对由公共部分和私有部分(公钥/私钥)组成,公共部分用于加密,私有部分用于解密...除非你有不同的方需要,否则没有意义交换钥匙
不对称密码通常用于加密解密对称密码的密钥,因为它们是SLOW而对称密码通常是快速的
不对称密码不用于加密大量数据
symetric密码适用于批量数据
如果您的目标只是在硬盘上放置信息时加密信息,那么您可以使用对称密码
你需要一个密钥才能使密码运行......并且......你将有问题在哪里存储...所以如果可以,让用户输入一个足够复杂的密码...使用密码和一个名为PBKDF2的函数具有足够高的迭代次数(足够高=增加此数字,直到该过程需要几秒钟,如果您在启动时只需要这个,或者直到您的用户开始抱怨延迟)才能生成二进制密钥密码。
在GCM模式下使用此密钥进行AES(对称密码)
密码将需要一个名为IV或初始化向量的东西......
iv并不是秘密,你可以将这个东西作为明文信息添加到你的密文中 iv需要是密码的一个块的大小,因此在AES 128位= 16字节的情况下 所以加密时你的IV是一个16字节(唯一)的随机数(意味着你可能不会使用IV两次或更多次:坚持使用过的IV,当得到一个新的时,检查它是否已经存储,如果是,则启动IV生成,如果没有,存储它然后使用它)
解密时,从文件中读取前置的明文IV(前16个字节)
如果您只想将密文存储在磁盘上,请将其写入二进制文件
如果文件必须只包含可打印文本,则在将字节写入文件之前应用base16 / 32/64之类的编码,并在解密前解码为字节数组(除非您的数据太大,否则您将拥有查找/编写将为您添加/剥离编码的流包装器
答案 2 :(得分:0)
你应该Base64加密的内容。顺便说一句,这是通常的技术。
我猜客户端的问题不是Base64格式本身,而是事实上,Base64不是(强大的)加密。
答案 3 :(得分:0)
问题是填充。我使用AES/CBC/NoPadding
并确保我的字符串是16个字节的倍数。所以除了改变ecryption和解密之外我还要添加两种方法。一个是将\0
,即隐式空终止符添加到文本的结尾,使其成为16的倍数,另一个是在解密后删除它们。所以最终版本是这样的。
public class crypto {
static String IV = "AAAAAAAAAAAAAAAA";
static String plaintext = "my non padded text";
static String encryptionKey = "0123456789abcdef";
public static void main(String[] args)
{
byte[] cipher = encrypt(plaintext);
String decrypted = decrypt(cipher);
}
protected static String covertto16Byte(String plainText)
{
while(plainText.length()%16 != 0)
plainText += "\0";
return plainText;
}
protected static String removePadding(String plainText)
{
return plainText.replace("\0","");
}
protected static byte[] encrypt(String plainText)
{
try
{
String _plaintText_16 = covertto16Byte(plainText);
Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding", "SunJCE");
SecretKeySpec key = new SecretKeySpec(encryptionKey.getBytes("UTF-8"), "AES");
cipher.init(Cipher.ENCRYPT_MODE, key,new IvParameterSpec(IV.getBytes("UTF-8")));
return cipher.doFinal(_plaintText_16.getBytes("UTF-8"));
} catch (Exception ex)
{
//catch mechanism
return null;
}
}
protected static String decrypt(byte[] cipherText)
{
try
{
Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding", "SunJCE");
SecretKeySpec key = new SecretKeySpec(encryptionKey.getBytes("UTF-8"), "AES");
cipher.init(Cipher.DECRYPT_MODE, key,new IvParameterSpec(IV.getBytes("UTF-8")));
return removePadding(new String(cipher.doFinal(cipherText), "UTF-8"));
} catch (Exception ex)
{
//catch mechanism
return null;
}
}
}