Starbucks Caramel Frappuccino
본문 바로가기
  • 그래 그렇게 조금씩
UIKit/UIKit

Objective-C 암호화(AES/RSA), 해시(Hash)

by Toughie 2024. 6. 5.

KAKAO-Choonsik

해싱(Hashing)

    • 목적: 입력 데이터를 고정된 크기의 고유한 해시 값으로 변환해서 데이터를 식별하거나 무결성을 확인.
    • 특징: 단방향 함수로, 해시 값으로부터 원래 데이터를 복원할 수 없다.
    • 사용 사례:
      • 데이터 무결성 확인: 파일의 해시 값을 저장해두고, 나중에 동일한 해시 값을 생성하여 데이터가 변경되지 않았음을 확인.
      • 비밀번호 저장: 비밀번호를 해시 값으로 변환하여 저장함으로써, 실제 비밀번호를 저장하지 않고도 비밀번호 검증이 가능.
      • 디지털 서명: 문서의 해시 값을 서명하여, 문서의 변경 여부를 검증.
    • 종류:
      • MD5, SHA-1,SHA256 등 현재는 SHA256을 가장 많이 사용한다.

SHA-256 (Secure Hash Algorithm 256-bit)

    • 길이: 256비트 해시 값 생성
    • 특징: SHA-2 계열에 속하며, 현재 널리 사용되는 안전한 해시 함수
    • 사용 예시: 비밀번호 저장, 디지털 서명, 블록체인

SHA256 해싱 알고리즘 예시

#import <Foundation/Foundation.h>
#import <CommonCrypto/CommonDigest.h>

NSString *sha256String(NSString *input) {
    const char *s = [input cStringUsingEncoding:NSUTF8StringEncoding];
    NSData *keyData = [NSData dataWithBytes:s length:strlen(s)];
    
    uint8_t digest[CC_SHA256_DIGEST_LENGTH];
    
    CC_SHA256(keyData.bytes, (CC_LONG)keyData.length, digest);
    
    NSMutableString *output = [NSMutableString stringWithCapacity:CC_SHA256_DIGEST_LENGTH * 2];
    for (int i = 0; i < CC_SHA256_DIGEST_LENGTH; i++) {
        [output appendFormat:@"%02x", digest[i]];
    }
    
    return output;
}

//NSData로 반환
NSData *sha256Data(NSString *input) {
    const char *s = [input cStringUsingEncoding:NSUTF8StringEncoding];
    NSData *keyData = [NSData dataWithBytes:s length:strlen(s)];
    
    uint8_t digest[CC_SHA256_DIGEST_LENGTH];
    
    CC_SHA256(keyData.bytes, (CC_LONG)keyData.length, digest);
    
    return [NSData dataWithBytes:digest length:CC_SHA256_DIGEST_LENGTH];
}

int main(void)
{
	@autoreleasepool {
    	NSString *pw= @"Hello SHA";
        NSString *hashed = sha256String(pw);
        NSLog(@"%@", hashed);
        //4ea3b17f124867y1294ffad~~~
    }
    return 0;
}

 

SHA256 알고리즘을 통해 간단한 문자열을 해시값으로 바꾸는 예시이다.


암호화 알고리즘

데이터를 인코딩해서 키가 있는 사람만 복호화 할 수 있도록 하는 방법이다.

크게 대칭 키 암호화와 비대칭 키 암호화로 나눌 수 있다.

 

AES (Advanced Encryption Standard)

  • 키 길이: 128비트, 192비트, 256비트
  • 특징: 높은 보안성을 제공하며, 현재 표준으로 널리 사용됨
  • 사용 예시: 데이터베이스 암호화, 파일 암호화, 네트워크 통신 보안

AES는 대표적인 대칭 키 암호화 알고리즘으로,

'하나의 비밀 키'를 사용해서 데이터를 암호화하고 복호화 한다.

사물함을 여는 열쇠와 닫는 열쇠가 하나로 같다고 비유할 수 있다.

 

 

AES 데이터 암호화 예시

#import <Foundation/Foundation.h>
#import <CommonCrypto/CommonCrypto.h>

// SHA-256 해시(대칭 키 해시처리, NSData 리턴)
NSData *sha256Data(NSString *input) {
    const char *s = [input cStringUsingEncoding:NSUTF8StringEncoding];
    NSData *keyData = [NSData dataWithBytes:s length:strlen(s)];
    
    uint8_t digest[CC_SHA256_DIGEST_LENGTH];
    
    CC_SHA256(keyData.bytes, (CC_LONG)keyData.length, digest);
    
    return [NSData dataWithBytes:digest length:CC_SHA256_DIGEST_LENGTH];
}

 

 

AES 암호화

// AES 암호화
NSData *aesEncrypt(NSData *data, NSData *key) {
    size_t outLength;
    NSMutableData *cipherData = [NSMutableData dataWithLength:data.length + kCCBlockSizeAES128];
    
    CCCryptorStatus result = CCCrypt(kCCEncrypt, kCCAlgorithmAES, kCCOptionPKCS7Padding,
                                     key.bytes, kCCKeySizeAES256,
                                     NULL,
                                     data.bytes, data.length,
                                     cipherData.mutableBytes, cipherData.length,
                                     &outLength);
    
    if (result == kCCSuccess) {
        cipherData.length = outLength;
    } else {
        return nil;
    }
    
    return cipherData;
}

 

 

AES 복호화

// AES 복호화
NSData *aesDecrypt(NSData *data, NSData *key) {
    size_t outLength;
    NSMutableData *decryptedData = [NSMutableData dataWithLength:data.length + kCCBlockSizeAES128];
    
    CCCryptorStatus result = CCCrypt(kCCDecrypt, kCCAlgorithmAES, kCCOptionPKCS7Padding,
                                     key.bytes, kCCKeySizeAES256,
                                     NULL,
                                     data.bytes, data.length,
                                     decryptedData.mutableBytes, decryptedData.length,
                                     &outLength);
    
    if (result == kCCSuccess) {
        decryptedData.length = outLength;
    } else {
        return nil;
    }
    
    return decryptedData;
}

 

 

AES 암호화 후 복호화

int main(void) {
	@autoreleasepool {
            NSString *myData = @"myData";
            NSData *encodedData = [myData dataUsingEncoding:NSUTF8StringEncoding];
            NSString *pw = @"myPassword";
            NSData *keyData = sha256(pw);

            NSData *encryptedData = aesEncrypt(encodedData, keyData);
            NSData *decryptedData = aesDecrypt(encryptedData, keyData);
            NSString *decryptedString = [[NSString alloc] initWithData:decryptedData encoding:NSUTF8StringEncoding];

            NSLog(@"AES 암호화 됨: %@", encryptedData);
            // {length = ~~, bytes = @xf31939afds~~}
            NSLog(@"AES 복호화 됨: %@", decryptedString); //myData
	}
}

RSA (Rivest–Shamir–Adleman)

  • 키 길이: 일반적으로 2048비트 또는 4096비트
  • 특징: 공개 키로 암호화하고 개인 키로 복호화할 수 있음. 키 관리가 복잡하지만 높은 보안성 제공
  • 사용 예시: 데이터 전송 보안, 디지털 서명

RSA는 대표적인 비대칭 키 암호화 알고리즘으로,

공개 키와 개인 키 두개의 키를 사용해서 데이터 암호화와 복호화를 수행한다.

사물함을 잠구는 열쇠와 사물함을 여는 열쇠가 따로 있다고 비유할 수 있다.

 

 

공개키, 비밀키 생성

(Deprecated된 것이 좀 있고, 파라미터 전달 방식이 꽤 다양했는데 그냥 키사이즈만 전달하는 방식으로 작성함)

 

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

SecKeyRef generatePrivateKey(int keySize) {
    NSDictionary *attributes = @{
        (id)kSecAttrKeyType: (id)kSecAttrKeyTypeRSA,
        (id)kSecAttrKeySizeInBits: @(keySize)
    };
    
    CFErrorRef error = NULL;
    SecKeyRef privateKeyRef = SecKeyCreateRandomKey((__bridge CFDictionaryRef)attributes, &error);
    
    if (!privateKeyRef) {
        NSError *err = CFBridgingRelease(error);
        NSLog(@"비공개키 생성 실패: %@", err.localizedDescription);
        return NULL;
    }
    
    return privateKeyRef;
}

-> 비공개키를 생성하고 반환하면 여기서 공개키를 copy(추출)해서 사용

 

 

RSA 암호화

NSData *rsaEncrypt(NSData *data, SecKeyRef publicKey) {
    CFErrorRef error = NULL;
    NSData *cipherData = (NSData *)CFBridgingRelease(
        SecKeyCreateEncryptedData(publicKey,
                                  kSecKeyAlgorithmRSAEncryptionPKCS1,
                                  (__bridge CFDataRef)data,
                                  &error)
    );
    
    if (error) {
        NSError *err = CFBridgingRelease(error);
        NSLog(@"Encryption error: %@", err.localizedDescription);
        return nil;
    }
    
    return cipherData;
}

 

 

RSA 복호화

NSData * rsaDecrypt(NSData *encryptedData, SecKeyRef privateKey) {
    CFErrorRef error = NULL;
    NSData *plainData = (NSData *)CFBridgingRelease(
    SecKeyCreateDecryptedData(privateKey, kSecKeyAlgorithmRSAEncryptionPKCS1,
    (__bridge CFDataRef)cipherData, &error));
    
    if (error) {
    	NSError *err = CFBridgingRelease(error);
        NSLog(@"복호화 에러: %@", err.localizedDescription);
        return nil;
    }
    
    return plainData;
}

 

 

RSA 암호화 및 복호화 테스트

int main(void) {
  @autoreleasepool {
    NSString *data = @"myData";
    NSData *encodedData = [data dataUsingEncoding: NSUTF8StringEncoding];

    SecKeyRef privateKey = generatePrivatKey(2048);
    SecKeyRef publicKey = SecKeyCopyPublicKey(privateKey);


    //암호화
    NSData *encryptedData = rsaEncrypt(encodedData, publicKey);
    NSData *decryptedData = rsaDecrypt(encryptedData, privateKey);

    NSLog(@"encrypted: %@", encryptedData) // {length = 256, bytes = 0x0e723fa9 38344f8d ...}
    NSLog(@"decrypted: %@", [[NSString alloc] initWithData: decryptedData encoding: NSUTF8StringEncoding]); //myData

  }
}

 


주민등록번호 등 데이터 암호화가 필요한 부분에서 자주 쓰이는 암호화에 대해 간단하게 알아보았다.

실제로 적용할 때는 더 자세한 에러처리, 데이터 관리 등의 로직이 추가되겠지만

기본적으로 AES가 단일 키 방식, RSA는 다중 키(개인 키, 공개 키)방식으로 암호화 및 복호화가 이루어진다는 것,

Objective-C환경에서 CommonCrypto와 Security를 사용한다는 것을 알 수 있었다.