您的位置:首页 > 运维架构 > Linux

解决Linux操作系统下AES解密失败的问题

2012-11-26 17:24 239 查看
现象描述:

windows上加解密正常,linux上加密正常,解密时发生如下异常:

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

at chb.test.crypto.AESUtils.crypt(AESUtils.java:386)

at chb.test.crypto.AESUtils.AesDecrypt(AESUtils.java:254)

at chb.test.crypto.AESUtils.main(AESUtils.java:40)
解决方法:

经过检查之后,定位在生成KEY的方法上,如下:

view
plaincopy
to clipboardprint?

public static SecretKey getKey (String strKey) {

try {

KeyGenerator _generator = KeyGenerator.getInstance( "AES" );

_generator.init(128, new SecureRandom(strKey.getBytes()));

return _generator.generateKey();

} catch (Exception e) {

throw new RuntimeException( " 初始化密钥出现异常 " );

}

}

修改到如下方式,问题解决:

view
plaincopy
to clipboardprint?

public static SecretKey getKey(String strKey) {

try {

KeyGenerator _generator = KeyGenerator.getInstance( "AES" );

SecureRandom secureRandom = SecureRandom.getInstance("SHA1PRNG" );

secureRandom.setSeed(strKey.getBytes());

_generator.init(128,secureRandom);

return _generator.generateKey();

} catch (Exception e) {

throw new RuntimeException( " 初始化密钥出现异常 " );

}

}

原因分析

SecureRandom 实现完全隨操作系统本身的內部狀態,除非調用方在調用 getInstance 方法之後又調用了 setSeed 方法;该实现在 windows 上每次生成的 key 都相同,但是在 solaris 或部分 linux 系统上则不同。

原因二:

1、加密完byte[] 后,需要将加密了的byte[] 转换成base64保存,如:

BASE64Encoder base64encoder = new BASE64Encoder();

String encode=base64encoder.encode(bytes);

2、解密前,需要将加密后的字符串从base64转回来再解密,如:

BASE64Decoder base64decoder = new BASE64Decoder();

byte[] encodeByte = base64decoder.decodeBuffer(str);

完整例子:

Java代码


import java.io.IOException;

import java.io.UnsupportedEncodingException;

import java.security.InvalidKeyException;

import java.security.NoSuchAlgorithmException;

import java.security.SecureRandom;

import javax.crypto.BadPaddingException;

import javax.crypto.Cipher;

import javax.crypto.IllegalBlockSizeException;

import javax.crypto.KeyGenerator;

import javax.crypto.NoSuchPaddingException;

import javax.crypto.SecretKey;

import javax.crypto.spec.SecretKeySpec;

import sun.misc.BASE64Decoder;

import sun.misc.BASE64Encoder;

public class SecurityAES {

private final static String encoding = "UTF-8";

/**

* AES加密

*

* @param content

* @param password

* @return

*/

public static String encryptAES(String content, String password) {

byte[] encryptResult = encrypt(content, password);

String encryptResultStr = parseByte2HexStr(encryptResult);

// BASE64位加密

encryptResultStr = ebotongEncrypto(encryptResultStr);

return encryptResultStr;

}

/**

* AES解密

*

* @param encryptResultStr

* @param password

* @return

*/

public static String decrypt(String encryptResultStr, String password) {

// BASE64位解密

String decrpt = ebotongDecrypto(encryptResultStr);

byte[] decryptFrom = parseHexStr2Byte(decrpt);

byte[] decryptResult = decrypt(decryptFrom, password);

return new String(decryptResult);

}

/**

* 加密字符串

*/

public static String ebotongEncrypto(String str) {

BASE64Encoder base64encoder = new BASE64Encoder();

String result = str;

if (str != null && str.length() > 0) {

try {

byte[] encodeByte = str.getBytes(encoding);

result = base64encoder.encode(encodeByte);

} catch (Exception e) {

e.printStackTrace();

}

}

//base64加密超过一定长度会自动换行 需要去除换行符

return result.replaceAll("\r\n", "").replaceAll("\r", "").replaceAll("\n", "");

}

/**

* 解密字符串

*/

public static String ebotongDecrypto(String str) {

BASE64Decoder base64decoder = new BASE64Decoder();

try {

byte[] encodeByte = base64decoder.decodeBuffer(str);

return new String(encodeByte);

} catch (IOException e) {

e.printStackTrace();

return str;

}

}

/**

* 加密

*

* @param content 需要加密的内容

* @param password 加密密码

* @return

*/

private static byte[] encrypt(String content, String password) {

try {

KeyGenerator kgen = KeyGenerator.getInstance("AES");

//防止linux下 随机生成key

SecureRandom secureRandom = SecureRandom.getInstance("SHA1PRNG" );

secureRandom.setSeed(password.getBytes());

kgen.init(128, secureRandom);

//kgen.init(128, new SecureRandom(password.getBytes()));

SecretKey secretKey = kgen.generateKey();

byte[] enCodeFormat = secretKey.getEncoded();

SecretKeySpec key = new SecretKeySpec(enCodeFormat, "AES");

Cipher cipher = Cipher.getInstance("AES");// 创建密码器

byte[] byteContent = content.getBytes("utf-8");

cipher.init(Cipher.ENCRYPT_MODE, key);// 初始化

byte[] result = cipher.doFinal(byteContent);

return result; // 加密

} catch (NoSuchAlgorithmException e) {

e.printStackTrace();

} catch (NoSuchPaddingException e) {

e.printStackTrace();

} catch (InvalidKeyException e) {

e.printStackTrace();

} catch (UnsupportedEncodingException e) {

e.printStackTrace();

} catch (IllegalBlockSizeException e) {

e.printStackTrace();

} catch (BadPaddingException e) {

e.printStackTrace();

}

return null;

}

/**解密

* @param content 待解密内容

* @param password 解密密钥

* @return

*/

private static byte[] decrypt(byte[] content, String password) {

try {

KeyGenerator kgen = KeyGenerator.getInstance("AES");

//防止linux下 随机生成key

SecureRandom secureRandom = SecureRandom.getInstance("SHA1PRNG" );

secureRandom.setSeed(password.getBytes());

kgen.init(128, secureRandom);

//kgen.init(128, new SecureRandom(password.getBytes()));

SecretKey secretKey = kgen.generateKey();

byte[] enCodeFormat = secretKey.getEncoded();

SecretKeySpec key = new SecretKeySpec(enCodeFormat, "AES");

Cipher cipher = Cipher.getInstance("AES");// 创建密码器

cipher.init(Cipher.DECRYPT_MODE, key);// 初始化

byte[] result = cipher.doFinal(content);

return result; // 加密

} catch (NoSuchAlgorithmException e) {

e.printStackTrace();

} catch (NoSuchPaddingException e) {

e.printStackTrace();

} catch (InvalidKeyException e) {

e.printStackTrace();

} catch (IllegalBlockSizeException e) {

e.printStackTrace();

} catch (BadPaddingException e) {

e.printStackTrace();

}

return null;

}

/**将二进制转换成16进制

* @param buf

* @return

*/

public static String parseByte2HexStr(byte buf[]) {

StringBuffer sb = new StringBuffer();

for (int i = 0; i < buf.length; i++) {

String hex = Integer.toHexString(buf[i] & 0xFF);

if (hex.length() == 1) {

hex = '0' + hex;

}

sb.append(hex.toUpperCase());

}

return sb.toString();

}

/**将16进制转换为二进制

* @param hexStr

* @return

*/

public static byte[] parseHexStr2Byte(String hexStr) {

if (hexStr.length() < 1)

return null;

byte[] result = new byte[hexStr.length()/2];

for (int i = 0;i< hexStr.length()/2; i++) {

int high = Integer.parseInt(hexStr.substring(i*2, i*2+1), 16);

int low = Integer.parseInt(hexStr.substring(i*2+1, i*2+2), 16);

result[i] = (byte) (high * 16 + low);

}

return result;

}

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: