Skip welcome & menu and move to editor
Welcome to JS Bin
Load cached copy from
 
<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width">
  <title>JS Bin</title>
</head>
<body>
<br>
  <div>平文 (半角190字まで、全角126字弱まで)<br>
    <textarea id="plain"></textarea>
  </div>
  <button id="encrypt_button" onclick="encrypt()">平文 → 暗号文</button>
  <div>暗号文 (短くて350字ほど)<br>
    <textarea id="encrypted"></textarea>
  </div>
  <label for="show_decryption_ui"><button onclick="document.getElementById('show_decryption_ui').checked = !document.getElementById('show_decryption_ui').checked;">
    復号UI
    </button></label>
  <input id="show_decryption_ui" type="checkbox">
  ← do not touch.
  <div id="for_decrypter">
  <div>public key<br>
  <textarea id="public" disabled>
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAu9BE2aLt4fhmgLYVzl6vPbcwPgC72Bt9K6WfOf3PM9WeVGk9CpDE8TFZPtj3loh6HnmNqnbTwbTsVTo4tD7kQrfeJkVrvNLbNO3CiIAF6cxUE1RBcSgDU6xpPIX5ERv80+/dfBJzNWbc1VgepI6j7M2WQmb+fgM7eAs18yQTHLaNY1Zku20Q+CefJ6FcIo4+bWwq09kB1lGhqZSvv8mW1ytvKQ7mcS30Quov1zRMkC8NtNrZP4Z7CTTxY9bCcFXHXn3V7ypWNKXhZFLsj3okpiYMNWH+UbTOCUawcyhyYeEbv8iQHm4cpvLluSDCeod6bgJnZVi+ZBSkYFQKvCroNQIDAQAB
    </textarea>
  </div>
  <div>private key<br>
    <textarea id="private"></textarea>
  </div>
  <button id="decrypt_button" onclick="decrypt()">暗号文 → 平文</button>
  <button id="generate_button">鍵ペア生成</button>
  <div>decrypted<br>
    <textarea id="decrypted"></textarea>
  <div id="error"></div>
    </div>
  </body>
</html>
 
div {
margin: 10px;
}
textarea {
  width: 100%;
}
#encrypted {
  height: 13em;
}
button {
  height: 3em;
  padding: 1em;
}
#for_decrypter {
  opacity: 50%
}
label div {
  height: 3em;
  background: #8882;
}
#for_decrypter {
  opacity: 50%;
  pointer-events: none;
}
#show_decryption_ui:checked ~ #for_decrypter {
  opacity: 100%;
  pointer-events: auto;
}
 
/*
 * ほとんどこれの改変です.
 * https://zenn.dev/spacemarket/articles/9357ba7de0c9d3
 */
/**
 * RSA方式の公開・秘密鍵を生成する
 * return Promise<CryptoKeyPair>
 */
function generateKey() {
  return window.crypto.subtle.generateKey(
    {
      name: 'RSA-OAEP',
      modulusLength: 2048,
      publicExponent: new Uint8Array([1, 0, 1]),
      hash: 'SHA-256',
    },
    true,
    ['encrypt', 'decrypt'],
  );
};
/**
 * ArrayBufferをbase64にencodeする
 * buffer: ArrayBuffer
 * return string;
 */
function arrayBufferToBase64(buffer) {
  const str = String.fromCharCode.apply(null, new Uint8Array(buffer));
  return window.btoa(str);
};
/**
 * CryptoKey
 * return Promise<string>
 */
async function privateKeyToBase64(ckey) {
  const key = await window.crypto.subtle.exportKey('pkcs8', ckey);
  return arrayBufferToBase64(key);
};
/**
 * CryptoKey
 * return Promise<string>
 */
async function publicKeyToBase64(ckey) {
  const key = await window.crypto.subtle.exportKey('spki', ckey);
  return arrayBufferToBase64(key);
};
/**
 * base64をArrayBufferに変換する
 * return ArrayBuffer
 * https://developers.google.com/web/updates/2012/06/How-to-convert-ArrayBuffer-to-and-from-String
 */
function base64ToArrayBuffer(base64) {
  const str = window.atob(base64);
  const buf = new ArrayBuffer(str.length);
  const bufView = new Uint8Array(buf);
  for (let i = 0, strLen = str.length; i < strLen; i++) {
    bufView[i] = str.charCodeAt(i);
  };
  return buf;
};
/**
 * base64でencodeされた鍵をimportする
 * return : Promise<CryptoKey>
 */
function importPrivateBase64Key(base64Key) {
  return window.crypto.subtle.importKey(
    'pkcs8',
    base64ToArrayBuffer(base64Key),
    {
      name: 'RSA-OAEP',
      hash: 'SHA-256',
    },
    true,
    ['decrypt'],
  );
};
function importPublicBase64Key(base64Key) {
  return window.crypto.subtle.importKey(
    'spki',
    base64ToArrayBuffer(base64Key),
    {
      name: 'RSA-OAEP',
      hash: 'SHA-256',
    },
    true,
    ['encrypt'],
  );
};
async function encryptText(text, publicKey) {
  const encoded = new TextEncoder().encode(text);
  const encryptedBuffer = await window.crypto.subtle.encrypt(
    {name: 'RSA-OAEP'}, publicKey, encoded);
  return arrayBufferToBase64(encryptedBuffer);
};
async function decryptText(encryptedBase64Text, privateKey) {
  const decryptedBuffer = await window.crypto.subtle.decrypt(
    {name: 'RSA-OAEP',},
    privateKey,
    base64ToArrayBuffer(encryptedBase64Text));
  return new TextDecoder().decode(decryptedBuffer);
};
async function generateKeyPair() {
  const public = document.getElementById("public");
  const private = document.getElementById("private");
  // CryptoKeyPair
  const keyPair = await generateKey(); // 鍵を生成
  // string
  const publickey = await publicKeyToBase64(keyPair.publicKey);
  public.textContent = publickey;
  const privatekey = await privateKeyToBase64(keyPair.privateKey);
  private.textContent = privatekey;
  console.log(keyPair);
};
async function encryptAsync() {
  const plain = document.getElementById("plain");
  const encrypted = document.getElementById("encrypted");
  const public = document.getElementById("public");
  const private = document.getElementById("private");
  encrypted.value = "";
  const publickey = await importPublicBase64Key(public.value);
  encrypted.value = await encryptText(plain.value, publickey);
};
async function decryptAsync() {
  const plain = document.getElementById("plain");
  const encrypted = document.getElementById("encrypted");
  const decrypted = document.getElementById("decrypted");
  const public = document.getElementById("public");
  const private = document.getElementById("private");
  const error = document.getElementById("error");
  decrypted.value = "";
  try {
    const privatekey = await importPrivateBase64Key(private.value);
    // console.log(privatekey);
    const result = await decryptText(encrypted.value, privatekey);
    console.log(result);
    decrypted.value = result;
  } catch(e) {
    error.value = e;
  };
};
function encrypt() {
  encryptAsync();
};
function decrypt() {
  decryptAsync();
};
function init() {
  const encrypt_button = document.getElementById("encrypt_button");
  const decrypt_button = document.getElementById("decrypt_button");
  const generate_button = document.getElementById("generate_button");
  encrypt_button.onclick = "";
  decrypt_button.onclick = "";
  generate_button.onclick = "";
  encrypt_button.addEventListener("click", encryptAsync);
  decrypt_button.addEventListener("click", decryptAsync);
  generate_button.addEventListener("click", generateKeyPair);
};
if (document.readyState === 'complete') {
  init();
} else {
  document.addEventListener("DOMContentLoaded", init);
};
/* css
 ********************
div {
margin: 10px;
}
textarea {
  width: 100%;
}
#encrypted {
  height: 13em;
}
button {
  height: 3em;
  padding: 1em;
}
#for_decrypter {
  opacity: 50%
}
#for_decrypter {
  opacity: 50%;
  pointer-events: none;
}
#show_decryption_ui:checked ~ #for_decrypter {
  opacity: 100%;
  pointer-events: auto;
 }
 ********************
 */
/* html
 ********************
<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width">
  <title>JS Bin</title>
</head>
<body>
<br>
  <div>平文<br>
    <textarea id="plain"></textarea>
  </div>
  <button id="encrypt_button" onclick="encrypt()">平文 → 暗号文</button>
  <div>暗号文<br>
    <textarea id="encrypted"></textarea>
  </div>
  <label for="show_decryption_ui">decryption ui</label>
  <input id="show_decryption_ui" type="checkbox">
  <div id="for_decrypter">
  <div>public key<br>
  <textarea id="public" disabled>
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAu9BE2aLt4fhmgLYVzl6vPbcwPgC72Bt9K6WfOf3PM9WeVGk9CpDE8TFZPtj3loh6HnmNqnbTwbTsVTo4tD7kQrfeJkVrvNLbNO3CiIAF6cxUE1RBcSgDU6xpPIX5ERv80+/dfBJzNWbc1VgepI6j7M2WQmb+fgM7eAs18yQTHLaNY1Zku20Q+CefJ6FcIo4+bWwq09kB1lGhqZSvv8mW1ytvKQ7mcS30Quov1zRMkC8NtNrZP4Z7CTTxY9bCcFXHXn3V7ypWNKXhZFLsj3okpiYMNWH+UbTOCUawcyhyYeEbv8iQHm4cpvLluSDCeod6bgJnZVi+ZBSkYFQKvCroNQIDAQAB
    </textarea>
  </div>
  <div>private key<br>
    <textarea id="private"></textarea>
  </div>
  <button id="decrypt_button" onclick="decrypt()">暗号文  平文</button>
  <button id="generate_button">鍵ペア生成</button>
  <div>decrypted<br>
    <textarea id="decrypted"></textarea>
  <div id="error"></div>
    </div>
  </body>
 </html>
 ********************
 */
Output

This bin was created anonymously and its free preview time has expired (learn why). — Get a free unrestricted account

Dismiss x
public
Bin info
anonymouspro
0viewers