java中AES解密算法的异常 [英] Exception in AES decryption algorithm in java

查看:15
本文介绍了java中AES解密算法的异常的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在 Java 中的 AES 算法的以下代码中遇到异常.

I got an exception in the following code for AES algorithm in java.

代码解密加密字符串并返回原始字符串.

Code decryptes an encrypted string and returns the original string.

请帮我解决这个问题.

代码:

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(); 

}} 
`

例外:

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*..) 

推荐答案

根据 Java™ 密码体系结构 (JCA) 参考指南(重点是我的):

According to Java™ Cryptography Architecture (JCA) Reference Guide (emphasis mine):

Cipher 对象通过使用获得Cipher getInstance() 静态工厂方法.在这里,算法名称与 with 略有不同其他引擎类,因为它不仅指定算法名称,而是转型".一个转换是一个字符串描述操作(或一组操作)在给定输入以产生一些输出.一个转换总是包括密码算法名称(例如,DES),并且可能后跟模式和填充方案.

Cipher objects are obtained by using one of the Cipher 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.

转换的形式为:

  • 算法/模式/填充"或
  • "算法"

例如,以下是有效的转换:

For example, the following are valid transformations:

  • DES/CBC/PKCS5Padding"
  • DES"

如果只指定了一个转换名称,系统将确定是否存在请求的执行转换可用环境,如果有超过一,返回有首选.

If just a transformation name is specified, the system will determine if there is an implementation of the requested transformation available in the environment, and if there is more than one, returns there is a preferred one.

如果转换名称和包提供者被指定,系统将确定是否存在请求的执行包中的转换请求,并抛出异常,如果没有.

If both a transformation name and a package provider are specified, the system will determine if there is an implementation of the requested transformation in the package requested, and throw an exception if there is not.

如果没有指定模式或填充,提供者特定的默认值使用模式和填充方案.例如,SunJCE 提供程序使用ECB 作为默认模式,以及PKCS5Padding 作为默认填充DESDES-EDEBlowfish 的方案密码.这意味着在这种情况下SunJCE 提供者的:

If no mode or padding is specified, provider-specific default values for the mode and padding scheme are used. For example, the SunJCE provider uses ECB as the default mode, and PKCS5Padding as the default padding scheme for DES, DES-EDE and Blowfish ciphers. This means that in the case of the SunJCE provider:

Cipher c1 = Cipher.getInstance("DES/ECB/PKCS5Padding");

Cipher c1 = Cipher.getInstance("DES");

是等效的语句.

使用模式例如 CFB 和 OFB,分组密码可以以小于密码的实际块大小.什么时候请求这种模式,你可以可选地指定位数通过附加一次处理这个数字到模式名称,如图所示在DES/CFB8/NoPadding"和"DES/OFB32/PKCS5Padding"转换.如果没有这样的数字指定,提供者特定的默认值用来.(例如,SunJCE提供程序使用 64 位的默认值DES.)因此,分组密码可以是变成面向字节的流使用 8 位模式加密,例如CFB8 或 OFB8.

Using modes such as CFB and OFB, block ciphers can encrypt data in units smaller than the cipher's actual block size. When requesting such a mode, you may optionally specify the number of bits to be processed at a time by appending this number to the mode name as shown in the "DES/CFB8/NoPadding" and "DES/OFB32/PKCS5Padding" transformations. If no such number is specified, a provider-specific default is used. (For example, the SunJCE provider uses a default of 64 bits for DES.) Thus, block ciphers can be turned into byte-oriented stream ciphers by using an 8 bit mode such as CFB8 or OFB8.

附录 A<本文档的/a> 包含一个可以使用的标准名称列表用于指定算法名称,模式和填充方案组件转型.

工厂返回的对象方法未初始化,必须是在它们可用之前进行初始化.

The objects returned by factory methods are uninitialized, and must be initialized before they become usable.

由于您的代码未指定模式或填充,因此正在使用特定于提供程序的默认值.看来您的提供程序是 SunJCE 并且它的默认填充可能是 "NoPadding".使用此填充,您负责确保被加密的字节数组的大小是密钥中字节数的倍数.您可以通过在转换中指定模式和填充来让您的生活更轻松:

Because your code does not specify mode or padding, provider-specific default values are being used. It appears that your provider is SunJCE and that it's default padding is probably "NoPadding". With this padding, you are responsible for ensuring that the size of the byte array being encrypted is a multiple of the number of bytes in the secret key. You can make you're life easier by specifying the mode and padding in your transformation:

Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");

警告:您不应在实际代码中使用 ECB 模式.试试 CBC.

更新:我认为推荐 CBC 模式而不提供其工作原理的小样本是不公平的:

Update: I didn't think it was fair to recommend CBC mode without offering a little sample of how it works:

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");
    }
}

这篇关于java中AES解密算法的异常的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆