ADR-13: NaCl SecretBox 암호화
| 날짜 | 작성자 | 리포지토리 |
|---|---|---|
| 2025-12-23 | @KubrickCode | core, web, collector |
배경
문제 상황
데이터베이스에 저장되는 OAuth 토큰은 암호화가 필요함. 여러 서비스에서 토큰 암복호화가 발생함:
- Web 서비스: OAuth 자격증명 저장 시 암호화
- Collector 서비스: GitHub API 접근 시 복호화
요구사항
| 요구사항 | 설명 |
|---|---|
| 인증된 암호화 | 변조 방지 및 데이터 무결성 보장 |
| 대칭키 | 동일 키로 암복호화 |
| 스레드 안전 | 멀티 고루틴 환경에서 동시 암호화 가능 |
| 서비스 간 공유 | web/collector에서 동일 코드베이스 사용 |
| 키 로테이션 지원 | 데이터 손실 없이 키 교체 가능 |
결정
NaCl SecretBox (XSalsa20 + Poly1305)를 대칭 인증 암호화에 사용함.
pkg/crypto 패키지 제공 사항:
- 암복호화를 위한
Encryptor인터페이스 - Base64 인코딩 출력 형식:
Base64(nonce || ciphertext) - 타입 안전한 에러 처리를 위한 센티널 에러
- 스레드 안전 구현
검토한 옵션
Option A: NaCl SecretBox (선택됨)
XSalsa20 스트림 암호 + Poly1305 MAC.
장점:
- 오용 방지 설계: 192비트 nonce로 충돌 위험 사실상 제거
- 인증됨: Poly1305 MAC으로 변조 감지
- 단순한 API: 단일 함수, 오용하기 어려움
- 검증됨: libsodium 구현, 광범위한 보안 감사 완료
- IV 관리 불필요: 암호화마다 랜덤 nonce 자동 생성
단점:
- FIPS-140 비준수 (규정 준수 필요 시)
- 엔터프라이즈 환경에서 AES보다 덜 일반적
Option B: AES-GCM
Galois/Counter Mode AES.
장점:
- FIPS-140 준수
- 하드웨어 가속 (AES-NI)
- 업계 표준
단점:
- 96비트 nonce: 충돌 위험 높음, nonce 추적 필요
- nonce 재사용 치명적: 재사용 시 인증 키 노출
- 복잡한 API, 오용 가능성
Option C: AES-CBC + HMAC
암호화용 AES-CBC, 인증용 별도 HMAC.
장점:
- FIPS-140 준수
- 잘 알려진 방식
단점:
- Encrypt-then-MAC 순서 중요: 잘못된 순서는 보안 취약
- IV 관리 필요: 유일성 보장 필수
- 패딩 오라클 공격: 신중한 구현 필요
- 코드량 증가, 오류 가능성 증가
결과
긍정적
단순성
- 단일
Seal/Open함수 쌍 - 랜덤 nonce 자동 생성
- 모드 선택이나 파라미터 조정 불필요
- 단일
보안 마진
- 256비트 키, 192비트 nonce
- XSalsa20은 원본 Salsa20 대비 nonce 공간 확장
- 알려진 실용적 공격 없음
이식성
golang.org/x/crypto의 순수 Go 구현- CGO 의존성 없음
- 크로스 플랫폼 빌드 가능
부정적
규정 준수 제한
- FIPS-140 인증되지 않음
- 완화: 현재 사용 사례(OAuth 토큰)에는 허용 가능
알고리즘 종속
- 알고리즘 변경 시 전체 데이터 재암호화 필요
- 완화: 인터페이스 추상화로 구현 교체 가능
구현 세부사항
출력 형식:
Base64(nonce || ciphertext)
24 bytes plaintext + 16 bytes overhead키 관리:
bash
# 32바이트 키 생성
openssl rand -base64 32인터페이스 설계:
go
type Encryptor interface {
Encrypt(plaintext string) (string, error)
Decrypt(ciphertext string) (string, error)
Close() error // 메모리에서 키 제거
}