在使用密码加密消息时,使用哪些AES参数和由crypto-j内部执行的步骤? [英] What are the AES parameters used and steps performed internally by crypto-js while encrypting a message with a password?

查看:107
本文介绍了在使用密码加密消息时,使用哪些AES参数和由crypto-j内部执行的步骤?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

Background: The application that I am working on is supposed to work offline. I should encrypt some text data using a password as a key at the java server side. The encrypted data is passed to the HTML5 page and at the client side using crypto-js library the server encrypted data should be decrypted.

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

My issue: In order to encrypt my message in such a way that the client can decrypt it with crypt-js (using a user entered password), I need to know the exact steps that crypto-js expects while encrypting a message.

我需要知道的是: strong>
我有以下加密代码,使用crypto-js在客户端对消息进行加密。

What I need to know: I have the following encryption code which does the encryption of a message at the client side using 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))。如果有人可以确认,这将是一个很大的帮助...我最近几天试图解决这个谜题。

I need to know the AES parameters used by CryptoJS while encrypting a message(Not sure what they are, but it sounds like: key size (256), padding (pkcs5), mode (CBC), PBE algorithm (PBKDF2), salt (random), iteration count (100)) . It would be a great help if some one could confirm it...I been trying to solve this mystery for the last few days?.

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

I need to know the different steps performed by CryptoJS while AES encrypting a message

推荐答案

CryptoJS 使用非标准OpenSSL KDF进行密钥推导( EvpKDF ),使用 MD5 作为散列算法和 1 迭代。 IV也是从密码中得出的,这意味着在Java端只需要实际的密文,密码和salt来解密。

CryptoJS uses the non-standardized OpenSSL KDF for key derivation (EvpKDF) with MD5 as the hashing algorithm and 1 iteration. The IV is also derived from the password which means that only the actual ciphertext, the password and the salt are needed to decrypt this on Java side.

换句话说,PBKDF2不用于CryptoJS的密码模式的密钥导出。默认情况下,AES-256在CBC模式下使用PKCS5填充(这是与PKCS7填充相同)。请记住,您可能需要 JCE无限力量管辖权政策文件。另请参阅为什么有限制使用超过一定长度的密钥加密?

In other words, PBKDF2 is not used for key derivation in password mode of CryptoJS. By default AES-256 is used in CBC mode with PKCS5 padding (which is the same as PKCS7 padding). Keep in mind that you might need the JCE Unlimited Strength Jurisdiction Policy Files. See also Why there are limitations on using encryption with keys beyond certain length?

以下代码以Java重新创建KDF( keySize ivSize 对于AES-256分别为8,来自)。

The following code recreates the KDF in Java (keySize and ivSize are 8 respectively 4 for AES-256 and come from ).

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 http://stackoverflow.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代码中的值:

and the JavaScript code which was used for the generation of the values in the Java code:

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

这篇关于在使用密码加密消息时,使用哪些AES参数和由crypto-j内部执行的步骤?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆