ブラウザ上で公開鍵を用いて暗号化してから送信、そのままDBに保存、サーバー側で参照するときに復号というシチュエーションで使えるJavaScriptのライブラリを調査しました。
メモとして手順や注意点を残します。
cryptico
クライアントとサーバーの両方で使えるライブラリとなると、このcryptico以外見つけられませんでした。
最後の更新が6年前となかなかの枯れ具合です。
NPM版がこちらで、構成が少し違っています。
オリジナルの方は、秘密鍵の永続化の手段がありませんでしたが、NPM版にはその手段が補われています。
キーの生成
OpenSSH形式を使えたらよかったのですが、秘密鍵を独自のJSON形式で永続化するのが楽でした。
const Cryptico = require('cryptico'),
Fs = require('fs');
// ビット数とパスフレーズ
const bits = 2048;
const passphrase = 'the-passphrase';
// キーの生成
console.log('generating...');
const key = Cryptico.generateRSAKey(passphrase, bits);
// 公開鍵の保存
Fs.writeFileSync('./public.key', Cryptico.publicKeyString(key));
// 秘密鍵の保存
Fs.writeFileSync('./private.json', JSON.stringify(key.toJSON()));
console.log('complete');
秘密鍵はいわばパスフレーズ込みの状態で永続化されるようで、この後パスフレーズを使うことはありませんw
暗号化
Node.js向けのプログラムですが、公開鍵をテキストで用意してあげて、crypt.cipher
を参照すれば暗号文を取得できます。この部分はブラウザでも容易に実行可能です。
miyanaga
という平文を暗号化します。
const Cryptico = require('cryptico'),
Fs = require('fs');
// 公開鍵
const key = Fs.readFileSync('./public.key').toString();
// 平文
const plain = 'miyanag';
// 暗号化
const crypt = Cryptico.encrypt(plain, key);
// 暗号文
Fs.writeFileSync('./cipher.txt', crypt.cipher);
console.log(crypt.cipher);
このような暗号文が取得できました。
UbV1xXLUzISZBUF9ZkqwBPXtYbueCTeLfxVuNcQldlgz304vHddZjcBX2df/D2t2dANVyZPgDLugAablFy5YMhepwlDS+i1blJ8OPKOCSN7WSP8k3uRc0XKgeISvzayynbgwmv0rR8dXtI752hJk/mXnY8dcYhQqlgDkjs1nWbXrRl4py5Te1qxGs+kpHHWr7ySYsnBmRkkW1WErgB8peh5EH2/bhLH/OzVh6yoUrghS57ErtLz/OoIZCwLiTHU2JU6t5fnSoqxIKwnpX+ET8YWdDn4R4sepC176X5OmYF+hUD7QXDijT4GaZfKhvQ0zt8AUyGtvHboGnz5xKLtQGg==?AtqooM9ANbOhW/XxANySb+Sp2uwiUIonJx3qsTouZRw=
復号
RSAKey.parse
で秘密鍵を復元できます。
const Cryptico = require('cryptico'),
Fs = require('fs');
// JSON形式の秘密鍵を復元
const keyJson = Fs.readFileSync('./private.json').toString();
const key = Cryptico.RSAKey.parse(keyJson);
// 暗号文
const cipher = Fs.readFileSync('./cipher.txt').toString();
// 復号
const decrypt = Cryptico.decrypt(cipher, key);
// 平文
console.log(decrypt.plaintext);
無事、平文miyanaga
を取得できました。
ライブラリの古さは感じましたが、容易に目的は達成できました。