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

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

问题描述



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



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
{

if(((int)buf [i]& 0xff)< 0x10) strbuf.append( 0);

strbuf.append(Long.toString((int)buf [i]& 0xff,16));

}

返回strbuf.toString();

}

public String AESencryptalgo(byte [] text)

{

String newtext =;

//获取KeyGenerator

尝试

{

KeyGenerator kgen = KeyGenerator.getInstance(AES) ;

kgen.init(128); // 192和256位可能不可用

//生成秘密密钥规范。

SecretKey skey = kgen.generateKey();

byte [] raw = skey.getEncoded();

SecretKeySpec skeySpec = new SecretKeySpec(raw,AES);

//实例化密码密码密码= 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(异常e)

{}

终于

{

newtext = new String(encrypted);

System.out.println(ENCRYPTED+ newtext);

// AESdecryptalgo(newtext.getBytes());

return newtext;

}

}

public String AESdecryptalgo(byte [] text)

{

//获取KeyGenerator

尝试

{

KeyGenerator kgen = KeyGenerator.getInstance(AES);

kgen.init(128); // 192和256位可能不可用

//生成秘密密钥规范。

SecretKey skey = kgen.generateKey();

byte [] raw = skey.getEncoded();

SecretKeySpec skeySpec = new SecretKeySpec(raw,AES);

//实例化密码

密码密码= Cipher.getInstance(AES);

cipher.init(Cipher.DECRYPT_MODE,skeySpec);

original = cipher.doFinal(text); //这里发生异常

originalString = new String(original);

System.out.println(原始字符串:+ originalString ++ asHex(原始));

}

catch(异常e)

{

System.out.println(exception);

}

终于

{

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:给定最终块未正确填充
com.sun.crypto.provider.SunJCE_f.b(DashoA13 * ..)在
com.sun.crypto.provider.SunJCE_f.b(DashoA13 * ..)at
com.sun.crypto.provider.AESCipher.engineDoFinal(DashoA13 * ..)at
javax.crypto.Cipher.doFinal(DashoA13 * ..)


解决方案

根据 Java™密码学架构(JCA)参考指南(强调我的):


密码对象是通过使用
获得的一个 Cipher getInstance() static
工厂方法
。这里,算法
名称与
其他引擎类略有不同,因为它
不仅指定算法名称
而是转换。 A
转换是一个字符串,
描述要在
给定输入上执行的操作(或
操作集)以产生一些输出。 A
转换总是包含加密算法
(例如 DES )的
名称,后面可以是
模式和填充方案。



转换形式如下:




  • 模式/填充

  • 算法



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




  • DES / CBC / PKCS5Padding

  • DES



如果只指定了一个转换名称,系统将
确定是否有
实现
环境中可用的请求的
转换,如果有超过
一个,返回是一个首选。



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



如果没有模式或填充指定,
提供者特定的
的默认值,使用模式和填充方案。

例如, SunJCE 提供者使用
ECB 作为默认模式,
PKCS5Padding 作为默认填充$ b code $ DES / code>,$ code> DES-EDE 和 Blowfish
密码。这意味着在$ code> SunJCE 提供者的

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

  Cipher c1 = Cipher.getInstance(DES); 

是等效语句。



使用
的模式,如CFB和OFB,块密码可以
以小于
密码的实际块大小的单位加密数据。当
请求这样的模式时,您可以
可选地指定要一次处理的位数
,将
这个数字追加到模式名称中,如图所示
在 DES / CFB8 / NoPadding 和
DES / OFB32 / PKCS5Padding
转换。如果没有指定这样的号码是
,则使用提供者特定的默认值
。 (例如,$ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $面向字节的流
通过使用8位模式,如
CFB8或OFB8。$ /

附录A 包含
列表标准名称可以是
用于指定算法名称,
模式和
a转换的填充方案组件。








工厂
方法返回的对象未初始化,必须在
初始化之前才能使用。


p>因为您的代码未指定模式或填充,因此正在使用提供者特定的默认值。您的提供商似乎是 SunJCE ,而且它的默认填充大概是NoPadding。使用此填充,您有责任确保加密的字节数组的大小是密钥中字节数的倍数。您可以通过在转换中指定模式和填充来使生活更轻松:

 密码密码= Cipher.getInstance( AES / ECB / PKCS5Padding); 

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



更新:我不认为推荐CBC模式是不公平的,如何工作:

  public static void main(String ... args)throws异常{
byte [] data =hello.getBytes();

KeyGenerator keyGenerator = KeyGenerator.getInstance(AES);
keyGenerator.init(128); // 192和256位可能不可用

SecretKey secretKey = keyGenerator.generateKey();

密码密码= Cipher.getInstance(AES / CBC / PKCS5Padding);

//通过在CBC模式下初始化密码,初始化向量已经被随机生成
//。这个初始化向量将是解密加密数据所必需的。
//将初始化向量存储为纯文本以供以后使用是安全的。您可以通过调用iv.getIV()获取
//它的字节。
cipher.init(Cipher.ENCRYPT_MODE,secretKey);
IvParameterSpec iv = cipher.getParameters()。getParameterSpec(IvParameterSpec.class);
byte [] encryptedData = cipher.doFinal(data);

//解密加密数据时,必须在加密阶段提供使用
//的初始化向量。
cipher.init(Cipher.DECRYPT_MODE,secretKey,iv);
byte [] decryptptedData = cipher.doFinal(encryptedData);

如果(!Arrays.equals(data,decryptptedData)){
抛出新的异常(数据未被成功解密);
}
}


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

Code decryptes an encrypted string and returns the original string.

Plz help me to fix this.

Code:

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

}} 
`

exception:

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

解决方案

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

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.

A transformation is of the form:

  • "algorithm/mode/padding" or
  • "algorithm"

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.

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

and

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

are equivalent statements.

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.

Appendix A of this document contains a list of standard names that can be used to specify the algorithm name, mode, and padding scheme components of a transformation.

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

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

WARNING: You should not use ECB mode in real code. Try CBC instead.

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解密算法中的异常的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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