opensslで暗号化したファイルをnode.jsのcreateDecipherivで復号する

2 min read読了の目安(約2100字

VercelにGCPのキーを渡すのをどうにかしたい方法について検討していたところ自前でencryptする例を見つけた。

この例だとオンラインの変換ツールを使っているのだが、もう少しスマートにopensslコマンドで暗号化ファイルを生成すればもうちょっといい感じに出来るのではないかと色々試してみた

手順サンプル

下準備

まず秘匿化したいファイルを生成

$ echo "this is secret" > rawfile.txt

これをopensslでencodingする。

$ openssl enc -aes-256-cbc -a -in rawfile.txt -out encrypted.txt -k passphrase -p
  • encでエンコードに指定
  • -aes-256-cbc でアルゴリズム指定
    • keyを短くしたい場合は-aes-128-cbcでも良いだろう
  • -aでbase64平文で出力。-Aにすればbase64 binaryになる
  • -k passphraseでパスフレーズを入力。今回はわかりやすさのためにCLIで指定してるが、本来しないほうが良い。
  • -pで下記のようにkey/ivが出力される
salt=4FB66F28D1694A76
key=BB2C6AE86D97EB01D4CC0C9A54EBC024A195B54158C7D07AA3FDA24430F25286
iv =AA3789F28406951F8C675F05AF672B45
  • passphraseとsaltによってkeyとivが生成されているので、これを-pで出力せずにnode側で計算することも出来そうだったが、今回は諦めた。
  • saltを固定したい場合は-S 4FB66F28D1694A76のようにすると良い。

コード

これを復号化するコードを書いてみたい。

// decrypt.js

const crypto = require("crypto")
const fs = require('fs')

const algorithm = "aes-256-cbc" 
const key = process.env.DECRYPT_KEY
const iv = process.env.DECRYPT_IV

const decrypt = (key, iv, source) => {
  const decipher = crypto.createDecipheriv(
    algorithm,
    Buffer.from(key, "hex"),
    Buffer.from(iv, "hex")
  )
  // ↓ここポイント。`slice`でsalt部分を消す。
  const data = Buffer.from(source, "base64").slice(16)
  const start = decipher.update(data)
  const final = decipher.final();
  const result = Buffer.concat([start, final]).toString("utf8")
  return result
}

// Base64のファイルだが、データ自体はテキストファイルなのでutf8で開く
const source = fs.readFileSync("encrypted.txt", { encoding: "utf8" })
const result = decrypt(key,iv, source)

console.log("decrypt:", result)

一番厄介なのが.slice(16)している部分。opensslの仕様として先頭にSaltが埋め込まれてるっぽい(調べたがいまいちわからなかった)
openssl-nosaltのオプションを付ければこの処理が不要にはなるが、後方互換用のオプションなのでおそらくやめたほうが良さそうだ。

そしてこれを環境変数で指定して実行してみる

$ DECRYPT_KEY=BB2C6AE86D97EB01D4CC0C9A54EBC024A195B54158C7D07AA3FDA24430F25286 \
DECRYPT_IV=AA3789F28406951F8C675F05AF672B45 \
node decrypt.js

下記のように復号化が確認できるだろう。

decrypt: this is secret

vercelで利用したい場合はDECRYPT_KEYDECRYPT_IVを埋め込めが復号化出来るはずだ