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

现象描述:
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的方法上,如下:
  1. public static SecretKey getKey (String strKey) {  
  2.          try {           
  3.             KeyGenerator _generator = KeyGenerator.getInstance( "AES" );  
  4.             _generator.init(128new SecureRandom(strKey.getBytes()));  
  5.                 return _generator.generateKey();  
  6.         }  catch (Exception e) {  
  7.              throw new RuntimeException( " 初始化密钥出现异常 " );  
  8.         }  
  9.       }   
修改到如下方式,问题解决:

  1. public static SecretKey getKey(String strKey) {  
  2.        try {           
  3.           KeyGenerator _generator = KeyGenerator.getInstance( "AES" );  
  4.            SecureRandom secureRandom = SecureRandom.getInstance("SHA1PRNG" );  
  5.           secureRandom.setSeed(strKey.getBytes());  
  6.           _generator.init(128,secureRandom);  
  7.               return _generator.generateKey();  
  8.       }  catch (Exception e) {  
  9.            throw new RuntimeException( " 初始化密钥出现异常 " );  
  10.       }  
  11.     }   

原因分析

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


posted @ 2012-11-26 17:24  cuker919  阅读(500)  评论(0编辑  收藏  举报