javascript – 使用密码加密消息时,crypto-js内部使用的AES参数和步骤是什么?

背景:
我正在处理的应用程序应该脱机工作.我应该使用密码作为Java服务器端的密钥加密一些文本数据.加密数据传递到HTML5页面,在客户端使用crypto-js库,应解密服务器加密数据.

我的问题:
为了加密我的消息,客户端可以用crypt-js解密它(使用用户输入的密码),我需要知道加密消息时crypto-js所期望的确切步骤.

我需要知道的是:
我有以下加密代码,使用crypto-js在客户端加密消息.

var message = "my message text";
var password = "user password";
var encrypted = CryptoJS.AES.encrypt( message ,password );
console.log(encrypted.toString());

我需要知道加密消息时CryptoJS使用的AES参数(不确定它们是什么,但听起来像:密钥大小(256),填充(pkcs5),模式(CBC),PBE算法(PBKDF2),盐(随机),迭代计数(100)).如果有人能证实这一点,那将是一个很大的帮助……过去几天我一直试图解开这个谜团?

我需要知道在加密消息时CryptoJS执行的不同步骤

解决方法:

CryptoJS uses用于密钥推导的非标准化OpenSSL KDF(EvpKDF),其中MD5作为哈希算法和1次迭代. IV也来自密码,这意味着在Java端只需要实际的密文,密码和盐来解密它.

换句话说,PBKDF2不用于CryptoJS的密码模式中的密钥派生.默认情况下,AES-256在CBC模式下使用PKCS5填充(即same as PKCS7 padding).请记住,您可能需要JCE Unlimited Strength Jurisdiction Policy Files.另见Why there are limitations on using encryption with keys beyond certain length?

以下代码在Java中重新创建KDF(对于AES-256,keySize和ivSize分别为8和4).

public static byte[] evpKDF(byte[] password, int keySize, int ivSize, byte[] salt, int iterations, String hashAlgorithm, byte[] resultKey, byte[] resultIv) throws NoSuchAlgorithmException {
    int targetKeySize = keySize + ivSize;
    byte[] derivedBytes = new byte[targetKeySize * 4];
    int numberOfDerivedWords = 0;
    byte[] block = null;
    MessageDigest hasher = MessageDigest.getInstance(hashAlgorithm);
    while (numberOfDerivedWords < targetKeySize) {
        if (block != null) {
            hasher.update(block);
        }
        hasher.update(password);
        block = hasher.digest(salt);
        hasher.reset();

        // Iterations
        for (int i = 1; i < iterations; i++) {
            block = hasher.digest(block);
            hasher.reset();
        }

        System.arraycopy(block, 0, derivedBytes, numberOfDerivedWords * 4,
                Math.min(block.length, (targetKeySize - numberOfDerivedWords) * 4));

        numberOfDerivedWords += block.length/4;
    }

    System.arraycopy(derivedBytes, 0, resultKey, 0, keySize * 4);
    System.arraycopy(derivedBytes, keySize * 4, resultIv, 0, ivSize * 4);

    return derivedBytes; // key + iv
}

以下是完整的参考类:

public class RecreateEVPkdfFromCryptoJS {
    public static void main(String[] args) throws UnsupportedEncodingException, GeneralSecurityException {
        String msg = "hello";
        String password = "mypassword";
        String ivHex = "aab7d6aca0cc6ffc18f9f5909753aa5f";
        int keySize = 8; // 8 words = 256-bit
        int ivSize = 4; // 4 words = 128-bit
        String keyHex = "844a86d27d96acf3147aa460f535e20e989d1f8b5d79c0403b4a0f34cebb093b";
        String saltHex = "ca35168ed6b82778";
        String openSslFormattedCipherTextString = "U2FsdGVkX1/KNRaO1rgneK9S3zuYaYZcdXmVKJGqVqk=";
        String cipherTextHex = "af52df3b9869865c7579952891aa56a9";
        String padding = "PKCS5Padding";

        byte[] key = hexStringToByteArray(keyHex);
        byte[] iv = hexStringToByteArray(ivHex);
        byte[] salt = hexStringToByteArray(saltHex);
        byte[] cipherText = hexStringToByteArray(cipherTextHex);

        byte[] javaKey = new byte[keySize * 4];
        byte[] javaIv = new byte[ivSize * 4];
        evpKDF(password.getBytes("UTF-8"), keySize, ivSize, salt, javaKey, javaIv);
        System.out.println(Arrays.equals(key, javaKey) + " " + Arrays.equals(iv, javaIv));

        Cipher aesCipherForEncryption = Cipher.getInstance("AES/CBC/PKCS5Padding"); // Must specify the mode explicitly as most JCE providers default to ECB mode!!

        IvParameterSpec ivSpec = new IvParameterSpec(javaIv);
        aesCipherForEncryption.init(Cipher.DECRYPT_MODE, new SecretKeySpec(javaKey, "AES"), ivSpec);

        byte[] byteMsg = aesCipherForEncryption.doFinal(cipherText);
        System.out.println(Arrays.equals(byteMsg, msg.getBytes("UTF-8")));
    }

    public static byte[] evpKDF(byte[] password, int keySize, int ivSize, byte[] salt, byte[] resultKey, byte[] resultIv) throws NoSuchAlgorithmException {
        return evpKDF(password, keySize, ivSize, salt, 1, "MD5", resultKey, resultIv);
    }

    public static byte[] evpKDF(byte[] password, int keySize, int ivSize, byte[] salt, int iterations, String hashAlgorithm, byte[] resultKey, byte[] resultIv) throws NoSuchAlgorithmException {
        int targetKeySize = keySize + ivSize;
        byte[] derivedBytes = new byte[targetKeySize * 4];
        int numberOfDerivedWords = 0;
        byte[] block = null;
        MessageDigest hasher = MessageDigest.getInstance(hashAlgorithm);
        while (numberOfDerivedWords < targetKeySize) {
            if (block != null) {
                hasher.update(block);
            }
            hasher.update(password);
            block = hasher.digest(salt);
            hasher.reset();

            // Iterations
            for (int i = 1; i < iterations; i++) {
                block = hasher.digest(block);
                hasher.reset();
            }

            System.arraycopy(block, 0, derivedBytes, numberOfDerivedWords * 4,
                    Math.min(block.length, (targetKeySize - numberOfDerivedWords) * 4));

            numberOfDerivedWords += block.length/4;
        }

        System.arraycopy(derivedBytes, 0, resultKey, 0, keySize * 4);
        System.arraycopy(derivedBytes, keySize * 4, resultIv, 0, ivSize * 4);

        return derivedBytes; // key + iv
    }

    /**
     * Copied from https://*.com/a/140861
     * */
    public static byte[] hexStringToByteArray(String s) {
        int len = s.length();
        byte[] data = new byte[len / 2];
        for (int i = 0; i < len; i += 2) {
            data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4)
                    + Character.digit(s.charAt(i+1), 16));
        }
        return data;
    }
}

以及用于在Java代码中生成值的JavaScript代码:

var msg = "hello";
var password = "mypassword"; // must be present on the server
var encrypted = CryptoJS.AES.encrypt( msg, password );
var ivHex = encrypted.iv.toString();
var ivSize = encrypted.algorithm.ivSize; // same as the blockSize
var keySize = encrypted.algorithm.keySize;
var keyHex = encrypted.key.toString();
var saltHex = encrypted.salt.toString(); // must be sent as well
var openSslFormattedCipherTextString = encrypted.toString(); // not used
var cipherTextHex = encrypted.ciphertext.toString(); // must be sent
上一篇:SHA512哈希在android,php和javascript上有所不同


下一篇:javascript – 未捕获的TypeError:无法读取未定义的CryptoJS的属性“0”