我在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哈希,但我已经删除了它,并且认为字符串编码存在一些不匹配。
我之所以在这里发布这篇文章,是因为肯定会有其他人试图对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);
使用CommonCrypto的iOS SDK
// 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!
*/
希望这能为其他人节省我浪费的时间:)
-
你确定两个库中使用的是同一个密钥吗?你说你去掉了AESCrypt中的SHA-256部分,库现在如何使用密码参数?AES算法只能使用长度为16、24或32字节的密钥。您的密码是16字节长,但您是否在加密函数中将相应的参数更改为128(而不是256)?你知道CryptoJS是如何使用密钥参数的吗?你确定它是直接使用的吗?或者在它被传递给底层原语AES加密函数之前可能会进行一些处理(例如哈希)?
-
CryptoJS库使用什么加密模式?它的文件没有说明。考虑到它要求静脉注射,它可能是CBC,但你必须查看来源才能确定。AESCrypt的文档声称使用CBC模式,但你不会在任何地方给它IV。这一定意味着它在某个地方生成自己的,或者总是使用固定的。(哪一半违背了CBC模式的目的,但那是另一回事)。所以你需要弄清楚IV到底是什么。
TL;DR:除非你确保在两个库中使用相同的密钥和密钥长度、相同的模式和相同的IV,否则你会有不同的密文。