• ruby 重写 JAVA AES/CBC/PKCS5Padding


    JAVA部分代码:

    import javax.crypto.Cipher;
    import javax.crypto.KeyGenerator;
    import javax.crypto.spec.IvParameterSpec;
    import javax.crypto.spec.SecretKeySpec;
    import java.security.MessageDigest;
    import java.security.SecureRandom;
    
    public class AESUtil {
    
        // AES密码器
        private static Cipher cipher;
    
        private static final String KEY_CHARSET = "UTF-8";
    
        // 算法方式
        private static final String KEY_ALGORITHM = "AES";
    
        // 算法/模式/填充
        private static final String CIPHER_ALGORITHM_CBC = "AES/CBC/PKCS5Padding";
    
        private static final Integer PRIVATE_KEY_SIZE_BIT = 128;
        private static final Integer PRIVATE_KEY_SIZE_BYTE = 16;
    
        /**
         * 加密
         *
         * @param key
         *            密钥:我司提供
         * @param plainText
         *            明文:要加密的内容
         * @return cipherText
         *                  密文:加密后的内容,如有异常返回空串:""
         */
        public static String encrypt(String key, String plainText) {
            String secretKey = md5_16(key);
            if (secretKey.length() != PRIVATE_KEY_SIZE_BYTE) {
                throw new RuntimeException("AESUtil:Invalid AES secretKey length (must be 16 bytes)");
            }
    
            // 密文字符串
            String cipherText;
            try {
                // 加密模式初始化参数
                initParam(secretKey, Cipher.ENCRYPT_MODE);
                // 获取加密内容的字节数组
                byte[] bytePlainText = plainText.getBytes(KEY_CHARSET);
                // 执行加密
                byte[] byteCipherText = cipher.doFinal(bytePlainText);
                cipherText = byteArrayToHex(byteCipherText);
            } catch (Exception e) {
                throw new RuntimeException("AESUtil:encrypt fail!", e);
            }
            return cipherText;
        }
    
        /**
         * 解密
         *
         * @param key
         *            密钥:我司提供
         * @param cipherText
         *            密文:加密后的内容,即需要解密的内容
         * @return plainText
         *                     明文:解密后的内容即加密前的内容,如有异常返回空串:""
         */
        public static String decrypt(String key, String cipherText) {
            String secretKey = md5_16(key);
            if (secretKey.length() != PRIVATE_KEY_SIZE_BYTE) {
                throw new RuntimeException("AESUtil:Invalid AES secretKey length (must be 16 bytes)");
            }
    
            // 明文字符串
            String plainText;
            try {
                initParam(secretKey, Cipher.DECRYPT_MODE);
                // 将加密并编码后的内容解码成字节数组
                byte[] byteCipherText = hexToByteArray(cipherText);
                // 解密
                byte[] bytePlainText = cipher.doFinal(byteCipherText);
                plainText = new String(bytePlainText, KEY_CHARSET);
            } catch (Exception e) {
                throw new RuntimeException("AESUtil:decrypt fail!", e);
            }
            return plainText;
        }
    
        public static String md5(String text) {
            byte[] bts;
            try {
                bts = text.getBytes("UTF-8");
                MessageDigest md = MessageDigest.getInstance("MD5");
                byte[] bts_hash = md.digest(bts);
                StringBuffer buf = new StringBuffer();
                for (byte b : bts_hash) {
                    buf.append(String.format("%02X", b & 0xff));
                }
                return buf.toString();
            } catch (java.io.UnsupportedEncodingException e) {
                e.printStackTrace();
                return "";
            } catch (java.security.NoSuchAlgorithmException e) {
                e.printStackTrace();
                return "";
            }
        }
    
        public static String md5_16(String str)
        {
            return md5(str).substring(8, 24);
        }
    
        public static String byteArrayToHex(byte[] a) {
            StringBuilder sb = new StringBuilder(a.length * 2);
            for(byte b: a)
                sb.append(String.format("%02X", b));
            return sb.toString();
        }
    
        private static byte[] hexToByteArray(String hexStr) {
            byte[] bits = new byte[hexStr.length()/2];
            for (int i = 0; i < hexStr.length(); i += 2) {
                String str = hexStr.substring(i, i + 2);
                bits[i/2] = (byte)Integer.parseInt(str, 16);
            }
            return bits;
        }
    
        /**
         * 初始化参数
         * @param secretKey
         *                  密钥:加密的规则 16位
         * @param mode
         *                 加密模式:加密or解密
         */
        public static void initParam(String secretKey, int mode) {
            try {
                // 防止Linux下生成随机key
                SecureRandom secureRandom = SecureRandom.getInstance("SHA1PRNG");
                secureRandom.setSeed(secretKey.getBytes());
                // 获取key生成器
                KeyGenerator keygen = KeyGenerator.getInstance(KEY_ALGORITHM);
                keygen.init(PRIVATE_KEY_SIZE_BIT, secureRandom);
    
                // 获得原始对称密钥的字节数组
                byte[] raw = secretKey.getBytes();
    
                // 根据字节数组生成AES内部密钥
                SecretKeySpec key = new SecretKeySpec(raw, KEY_ALGORITHM);
                // 根据指定算法"AES/CBC/PKCS5Padding"实例化密码器
                cipher = Cipher.getInstance(CIPHER_ALGORITHM_CBC);
                IvParameterSpec iv = new IvParameterSpec(md5_16(secretKey).getBytes());
                //System.out.println("iv:" + new String(iv.getIV()));
                cipher.init(mode, key, iv);
            } catch (Exception e) {
                throw new RuntimeException("AESUtil:initParam fail!", e);
            }
        }
    }

    Ruby实现代码:

        def encrypt_data(content)
          result_key = md5_16(key)
          cipher = OpenSSL::Cipher.new("aes-128-cbc")
          cipher.encrypt
          cipher.key = result_key
          cipher.iv = md5_16(result_key)
          crypt = cipher.update(content.force_encoding("utf-8"))
          crypt << cipher.final()
          return crypt.bytes.map { |n| '%02X' % (n & 0xFF) }.join
        end
    
        # md5 加密之后取16个字符
        def md5_16(str)
          md5 = Digest::MD5.new
          md5_key = md5.update str
          md5_key_hex_str = md5_key.hexdigest.upcase
          result = md5_key_hex_str[8, 16]
          return result
        end
    
        def md5(str)
          md5 = Digest::MD5.new
          md5_key = md5.update str
          md5_key_hex_str = md5_key.hexdigest.upcase
        end
    
        def get_sha256(str)
          sha_256 = Digest::SHA256.new
          sha_256 << str
          return sha_256.hexdigest
        end
  • 相关阅读:
    344.反正字符串
    125.验证回文串
    167.两数之和 II
    278.第一个错误的版本
    缓冲流
    Windows10剪贴板不能用
    chapter_21【字节流、字符流】
    属性集
    IO异常的处理
    字符流
  • 原文地址:https://www.cnblogs.com/tomtang/p/14062178.html
Copyright © 2020-2023  润新知