해시함수와 암호화 비교
해시(Hash)와 암호화(Encryption)의 가장 큰 차이는 '방향'이다.
- 해시 : 단방향 암호화이므로 복호화는 불가능하다. 데이터 보안에 중점을 둠.
- 암호화 : 양방향 암호화이므로 복호화 가능하다. 통신에서 보안에 중점을 둠.
암호화의 목적은 반드시 복호화하는 것은 아니기 때문에, 각자 관점에 따라 둘 다 암호화라고 부르기도 한다. 예를 들어 암호화 해시 함수(cryptographic hash function)라는 개념이 있듯이 말이다. 그래서 해시를 암호화가 아니라고 할 필요는 없는 것 같다(?)
암호화
개인키 (Symmetric key)
다른 말로 대칭키, 비공개키, 비밀키라고 부른다. 암호화와 복호화할 때 같은 비밀키를 공유한다. 따라서 키가 유출되면 해킹 당할 수도 있다. 하나의 키를 사용하기 때문에 속도가 빠르지만, 어느 한 쪽이 생성한 키를 다른 한 쪽에게 안전하게 전달하는 것이 힘들다.
- 개인키 종류 : DES, 3DES, AES, SEED 등
공개키 (ASymmetric key)
다른 말로 비대칭키라고 부른다. 암호화와 복호화할 때 두 개의 키를 사용한다. 암호화할 때는 공개키를 사용하고, 복호화할 때는 비밀키를 사용한다. 보내야 하는 데이터를 수신측의 공개키로 암호화를 걸어 놓고, 송신측이 자신의 비밀키로 복호화를 한다.
- 공개키 종류 : DSA, RSA 등
해시함수(Hash Function)
해시함수는 체크섬(checksum)이라고 불린다. 해시함수는 메시지 인증과 무결성 체크를 위해 존재한다.
- 해시함수 종류 : MD5, SHA 등
해시함수의 특징은 입력 값의 길이에 상관 없이 고정된 길이의 해시값(=다이제스트)이 출력된다. 입력 값의 일부만 변경되더라도 avalanche 효과로 전혀 다른 해시값이 출력되버린다. (>> 테스트 해보기)
앞서 말했듯이 해시함수는 단방향(one-way)이므로 복호화를 할 수 없다. 즉 암호화는 가능하지만 복호화는 불가능하기 때문에 원본을 알 수 없다. 그렇기 때문에 패스워드는 반드시 단방향 함수를 이용해야 한다.
해시함수의 문제점
1) 인식 가능성(recognizability)
메시지가 같으면 다이제스트도 같으므로, 다른 사용자랑 패스워드가 같으면 다이제스트도 같아서 한꺼번에 털릴 수 있다. 레인보우 공격(rainbow attack)을 당할 수 있다. 이는 rainbow table에 미리 해시해둔 패스워드를 잔뜩 가지고 있다가 훔쳐낸 패스워드와 비교하는 것이다.
2) 속도(speed)
해시 함수의 처리 속도가 빠르기 때문에 무차별 대입 공격(Brute force attack)을 당할 수 있다.
해시함수의 문제점 해결
1) 솔팅(Salting)
솔팅은 패스워드에다가 임의의 문자열인 salt를 추가하여 다이제스트를 생성하는 것이다. 솔팅의 목적은 salt를 이용해서 rainbow table을 무의미하게 만드는 것이며, salt는 최소 128bit 정도는 되어야 안전하다.
![](https://blog.kakaocdn.net/dn/XIlJ9/btsASGd7Ix5/KjL7OmdWkLC1Of0yPN1Gy0/img.png)
이제 패스워드의 다이제스트를 알아버려도, salting된 다이제스트로는 해커가 패스워드 일치 여부를 알기가 매우 어렵다. 또한 사용자마다 각자 다른 salt를 사용한다면 패스워드가 같더라도 다이제스트가 다르게 생성된다.
2) Key Stretching(키 스트레칭)
키 스트레칭은 말 그대로 쭉 늘린다는 뜻이다. 해시를 여러번 반복하여 충~분히 시간을 늘림으로서 Brute force attack에 대비한다.
![](https://blog.kakaocdn.net/dn/cnMsA1/btsARTSDxNB/eB5NQJPRjC33X2vKfB7Shk/img.png)
어떻게 시간을 늘리냐면, 패스워드의 다이제스트를 생성하고, 생성된 다이제스트를 입력 값으로 하여 다이제스트를 생성하고, 또 이를 반복(Iteration count)해서 다이제스트를 생성하는 식으로 늘린다. 보통 사용자가 작성한 패스워드가 짧거나 예측하기 쉬운 경우가 많은데 Key Stretching은 이를 더 어렵게 만들어 준다.
암호화 추천!
솔팅과 키 스트레칭으로 구성된 암호화 시스템을 구현하기 보다는 이미 잘 만들어지고 검증된 암호화 시스템을 사용하자. 암호화 시스템을 잘못 구현해서 발생하는 위험을 피할 수 있다.
- PBKDF2 : 가장 많이 사용되며 Django에서 기본으로 사용 중이다. ISO-27001의 보안 규정을 준수하고 있다.
- Bcrypt : 애초부터 패스워드 저장을 목적으로 설계되어 매우 강력한 패스워드 다이제스트를 생성하는 시스템을 쉽게 구현할 수 있다. 관련된 라이브러리도 언어별로 쉽게 찾을 수 있다.
- Scrypt : 위 두 개보다 진보된 시스템이다. 만약 구현하려는 시스템이 매우 민감한 정보를 다루고, 보안 시스템을 구현하는 데 많은 비용을 투자할 수 있다면 사용한다.