我在下面的代码中得到了一个例外,用于java中的AES算法.
代码解密加密的字符串并返回原始字符串.
Plz帮助我解决这个问题.
码:
public class AES
{
public byte[] encrypted;
public byte[] original;
public String originalString;
public static String asHex (byte buf[])
{
StringBuffer strbuf = new StringBuffer(buf.length * 2);
int i; for (i = 0; i < buf.length; i++)
{
if (((int) buf[i] & 0xff) < 0x10) strbuf.append("0");
strbuf.append(Long.toString((int) buf[i] & 0xff, 16));
}
return strbuf.toString();
}
public String AESencryptalgo(byte[] text)
{
String newtext="";
// Get the KeyGenerator
try
{
KeyGenerator kgen = KeyGenerator.getInstance("AES");
kgen.init(128); // 192 and 256 bits may not be available
// Generate the secret key specs.
SecretKey skey = kgen.generateKey();
byte[] raw = skey.getEncoded();
SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
// Instantiate the cipher Cipher cipher = Cipher.getInstance("AES");
cipher.init(Cipher.ENCRYPT_MODE, skeySpec); encrypted = cipher.doFinal(text);
System.out.println("encrypted string: " + asHex(encrypted));
cipher.init(Cipher.DECRYPT_MODE, skeySpec); original = cipher.doFinal(encrypted);
originalString = new String(original); System.out.println("Original string: " + originalString + " " + asHex(original));
}
catch(Exception e)
{ }
finally
{
newtext=new String(encrypted);
System.out.println("ENCRYPTED "+newtext);
//AESdecryptalgo(newtext.getBytes());
return newtext;
}
}
public String AESdecryptalgo(byte[] text)
{
// Get the KeyGenerator
try
{
KeyGenerator kgen = KeyGenerator.getInstance("AES");
kgen.init(128); // 192 and 256 bits may not be available
// Generate the secret key specs.
SecretKey skey = kgen.generateKey();
byte[] raw = skey.getEncoded();
SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
// Instantiate the cipher
Cipher cipher = Cipher.getInstance("AES");
cipher.init(Cipher.DECRYPT_MODE, skeySpec);
original = cipher.doFinal(text); //Exception occurs here
originalString = new String(original);
System.out.println("Original string: " + originalString + " " + asHex(original));
}
catch(Exception e)
{
System.out.println("exception");
}
finally
{
System.out.println("DECRYPTED "+originalString);
return originalString;
}
}
public static void main(String[] args)
{
AES a=new AES();
a.AESencryptalgo("hello".getBytes());
System.out.println();
}}
`
Run Code Online (Sandbox Code Playgroud)
例外:
javax.crypto.BadPaddingException: Given final block not properly padded at
com.sun.crypto.provider.SunJCE_f.b(DashoA13*..) at
com.sun.crypto.provider.SunJCE_f.b(DashoA13*..) at
com.sun.crypto.provider.AESCipher.engineDoFinal(DashoA13*..) at
javax.crypto.Cipher.doFinal(DashoA13*..)
Run Code Online (Sandbox Code Playgroud)
Ada*_*ter 14
According to Java™ Cryptography Architecture (JCA) Reference Guide (emphasis mine):
Cipherobjects are obtained by using one of theCipher getInstance()static factory methods. Here, the algorithm name is slightly different than with other engine classes, in that it specifies not just an algorithm name, but a "transformation". A transformation is a string that describes the operation (or set of operations) to be performed on the given input to produce some output. A transformation always includes the name of a cryptographic algorithm (e.g.,DES), and may be followed by a mode and padding scheme.A transformation is of the form:
- "algorithm/mode/padding" or
- "algorithm"
例如,以下是有效的转换:
"DES/CBC/PKCS5Padding""DES"如果只指定了转换名称,系统将确定环境中是否存在所请求转换的实现,如果有多个,则返回优先级.
如果同时指定了转换名称和包提供程序,系统将确定所请求的包中是否存在请求的转换的实现,如果没有则抛出异常.
如果未指定模式或填充,则使用模式和填充方案的特定于提供程序的默认值. 例如,
SunJCE提供者使用ECB作为默认模式,并且PKCS5Padding作为默认填充方案DES,DES-EDE和Blowfish密码.这意味着在SunJCE提供者的情况下:Run Code Online (Sandbox Code Playgroud)Cipher c1 = Cipher.getInstance("DES/ECB/PKCS5Padding");和
Run Code Online (Sandbox Code Playgroud)Cipher c1 = Cipher.getInstance("DES");是等同的陈述.
使用CFB和OFB等模式,分组密码可以以小于密码实际块大小的单位加密数据.请求此类模式时,您可以选择通过将此数字附加到模式名称来指定一次要处理的位数,如" DES/CFB8/NoPadding "和" DES/OFB32/PKCS5Padding "转换中所示.如果未指定此类数字,则使用特定于提供程序的默认值.(例如,
SunJCE提供程序对DES使用默认的64位.)因此,可以使用8位模式(如CFB8或OFB8)将块密码转换为面向字节的流密码.本文档的附录A包含标准名称列表,可用于指定转换的算法名称,模式和填充方案组件.
工厂方法返回的对象未初始化,必须在它们可用之前进行初始化.
由于您的代码未指定模式或填充,因此正在使用特定于提供程序的默认值.看来你的提供商是SunJCE,它的默认填充可能是"NoPadding".使用此填充,您负责确保加密的字节数组的大小是密钥中字节数的倍数.通过在转换中指定模式和填充,可以让您的生活更轻松:
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
Run Code Online (Sandbox Code Playgroud)
警告:您不应在实际代码中使用ECB模式.试试CBC吧.
更新:我不认为推荐CBC模式是公平的,如果不提供一些如何工作的样本:
public static void main(String... args) throws Exception {
byte[] data = "hello".getBytes();
KeyGenerator keyGenerator = KeyGenerator.getInstance("AES");
keyGenerator.init(128); // 192 and 256 bits may not be available
SecretKey secretKey = keyGenerator.generateKey();
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
// By initializing the cipher in CBC mode, an "initialization vector" has been randomly
// generated. This initialization vector will be necessary to decrypt the encrypted data.
// It is safe to store the initialization vector in plain text for later use. You can obtain
// it's bytes by calling iv.getIV().
cipher.init(Cipher.ENCRYPT_MODE, secretKey);
IvParameterSpec iv = cipher.getParameters().getParameterSpec(IvParameterSpec.class);
byte[] encryptedData = cipher.doFinal(data);
// When decrypting the encrypted data, you must provide the initialization vector used
// during the encryption phase.
cipher.init(Cipher.DECRYPT_MODE, secretKey, iv);
byte[] decryptedData = cipher.doFinal(encryptedData);
if (!Arrays.equals(data, decryptedData)) {
throw new Exception("Data was not decrypted successfully");
}
}
Run Code Online (Sandbox Code Playgroud)