DEV

Secure Coding)해시함수 응용편

시큐어 코딩

Featured image

@

Adaptive Key Derivation Functions

다이제스트를 생성할 때 솔팅(Salting)과 키 스트레칭(key stretching)을 반복하며 솔트와 패스워드 외에도 입력 값을 추가하여 공격자가 쉽게 다이제스트를 유추할 수 없도록 하고 보안의 강도를 선택할 수 있다. 이 함수들은 GPU와 같은 장비를 이용한 병렬화를 어렵게 하는 기능을 제공한다. 이와 같은 기능은 프로그램이 언어에서 제공하는 라이브러리만으로는 구현하기 어렵다.

PBKDF2

가장 많이 사용되는 함수는 PBKDF2(Password-Based Key Derivation Function)이다. 해시 함수의 컨테이너인 PBKDF2는 솔트를 적용한 후 해시 함수의 반복 횟수를 임의로 선택할 수 있다. PBKDF2는 아주 가볍고 구현하기 쉬우며, SHA와 같이 검증된 해시 함수만을 사용한다.

import CryptoSwift

let password: Array<UInt8> = Array("s33krit".utf8)
let salt: Array<UInt8> = Array("nacllcan".utf8)

do {
    /// password: 패스워드, salt: 암호학 솔트, iterations: 원하는 iteration 반복 수, keyLength: 원하는 다이제스트 길이, variant: 해시함수
    let PBKDF2 = try PKCS5.PBKDF2(password: password, salt: salt, iterations: 4096, keyLength: 32, variant: .sha256).calculate()
    print(PBKDF2)
} catch let err {
    print(err.localizedDescription)
}

bcrypt

bcrypt는 애초부터 패스워드 저장을 목적으로 설계되었다. Niels Provos와 David Mazières가 1999년 발표했고 현재까지 사용되는 가장 강력한 해시 메커니즘 중 하나이다. bcrypt는 보안에 집착하기로 유명한 OpenBSD에서 기본 암호 인증 메커니즘으로 사용되고 있고 미래에 PBKDF2보다 더 경쟁력이 있다고 여겨진다. bcrypt에서 “work factor” 인자는 하나의 해시 다이제스트를 생성하는 데 얼마만큼의 처리 과정을 수행할지 결정한다. “work factor”를 조정하는 것만으로 간단하게 시스템의 보안성을 높일 수 있다. 다만 PBKDF2나 scrypt와는 달리 bcrypt는 입력 값으로 72 bytes character를 사용해야 하는 제약이 있다.

import BCrypt

// Hash
let digest = try BCrypt.Hash.make(message: "foo")
print(digest.string)

// Verify
let digest = "$2a$04$TI13sbmh3IHnmRepeEFoJOkVZWsn5S1O8QOwm8ZU5gNIpJog9pXZm"
let result = try BCrypt.Hash.verify(message: "vapor", matches: digest)
print(result)

scrypt

PBKDF2와 유사한 adaptive key derivation function이며 Colin Percival이 2012년 9월 17일 설계했다. scrypt는 다이제스트를 생성할 때 메모리 오버헤드를 갖도록 설계되어, 억지 기법 공격(brute-force attack)을 시도할 때 병렬화 처리가 매우 어렵다. 따라서 PBKDF2보다 안전하다고 평가되며 미래에 bcrypt에 비해 더 경쟁력이 있다고 여겨진다. scrypt는 보안에 아주 민감한 사용자들을 위한 백업 솔루션을 제공하는 Tarsnap에서도 사용하고 있다. 또한 scrypt는 여러 프로그래밍 언어의 라이브러리로 제공받을 수 있다.

import CryptoSwift

let password: Array<UInt8> = Array("s33krit".utf8)
let salt: Array<UInt8> = Array("nacllcan".utf8)

do {
    /// password: 패스워드, salt: 암호학 솔트, dkLen: 원하는 다이제스트 길이, N: CPU 비용, r: 메모리 비용, p: 병렬화(parallelization)
    let scrypt = try Scrypt(password: password, salt: salt, dkLen: 64, N: 16384, r: 8, p: 1).calculate()
    print(scrypt)
} catch let err {
    print(err.localizedDescription)
}

마치며

전에 쓴 글에서 MD5, SHA 등의 해시 함수들은 암호화처럼 사용할 순 있었지만 시간이 지나고 기술이 발달하면서 취약점이 발견되어 사용할 수 없게되었고 간단한 메시지 인증과 무결성 체크로 활용하게 되었다. 취약점을 보안한 위와 같은 key derivation function이 생겨나게 되었고 암호화를 사용할거라면 위의 기술들을 사용하도록 하자.

출처

Why don't you read something next?

Secure Coding)대칭, 비대칭 키 암호

Share

BugkingK

Author

BugkingK

iOS developers who love to play guitar and develop

Comments

crossorigin="anonymous">