HideFile은 내 암호로 만든 키로 브라우저에서 파일을 암호화한 다음, 암호화된 결과를 평범한 사진, PDF, 비디오 안에 저장합니다. 파일과 암호는 저희에게 전송되지 않습니다. 이 페이지는 알고리즘과 매개변수의 이름을 밝히고, 앱이 실제로 무엇을 전송하는지 정확히 나열하며, 꼼꼼한 독자가 저희의 약점으로 꼽을 만한 부분까지 포함해 한계를 솔직하게 적습니다.

나머지 내용을 정리해 주는 두 가지 개념이 있습니다. 암호화는 보안 계층입니다. 암호가 없으면 내용을 읽을 수 없습니다. 커버 파일은 위장입니다. 내 파일을 둘러보는 사람에게 암호화된 바이트가 어떻게 보이는지를 바꿀 뿐, 조사하는 사람에게까지 보이지 않게 만들지는 않습니다.

암호는 내 기기에서 키가 됩니다

잠금 파일을 만들 때 HideFile은 메모리 하드(memory-hard) 키 유도 함수인 Argon2id(버전 1.3)로 암호를 키로 바꿉니다. 메모리 하드란 시도할 때마다 시간뿐 아니라 메모리 블록도 소모한다는 뜻이어서, 추측용으로 만든 하드웨어에서도 추측이 느립니다.

비용은 파일을 만드는 환경에 따라 달라집니다. 데스크톱 브라우저에서 Argon2id는 단일 레인에서 메모리 64MiB와 반복 3회를 사용합니다. 휴대폰이나 태블릿으로 보고하는 브라우저, 또는 메모리 4GB 이하인 브라우저에는 19MiB, 반복 2회, 단일 레인이 적용됩니다. 휴대폰 브라우저는 잠금을 풀 때마다 64MiB를 안정적으로 쓰다가는 실패하기 때문입니다. 이 낮은 설정은 Argon2id에 대한 OWASP 최소 권장 사항을 충족합니다. 매개변수는 잠금 파일 안에 저장되므로, 데스크톱에서 만든 파일은 휴대폰에서 열어도 64MiB 비용이 유지됩니다.

잠금 파일마다 무작위 16바이트 솔트(salt)가 함께 저장됩니다. 같은 암호를 고른 두 사람도 서로 다른 키를 얻으므로, 추측 표를 하나 미리 계산해 모든 파일에 써먹을 수는 없습니다.

파일은 XChaCha20-Poly1305로 봉인됩니다

암호에서 나온 키가 파일을 직접 암호화하지는 않습니다. 잠금 파일마다 내 기기에서 생성한 고유한 무작위 256비트 파일 키가 있습니다. 암호 키가 이 파일 키를 감싸고(wrap), 파일 키가 내 파일을 봉인합니다.

봉인에는 인증 암호(authenticated cipher)인 XChaCha20-Poly1305를 사용하며, 내용을 비공개로 유지하고 변조를 감지합니다. 파일은 레코드로 저장되고, 각 레코드에는 고유한 무작위 192비트 논스(nonce)와 Poly1305 인증 태그가 있습니다. 손상된 사본이든 고의든 레코드가 바뀌면, 조용히 잘못된 내용을 돌려주는 대신 잠금 해제가 오류와 함께 실패합니다.

브라우저 안에서: 암호와 무작위 16바이트 솔트가 Argon2id(64MiB 3회, 휴대폰과 저메모리 브라우저는 19MiB 2회)에 들어가 32바이트 암호 키를 만듭니다. 이 키가 무작위 256비트 파일 키를 감쌉니다. XChaCha20-Poly1305가 파일을 레코드로 봉인하며, 각 레코드에는 무작위 192비트 논스와 변조 태그가 있습니다. 봉인된 레코드는 커버 파일 안에 저장됩니다.
암호 하나, 키 둘. 암호 키는 파일 키를 감쌀 뿐입니다.

두 알고리즘 모두 오픈 소스 RustCrypto 라이브러리(argon2, chacha20poly1305 크레이트)에서 가져왔습니다. Rust로 작성한 저희 자체 코어가 이를 사용하며, WebAssembly로 컴파일되어 브라우저에서 실행됩니다. HideFile이 실행되는 모든 곳에서 같은 코어가 실행되므로, 플랫폼마다 따로가 아니라 하나의 구현만 검토하면 됩니다.

HideFile의 Set a password 단계. 가려진 암호, Strong이라고 표시된 녹색 강도 표시기, Create locked file 버튼이 있습니다.
암호가 유일한 열쇠입니다. Create locked file 뒤의 멈춤은 Argon2id가 일하는 시간입니다.

잠그는 내용은 아무것도 업로드되지 않습니다

잠그기, 잠금 해제, 저장은 모두 브라우저 탭에서 이루어집니다. 파일, 파일 이름, 암호, 키는 HideFile 서버로 전송되지 않으며, 잠금 파일을 저장하는 HideFile 서버도 없습니다. 한 가지 예외는 직접 켜는 기능입니다. Cloudflare R2 같은 S3 호환 버킷을 직접 연결하면, 앱은 암호화된 바이트를 저희가 아니라 그 버킷으로 내 기기에서 곧바로 보냅니다.

앱은 몇 가지를 내 기기의 브라우저에 보관합니다. 다시 열기를 빠르게 하려고, 마지막으로 연 잠금 파일의 사본을 암호화된 상태로 최대 하루, 최대 100MB까지 저장합니다. 재사용하려고 저장한 파일과 열려 있는 파일의 작업용 사본은 브라우저의 비공개 파일 저장소에 있습니다. 또한 테마, 보기 방식 같은 설정과, 마지막으로 연 커버 열 개의 이름, 크기, 시간을 기억하며, 암호는 절대 기억하지 않습니다. 사이트 데이터를 삭제하면 모두 지워집니다. 공용이거나 빌린 컴퓨터에서는 사용을 마칠 때 이렇게 하세요.

전송되는 분석 데이터에는 파일 정보가 없습니다

사용량을 집계하기 위해 PostHog를 사용하며 자동 캡처(autocapture)는 꺼 두었기 때문에, 클릭과 페이지 내용은 기록되지 않습니다. 전송되는 항목은 다음과 같습니다.

  • 페이지 조회: 페이지 경로와 참조 URL, 브라우저와 기기 종류, 화면 크기.
  • 대략적인 국가. 요청이 도착할 때 PostHog가 IP 주소로부터 추정합니다.
  • 재방문을 세기 위해 브라우저에 보관되는 익명의 무작위 식별자.
  • 이벤트 세 가지, locked_file_created, locked_file_opened, locked_file_saved. 각각 커버 형식(png, jpeg, mp4, pdf)과 플랫폼(web 또는 native)만 담고 있습니다.

파일 이름, 크기, 개수, 경로, 암호, 키, 내용, 오류 메시지는 전송되지 않습니다. uBlock Origin 같은 콘텐츠 차단기는 분석을 차단하며, 앱은 똑같이 동작합니다. 직접 확인할 수도 있습니다. 브라우저 개발자 도구를 열고, 파일을 잠그고 저장하는 동안 네트워크 탭을 지켜보면서 내 파일을 담은 요청이 있는지 찾아보세요. 이 목록의 구속력 있는 버전은 개인정보 처리방침입니다.

내 기기에 남는 것: 파일, 파일 이름과 크기, 암호, 암호화 키, 잠금 해제된 내용, 커버 파일. 분석으로 전송되는 것: 경로와 참조 페이지가 있는 페이지 조회, 브라우저, 기기, 화면 크기, 대략적인 국가, 익명의 무작위 ID, 커버 형식과 플랫폼만 담은 세 가지 이벤트(생성, 열기, 저장). 직접 설정한 경우에만: 암호화된 바이트가 저희가 아니라 내 S3 또는 R2 버킷으로 전송됩니다. 앱의 코드는 방문할 때 hidefile.app에서 내려받습니다.
내 기기에 남는 것과, 밖으로 나가는 짧은 목록.

위협 모델, 사람 기준으로 정리

누가결과이유
내 휴대폰, 노트북, 클라우드 드라이브를 넘겨 보는 사람막음평범한 사진, PDF, 비디오가 보이고, 금고라는 이름이 붙은 것은 없습니다
내 휴대폰 암호를 아는 사람막음커버에는 기기 잠금과 별개인 자체 암호가 있습니다
커버 사본은 있지만 암호는 없는 사람막음내용은 암호화된 채로 남습니다
포렌식 조사관, 또는 HideFile을 알고 꼼꼼히 확인하는 사람숨겨지지 않음데이터가 추가되었다는 것은 알 수 있으며, 내용은 암호화된 채로 남습니다
암호를 내놓으라고 강요할 수 있는 사람막지 못함어떤 소프트웨어도 이를 해결하지 못합니다
잠금이 풀린 기기의 악성코드, 화면 녹화, 지켜보는 사람막지 못함파일이 열려 있는 동안에는 내가 보는 것을 그대로 봅니다
막음: 내 휴대폰이나 노트북을 넘겨 보며 평범한 사진을 보게 되는 사람, 커버에 자체 암호가 있으므로 내 휴대폰 암호를 아는 사람, 내용이 암호화된 채로 남으므로 암호 없이 사본을 가진 누구나. 숨겨지지 않음: 데이터가 추가되었음을 알 수 있는 포렌식 조사관. 막지 못함: 암호를 강제로 받아낼 수 있는 사람, 잠금이 풀린 기기의 악성코드나 지켜보는 사람.
HideFile은 가벼운 훔쳐보기를 막아 주며, 포렌식 도구를 막아 주지는 않습니다.

포렌식 도구는 데이터가 추가되었음을 알 수 있습니다

HideFile은 데이터가 존재한다는 사실을 포렌식 검사에서 숨기려 하지 않으며, 그렇다고 주장하지도 않습니다. 암호화된 레코드는 커버 자체의 파일 구조 안에 있어서 일반 뷰어는 이를 무시합니다. 목적에 맞게 만든 도구나 무엇을 찾아야 할지 아는 조사관은 레코드가 추가되었음을 식별할 수 있습니다. 파일 크기는 더 단순한 단서입니다. 짧은 휴가 스냅 사진이 수 기가바이트를 담고 있다면 이상하며, 커버를 손대지 않은 원본과 비교하면 차이가 곧바로 드러납니다.

조사관이 얻는 것은 무언가 있다는 사실이지 내용이 아닙니다. 암호가 없으면 레코드는 봉인된 채로 남습니다. 이것이 솔직한 경계선입니다. 눈에 띄지 않게 두는 방식은 호기심 많은 사람과 일반적인 검색에 대한 답이지, 내 기기를 손에 쥔 집요한 조사관에 대한 답이 아닙니다. 국경 검색, 훈련된 조사관, 법적 압박에는 맞지 않는 도구입니다.

변조 감지는 봉인된 레코드를 대상으로 하며, 커버의 모든 바이트를 대상으로 하지는 않습니다. 커버를 다시 저장하거나, 메타데이터를 제거하거나, 다시 압축하는 앱은 암호화 쪽에서 아무 경고 없이 사진을 바꿀 수 있고, 레코드를 통째로 지워 버릴 수도 있으며, 그러면 안의 파일이 사라집니다. 커버는 파일로 보관하세요.

암호 복구는 없습니다

저희는 내 암호를 갖고 있지 않으며 잠금 파일로부터 암호를 유추할 수도 없습니다. 재설정 링크도, 복구 코드도, 파일을 열어 줄 수 있는 지원 절차도 없습니다. 암호를 잃으면 안의 파일도 잃습니다. 이것은 설계상의 특성이며, 내 커버 사본을 가진 누군가가 저희에게 열어 달라고 요청할 수 없는 이유이기도 합니다.

오픈 소스가 아니고 감사도 받지 않은 부분

HideFile 소스 코드는 공개되어 있지 않으며, 독립된 업체의 감사도 받지 않았습니다. 알고리즘은 표준이고, 이를 구현한 라이브러리는 오픈 소스이며, 이 페이지와 앱 안의 보안 페이지가 매개변수를 알려 주지만, 이를 호출하는 저희 코드는 현재 외부인이 읽을 수 없습니다.

이는 중요한 문제입니다. 사진에 데이터를 숨기는 또 다른 비공개 도구에 반응한 Hacker News 댓글 작성자는 이를 네 단어로 표현했습니다. "no source code == no security." 그 커뮤니티의 다른 사람들은 웹 앱이 방문할 때마다 서버에서 새로 전달되므로, 소스를 공개하더라도 내가 실행하는 코드가 그 소스와 일치하는지 확인할 방법이 필요하다고 지적합니다. 두 지적 모두 타당하며, 그런 기준을 지키는 독자에게 HideFile은 아직 그 기준을 충족하지 못합니다. 변명하기보다 그렇게 말씀드리겠습니다. 결함을 발견하면 재현 방법과 함께 support@hidefile.app으로 이메일을 보내 주시고, 공개하기 전에 수정본을 낼 합리적인 시간을 주세요.

출처