1

我不确定我的解决方案有多安全。

Rob Napier有一个非凡的框架 ( RNCryptor ) 可以在 iOS 和其他系统中进行加密和解密。

据我所知,他正在使用AES-CBC,这实际上是 CommonCryptor.h 的标准

但是,我的要求迫使我使用AES-CTR。两者都非常相似,所以理论上它必须是简单的。但事实并非如此。

CommonCryptor.h 周围缺乏相关信息。它是有史以来最糟糕的解释框架之一。

CBC合作,您只需致电CCCrypt(). 但是,要使用CTR ,您应该调用: CCCrytorCreate(), CCCryptorUpdate(), CCCryptorFinal() 和CCCryptorRelease()

尝试加密我的数据时,我每次都收到不同的数据,当然解密它的结果不正确。

我在第一种方法中遇到了两个大问题:密钥的长度和写入 dataOut 的字节数。

我对问题进行了排序:

1.- 32 个字符的 NSString 键

NSString *key = @"1234567890ABCDEFGHIJKLMNOPQRSTUV";

2.- 以所需长度剪切 dataOut

最后这是我的加密和解密代码:

#import <CommonCrypto/CommonCryptor.h>
#import <CommonCrypto/CommonKeyDerivation.h>
#import <Security/Security.h>

+ (NSMutableData*) encryptString: (NSString*) stringToEncrypt withKey: (NSString*) keyString
{
//Key to Data
NSData *key = [keyString dataUsingEncoding:NSUTF8StringEncoding];

//String to encrypt to Data
NSData *data = [stringToEncrypt dataUsingEncoding:NSUTF8StringEncoding];

// Init cryptor
CCCryptorRef cryptor = NULL;

// Alloc Data Out
NSMutableData *cipherData = [NSMutableData dataWithLength:data.length + kCCBlockSizeAES128];

//Empty IV: initialization vector
NSMutableData *iv =  [NSMutableData dataWithLength:kCCBlockSizeAES128];

//Create Cryptor
CCCryptorStatus  create = CCCryptorCreateWithMode(kCCEncrypt,
                                                  kCCModeCTR,
                                                  kCCAlgorithmAES,
                                                  ccPKCS7Padding,
                                                  iv.bytes, // can be NULL, because null is full of zeros
                                                  key.bytes,
                                                  key.length,
                                                  NULL,
                                                  0,
                                                  0,
                                                  kCCModeOptionCTR_BE,
                                                  &cryptor);

if (create == kCCSuccess)
{
    //alloc number of bytes written to data Out
    size_t outLength;

    //Update Cryptor
    CCCryptorStatus  update = CCCryptorUpdate(cryptor,
                                              data.bytes,
                                              data.length,
                                              cipherData.mutableBytes,
                                              cipherData.length,
                                              &outLength);
    if (update == kCCSuccess)
    {
        //Cut Data Out with nedded length
        cipherData.length = outLength;

        //Final Cryptor
        CCCryptorStatus final = CCCryptorFinal(cryptor, //CCCryptorRef cryptorRef,
                                               cipherData.mutableBytes, //void *dataOut,
                                               cipherData.length, // size_t dataOutAvailable,
                                               &outLength); // size_t *dataOutMoved)

        if (final == kCCSuccess)
        {
            //Release Cryptor
            //CCCryptorStatus release =
            CCCryptorRelease(cryptor ); //CCCryptorRef cryptorRef
        }
        return cipherData;

    }



}
else
{
    //error

}

return nil;
}



+ (NSString*) decryptData: (NSData*) data withKey: (NSString*) keyString
{
//Key to Data
NSData *key = [keyString dataUsingEncoding:NSUTF8StringEncoding];

// Init cryptor
CCCryptorRef cryptor = NULL;

//Empty IV: initialization vector
NSMutableData *iv =  [NSMutableData dataWithLength:kCCBlockSizeAES128];

// Create Cryptor
CCCryptorStatus createDecrypt = CCCryptorCreateWithMode(kCCDecrypt, // operation
                                                        kCCModeCTR, // mode CTR
                                                        kCCAlgorithmAES, // Algorithm
                                                        ccPKCS7Padding, // padding
                                                        iv.bytes, // can be NULL, because null is full of zeros
                                                        key.bytes, // key
                                                        key.length, // keylength
                                                        NULL, //const void *tweak
                                                        0, //size_t tweakLength,
                                                        0, //int numRounds,
                                                        kCCModeOptionCTR_BE, //CCModeOptions options,
                                                        &cryptor); //CCCryptorRef *cryptorRef


if (createDecrypt == kCCSuccess)
{
    // Alloc Data Out
    NSMutableData *cipherDataDecrypt = [NSMutableData dataWithLength:data.length + kCCBlockSizeAES128];

    //alloc number of bytes written to data Out
    size_t outLengthDecrypt;

    //Update Cryptor
    CCCryptorStatus updateDecrypt = CCCryptorUpdate(cryptor,
                                                    data.bytes, //const void *dataIn,
                                                    data.length,  //size_t dataInLength,
                                                    cipherDataDecrypt.mutableBytes, //void *dataOut,
                                                    cipherDataDecrypt.length, // size_t dataOutAvailable,
                                                    &outLengthDecrypt); // size_t *dataOutMoved)

    if (updateDecrypt == kCCSuccess)
    {
        //Cut Data Out with nedded length
        cipherDataDecrypt.length = outLengthDecrypt;

        // Data to String
        NSString* cipherFinalDecrypt = [[NSString alloc] initWithData:cipherDataDecrypt encoding:NSUTF8StringEncoding];

        //Final Cryptor
        CCCryptorStatus final = CCCryptorFinal(cryptor, //CCCryptorRef cryptorRef,
                                               cipherDataDecrypt.mutableBytes, //void *dataOut,
                                               cipherDataDecrypt.length, // size_t dataOutAvailable,
                                               &outLengthDecrypt); // size_t *dataOutMoved)

        if (final == kCCSuccess)
        {
            //Release Cryptor
            //CCCryptorStatus release =
            CCCryptorRelease(cryptor); //CCCryptorRef cryptorRef
        }

        return cipherFinalDecrypt;
    }
}
    else
{
    //error

}

return nil;
}

调用它:

NSString *key = @"1234567890ABCDEFGHIJKLMNOPQRSTUV";
NSString *stringToEncrypt = @"Gabriel.Massana";

NSData* encrypted = [GM_AES128_CTR encryptString:stringToEncrypt withKey:key];

NSString *decrypted = [GM_AES128_CTR decryptData:encrypted withKey:key];

我发布我的解决方案是因为 Stackoverflow 中的 AES CTR 没有太多问题。同样,如果有人想检查它并告诉我是否有问题,将不胜感激。

我在 GitHub 中的示例

这个解决方案有多安全?破解系统容易吗?为 AES-CTR 添加更多安全性的可能性是什么?

4

1 回答 1

2

我将此列为单独的答案,但我只是在放大 Zaph 已经说过的话:

这是完全破坏的加密。

这件事发生在你身上并不奇怪。当您尝试构建自己的方案时,这是一个非常常见的问题。有很多地方你可以搞砸。但我不想低估这个方案的不安全性。它真的,真的坏了。

CTR 不能重复相同的 nonce+key,并且您每次都重复使用 nonce 这与CBC有很大不同。在 CBC 中,如果您重用 IV,那么您可以让攻击者更容易破解您的加密。在 CTR 中,如果你重用 nonce+key,一旦你有一些密文,就很容易解密消息。一些很好的讨论可以在RFC3686中找到。

正确使用时,AES-CTR 可提供高度机密性。不幸的是,AES-CTR 很容易被错误地使用。作为流密码,任何重复使用每个数据包的值,称为 IV,具有相同的随机数和密钥都是灾难性的。IV 冲突会立即泄露两个数据包中的明文信息。出于这个原因,不适合将这种操作模式与静态键一起使用。需要采取特殊措施来防止在电源周期内将 IV 值与静态密钥重复使用。为了安全起见,实现必须使用带有 AES-CTR 的新密钥。Internet 密钥交换 (IKE) [IKE] 协议可用于建立新密钥。IKE 还可以提供 nonce 值。

请注意,RNCryptor 最初使用 CTR。在与他们谈论搞砸 CTR 是多么容易之后,我在 Apple 的推荐下回到了 CBC。如果您可以避免点击率,那么您绝对应该这样做。它对于某些问题非常有用,但对于一般文件加密它很少适用。

也就是说,我知道你的芯片有问题。你的芯片将如何获得它的密钥?以这种方式在芯片上使用对称加密似乎很奇怪。无论如何,RNCryptor v1 可能会满足您的需求。您可能需要使用encryptFromStream:toStream:encryptionKey:HMACKey:error:,因为我认为该芯片无法处理 PBKDF2。

尝试加密我的数据时,我每次都收到不同的数据,当然解密它的结果不正确。

任何好的加密系统都会有这个属性。这就是为什么您需要将 nonce/IV(如果您使用密码,盐)与密文一起发送。

NSString *key = @"1234567890ABCDEFGHIJKLMNOPQRSTUV";

这不是钥匙。这是一个密码,会大大减少您的可用密钥空间。键通常是NSData因为需要从所有可能的值中选择它们,而不仅仅是 ASCII。

于 2014-06-19T17:40:00.990 回答