Notice
Recent Posts
Recent Comments
Link
투케이2K
49. (ios/swift) aes 암호화 파생 인코딩 , 디코딩 수행 실시 - secretkey , iv , salt 본문
[개발 환경 설정]
개발 툴 : XCODE
개발 언어 : SWIFT
[소스 코드]
import Foundation
// MARK: - [필요 헤더 브릿지 : #import <CommonCrypto/CommonCrypto.h>]
struct C_AES256 {
// MARK: - [클래스 설명]
/*
1. AES256 암호화 수행 파생 클래스
2. 추가하는 값 KEY, IV, SALT 값
3. CBC : 블록 암호화 운영 모드 중 보안 성이 제일 높은 암호화 방법으로 가장 많이 사용 (IV 사용)
4. PKCS 5 : 8 바이트 패딩 (데이터 길이가 모자라다면 8 바이트까지 마지막 값 기준 채우고, 8 바이트 이상인 경우 뒤에 8바이트 패딩 추가)
5. PKCS 7 : 16 바이트 패딩 (데이터 길이가 모자라다면 16 바이트까지 마지막 값 기준 채우고, 16 바이트 이상인 경우 뒤에 8바이트 패딩 추가)
7. 참고 사이트 (aos) : https://www.tabnine.com/code/java/methods/javax.crypto.spec.PBEKeySpec/%3Cinit%3E
8. 참고 사이트 (ios) : https://gist.github.com/hfossli/7165dc023a10046e2322b0ce74c596f8
*/
// MARK: - [사용 방법 정의]
/*
DispatchQueue.main.async {
do {
// [데이터 지정]
let data = "hello".data(using: .utf8)!
// [필요 변수 선언]
let secretKey = "0123456789abcdef0123456789abcdef" // [32 byte]
let iv = "0123456789abcdef".data(using: .utf8)! // [16 byte]
let salt = "0123456789abcdef0123456789abcdef".data(using: .utf8)! // [random byte]
let keyLength = kCCKeySizeAES256 // [256 = 32 length]
let iterationCount = 10000
// [KeySpec]
let key = try C_AES256.createKey(secretKey: secretKey.data(using: .utf8)!, salt: salt, keyLength: keyLength, iterationCount: UInt32(iterationCount))
// [Cipher]
let aes = try C_AES256(key: key, iv: iv)
// [AES 데이터 인코딩 수행 실시]
let encryptedBase64 = try aes.encrypt(data).base64EncodedString() // 데이터 인코딩
print("")
print("===============================")
print("[C_AES256 >> :: AES 암호화 인코딩 수행 실시]")
print("secretKey :: ", secretKey)
print("iv :: ", String(decoding: iv, as: UTF8.self))
print("salt :: ", String(decoding: salt, as: UTF8.self))
print("keyLength :: ", keyLength)
print("iterationCount :: ", iterationCount)
print("원본 :: ", String(decoding: data, as: UTF8.self))
print("인코딩 :: ", encryptedBase64)
print("===============================")
print("")
// [AES 데이터 디코딩 수행 실시]
let decryptedBase64 = String(data: try aes.decrypt(Data(base64Encoded: encryptedBase64)!), encoding: .utf8) ?? "" // 데이터 디코딩
print("")
print("===============================")
print("[C_AES256 >> :: AES 암호화 디코딩 수행 실시]")
print("secretKey :: ", secretKey)
print("iv :: ", String(decoding: iv, as: UTF8.self))
print("salt :: ", String(decoding: salt, as: UTF8.self))
print("keyLength :: ", keyLength)
print("iterationCount :: ", iterationCount)
print("원본 :: ", encryptedBase64)
print("디코딩 :: ", decryptedBase64)
print("===============================")
print("")
}
catch {
print("")
print("===============================")
print("[C_AES256 >> :: AES 인코딩 및 디코딩 수행 실패]")
print("error :: ", error)
print("===============================")
print("")
}
}
*/
// MARK: - [결과 출력 예시]
/*
===============================
[C_AES256 >> :: AES 암호화 인코딩 수행 실시]
secretKey :: 0123456789abcdef0123456789abcdef
iv :: 0123456789abcdef
salt :: 0123456789abcdef0123456789abcdef
keyLength :: 32
iterationCount :: 10000
원본 :: hello
인코딩 :: 4KpINm+YV8sEqzj8ccXIkw==
===============================
===============================
[C_AES256 >> :: AES 암호화 디코딩 수행 실시]
secretKey :: 0123456789abcdef0123456789abcdef
iv :: 0123456789abcdef
salt :: 0123456789abcdef0123456789abcdef
keyLength :: 32
iterationCount :: 10000
원본 :: 4KpINm+YV8sEqzj8ccXIkw==
디코딩 :: hello
===============================
*/
// MARK: - [전역 변수 선언 실시]
private var key: Data
private var iv: Data
// MARK: - [enum 에러 타입 정의]
enum Error: Swift.Error {
case keyGeneration(status: Int)
case cryptoFailed(status: CCCryptorStatus)
case badKeyLength
case badInputVectorLength
}
// MARK: - [클래스 생성자 초기화 실시]
public init(key: Data, iv: Data) throws {
// [secret key 32 바이트 체크 실시]
guard key.count == kCCKeySizeAES256 else {
throw Error.badKeyLength
}
// [iv 16 바이트 체크 실시]
guard iv.count == kCCBlockSizeAES128 else {
throw Error.badInputVectorLength
}
self.key = key
self.iv = iv
}
// MARK: - [key 생성 수행 부분]
static func createKey(secretKey: Data, salt: Data, keyLength:Int, iterationCount:UInt32) 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, // [saltLength]
// 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: - [인코딩 수행 실시]
func encrypt(_ digest: Data) throws -> Data {
return try crypt(input: digest, operation: CCOperation(kCCEncrypt))
}
// MARK: - [디코딩 수행 실시]
func decrypt(_ encrypted: Data) throws -> Data {
return try crypt(input: encrypted, operation: CCOperation(kCCDecrypt))
}
// MARK: - [인코딩, 디코딩 데이터 생성]
private func crypt(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)
}
} // [클래스 종료]
[결과 출력]
반응형
'IOS' 카테고리의 다른 글
Comments