6 min to read
Secure Coding)대칭, 비대칭 키 암호
시큐어 코딩
@
대칭키 암호 방식
대칭 키 암호 방식의 핵심은 “같은 키를 가지고 암호화, 복호화를 진행한다” 이다. 즉, 내가 철수에게 암호화된 파일을 건내 받았는데 철수가 열쇠를 주지 않는다면 나는 영영 못열게 되는 암호방식이다. 대표적으로 DES, SEED, AES가 있다.
비 대칭키 암호 방식
암호화된 통신을 할 두 사용자가 하나의 비밀키를 공유해야 하기 때문에 비밀키 전달 과정에서 키가 외부에 노출될 위험이 있다. 내 공개키를 상대방에게 알려주면 상대방은 공개키를 이용해 데이터를 암호화하고, 암호화된 데이터를 나에게 보낸다. 암호화된 데이터는 내가 갖고 있는 개인키를 이용해 복호화할 수 있다. 반대로 내가 상대방에게 데이터를 보낼 때는 상대방이 알려준 공개키를 이용해 암호화하고, 상대방은 자신이 갖은 비밀키를 사용해 복호화한다. 즉, 전달되는 것은 공개키 뿐인데 공개키 만으로는 데이터를 복호화할 수 없다. 비대칭키 암호의 대표적인 예로는 RSA, 타원 곡선 암호, 전자 서명 등이 있다.
AES를 알아보자
대표적으로 랜섬웨어에 사용되는 AES를 알아보고 사용해보자. AES는 Advanced Encryption Standard를 줄인 말이다. 한국어로 번역하면 ‘고급 암호화 표준’이다. 대칭키를 쓰는 블럭 암호이다. 높은 안전성과 속도로 인해 인기를 얻어 전 세계적으로 사용되고 있다.
- 대칭형, 블럭 암호화 알고리즘
- 암호화 키는 128, 192, 256의 세 가지 중 하나가 될 수 있으며, 각각 AES-128, AES-192, AES-256으로 불린다.
- 암호화 키의 길이에 따라 실행하는 라운드의 수가 다른데, 각각 10, 12, 14 라운드를 실행한다.
자세한 알고리즘은 생략하고 주요한 용어와 사용방법을 설명한다.
IV(Initialization Vector)
- 초기화 벡터는 동일한 일반 텍스트가 동일한 키로 여러 번 독립적으로 암호화되어도 별개의 암호 텍스트가 생성되도록 하기 위해 사용된다.
- 동일한 키에서 초기화 벡터를 사용하면 안된다.
- CBC의 경우, IV를 재사용하면 첫 번째 블록의 평문에 대한 정보와 두 메세지가 공유하는 공통 접두사가 누설될 수 있다.
- OFB 혹은 CTR 모드의 경우 IV를 다시 사용하면 보안이 완전히 파괴된다.
- CBC 모드에서는 IV는 암호화시 예측할 수 없어야 한다.
Padding
- 블록 암호는 고정된 블록 크기에서 작동하지만, 메세지는 다양한 길이로 나타난다.
- 데이터(메세지)를 블럭으로 암호화 할 때 평문이 항상 블럭 크기(일반적으로 64비트 / 128비트)의 배수가 되지 않을 경우가 존재한다.
- 패딩은 어떻게 평문의 마지막 블록이 암호화 되기 전에 데이터로 채워지는가를 확실히 지정하는 방법 이다. 복호화 과정에서는 패딩을 제거하고, 평문의 실제 길이를 지정하게 된다.
- 암호 블록 사이즈와 데이터 사이즈가 맞지 않을 경우에 배수에 맞춰 빈공간을 채워주는 방식이라고 볼 수가 있다.
- 종류로는 PKCS#5, PKCS#7가 있다. 두 개의 차이는 PKCS#5는 8바이트 고정길이, PKCS#7은 1~255바이트의 가변길이이다.
Common modes
블록 암호는 특정한 길이의 블록 단위로 동작하기 때문에, 가변 길이 데이터를 암호화하기 위해서는 먼저 이들을 단위 블록들로 나누어야 하며, 그리고 그 블록들을 어떻게 암호화할지를 정해야 한다.
- CBC(Cipher-Block Chaining)
- GCM(Galois/Counter Mode)
- CCM 외 등..
AES-CBC
import CryptoSwift
let input: Array<UInt8> = [0,1,2,3,4,5,6,7,8,9]
let key: Array<UInt8> = [0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00]
let iv: Array<UInt8> = AES.randomIV(AES.blockSize)
do {
let encrypted = try AES(key: key, blockMode: CBC(iv: iv), padding: .pkcs7).encrypt(input)
let decrypted = try AES(key: key, blockMode: CBC(iv: iv), padding: .pkcs7).decrypt(encrypted)
} catch {
print(error)
}
AES-GCM
import CryptoSwift
let input: Array<UInt8> = [0,1,2,3,4,5,6,7,8,9]
let key: Array<UInt8> = [0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00]
let iv: Array<UInt8> = AES.randomIV(AES.blockSize)
let retGCM = self.encryptABS_GCM(input: input, key: key, iv: iv)
print(retGCM.encrypted, retGCM.tag)
if let encrypted = retGCM.encrypted {
let decrypt = decryptABS_GCM(encrypted: encrypted, key: key, iv: iv)
print(decrypt)
}
func encryptABS_GCM(input:[UInt8], key:[UInt8], iv:[UInt8]) -> (encrypted:[UInt8]?, tag:[UInt8]?){
do {
let gcm = GCM(iv: iv, mode: .combined)
let aes = try AES(key: key, blockMode: gcm, padding: .noPadding)
let encrypted = try aes.encrypt(input)
let tag = gcm.authenticationTag
return (encrypted, tag)
} catch let err {
print(err.localizedDescription)
return (nil, nil)
}
}
func decryptABS_GCM(encrypted:[UInt8], key:[UInt8], iv:[UInt8]) -> [UInt8]? {
do {
let gcm = GCM(iv: iv, mode: .combined)
let aes = try AES(key: key, blockMode: gcm, padding: .noPadding)
let decrypt = try aes.decrypt(encrypted)
return decrypt
} catch let err {
print(err.localizedDescription)
return nil
}
}
Comments