はじめに

Node.js で node-rsa の代わりに、@bluecrypt/keypairsnode-forge を使って鍵の生成や 暗号化/復号化 を行う方法を整理した。

なお node-rsa を使わない理由は単純に処理速度の観点から。

TL;DR

  • node-rsa 以外の RSA 暗号化関連ライブラリについて整理
  • 鍵生成は @bluecrypt/keypairs が速い(※)
  • 暗号化/復号化 などは node-forge が速い(※)
  • 記事が長くなったので、計測結果詳細は別途まとめる(と思う)

※あくまで「自分の計測した範囲では」なので、環境や状況で結果は異なると思う。

この記事が参考になった方
ここここからチャージや購入してくれると嬉しいです(ブログ主へのプレゼントではなく、ご自身へのチャージ)
欲しいもの / Wish list

目次

  1. はじめに
  2. TL;DR
  3. 環境・条件
  4. 詳細
    1. node-rsa
      1. 鍵の生成
      2. 暗号化/復号化
      3. 署名/検証
    2. @bluecrypt/keypairs
      1. 鍵の生成
      2. エクスポート
    3. node-forge
      1. 鍵の生成
      2. 鍵のエクスポート
      3. 鍵のインポート
      4. 暗号化/復号化
      5. 署名/検証
    4. Tips: base64 encode/decode
  5. まとめ
  6. 参考文献

環境・条件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
$ sw_vers
ProductName: Mac OS X
ProductVersion: 10.15.1
BuildVersion: 19B88

$ node -v
v12.7.0

$ npm ls node-rsa
node-rsa@1.0.6 | MIT | deps: 1 | versions: 42

$ npm ls @bluecrypt/keypairs
@bluecrypt/keypairs@0.1.1 | MPL-2.0 | deps: none | versions: 1

$ npm ls node-forge
node-forge@0.9.1 | (BSD-3-Clause OR GPL-2.0) | deps: none | versions: 123

詳細

node-rsa

まずは node-rsa の使い方。

鍵の生成

https://www.npmjs.com/package/node-rsa#creating-empty-key

1
2
const nodeRsa = require("node-rsa");
const key = new nodeRsa({b: 512});

暗号化/復号化

https://www.npmjs.com/package/node-rsa#encryptingdecrypting

1
2
3
4
5
6
7
8
const target = 'hello';
const encrypted = key.encrypt(target);
console.log(encrypted.toString());
// => B\u0011�\u001e��m�Y;�sJ\t0"\u0007\u0018{1�E�-8}�Y�l���k���X�/���Y�-\u0018��\u001fn��=��@t��C��

const decrypted = key.decrypt(encrypted);
console.log(decrypted.toString());
// => hello

署名/検証

https://www.npmjs.com/package/node-rsa#signingverifying

1
2
3
4
5
6
7
8
const target = 'bye';
const signature = key.sign(target);
console.log(signature.toString());
// => 't@�V> 6sU\u0013\u001f�E\u0002A�1���1ٗ/\u001ed,�{��[�\u0006��v\u0003Q�ɮB��#�lQc�\u001b�K\u001co]ש�0��N

const result = key.verify(target, signature);
console.log(result);
// => true

@bluecrypt/keypairs

@bluecrypt/keypairs はブラウザ向けなので、CDN から読み込む。

1
<script src="https://rootprojects.org/keypairs/bluecrypt-keypairs.min.js"></script>

なお、あくまで鍵の生成に特化したライブラリなので、暗号化/復号化/署名/検証 はできない。

鍵の生成

1
2
let keypair;
Keypairs.generate({kty: 'RSA', modulusLength: 512}).then(pair => keypair = pair);

エクスポート

Keypairs.export で PEM 形式での出力ができる。

公開鍵。jwk にキーペアの public を指定。

1
2
3
4
5
6
let publicPem;
Keypairs.export({jwk: keypair.public}).then(pem => publicPem = pem);
console.log(publicPem)
// => -----BEGIN RSA PUBLIC KEY-----
// MEgCQQ...
// -----END RSA PUBLIC KEY-----

秘密鍵。jwk にキーペアの private を指定。

1
2
3
4
5
6
let privatePem;
Keypairs.export({jwk: keypair.private}).then(pem => privatePem = pem);
console.log(privatePem);
// => -----BEGIN RSA PRIVATE KEY-----
// MIIBOQ...
// -----END RSA PRIVATE KEY-----

node-forge

node-forge で RSA 暗号化

鍵の生成

1
2
3
4
5
6
const forge = require("node-forge");
const pki = forge.pki;
const rsa = pki.rsa;

const keypair = rsa.generateKeyPair({bits: 512});
console.log(keypair);

鍵のエクスポート

pki.privateKeyToPempki.publicKeyToPem を使う。

1
2
3
4
5
6
7
8
9
10
const publicPem = pki.publicKeyToPem(keypair.publicKey);
console.log(publicPem)
// => -----BEGIN RSA PUBLIC KEY-----
// MEgCQQ...
// -----END RSA PUBLIC KEY-----

const privatePem = pki.privateKeyToPem(keypair.privateKey);
// => -----BEGIN RSA PRIVATE KEY-----
// MIIBOQ...
// -----END RSA PRIVATE KEY-----

鍵のインポート

@bluecrypt/keypairs などで生成した鍵をインポートする際は、pki.privateKeyFromPempki.publicKeyFromPem を使う。

1
2
3
4
5
6
7
8
9
10
11
12
// Keypairs.export などで生成したり、鍵ファイルを読み込んだりする想定
console.log(publicPem)
// => -----BEGIN RSA PUBLIC KEY-----
// MEgCQQ...
// -----END RSA PUBLIC KEY-----
publicKey = pki.publicKeyFromPem(publicPem);

console.log(privatePem);
// => -----BEGIN RSA PRIVATE KEY-----
// MIIBOQ...
// -----END RSA PRIVATE KEY-----
privateKey = pki.privateKeyFromPem(privatePem);

暗号化/復号化

1
2
3
4
5
6
7
8
const target = 'hello';
const encrypted = keypair.publicKey.encrypt(target);
console.log(encrypted);
// => F\u0013-§dW<+Ô1¿wA½'\u000b\\f-\u0007\u0004Ä\u0003$\fǸ‚\u0003<µ›öº\u0017³Ôß´\u0016\u0017\u0010VSè¨å|ô\u0005¢ó\u0018o‚™\u0012‚׋±÷"

const decrypted = keypair.privateKey.decrypt(encrypted);
console.log(decrypted);
// => hello

署名/検証

いったん forge.md.sha1.create などを噛ませる必要がある。

署名。forge.md.sha1.create() の後に md.update('対象文字列', 'encoding') としたものを使う。

1
2
3
4
5
6
7
8
const target = 'sign';

const md = forge.md.sha1.create();
md.update(target, 'utf8');

const signature = keypair.privateKey.sign(md);
console.log(signature);
// => 3çåêÝ÷â^¢<š_܅ƒ,Óþ/óop9\àÁ‡jd2sCX¾]©×AZßöƒ®Ôôêhñä©<7üÊâ

検証。(当然だが) 署名時に使ったものと同じデータを使う、md.digest().bytes()signature とを引数に渡す。

1
2
3
4
5
6
const md = forge.md.sha1.create();
md.update(target, 'utf8');

const result = keypair.publicKey.verify(md.digest().bytes(), signature);
console.log(result);
// => true

Tips: base64 encode/decode

通信時には、暗号化や署名した結果をさらに base64 エンコードしたり、逆に受信したデータを base64 デコードしたりすることもあると思う。

Node.js はで Buffer.from を使うことで base64 encode/decode が簡単に実現できる。

1
2
3
4
5
6
7
8
9
const target = 'hello';

const base64enc = Buffer.from(target).toString('base64');
console.log(base64enc);
// => aGVsbG8=

const base64dec = Buffer.from(base64enc, 'base64').toString();
console.log(base64dec);
// => hello

base64 以外にも ascii, utf8, hex などがある。

まとめ

  • node-rsa 以外の RSA 暗号化関連ライブラリについて整理
  • 鍵生成は @bluecrypt/keypairs が速い(※)
  • 暗号化/復号化 などは node-forge が速い(※)
  • 記事が長くなったので、計測結果詳細は別途まとめる(と思う)

参考文献

関連記事

この記事が参考になった方
ここここからチャージや購入してくれると嬉しいです(ブログ主へのプレゼントではなく、ご自身へのチャージ)
欲しいもの / Wish list