encryptWithAD

HKDFによりk,ckを入手したら、kを利用して暗号化(encrypt)する。それは良いが、何がADなのか、というと、おそらく、associated data。

boltで定義されているそれを見てみると、

encryptWithAD(k, n, ad, plaintext)

Where encrypt is an evaluation of ChaCha20-Poly1305 (IETF variant) with the passed arguments, with nonce n encoded as 32 zero bits, followed by a little-endian 64-bit value.
Note: this follows the Noise Protocol convention, rather than our normal endian.

渡された引数とnonceでChaCha20-Poly1305を利用して暗号化します。これはnoise protocolの規則に従い、通常のエンディアンとは異なります。って感じか。

また新しい単語が出てきた。ChaCha20-Poly1305とは。

ChaCha20-Poly1305

このブログが詳しい。

まずは、これは新しいTLSの暗号方式なのだけれど、そもそもTLSがなんなのかわからない。無限に続く芋づるだけれど、付き合う。

Transport Layer Security(トランスポート・レイヤー・セキュリティ、TLS)は、インターネットなどのコンピュータネットワークにおいてセキュリティを要求される通信を行うためのプロトコルである。主な機能として、通信相手の認証、通信内容の暗号化、改竄の検出を提供する。TLSはIETFによって策定された。
当プロトコルは(特に区別する場合を除いて)SSL (Secure Sockets Layer) と呼ばれることも多い。これは、TLSの元になったプロトコルがSSLであり、そのSSLという名称が広く普及していることによる。

これはすんなり入ってくる。SSLはSecure Sockets Layerのことだったのか。TCP/IPも一度しっかり抑えたほうが、いろんな知識が入りやすくなるかもしれないな。

lndでは下記の形でおそらく

  1. c = encryptWithAD(temp_k1, 0, h, zero)
  2. h = SHA-256(h || c)

を実行している。

// EncryptAndHash returns the authenticated encryption of the passed plaintext.
// When encrypting the handshake digest (h) is used as the associated data to
// the AEAD cipher.
func (s *symmetricState) EncryptAndHash(plaintext []byte) []byte {  
    ciphertext := s.Encrypt(s.handshakeDigest[:], nil, plaintext)

    s.mixHash(ciphertext)

    return ciphertext
}

ここまでの流れを整理すると

import * as elliptic from 'elliptic';  
const sha256 = require('bcrypto/lib/sha256');  
const ecdsa = new elliptic.ec('secp256k1');

// 1. e = generateKey()
const e = ecdsa.keyFromPrivate('22a47fa09a223f2aa079edf85a7c2d4f8720ee63e502ee2869afab7de234b80c', 'hex');

// 2. h = SHA-256(h || e.pub.serializeCompressed())
const digest = sha256.digest(Buffer.from('Noise_XK_secp256k1_ChaChaPoly_SHA256', 'ascii'));  
const h = sha256.multi(digest, Buffer.from(e.getPublic('hex')));

// 3. es = ECDH(e.priv, rs)
const point = re.getPublic().mul(e.getPrivate());  
let format = '02';  
if (point.getY().isOdd()) {  
  format = '03';
}
const es = format + point.getX().toString(16);

// 4. ck, temp_k1 = HKDF(ck, es)

// 5. c = encryptWithAD(temp_k1, 0, h, zero)

先は長い・・・