美文网首页
javax.crypto.BadPaddingException

javax.crypto.BadPaddingException

作者: 流沙飞雪 | 来源:发表于2020-01-09 10:04 被阅读0次

    在做AES加解密的时候遇到这个问题,发现win现每次加密结果都一样,但是linux下每次都是随机的,后来在网上找到原因。

    原因:SecureRandom 实现完全随操作系统本身的內部状态,除非调用方在调用 getInstance 方法,然后调用 setSeed 方法;该实现在 windows 上每次生成的 key 都相同,但是在 solaris 或部分 linux 系统上则不同。关于SecureRandom类的详细介绍,参考网上文章

    解决办法:调用getInstance方法

    SecureRandom secureRandom = SecureRandom.getInstance("SHA1PRNG") ;
    secureRandom.setSeed(encodeRules.getBytes());
    

    最终代码如下:

    @Slf4j
    public class AESUtil {
        /**
         * 注意key和加密用到的字符串是不一样的 加密还要指定填充的加密模式和填充模式 AES密钥可以是128或者256,加密模式包括ECB, CBC等 * ECB模式是分组的模式,CBC是分块加密后,每块与前一块的加密结果异或后再加密 第一块加密的明文是与IV变量进行异或
         */
        public static final String KEY_ALGORITHM = "AES";
        public static final String ECB_CIPHER_ALGORITHM = "AES/ECB/PKCS5Padding";
        public static final String RANDOM_ALGORITHM = "SHA1PRNG";
        public static final String ENCODING = "UTF-8";
    
        /*
         * 加密
         * 1.构造密钥生成器
         * 2.根据ecnodeRules规则初始化密钥生成器
         * 3.产生密钥
         * 4.创建和初始化密码器
         * 5.内容加密
         * 6.返回字符串
         */
        public static SecretKeySpec genKey(String myKey) {
            //MessageDigest sha = null;
            try {
                //1.构造密钥生成器,指定为AES算法,不区分大小写
                KeyGenerator kgen = KeyGenerator.getInstance(KEY_ALGORITHM);
                //2.根据myKey规则初始化密钥生成器
                //生成一个128位的随机源,根据传入的字节数组
                SecureRandom secureRandom = SecureRandom.getInstance(RANDOM_ALGORITHM);
                secureRandom.setSeed(myKey.getBytes());
                kgen.init(128, new SecureRandom(myKey.getBytes()));
                //3.产生原始对称密钥
                SecretKey secretKey = kgen.generateKey();
                //4.获得原始对称密钥的字节数组
                byte[] encodeFormat = secretKey.getEncoded();
                //5.根据字节数组生成AES密钥
                return new SecretKeySpec(encodeFormat, KEY_ALGORITHM);
            } catch (NoSuchAlgorithmException e) {
                log.error("初始化密钥错误:", e);
            }
            return null;
        }
    
        /**
         * 使用ECB模式进行加密。 加密过程三步走: 1. 传入算法,实例化一个加解密器 2. 传入加密模式和密钥,初始化一个加密器 3. * 调用doFinal方法加密
         *
         * @param strToEncrypt
         * @param secret
         * @return
         */
        public static String encrypt(String strToEncrypt, String secret) {
            try {
                //6.根据指定算法AES自成密码器
                Cipher cipher = Cipher.getInstance(ECB_CIPHER_ALGORITHM);
                //7.初始化密码器,第一个参数为加密(Encrypt_mode)或者解密解密(Decrypt_mode)操作,第二个参数为使用的KEY
                cipher.init(Cipher.ENCRYPT_MODE, genKey(secret));
                //8.获取加密内容的字节数组(这里要设置为utf-8)不然内容中如果有中文和英文混合中文就会解密为乱码
                //9.根据密码器的初始化方式--加密:将数据加密 cipher.doFinal
                //10.将加密后的数据转换为字符串
                //这里用Base64Encoder中会找不到包
                //解决办法:
                return Base64.getEncoder().encodeToString(cipher.doFinal(strToEncrypt.getBytes(ENCODING)));
            } catch (Exception e) {
                log.error("AES加密错误: ", e);
            }
            return null;
        }
    
        /**
         * 解密
         *
         * @param strToDecrypt
         * @param secret
         * @return
         */
        public static String decrypt(String strToDecrypt, String secret) {
            try {
                Cipher cipher = Cipher.getInstance(ECB_CIPHER_ALGORITHM);
                cipher.init(Cipher.DECRYPT_MODE, genKey(secret));
                return new String(cipher.doFinal(Base64.getDecoder().decode(strToDecrypt.getBytes(ENCODING))));
            } catch (Exception e) {
                log.error("AES解密错误: ", e);
            }
            return null;
        }
    
        public static void main(String[] args) {
            final String secretKey = "cZmmOQM#j2X32OaR";
    
            String originalString = "44,2020-01-09";
            String encryptedString = AESUtil.encrypt(originalString, secretKey);
            String decryptedString = AESUtil.decrypt(encryptedString, secretKey);
    
            System.out.println(originalString);
            System.out.println(encryptedString);
            System.out.println(decryptedString);
        }
    }
    

    本文参考 https://blog.csdn.net/seapeak007/article/details/79747309

    相关文章

      网友评论

          本文标题:javax.crypto.BadPaddingException

          本文链接:https://www.haomeiwen.com/subject/xyxyactx.html