メッセージアプリはコンテナを届ける
Secure ChatはTelegram、メール、その他の送信手段とは独立して動作します。送信者の端末でテキストやファイルを暗号化コンテナに変換します。そのコンテナを選んだ経路で送り、受信者が自分の秘密鍵で端末内で復号します。
- 利用者同士が自分のプロファイルを作成し、公開鍵カードを交換します。
- 独立した方法で鍵のフィンガープリント全体を照合し、アプリ内で連絡先を確認済みにします。
- 送信者が自分のプロファイル、宛先、アルゴリズムを選択します。Secure Chatが内容を暗号化し、コンテナに署名します。
- 受信者がコンテナを開き、必要に応じてキーストアのパスワードを入力すると、検証済みの結果を取得できます。
メッセージアプリの履歴にアクセスできても、それだけでSecure Chatの秘密鍵を取得できるわけではありません。この追加の保護は、事前に暗号化した内容に対して有効です。通信の事実、参加者、送信時刻、ネットワークアドレスは隠しません。また、すでにマルウェアが動作している端末は保護できません。
各プロファイルに2組の鍵ペア
| 用途 | 方式 |
|---|---|
| コンテンツ鍵の受け渡し | RSA-3072とOAEP-SHA256 |
| コンテナの署名 | ECDSA、NIST P-256曲線、SHA-256ハッシュ |
| 公開鍵の形式 | 正規化DERのSubjectPublicKeyInfo(SPKI) |
| 秘密鍵の形式 | DER PKCS#8、暗号化されたキーストア内に保存 |
公開鍵カード
.scpub
には、名前、2つの公開鍵、フィンガープリント、形式のバージョンが含まれます。秘密鍵は含まれません。カードは可読JSON形式で、バイナリのフィールドはBase64で表します。
Format: SecureChat.PublicKey
Version: 1
Name
EncryptionPublicKey
SigningPublicKey
Fingerprint
相手の確認方法
フィンガープリントは、2つの公開鍵をまとめたSHA-256ハッシュで、64文字の16進数です。送信前に、対面または別の信頼できる経路で全体を照合してください。インポートしたカードの名前だけでは本人確認になりません。
SHA256(
UTF8("SecureChat.Identity.v1\0")
|| int32BE(length(RSA_SPKI)) || RSA_SPKI
|| int32BE(length(ECDSA_SPKI)) || ECDSA_SPKI
)
インポートした連絡先は必ず未確認になります。照合を確認してから、その連絡先宛ての暗号化が可能になります。動作確認用に、自分のプロファイルを宛先に選ぶこともできます。
正しいデジタル署名は、コンテナがその署名鍵に対応していることを確認します。その鍵と特定の人物との関係は、フィンガープリントの照合によって確立します。未知の鍵や未照合の鍵については、送信者の本人確認ができていないことを別途表示します。
コンテナごとに独立したランダム鍵
新しいメッセージやファイルごとに、次のAPIで新しいランダムな256ビット鍵を生成します:
RandomNumberGenerator.GetBytes
。ユーザーは次の2種類の認証付き暗号(AEAD)から選択します:
| アルゴリズム | 鍵 | Nonce | タグ |
|---|---|---|---|
| AES-256-GCM | 32バイト | 12バイト | 16バイト |
| ChaCha20-Poly1305 | 32バイト | 12バイト | 16バイト |
ChaCha20-Poly1305はOSが対応している場合にのみ選択できます。選択したアルゴリズムは認証対象のヘッダーに含まれます。より弱い方式への自動切り替えはありません。
ランダムなコンテンツ鍵を受信者のRSA公開鍵で暗号化します。別のコピーを送信者のRSA公開鍵で暗号化するため、送信者も自分の送信内容を開けます。自分宛ての場合は鍵スロットを1つだけ作成します。
AEADは内容と関連データの完全性を検証します。ECDSA-P256/SHA-256署名により、コンテナを送信者の鍵に結び付けます。検証に失敗すると復号を中止します。
パスワードで保護するキーストア
秘密鍵を含むプロファイル、連絡先、保護対象の設定、履歴は、次の単一ファイルに保存されます:
Data/wallet.scvault
。アプリと同じ場所に置き、AES-256-GCMで暗号化します。
| パラメーター | 値 |
|---|---|
| パスワードからの鍵導出 | PBKDF2-HMAC-SHA-256、600,000回反復 |
| ランダムなソルト | 32バイト |
| 導出鍵 | 32バイト |
| 保存時のノンス | 毎回新しいランダムな12バイト |
| 認証タグ | 16バイト |
| 作成時のパスワード長 | 12~1024文字 |
| 復号後のキーストアの最大サイズ | 64 MiB |
パスワードや、照合用の独立したパスワードハッシュは保存しません。PBKDF2は総当たりを遅くしますが、保護の強さはパスワード自体にも依存します。長く一意なパスフレーズには、ランダムな単語やパスワード管理ツールの利用を推奨します。
64バイトのヘッダーも認証対象です。その後に暗号文とタグを書き込みます:
"SCVAULT1"[8]
|| version:int32LE
|| iterations:int32LE
|| salt[32]
|| nonce[12]
|| ciphertext_length:int32LE
|| ciphertext
|| tag[16]
バージョン1形式では、指定済みのKDFパラメーター、制限内のサイズ、正確なファイル長のみを受け入れます。保存時は暗号化コピー全体を完成させてからファイルを置き換えます。同時書き込みや、検出された外部変更への上書きは拒否します。補助ファイル
.lock
に鍵は含まれません。
暗号化されないヘッダーの内容
メッセージやファイルのコンテナは、4バイトの種別、JSONヘッダーの長さ、ヘッダー本体で始まります。JSONの上限は16,384バイトです。
magic[4] || header_length:int32LE || header_json[header_length]
| フィールド | 内容 |
|---|---|
Version
|
形式のバージョン:1 |
Kind
|
text
または
file
|
Algorithm
|
0 — AES-256-GCM; 1 — ChaCha20-Poly1305 |
SenderEncryptionPublicKey
,
SenderSigningPublicKey
|
送信者の公開鍵 |
RecipientFingerprint
|
主な受信者のフィンガープリント |
PlaintextLength
|
元の内容の長さ(バイト) |
OriginalFileName
|
ファイル名。テキストでは空文字列 |
ChunkSize
|
ファイルは1,048,576、テキストは0 |
Nonce
|
テキストではランダムな12バイト、ファイルではランダムな4バイトのプレフィックス |
KeySlots
|
1つまたは2つのスロット:フィンガープリントと384バイトのRSAラップ済み鍵 |
これらのメタデータは暗号化されません。 アルゴリズム、サイズ、ファイル名、公開鍵、フィンガープリントは外から見えます。固定の鍵により、同じ送信者のコンテナを関連付けることができます。ファイル名が機密情報なら、暗号化する前に変更してください。
暗号化されないヘッダーも、検知されない改ざんから保護します。署名とAEADはJSONを再構成せず、元のバイト列を使います。以下の説明で、
||
はバイト列の連結を表します。整数はリトルエンディアンで記録し、ビッグエンディアンを使う例外は明示しています。
テキスト:SC1コンテナと.scmsg添付ファイル
元のテキストは厳密なUTF-8で最大1 MiBです。バイナリコンテナの種別は
SCT1
:
"SCT1"
|| header_length:int32LE || header_json
|| ciphertext_length:int32LE || ciphertext
|| tag[16] || signature[64]
追加認証データ(AAD)には、種別、長さ、JSONヘッダーを含むプレフィックス全体を使います。ECDSA-P256署名は、それ以前の全バイトのSHA-256に対して計算します。署名の形式は
IeeeP1363FixedFieldConcatenation
:
r || s
で、それぞれ32バイトです。
送信時は、バイナリコンテナをパディング文字なしのBase64urlに変換します。パディング文字は
=
:
SC1:<base64url(binary_container)>
securechat://message/<base64url(binary_container)>
テキストを表示する前に、構造、正確な長さ、署名を検証し、その後RSAラップを復号してAEADを検証します。不正な文字、エンベロープ内の改行、追加URIパラメーター、破損データは拒否します。
Telegramでの送信
「チャット用ファイル」ボタンで、暗号化したファイル
.scmsg
をWindowsのファイル用クリップボードにコピーします。チャットへの貼り付けには
Ctrl
+
V
を使い、添付ファイルとして送信します。受信者はダウンロードしてSecure Chatで開きます。アプリがロック中なら、先にパスワードを求めます。
通常のエンベロープ
SC1:…
も手動でコピーして貼り付けられます。Windowsのリンク
securechat://…
は8,000文字までで、すべてのクライアントでクリックできるわけではありません。Telegram Desktopはこの独自スキームを通常の自動リンクにしないため、添付ファイル
.scmsg
を使います。旧形式のリンク
.sct
はアプリ内で明示的に開きます。
ファイル:ブロック、署名、2回の検証
暗号化ファイルの拡張子は
.scx
、種別は
SCF1
です。元のファイルの形式上の上限は1 TiBです。ストリーム処理のため、全体をメモリへ読み込まず、内容を1 MiBのブロックに分けます。
"SCF1" || header_length:int32LE || header_json
|| (chunk_length:int32LE || ciphertext[chunk_length] || tag[16])*
|| 0:int32LE || terminal_tag[16]
|| signature[64]
各ブロックには独立した12バイトのノンスを割り当てます。コンテナのランダムな4バイトのプレフィックスと、8バイトのブロック番号で構成します:
nonce = Nonce[4] || uint64BE(chunk_index)
AAD = SHA256(full_prefix)[32]
|| uint64BE(chunk_index)
|| int32LE(chunk_length)
番号は0から始まります。末尾の空ブロックには次の番号と独自のタグを割り当てます。空ファイルにもヘッダー、終端ブロック、タグ、署名があります。新しいファイルごとにコンテンツ鍵を新しく生成します。
署名の対象は、
SCF1
から末尾のAEADタグまでの全バイトです。ブロックの順序とサイズ、コンテナの正確な長さ、ファイル終端を検証します。並べ替え、複製、削除、切り詰め、データの追記はいずれも拒否につながります。
復号時の処理
- 上限内のヘッダー、ファイル長、対応する秘密鍵があることを確認します。
- 1回目の読み取りでコンテナ全体の署名を検証します。この時点では平文の一時ファイルは作成しません。
- 2回目の読み取りで各ブロックのAEADを検証し、復号データを一時ファイルへ書き込み、最後に署名をもう一度検証します。
- すべて成功すると、一時ファイルをユーザーが指定した新しいファイル名へ変更します。既存のファイルは上書きしません。
ステータスバーには、署名検証、復号、保存を通じた全体の進捗率を表示します。100%は結果の保存成功を意味します。処理中はキャンセル可能で、通常のエラーやキャンセルでは一時ファイルを削除します。
元のファイルは残ります。復号した結果を自動実行することはありません。停電、プロセスの強制終了、削除を妨げる外部ハンドルがある場合には、平文の一時ファイルが残る可能性があります。出力先フォルダーとディスクの保護も、秘密を扱ううえで重要です。
ローカル保存、履歴、ロック
| ファイルまたはフォルダー | 用途 |
|---|---|
Data/wallet.scvault
|
暗号化されたプロファイル、鍵、連絡先、設定、履歴 |
Data/window-state.json
|
ウィンドウのサイズ、位置、状態。鍵や会話は含まない |
Data/ui-preferences.json
|
言語と更新確認の設定。キーストアのデータは含まない |
Data/ClipboardAttachments
|
チャットに貼り付ける暗号化メッセージの一時コピー |
履歴には操作のメタデータと暗号化テキストのエンベロープを保存します。平文やファイルの内容は記録しません。最新100件、エンベロープ合計約8 MiBを保持し、古い記録は自動削除します。履歴を無効にしたり、消去したりできます。
キーストアは、次のショートカットでロックします: Ctrl + L 。また、最小化、Windowsセッションのロックや切断、スリープ、無操作でもロックします。無操作時間は1~15分で設定でき、初期値は5分です。鍵を解放する前に、進行中のファイル処理をキャンセルします。
ロック時は入力欄と記録への参照を消去し、アプリが所有する秘密鍵と導出鍵の配列をゼロで上書きします。すべてのコピーをメモリから消すことは保証しません。マネージド文字列、クリップボード、ダンプ、ページファイルにデータが残る可能性があります。
クリップボードの2つのモード
「テキストをコピー」はアプリ自身の項目を識別し、まだSecure Chatの項目であれば、30秒後またはロック時に消去します。他のアプリによる新しい項目は消去しません。システムの通常のコピーコマンド Ctrl + C はこのタイマーの対象外です。
「チャット用ファイル」は、作成済みのファイル
.scmsg
へのパスをWindows FileDropに設定します。中身は暗号文のみです。メッセージアプリが読み取れるように、ロック後やキーストアを閉じた後も利用できます。コピーするたびに独立した添付ファイルを作成します。
24時間より古いコピーは、次回起動時または次のコピー時に削除します。一時添付ファイルは同時に128個まで保存でき、上限に達した場合は任意のフォルダーへ明示的に保存できます。履歴とクラウドクリップボードの禁止はWindowsへのヒントとして渡すもので、他のクリップボード管理ソフトは無視する可能性があります。
バックアップ、移動、更新
バックアップはキーストア全体の暗号化コピーです。開くには作成時点のパスワードが必要です。新しい鍵を追加した後はバックアップを更新してください。パスワードと秘密鍵がない状態からの復旧機能はありません。
パスワード変更、プロファイル削除、履歴消去は現在のキーストアを変更します。古いバックアップには以前のパスワード、鍵、履歴が残ります。また、記録の削除によってSSD、スナップショット、ジャーナリングファイルシステムから物理的に消去される保証はありません。
0.1.6へ更新するには、Secure Chatを終了し、次のファイルを置き換えます:
SecureChat.exe
。元と同じフォルダーで置き換えてください。
Dataフォルダー全体を必ず残してください。
キーストアとコンテナの形式はバージョン1のままで、移行は不要です。今後形式が変わるリリースでは、移行手順を別途説明します。
別のフォルダーへ移動する場合は、EXEと一緒に次を移動します:
Data
および必要な外部翻訳ファイルのある
Languages
。その後、設定で次の形式の関連付けを再度有効にします:
.scmsg
,
.scx
とリンク。Windowsの登録は絶対パスを保持します。単一ファイルのEXEでも、.NETのネイティブライブラリをユーザーのシステムキャッシュへ展開する場合があります。
アプリが行うネットワークリクエスト
暗号化と復号にサーバーは不要です。Secure Chatには、メッセージの配送機能、鍵交換用アカウント、パスワードリセットサービスはありません。コンテナの配送には、自分で選んだメッセージアプリ、メール、その他の経路を使います。
「更新を確認」を押すと、次のアドレスから小さなJSONを取得します:
https://itmsft.com/securechat/update/latest.json
。起動時の確認は別途有効にでき、初期状態では無効です。HTTPSリクエストの通常のネットワーク情報と、アプリのバージョンを含む共通のUser-Agentを送信します。パスワード、鍵、プロファイル、履歴、ファイルの内容は送信しません。
クライアントは応答を64 KiB、読み取り時間を10秒に制限し、バージョンと対応アーキテクチャのパッケージを確認します。サーバー、ネットワーク、形式のエラーでは確認できないことを表示し、インストール済みバージョンが最新だとは表示しません。
ダウンロードボタンは、通常のブラウザーで次のサイト上の許可されたHTTPSパッケージURLを開きます:
itmsft.com
。アプリは自動インストールせず、ダウンロードしたファイルも実行しません。SHA-256フィールドの形式は確認しますが、ブラウザーが取得したZIP本体のバイト列は検証しません。バージョン0.1.6のEXEには発行者のデジタル署名がありません。
理解しておくべき限界
- 端末の安全性。 マルウェア、キーロガー、メモリの読み取り、EXEの置き換え、リモートアクセスによって、暗号化前や復号後のテキストが漏れる可能性があります。
- メタデータ。 コンテナの暗号化されないヘッダーと、送信経路のネットワーク情報は外から見えます。匿名化のためのツールではありません。
- 固定の鍵。 前方秘匿性(forward secrecy)は実装していません。秘密鍵が盗まれると、その鍵宛てに過去に傍受されたコンテナも読めます。
- 侵害後の秘匿性の回復。 Double Ratchetと侵害後の安全性(post-compromise security)は提供しません。独自形式であり、Signalプロトコルの実装ではありません。
- 再送とロールバック。 有効なコンテナは繰り返し送信できます。正しい古いキーストアのコピーもロールバックから保護されません。完全性は最新であることを証明しません。
- パスワード。 最低文字数や画面上の待機時間では、盗まれたキーストアに対するオフラインの総当たりを防げません。主な対策は強いパスワードとKDFです。
- データの消去。 RAM、ページファイル、クラウドクリップボード、記憶装置からの完全消去は保証しません。
- 暗号学的な性質。 この方式は耐量子ではありません。コンテナを入手した第三者も署名を検証できます。暗号学的否認可能性は提供しません。
- 検証の状況。 標準プリミティブや自動テストは、プロトコルと実装の独立した監査の代わりにはなりません。
Secure Chatは、選んだ内容を独立して管理する手段を追加します。特に機密性の高いデータに使う場合は、自分の脅威モデルの評価、安全な端末、実装の独立した専門家レビューが必要です。