写丸君

撮った瞬間に「本物のカメラで撮った」証明を写真・動画に埋め込むカメラアプリ(Android)。

証明の形式は業界標準の C2PA(Content Credentials) です。Adobe・Google・Sony・Leica などが採用している同じ規格なので、 contentcredentials.org/verify などの検証ツールで誰でも中身を確かめられます。

証明を確かめる(写丸君を持っていない人も)

証明を確認するページに写真・動画を置くと、ブラウザの中だけで証明を読み取って表示します。 ファイルはどこにも送信されません。検証エンジンは Content Authenticity Initiative の c2pa-web(MIT)を同梱しています。

何ができるか

何が証明できて、何ができないか

プライバシー

外部通信について

iPhone 版は、既定ではインターネットに一切接続しません。 時刻証明の機能もありません(写丸君-iOS.md)。 設定の「会社の証明書で署名する」をオンにしたときだけ、1 年に 1 回、証明書を受け取るために通信します (送るのは公開鍵と App Attest の証拠だけ。写真・動画は送りません)。 さらに「会社のサーバーで署名する」もオンにすると、撮るたびに署名データのハッシュ値(32 バイト)を会社のサーバーに送ります。 オフに戻せば、また一切接続しません。 証明を読むときの遠隔取得(別サーバーにあるマニフェスト・OCSP)も切ったうえで、 c2pa に渡す HTTP の口そのものをふさいでいます(Provenance.swift の context)。

以下は Android 版の話です。

写丸君がインターネットに通信するのは、設定でオンにした機能を使うときだけです。 すべて既定はオフで、全部オフなら一切通信しません。

会社の証明書を受け取る(設定「写丸君の運営会社の証明書を使う」)

自己署名だと、誰でも同じ名義を名乗れます。運営会社(株式会社カリロエ)の認証局から端末証明書をもらうと、 証明書のつながりが会社のルートに辿り着くかどうかで本物かどうかが決まるようになります。

項目内容
いつ1 年に 1 回(証明書の期限が近づいたとき)。受け取ったあとの撮影・署名は端末の中だけ
相手株式会社カリロエの認証局 shamaru-ca-joizw6cvaq-an.a.run.app
送るもの署名鍵の公開鍵と、その鍵がこの端末の中で作られたという証拠(Android のハードウェア証明)
送らないもの写真・動画・サムネイル・位置情報・アカウント情報・利用者を特定する情報
受け取るものこの端末だけの証明書。端末や利用者を特定できる情報は入っていない(名義は全端末で同じ、区別が付くのは乱数の通し番号だけ)
失敗したら撮影は止めない。 自己署名のまま撮り、24 時間あけて再試行する
確かめ方受け取った証明書が、アプリに同梱した会社のルートで検証できることを確かめてから使う

ルート証明書と中間証明書は <https://callirrhoe.jp/app/shamaru-kun/ca/> で公開しています。

公式の証明書で署名する(設定「公式の証明書で署名する」)

Android 0.1.10 以降・iPhone 1.1.0 以降。どちらも既定はオフ。

①の証明書はトラストリストに載らないので、よその検証サイトでは「未認識」のままです。 公式に信頼される証明書は端末ごとに配れないため、端末が claim を組み立て、会社のサーバーが署名する形にします (C2PA の言い方では Distributed 実装クラス)。

項目内容
いつ1 つ署名するたびに 1 回
相手株式会社カリロエの署名サーバー shamaru-ca-joizw6cvaq-an.a.run.app
送るもの署名するデータのハッシュ値 32 バイト、この端末の証明書(①で受け取ったもの)、使い捨ての乱数と時刻、それらへの端末の鍵による署名
送らないもの写真・動画・サムネイル・位置情報・アカウント情報・利用者を特定する情報
確かめ方サーバーは、端末証明書が自社の中間 CA から出ていること・期限内・署名が合うこと・乱数が未使用であることを確かめてから署名する。証明書だけでは署名しない(端末の鍵による所持の証明が要る)
届かなかったら撮影は止めない。 その 1 枚は①の証明書で署名し、5 分は再試行しない
前提①の証明書を受け取っていること(自己署名では認証が通らない)

1 つのファイルに付く署名は 1 つだけです。①と②を重ねません。

署名に時刻証明を付ける(設定「署名に時刻証明を付ける」)

項目内容
いつ上の設定がオンで、写真・動画・音声メモを1つ署名するたびに1回
相手DigiCert のタイムスタンプ局 timestamp.digicert.com(RFC 3161)
送るもの署名データのハッシュ値(数十バイト)。RFC 3161 のタイムスタンプ要求そのもの
送らないもの写真・動画・サムネイル・位置情報・端末情報・鍵・証明書・利用者を特定する情報
受け取るもの「このハッシュはこの時刻に存在した」という TSA 署名つきの応答。署名の中に埋め込む
相手に見えるもの通信元の IP アドレス(インターネット通信の性質上避けられない)
通信できないとき時刻証明なしで署名して保存し、その旨を画面に表示する。撮影は止めない
目的撮影日時(端末の時計)とは別に、第三者が保証する時刻を署名に付けるため

この通信は Android の INTERNET 権限で行います。この権限は確認ダイアログが出ない種類のものなので、 上の設定スイッチが実質的な同意の場所です。

撮影の設定

動作環境

ビルド

Android Studio は不要です。Unity 6000.4.3f1 に同梱の OpenJDK 17 / Android SDK / Gradle 8.13 を使います。

tools/gradle.sh assembleDebug

PowerShell なら .\tools\gradle.ps1 assembleDebug。出力は app/build/outputs/apk/debug/app-debug.apk。

構成

ファイル役割
MainActivity.ktカメラ画面。CameraX で撮影し、一時ファイルに書いてから署名・保存
Settings.kt / SettingsActivity.kt撮影の設定と設定画面
ImageConvert.ktJPEG を PNG に変換(EXIF の向きを反映)、署名用サムネイル
LocationTracker.kt位置情報(同意制)。カメラ画面を開いている間だけ測位
DeviceKey.ktAndroid Keystore に署名鍵を作り、自己署名証明書を付ける
Provenance.ktマニフェスト(何を記録するか)の組み立て、署名、読み取りと要約
MediaStorage.ktギャラリー(DCIM/写丸君)への保存と一覧。Android 9 と 10 以降の差を吸収
GalleryActivity.kt / DetailActivity.kt撮ったものの一覧と、証明の詳細表示

ライセンス

MIT License。第三者ソフトウェアの帰属表示は NOTICE.md を参照してください。