• AES php java 互转


    php

    <?php
    
    class AesCrypt
    {
        //初始化向量
        private $iv = '84195bd96a8a2e7f';
    
        //Mcrypt算法
        private $cipher = MCRYPT_RIJNDAEL_128;
    
        //Mcrypt支持的加密模型  特别适用于对文件进行加密。 相比 ECB, 它的安全性有明显提升。
        private $mode = MCRYPT_MODE_CBC;
    
        public function encrypt($str, $key = '')
        {
            $str = $this->addPKCS7Padding($str);
    
            $encrypted = mcrypt_encrypt($this->cipher, $key, $str, $this->mode, $this->iv);
    
            return $encrypted;
        }
    
        public function decrypt($code, $key = '')
        {
            $decrypted = mcrypt_decrypt($this->cipher, $key, $code, $this->mode, $this->iv);
    
            $decrypted = $this->stripPKSC7Padding($decrypted);
    
            return $decrypted;
        }
    
        protected function addPKCS7Padding($source)
        {
            $block = mcrypt_get_block_size($this->cipher, $this->mode);
    
            $pad = $block - (strlen($source) % $block);
    
            $char = chr($pad);
    
            $source .= str_repeat($char, $pad);
    
            return $source;
        }
    
        public function stripPKSC7Padding($source)
        {
            $char = substr($source, -1);
            $num = ord($char);
            $source = substr($source, 0, -$num);
            return $source;
        }
    }

    注意:php 的 mcrypt_簇 在 7.1.0 版本中开始 deprecated,并在 7.2.0 版本中彻底废弃 ,可以增加@来抑制报错

    mcrypt always pads data will the null ('') character to fill out to n * blocksize

    mcrypt_簇 和 openssl_族对应关系

    注意 MCRYPT_RIJNDAEL_256 并不是 AES-256,如果想使用mcrypt_簇 实现 AES-256,则你应该使用 MCRYPT_RIJNDAEL_128 算法 + 32 位的 key

    MCRYPT_RIJNDAEL_128 & MCRYPT_MODE_CBC + 16位Key = openssl_encrypt(AES-128-CBC, 16位Key) = AES-128
    MCRYPT_RIJNDAEL_128 & MCRYPT_MODE_CBC + 24位Key = openssl_encrypt(AES-192-CBC, 24位Key) = AES-192
    MCRYPT_RIJNDAEL_128 & MCRYPT_MODE_CBC + 32位Key = openssl_encrypt(AES-256-CBC, 32位Key) = AES-256

    java

    /**
     * AES加解密 for原创php代码
     * 非PHP重构代码不要使用该方法
     */
    @Slf4j
    public class OgnvAesCrypt {
        /**
         * 使用固定长度密钥
         */
        private static final int KEY_LENGTH = 16;
        /**
         * 算法/模式/填充方式
         */
        private static final String AES_CIPHER = "AES/CBC/PKCS7Padding";
        private static final String AES_ALGORITHM = "AES";
        private static final IvParameterSpec IV = new IvParameterSpec("84195bd96a8a2e7f".getBytes());
    
        static {
            //support PKCS7Padding
            if (Security.getProvider(BouncyCastleProvider.PROVIDER_NAME) == null) {
                Security.addProvider(new BouncyCastleProvider());
            }
        }
    
        /**
         * aes解密
         * @param data 加密数据
         * @param key 解密密钥
         * @return null 参数不符合要求或解密失败
         */
        public static byte[] decrypt(byte[] data, byte[] key) {
            if (data == null || key == null) {
                return null;
            }
    
            if (key.length != KEY_LENGTH) {
                throw new RuntimeException("Invalid AES key length (must be 16 bytes)");
            }
    
            try {
                SecretKeySpec secretKey = new SecretKeySpec(key, AES_ALGORITHM);
                byte[] enCodeFormat = secretKey.getEncoded();
                SecretKeySpec seckey = new SecretKeySpec(enCodeFormat, AES_ALGORITHM);
    
                Cipher cipher = Cipher.getInstance(AES_CIPHER);
                cipher.init(Cipher.DECRYPT_MODE, seckey, IV);
    
                return cipher.doFinal(data);
            } catch (Exception e) {
                log.error("OgnvAesCrypt decrypt fail:{}", e.getMessage(), e);
            }
    
            return null;
        }
    
        /**
         * aes加密
         * @param data 需要加密的内容
         * @param key  加密密钥
         * @return 参数不符合要求或加密失败
         */
        public static byte[] encrypt(byte[] data, byte[] key) {
            if (data == null || key == null) {
                return null;
            }
    
            if (key.length != KEY_LENGTH) {
                throw new RuntimeException("Invalid AES key length (must be 16 bytes)");
            }
    
            try {
                SecretKeySpec secretKey = new SecretKeySpec(key, AES_ALGORITHM);
                byte[] enCodeFormat = secretKey.getEncoded();
                SecretKeySpec seckey = new SecretKeySpec(enCodeFormat, AES_ALGORITHM);
    
                Cipher cipher = Cipher.getInstance(AES_CIPHER);
    
                cipher.init(Cipher.ENCRYPT_MODE, seckey, IV);
                return cipher.doFinal(data);
            } catch (Exception e) {
                log.error("OgnvAesCrypt encrypt fail:{}", e.getMessage(), e);
            }
    
            return null;
        }
    }

    AES 是  Rijndael 子集

    AES has a fixed block size of 128 bits and a key size of 128, 192, or 256 bits, 
    whereas Rijndael can be specified with block and key sizes in any multiple of 32 bits, with a minimum of 128 bits and a maximum of 256 bits.

    BouncyCastle 是一个提供了很多 Java标准库 哈希算法和加密算法的第三方库

    PKCS5Padding是不支持AES算法的,当 Cipher.getInstance("AES/CBC/PKCS5Padding") 时实际使用的是PKCS7Padding,可能是历史遗留问题

    pkcs5 vs pkcs7

    pkcs5是pkcs7的子集算法
    pkcs5: blockSize固定为8byte
    pkcs7: blockSize固定为 1~255byte

     

    生成指定长度密钥

      口令可以为任意长度,但是不同加密算法对密钥长度有严格要求

         //口令
            String password = "jksong";
    
            //密钥生成器
            KeyGenerator keyGenerator = KeyGenerator.getInstance("AES");
    
            //SHA1PRNG随机算法为:原始秘钥经过两次sha1加密
            //php对应代码: substr(openssl_digest(openssl_digest($key, 'sha1', true), 'sha1', true), 0, 密钥位数);
            SecureRandom secureRandom = SecureRandom.getInstance("SHA1PRNG");
            secureRandom.setSeed(password.getBytes());
    
            //设置密钥的大小和随机源
            keyGenerator.init(128, secureRandom);
    
            //生成唯一秘钥
            SecretKey secretKey = keyGenerator.generateKey();
            byte[] encoded = secretKey.getEncoded();
    
            System.out.println(Hex.encodeHexString(encoded));

     

    参考

      PKCS7 / PKCS5 填充算法

      mcrypt_encrypt 迁移至 openssl_encrypt 的方法

      difference-between-pkcs5-padding-and-pkcs7-padding

      aes-rsa-java

      sha1prng

  • 相关阅读:
    ECMAScript 2016(ES7) 知多少
    PyCharm连接远程服务器
    PyCharm远程开发和调试
    SecureCRT使用帮助
    NLP文本相似度
    程序控制结构--案例
    程序控制结构--选择结构
    程序控制结构--条件表达式
    Python序列结构--集合
    Python序列结构--字典
  • 原文地址:https://www.cnblogs.com/siqi/p/14458561.html
Copyright © 2020-2023  润新知