[Objective-c] AES128 암호화, 복호화 (AES128 Encrypt, Decrypt)

[Objective-c] AES128 암호화, 복호화 (AES128 Encrypt, Decrypt)

Objective-c 에서 AES128 로 암호화, 복호화하는 방법을 작성했다.

구글에 검색해보면 보통 NSData+AES.h 파일과 NSData+AES.m 파일이 나오는데, 막상 암호화와 복호화를 사용하는 예제가 부실해서 활용하기가 좋지 않았다.

검색을 거듭해서 AESExtention.h, AESExtention.m 이라는 파일을 찾았고, 쓸만해보여서 해당 코드를 기반으로 전체적으로 수정, 보완했다.

(1) AESExtension.h, AESExtension.m 이라고 파일명을 변경했다(Extention 은 오타로 판단됨. Extension 이 맞는 철자임)

(2) Hex 값으로만 암호화, 복호화할 수 있었던 코드였는데 Base64 로 암호화, 복호화할 수 있는 메서드를 추가했다.

(3) 기존 소스코드는 ECB 방식으로 되어있었는데, iv 값을 사용하는 CBC 방식으로 수정했다.

(4) 기타 코드를 전체적으로 수정, 보완했다.

1. 새 파일 작성 (Make new files)

1-1. AESExtension.h

#import <Foundation/Foundation.h>

#import <CommonCrypto/CommonCryptor.h>

@interface AESExtension : NSObject

– (NSString *) aesEncryptNSData🙁NSString *)textString;

– (NSString *) aesEncryptHexString🙁NSString *)textString;

– (NSString *) aesEncryptBase64🙁NSString *)textString;

– (NSString *) aesDecryptNSData🙁NSString *)textString;

– (NSString *) aesDecryptHexString🙁NSString *)textString;

– (NSString *) aesDecryptBase64🙁NSString *)textString;

– (NSData *) AES128Encrypt🙁NSData *)Data;

– (NSData *) AES128Decrypt🙁NSData *)Data;

– (NSString *) encodeNSDataToHexString🙁NSData *)data;

– (NSData *) decodeHexStringToNSData🙁NSString *)hexString;

@end

1-2. AESExtension.m

#import “AESExtension.h”

@implementation AESExtension

NSString *m_key = @”aaaaaaaaaabbbbbb”;

NSString *m_ivText = @”aaaaaaaaaabbbbbb”;

int m_ivLength = 16;

– (NSData *) aesEncryptNSData🙁NSString *)textString {

    NSData *data = [textString dataUsingEncoding:NSUTF8StringEncoding];

    

    NSData *ret = [self AES128Encrypt:data];

    return ret;

}

– (NSString *) aesEncryptHexString🙁NSString *)textString {

    NSData *ret = [self aesEncryptNSData:textString];

    

    // NSData to HexString

    NSString *hexString = [self encodeNSDataToHexString:ret];

    return hexString;

}

– (NSString*) aesEncryptBase64🙁NSString *)textString {

    NSData *ret = [self aesEncryptNSData:textString];

    

    // NSData to Base64String

    NSData *base64Data = [ret base64EncodedDataWithOptions:0];

    NSString *base64String = [[NSString alloc] initWithData:base64Data encoding:NSUTF8StringEncoding];

    return base64String;

}

– (NSString *) aesDecryptNSData🙁NSData *)nsdata {

    NSData *ret = [self AES128Decrypt:nsdata];

    

    NSString *plainText = [[NSString alloc] initWithData:ret encoding:NSUTF8StringEncoding];

    return plainText;

}

– (NSString *) aesDecryptHexString🙁NSString *)hexString {

    NSData *hexData = [self decodeHexStringToNSData:hexString];

    NSString *plainText = [self aesDecryptNSData:hexData];

    return plainText;

}

– (NSString *) aesDecryptBase64🙁NSString *)base64String {

    // Base64String to NSData

    NSData *cryptData = [[NSData alloc] initWithBase64EncodedString:base64String options:0];

    

    NSString *plainText = [self aesDecryptNSData:cryptData];

    return plainText;

}

– (NSData *) AES128Encrypt🙁NSData *)Data {

    // ‘key’ should be 32 bytes for AES256, will be null-padded otherwise

    char keyPtr[kCCKeySizeAES128+1]; // room for terminator (unused) // oorspronkelijk 256

    bzero(keyPtr, sizeof(keyPtr)); // fill with zeroes (for padding)

    

    // fetch key data

    [m_key getCString:keyPtr maxLength:sizeof(keyPtr) encoding:NSUTF8StringEncoding];

    

    NSUInteger dataLength = [Data length];

    

    // See the doc: For block ciphers, the output size will always be less than or

    // equal to the input size plus the size of one block.

    // That’s why we need to add the size of one block here

    size_t bufferSize = dataLength + kCCBlockSizeAES128;

    void *buffer = malloc(bufferSize);

    

    size_t numBytesEncrypted = 0;

    

    // ECB 방식

    /*

    CCCryptorStatus cryptStatus = CCCrypt(kCCEncrypt,

                                          kCCAlgorithmAES128,

                                          kCCOptionECBMode + kCCOptionPKCS7Padding,

                                          keyPtr,

                                          kCCKeySizeAES128, // oorspronkelijk 256

                                          NULL, // iv : initialization vector (optional)

                                          [Data bytes],

                                          dataLength, // input

                                          buffer,

                                          bufferSize, // output

                                          &numBytesEncrypted);

     */

    

    // CBC 방식

    unsigned char iv[] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};

    for (int i=0; i<m_ivLength; i++) {

        iv[i] = [m_ivText characterAtIndex:i];

    }

    

    NSData *ivData = [NSData dataWithBytes:iv length:sizeof(iv)];

    uint8_t clv[m_ivLength];

    bzero(clv, m_ivLength);

    [ivData getBytes:clv length:m_ivLength];

    

    CCCryptorStatus cryptStatus = CCCrypt(kCCEncrypt,

                                          kCCAlgorithmAES128,

                                          kCCOptionPKCS7Padding,

                                          keyPtr,

                                          kCCKeySizeAES128, // oorspronkelijk 256

                                          clv, // iv : initialization vector (optional)

                                          [Data bytes],

                                          dataLength, // input

                                          buffer,

                                          bufferSize, // output

                                          &numBytesEncrypted);

        

    if (cryptStatus == kCCSuccess) {

        // the returned NSData takes ownership of the buffer and will free it on deallocation

        return [NSData dataWithBytesNoCopy:buffer length:numBytesEncrypted];

    }

    

    // free the buffer

    free(buffer);

    

    return nil;

}

– (NSData *) AES128Decrypt🙁NSData *)Data {

    // ‘key’ should be 32 bytes for AES256, will be null-padded otherwise

    char keyPtr[kCCKeySizeAES128+1]; // room for terminator (unused) // oorspronkelijk 256

    bzero(keyPtr, sizeof(keyPtr)); // fill with zeroes (for padding)

    

    // fetch key data

    [m_key getCString:keyPtr maxLength:sizeof(keyPtr) encoding:NSUTF8StringEncoding];

    

    NSUInteger dataLength = [Data length];

    

    // See the doc: For block ciphers, the output size will always be less than or

    // equal to the input size plus the size of one block.

    // That’s why we need to add the size of one block here

    size_t bufferSize = dataLength + kCCBlockSizeAES128;

    void *buffer = malloc(bufferSize);

    

    size_t numBytesDecrypted = 0;

    

    // ECB 방식

    /*

    CCCryptorStatus cryptStatus = CCCrypt(kCCDecrypt,

                                          kCCAlgorithmAES128,

                                          kCCOptionECBMode + kCCOptionPKCS7Padding,

                                          keyPtr, kCCKeySizeAES128, // oorspronkelijk 256

                                          NULL, // iv : initialization vector (optional)

                                          [Data bytes], dataLength, // input

                                          buffer, bufferSize, // output

                                          &numBytesDecrypted);

    */

    

    // CBC 방식

    unsigned char iv[] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};

    for (int i=0; i<m_ivLength; i++) {

        iv[i] = [m_ivText characterAtIndex:i];

    }

    

    NSData *ivData = [NSData dataWithBytes:iv length:sizeof(iv)];

    uint8_t clv[m_ivLength];

    bzero(clv, m_ivLength);

    [ivData getBytes:clv length:m_ivLength];

    

    CCCryptorStatus cryptStatus = CCCrypt(kCCDecrypt,

                                          kCCAlgorithmAES128,

                                          kCCOptionPKCS7Padding,

                                          keyPtr, kCCKeySizeAES128, // oorspronkelijk 256

                                          clv, // iv : initialization vector (optional)

                                          [Data bytes], dataLength, // input

                                          buffer, bufferSize, // output

                                          &numBytesDecrypted);

    

    if (cryptStatus == kCCSuccess) {

        // the returned NSData takes ownership of the buffer and will free it on deallocation

        return [NSData dataWithBytesNoCopy:buffer length:numBytesDecrypted];

    }

    

    // free the buffer

    free(buffer);

    

    return nil;

}

– (NSString *) encodeNSDataToHexString🙁NSData *)data {

    NSMutableString *hexString = [NSMutableString string];

    unsigned char *bytes = (unsigned char *)[data bytes];

    char temp[3];

    NSUInteger i=0;

    

    for (i=0; i<[data length]; i++){

        temp[0] = temp[1] = temp[2] =0;

        (void)sprintf(temp, “%02x”,bytes[i]);

        [hexString appendString:[NSString stringWithUTF8String:temp]];

        

    }

    

    return hexString;

}

– (NSData *) decodeHexStringToNSData🙁NSString *)hexString {

    unsigned long tlen = [hexString length]/2;

    

    char tbuf[tlen];

    int i,k,h,l;

    bzero(tbuf, sizeof(tbuf));

    

    for (i=0, k=0; i<tlen; i++) {

        h=[hexString characterAtIndex:k++];

        l=[hexString characterAtIndex:k++];

        h=(h >= ‘A’) ? h-‘A’+10 : h-‘0’;

        l=(l >= ‘A’) ? l-‘A’+10 : l-‘0’;

        tbuf[i]= ((h<<4)&0xf0)| (l&0x0f);

    }

    

    return [NSData dataWithBytes:tbuf length:tlen];

}

@end

2. AES128 암호화, 복호화 방법

2-1. 원하는 파일 상단에 아래 내용 추가 (Add the below content to the top of the desired file)

#import “AESExtension.h”

2-2. HEX 문자열로 AES128 암호화 (AES128 encrypt to HEX String)

NSString *plainText = @”1234″;

AESExtension *aes = [[AESExtension alloc] init];

NSString *hexString = [NSString stringWithFormat:@”%@”, [aes aesEncryptHexString:plainText]];

[aes release];


// hexString : a01a8acf2a239460f98439ee148e75c1

NSLog(@”hexString : %@”, hexString);

2-3. HEX 문자열로부터 AES128 복호화 (AES128 descrypt from HEX String)

NSString *hexString = @”a01a8acf2a239460f98439ee148e75c1″;


AESExtension *aes = [[AESExtension alloc] init];

NSString *decodedString = [NSString stringWithFormat:@”%@”, [aes aesDecryptHexString:hexString]];

[aes release];

// decodedString : 1234

NSLog(@”decodedString : %@”, decodedString);

2-4. Base64 문자열로 AES128 암호화 (AES128 encrypt to Base64 String)

NSString *plainText = @”1234″;

AESExtension *aes = [[AESExtension alloc] init];

NSString *base64string = [NSString stringWithFormat:@”%@”, [aes aesEncryptBase64:plainText]];

[aes release];

// base64string : oBqKzyojlGD5hDnuFI51wQ==

NSLog(@”base64string : %@”, base64string);

2-5. Base64 문자열로부터 AES128 복호화 (AES128 descrypt from Base64 String)

NSString *base64string = @”oBqKzyojlGD5hDnuFI51wQ==”;


AESExtension *aes = [[AESExtension alloc] init];

NSString *decodedString = [NSString stringWithFormat:@”%@”, [aes aesDecryptBase64:base64string]];

[aes release];


// decodedString : 1234

NSLog(@”decodedString : %@”, decodedString);

3. 결과 (Result)

m_key : aaaaaaaaaabbbbbb

m_ivText : aaaaaaaaaabbbbbb

salt : undefined

plainText : 1234

HEX String encryption value : a01a8acf2a239460f98439ee148e75c1

Base64 String encryption value : oBqKzyojlGD5hDnuFI51wQ==

decodedString : 1234

참고사이트 1 : https://blog.suromind.com/34