首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >在目标C中解密SJCL密码文本

在目标C中解密SJCL密码文本
EN

Stack Overflow用户
提问于 2016-04-07 15:37:17
回答 1查看 389关注 0票数 0

我正在接收用SJCL加密到iOS应用程序中的数据,在那里我需要解密它。另一端是使用带有AES CCM模式的SJCL,苹果的CommonCrypto不支持这种模式,因此我使用VPCCMCrypt库。无法对发送SJCL密码文本的另一方进行任何更改。

下面是我的解密方法:

代码语言:javascript
复制
+ (NSData *)decryptSjcl:(NSDictionary *)cipher password:(NSString *)password {
    if (cipher == nil || password == nil) {
        return nil;
    }

    int version = [cipher[@"v"] intValue];
    NSString *iv = cipher[@"iv"];
    uint iter = [cipher[@"iter"] unsignedIntValue];
    uint ks = [cipher[@"ks"] unsignedIntValue];
    uint ts = [cipher[@"ts"] unsignedIntValue];
    NSString *mode = cipher[@"mode"];
    NSString *adata = cipher[@"adata"];
    NSString *algorithm = cipher[@"cipher"];
    NSString *salt = cipher[@"salt"];
    NSString *ct = cipher[@"ct"];

    if (version != 1 || ! [@"aes" isEqualToString:algorithm]) {
        return nil;
    }

    NSData *rawIv = [[NSData alloc] initWithBase64EncodedString:iv options:0];
    NSData *rawSalt = [[NSData alloc] initWithBase64EncodedString:salt options:0];
    NSData *rawAdata = [[NSData alloc] initWithBase64EncodedString:adata options:0];
    NSData *cipherData = [[NSData alloc] initWithBase64EncodedString:ct options:0];
    NSData *key;

    NSMutableData *decipheredData = nil;

    if ([@"ccm" isEqualToString:mode]) {
        key = [Cryptor sjclAesKeyForPassword:password salt:rawSalt iterations:iter keySize:ks];
        decipheredData = [Cryptor decryptAesCcmData:cipherData iv:rawIv key:key adata:rawAdata tagSize:ts];
    }

    return decipheredData;
}

SJCL密钥生成:

代码语言:javascript
复制
+ (NSData *)sjclAesKeyForPassword:(NSString *)password salt:(NSData *)salt iterations:(uint)iterations keySize:(uint)keySizeBits {
    NSMutableData *derivedKey = [NSMutableData dataWithLength:keySizeBits / 8];

    int result = CCKeyDerivationPBKDF(kCCPBKDF2,
            password.UTF8String,
            [password lengthOfBytesUsingEncoding:NSUTF8StringEncoding],
            salt.bytes,
            salt.length,
            kCCPRFHmacAlgSHA256,
            iterations,
            derivedKey.mutableBytes,
            derivedKey.length);

    NSAssert(result == kCCSuccess, @"Unable to create AES key for password: %d", result);

    return derivedKey;
}

AES CCM解密:

代码语言:javascript
复制
+ (NSMutableData *)decryptAesCcmData:(NSData *)cipherData iv:(NSData *)iv key:(NSData *)key adata:(NSData *)adata tagSize:(uint)tagSizeBits {
    VPCCMCrypt *ccm = [[VPCCMCrypt alloc] initWithKey:key
                                                   iv:iv
                                                adata:adata
                                            tagLength:tagSizeBits / 8];

    [ccm decryptDataWithData:cipherData
               finishedBlock:^(NSData *data) {
                   NSString *result = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];

                   NSLog(@"Decrypted SJCL message: %@", result);
               }
                  errorBlock:^(NSError *error) {
                      NSLog(@"ERROR");
                  }];

    return nil;
}

SJCL中的所有输入数据都被正确地解析(IV、salt、key大小、标记大小、PBKDF迭代、密码文本),并从它们的NSData编码表示形式解码到SJCL。密码使用相同。所有数据(包括创建的AES键)都不是零。

最后,它在VPCCMCrypt内部失败,验证CCM标记(标记不同)。上面的代码有什么问题吗?还有其他iOS/Objective/Swift库可以解密AES、CCM或更好的SJCL吗?我对SJCL库的JavaScript包装不感兴趣。

为了进行测试,我使用了来自SJCL演示页面的简单加密数据。

编辑:

正如注释中所述,SJCL为CCM模式发送16字节IV而不是最大12字节,然后在内部解密时将其锁定为最大12字节。以下是更新的解密方法:

代码语言:javascript
复制
+ (NSData *)decryptSjcl:(NSDictionary *)cipher password:(NSString *)password {
    if (cipher == nil || password == nil) {
        return nil;
    }

    int version = [cipher[@"v"] intValue];
    NSString *iv = cipher[@"iv"];
    uint iter = [cipher[@"iter"] unsignedIntValue];
    uint ks = [cipher[@"ks"] unsignedIntValue];
    uint ts = [cipher[@"ts"] unsignedIntValue];
    NSString *mode = cipher[@"mode"];
    NSString *adata = cipher[@"adata"];
    NSString *algorithm = cipher[@"cipher"];
    NSString *salt = cipher[@"salt"];
    NSString *ct = cipher[@"ct"];

    if (version != 1 || ! [@"aes" isEqualToString:algorithm]) {
        return nil;
    }

    NSMutableData *rawIv = [[NSMutableData alloc] initWithBase64EncodedString:iv options:0];
    NSMutableData *rawSalt = [[NSMutableData alloc] initWithBase64EncodedString:salt options:0];
    NSMutableData *rawAdata = [[NSMutableData alloc] initWithBase64EncodedString:adata options:0];
    NSMutableData *cipherData = [[NSMutableData alloc] initWithBase64EncodedString:ct options:0];
    NSData *key;

    NSData *decipheredData = nil;

    if ([@"ccm" isEqualToString:mode]) {
        key = [Cryptor sjclAesKeyForPassword:password salt:rawSalt iterations:iter keySize:ks];

        // Clamp the SJCL IV - They use a 16 byte IV for CCM mode which is against specification and they do a funky
        // clamping. CCM mode IV should be max 13 bytes long. They almost always clamp it to 13 bytes but save the whole
        // 16 bytes in their JSON container.
        // for (L=2; L<4 && ol >>> 8*L; L++) {}
        // if (L < 15 - ivl) { L = 15-ivl; }
        // iv = w.clamp(iv,8*(15-L));
        int64_t ivl = rawIv.length;
        int64_t ol = cipherData.length - (ts / 8);
        int64_t L = 2;
        for (L = 2; L < 4 && ol >> 8*L; L++) {}
        if (L < 15 - ivl) {
            L = 15 - ivl;
        }
        NSRange subrange = NSMakeRange(0, (NSUInteger)(15 - L));

        decipheredData = [Cryptor decryptAesCcmData:cipherData iv:[rawIv subdataWithRange:subrange] key:key adata:rawAdata tagSize:ts];
    }
    else {
        decipheredData = nil;
    }

    return decipheredData;
}

最后一个缺失的事情是验证标签,我无法做到这一点。有什么想法吗?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2016-04-20 14:14:09

SJCL没有在AES-CCM模式下使用整个(128/192/256位) IV,但演示页面显示了它。尝试使用较少的字节。

在这里您可以找到IV长度计算的工作方式:ccm.js.html

代码语言:javascript
复制
for (L=2; L<4 && ol >>> 8*L; L++) {}
if (L < 15 - ivl) { L = 15-ivl; }
iv = w.clamp(iv,8*(15-L));
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/36480942

复制
相关文章

相似问题

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