首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >加密-js在使用密码加密消息时,在内部执行哪些AES参数和步骤?

加密-js在使用密码加密消息时,在内部执行哪些AES参数和步骤?
EN

Stack Overflow用户
提问于 2014-12-01 00:55:40
回答 3查看 14.1K关注 0票数 3

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

My entered :为了对我的消息进行加密,使客户端可以使用密码-js(使用用户输入的密码)解密它,我需要知道加密-js加密消息时所期望的确切步骤。

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

代码语言:javascript
复制
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)、salt (随机)、迭代计数(100))。如果有人能证实这一点,那会有很大的帮助.我这几天一直在试图解开这个谜团?

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

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2014-12-02 13:40:06

CryptoJS 使用是用于密钥派生(EvpKDF)的非标准化OpenSSL KDF,使用MD5作为散列算法和1迭代。IV也是从密码派生出来的,这意味着只有实际的密文、密码和salt才能在Java端解密。

换句话说,PBKDF2不用于CryptoJS密码模式下的密钥派生。默认情况下,在CBC模式中使用AES-256,并使用PKCS5填充(即与PKCS7填充相同)。请记住,您可能需要JCE无限强权限策略文件。另见为什么对超过一定长度的密钥使用加密有限制?

下面的代码在Java中重新创建KDF (对于AES-256,keySizeivSize分别为8 )。

代码语言:javascript
复制
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
}

以下是供参考的完整类:

代码语言:javascript
复制
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代码中的值的JavaScript代码:

代码语言: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
票数 12
EN

Stack Overflow用户

发布于 2018-10-01 20:39:45

在@Artjom对这个问题和这里供python用户使用的出色回答之后,我加入了完整的java代码,它帮助我解密了一个以这种方式加密的字符串

代码语言:javascript
复制
var encrypted = CryptoJS.AES.encrypt(message, password).toString();

当您只知道密码时(即没有用加密的字符串发送salt ),这段Java代码非常有用:

代码语言:javascript
复制
public String decrypt(String encrypted, String password) throws Exception {
    int keySize = 8;
    int ivSize = 4;
    // Start by decoding the encrypted string (Base64)
    // Here I used the Android implementation (other Java implementations might exist)
    byte[] cipherText = Base64.decode(encrypted, Base64.DEFAULT);
    // prefix (first 8 bytes) is not actually useful for decryption, but you should probably check that it is equal to the string "Salted__"
    byte[] prefix = new byte[8];
    System.arraycopy(cipherText, 0, prefix, 0, 8);
    // Check here that prefix is equal to "Salted__"
    // Extract salt (next 8 bytes)
    byte[] salt = new byte[8];
    System.arraycopy(cipherText, 8, salt, 0, 8);
    // Extract the actual cipher text (the rest of the bytes)
    byte[] trueCipherText = new byte[cipherText.length - 16];
    System.arraycopy(cipherText, 16, trueCipherText, 0, cipherText.length - 16);
    byte[] javaKey = new byte[keySize * 4];
    byte[] javaIv = new byte[ivSize * 4];
    evpKDF(password.getBytes("UTF-8"), keySize, ivSize, salt, javaKey, javaIv);
    Cipher aesCipherForEncryption = Cipher.getInstance("AES/CBC/PKCS5Padding");
    IvParameterSpec ivSpec = new IvParameterSpec(javaIv);
    aesCipherForEncryption.init(Cipher.DECRYPT_MODE, new SecretKeySpec(javaKey, "AES"), ivSpec);

    byte[] byteMsg = aesCipherForEncryption.doFinal(trueCipherText);
    return new String(byteMsg, "UTF-8");
}

public  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  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
}
票数 3
EN

Stack Overflow用户

发布于 2014-12-01 15:20:10

我在看在文件上

  • 密钥大小:“如果您使用密码,那么它将生成一个256位的密钥。”
  • 填充: Pkcs7 (默认)
  • 模式: CBC (默认)
  • iv:生成并存储在密码文本对象中:与"encrypted.iv“一起使用

用来生成密钥的东西:

  • salt:生成并存储在密码文本对象中:与"encrypted.salt“一起使用(尽管它并没有这么说,所以我在这里猜测)
  • pbe算法:不清楚。没有记录在案。
  • 迭代计数:我在任何地方都找不到这个文档。代码中的示例似乎使用了1000。

您可以手动设置参数,这可能比依赖默认值更安全,例如,根据文档中的示例设置一些伪代码:

代码语言:javascript
复制
var salt = CryptoJS.lib.WordArray.random(128/8);
var iv = CryptoJS.lib.WordArray.random(128);
var key256Bits10000Iterations = CryptoJS.PBKDF2("Secret Passphrase", salt, { keySize: 256/32, iterations: 10000 }); //I don't know this is dividing by 32
var encrypted = CryptoJS.AES.encrypt("Message", key, { mode: CryptoJS.mode.CBC, padding: CryptoJS.pad.Pkcs7, iv:iv });

你可能要做实验。我会一步一步地走。通过篡改这些参数来获取基于密码的密钥来匹配,然后得到要匹配的密文,然后计算出解密。不要急于简化一些事情,比如跳过IV或者使用欧洲央行。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/27220297

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档