【问题标题】:iPhone - Decrypting an AES-encrypted message with a different key than the one used to encryptiPhone - 使用与用于加密的密钥不同的密钥解密 AES 加密的消息
【发布时间】:2011-12-06 18:33:30
【问题描述】:

我只是在 iPhone 上使用 CCrypt 编写基本的“加密”和“解密”方法。

我一直在运行一些测试,我真的很惊讶地发现,有时,如果您尝试使用与用于加密纯文本的密钥不同的密钥来解密加密文本,CCrypt 不会返回任何错误。

这是一个例子:

- (void) testDecryptTextWithTheWrongKey {
    NSData *encryptKey = [Base64 decodeBase64WithString:@"+LtNYThpgIlQs2CaL00R6AuG2C/i6U1Vt1+6wfFeFMk="];
    NSData *decryptKey = [Base64 decodeBase64WithString:@"yg7BvhM8npVGpAFpAESDn3IRWpe6qeQWaa1rwHiTsyU="];

    NSString *plainText = @"The text to be encrypted";
    NSData *plainTextData = [plainText dataUsingEncoding:NSUTF8StringEncoding];

    NSError *error = nil;
    NSData *encrypted = [LocalCrypto encryptText:plainTextData key:encryptKey error:&error];

    assertThat(error, nilValue());
    assertThat(encrypted, notNilValue());

    error = nil;
    NSData *decrypted = [LocalCrypto decryptText:encrypted key:decryptKey error:&error];

    assertThat(error, notNilValue());
    assertThat(decrypted, nilValue());
}

我在 LocalCrypto 中定义的加密和解密方法只是调用了一个内部“executeCryptoOperation”方法,表明他们想要加密或解密:

+ (NSData *) executeCryptoOperation:(CCOperation)op key:(NSData *) key input:(NSData *) input error:(NSError **)error {
    size_t outLength;
    NSMutableData *output = [NSMutableData dataWithLength:input.length + kCCBlockSizeAES128];

    CCCryptorStatus result = CCCrypt(op,                    // operation
                                     kCCAlgorithmAES128,    // Algorithm
                                     kCCOptionPKCS7Padding | kCCOptionECBMode, // options
                                     key.bytes,             // key
                                     key.length,            // keylength
                                     nil,                   // iv
                                     input.bytes,           // dataIn
                                     input.length,          // dataInLength,
                                     output.mutableBytes,   // dataOut
                                     output.length,         // dataOutAvailable
                                     &outLength);           // dataOutMoved

    if (result == kCCSuccess) {
        output.length = outLength;
    } else {
        *error = [NSError errorWithDomain:kCryptoErrorDomain code:result userInfo:nil];
        return nil;
    }

    return output;
}

好吧,我的问题是:当我们尝试使用与加密期间使用的密钥不同的密钥解密加密文本时,CCrypt 返回 kCCSuccess 是否正常?我错过了什么或做错了什么?

确实,即使 CCrypt 返回解密成功,我也无法从结果数据中获得正确的 NSString,但我当然希望 CCrypt 在这种情况下返回某种错误(Java 可能会这样做) )。

如果这是正常行为,我应该如何知道解密操作返回的是真正的纯文本还是只是一堆没有任何意义的字节?

这里有一个类似的问题,但答案并不能真正说服我:Returning wrong decryption text when using invalid key

谢谢!

【问题讨论】:

  • 链接问题中的答案非常有意义。只要你的密钥符合要求,就用来解密加密的字符串,没有出现错误。它应该如何以及为什么要知道解密后的文本应该是什么样子?
  • 我明白你的意思,它确实有道理。让我感到困惑的是,如果我在 Java 中运行相同的测试(用一个密钥加密并用另一个密钥解密),我在解密过程中会遇到异常(更具体的是 BadPaddingException)......关于原因的任何想法Java“检测到”出现了问题而 iOS 没有?

标签: iphone objective-c cocoa encryption aes


【解决方案1】:

有些密码算法包含填充(如您的 Java 实现中的 PKCS#5 填充),有些则不包含。

如果您的加密算法使用填充,则相应的解密算法预计解密后的明文中也会有格式正确的填充。这是一种廉价的部分完整性检查,因为使用错误的密钥,输出可能不会有正确的填充。 (随机 n 字节块(对于 AES,n=16)具有有效 PKCS#5 填充的概率为 1/256 + 1/(256^2) + ... + 1/(256^n),仅略高于 1/256。)

可能是你的 Objective-C CCCrypt 函数不检查填充是否有效,只检查它的最后一个字节(或者甚至只检查最后一个字节的一些位),查看填充了多少字节(并且是现在被切断)。

如果您想确定密钥是正确的,请加密明文的某些已知部分,如果它不在解密部分中,则出错。 (但不要在 ECB 模式下这样做,见下文。)

如果您还想确保数据未被修改,也可以使用MAC,或使用组合的authenticated encryption mode of operation 作为分组密码。

另一个注意事项:您不应使用 ECB 模式,而应使用安全的 mode of operation(关于本文中指出并由您的实施支持的任何其他模式都可以 - 现在的标准是 CBC 或 CTR模式)。某些模式(如 CFB、OFB 和 CTR)根本不需要填充。

【讨论】:

    【解决方案2】:

    您错过了解密函数不知道明文(解密数据)应该是什么样子的事实。

    就解密函数而言,它从您那里获得了一个密钥和一个密文,使用您提供的密钥将解密例程应用于密文,并且没有出现错误。因此,成功。

    您的工作是验证您获得的明文实际上是否正确/符合您预期的格式。

    【讨论】:

    • 我明白你的意思,它确实有道理。让我感到困惑的是,如果我在 Java 中运行相同的测试(用一个密钥加密并用另一个密钥解密),我在解密过程中会遇到异常(更具体的是 BadPaddingException)......关于原因的任何想法Java“检测到”出现了问题而 iOS 没有?
    • 填充的允许格式很少。不正确的键不太可能在最后一个块的末尾产生正确的填充。您的解密方法期望的填充是什么?
    • 在 Java 中,我使用的填充方案是 PKCS#5
    • 我猜这与Java中的具体实现有关。您可以使用您正在使用的确切 java 方法更新您的问题,最好使用文档链接。
    猜你喜欢
    • 1970-01-01
    • 2017-11-08
    • 1970-01-01
    • 1970-01-01
    • 2019-01-14
    • 1970-01-01
    • 2012-02-21
    • 2022-01-28
    • 2012-07-20
    相关资源
    最近更新 更多