[JavaScript] Web Crypto API を使用して RSAES-OAEP データ暗号化および復号化を行う

JavaScript で RSAES-OAEP データ暗号化および復号化を行う方法について説明します。

RSAES-OAEP と RSA-OAEP は同じ意味です。

# 1. 暗号化および復号化のための準備

## 1.1. 文字列と `Uint8Array` や `ArrayBuffer` の変換

暗号化および復号化で文字列を `Uint8Array` 型や `ArrayBuffer` 型で扱うため、`TextEncoder` および `TextDecoder` を用いて変換します。

```js
const textEncoder = new TextEncoder();
const encodeString = string => textEncoder.encode(string);

const textDecoder = new TextDecoder();
const decodeString = buffer => textDecoder.decode(buffer);
```

参考「[TextEncode.encode() - Web API | MDN](https://developer.mozilla.org/ja/docs/Web/API/TextEncoder/encode)」
参考「[TextDecoder.decode() - Web APIs | MDN](https://developer.mozilla.org/en-US/docs/Web/API/TextDecoder/decode)」

## 1.2. Base64 エンコードおよびデコード

バイナリデータをテキストとして扱うため Base64 を利用することにします。

JavaScript での Base64 エンコードおよびデコードに関する説明は別記事にしました。

参考「[[JavaScript] Unicode 文字列やバイナリデータを Base64 エンコードおよびデコードする - Qiita](https://qiita.com/kerupani129/items/1d6b936974ec65ae4833)」

本記事では以下のコードを利用することにします。

```js
const encodeBinaryString = binaryString => Uint8Array.from(
	binaryString,
	binaryChar => binaryChar.charCodeAt(0),
);

const decodeBinaryString = uint8Array => uint8Array.reduce(
	(binaryString, uint8) => binaryString + String.fromCharCode(uint8),
	'',
);

const encodeBase64 = uint8Array => {
	const binaryString = decodeBinaryString(uint8Array);
	const base64 = btoa(binaryString);
	return base64;
};

const decodeBase64 = base64 => {
	const binaryString = atob(base64);
	const uint8Array = encodeBinaryString(binaryString);
	return uint8Array;
};
```

# 2. 暗号化および復号化

## 2.1. 暗号鍵の生成

`crypto.subtle.generateKey` 関数で暗号鍵を生成できます。

本記事では、RSA 鍵の長さは 3072 ビット (384 バイト) とし、メッセージ・ダイジェスト・アルゴリズムに SHA-256 を使用することにします。

RSA 鍵を生成する際の公開指数は 65537 ($= 2^{16} + 1$) が使われることが多く、本記事でもそれを使用することにします (バイト配列で表現すると `[0x01, 0x00, 0x01]` になります) 。

参考「[SubtleCrypto.generateKey() - Web API | MDN](https://developer.mozilla.org/ja/docs/Web/API/SubtleCrypto/generateKey)」
参考「[RsaHashedKeyGenParams - Web API | MDN](https://developer.mozilla.org/ja/docs/Web/API/RsaHashedKeyGenParams)」

参考「[公開指数(public exponent)について | GMOグローバルサイン サポート](https://jp.globalsign.com/support/ssl/confinfo/about_public_exponent.html)」

`crypto.subtle.generateKey` 関数で生成される暗号鍵は `CryptoKey` 型になっています。

`crypto.subtle.exportKey` 関数で `CryptoKey` 型の鍵を外部出力可能な形式に変換した後、バイナリデータを Base64 エンコードして文字列化します。

参考「[SubtleCrypto.exportKey() - Web APIs | MDN](https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto/exportKey)」

RSA 公開鍵は SubjectPublicKeyInfo 形式 (`spki`)、RSA 秘密鍵は PKCS #8 (Private-Key Information) 形式 (`pkcs8`) で出力します。

参考「[PKCS #8 - Supported formats - SubtleCrypto.importKey() - Web APIs | MDN](https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto/importKey#pkcs_8)」
参考「[RFC 5208 - Public-Key Cryptography Standards (PKCS) #8: Private-Key Information Syntax Specification Version 1.2](https://datatracker.ietf.org/doc/html/rfc5208)」
参考「[SubjectPublicKeyInfo - Supported formats - SubtleCrypto.importKey() - Web APIs | MDN](https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto/importKey#subjectpublickeyinfo)」

```js
const exportPublicKey = async key => {
	const keyArrayBuffer = await crypto.subtle.exportKey('spki', key);
	const keyBase64 = encodeBase64(new Uint8Array(keyArrayBuffer));
	return keyBase64;
};

const exportPrivateKey = async key => {
	const keyArrayBuffer = await crypto.subtle.exportKey('pkcs8', key);
	const keyBase64 = encodeBase64(new Uint8Array(keyArrayBuffer));
	return keyBase64;
};

const generateKeyPair = async () => {

	const keyPair = await crypto.subtle.generateKey(
		{
			name: 'RSA-OAEP',
			modulusLength: 3072,
			publicExponent: new Uint8Array([0x01, 0x00, 0x01]),
			hash: 'SHA-256',
		},
		true,
		['encrypt', 'decrypt'],
	);

	const publicKey = await exportPublicKey(keyPair.publicKey);
	const privateKey = await exportPrivateKey(keyPair.privateKey);

	return {
		publicKey,
		privateKey,
	};

};

// 
const keyPair = await generateKeyPair();

const publicKeyBase64 = keyPair.publicKey;
console.log(publicKeyBase64);

const privateKeyBase64 = keyPair.privateKey;
console.log(privateKeyBase64);
```

```:実行結果の例
MIIBojANBgkqhkiG9w0BAQEFAAOCAY8AMIIBigKCAYEAuXRtjroFtFYc3CakJALtvka9Rrq5aqN8BV0aQtQtc9OYYDG8+A1WukGxl+Q0jr0GF45BW/d2fvWFE/D4wygTzyQf4kjoIuwto001ENq3wXPWij/TfDx0YSp1zm3CL4hIFBnzyZbHL7mBabHCsjXtakApo19sXViQqdiRyXRj4CeYhoi3jJY4fWut+eqxlF+2J6L0NrpDjuAvdtgThg+HTyTI0mgBJihDM2Lr4Ca1zMbEL+6mF9oZlVS9Nqzw+YBu5aaAjTGIly1qGcdBTM2Bc3u4tx9OopYOFoXbdmjwEsk0XpDMa2BVWEfrQm5VE5oq2PuR/4U7ynuBJcyOQPBSdNK1hQYPH+Y5OJlksZRlipLk7p809afcH/iGNTShpm/TYkWT0xzS6aupZB0t8ldfI5OVFnUY+N6Yh7OeaxZ8dDjJ97VYaSq/d3N7O/IJzp/ZKRp6r0p51pR/4Y9iU182M0kEUdDQMuO7B5u+awof9eSiovbHzd1DBHIrsoc7z+97AgMBAAE=
MIIG/AIBADANBgkqhkiG9w0BAQEFAASCBuYwggbiAgEAAoIBgQC5dG2OugW0VhzcJqQkAu2+Rr1Gurlqo3wFXRpC1C1z05hgMbz4DVa6QbGX5DSOvQYXjkFb93Z+9YUT8PjDKBPPJB/iSOgi7C2jTTUQ2rfBc9aKP9N8PHRhKnXObcIviEgUGfPJlscvuYFpscKyNe1qQCmjX2xdWJCp2JHJdGPgJ5iGiLeMljh9a6356rGUX7YnovQ2ukOO4C922BOGD4dPJMjSaAEmKEMzYuvgJrXMxsQv7qYX2hmVVL02rPD5gG7lpoCNMYiXLWoZx0FMzYFze7i3H06ilg4Whdt2aPASyTRekMxrYFVYR+tCblUTmirY+5H/hTvKe4ElzI5A8FJ00rWFBg8f5jk4mWSxlGWKkuTunzT1p9wf+IY1NKGmb9NiRZPTHNLpq6lkHS3yV18jk5UWdRj43piHs55rFnx0OMn3tVhpKr93c3s78gnOn9kpGnqvSnnWlH/hj2JTXzYzSQRR0NAy47sHm75rCh/15KKi9sfN3UMEciuyhzvP73sCAwEAAQKCAYAipdHiHHb8Xio+Jyn7YGCyb9zk3fXOKoT9K4vAeIuVXC7XqfM4FKXjXmqjigsXr9D3jahAWldVGOGn/Bk9vLsWtBUQ3bYg8CcGn2IOqA40okOuyIXmbBUCIkCoNHFXGAr/Vmnpe7XzAKFg8ckCKnkUpLAiya0hM26zjLaQAKK4Oi2Q1PIV3ern47o5OtO6eLc7aIJfxyTgCJpVhcEABt6stp6eULgGPPdxHkYbNqA4hdoZami1hBXLhG1lTaInuwqqkUqh6IlaEAzO1TSxgKzWD1+lTNqUeucfZkHhWdq/xK/j6cZcxEnIzOfKkegIsyolmnbIS5peRm0RA9O4XH9/VzMFWKhZ94mkWrMFZbijQF0n1KsIdolukbDpip9Hd3S0KOzeaYv4saomU6OaqHPXkE6YEM+V/FQFalx6rU6LrbTqCi+nWdHU8U4DY51c4LJHzPRPjTJ9E2dadhHmSt6ami0Xsmax7NbYN1CDhF0n+MM+AvUEA5q8bpVYfCfCrYECgcEA/km4BucFP2JFLTD9CUACIo/IqLx/3VxQBwIe5i1+Hy1zaB9odo/SsC83ZQRZlJtgLp/Ao2brEfPRRi08fYqUGCNWDg40BIjSWoyBBTwxnewx/q7QgzhMzmeFojpNdSC1WRD2RtWhsoNAEENv9LErKDw5voyH0N5gUWW2sCwyiwJedC/Sd+Z/WBcqewLa8MhuTejzNgchx3cQ6AeRxICZeQB19Ok/K2nBDXV69xF0fF5at/aYyTaSRomOxi7OgqJrAoHBALq0EiNe71eY0iarb4dvFvgD/QFULKmDGMEJxfA/ioF2IEqgWDHPnubZNoKjDJYYPXosY9Op17+fSQRRhogY41TEZiTY9bsbFtVDA0jOVVtxlWkrIFik4MD7z+p3rWKYYEf6zbv7Xv/XpXWvN2CrVgUfh1OSbrmGEuAc21SttoeGMXpXPSZXtlJPoAXlt4Mj9YJOzGBkgOhv4u82xFcSBxPr5bhTZx9SUYTEe0Kxe/bZmHtjeeQa4erKuAorwwzLMQKBwExkCQzJyiHIe8+fr+RffkSzvSwztJXjbYctc+riL8ld9hWJmfBENJ8JEDMgo2ipZLOc+locSPITtQLIBCwSvXqi4u9GBQp3r/nTy86uzpkKo9pG2g0RlMFNCDA8I5jUQqaHGfUdqH3gQBaiq7duofBsZ0x/Gy38ICNT0xYJsQVhqM5ur2Olswvbqb9alDtRexGcsbPBYLxzYHjUDU5i87gOE2GH0JpSItTQPiiK7duO3OH3Ct8nrbnTCTkwRomoEQKBwA9cYWGnnemHGUM1N6fc6/bb3SUO193ae17mfvKVR7//CAkbyCXQ/zHfDS0SXSa8N9KldFEl2Cpb4JYKXxczdQC0Z/MAJreOMwK40LxcvYkYf0J32eFxL0yxaxnPXuSNxN4nNGYS+G30QBi+ob/CWQFy5p9pnNKGxWbK+QCuiiX8VHXMV6uf69A53OCfVcnkW36tHQORQUnear1jtCO1x/9LmUrhEcrx6uMRh1KlZ52XqYP9Wzn5PD0lEJ9FmnajAQKBwGT3qys+V8JxhQ45d6d/9dGZKdVBukjZEpAJGK++nBQZwBizz8c55MyEQjoW1w2DvwA9G8bwBeqSJTujiEi7JOgmRLKsxwkykLVwk+2vYbOpAzqpYfgvH6HWhznv6iM6xoGqkmu9vtWcdANBl61IO3RQURGsBTAGLp1riESOBNPQAdqxvy4iFvcB1dvpYZoEZ07FbXOtfmiMtLc8q8JSMZj1YlPz7s4BLAigOVSyk0i85flmFKLTGcwaygx+Giam1g==
```

(※ここでは例として秘密鍵も記載していますが、実際には秘密鍵を第三者に知られないようにする必要があります。)

## 2.2. 暗号化

データ暗号化は `crypto.subtle.encrypt` 関数を用います。

参考「[SubtleCrypto.encrypt() - Web APIs | MDN](https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto/encrypt)」

`crypto.subtle.encrypt` 関数で使用する暗号鍵 (ここでは RSA 公開鍵) は `CryptoKey` 型で指定するため、暗号鍵の文字列を Base64 デコードして `crypto.subtle.importKey` 関数で `CryptoKey` 型に変換します。

参考「[SubtleCrypto.importKey() - Web APIs | MDN](https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto/importKey)」

```js
const importPublicKey = async keyBase64 => {
	const keyUint8Array = decodeBase64(keyBase64);
	const key = await crypto.subtle.importKey(
		'spki',
		keyUint8Array,
		{
			name: 'RSA-OAEP',
			hash: 'SHA-256',
		},
		false,
		['encrypt'],
	);
	return key;
};

const encryptString = async (keyBase64, plaintext) => {
	const key = await importPublicKey(keyBase64);
	const plaintextUint8Array = encodeString(plaintext);
	const ciphertextArrayBuffer = await crypto.subtle.encrypt(
		{
			name: 'RSA-OAEP',
		},
		key,
		plaintextUint8Array,
	);
	const ciphertextBase64 = encodeBase64(new Uint8Array(ciphertextArrayBuffer));
	return ciphertextBase64;
};

// 
const publicKeyBase64 = 'MIIBojANBgkqhkiG9w0BAQEFAAOCAY8AMIIBigKCAYEAuXRtjroFtFYc3CakJALtvka9Rrq5aqN8BV0aQtQtc9OYYDG8+A1WukGxl+Q0jr0GF45BW/d2fvWFE/D4wygTzyQf4kjoIuwto001ENq3wXPWij/TfDx0YSp1zm3CL4hIFBnzyZbHL7mBabHCsjXtakApo19sXViQqdiRyXRj4CeYhoi3jJY4fWut+eqxlF+2J6L0NrpDjuAvdtgThg+HTyTI0mgBJihDM2Lr4Ca1zMbEL+6mF9oZlVS9Nqzw+YBu5aaAjTGIly1qGcdBTM2Bc3u4tx9OopYOFoXbdmjwEsk0XpDMa2BVWEfrQm5VE5oq2PuR/4U7ynuBJcyOQPBSdNK1hQYPH+Y5OJlksZRlipLk7p809afcH/iGNTShpm/TYkWT0xzS6aupZB0t8ldfI5OVFnUY+N6Yh7OeaxZ8dDjJ97VYaSq/d3N7O/IJzp/ZKRp6r0p51pR/4Y9iU182M0kEUdDQMuO7B5u+awof9eSiovbHzd1DBHIrsoc7z+97AgMBAAE=';

const plaintextA = '犬と猫、そして兎';
console.log(plaintextA);

const ciphertextBase64 = await encryptString(publicKeyBase64, plaintextA);
console.log(ciphertextBase64);
```

```:実行結果
犬と猫、そして兎
BHSdH2hu6GXOkBSbEMlU6wLUCiXNqnNRQ0s3gvHx12TBlFR8BT5vcnz6eymbCCp+e2xPPOXUXvqdl9/x6ihO90p9pXWQsf5YyvvSkWZwwd5+GWfSEFtu5/OiQyzvCNxYVP+m3rCUamvGIBN/8lLdO4Yd+jSKqRomzS4jQq/HxoTeUDSBle5O5DHhR+8AZaH1rR5vgXzmRm1Herh92HjKK9dtSXRoF7TW2D80H6QlMP3UMeKQ/1vGFkl7aaVVhRFaE+hF0sv2/B+cfSkB8DG5SDbCt7iQyWDIYOPGSzGfo058Ukqr+FnqhuXqzUsORZVeL/ui9Of4hSPsfRfeOQmFih8OJ3T0/vxW6/oNiEghyOIZT1sapWZPPWWrLgBKT1nMxmYuaUZbMW4SnIjVgeqE31IbklS/b6L3i93U08dS6lh5gBevy5rBEy15B1HNTzOjohP+bofpZdh+lEEnfur8CQ5r6nPTFrk0S4bpxPOY/H2XqRcj9r23PqnWzQV2Zf/b
```

## 2.3. 復号化

データ復号化は `crypto.subtle.decrypt` 関数を用います。

参考「[SubtleCrypto.decrypt() - Web APIs | MDN](https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto/decrypt)」

`crypto.subtle.decrypt` 関数で使用する復号鍵 (ここでは RSA 秘密鍵) は `CryptoKey` 型で指定するため、復号鍵の文字列を Base64 デコードして `crypto.subtle.importKey` 関数で `CryptoKey` 型に変換します。

参考「[SubtleCrypto.importKey() - Web APIs | MDN](https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto/importKey)」

```js
const importPrivateKey = async keyBase64 => {
	const keyUint8Array = decodeBase64(keyBase64);
	const key = await crypto.subtle.importKey(
		'pkcs8',
		keyUint8Array,
		{
			name: 'RSA-OAEP',
			hash: 'SHA-256',
		},
		false,
		['decrypt'],
	);
	return key;
};

const decryptString = async (keyBase64, ciphertextBase64) => {
	const key = await importPrivateKey(keyBase64);
	const ciphertextUint8Array = decodeBase64(ciphertextBase64);
	const plaintextArrayBuffer = await crypto.subtle.decrypt(
		{
			name: 'RSA-OAEP',
		},
		key,
		ciphertextUint8Array,
	);
	const plaintext = decodeString(plaintextArrayBuffer);
	return plaintext;
};

// 
const privateKeyBase64 = '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';

const ciphertextBase64 = 'BHSdH2hu6GXOkBSbEMlU6wLUCiXNqnNRQ0s3gvHx12TBlFR8BT5vcnz6eymbCCp+e2xPPOXUXvqdl9/x6ihO90p9pXWQsf5YyvvSkWZwwd5+GWfSEFtu5/OiQyzvCNxYVP+m3rCUamvGIBN/8lLdO4Yd+jSKqRomzS4jQq/HxoTeUDSBle5O5DHhR+8AZaH1rR5vgXzmRm1Herh92HjKK9dtSXRoF7TW2D80H6QlMP3UMeKQ/1vGFkl7aaVVhRFaE+hF0sv2/B+cfSkB8DG5SDbCt7iQyWDIYOPGSzGfo058Ukqr+FnqhuXqzUsORZVeL/ui9Of4hSPsfRfeOQmFih8OJ3T0/vxW6/oNiEghyOIZT1sapWZPPWWrLgBKT1nMxmYuaUZbMW4SnIjVgeqE31IbklS/b6L3i93U08dS6lh5gBevy5rBEy15B1HNTzOjohP+bofpZdh+lEEnfur8CQ5r6nPTFrk0S4bpxPOY/H2XqRcj9r23PqnWzQV2Zf/b';
console.log(ciphertextBase64);

const plaintextB = await decryptString(privateKeyBase64, ciphertextBase64);
console.log(plaintextB);
```

(※ここでは例として秘密鍵も記載していますが、実際には秘密鍵を第三者に知られないようにする必要があります。)

```:実行結果
BHSdH2hu6GXOkBSbEMlU6wLUCiXNqnNRQ0s3gvHx12TBlFR8BT5vcnz6eymbCCp+e2xPPOXUXvqdl9/x6ihO90p9pXWQsf5YyvvSkWZwwd5+GWfSEFtu5/OiQyzvCNxYVP+m3rCUamvGIBN/8lLdO4Yd+jSKqRomzS4jQq/HxoTeUDSBle5O5DHhR+8AZaH1rR5vgXzmRm1Herh92HjKK9dtSXRoF7TW2D80H6QlMP3UMeKQ/1vGFkl7aaVVhRFaE+hF0sv2/B+cfSkB8DG5SDbCt7iQyWDIYOPGSzGfo058Ukqr+FnqhuXqzUsORZVeL/ui9Of4hSPsfRfeOQmFih8OJ3T0/vxW6/oNiEghyOIZT1sapWZPPWWrLgBKT1nMxmYuaUZbMW4SnIjVgeqE31IbklS/b6L3i93U08dS6lh5gBevy5rBEy15B1HNTzOjohP+bofpZdh+lEEnfur8CQ5r6nPTFrk0S4bpxPOY/H2XqRcj9r23PqnWzQV2Zf/b
犬と猫、そして兎
```