Open sounisi5011 opened 4 years ago
よって、
Date.now()
の返り値を使用する。ECMAScript Date objectsがサポートする最大のUnixtimeは8,640,000,000,000,000ミリ秒で、これは7 bytesに収まるため、Unixtimeに追加の乱数5 bytes(もしくは6 bytes。Unixtimeの最大値も6 bytesになるが、6 bytesを超えるのは西暦10889年8月2日であるため、問題は無い)を追加した値を初期ベクトル(IV)に使用する。
データ通信処理への転載を想定するなら、ミリ秒単位の日付情報なんて当てにならない。実装次第では1秒ごとに変化するなんてこともある。1秒の間に、6 bytesの乱数が誕生日パラドックスで衝突してしまうリスクは十分考慮すべきでは?
まっとうな実装は、IVとしてカウンターを使います。 ─ 本当は怖いAES-GCMの話 - ぼちぼち日記
暗号化処理のオプションで以前までのカウント値を指定できるようにしたほうがいいぞ… 必須オプションにすれば、省略もできなくなるし、勉強になる
cipheriv
でnpm内を検索したら、以下の興味深いパッケージを発見した:
string-crypto
「1つのパスワードのみでデータを暗号化する」という目的は共通している。
ただし、IVをランダムに生成していたり、Buffer
をわざわざ文字列化して結合していたりと問題もある。
興味深い点として、パスフレーズを鍵導出関数の一種PBKDF2を使用してハッシュ化した上でcrypto.createCipheriv()
メソッドのkey
引数に渡している。この点は考慮していなかったため、必要があれば導入を検討するべきかもしれない。@ronomon/crypto-async
Node.js組み込みのcrypto
モジュールを高速化・マルチスレッド対応化したものらしい。ところで随分前に@sounisi5011/encrypted-archive
を作ってしまってだな
plugins/metalsmith/url-shortener/encrypt.js
に含まれるいくつかの問題を修正する。authTagLength
を生成するバイナリファイルに含めないcipher.getAuthTag()
メソッドが生成するBuffer
オブジェクトのlength
プロパティから取得できるため。TLS1.2のAES-GCMフレームにも含まれていないため、おそらく省略は可能。crypto.createCipheriv()
のauthTagLength
オプションを省略するGCM modeでは、
authTagLength
オプションは省略することができる。初期値は16 bytesで、これは現在の設定と同様。ただでさえややこしいのだから、省略できるパラメータは除くことが好ましい。追記:
aes-256-gcm
ではauthTagLength
オプションが省略可能だが、chacha20-poly1305
ではauthTagLength
オプションが必須のため、省略はしない。バイナリデータのチャンク長を表現する数値でunsigned-varintを使用する。
当初はPNGのチャンクと同様に同じ
chunkType
を持つ複数のチャンクで255 bytesを超える長さのデータを扱うつもりだったが、WebAssemblyのunsigned LEB128やmultiformatsのunsigned varintのほうが効率が良いと思われるため、varint
パッケージを使用して対応する。iv
の再生成で乱数のみを使用しない初期ベクトル(IV)の生成に乱数を用いた場合は、多量の暗号化処理の際に同じ乱数が生成され、衝突する可能性が高まる。誕生日パラドックスにより、この確率は意外と高い。この用途ではビルドの度に再生成するため、データ通信ほど高頻度に生成されることは無く、このリスクはおそらく無視できるほどに小さい。しかし、将来(私自身を含め)誰かがこのコードをパクってデータ通信処理を書いた場合に、脆弱性を組み込む可能性がある。
よって、
Date.now()
の返り値を使用する。ECMAScript Date objectsがサポートする最大のUnixtimeは8,640,000,000,000,000ミリ秒で、これは7 bytesに収まるため、Unixtimeに追加の乱数5 bytes(もしくは6 bytes。Unixtimeの最大値も6 bytesになるが、6 bytesを超えるのは西暦10889年8月2日であるため、問題は無い)を追加した値を初期ベクトル(IV)に使用する。