같은 평문에 같은 키를 넣었는데 암호문이 매번 달라지는 이유와, 그래서 뭘 조심해야 하는지 알아보는 글입니다.
같은 값을 두 번 암호화해 봤는데 결과가 서로 달랐습니다. 키도 같고 입력도 같은데 나온 문자열이 다릅니다.
처음에는 코드를 의심했습니다. 키가 매번 새로 만들어지나, 인코딩이 섞였나 하고 한참을 봤습니다.
그런데 복호화해 보면 둘 다 원래 값이 정확히 나왔습니다. 깨진 게 아니었습니다.
- 암호문이 매번 다른 건 버그가 아니라 정상이다
- 매번 같이 나오는 쪽이 오히려 위험한 설정이다
- 암호문 앞부분에 매번 새로 만든 값이 붙어 있다
- 그래서 암호문끼리 비교하는 코드는 반드시 틀린다
- 검색이나 중복 확인이 필요하면 다른 장치를 따로 둬야 한다
1. 결과가 매번 달라지는 게 정상입니다
같은 입력에 같은 키를 넣으면 같은 결과가 나와야 할 것 같지만, 실제로 쓰이는 암호화 방식은 의도적으로 매번 다른 결과를 냅니다.
암호화할 때 난수를 하나 만들어서 같이 섞기 때문입니다. 이 난수를 초기화 벡터, 줄여서 IV 라고 부릅니다.
난수는 아무 값이나 쓰면 안 되고 SecureRandom 처럼 예측할 수 없는 방식으로 만듭니다.

같은 값을 열 번 암호화하면 열 개가 전부 다르게 나오고, 열 개를 복호화하면 전부 같은 값이 나옵니다. 이 상태가 정상입니다.
2. 매번 같으면 무엇이 새는가
그럼 왜 굳이 다르게 만드는지가 궁금해집니다. 같으면 편할 것 같은데 말입니다.
같은 값이 항상 같은 암호문이 되면, 암호를 못 풀어도 알 수 있는 것들이 생깁니다.
- 두 사람의 값이 같은지 다른지를 알 수 있다
- 어떤 값이 몇 번 나왔는지 셀 수 있다
- 자주 나오는 값이 흔한 값이라는 걸 추측할 수 있다
예를 들어 등급 컬럼이 암호화돼 있어도 같은 암호문이 반복되면 어느 값이 다수인지 세어볼 수 있습니다. 값 자체를 몰라도 분포가 드러납니다.
주소나 생년월일처럼 겹치기 쉬운 항목이라면 같은 값을 가진 사람들을 묶어낼 수 있다는 것 자체가 이미 정보입니다.
그래서 매번 다른 난수를 섞어 같은 값이라도 다른 암호문이 되게 만듭니다.
3. 그 난수는 암호문 안에 들어 있습니다
여기서 자연스러운 질문이 나옵니다. 매번 다른 난수를 썼다면 복호화할 때 그 난수를 어디서 구하느냐입니다.
답은 간단합니다. 암호문 앞에 붙여서 같이 보관합니다.

앞의 정해진 길이만큼 잘라내면 그게 IV 이고, 나머지가 실제 암호문입니다. 복호화할 때는 이 둘을 다시 나눠서 넣습니다.
자바로 치면 AES/CBC/PKCS5Padding 에 IvParameterSpec 으로 IV 를 넘기는 구조이고, 길이는 AES 블록 크기와 같은 16바이트입니다.
IV 는 숨겨야 하는 값이 아닙니다. 키가 아니기 때문에 같이 저장해도 되고, 실제로 그렇게 씁니다. 대신 매번 새로 만들어야 하고, 예측할 수 없어야 합니다.
- 키는 비밀. 절대 같이 두면 안 된다
- IV 는 비밀이 아님. 암호문에 붙여서 보관한다
- 대신 IV 는 매번 새로, 예측 불가능하게 만든다
그래서 암호문 길이가 원문보다 길어집니다. 앞부분이 통째로 IV 자리라서 그렇습니다.
4. 진짜 문제는 비교하는 코드에서 터집니다
여기까지는 그냥 알아두면 되는 이야기인데, 실무에서 사고가 나는 지점은 따로 있습니다. 암호문끼리 비교하는 코드입니다.

암호화한 값으로 조회하는 코드는 한 건도 못 찾습니다. 저장할 때 붙은 IV 와 지금 만든 IV 가 다르니 문자열이 아예 다릅니다.
더 나쁜 건 에러가 안 난다는 점입니다. 예외도 없고 로그도 조용한데 결과만 없습니다. 그래서 데이터가 없는 줄로 착각하기 쉽습니다.
- 조회 조건에 암호화한 값을 넣으면 못 찾는다
- 중복 확인을 암호문으로 하면 전부 새 값으로 판정된다
- 두 암호문이 다르다고 해서 원문이 다른 게 아니다
두 값이 같은지 보려면 양쪽을 복호화해서 비교해야 합니다. 암호문을 그대로 대조하면 안 됩니다.
5. 검색이 필요하면 장치를 따로 둡니다
그런데 실제로는 암호화된 항목으로 찾아야 할 때가 있습니다. 전화번호로 조회한다든지 하는 경우입니다.
전부 복호화해서 훑는 방법은 건수가 늘어나면 못 씁니다. 그래서 찾기 위한 값을 따로 만들어 둡니다.
- 원문을 일정한 방식으로 변환한 값을 별도 컬럼에 같이 저장한다
- 이 값은 같은 입력이면 항상 같게 나오도록 만든다
- 조회할 때는 그 컬럼으로 찾고, 꺼낸 뒤에 복호화한다
이 값은 되돌릴 수 없어야 하고, 단순 변환이면 짧은 값은 미리 만들어 둔 표로 역추적당할 수 있으니 비밀 키를 섞은 방식을 씁니다.
정리하면 보관용 컬럼과 조회용 컬럼을 나누는 것입니다. 하나로 두 가지를 다 하려고 하면 둘 중 하나가 깨집니다.
6. IV 를 고정하면 안 되는 이유
비교가 안 되니 IV 를 고정값으로 박아버리고 싶어집니다. 그러면 같은 값은 항상 같은 암호문이 되니 검색도 되고 편합니다.
그 순간 2절에서 말한 것들이 전부 돌아옵니다. 값이 같은지 다른지, 어느 값이 많은지가 다시 드러납니다.
거기에 더해 문제가 하나 붙습니다. 흔히 쓰는 방식은 앞부분이 같으면 암호문 앞부분도 같아집니다. 그래서 값이 조금씩만 다른 항목들은 어디까지 같고 어디서 갈라지는지까지 보입니다.
- IV 고정은 암호화 강도를 스스로 낮추는 것이다
- 편의를 위해 고정할 거면 차라리 5절 방식으로 간다
- 소스에 IV 가 상수로 박혀 있으면 점검 대상이다
7. 정리
암호문이 매번 달라지는 건 고장이 아니라 설계입니다. 그걸 모르고 보면 멀쩡한 코드를 며칠씩 뒤지게 됩니다.
정리하면 이렇습니다.
- 같은 값이라도 암호문은 매번 달라야 정상이다
- 다르게 만드는 재료(IV)는 암호문 앞에 같이 저장된다
- IV 는 비밀이 아니지만 매번 새로 만들어야 한다
- 암호문끼리 비교하는 코드는 반드시 틀린다. 복호화해서 비교한다
- 검색이 필요하면 조회용 값을 별도 컬럼으로 둔다
- IV 고정은 하지 않는다
암호화는 넣고 빼는 코드만 맞으면 끝난 것처럼 보이는데, 실제로 문제가 되는 건 그 값을 비교하고 찾는 자리입니다. 도입할 때 조회 요건까지 같이 정해두는 편이 낫습니다.
여기까지 암호문 앞에 붙는 랜덤 IV 에 대해서 작성해봤습니다. 여기까지 읽어주셔서 감사합니다!
'일상' 카테고리의 다른 글
| python-pptx 로 만든 장표에서 글자가 겹칠 때 (상자 높이와 글자 높이는 다르다) (0) | 2026.09.10 |
|---|---|
| 3.3% 떼고 받았는데 5월에 또 신고하라고 할 때 (원천징수는 세금이 아니라 선납) (0) | 2026.09.09 |
| AWS SES 535 Authentication Credentials Invalid 로 메일 발송이 막힐 때 (IAM 액세스 키와 SMTP 자격증명 차이) (0) | 2026.09.09 |
| ssh-keygen 한 번에 개인키를 날렸을 때 (덮어쓰기 함정과 복구 경로) (0) | 2026.08.30 |
| python-pptx로 투명도와 그라데이션 넣기 (안 먹는 속성 대신 XML 직접 쓰기) (0) | 2026.08.30 |