coldkey
CI
Release
Go
License: MIT
사용자의 에이지 암호화 키는 디스크 장애 한 번으로도 완전히 손실될 수 있습니다. 만약 age나 sops를 사용하여 비밀 정보를 암호화한다면, 개인 키를 잃어버리는 것은 그것이 보호하는 모든 것에 대한 접근을 영원히 잃는 것을 의미합니다.
coldkey는 포스트-양자(post-quantum) 에이지 키(ML-KEM-768 + X25519)를 생성하고, QR 코드가 포함된 단일 페이지 인쇄용 HTML 백업을 만듭니다. 이를 인쇄하여 라미네이팅하고 방화 금고에 보관하세요. 모든 디지털 사본이 사라지더라도 사용자의 비밀 정보는 살아남습니다.
demo
Image of Printout
빠른 시작 (Quick start)
brew install --cask pike00/tap/coldkey
...
키 생성 시 방어 심층(defense-in-depth)을 위해 아래의 Hardened mode (Docker)를 참고하세요.
명령어 (Commands)
coldkey (인수 없음) — 대화형 모드 (Interactive mode)
새 키를 생성하거나 기존 키에서 백업을 만들도록 메뉴를 표시합니다. 파일 경로를 요청하고 덮어쓰기 전에 확인합니다.
coldkey generate
새로운 포스트-양자 에이지 키 쌍(post-quantum age key pair)을 생성합니다.
coldkey generate [flags]
-o PATH 키 파일 출력 경로 (기본값: stdout)
-f 기존 파일 덮어쓰기
...
coldkey backup
기존 키 파일에서 인쇄 가능한 HTML 종이 백업을 만듭니다.
coldkey backup [flags] KEYFILE
-o PATH HTML 출력 경로 (기본값: KEYFILE-backup.html)
coldkey version
버전 문자열을 출력합니다.
보안 모델 (Security model)
| 레이어 | 측정 항목 |
|---|
| 메모리 | mlockall(MCL_CURRENT|MCL_FUTURE)는 키 자료가 디스크로 스왑되는 것을 방지합니다. |
| ... | |
Hardened mode (Docker)
선택적(optional) distroless Docker 이미지는 네트워크 격리, 읽기 전용 루트 파일 시스템 및 제거된 권한(dropped capabilities) 하에서 키 생성을 실행합니다. 결과로 생성되는 keys.txt는 호스트에 마운트된 볼륨에 기록되므로, 컨테이너는 생성 단계만 강화하며 — 키가 저장되는 상태(key at rest)는 다른 파일과 마찬가지로 호스트에 존재합니다.
docker pull ghcr.io/pike00/coldkey:latest
...
출력은 ./output/에 작성됩니다. just docker-run 및 just docker-backup 레시피는 이 플래그들을 자동으로 적용합니다:
| 플래그 | 목적 |
|---|
--network none | 네트워크 접근 없음 — 키 생성이 순수하게 로컬에서 이루어짐 |
| ... | |
QR 코드 인코딩
PQ age는 32바이트 시드(확장된 ML-KEM-768 개인 키가 아님)만 저장하므로, 전체 keys.txt는 일반적으로 약 2,089바이트 — 단일 QR 코드에 적합합니다 (버전 40, EC-L은 2,953바이트 지원).
키 파일이 단일 QR 코드 용량을 초과하는 경우, coldkey는 간단한 프레이밍 프로토콜을 사용하여 여러 QR 코드로 자동으로 분할합니다:
COLDKEY:<part>/<total>:<data>
복구: 모든 QR 코드를 순서대로 스캔하고, 각 코드에서 COLDKEY:N/M: 접두사를 제거한 다음, 연결하고 SHA-256 체크섬을 확인합니다.
종이 백업 내용물
생성된 HTML 문서에는 다음 내용이 포함됩니다:
- 제목 및 메타데이터 (날짜, 호스트 이름, 사용자, 소스 경로)
- 모노스페이스 형식의 원시 키 텍스트 (수동 전사용)
- 용량 주석이 있는 QR 코드(들)
- 검증을 위한 SHA-256 체크섬
- 단계별 복구 지침
- 인쇄 버튼 (인쇄 매체에서 숨겨짐)
복구 절차
- QR 코드를 스캔하거나 (또는 원시 키 텍스트를 입력)
~/.config/sops/age/keys.txt에 저장
- 검증:
sha256sum keys.txt가 인쇄된 체크섬과 일치하는지 확인
- 테스트:
sops -d <임의의 .sops 파일>
빌드
just build
just docker
just test
...
제한 사항
- Go GC 및 보안 메모리 처리: Go의 가비지 컬렉터(GC)는 메모리 내 객체를 복사할 수 있으며, Go 문자열은 불변(immutable)이므로
string으로 보유된 키 자료(예: identity.String()에서 가져온 것)는 신뢰성 있게 덮어쓸 수 없습니다. secure.Zero()는 Go의 내장 clear()를 사용하여 []byte 버퍼를 지우지만, 이전에 발생한 문자열 복사본은 가비지 컬렉션될 때까지 힙(heap)에 남아 있을 수 있습니다. mlockall은 이러한 내용이 디스크로 스왑되는 것을 방지합니다. 이들을 함께 사용하면 키 자료가 RAM에서 즉시 지워진다는 암호학적 보장은 아니지만, 깊이 있는 방어(defense-in-depth)를 제공합니다.
mlockall은 CAP_IPC_LOCK 필요: 완전한 스왑 보호를 위해 Docker 실행 시 --cap-add IPC_LOCK을 추가하십시오. 이것 없이는 coldkey가 stderr에 경고 메시지를 출력하고 계속 진행됩니다.
- QR 스캔: 매우 밀도가 높은 QR 코드(버전 40)는 종이에서 스캔하기 어려울 수 있습니다. 원본 키 텍스트는 항상 수동 대체 방안으로 포함되어 있습니다.
라이선스
MIT