• 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

  • 相关阅读:
    HDU 3081 Marriage Match II
    HDU 4292 Food
    HDU 4322 Candy
    HDU 4183 Pahom on Water
    POJ 1966 Cable TV Network
    HDU 3605 Escape
    HDU 3338 Kakuro Extension
    HDU 3572 Task Schedule
    HDU 3998 Sequence
    Burning Midnight Oil
  • 原文地址:https://www.cnblogs.com/siqi/p/14458561.html
Copyright © 2020-2023  润新知