Javascript AES加密与iOS AES加密不匹配 [英] Javascript AES encryption doesn't match iOS AES encryption

查看:712
本文介绍了Javascript AES加密与iOS AES加密不匹配的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

 

我正在加密iOS中的 NSString code> NSString * stringtoEncrypt = @此字符串要加密;
NSString * key = @12345678901234567890123456789012;

//编码
NSData * plain = [stringtoEncrypt dataUsingEncoding:NSUTF8StringEncoding];
NSData * cipher = [plain AES256EncryptWithKey:key];

NSString * cipherBase64 = [cipher base64EncodedString];
NSLog(@ciphered base64:%@,cipherBase64);

//解码
NSData * decipheredData = [cipherBase64 base64DecodedData];
NSString * decoded = [[NSString alloc] initWithData:[decipheredData AES256DecryptWithKey:key] encoding:NSUTF8StringEncoding];
NSLog(@%@,解码);

NSData扩展名:

   - (NSData的*)AES256EncryptWithKey:(的NSString *)键
{
// '钥匙' 应该是AES256 32个字节,将空填充否则
炭keyPtr [kCCKeySizeAES256 + 1]; //用于终结器的空间(未使用)
bzero(keyPtr,sizeof(keyPtr)); //填充零(用于填充)

//获取密钥数据
[key getCString:keyPtr maxLength:sizeof(keyPtr)encoding:NSUTF8StringEncoding];

NSUInteger dataLength = [self length];

//查看文档:对于块密码,输出大小始终小于或等于输入大小加上一个块的大小。
//这就是为什么我们需要在这里添加一个块的大小
size_t bufferSize = dataLength + kCCBlockSizeAES128;
void * buffer = malloc(bufferSize);

size_t numBytesEncrypted = 0;
CCCryptorStatus cryptStatus = CCCrypt(kCCEncrypt,kCCAlgorithmAES128,kCCOptionPKCS7Padding,
keyPtr,kCCKeySizeAES256,
NULL / *初始化向量(可选)* /,
[自字节],数据长度,/ * input * /
buffer,bufferSize,/ * output * /
& numBytesEncrypted);
如果(cryptStatus == kCCSuccess){
//返回的NSData取缓冲器的所有权,将释放其上解除分配
返回[NSData的dataWithBytesNoCopy:缓冲区长度:numBytesEncrypted];
}

free(buffer); //释放缓冲区;
return nil;
}

我可以成功地将生成的Base64字符串传递给 Node .js 并对其进行解码。我还需要的是与 Javascript 中编写的相同的编码方法。
这是我迄今为止所做的:

 < script src =http:// crypto-js。 googlecode.com/svn/tags/3.1.2/build/rollups/aes.js\"></script> 
...
var text =此字符串要加密;
var key =12345678901234567890123456789012;
var iv ='\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00 \x00\x00' ;
var encrypted = CryptoJS.AES.encrypt(text,key,{iv:iv});
console.log(Base64 encoded:+ window.btoa(encrypted.ciphertext));

然而,生成的Base64字符串与iOS生成的字符串不匹配。
任何想法?

解决方案

当您将字符串作为密钥传递时,CryptoJS使用与OpenSSL兼容的基于密码的加密。既然你已经有一个完整的键和IV,你需要将它们转换成CryptoJS的本机类型,这是一个WordArray:

  var key = CryptoJS.enc.Utf8.parse(12345678901234567890123456789012); 
var iv = CryptoJS.lib.WordArray.create([0,0,0,0]); //每个数字是一个32位的字b

通过调用 btoa() 在WordArray对象上,您强制将其绑定到字符串。为此使用默认的十六进制编码。之后 btoa()将这个十六进制编码的字符串编码到Bas64中,这样会更加膨胀。



您可以直接编码一个WordArray into Base64:

  encrypted.ciphertext.toString(CryptoJS.enc.Base64)


I am encrypting an NSString in iOS like this which encodes and decodes fine:

NSString *stringtoEncrypt = @"This string is to be encrypted";
NSString *key = @"12345678901234567890123456789012";

// Encode
NSData *plain = [stringtoEncrypt dataUsingEncoding:NSUTF8StringEncoding];
NSData *cipher = [plain AES256EncryptWithKey:key];

NSString *cipherBase64 = [cipher base64EncodedString];
NSLog(@"ciphered base64: %@", cipherBase64);

// Decode
NSData *decipheredData = [cipherBase64 base64DecodedData];
NSString *decoded = [[NSString alloc] initWithData:[decipheredData AES256DecryptWithKey:key] encoding:NSUTF8StringEncoding];
NSLog(@"%@", decoded);

NSData extension:

- (NSData *)AES256EncryptWithKey:(NSString *)key
{
    // 'key' should be 32 bytes for AES256, will be null-padded otherwise
    char keyPtr[kCCKeySizeAES256+1]; // room for terminator (unused)
    bzero(keyPtr, sizeof(keyPtr)); // fill with zeroes (for padding)

    // fetch key data
    [key getCString:keyPtr maxLength:sizeof(keyPtr) encoding:NSUTF8StringEncoding];

    NSUInteger dataLength = [self length];

    //See the doc: For block ciphers, the output size will always be less than or
    //equal to the input size plus the size of one block.
    //That's why we need to add the size of one block here
    size_t bufferSize = dataLength + kCCBlockSizeAES128;
    void *buffer = malloc(bufferSize);

    size_t numBytesEncrypted = 0;
    CCCryptorStatus cryptStatus = CCCrypt(kCCEncrypt, kCCAlgorithmAES128, kCCOptionPKCS7Padding,
                                          keyPtr, kCCKeySizeAES256,
                                          NULL /* initialization vector (optional) */,
                                          [self bytes], dataLength, /* input */
                                          buffer, bufferSize, /* output */
                                          &numBytesEncrypted);
    if (cryptStatus == kCCSuccess) {
        //the returned NSData takes ownership of the buffer and will free it on deallocation
        return [NSData dataWithBytesNoCopy:buffer length:numBytesEncrypted];
    }

    free(buffer); //free the buffer;
    return nil;
}

I can successfully pass the resulting Base64 string to Node.js and have it decode the message. What I also need, is the same encoding method written in Javascript. Here is what I have so far:

<script src="http://crypto-js.googlecode.com/svn/tags/3.1.2/build/rollups/aes.js"></script>
...
var text = "This string is to be encrypted";
var key = "12345678901234567890123456789012";
var iv  = '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00';
var encrypted = CryptoJS.AES.encrypt(text, key, {iv: iv});
console.log("Base64 encoded: " + window.btoa(encrypted.ciphertext));

However the resulting Base64 string does not match the one generated by iOS. Any ideas?

解决方案

CryptoJS uses a password-based encryption compatible with OpenSSL when you pass a string as a key. Since you already have a full key and IV, you need to convert them into CryptoJS' native type which is a WordArray:

var key = CryptoJS.enc.Utf8.parse("12345678901234567890123456789012");
var iv  = CryptoJS.lib.WordArray.create([0, 0, 0, 0]); // each number is a word of 32 bit

By calling btoa() on a WordArray object, you're forcing it to the stringified. The default hex-encoding is used for this. Afterwards btoa() encodes this hex-encoded string into Bas64 which bloats it even more.

You can directly encode a WordArray into Base64:

encrypted.ciphertext.toString(CryptoJS.enc.Base64)

这篇关于Javascript AES加密与iOS AES加密不匹配的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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