DEVELOPER / 管理者向け技術資料

.bookreaderprofile仕様

同期プロトコル2 · 設定形式v1 · 更新日 2026-10-31

Drive本棚設定はGoogleサービスアカウント鍵、Driveルート、読書状態の接続先をまとめる暗号化ファイルです。書籍、アプリのライセンスキー、Google OAuthログインの代替トークンではありません。推奨MIMEは application/vnd.bookreader.profile+json、文字コードはUTF-8です。

1. 外側のJSON

{
  "format": "bookreaderprofile",
  "version": 1,
  "kdf": "PBKDF2-HMAC-SHA256",
  "iterations": 600000,
  "salt": "BASE64_16_BYTES",
  "cipher": "AES-256-GCM",
  "nonce": "BASE64_12_BYTES",
  "payload": "BASE64_CIPHERTEXT_AND_TAG"
}

例のBASE64文字列は説明用で、取り込み可能なファイルではありません。AES鍵は、パスフレーズのUTF-8バイト列とsaltに対して、PBKDF2-HMAC-SHA256(反復回数600,000、出力長32バイト)で定義される値です。saltは16バイト、AES-256-GCMのnonceは12バイト、認証タグは16バイト。AADはUTF-8の bookreaderprofile:1 固定。暗号文の末尾にタグを連結してpayloadに入れます。

saltとnonceは発行ごとに暗号学的乱数で新規生成します。Base64はRFC 4648標準alphabet、paddingあり、空白なし、URL-safe不可。パスフレーズのUTF-8をそのまま使い、空白除去やUnicode正規化をしません。

2. 復号したJSON

{
  "version": 1,
  "displayName": "個人用の本棚",
  "serviceAccount": {
    "type": "service_account",
    "client_email": "reader@example-drive.iam.gserviceaccount.com",
    "client_id": "123456789012345678901",
    "private_key_id": "0123456789abcdef0123456789abcdef01234567",
    "private_key": "YOUR_RSA_PKCS8_PEM",
    "token_uri": "https://oauth2.googleapis.com/token"
  },
  "drive": {
    "rootFolderId": "YOUR_DRIVE_FOLDER_ID"
  },
  "sync": {
    "endpoint": "https://sync.example.com",
    "audience": "https://sync.example.com",
    "projectId": "example-sync",
    "apiKey": "YOUR_FIREBASE_API_KEY"
  }
}
項目必須条件
version整数リテラル1
displayName空白のみ不可、最大200 Unicode scalar。Cc/Cf/Zl/Zp禁止。
serviceAccountJSON化して64KiB以内。type=service_account。
client_email最大320 ASCII文字。Googleのサービスアカウントemail(.iam.gserviceaccount.com)。
client_id数字のみの文字列、1〜128桁。IAMのuniqueIdと対応。
private_key_id小文字16進40桁。
private_keyPKCS#8 PEM、RSA 2,048〜8,192bit、最大16,384文字。実鍵を公開資料へ埋め込まない。
token_urihttps://oauth2.googleapis.com/token と完全一致。
drive.rootFolderId必須文字列。空、またはASCII英数字・_・-で256文字以内。配布時は目的のルートを設定することを推奨。
sync.endpoint / audienceHTTPS origin、最大2,048文字。末尾 / を含むpath、userinfo、query、fragment不可。両者は完全一致。
sync.projectId小文字英字で開始し、以降は小文字英字・数字・-。2〜128文字。
sync.apiKeyASCII英数字・_・-、1〜512文字。Firebaseの公開クライアント設定値であり、アクセス許可そのものではない。

記載フィールドはすべて必須です。構造上限内の未知フィールドは許容します。オブジェクトのキー順は自由ですが、重複キー、不正UTF-8、孤立サロゲート、非JSON構文、末尾の別値は禁止。最大深さ16、最大8,192 value nodes。外側ファイルは1MiB、平文は512KiB、暗号文+タグは512KiB+16バイトまで。

versionとiterationsは文字列・小数・指数表現・真偽値で代用できません。未対応の形式・アルゴリズム・反復回数はKDF前に拒否。認証失敗時は誤パスフレーズと改ざんを区別しません。現行の対応版では発行・インポートともUTF-8で1,024バイト以内。空文字列や短い値も形式上は受け付けますが、空のパスフレーズでは秘密情報を保護できません。配布には推測されにくい長いパスフレーズを使ってください。旧版では短い値を受け付けない場合があります。

3. ファイルの生成とインポート

  1. サービスアカウントJSON、Driveルート、同期接続先を使い、上記の平文JSONを構成して各フィールドの制約を検証します。
  2. パスフレーズをUTF-8へ変換します。空白の除去やUnicode正規化は行いません。
  3. 暗号学的乱数で16バイトのsaltと12バイトのnonceを生成します。
  4. パスフレーズとsaltに対応する、上記の仕様で定義された32バイトのAES鍵を用意します。
  5. 平文JSONのUTF-8バイト列をAES-256-GCMで暗号化します。AADに bookreaderprofile:1 のUTF-8バイト列を指定し、16バイトの認証タグを取得します。
  6. 暗号文と認証タグをこの順で連結します。salt、nonce、暗号文+タグをそれぞれ標準Base64へ変換し、外側のJSONを構成します。
  7. 外側のJSONをUTF-8で保存し、拡張子を .bookreaderprofile にします。

鍵の計算方法・ライブラリ・呼び出し回数は問いません。暗号化に使う鍵が、指定したパスフレーズとsaltからアプリが復元する鍵と一致することが互換条件です。鍵は16進文字列やBase64文字列ではなく32バイトの生バイト列として扱います。外側JSONのiterationsはv1では600000固定です。

暗号ライブラリがタグを別に返す場合は連結し、すでに末尾へ付加する場合は二重に付加しないでください。ファイルへのアクセスを発行者に限定し、平文・鍵・パスフレーズをログや一時ファイルへ保存しないでください。ファイルの生成とは別に、Drive共有と同期接続先の権限設定が必要です。

利用者はプロフィールを選んで設定ファイルを取り込み、復号後のアカウント・接続先を確認して保存します。既存プロフィールの名前、一般Google接続、ダウンロード済みのローカル本を保ち、Drive本棚を追加します。アプリ内プロフィールのロックパスワードと、このファイルの復号パスフレーズは別物です。

4. 鍵の配布・失効

ファイルとパスフレーズを両方持つ人はサービスアカウント鍵を取得できます。暗号化は配布元の真正性や有効期限を保証しません。別経路でパスフレーズを渡し、読み取り権限を絞った専用アカウントを使います。同じサービスアカウントの配布先は同じ同期UIDを共有するため、利用者を分けたい場合はアカウントも分けます。

漏えい時は鍵の削除・アカウント無効化、Drive共有、入口IAM、許可リストを見直します。すでに取得された書籍の遠隔削除は保証できません。秘密鍵をサーバーへ送らず、署名で所持を証明します。