보안 설계

폰에서 잠그고,
폰에서 엽니다.

글과 사진, 대화는 폰을 떠나기 전에 봉인되고, 내가 고른 사람만 열 수 있습니다. 누구와 아는 사이인지는 각자의 폰이 지니고, 서버에는 저장하지 않습니다.

01 봉인

내가 고른 사람만
열 수 있습니다

글을 올리면 폰이 먼저 봉인한 뒤에 보냅니다. 서버는 봉인된 글을 맡아 전할 뿐, 열 열쇠가 없습니다. 답과 사진, 영상, 링크 미리보기도 같은 길로 오갑니다.

글 한 편이 봉인되어 가는 길: 글쓴이의 폰, Krypton 서버, 받는 사람의 폰
  1. 글쓴이의 폰이 보안 코어 안에서 이 글만을 위한 새 콘텐츠 열쇠를 만듭니다.

  2. 그 열쇠로 글과 사진·영상을 잠급니다. 글은 정확한 길이가 드러나지 않게 정해진 크기까지 채운 뒤 잠급니다.

  3. 받는 사람마다 콘텐츠 열쇠를 그 사람의 암호화 열쇠로 봉해 봉투를 하나씩 만듭니다. 글쓴이 자신의 봉투도 하나 있습니다.

서버는 암호문과 봉투를 받아 두었다가 받는 사람에게 건넵니다. 봉투를 여는 열쇠는 받는 사람의 폰에만 있어 서버는 열지 못합니다.

  1. 받는 사람의 폰은 보안 코어 안에서 자기 봉투를 열어 콘텐츠 열쇠를 꺼냅니다.

  2. 그 열쇠로 글을 풀어 화면에 보여 줍니다.

서버에는 암호문뿐
글, 답, 사진, 영상, 링크 미리보기는 서버에 닿기 전에 이미 잠겨 있습니다.
읽는 사람마다 봉투 하나
글의 열쇠는 읽는 사람마다 따로 봉투에 담기고, 그 봉투는 그 사람의 폰만 엽니다.
글마다 새 열쇠
글과 답마다 새 열쇠를 만듭니다. 한 글의 열쇠로는 다른 글이 열리지 않습니다.
받을 사람은 내 폰이 정합니다
내 폰은 스스로 지닌 Fam 목록에 글을 봉합니다. 그 목록에는 신청을 받아들였거나 QR 코드·Fam 링크로 맺은 사람만 들어옵니다. 내가 보낸 Fam 링크는 24시간 안에 한 번만 쓰이고, 먼저 연 한 사람이 내 확인 없이 Fam이 됩니다 — 링크를 보낸 것이 동의입니다.

글은 XChaCha20-Poly1305로 잠그고, 봉투는 X25519로 봉해 쌍의 비밀 안에 담습니다. 쌍의 비밀은 X25519와 ML-KEM-768로 함께 나눕니다.

02 관계

누구와 아는 사이인지는
폰에만 남습니다

내 Fam 목록은 폰에서 봉인되고, 서버는 누가 누구를 들였는지도, 누가 누구에게 보냈는지도 저장하지 않습니다. 봉인된 것은 어느 계정에도 묶이지 않은 우편함으로 오갑니다. 다만 요청이 오가는 그 순간에는 서버도 IP 주소와 시각을 보고, 이것으로 우편함이 계정과 이어질 수 있습니다. Krypton 팀이 직접 들인 사람은 팀이 들였다는 것이 서버에 남습니다.

두 폰만 아는 비밀
두 사람이 Fam이 되면 두 폰은 서버가 보지 못하는 비밀을 나눕니다. 둘 사이에 오가는 것은 모두 이 비밀로 길을 찾습니다.
계정이 아니라 우편함
글과 대화, 명함은 어느 계정에도 묶이지 않은 우편함에 들어가고, 우편함 번호는 30일마다 바뀝니다.
보낸 사람은 봉인 안에
누가 보냈는지는 서명과 함께 봉인 안에 들어 있고, 받는 폰이 그 서명을 확인합니다.
기록에 남지 않는 초대
회원은 서버가 들여다보지 않고 내준 초대 표를 받습니다. 누군가 들어올 때 서버는 그 표가 진짜인지만 확인합니다. 서버에 저장된 기록에는 누가 누구를 들였는지가 없지만, 접속 기록과 그 순간의 요청으로는 알 수 있습니다.

둘만의 비밀은 X25519와 ML-KEM-768로 함께 봉하고, 우편함 열쇠는 HKDF-SHA256으로 뽑으며, 보낸 사람은 Ed25519로 서명합니다.

03 열쇠

열쇠는
내 폰 안에

개인 열쇠는 내 폰의 보안 코어 안에 있습니다. iPhone과 Android 앱이 함께 쓰는 코어입니다. 화면을 그리는 앱 코드에도 열쇠는 넘어가지 않습니다.

내 폰 안에서 열쇠가 있는 자리
내 폰
Krypton 앱
화면 코드JavaScript
  • 번호표(핸들)
  • 풀린 글·사진

개인 열쇠는 넘어가지 않습니다

보안 코어Rust
  • 개인 열쇠 넷
  • 콘텐츠 열쇠
키체인 · 키스토어
  • 잠긴 개인 열쇠
  • 이 폰에서만
Krypton 서버
  • 공개 열쇠
  • 잠긴 되찾기 보관본
  • 되찾기 반쪽·찾기 표 해시
이 폰에서만
iPhone 키체인이나 Android 키스토어에 두고, 백업으로 다른 폰에 옮겨 가지 않습니다. 새 폰은 되찾기로만 열쇠를 받습니다.
앱 코드는 번호표만
코어는 앱에 열쇠 대신 번호표를 줍니다. 번호표만으로는 앱 밖에서 아무것도 열리지 않습니다.
전화번호도 이메일도 없이
가입하고 들어올 때 쓰는 것은 폰에 있는 열쇠뿐입니다. 전화번호와 이메일은 받지 않습니다.
널리 쓰이는 표준 암호
직접 만든 암호는 쓰지 않습니다. 널리 쓰이는 표준을 Rust 라이브러리 dalek과 RustCrypto의 구현으로 씁니다.
  • X25519
  • ML-KEM-768
  • Ed25519
  • XChaCha20-Poly1305
  • HKDF-SHA256
  • BIP39

04 되찾기

폰을 잃어도
계정은 그대로

PIN을 정하고, 영어 단어 18개를 받아 종이에 적어 둡니다. 단어는 가입할 때 받거나 나중에 설정에서 만들 수 있습니다. 새 폰에서 단어와 PIN이 맞으면 계정이 돌아옵니다.

종이에만 있는 단어
단어 18개는 만들 때 한 번만 보여 드리고, 적은 단어를 되물어 확인합니다. 가입할 때 만들거나 나중에 설정에서 만들 수 있습니다. 단어는 서버에도 클라우드에도 폰에도 남지 않고, 다시 보여 드리지 않습니다.
단어와 PIN 둘 다
단어만으로도 PIN만으로도 열리지 않습니다. PIN은 몇 번 틀리면 잠기고, 서버는 단어 대신 단어에서 한쪽으로만 만든 값의 해시로 계정을 찾습니다.
멈출 수 있는 시간
되찾기는 48시간을 기다린 뒤에 끝납니다. 그동안 옛 폰은 요청을 보고 취소할 수 있습니다.
서버가 가진 것만으로는 열리지 않습니다
백업을 여는 비밀은 두 쪽입니다. 한쪽은 서버에, 다른 쪽은 종이에 적은 단어에 있습니다. 서버를 통째로 가져가도 단어 없이는 열리지 않습니다.

단어는 BIP39 표준 단어 18개, 192비트입니다. 양자 컴퓨터로 대입해도 2⁹⁶번이 필요합니다. 두 쪽은 HKDF로 합쳐 보관본을 엽니다.

05 통화

둘 사이에만 머무는
통화

Fam과 목소리로 이야기합니다. 목소리는 두 폰 사이에서 암호화되어 오가고, 통화 기록은 각자의 폰에만 남습니다.

Fam끼리만 걸립니다
벨은 봉인되어 두 사람만 쓰는 우편함으로 울립니다. 서버는 누가 누구에게 거는지 기록하지 않습니다.
건 사람은 받는 폰만 압니다
누가 거는지는 받는 폰이 직접 풀어 벨 화면에 띄웁니다. 서버는 건 사람의 이름을 모릅니다.
중계로 가리는 IP 주소
통화는 보통 중계 서버를 거쳐 이어집니다. 중계 서버는 두 폰의 IP 주소를 보지만 암호화된 소리는 열지 못하고, 상대에게는 내 IP 주소가 보이지 않습니다. 폰이 중계 정보를 받지 못하면 두 폰이 직접 이어지고, 그때는 서로의 IP 주소가 보일 수 있습니다.
두 폰이 서명한 연결
두 폰은 연결 정보에 각자의 열쇠로 서명합니다. 중간에서 무엇이든 바꿔치기하면 통화가 이어지지 않습니다.

연결 정보는 각자의 Ed25519 계정 열쇠로 서명합니다.

06 내가 정하는 것

무엇을 보일지
내가 정합니다

앱을 잠그고, 명함을 볼 사람을 고르고, 화면에 띄운 것은 화면에만 둡니다.

앱 잠금
폰의 얼굴·지문 인식이나 폰 암호로 Krypton을 잠급니다. 바로, 또는 앱을 떠난 지 1분·15분·1시간 뒤에. 켜 두면 앱 전환 화면에도 내용이 보이지 않습니다. 설정은 이 폰에만 두고, 서버는 잠금을 쓰는지 모릅니다.
명함을 볼 사람
명함은 봉인되어 있습니다. Fam만과 전체 공개 가운데 고르고, 어느 쪽이든 원본 사진은 Fam에게만 갑니다. 범위를 좁히면 폰이 새 열쇠로 명함을 다시 봉합니다.
화면 캡처 차단
Krypton에서 보는 화면은 캡처도 녹화도 되지 않습니다.
사라지는 글
사라지는 글로 올리면 나타난 지 24시간 뒤에 글과 대화, 사진이 함께 사라집니다.

07 양자 내성

양자 컴퓨터도
뚫기 어렵게

암호문을 지금 모아 두었다가 훗날 양자 컴퓨터로 여는 공격이 있습니다. Krypton은 내가 고른 사람에게 열쇠를 건네는 바깥 층에서 지금 검증된 암호(X25519)와 양자 내성 암호(ML-KEM-768)를 함께 씁니다.

둘 다 깨야 열립니다
두 암호에서 나온 비밀을 하나로 합쳐 봉합니다. 한쪽에 약점이 드러나도 다른 쪽이 지킵니다. Signal과 iMessage가 택한 것과 같은 하이브리드 방식입니다.
바깥 층은 모두 두 암호로
Fam 신청과 쌍마다의 비밀을 나누는 쪽지, 봉인된 백업, 되찾기, 초대 꾸러미, 신고처럼 열쇠를 건네는 바깥 층은 모두 두 암호로 봉합니다. 쌍 우편함 안의 글과 대화는 이렇게 나눈 쌍의 256비트 비밀로 감쌉니다.
바꿔치기할 수 없는 공개키
양자 내성 공개키도 계정 서명으로 묶습니다. 서버나 중간의 누군가가 다른 키로 바꾸면 서명이 맞지 않아 폰이 받지 않습니다.
본문 잠금은 그대로 튼튼합니다
글과 사진을 잠그는 256비트 XChaCha20-Poly1305와 SHA-256은 양자 컴퓨터 앞에서도 충분한 세기가 남아 바꿀 필요가 없습니다.

바깥 층은 X25519와 ML-KEM-768(미국 NIST 표준 FIPS 203)로 함께 봉하고, 두 비밀은 SHA3-256으로 하나로 묶습니다.

아직 옮기는 중인 것

  • 서명(Ed25519)은 아직 양자 내성이 아닙니다. 서명은 위조되더라도 지난 내용을 열지는 못합니다. 계정마다 ML-DSA(FIPS 204) 서명 열쇠를 가입할 때 만들어 신원에 묶어 두었고, 실용적인 양자 컴퓨터가 나올 것으로 보이기 전에 Ed25519와 함께 쓰도록 켤 계획입니다.
  • 익명 초대는 양자 컴퓨터 앞에서도 누구의 초대였는지 계속 가려 줍니다. 초대를 위조하지 못하게 막는 부분은 서명과 함께 옮깁니다.
  • 통화 음성은 두 폰 사이에서 WebRTC 표준 암호로 잠그며, 이 부분은 아직 양자 내성이 아닙니다.

어떤 앱도 지킬 수 없는 것

  • 받은 사람이 자기 사진첩에 저장한 사진, 다른 카메라로 찍은 화면
  • 잠금을 푼 채 내 폰을 넘겨받은 사람
  • 고친 앱으로 자기가 받은 것을 꺼내는 사람
  • 통화 상대가 따로 하는 녹음
  • 이미 악성 코드에 장악된 폰
  • 네트워크를 지켜보는 사람이 IP 주소와 시각으로 우편함·통화·가입을 계정에 잇는 것 — Krypton은 요청을 IP 주소를 가리는 중계로 보내지 않습니다
  • 고친 앱이 기기에서 지키는 규칙을 무시하는 것 — 차단이나 건네기 횟수의 한도 같은 규칙은 받는 사람의 앱이 지키고, 서버는 막지 않습니다
  • 나와 Fam 한 사람 사이의 비밀이 새는 것 — 이 비밀은 시간이 지나도 바뀌지 않아, 서버에 남은 그 쌍의 봉인된 쪽지(최대 90일)가 열릴 수 있습니다

자세한 기술 설명은 GitHub에 공개할 예정입니다.