HOW IT WORKS / VERIFY IT YOURSELF

映像をサーバに送らない。
仕組みと、確かめ方。

通常の撮影中、映像・音声は端末内で暗号化し、暗号文も端末内に保存します。サーバへ送るのは、メール認証の情報、撮影ID、暗号化に必要な公開情報、暗号文のハッシュなどです。

データは、どこを通る?

あなたの端末カメラ・マイク

一時的な録画データ
↓ ECDH・HKDF・AES-256-GCM
暗号文をブラウザ内に逐次保存
↓ 撮影後にダウンロード
あなたがファイルを保管

送信 →

撮影ID・ヘッダー・ハッシュなど

← 受信

公開鍵・ハッシュ受信時刻の署名など

運営のサーバ鍵・記録情報

メールアドレス
復号用秘密鍵
撮影ID・ヘッダーハッシュ
暗号文ハッシュの受信記録
通常の撮影では動画ファイルを受け取らない

この説明は通常の撮影経路についてのものです。復号を依頼する際には撮影者から暗号文を受け取り、管理者用の復号画面ではファイルをサーバにアップロードします。

撮影中の通信は、小さなJSON

撮影用APIは、このサイトの api.php へのJSON形式のPOSTです。各操作に action という名前が付いています。

操作リクエスト本文用途
session / logoutactionメール確認済みセッションの確認・解除
code-requestaction, emailメール確認コードを要求
code-confirmaction, code6桁コードで同じセッションを確認
createaction撮影ID・トークン・運営の公開鍵を受け取る
checkaction, id, nonce鍵の所持を署名で確認
beginaction, id, token, header暗号化形式・公開鍵などのヘッダーを登録
chunkaction, id, token, seq, hash, previousHash暗号文のハッシュを登録し、署名付き受信記録を得る
finishaction, id, token, seq, hash記録の終了を登録

begin の header はBase64url文字列ですが、動画ではありません。復号に必要な公開情報を記したJSONです。デコードすると撮影ID、公開鍵、salt、IVの接頭部、動画形式、鍵の指紋、ID発行時刻などが読めます。秘密鍵・動画・音声は含みません。

chunk という名前は「録画データの区切り」を意味しますが、その本文に録画データは含みません。例えば、最初の区切りでは次のような情報だけを送ります。以下のID・トークン・ハッシュは説明用です。

{
  "action": "chunk",
  "id": "SL-0123456789abcdef0123456789abcdef",
  "token": "撮影用トークン(公開しないでください)",
  "seq": 0,
  "hash": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
  "previousHash": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"
}

ハッシュはSHA-256の256ビット値を64桁の16進数で表したものです。暗号文の内容に加え、順序と前のハッシュを結び付けます。サーバはその値を受け取った時刻とともに署名します。動画の区切りが大きくても、ハッシュ値は64桁です。ハッシュから元の暗号文や映像を実用的に復元することはできません。

API本文の上限は24,000バイトで、JSON以外の本文は拒否します。ただし、この上限だけでは「他の送信経路がない」ことの証明にはなりません。通信一覧と実際に配信されたプログラムを合わせて確認します。

自分のブラウザで通信を確認する

まず、顔や個人情報が映らない短いテスト撮影で試してください。PCのChrome・Edgeなら開発者ツールを使えます。スマホでは、対応するPCとのリモートデバッグを使う方法があります。

  1. 撮影前に開発者ツールを開き、Network(ネットワーク)を選びます。ログの記録を有効にし、必要なら Preserve log を有効にします。ページを読み直して、認証から終了まで記録します。
  2. All(すべて)を選び、フィルターを空にして全通信を確認します。宛先、HTTPメソッド、Initiator(開始元)、POST本文を見ます。画像・HTML・JavaScriptのGETは表示用ファイルのダウンロードです。マンガの画像もGETです。
  3. 次に api.php で絞り込み、撮影中に繰り返すPOSTを選びます。Payload(ペイロード)で、action: "chunk" と上の6項目を確認します。動画のバイナリ、Blob、長い動画のBase64文字列、ファイルのmultipartアップロードが含まれていないか見ます。
  4. begin のヘッダーも確認します。開発者ツールのConsoleで下の式を実行すると、コピーしたBase64url文字列をJSONとして読めます。token は貼り付ける必要がありません。
  5. 撮影を終了し、暗号文を保存します。もう一度フィルターを外し、ほかの宛先や送信経路がないか確認します。Fetch/XHRだけでなく、WebSocketやその他の種類の通信も見ます。Networkの Size 列は通常、レスポンス側のサイズなので、それだけでアップロード量を判断しないでください。
// h には begin リクエストの header の値だけを入れる
const h = 'ここを実際のheaderに置き換える';
const b64 = h.replace(/-/g, '+').replace(/_/g, '/');
const bytes = Uint8Array.from(atob(b64), c => c.charCodeAt(0));
JSON.parse(new TextDecoder().decode(bytes));

ブラウザ内では、生成した .recryptor ファイルをOPFSというサイト専用の保存領域に書き込みます。互換性のため、内部のディレクトリ名は semilive-v1 のままです。「暗号文を保存」はこのローカルファイルの書き出しです。

通信ログにはメールアドレス、確認コード、撮影用トークン、セッションCookieが含まれる場合があります。HARなどのログを第三者へ公開するときは、これらを削除してください。

操作の参考:Chrome DevTools公式・Networkパネル / ペイロード・通信サイズなどのリファレンス

配信されたソースコードを読む

ブラウザが実行するJavaScriptは、開発者ツールのNetworkやSourcesで読めます。次のリンクは、このサイトから配信している実際のファイルです。Worker内の処理も対象にしてください。

通信APIとして fetch、XMLHttpRequest、WebSocket、sendBeaconなどが使われていないか、フォームやリソースURLへデータを埋め込んでいないかも確認します。ページ全体、importされたモジュール、Worker、Service Workerなどを含めて見ます。

この検証で分かる範囲

通信の観察は、そのとき、そのブラウザに配信されたコードによる撮影を確かめる方法です。運営が将来別のプログラムへ差し替えないことや、端末・ブラウザ・拡張機能の内部動作まで保証するものではありません。HTTPSは通信を保護しますが、送信先の運営を技術的に信用不要にはしません。

端末には暗号化前の映像・音声が一時的に存在します。このプログラムはそれを動画ファイルとして保存しませんが、ブラウザやOSの内部バッファ、スワップ等の残留を完全には保証しません。撮影プログラムを改変して平文や鍵を別に保存する不正も、一般的なブラウザサービスだけでは完全には防げません。

鍵のない撮影者が保存済みファイルを通常の操作で復号できないことと、撮影中の端末が原理的に映像を扱えないことは別です。サーバの秘密鍵と対応する暗号文がそろえば、運営は復号できます。警察・裁判所の要請がある場合だけ扱うという条件は、暗号の制約ではなく運用方針です。

サーバには、メールアドレス、撮影ID、撮影開始の受付・ハッシュ受信の時刻などが残ります。WebサーバのアクセスログにはIPアドレス等も記録され得ます。「映像を送らない」は「個人情報や利用状況を何も送らない」という意味ではありません。

時刻参照機能を有効にした場合は、3系統以上の外部NTP時計を照合し、一致する過半数の時刻を参照します。食い違い・通信失敗・古い情報などは記録し、多数派が成立しない場合は自サーバ時刻への切替を警告として残します。参照元と警告は復号ZIPの時刻記録で確認できます。外部時計への照会では映像・メール・撮影ID・暗号文ハッシュを送りません。これは第三者の署名付きタイムスタンプ証明ではなく、受信記録の署名は運営によるものです。実際の撮影時刻、場所、本人の存在、同意の有無、映像の内容が真実であることを、それだけで証明する仕組みではありません。

ブラウザの変更検査で送る情報

撮影開始前に、配布ファイルのSHA-256指紋と運営の署名を取得し、端末で照合します。端末の検査結果、変更を検知した機能の名前、撮影IDを運営へ報告します。検査のために映像・音声・暗号文を送ることはありません。検査報告への署名は、その報告を受け付けた記録です。端末の安全性、不正の有無、別保存の有無を証明するものではありません。