AES 128 GCM目标C osx

时间:2016-08-12 08:32:08

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

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

2 个答案:

答案 0 :(得分:0)

不久前我遇到了类似的问题,我能找到的最佳答案是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字符串中的令牌,并且只是不时,我不建议要求更多的东西。

问候。

答案 1 :(得分:0)

/*
 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;
}