【问题标题】:AES 128 GCM objective C osxAES 128 GCM 物镜 C osx
【发布时间】:2016-12-19 04:48:57
【问题描述】:

我正在尝试在目标 c 中加密/解密 AES-128 GCM 格式的字符串。我到处寻找,但似乎找不到有效的解决方案。

【问题讨论】:

    标签: objective-c macos encryption aes aes-gcm


    【解决方案1】:

    不久前我遇到了类似的问题,我能找到的最佳答案是this one。总而言之,iOS 有一些功能可以做你想做的,但它们是私有的。

    因此,在 Apple 决定发布这些功能之前,我选择开发自己的库,目前存储在 GitHub 并在 CocoaPods 中可用。

    你描述的情况可以这样实现:

    #import <CommonCrypto/CommonCrypto.h>
    #import "IAGAesGcm.h"
    
    // For the case you describe, the key length is 128 bits (16 bytes)
    u_char keyBytes[kCCKeySizeAES128] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10};
    NSData *key = [NSData dataWithBytes:keyBytes length:sizeof(keyBytes)];
    
    // GCM recommends a IV size of 96 bits (12 bytes), but you are free
    // to use other sizes
    u_char ivBytes[12] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C};
    NSData *iv = [NSData dataWithBytes:ivBytes length:sizeof(ivBytes)];
    
    NSData *aad = [@"AdditionalAuthenticatedData" dataUsingEncoding:NSUTF8StringEncoding];
    
    // Authenticated Encryption Function
    NSData *expectedPlainData = [@"PlainData" dataUsingEncoding:NSUTF8StringEncoding];
    
    // The returned ciphered data is a simple class with 2 properties: the actual encrypted data and the authentication tag.
    // The authentication tag can have multiple sizes and it is up to you to set one, in this case the size is 128 bits
    // (16 bytes)
    IAGCipheredData *cipheredData = [IAGAesGcm cipheredDataByAuthenticatedEncryptingPlainData:expectedPlainData
                                                              withAdditionalAuthenticatedData:aad
                                                                      authenticationTagLength:IAGAuthenticationTagLength128
                                                                         initializationVector:iv
                                                                                          key:key
                                                                                        error:nil];
    
    // Authenticated Decryption Function
    NSData *plainData = [IAGAesGcm plainDataByAuthenticatedDecryptingCipheredData:cipheredData
                                                  withAdditionalAuthenticatedData:aad
                                                             initializationVector:iv
                                                                              key:key
                                                                            error:nil];
    
    XCTAssertEqualObjects(expectedPlainData, plainData);
    

    希望此代码对您有所帮助。

    最后(感谢zaph 提到这一点),我没有对这段代码进行任何基准测试,所以假设它是。我打算用它来破译 JWE 字符串中的令牌,而且我只是不时地不推荐比这更需要的东西。

    问候。

    【讨论】:

    • 请注意,Apple AES-GCM 有点脑残,它不处理相关数据。甚至苹果公司也承认这是一个糟糕的实现,只能满足他们的使用要求。顺便说一句,你有任何基准吗?
    • 我不知道,非常感谢您提供的信息。好吧,尽管如此,这是一次学习体验:)。关于性能,我在 repo 中链接了this document,它指出了一种实现该算法的有效方法……这不是我编码它的方式,我更关心编写易于调试的代码。所以,性能必须不是很好
    • 干得好,代码看起来很棒。不幸的是,对我来说,只是让一个示例示例运行是我想要花费的更多工作。整个 podfile 事情需要我一个小时左右才能弄清楚并更新所有内容。
    • 嗨 Zaph,感谢您的反馈,但我有点困惑,我没有找到您提到的问题。我的意思是,如果您尝试以下步骤: 1. git clone git@github.com:indisolvent/AesGcm.git 2. cd AesGcm/Example/ 3. xcodebuild test -workspace AesGcm.xcworkspace -scheme AesGcm-Example -destination 'platform= iOS Simulator,name=iPhone SE,OS=10.0' 你收到上面提到的错误了吗?提前致谢。
    【解决方案2】:
    /*
     typical GCM use case: sending an authenticated packet
    
     +--------------+-------+--------------+
     |    header    |  seq. |   Data       |
     +--------------+-------+--------------+
            |           |         |
            |           |         |
     Addtl auth data   IV     plain text
            |           |         |
            |           |         V
            |           |     +--------------------+
            |           +---->|                    |
            |           |     | GCM encryption     |
            +---------------->|                    |
            |           |     +--------------------+
            |           |         |            |
            |           |     cipher text    Auth tag
            |           |         |            |
            V           V         V            V
     +--------------+-------+----------------+---------+
     |    header    |  seq. | encrypted data |   ICV   |
     +--------------+-------+----------------+---------+
     */
    
    #define CCCryptorGCMprologue()   CCCryptor *cryptor = getRealCryptor(cryptorRef, 0); \
    CC_DEBUG_LOG("Entering\n"); \
    if(!cryptor) return kCCParamError;
    
    static inline CCCryptorStatus translate_err_code(int err)
    {
        if (err==0) {
            return kCCSuccess;
        } /*else if(err == CCMODE_INVALID_CALL_SEQUENCE){ //unti we can read error codes from corecrypto
            return kCCCallSequenceError;
        } */ else {
            return kCCUnspecifiedError;
        }
    
    }
    
    CCCryptorStatus
    CCCryptorGCMAddIV(CCCryptorRef cryptorRef,
                      const void        *iv,
                      size_t ivLen)
    {
        CCCryptorGCMprologue();
        if(ivLen!=0 && iv==NULL) return kCCParamError;
        //it is okay to call with ivLen 0 and/OR iv==NULL
        //infact this needs to be done even with NULL values, otherwise ccgcm_ is going to return call sequence error.
        //currently corecrypto accepts NULL
        //rdar://problem/23523093
        int rc = ccgcm_set_iv_legacy(cryptor->symMode[cryptor->op].gcm,cryptor->ctx[cryptor->op].gcm, ivLen, iv);
        return translate_err_code(rc);
    
    }
    
    //Add additional authentication data
    CCCryptorStatus
    CCCryptorGCMAddAAD(CCCryptorRef cryptorRef,
                       const void       *aData,
                       size_t aDataLen)
    {
        CCCryptorGCMprologue();
        if(aDataLen!=0 && aData==NULL) return kCCParamError;
        //it is okay to call with aData zero
        int rc = ccgcm_gmac(cryptor->symMode[cryptor->op].gcm,cryptor->ctx[cryptor->op].gcm, aDataLen, aData);
        return translate_err_code(rc);
    }
    
    // This is for old iOS5 clients
    CCCryptorStatus
    CCCryptorGCMAddADD(CCCryptorRef cryptorRef,
                       const void       *aData,
                       size_t aDataLen)
    {
        return  CCCryptorGCMAddAAD(cryptorRef, aData, aDataLen);
    }
    
    // This was a temp mistake in MacOSX8
    CCCryptorStatus
    CCCryptorGCMaddAAD(CCCryptorRef cryptorRef,
                       const void       *aData,
                       size_t aDataLen)
    {
        return CCCryptorGCMAddAAD(cryptorRef, aData, aDataLen);
    }
    
    //we are not providing this function to users.
    //The reason is that we don't want to create more liability for ourself
    //and a new interface function just increases the number of APIs
    //without actually helping users
    //User's use the old CCCryptorGCMEncrypt() and CCCryptorGCMDecrypt()
    static CCCryptorStatus gcm_update(CCCryptorRef cryptorRef,
                                              const void *dataIn,
                                              size_t dataInLength,
                                              void *dataOut)
    {
        CCCryptorGCMprologue();
        if(dataInLength!=0 && dataIn==NULL) return kCCParamError;
        //no data is okay
        if(dataOut == NULL) return kCCParamError;
        int rc = ccgcm_update(cryptor->symMode[cryptor->op].gcm,cryptor->ctx[cryptor->op].gcm, dataInLength, dataIn, dataOut);
        return translate_err_code(rc);
    }
    
    
    CCCryptorStatus CCCryptorGCMEncrypt(CCCryptorRef cryptorRef,
                                        const void *dataIn,
                                        size_t dataInLength,
                                        void *dataOut)
    {
        return gcm_update(cryptorRef, dataIn, dataInLength, dataOut);
    
    }
    
    
    
    CCCryptorStatus CCCryptorGCMDecrypt(CCCryptorRef cryptorRef,
                                        const void *dataIn,
                                        size_t dataInLength,
                                        void *dataOut)
    {
        return gcm_update(cryptorRef, dataIn, dataInLength, dataOut);
    }
    
    
    CCCryptorStatus CCCryptorGCMFinal(CCCryptorRef cryptorRef,
                                      void   *tagOut,
                                      size_t *tagLength)
    {
        CCCryptorGCMprologue();
        if(tagOut == NULL || tagLength == NULL)  return kCCParamError;
        int rc = ccgcm_finalize(cryptor->symMode[cryptor->op].gcm,cryptor->ctx[cryptor->op].gcm, *tagLength, (void *) tagOut);
        if(rc == -1)
            return kCCUnspecifiedError;
        else
            return kCCSuccess; //this includes 0 and any error message other than -1
    
       // ccgcm_finalize() returns CCMODE_INTEGRITY_FAILURE (-3) if the expected tag is not coppied to the buffer. but that doesn't mean there is an error
    }
    
    
    CCCryptorStatus CCCryptorGCMReset(CCCryptorRef cryptorRef)
    {
        CCCryptorGCMprologue();
        int rc = ccgcm_reset(cryptor->symMode[cryptor->op].gcm,cryptor->ctx[cryptor->op].gcm);
        return translate_err_code(rc);
    }
    
    CCCryptorStatus CCCryptorGCM(CCOperation op,                /* kCCEncrypt, kCCDecrypt */
                                 CCAlgorithm alg,
                                 const void  *key,    size_t keyLength, /* raw key material */
                                 const void  *iv,     size_t ivLen,
                                 const void  *aData,  size_t aDataLen,
                                 const void  *dataIn, size_t dataInLength,
                                 void        *dataOut,
                                 void        *tagOut,    size_t *tagLength)
    
    {
        CCCryptorRef cryptorRef;
        CCCryptorStatus retval;
    
        CC_DEBUG_LOG("Entering Op: %d Cipher: %d\n", op, alg);
    
        retval = CCCryptorCreateWithMode(op, kCCModeGCM, alg, 0, NULL, key, keyLength,
                                             NULL, 0, 0, 0, &cryptorRef);
        if(retval) return retval;
    
        //call even with NULL pointer and zero length IV
        retval = CCCryptorGCMAddIV(cryptorRef, iv, ivLen);
        if(retval) return retval;
    
        retval = CCCryptorGCMaddAAD(cryptorRef, aData, aDataLen);
        if(retval) return retval;
    
        retval = gcm_update(cryptorRef, dataIn, dataInLength, dataOut);
        if(retval) return retval;
    
        retval = CCCryptorGCMFinal(cryptorRef, tagOut, tagLength);
        CCCryptorRelease(cryptorRef);
    
        return retval;
    }
    

    【讨论】:

      猜你喜欢
      • 2013-07-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-12-21
      • 2013-01-16
      • 2018-01-08
      • 2015-03-10
      • 1970-01-01
      相关资源
      最近更新 更多