20170624追記
RFC8188 として標準化されました
HTTPリクエスト・レスポンスのボディを暗号化する、「Content-Encoding: aes128gcm」を新しく標準化する「Encrypted Content-Encoding for HTTP」という仕様が議論されております。
提案自体は数年前に行われており、すでにWGドラフトになっています。
Encrypted Content-Encoding for HTTP
この仕様では、HTTPのボディをAEAD_AES_128_GCMで暗号化します。HTTPSと違って通信路だけでなく、アップロードファイル・ダウンロードファイル自体が暗号化されているため、ファイルが保存される場合も鍵を知っている人(ソフトウェア)のみがその内容を読むことができます。
仕様上では上記のような例があげられておりますが、IETFで同様に議論されているPush通知の標準プロトコル Web Push でこの仕様を使用します。「Message Encryption for Web Push」という仕様で、Content-Encoding: aes128gcmを使ってPush通知の暗号化プロトコルが実現されています。
暗号化概要
この仕様では、暗号化されたデータの他にも幾つかのパラメータをHTTPボディに含めて送信します。
具体的には下記のパラメータが暗号データ以外に送信されます
+-----------+--------+-----------+---------------+ | salt (16) | rs (4) | idlen (1) | keyid (idlen) | +-----------+--------+-----------+---------------+
- salt: ソルト
- rs: レコードサイズ
- idlen: keyidの長さ
- keyid: keying materialの識別子
特徴として鍵交換の具体的方法は定義されておりません、別途別の手段で交換する必要があります。この仕様ではお互いにどのkeying materialを使用しているか識別するためのkeyidを通知するだけになります。
実際に暗号化に使用する鍵は、keying materialより導出されます。
鍵の導出
送信したパラメータと、keying materialより暗号化に用いる鍵を導出します
input keying material (IKM), pseudorandom key (PRK), content encryption key (CEK)
PRK = HMAC-SHA-256(salt, IKM) cek_info = "Content-Encoding: aes128gcm" || 0x00 CEK = HMAC-SHA-256(PRK, cek_info || 0x01)
( || は結合)
ノンスの導出
同様にノンスも導出します
The record sequence number (SEQ)
nonce_info = "Content-Encoding: nonce" || 0x00 NONCE = HMAC-SHA-256(PRK, nonce_info || 0x01) XOR SEQ
レコードのシーケンス番号がつくことで、順番の入れ替えや欠落を検出できるようになっております。
例
パディングの順番が変更になりそうですので、その例でどのように暗号化されるか見ていきます。
( https://github.com/httpwg/http-extensions/blob/0f3ff05b3679f9ead35c1be800723e73915b6aaf/draft-ietf-httpbis-encryption-encoding.md )
この例では、暗号化するデータは「I am the walrus」(UTF-8)、keying materialは「B33e_VeFrOyIHwFTIfmesA」(base64)、keyidは空文字列
HTTP/1.1 200 OK Content-Type: application/octet-stream Content-Length: 54 Content-Encoding: aes128gcm I1BsxtFttlv3u_Oo94xnmwAAEAAA-NAVub2qFgBEuQKRapoZu-IxkIva3MEB1PD- ly8Thjg
- salt (from header) = I1BsxtFttlv3u_Oo94xnmw
- PRK = zyeH5phsIsgUyd4oiSEIy35x-gIi4aM7y0hCF8mwn9g
- CEK = _wniytB-ofscZDh4tbSjHw
- NONCE = Bcs8gkIRKLI8GeI8
- plaintext = SSBhbSB0aGUgd2FscnVzAg