투케이2K

20. (TWOK/UTIL) [Ios/Swift] C_Encryption - 데이터 암호화 인코딩 (encode) , 디코딩 (decode) , URL 인코딩, 디코딩 관련 클래스 본문

투케이2K 유틸파일

20. (TWOK/UTIL) [Ios/Swift] C_Encryption - 데이터 암호화 인코딩 (encode) , 디코딩 (decode) , URL 인코딩, 디코딩 관련 클래스

투케이2K 2022. 3. 25. 18:05

[설 명]

프로그램 : Ios / Swift

설 명 : 데이터 암호화 인코딩 (encode) , 디코딩 (decode) , URL 인코딩 , 디코딩 관련 클래스

 

[소스 코드]

import Foundation
import UIKit

class C_Encryption {
    
    
    // MARK: - [클래스 설명]
    /*
    // -----------------------------------------
    1. 데이터 암호화 인코딩, 디코딩 관련 클래스
    // -----------------------------------------
    */
    
    
    
    
    
    // MARK: - [base64 인코딩]
    func getBase64EncodeString(string: String) -> String {
        
        /*
        // -----------------------------------------
        [getBase64EncodeString 메소드 설명]
        // -----------------------------------------
        1. 호출 방법 : C_Encryption().getBase64EncodeString(string: "hello")
        // -----------------------------------------
        2. 리턴 결과 : Base64 암호화 문자열 반환
        // -----------------------------------------
        */
        
        // [리턴 데이터 변수 선언 실시]
        var returnData = ""
        if string != nil && string.count>0 && string != "" {
            
            let strData = string.data(using: .utf8)! // Data 형식으로 만들기
            returnData = strData.base64EncodedString() // Data 형식을 Base64 String 으로 변환
            
        }
        
        // [로그 출력 실시]
        print("")
        print("====================================")
        print("[C_Encryption >> getBase64EncodeString() :: base64 인코딩 실시]")
        print("-------------------------------")
        print("input :: \(string)")
        print("-------------------------------")
        print("return :: \(returnData)")
        print("====================================")
        print("")
        // */
        
        // [리턴 데이터 반환]
        return returnData
    }
    
    
    
    
    
    // MARK: - [base64 디코딩]
    func getBase64DecodeString(string: String) -> String {
        
        /*
        // -----------------------------------------
        [getBase64DecodeString 메소드 설명]
        // -----------------------------------------
        1. 호출 방법 : C_Encryption().getBase64DecodeString(string: "aGVsbG8=")
        // -----------------------------------------
        2. 리턴 결과 : Base64 복호화 문자열 반환
        // -----------------------------------------
        */
        
        // [리턴 데이터 변수 선언 실시]
        var returnData = ""
        if string != nil && string.count>0 && string != "" {
            
            let decodeData = Data(base64Encoded: string)! // Data 형식으로 만들기
            returnData = String(data: decodeData, encoding: .utf8)! // Data 형식을 Base64 String 으로 변환
            
        }
        
        // [로그 출력 실시]
        print("")
        print("====================================")
        print("[C_Encryption >> getBase64DecodeString() :: base64 디코딩 실시]")
        print("-------------------------------")
        print("input :: \(string)")
        print("-------------------------------")
        print("return :: \(returnData)")
        print("====================================")
        print("")
        // */
        
        // [리턴 데이터 반환]
        return returnData
    }
    
    
    
    
    
    // MARK: - [AES256 인코딩]
    func getAES256EncodeString(secretKey:String, iv:String, string:String) -> String {
        
        /*
        // -----------------------------------------
        [getAES256EncodeString 메소드 설명 : CBC 모드]
        // -----------------------------------------
        1. AES 암호화 란 비밀키를 사용해 인코딩 , 디코딩을 수행하는 암호화 기법입니다
        // -----------------------------------------
        2. AES 128 [secret key] : 16 byte
        // -----------------------------------------
        3. AES 192 [secret key] : 24 byte
        // -----------------------------------------
        4. AES 256 [secret key] : 32 byte
        // -----------------------------------------
        5. AES Iv [공통] : 16 byte
        // -----------------------------------------
        6. 필수 사항 [브릿지 헤더에 import 추가] : #import <CommonCrypto/CommonCrypto.h>
        // -----------------------------------------
        7. 호출 방법 :
           - iv 값 없이 호출 : C_Encryption().getAES256EncodeString(secretKey:"0123456789abcdef0123456789abcdef", iv:"", string:"hello")
           - iv 값 포함 호출 : C_Encryption().getAES256EncodeString(secretKey:"0123456789abcdef0123456789abcdef", iv:"0123456789abcdef", string:"hello")
        // -----------------------------------------
        */
        
        
        // [리턴 데이터 반환 변수 선언]
        var returnData = ""
        
        
        // [사전 인풋 값 체크 방어 로직 추가]
        if secretKey != nil && secretKey != "" && secretKey.count == 32
            && string != nil && string != "" && string.count > 0 {
            
            // [AES256 : 비밀키 길이가 32 필요]
            // [iv 값 길이 16 필요]
            // [데이터 길이가 null 아니어야함]
        }
        else {
            print("")
            print("====================================")
            print("[C_Encryption >> getAES256EncodeString() :: AES256 인코딩 실시]")
            print("-------------------------------")
            print("error :: 인풋 데이터 체크 에러 발생")
            print("-------------------------------")
            print("secretKey :: \(secretKey)")
            print("-------------------------------")
            print("iv :: \(iv)")
            print("-------------------------------")
            print("input :: \(string)")
            print("-------------------------------")
            print("return :: \(returnData)")
            print("====================================")
            print("")
            
            // [리턴 결과 반환]
            return returnData
        }
        
        
        // [인풋 값을 Data 형식으로 생성 실시]
        let keyData = secretKey.data(using: .utf8)!
        let ivData = iv.data(using: .utf8)!
        let strData = string.data(using: .utf8)!
        
        
        // [인코딩 Data 생성 실시]
        guard let encodeData = try? C_Encryption().crypt(
            key: keyData,
            iv: ivData,
            input: strData,
            operation: CCOperation(kCCEncrypt)
        )
        else {
            print("")
            print("====================================")
            print("[C_Encryption >> getAES256EncodeString() :: AES256 인코딩 실시]")
            print("-------------------------------")
            print("error :: AES256 인코딩 수행 에러")
            print("-------------------------------")
            print("secretKey :: \(secretKey)")
            print("-------------------------------")
            print("iv :: \(iv)")
            print("-------------------------------")
            print("input :: \(string)")
            print("-------------------------------")
            print("return :: \(returnData)")
            print("====================================")
            print("")
            return returnData
        }
        
        // [정상적으로 인코딩 데이터가 생성된 경우 Base64 로 포맷 후 리턴 실시]
        returnData = encodeData.base64EncodedString()
        
        // [로그 출력 실시]
        print("")
        print("====================================")
        print("[C_Encryption >> getAES256EncodeString() :: AES256 인코딩 실시]")
        print("-------------------------------")
        print("type :: Success")
        print("-------------------------------")
        print("secretKey :: \(secretKey)")
        print("-------------------------------")
        print("iv :: \(iv)")
        print("-------------------------------")
        print("input :: \(string)")
        print("-------------------------------")
        print("return :: \(returnData)")
        print("====================================")
        print("")
        
        // [결과 리턴 실시]
        return returnData
    }
    
    
    
    
    
    // MARK: - [AES256 디코딩]
    func getAES256DecodeString(secretKey:String, iv:String, string:String) -> String {
        
        /*
        // -----------------------------------------
        [getAES256DecodeString 메소드 설명 : CBC 모드]
        // -----------------------------------------
        1. AES 암호화 란 비밀키를 사용해 인코딩 , 디코딩을 수행하는 암호화 기법입니다
        // -----------------------------------------
        2. AES 128 [secret key] : 16 byte
        // -----------------------------------------
        3. AES 192 [secret key] : 24 byte
        // -----------------------------------------
        4. AES 256 [secret key] : 32 byte
        // -----------------------------------------
        5. AES Iv [공통] : 16 byte
        // -----------------------------------------
        6. 필수 사항 [브릿지 헤더에 import 추가] : #import <CommonCrypto/CommonCrypto.h>
        // -----------------------------------------
        7. 호출 방법 :
           - iv 값 없이 호출 : C_Encryption().getAES256DecodeString(secretKey:"0123456789abcdef0123456789abcdef", iv:"", string:"pZwJZBLuy3mDACEQT4YTBw==")
           - iv 값 포함 호출 : C_Encryption().getAES256DecodeString(secretKey:"0123456789abcdef0123456789abcdef", iv:"0123456789abcdef", string:"UQdw44JDqzsxYpkSCwXDIA==")
        // -----------------------------------------
        */
        
        
        // [리턴 데이터 반환 변수 선언]
        var returnData = ""
        
        
        // [사전 인풋 값 체크 방어 로직 추가]
        if secretKey != nil && secretKey != "" && secretKey.count == 32
            && string != nil && string != "" && string.count > 0 {
            
            // [AES256 : 비밀키 길이가 32 필요]
            // [iv 값 길이 16 필요]
            // [데이터 길이가 null 아니어야함]
        }
        else {
            print("")
            print("====================================")
            print("[C_Encryption >> getAES256DecodeString() :: AES256 디코딩 실시]")
            print("-------------------------------")
            print("error :: 인풋 데이터 체크 에러 발생")
            print("-------------------------------")
            print("secretKey :: \(secretKey)")
            print("-------------------------------")
            print("iv :: \(iv)")
            print("-------------------------------")
            print("input :: \(string)")
            print("-------------------------------")
            print("return :: \(returnData)")
            print("====================================")
            print("")
            
            // [리턴 결과 반환]
            return returnData
        }
        
        
        // [인풋 값을 Data 형식으로 생성 실시]
        let keyData = secretKey.data(using: .utf8)!
        let ivData = iv.data(using: .utf8)!
        let strData = Data(base64Encoded: string)!
        
        
        // [디코딩 Data 생성 실시]
        guard let decodeData = try? C_Encryption().crypt(
            key: keyData,
            iv: ivData,
            input: strData,
            operation: CCOperation(kCCDecrypt)
        )
        else {
            print("")
            print("====================================")
            print("[C_Encryption >> getAES256DecodeString() :: AES256 디코딩 실시]")
            print("-------------------------------")
            print("error :: AES256 디코딩 수행 에러")
            print("-------------------------------")
            print("secretKey :: \(secretKey)")
            print("-------------------------------")
            print("iv :: \(iv)")
            print("-------------------------------")
            print("input :: \(string)")
            print("-------------------------------")
            print("return :: \(returnData)")
            print("====================================")
            print("")
            return returnData
        }
        
        // [정상적으로 디코딩 데이터가 생성된 경우 원본 데이터 리턴 실시]
        returnData = String(data:decodeData, encoding: .utf8) ?? ""
        
        // [로그 출력 실시]
        print("")
        print("====================================")
        print("[C_Encryption >> getAES256DecodeString() :: AES256 디코딩 실시]")
        print("-------------------------------")
        print("type :: Success")
        print("-------------------------------")
        print("secretKey :: \(secretKey)")
        print("-------------------------------")
        print("iv :: \(iv)")
        print("-------------------------------")
        print("input :: \(string)")
        print("-------------------------------")
        print("return :: \(returnData)")
        print("====================================")
        print("")
        
        // [결과 리턴 실시]
        return returnData
    }
    
    
    
    
    
    // MARK: - [AES256 에러 타입 정의 및 데이터 인코딩 , 디코딩 수행 실시]
    enum Error: Swift.Error {
        case keyGeneration(status: Int)
        case cryptoFailed(status: CCCryptorStatus)
        case badKeyLength
        case badInputVectorLength
    }
    private func crypt(key: Data, iv:Data, input: Data, operation: CCOperation) throws -> Data {
        // MARK: [SecretKeySpec : 인코딩, 디코딩 수행에서 AES 지정]
        let secretKeySpecType = kCCAlgorithmAES
        
        // MARK: [Cipher : 인코딩, 디코딩 수행에서 필요한 패딩 지정]
        let padding = kCCOptionPKCS7Padding
        
        // MARK: [인코딩 및 디코딩 수행 데이터]
        var outLength = Int(0)
        var outBytes = [UInt8](repeating: 0, count: input.count + kCCBlockSizeAES128)
        
        // MARK: [키 생성 상태 값 지정]
        var status: CCCryptorStatus = CCCryptorStatus(kCCSuccess)
        input.withUnsafeBytes { (encryptedBytes: UnsafePointer<UInt8>!) -> () in
            iv.withUnsafeBytes { (ivBytes: UnsafePointer<UInt8>!) in
                key.withUnsafeBytes {
                    (keyBytes: UnsafePointer<UInt8>!) -> () in status = CCCrypt(
                        operation,
                        
                        // MARK: [SecretKeySpec : 인코딩, 디코딩 수행에서 AES 지정]
                        CCAlgorithm(secretKeySpecType),
                        
                        // MARK: [Cipher : 인코딩, 디코딩 수행에서 필요한 패딩 지정]
                        CCOptions(padding),
                        
                        // MARK: [Cipher : KeySpec + iv]
                        keyBytes, // [key]
                        key.count, // [keylength]
                        
                        // MARK: [Cipher : KeySpec + iv]
                        ivBytes, // [iv]
                        
                        // MARK: [inputData]
                        encryptedBytes, // [inputData]
                        input.count, // [inputDataLength]
                        
                        // MARK: [outputData]
                        &outBytes, // [outputData]
                        outBytes.count, // [outputDataLength]
                        &outLength // [dataOutMoved]
                    )
                }
            }
        }
        guard status == kCCSuccess else {
            throw Error.cryptoFailed(status: status)
        }
        return Data(bytes: UnsafePointer<UInt8>(outBytes), count: outLength)
    }
    
    
    
    
    
    // MARK: - [URL 인코딩 관련 메소드]
    func urlEncodeString(data: String) -> String {
        
        /*
        // -----------------------------------------
        [urlEncodeString 메소드 설명]
        // -----------------------------------------
        1. URL 인코딩 관련 메소드
        // -----------------------------------------
        2. 호출 방법 : C_Encryption().urlEncodeString(data: "투케이")
        // -----------------------------------------
        3. 리턴 반환 : URL 인코딩 데이터
        // -----------------------------------------
        */
        
        // [초기 리턴 데이터 변수 선언 실시]
        var returnData = ""
        
        // [인풋 데이터 널 체크 수행 실시]
        if data != nil
            && data.count>0
            && data != ""
            && data.trimmingCharacters(in: .whitespacesAndNewlines) != ""
            && data.trimmingCharacters(in: .whitespacesAndNewlines) != "null"
            && data.isEmpty == false {
            
            // [URL 인코딩 수행 실시]
            returnData = data.addingPercentEncoding(withAllowedCharacters: .urlHostAllowed)!
        }
        
        // [로그 출력 실시]
        print("")
        print("====================================")
        print("[C_Encryption >> urlEncodeString() :: URL 인코딩 수행 실시]")
        print("-------------------------------")
        print("input :: \(data)")
        print("-------------------------------")
        print("return :: \(returnData)")
        print("====================================")
        print("")
        
        // [리턴 데이터 반환 실시]
        return returnData
    }
    
    
    
    
    
    // MARK: - [URL 디코딩 관련 메소드]
    func urlDecodeString(data: String) -> String {
        
        /*
        // -----------------------------------------
        [urlDecodeString 메소드 설명]
        // -----------------------------------------
        1. URL 디코딩 관련 메소드
        // -----------------------------------------
        2. 호출 방법 : C_Encryption().urlDecodeString(data: "%ED%88%AC%EC%BC%80%EC%9D%B4")
        // -----------------------------------------
        3. 리턴 반환 : URL 디코딩 데이터
        // -----------------------------------------
        */
        
        // [초기 리턴 데이터 변수 선언 실시]
        var returnData = ""
        
        // [인풋 데이터 널 체크 수행 실시]
        if data != nil
            && data.count>0
            && data != ""
            && data.trimmingCharacters(in: .whitespacesAndNewlines) != ""
            && data.trimmingCharacters(in: .whitespacesAndNewlines) != "null"
            && data.isEmpty == false {
            
            // [URL 디코딩 수행 실시]
            returnData = data.removingPercentEncoding!
        }
        
        // [로그 출력 실시]
        print("")
        print("====================================")
        print("[C_Encryption >> urlDecodeString() :: URL 디코딩 수행 실시]")
        print("-------------------------------")
        print("input :: \(data)")
        print("-------------------------------")
        print("return :: \(returnData)")
        print("====================================")
        print("")
        
        // [리턴 데이터 반환 실시]
        return returnData
    }
    
    
    
    
    
    // MARK: - [Aes256 인코딩 : key + iv + salt 사용]
    func getAES_Salt_EncodeString(secretKey:String, iv:String, salt:String, string:String) -> String {
        
        /*
        // -----------------------------------------
        [getAES_Salt_EncodeString 메소드 설명]
        // -----------------------------------------
        1. AES 암호화 란 비밀키를 사용해 인코딩 , 디코딩을 수행하는 암호화 기법입니다
        // -----------------------------------------
        2. AES 128 [secret key] : 16 byte
        // -----------------------------------------
        3. AES 192 [secret key] : 24 byte
        // -----------------------------------------
        4. AES 256 [secret key] : 32 byte
        // -----------------------------------------
        5. AES Iv [공통] : 16 byte
        // -----------------------------------------
        6. AES Salt [공통] : 16 byte
        // -----------------------------------------
        7. 필수 사항 [브릿지 헤더에 import 추가] : #import <CommonCrypto/CommonCrypto.h>
        // -----------------------------------------
        8. 호출 방법 :
         C_Encryption().getAES_Salt_EncodeString(
             secretKey:"0123456789abcdef0123456789abcdef",
             iv:"0123456789abcdef0123456789abcdef",
             salt: "0123456789abcdef0123456789abcdef",
             string:"hello"
         )
        // -----------------------------------------
        */
        
        
        // [리턴 데이터 반환 변수 선언]
        var returnData = ""
        
        
        // [사전 인풋 값 체크 방어 로직 추가]
        if secretKey != nil && secretKey != "" && secretKey.isEmpty == false && secretKey.count == 32
            && iv != nil && iv != "" && iv.isEmpty == false && iv.count == 32
            && salt != nil && salt != "" && salt.isEmpty == false && salt.count == 32
            && string != nil && string != "" && string.isEmpty == false && string.count > 0 {
            
            // [AES256 : 비밀키 길이가 32 필요]
            // [iv 값 길이 32 필요 : hex]
            // [salt 값 길이 32 필요 : hex]
            // [데이터 길이가 null 아니어야함]
        }
        else {
            print("")
            print("====================================")
            print("[C_Encryption >> getAES_Salt_EncodeString() :: AES [key + iv + salt] 인코딩 실시]")
            print("-------------------------------")
            print("error :: 인풋 데이터 체크 에러 발생")
            print("-------------------------------")
            print("secretKey :: \(secretKey)")
            print("-------------------------------")
            print("iv [hex] :: \(iv)")
            print("-------------------------------")
            print("salt [hex] :: \(salt)")
            print("-------------------------------")
            print("input :: \(string)")
            print("-------------------------------")
            print("return :: \(returnData)")
            print("====================================")
            print("")
            
            // [리턴 결과 반환]
            return returnData
        }
        
        
        // [인풋 값을 Data 형식으로 생성 실시]
        let keyData = secretKey.data(using: .utf8)!
        let ivData = self.hexStringToData(string: iv) // [hex >> byte 변환]
        let saltData = self.hexStringToData(string: salt) // [hex >> byte 변환]
        let strData = string.data(using: .utf8)!
        
        
        // [key + salt 사용해 새로운 키 생성 실시]
        guard let newKey = try? C_Encryption().createKey(
            secretKey: keyData, // [인풋 비밀키]
            salt: saltData, // [인풋 salt 데이터]
            iterationCount: UInt32(1000), // [iterationCount]
            keyLength: kCCKeySizeAES256 // [256 = 32 length]
        )
        else {
            print("")
            print("====================================")
            print("[C_Encryption >> getAES_Salt_EncodeString() :: AES [key + iv + salt] 인코딩 실시]")
            print("-------------------------------")
            print("error :: 새로운 비밀키 생성 에러")
            print("-------------------------------")
            print("secretKey :: \(secretKey)")
            print("-------------------------------")
            print("iv [hex] :: \(iv)")
            print("-------------------------------")
            print("salt [hex] :: \(salt)")
            print("-------------------------------")
            print("input :: \(string)")
            print("-------------------------------")
            print("return :: \(returnData)")
            print("====================================")
            print("")
            return returnData
        }
        
        
        // [인코딩 Data 생성 실시]
        guard let encodeData = try? C_Encryption().crypt(
            key: newKey,
            iv: ivData,
            input: strData,
            operation: CCOperation(kCCEncrypt)
        )
        else {
            print("")
            print("====================================")
            print("[C_Encryption >> getAES_Salt_EncodeString() :: AES [key + iv + salt] 인코딩 실시]")
            print("-------------------------------")
            print("error :: AES256 인코딩 수행 에러")
            print("-------------------------------")
            print("secretKey :: \(secretKey)")
            print("-------------------------------")
            print("iv [hex] :: \(iv)")
            print("-------------------------------")
            print("salt [hex] :: \(salt)")
            print("-------------------------------")
            print("input :: \(string)")
            print("-------------------------------")
            print("return :: \(returnData)")
            print("====================================")
            print("")
            return returnData
        }
        
        // [정상적으로 인코딩 데이터가 생성된 경우 Base64 로 포맷 후 리턴 실시]
        returnData = encodeData.base64EncodedString()
        
        // [로그 출력 실시]
        print("")
        print("====================================")
        print("[C_Encryption >> getAES_Salt_EncodeString() :: AES [key + iv + salt] 인코딩 실시]")
        print("-------------------------------")
        print("type :: Success")
        print("-------------------------------")
        print("secretKey :: \(secretKey)")
        print("-------------------------------")
        print("iv [hex] :: \(iv)")
        print("-------------------------------")
        print("salt [hex] :: \(salt)")
        print("-------------------------------")
        print("input :: \(string)")
        print("-------------------------------")
        print("return :: \(returnData)")
        print("====================================")
        print("")
        
        // [결과 리턴 실시]
        return returnData
    }
    
    
    
    
    
    // MARK: - [Aes256 디코딩 : key + iv + salt 사용]
    func getAES_Salt_DecodeString(secretKey:String, iv:String, salt:String, string:String) -> String {
        
        /*
        // -----------------------------------------
        [getAES_Salt_DecodeString 메소드 설명]
        // -----------------------------------------
        1. AES 암호화 란 비밀키를 사용해 인코딩 , 디코딩을 수행하는 암호화 기법입니다
        // -----------------------------------------
        2. AES 128 [secret key] : 16 byte
        // -----------------------------------------
        3. AES 192 [secret key] : 24 byte
        // -----------------------------------------
        4. AES 256 [secret key] : 32 byte
        // -----------------------------------------
        5. AES Iv [공통] : 16 byte
        // -----------------------------------------
        6. AES Salt [공통] : 16 byte
        // -----------------------------------------
        7. 필수 사항 [브릿지 헤더에 import 추가] : #import <CommonCrypto/CommonCrypto.h>
        // -----------------------------------------
        8. 호출 방법 :
         C_Encryption().getAES_Salt_DecodeString(
             secretKey:"0123456789abcdef0123456789abcdef",
             iv:"0123456789abcdef0123456789abcdef",
             salt: "0123456789abcdef0123456789abcdef",
             string:"0yHy16m2dy5OpZH2+NX/4w=="
         )
        // -----------------------------------------
        */
        
        
        // [리턴 데이터 반환 변수 선언]
        var returnData = ""
        
        
        // [사전 인풋 값 체크 방어 로직 추가]
        if secretKey != nil && secretKey != "" && secretKey.isEmpty == false && secretKey.count == 32
            && iv != nil && iv != "" && iv.isEmpty == false && iv.count == 32
            && salt != nil && salt != "" && salt.isEmpty == false && salt.count == 32
            && string != nil && string != "" && string.isEmpty == false && string.count > 0 {
            
            // [AES256 : 비밀키 길이가 32 필요]
            // [iv 값 길이 32 필요 : hex]
            // [salt 값 길이 32 필요 : hex]
            // [데이터 길이가 null 아니어야함]
        }
        else {
            print("")
            print("====================================")
            print("[C_Encryption >> getAES_Salt_DecodeString() :: AES [key + iv + salt] 디코딩 실시]")
            print("-------------------------------")
            print("error :: 인풋 데이터 체크 에러 발생")
            print("-------------------------------")
            print("secretKey :: \(secretKey)")
            print("-------------------------------")
            print("iv [hex] :: \(iv)")
            print("-------------------------------")
            print("salt [hex] :: \(salt)")
            print("-------------------------------")
            print("input :: \(string)")
            print("-------------------------------")
            print("return :: \(returnData)")
            print("====================================")
            print("")
            
            // [리턴 결과 반환]
            return returnData
        }
        
        
        // [인풋 값을 Data 형식으로 생성 실시]
        let keyData = secretKey.data(using: .utf8)!
        let ivData = self.hexStringToData(string: iv) // [hex >> byte 변환]
        let saltData = self.hexStringToData(string: salt) // [hex >> byte 변환]
        let strData = Data(base64Encoded: string)!
        
        
        // [key + salt 사용해 새로운 키 생성 실시]
        guard let newKey = try? C_Encryption().createKey(
            secretKey: keyData, // [인풋 비밀키]
            salt: saltData, // [인풋 salt 데이터]
            iterationCount: UInt32(1000), // [iterationCount]
            keyLength: kCCKeySizeAES256 // [256 = 32 length]
        )
        else {
            print("")
            print("====================================")
            print("[C_Encryption >> getAES_Salt_DecodeString() :: AES [key + iv + salt] 디코딩 실시]")
            print("-------------------------------")
            print("error :: 새로운 비밀키 생성 에러")
            print("-------------------------------")
            print("secretKey :: \(secretKey)")
            print("-------------------------------")
            print("iv [hex] :: \(iv)")
            print("-------------------------------")
            print("salt [hex] :: \(salt)")
            print("-------------------------------")
            print("input :: \(string)")
            print("-------------------------------")
            print("return :: \(returnData)")
            print("====================================")
            print("")
            return returnData
        }
        
        
        // [디코딩 Data 생성 실시]
        guard let decodeData = try? C_Encryption().crypt(
            key: newKey,
            iv: ivData,
            input: strData,
            operation: CCOperation(kCCDecrypt)
        )
        else {
            print("")
            print("====================================")
            print("[C_Encryption >> getAES_Salt_DecodeString() :: AES [key + iv + salt] 디코딩 실시]")
            print("-------------------------------")
            print("error :: AES256 디코딩 수행 에러")
            print("-------------------------------")
            print("secretKey :: \(secretKey)")
            print("-------------------------------")
            print("iv [hex] :: \(iv)")
            print("-------------------------------")
            print("salt [hex] :: \(salt)")
            print("-------------------------------")
            print("input :: \(string)")
            print("-------------------------------")
            print("return :: \(returnData)")
            print("====================================")
            print("")
            return returnData
        }
        
        // [정상적으로 디코딩 데이터가 생성된 경우 원본 데이터 리턴 실시]
        returnData = String(data:decodeData, encoding: .utf8) ?? ""
        
        // [로그 출력 실시]
        print("")
        print("====================================")
        print("[C_Encryption >> getAES_Salt_DecodeString() :: AES [key + iv + salt] 디코딩 실시]")
        print("-------------------------------")
        print("type :: Success")
        print("-------------------------------")
        print("secretKey :: \(secretKey)")
        print("-------------------------------")
        print("iv [hex] :: \(iv)")
        print("-------------------------------")
        print("salt [hex] :: \(salt)")
        print("-------------------------------")
        print("input :: \(string)")
        print("-------------------------------")
        print("return :: \(returnData)")
        print("====================================")
        print("")
        
        // [결과 리턴 실시]
        return returnData
    }
    
    
    
    
    
    // MARK: - [key + salt 사용해 new key 생성 수행 부분]
    private func createKey(secretKey: Data, salt: Data, iterationCount:UInt32, keyLength:Int) throws -> Data {
        // MARK: [알고리즘 변수 선언]
        let algo_1 = kCCPBKDF2
        let algo_2 = kCCPRFHmacAlgSHA1
        
        // MARK: [키 생성 상태 값 지정]
        var status = Int32(0)
        var derivedBytes = [UInt8](repeating: 0, count: keyLength)
        secretKey.withUnsafeBytes { (passwordBytes: UnsafePointer<Int8>!) in
            salt.withUnsafeBytes { (saltBytes: UnsafePointer<UInt8>!) in
                status = CCKeyDerivationPBKDF(
                    // MARK: [알고리즘 - 1]
                    CCPBKDFAlgorithm(algo_1), // [알고리즘]
                    
                    // MARK: [비밀키 지정]
                    passwordBytes, // [secretKey]
                    secretKey.count, // [secretKey Length]
                    
                    // MARK: [salt 지정]
                    saltBytes, // [salt]
                    salt.count, // [salt Length]
                    
                    // MARK: [알고리즘 - 2]
                    CCPseudoRandomAlgorithm(algo_2), // [알고리즘]
                    
                    // MARK: [iterationCount]
                    iterationCount,
                    
                    // MARK: [KeySpec : keyLength]
                    &derivedBytes, // [derivedKey]
                    keyLength // [keyLength]
                )
            }
        }
        guard status == 0 else {
            throw Error.keyGeneration(status: Int(status))
        }
        return Data(bytes: UnsafePointer<UInt8>(derivedBytes), count: keyLength)
    }
    
    
    
    
    
    // MARK: - [hex string to byte array 변환 메소드]
    func hexStringToData(string: String) -> Data {
        let stringArray = Array(string)
        var data: Data = Data()
        for i in stride(from: 0, to: string.count, by: 2) {
            let pair: String = String(stringArray[i]) + String(stringArray[i+1])
            if let byteNum = UInt8(pair, radix: 16) {
                let byte = Data([byteNum])
                data.append(byte)
            }
            else{
                fatalError()
            }
        }
        return data
    }
 
    
} // [클래스 종료]
 

[결과 출력]

 

 

반응형
Comments