1. はじめに
この記事では、LINE の暗号プロトコルである Letter Sealing について解説をする。この記事を書くにあたっては、次のホワイトペーパーを参考にしている。
Letter Sealing とは、End-to-End Encryption(以下、E2EE)プロトコルであり、LINE のメッセージや VoIP サービスに使われる。
これは、
- テキストメッセージ
- 位置情報
- 1:1 の音声とビデオ通話
に対して使用される。
LINE は送信者のデバイス上で、メッセージを暗号化し、LINE のメッセージサーバーに暗号化したメッセージを送信する。この暗号化されたメッセージは受信者だけが復号することができる。
なお、この暗号化の対象はメッセージペイロード(以下、平文 $M$)であり、次のメタ情報は暗号化されない。
- 送信者ID
- 受信者ID
Letter Sealing には、2つのバージョン(バージョン1, バージョン2)が存在する。
2つのバージョンの相違点をまとめたものを、次の図1-1に示す。
バージョン1では、データの完全性に関する問題が発生した。これは、メッセージの改ざんを完全には防ぐことができなかったことを意味している。
後のバージョン2では、より強固なメッセージ保護を保証し、完全性に関する問題はすべて解決された。メタデータは暗号化されないが、認証タグ(MAC/GCM Tag)を含めることで改ざん検知(完全性の保護)の対象に含まれている。
送信者側がバージョン2に対応しており、受信者側が対応していない場合は、送信者側がメッセージをダウングレードして、再送する仕組みである。
2. 鍵交換の仕組み
鍵交換は楕円曲線ディフィー・ヘルマン鍵共有(以下、ECDH)の手順に則る。
- 送信者が受信者の現在の公開鍵を取得する
- 送信者が自身の秘密鍵と、受信者の公開鍵を ECDH アルゴリズムに通して、共有の秘密鍵を生成する
- 受信者も同様の手順で自身の秘密鍵と、送信者の公開鍵を使って共有の秘密鍵を生成する
図2-1. ECDHの概念図
ECDH は楕円曲線の離散対数問題に安全性の根拠を置いており、公開鍵の
$$
A = aG \quad (or \ B = bG)
$$
から $a$(または $b$)を求めることが難しいことを使っている。
LINE上では、メッセージを送る際に Letter Sealing の ECDH 鍵ペア(公開鍵の計算と、秘密鍵のランダム生成)を要求する。もしデバイス上に鍵ペアがない場合は、新しく鍵ペアを作り出し、ユーザーのアプリ上のプライベートストレージ上に安全に保存する。
作り出した公開鍵は、LINE 上のメッセージングサーバー上に登録する。サーバーは鍵と認証済みのアカウント(鍵の所有者のアカウント)を紐づけ、クライアントに一意の Key を返す。これは最新版の公開鍵を示している。
このとき、サーバーは公開鍵の仲介を行っているだけで、秘密鍵自体は端末からは流出することはない。
送信する側は、受信者の公開鍵を取得し、自身(=送信者)が持つ秘密鍵と合わせて、共有シークレットを作り出す。
※ 図2-1 では概念的に「共有鍵」と示したが、実際にはこれを直接暗号化には使用せず、鍵生成の種(シークレット)として扱う。以後これを共有シークレットで統一する。
生成された共有シークレットは、そのまま暗号化に使われるわけではない。この共有シークレットを鍵導出関数(KDF: Key Derivation Function)を用いて、より安全なメッセージ暗号化用のセッション鍵を生成する。
図2-2. 鍵ペアの生成から共有シークレットの計算まで
3. Letter Sealing Version 1 の仕様
Version1では、メッセージごとにユニークな暗号鍵とInitialization Vector(以下、IV)を派生させる方式を採用している。暗号化は ECDH で共有した秘密値を元に、SHA-256を利用した派生処理を行う。
送信者は次のステップで、メッセージを暗号化する。
3.1. 暗号キーと IV の派生
- 8バイトのソルトを生成する
- ハッシュ関数(SHA-256)を使って、ECDH で作成した共有シークレット、ソルト、文字列 "Key" の3つを連結したものをハッシュ化する(これを、$Key_{encryption}$ とする)
- 2 と同様に共有シークレット、ソルト、文字列 "IV" の3つを連結したものをSHA-256でハッシュ化する(これを、$IV_{pre}$ とする)
- AES暗号のCBCモードに必要な16バイトのIVを生成する

図3-1. Version 1 における暗号鍵・IV の派生式(Whitepaper より)
3.2. メッセージの暗号化
次に、AES暗号256ビットのCBCモードを使って3.1.で求めた暗号鍵($Key_{encryption}$)と、IV($IV_{encryption}$)を使って、メッセージペイロード(元の平文 $M$)を暗号化する。これを暗号文とする。

図3-2. メッセージの暗号化(Whitepaper より)
そして暗号文のハッシュ値(SHA-256)を計算し、さらにそれをAESで暗号化したものをメッセージ認証コード(以下、MAC値)とする。
最後に次のフィールド(以下、メッセージフィールド)で構成されているメッセージを、相手に送信する。
メッセージフィールドに含まれているものは次のとおりである。
-
version: Letter Sealing のプロトコルバージョン(Version 1 の場合は1) -
content type: 暗号化されたメッセージの種類(ペイロード) -
salt: 3.1. で生成したソルト -
C: 暗号文 -
MAC: MAC 値 -
sender key ID: 暗号化に使用された送信者の公開鍵を識別する ID -
recipient key ID: 受信側がどの秘密鍵で復号すべきかを識別するための ID
ここで重要なのは、これらのヘッダ情報が暗号化されておらず、さらに MAC の検証範囲にも含まれていないという点である。そのため Version 1 では、攻撃者がメタデータを改ざんしても検出できない問題が存在した。
これはつまり、MAC が保証する完全性は暗号文Cのみであり、以下のメタデータは保護されていない。
- version
- content type
- salt
- sender key ID
- recipient key ID
そのため攻撃者は、MAC 値を改ざんすることなく、ヘッダ情報のみを書き換えることが可能だった。MAC は暗号文の改ざんは検出できるが、MAC の外側にあるメタデータの改ざんまでは防げない。
Version 2 では、この問題を解決するためにメタデータを追加認証データ(以下、AAD)として AES-GCM の認証タグに含める方式へと変更されている。
3.3. メッセージの復号
受信者は次の手順で、受け取った暗号化されたメッセージを、復号する。
- 受信者が復号できるかどうかを決定する
- 復号できるメッセージである場合、共有シークレット、対称鍵、IV を計算して得る(それぞれメッセージフィールドに含まれている情報と、メッセージサーバにある相手の公開鍵情報から計算することができる)
- 暗号文を計算し、この MAC 値を求める
- メッセージフィールドに含まれる MAC 値と 3 で求めた値を比較し、もし一致すれば受信者はメッセージを見ることができ、そうでなければメッセージは表示されない
4. Letter Sealing Version 2 での改善
Version 1 の問題点としては、メタデータが完全性保護の対象外であることだった。
MAC 値が保証していたのは、暗号文 $C$ の完全性のみであり、
versioncontent_typesaltsender key IDrecipient key ID
のようなヘッダ情報は攻撃者が自由に改ざんできた。
Version 2 では、この問題を解決するために AES-GCM を採用し、暗号化と完全性を実現している。
送信者は次の手順でメッセージを暗号化し、送信する。
4.1. 暗号化手順(Version 2)
はじめに、16バイトのソルトを生成し、共有シークレット、ソルト、"Key" 文字列から暗号化鍵を生成する。

図4-1. salt と暗号化鍵の生成(Whitepaper より)
次に、8 バイトのチャットカウンタと 4 バイトのランダム値からナンスを計算する。
このナンスは AES-GCM の一意性を保証するために必要となる。
次にメタデータを付随データ(AAD)として、AES-GCMに渡す。AESには暗号化対象ではないが、改ざんされては困る部分をAADとして渡すことができる。AADには次のメタデータを含めている。
Letter Sealing Version 2 では、Version 1 で保護されていなかったメタデータをすべて AAD として含め、安全性を強化している。
そして、AES-GCM による暗号化の結果として、暗号文 $C$ と 16 バイトの認証タグ(GCM tag)が生成される。
最後に次のフィールド(以下、メッセージフィールド)で構成されているメッセージを、相手に送信する。
Version 1 と比べて、メタデータが AAD として完全性保護されている点と、nonce が独立したフィールドとして追加されている点が大きな違いである。

図4-6. 送信フィールド ver.2 (Whitepaper より)
4.2. 復号の手順
受信者は次の手順で、受け取った暗号化されたメッセージを、復号する。
- メッセージ内の共有シークレットとソルトを使って暗号化鍵を導出する
- AES-GCM を使って暗号文を復号する準備を行う
- メッセージのメタデータを AAD(追加認証データ)として AES-GCM に渡す
- 復号処理の中で計算された GCM タグと、メッセージに含まれていたタグが一致した場合にのみ、復号されたメッセージをユーザに表示する。一致しない場合は改ざんされた可能性があるとみなし、メッセージを破棄して表示しない
5. グループメッセージ
グループメッセージにおいては、これまでの1:1のメッセージと同様の暗号化を行うが、異なるのが暗号化の手順である。
5.1. 鍵生成と登録
グループチャットでは、グループ全体で利用するグループ共有シークレットを生成し、それを各メンバーに安全に配布する必要がある。
この生成と配布は、グループで最初にメッセージを送ろうとするクライアントが行う。
手順は次のように行われる。
- クライアントは新しい ECDH 鍵ペアを生成し、その秘密鍵をグループ共有シークレットとして利用する
- グループに属する全メンバーの公開鍵をサーバから取得する
- 自分の秘密鍵と各メンバーの公開鍵を用いて、1:1 チャットと同じ手順でメンバー事の共有シークレットを導出する
- 手順1で作成した グループ共有シークレット を、手順3で得た 各メンバーとの共有シークレットから導出した対称鍵 でそれぞれ暗号化する
- 暗号化済みのグループ共有シークレットをサーバに送信し、サーバはこれらをグループに紐付けて管理する
LINE のメッセージサーバーは、暗号化されたグループ共有シークレットをグループに紐づけ、最新の共有シークレットの ID を返す。メンバーがグループに参加・退出した場合には、新しいグループ共有シークレットが生成され、再度グループ全体に配布される。
$\rightarrow$ グループの構成メンバーが変われば、新しいグループ共有シークレットを生成し直す必要がある。
5.2. グループメッセージの暗号化 ver.1
Letter Sealing Version 1 を使ってグループにメッセージを送る場合、LINE クライアントはまずサーバから暗号化されたグループ共有シークレットを取得し、それを復号してローカルにキャッシュする。
暗号化の流れは、1:1のときと同様に次のようになる。

図5-1. グループメッセージ暗号化手順 ver.1(Whitepaper より)
グループメッセージにおける唯一の違いは、recipient ID と recipient key ID が、group chat ID と 共有鍵の ID に置き換えられるという点である。
5.3. グループメッセージの暗号化 ver.2
Letter Sealing Version 2 では、グループメッセージの暗号化手順は 基本的に 1:1 チャットの暗号化手順と同じである。
唯一の違いは、メッセージヘッダ内の recipient key ID が shared group key ID に置き換わる点だけである。

図5-2. グループメッセージ暗号化手順 ver.2 (Whitepaper より)
6. VoIP
Letter Sealing はメッセージだけでなく、1:1 の VoIP 通話にも適用される。VoIP の暗号化では、通信ごとに新しい鍵を生成し、それを使って音声・映像データを暗号化する。
LINE の VoIP 用 ECDH のパラメータは、secp256r1 を使用し、対称鍵は AES を用いる。ECDH で得られる共有シークレットは、そのままでは暗号化に適した形になっていないため、鍵導出関数(KDF)を使って安全な鍵素材へ変換する必要がある。
そこで用いられるのが、HMAC に基づいたシンプルで標準化された鍵導出関数である HKDF である。
6.1. コール開始時の鍵交換
通話開始時、クライアントは次の流れで使い捨て鍵(以下、エフェメラルキー)を交換する。
- 発信者は、新しいエフェメラルキーを生成し、公開鍵を通話リクエストに含めて相手へ送信する
- 受信者が通話リクエストを受け取った後、受信者は自身のエフェメラルキーペアを生成し、発信者に公開鍵を送信する
ユーザー ID の正当性は、通話設定メッセージに署名を行う LINE のシグナリングサーバによって保証される。

図6-1. 共有シークレットの生成(Whitepaper より)
鍵交換を終えた後、それぞれマスターシークレットを生成し、以下の手順で、VoIP セッションキーとソルトを導出する。

図6-2. セッションキーとソルトの導出手順(Whitepaper より)
6.2. セッションキーの生成と SRTP の初期化
鍵交換が完了した後、各クライアントは共有シークレットから、受信方向(rx)/ 送信方向(tx)それぞれの MasterSecret を生成し、SRTP(Secure RTP)に必要な鍵素材を導出する。
まず、それぞれ 16 バイトのソルトをランダムに生成する。
次に、ECDH で得た共有シークレットと、双方の公開鍵を HKDF に入力し、受信方向・送信方向それぞれで異なる MasterSecret を計算する。
ここで、送信方向(tx)と受信方向(rx)で異なる値になるよう、公開鍵の順序を入れ替えている。
これにより、1本の共有シークレットから2本の独立した鍵系列が得られる。
この MasterSecret と salt を使い、SRTP の初期化に必要な音声・映像・データ用の鍵を導出する。
6.3. 音声・映像・データの暗号化(SRTP)
VoIP のメディアストリームは SRTP(Secure RTP) を使って暗号化される。LINE では、SRTP の暗号化方式として、AES_CM_128_HMAC_SHA1_80 を利用している。
これは、AES カウンターモードによる暗号化と、80ビットの HMAC-SHA1 認証タグを持つ SRTP の標準的な暗号スイートである。
VoIP のメディアは、音声、映像、データなど複数のストリームで構成されるため、各ストリームごとに独立した鍵が必要になる。
それぞれの SRTP 鍵は、前節で得られた MasterSecret をもとに HMAC-SHA256 で導出される。

図6-5. SRTP 鍵の生成(Whitepaper より)
7. 参考資料
[1]. LINE Encryption Overview
[2]. Wikipedia HKDF
[3]. SRTP とは
[4]. VoIP







