zoukankan      html  css  js  c++  java
  • 解决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;     
        }    
     
    }


  • 相关阅读:
    一则自用iptables例子解释
    SVN配置钩子文件限制提交文件时必须填写更新日志
    Nginx反向代理配置配置实例
    mysql 物理数据存放
    VisualVM、JConsole
    Rabbitmq
    pdm画表间结构
    tomcat jvm 参数优化
    【转载】Java导入导出excel
    【转载】使用 Google Guava 美化你的 Java 代码
  • 原文地址:https://www.cnblogs.com/cuker919/p/4878540.html
Copyright © 2011-2022 走看看