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

  • 相关阅读:
    回归,随缘写一些python心得吧
    划分树【有些东西,其实自己还不太会也要忍住把*装完】
    [codevs3273]两圆的交 计算几何
    10-12考试整理
    10-7考试整理
    [codevs1163]访问艺术馆
    [codevs2640]打印页数
    9-28 解题报告
    [CODEVS3323]时空跳跃者的封锁
    [codevs2442] kshort 经典题
  • 原文地址:https://www.cnblogs.com/siqi/p/14458561.html
Copyright © 2011-2022 走看看