iOS加密和Node.js解密AES

4
我已经搜索了很多关于如何在Node.js服务器和Objective-C客户端之间使用AES(或其他合适的加密方式)进行加密的解决方案。
由于我对密码学相对较新,因此我不理解为什么我的加密文本在每种语言中都是不同的。
以下是我目前所了解的内容:
Node.js加密方法使用这个CryptoJS库-node-cryptojs-aes
var node_cryptojs = require("node-cryptojs-aes");
var CryptoJS = node_cryptojs.CryptoJS;

    var textToEncrypt = 'Hello';
var key_clear = 'a16byteslongkey!';

//encrypted + decrypted

var encrypted = CryptoJS.AES.encrypt(clearText, key_clear, { iv: null });
var decrypted = CryptoJS.AES.decrypt(encrypted, key_clear, { iv: null });

//Outputs   
    console.log("encrypted: " + encrypted);     //encrypted: U2FsdGVkX1/ILXOjqIw2Vvz6DzRh1LMHgEQhDm3OunY=
console.log("decrypted: " + decrypted.toString(CryptoJS.enc.Utf8));   // decrypted: Hello

Objective-C加密方法 使用AESCrypt库

NSString* textToEncrypt = @"Hello";

// encrypt
NSString* encryptedText = [AESCrypt encrypt:textToEncrypt password:@"a16byteslongkey!"];

// decrypt
NSString* decryptedText = [AESCrypt decrypt:encryptedText password:@"a16byteslongkey!"];

// output
NSLog(@"Text to encrypt: %@", textToEncrypt);    // Text to encrypt: Hello
NSLog(@"Encrypted text: %@", encryptedText);     // Encrypted text: wY80MJyxRRJdE+eKw6kaIA==
NSLog(@"Decrypted text: %@", decryptedText);     // Decrypted text: Hello

我已经苦思冥想很久并尝试了我所能想到的一切。如果需要,可以展示库中的基础加密方法。在AESCrypt库中应用了SHAR256哈希算法于密钥,但我已将其删除,并认为字符串编码存在一些不匹配。
2个回答

13

我在这里发布这篇文章,因为肯定会有其他人尝试在Node.js和iOS之间进行交互。每个人似乎都在保持一切正确的结构、缓冲区、字符串等方面卡住了。我也是这样。因此,这里提供了一个分步骤的流程,用于创建密钥、创建iv、加密、解密并将其置于base64中以便于传输:

JavaScript (使用CryptoJS模块的Node.js)

    // Generate key from password and salt using SHA256 to hash and PDKDF2 to harden
    var password = "1234567890123456";
    var salt = "gettingsaltyfoo!";
    var hash = CryptoJS.SHA256(salt);
    var key = CryptoJS.PBKDF2(password, hash, { keySize: 256/32, iterations: 1000 });
    console.log("Hash :",hash.toString(CryptoJS.enc.Base64));
    console.log("Key :",key.toString(CryptoJS.enc.Base64));

    // Generate a random IV
    var iv = CryptoJS.lib.WordArray.random(128/8);
    console.log("IV :",iv.toString(CryptoJS.enc.Base64));

    // Encrypt message into base64
    var message = "Hello World!";
    var encrypted = CryptoJS.AES.encrypt(message, key, { iv: iv });
    var encrypted64 = encrypted.ciphertext.toString(CryptoJS.enc.Base64);
    console.log("Encrypted :",encrypted64);

    // Decrypt base64 into message again
    var cipherParams = CryptoJS.lib.CipherParams.create({ ciphertext: CryptoJS.enc.Base64.parse(encrypted64) });
    var decrypted = CryptoJS.AES.decrypt(cipherParams, key, { iv: iv }).toString(CryptoJS.enc.Utf8);
    console.log("Decrypted :",decrypted);

iOS SDK使用CommonCrypto

    // Generate key from password and salt using SHA256 to hash and PDKDF2 to harden
    NSString* password = @"1234567890123456";
    NSString* salt = @"gettingsaltyfoo!";
    NSMutableData* hash = [NSMutableData dataWithLength:CC_SHA256_DIGEST_LENGTH];
    NSMutableData* key = [NSMutableData dataWithLength:CC_SHA256_DIGEST_LENGTH];
    CC_SHA256(salt.UTF8String, (CC_LONG)strlen(salt.UTF8String), hash.mutableBytes);
    CCKeyDerivationPBKDF(kCCPBKDF2, password.UTF8String, strlen(password.UTF8String), hash.bytes, hash.length, kCCPRFHmacAlgSHA1, 1000, key.mutableBytes, key.length);
    NSLog(@"Hash : %@",[hash base64EncodedStringWithOptions:0]);
    NSLog(@"Key : %@",[key base64EncodedStringWithOptions:0]);

    // Generate a random IV (or use the base64 version from node.js)
    NSString* iv64 = @"ludWXFqwWeLOkmhutxiwHw==";       // Taken from node.js CryptoJS IV output
    NSData* iv = [[NSData alloc] initWithBase64EncodedString:iv64 options:0];
    NSLog(@"IV : %@",[iv base64EncodedStringWithOptions:0]);

    // Encrypt message into base64
    NSData* message = [@"Hello World!" dataUsingEncoding:NSUTF8StringEncoding];
    NSMutableData* encrypted = [NSMutableData dataWithLength:message.length + kCCBlockSizeAES128];
    size_t bytesEncrypted = 0;
    CCCrypt(kCCEncrypt,
            kCCAlgorithmAES128,
            kCCOptionPKCS7Padding,
            key.bytes,
            key.length,
            iv.bytes,
            message.bytes, message.length,
            encrypted.mutableBytes, encrypted.length, &bytesEncrypted);
    NSString* encrypted64 = [[NSMutableData dataWithBytes:encrypted.mutableBytes length:bytesEncrypted] base64EncodedStringWithOptions:0];
    NSLog(@"Encrypted : %@",encrypted64);

    // Decrypt base 64 into message again
    NSData* encryptedWithout64 = [[NSData alloc] initWithBase64EncodedString:encrypted64 options:0];
    NSMutableData* decrypted = [NSMutableData dataWithLength:encryptedWithout64.length + kCCBlockSizeAES128];
    size_t bytesDecrypted = 0;
    CCCrypt(kCCDecrypt,
            kCCAlgorithmAES128,
            kCCOptionPKCS7Padding,
            key.bytes,
            key.length,
            iv.bytes,
            encryptedWithout64.bytes, encryptedWithout64.length,
            decrypted.mutableBytes, decrypted.length, &bytesDecrypted);
    NSData* outputMessage = [NSMutableData dataWithBytes:decrypted.mutableBytes length:bytesDecrypted];
    NSString* outputString = [[NSString alloc] initWithData:outputMessage encoding:NSUTF8StringEncoding];
    NSLog(@"Decrypted : %@",outputString);

输出应该相同

    /*
        Hash : AEIHWLT/cTUfXdYJ+oai6sZ4tXlc4QQcYTbI9If/Moc=
        Key : WdHhJ19dSBURBA25HZSpbCJ4KnNEEgwzqjgyTBqa3eg=
        IV : ludWXFqwWeLOkmhutxiwHw==
        Encrypted : D3JpubesPMgQTiXbaoxAIw==
        Decrypted : Hello World!
    */

希望这篇文章能为其他人节省我浪费的时间 :)


它在我经历了那么多失败后拯救了我。我想为@Aku组织一场游行! - user1272965
谢谢你(是的,大写,因为我已经苦苦挣扎了几个小时)。 - tomidelucca
谢谢!比使用RNCryptor更好。 - Martijn Mellens

0
  1. 你确定两个库都使用了相同的密钥吗?你说你在 AESCrypt 中去掉了 SHA-256 部分,那么库现在如何使用密码参数呢?AES 算法只能使用长度为 16、24 或 32 字节的密钥。你的密码长度为 16 字节,但你是否在加密函数中将相应的参数更改为 128(而不是 256)? 你知道 CryptoJS 如何使用密钥参数吗?你确定它直接被使用了,还是在传递给底层原始 AES 加密函数之前进行了一些处理(例如哈希)?

  2. CryptoJS 库使用的是哪种加密模式?它的文档没有说明。考虑到它要求提供一个 IV,很可能是 CBC 模式,但你需要查看源代码才能确定。 AESCrypt 的文档声称使用 CBC 模式,但你没有在任何地方提供 IV。这必须意味着它在某个地方生成了自己的 IV,或者总是使用固定的 IV。(这在某种程度上破坏了 CBC 模式的目的,但这是另一个故事)。因此,你需要弄清楚 IV 到底是什么。

简而言之:除非你确保两个库使用相同的密钥和密钥长度、相同的模式和相同的IV,否则你将得到不同的密文。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接