使用给定密钥在iOS中使用AES128 CTR加密和解密随机NSString

时间:2014-06-18 16:09:09

标签: ios objective-c encryption aes rncryptor

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

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

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

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

CommonCryptor.h缺乏信息。这是有史以来解释最糟糕的框架之一。

使用 CBC ,您只需致电CCCrypt()即可。但是,要使用点击率 you should callCCCrytorCreate()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没有太多问题。同样,如果有人想检查它并告诉我是否有问题将非常感激。

My example in GitHub

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

1 个答案:

答案 0 :(得分:2)

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

这是完全破解的加密。

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

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

  

如果使用正确,AES-CTR提供高水平的      保密。不幸的是,AES-CTR很容易错误使用。      作为流密码,任何重用的每个数据包的值,称为      四,具有相同的随机数和关键是灾难性的。 IV碰撞      立即泄漏两个数据包中有关明文的信息。      因此,使用这种操作模式是不合适的      用静态键。需要采取特别措施来防止这种情况发生      在电力循环中使用静态密钥重用IV值。成为      安全,实现必须使用带有AES-CTR的新密钥。互联网      密钥交换(IKE)[IKE]协议可用于建立新鲜      键。 IKE还可以提供nonce值。

请注意RNCryptor originally used CTR。在与他们讨论了如何轻松搞砸点击率之后,我根据Apple的推荐回到了CBC。如果你可以避免点击率,你绝对应该。它对某些问题非常有用,但对于一般的文件加密,它很少适用。

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

  

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

任何好的加密系统都会拥有此属性。这就是为什么你需要发送你的随机数/ IV(如果你使用密码,盐)和密文。

  

NSString * key = @“1234567890ABCDEFGHIJKLMNOPQRSTUV”;

这不是关键。这是一个密码,可以显着减少您的可用密钥空间。密钥通常为NSData,因为需要选择所有可能的值,而不仅仅是ASCII。