SpaceMoon이 파일을 보호하는 방식
이 페이지에서는 SpaceMoon이 하는 일과 할 수 없는 일을 쉬운 말로 설명해요. 지나치게 큰 약속을 믿게 하기보다 한계를 알려 드리는 편이 낫다고 생각해요.
요약
- 모든 암호화는 휴대폰 안에서 이루어져요. SpaceMoon 서버도, 계정도 없어요.
- 파일은 무작위 키로 암호화돼요. 그 키는 내 패턴, 복구 문구, 지문으로만 열 수 있어요.
- 개발자인 저희는 패턴, 복구 문구, 키를 전혀 갖고 있지 않아요. 저희는 파일을 열 수 없고, 패턴을 초기화해 드릴 수도 없어요.
- Android에 내장된 암호화와 널리 알려진 libsodium 라이브러리를 사용해요. 암호화를 직접 만들지 않았어요.
- SpaceMoon은 아직 독립적인 보안 감사를 받지 않았어요.
패턴에서 키까지
패턴은 5×5 점에서 6개 이상을, 같은 점을 두 번 지나지 않게 이어 그려요. SpaceMoon은 Argon2id로 패턴을 키로 바꿔요. 이때 libsodium(Android에서는 1.0.20 버전)을 사용해요.
- 설정값: 메모리 64 MiB, 반복 3회, 레인 1개, 256비트 키.
- Argon2id는 일부러 느리게 동작하고, 추측할 때마다 많은 메모리가 필요해요. 그래서 그래픽 카드로 추측하는 데 드는 비용이 훨씬 커져요.
- 저희 테스트 휴대폰에서는 한 번 잠금 해제하는 데 약 0.6~0.9초가 걸려요.
- 패턴은 무작위 16바이트 기기 솔트와 섞여요. 솔트는 앱 안에 저장되며, 휴대폰 밖으로 복사할 수 없는 Android Keystore 키로 암호화돼요.
- 패턴 사본은 어디에도 저장하지 않아요. 앱은 그 패턴으로 키가 열리는지 시도해서 패턴을 확인해요.
- 패턴을 5번 연속 틀리면 30초를 기다려야 해요. 그 뒤로 틀릴 때마다 대기 시간이 두 배로 늘어나며, 최대 16분까지 늘어나요.
파일 암호화 방식
- 보관함마다 무작위 256비트 마스터 키가 있어요. 패턴 키와 복구 키는 이 마스터 키를 "감싸는"(암호화하는) 역할만 해요.
- 파일, 썸네일, 항목 목록(원래 파일 이름, 날짜, 크기)은 Android 내장 암호화로 AES-256-GCM 암호화돼요. GCM은 파일이 바뀌거나 다른 파일로 바꿔치기된 것도 알아내요.
- 앱 안의 파일은 무작위 이름을 써요. 큰 파일은 1 MiB 단위로 나눠 암호화하기 때문에, 동영상을 재생할 때도 암호화되지 않은 사본을 저장 공간에 쓰지 않아요.
- JPEG 사진의 숨은 정보(카메라, 날짜 같은 EXIF)는 따로 저장되며, 이것도 암호화돼요.
- 앱이 잠기면 메모리에 들고 있던 키를 0으로 덮어써요.
복구 문구
- 보관함을 만들 때 휴대폰의 안전한 난수 생성기가 영어 단어 9개를 골라요. 단어는 자주 쓰는 단어 1,024개로 된 목록 2개에서, 정해진 순서 4가지 중 하나로 뽑혀요. 무작위성은 92비트예요. 앱을 어떤 언어로 쓰든 단어는 영어예요.
- 문구도 같은 Argon2id 설정을 거치며, 문구 하나만으로 마스터 키를 열 수 있어요. 기기 솔트가 필요 없어서 패턴으로 열 수 없게 된 때에도 쓸 수 있어요.
- 문구 사본은 휴대폰에 두 번 암호화되어 저장돼요. 한 번은 마스터 키로, 한 번은 Android Keystore 키로요. 패턴을 다시 그리면 설정에서 볼 수 있어요.
- 패턴을 바꾸거나 문구로 다시 들어오면 새 문구를 받아요. 이전 문구는 더 이상 쓸 수 없어요.
지문
지문 잠금 해제는 선택 사항이에요. 지문은 SpaceMoon이 아니라 Android가 확인하며, 앱은 지문 정보를 받지 않아요. 강한 생체 인증을 막 통과했을 때만 쓸 수 있는 Android Keystore 키가 마스터 키를 열어요. 누군가 휴대폰에 새 지문을 추가하면 이 키는 더 이상 쓸 수 없고, 다시 패턴을 사용해야 해요.
백업 파일
- 백업은
.smb파일 하나예요. 이미 암호화된 상태 그대로의 항목과, 감싼 마스터 키 사본 2개가 들어 있어요. 하나는 백업할 때 그린 패턴용이고, 다른 하나는 그때의 복구 문구용이에요. - 패턴용 사본은 기기 솔트가 아니라 백업마다 새로 만든 무작위 솔트를 써요. 그래서 새 휴대폰에서도 백업을 열 수 있어요.
- 파일 헤더는 보호되어 있어서, 내용이 바뀌거나 일부가 바꿔치기되면 알아낼 수 있어요.
- 저장 위치는 Android 자체 저장 화면에서 직접 골라요. 파일은 저희를 거치지 않아요.
- 복원하려면 그 백업의 패턴이나 복구 문구로 파일을 열어요. 그다음 새 패턴을 그리고 새 복구 문구를 받아요.
앱의 다른 보호 기능
- 모든 화면에서 스크린샷, 화면 녹화, 최근 앱 목록의 미리보기가 차단돼요.
- 기본적으로 앱을 나가는 즉시 잠겨요. 대신 30초 후나 1분 후로 바꿀 수 있어요.
- Android 자체 클라우드 백업과 휴대폰 간 데이터 이전에는 SpaceMoon 데이터가 포함되지 않아요. 대신 백업 파일을 사용하세요.
- 앱은 위치, 연락처, "모든 파일" 접근 권한을 요청하지 않아요.
알아야 할 한계
모든 것을 막아 주는 앱은 없어요. SpaceMoon의 한계를 솔직하게 알려 드려요.
단순한 패턴은 맞히기 쉬워요
짧거나 흔한 모양(L, Z, 직선)은 옆에서 지켜보거나, 화면에 남은 자국을 보거나, 몇 번만 시도해도 맞힐 수 있어요. 사람들이 실제로 쓰는 패턴은 가능한 패턴의 수가 말해 주는 것보다 훨씬 맞히기 쉬워요. 더 많은 점을 지나고 더 여러 번 꺾어 주세요. 너무 단순한 패턴이면 앱이 알려 줘요.
추측에 걸리는 시간
앱 안에서는 한 번 시도할 때마다 약 1초가 걸리고, 5번 틀린 뒤로는 대기 시간이 늘어나요. 하지만 내 백업 파일을 가진 사람이나, 루팅된 휴대폰에서 기기 솔트를 빼낸 사람은 대기 시간 없이 컴퓨터로 추측할 수 있어요. Argon2id가 속도를 늦추지만, 패턴은 긴 비밀번호보다 경우의 수가 훨씬 적어요. 고성능 그래픽 카드 1장(RTX 4090급)으로 초당 약 1,000번 추측한다고 할 때의 대략적인 추정치예요.
| 추측 대상 | 경우의 수 | 걸리는 시간(그래픽 카드 1장) |
|---|---|---|
| 가장 흔한 패턴 10,000개 | 104 | 약 10초 |
| 점 6개로 된 모든 패턴 | 1.28 × 108 | 약 1.5일 |
| 점 7개로 된 모든 패턴 | 2.42 × 109 | 약 28일 |
| 점 8개로 된 모든 패턴 | 4.36 × 1010 | 약 1.4년 |
| 복구 문구(92비트) | 4.95 × 1027 | 약 1.6 × 1017년 |
측정값이 아니라 추정치예요. 패턴 수는 최대치이고, 실제로 쓰이는 패턴은 훨씬 적어요. 하드웨어가 더 많거나 빠르면 그만큼 추측도 빨라져요.
백업 파일은 나만 볼 수 있게 보관하세요
백업 파일에는 기기 솔트가 없어서, 파일을 손에 넣은 사람은 누구든 위처럼 오프라인으로 패턴을 시도할 수 있어요. 내 클라우드 계정처럼 나만 접근할 수 있는 곳에만 보관하고, 더 긴 패턴을 쓰세요.
루팅되었거나 악성 앱에 감염된 휴대폰
누군가 앱의 권한으로 코드를 실행할 수 있다면(예: 루팅된 휴대폰, 또는 휴대폰을 완전히 장악한 악성 앱), 기기 솔트를 열어 오프라인으로 추측할 수 있어요. 보관함이 열려 있는 동안에는 키가 메모리에 있어서 루트 권한이나 디버거로 읽을 수 있어요. Android와 Flutter 내부에서 만들어지는 일부 사본과 화면에 표시된 사진은 메모리에서 바로 지울 수 없어요.
일부 정보는 드러나요
앱 저장 공간에 있는 암호화된 파일의 개수, 대략적인 크기, 만들어지거나 바뀐 시각은 숨겨지지 않아요. SpaceMoon이 설치되어 있다는 사실도 마찬가지예요.
앱 아이콘 변경은 홈 화면만 바꿔요
- 런처의 아이콘과 이름만 바뀌어요. 휴대폰의 설정 > 앱 목록, 앱 정보, 저장 공간 화면에는 여전히 SpaceMoon으로 표시돼요.
- 화면 낭독기는 여전히 "SpaceMoon"이라고 읽을 수 있어요. 예를 들어 삼성 One UI 런처는 TalkBack에 실제 앱 이름을 전달하며, 앱에서 이를 바꿀 수 없어요.
- Android 공유 메뉴에는 항상 실제 앱 이름이 표시돼요. 그래서 아이콘을 바꾸면 SpaceMoon이 공유 메뉴에서 빠져요. 다시 켤 수 있어요.
- Android 권한 요청 창에는 실제 이름이 표시돼요. 그래서 앱은 아이콘을 바꾸기 전에 권한을 요청해요.
- 아이콘이 바뀐 동안에는 앱이 알림을 보내지 않아요.
- 열기 코드(4~8자리 숫자)는 잠금 화면만 열어 줘요. 파일을 열지는 못해요. 솔트를 넣은 해시로 저장되지만, 경우의 수가 아주 적어서 누군가 파일을 손에 넣으면 쉽게 알아낼 수 있어요.
지문은 더 약한 경로예요
지문 잠금 해제는 Argon2id를 거치지 않아요. 안전성은 휴대폰의 지문 센서와 Android Keystore에 달려 있어요. 언제든 설정에서 끌 수 있어요.
침입자 사진
앱은 셔터음을 내지 않지만, 일본이나 한국 등 일부 국가에서 판매된 휴대폰은 셔터음이 항상 나요. 다른 앱이 카메라를 쓰고 있거나 전면 카메라가 없으면 사진을 찍지 않아요. 처음 만든 보관함을 열기 전까지 사진은 Android Keystore 키로 잠겨 있어요.
사진 정보
- HEIC, PNG, WebP 사진의 숨은 정보(EXIF)는 파일 안에 그대로 남아요. 그래도 파일 전체는 암호화돼요.
- Android 10 이상에서는 앱이 위치 권한을 요청하지 않기 때문에, SpaceMoon이 읽는 사진에서 Android가 GPS 위치를 지워요. 갤러리에서 원본이 삭제되면 그 위치 정보는 사라져요.
- Android 사진 선택기로 추가한 사진은 날짜를 바탕으로 새 이름이 붙어요. 사진 선택기가 원래 이름을 알려 주지 않기 때문이에요.
시스템 화면이 열려 있는 동안에는 잠기지 않아요
시스템 화면(권한 요청, 삭제 확인, 사진·파일 선택기, 지문 확인 창)이 열려 있는 동안과 가져오기나 내보내기가 진행되는 동안에는 앱이 잠그기를 미뤄요. 앱을 나간 상태라면 그것이 끝나고 2초 뒤에 잠겨요.
보관함들은 기기 솔트를 함께 써요
한 휴대폰의 모든 보관함은 같은 기기 솔트를 써요. 누군가 그 솔트를 가지고 있다면, 한 번의 추측으로 모든 보관함을 동시에 시험할 수 있어요. 보관함 하나를 공격하는 데 드는 비용은 똑같아요.
어떤 앱도 막을 수 없는 것
누군가 패턴을 그리는 모습을 지켜보거나, 카메라로 화면을 찍는 경우예요.
둘 다 잃어버리면 누구도 도울 수 없어요
패턴과 복구 문구를 모두 잃어버리면 누구도 파일을 되살릴 수 없어요. 저희도 마찬가지예요.