<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 xKeyboard Shortcuts
Shortcut | Action |
---|---|
ctrl + [num] | Toggle nth panel |
ctrl + 0 | Close focused panel |
ctrl + enter | Re-render output. If console visible: run JS in console |
Ctrl + l | Clear the console |
ctrl + / | Toggle comment on selected lines |
ctrl + ] | Indents selected lines |
ctrl + [ | Unindents selected lines |
tab | Code complete & Emmet expand |
ctrl + shift + L | Beautify code in active panel |
ctrl + s | Save & lock current Bin from further changes |
ctrl + shift + s | Open the share options |
ctrl + y | Archive Bin |
Complete list of JS Bin shortcuts |
JS Bin URLs
URL | Action |
---|---|
/ | Show the full rendered output. This content will update in real time as it's updated from the /edit url. |
/edit | Edit the current bin |
/watch | Follow a Code Casting session |
/embed | Create an embeddable version of the bin |
/latest | Load the very latest bin (/latest goes in place of the revision) |
/[username]/last | View the last edited bin for this user |
/[username]/last/edit | Edit the last edited bin for this user |
/[username]/last/watch | Follow the Code Casting session for the latest bin for this user |
/quiet | Remove analytics and edit button from rendered output |
.js | Load only the JavaScript for a bin |
.css | Load only the CSS for a bin |
Except for username prefixed urls, the url may start with http://jsbin.com/abc and the url fragments can be added to the url to view it differently. |