Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

ユーザーデータの保護

背景

Akaza はユーザーの変換履歴を学習データとして保存する。具体的には、ユーザーが変換を確定するたびに以下の統計データが記録される:

  • unigram: 確定した単語の頻度(例: 互換/ごかん 3
  • bigram: 隣接する単語ペアの頻度(例: 互換/ごかん\t性/せい 2
  • skip-bigram: 1語飛ばしの単語ペアの頻度

これらのデータにはユーザーが「何を変換したか」が記録されるため、プライバシー上のリスクがある。ファイルを閲覧できる第三者がユーザーの入力内容を推測できる可能性がある。

一方、ユーザー辞書 (SKK-JISYO.user) は SKK 辞書形式のテキストファイルであり、ユーザーが手動で編集する用途もあるため、保護の対象外とする。

方針

Mozc のデータ保護設計 を参考に、以下の方針でユーザー統計データを保護する。

保護対象

ファイル内容保護
unigram.v2.bin単語の使用頻度AES256 CBC で難読化
bigram.v2.bin隣接語ペアの頻度AES256 CBC で難読化
skip_bigram.v2.bin1語飛ばしペアの頻度AES256 CBC で難読化
SKK-JISYO.userユーザー辞書保護なし(平文テキスト)

保護しない対象

  • ユーザー辞書 (SKK-JISYO.user): ユーザーが手動編集する用途があるため
  • システム辞書・言語モデル: 公開データから生成されるため

設計

レイヤー構成

鍵管理と暗号化ロジックを分離する。

┌─────────────────────────────────────────┐
│  フロントエンド (鍵の管理)                  │
│  ibus-akaza / mac-akaza:                │
│    encryption.key ファイル (0600)         │
│    将来: macOS Keychain 等               │
├─────────────────────────────────────────┤
│  libakaza (暗号化・復号ロジック + 鍵管理)    │
│  encryption_key モジュールで鍵生成・読込    │
│  user_stats_utils で AES256 CBC 暗号化   │
└─────────────────────────────────────────┘

libakaza は暗号化・復号のロジック、バイナリ形式の読み書き、および鍵ファイルの生成・読み込みを担当する。

各フロントエンド は libakaza の load_or_create_default_encryption_key() を呼び出し、取得した鍵を UserData に渡す:

  • ibus-akaza (Linux): ~/.local/share/akaza/encryption.key0600 パーミッションで保存
  • mac-akaza (macOS): 同上。将来的に Keychain への移行が可能

この分離により、プラットフォームごとに鍵の保護レベルを独立して向上させることができる。

難読化の仕組み

Mozc と同様に AES256 CBC を使用してユーザー統計データを難読化する。

  1. 初回起動時にランダムな 32 バイト鍵を生成し、鍵ファイル (encryption.key) に保存する
  2. 統計データの保存時に AES256 CBC で暗号化する
  3. 統計データの読み込み時に復号する

鍵はマシンごとに異なる値が生成される。プロダクト共通のマスターキーは使用しない。

ファイル形式

統計データはバイナリ形式で保存する。テキストエディタで開いても内容を読むことはできない。

[magic: 4 bytes "AKZ\x01"]  // フォーマット識別 + バージョン
[iv: 16 bytes]               // AES256 CBC の IV(保存ごとにランダム生成)
[encrypted payload]          // bincode(HashMap<String, u32>) を暗号化したもの
  • シリアライズ: bincode(Rust との親和性が高く高速)
  • 暗号化: AES256 CBC(IV は保存のたびにランダム生成)
  • 書き出し方式: 3秒間隔で HashMap 全体をシリアライズ → 暗号化 → 書き出し。一時ファイル + rename によるアトミック書き込み
  • 追記方式は採用しない: レコード単位の暗号化はオーバーヘッドが大きく、コンパクション等の複雑さに見合わない。ユーザーの語彙数(数千〜数万エントリ)であれば全体書き出しで十分高速

ファイルパーミッション

全てのユーザーデータファイルは 0600(所有者のみ読み書き可能)で保存する。これは現行の実装と同様である。

セキュリティ上の注意

Mozc の設計文書にも明記されているとおり、この難読化は同一ユーザー権限で動作するプロセスからの保護を意図していない。信頼境界はユーザーアカウントのレベルに設定する。

保護の目的は以下のとおり:

  • ファイルを cat 等で開いたときに変換履歴が即座に読めない状態にすること
  • カジュアルな覗き見を防止すること

同一ユーザー権限を持つ攻撃者に対する完全な保護は、このレイヤーでは提供しない。

マイグレーション

旧形式(v1、テキスト)と新形式(v2、暗号化バイナリ)の共存期間を設け、段階的に移行する。

ロード時の挙動

  1. 新形式ファイル(unigram.v2.bin 等)が存在すれば、それを読み込む
  2. 新形式が存在せず旧形式(unigram.v1.txt 等)が存在すれば、旧形式を読み込む
  3. どちらも存在しなければ初期状態から開始(初回起動時)

保存時の挙動

  • 常に新形式で保存する
  • 旧形式ファイルは削除しない(ダウングレード時の安全策として残す)

将来の旧形式サポート削除

十分な移行期間を経た後、旧形式の読み込みサポートを削除する。削除時期はリリースノートで事前に告知する。

デバッグ支援

暗号化によりデバッグが困難になることを防ぐため、akaza-data コマンドに復号表示機能を提供する。

# ユーザー統計データの内容を復号して表示
akaza-data dump-user-stats --key-file ~/.local/share/akaza/encryption.key

参考文献