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

 

posted @ 2020-11-30 16:46  皓贤  阅读(256)  评论(0编辑  收藏  举报