+ This online key signing and encryption example should
+ NEVER
+ be used in a production environment. This was made for educational purposes in exploring the use of cryptography in the web without the use of
+ third-party libraries. You can find the source code for this website here.
+
+
+
+ The resulting data is manipulated to allow for viewing in-line in the browser so the relationships can be more easily observed.
+
+
+
Your unencrypted text
+
+
+
+
+
+
+
+
+
+
+
Encrypted String
+
+
+
+
Decrypted String
+
+
+
+
+
Signature String
+
+
+
+
+
Public Key (Encryption)
+
+
+
+
+
Private Key (Encryption)
+
+
+
+
+
Public Key (Signing)
+
+
+
+
+
Private Key (Signing)
+
+
+
+
+
Results
+
+
+
+
+
+
diff --git a/index.js b/index.js
new file mode 100644
index 0000000..7dc64d9
--- /dev/null
+++ b/index.js
@@ -0,0 +1,92 @@
+let public_key;
+let private_key;
+
+let public_signing_key;
+let private_signing_key;
+
+const qs = (selector) => document.querySelector(selector);
+
+async function generateRSAKeyPair() {
+ // From what I can gather from online sources,
+ // the in browser crypto module can not generate keys that can be used for both signing and encryption.
+ // For this example we will just generate two key pairs, and use them for their recommended purpose.
+
+ // Create Encryption/Decryption keypair
+ const encryption_keypair = await window.crypto.subtle.generateKey(
+ {
+ name: "RSA-OAEP",
+ modulusLength: 2048,
+ publicExponent: new Uint8Array([0x01, 0x00, 0x01]), // 65537
+ hash: "SHA-256",
+ },
+ true,
+ ["encrypt", "decrypt"]
+ );
+
+ // Create signing keypair
+ const signing_keypair = await window.crypto.subtle.generateKey(
+ {
+ name: "RSASSA-PKCS1-v1_5",
+ modulusLength: 2048,
+ publicExponent: new Uint8Array([0x01, 0x00, 0x01]), // 65537
+ hash: "SHA-256",
+ },
+ true,
+ ["sign", "verify"]
+ );
+
+ // These keys will be used to encrypt data
+ public_key = encryption_keypair.publicKey;
+ private_key = encryption_keypair.privateKey;
+
+ // These keys will be used to "sign" messages
+ public_signing_key = signing_keypair.publicKey;
+ private_signing_key = signing_keypair.privateKey;
+
+ // Update displays
+ qs("#pub-key-enc").innerText = await _exportKey(public_key, "spki");
+ qs("#priv-key-enc").innerText = await _exportKey(private_key, "jwk");
+
+ qs("#pub-key-sign").innerText = await _exportKey(public_signing_key, "spki");
+ qs("#priv-key-sign").innerText = await _exportKey(private_signing_key, "jwk");
+}
+async function executeTests() {
+ const user_string = document.querySelector("#my-secret-string").value;
+
+ // Get our data with our generated keys and user-submitted text
+ const encrypted_string = await encryptString(user_string);
+ const decrypted_string = await decryptString(encrypted_string);
+ const signed_message = await signMessage(user_string);
+ const message_verified = await verifyMessage(user_string, signed_message);
+
+ // Generate Results
+ let results = `Message Signature Verified? ${message_verified} `;
+
+ qs("#encrypted-string").innerText = new Uint8Array(encrypted_string).toString();
+ qs("#decrypted-string").innerText = decrypted_string;
+ qs("#signature-string").innerText = new Uint8Array(signed_message).toString();
+ qs("#results").innerHTML = results;
+}
+
+async function encryptString(string_d) {
+ return await window.crypto.subtle.encrypt({ name: "RSA-OAEP" }, public_key, new TextEncoder().encode(string_d));
+}
+async function decryptString(string_d) {
+ return new TextDecoder().decode(await window.crypto.subtle.decrypt({ name: "RSA-OAEP" }, private_key, string_d));
+}
+
+async function signMessage(string_d) {
+ return await window.crypto.subtle.sign({ name: "RSASSA-PKCS1-v1_5" }, private_signing_key, new TextEncoder().encode(string_d));
+}
+async function verifyMessage(string_d, signed_message) {
+ return await window.crypto.subtle.verify("RSASSA-PKCS1-v1_5", public_signing_key, signed_message, new TextEncoder().encode(string_d));
+}
+
+// This is just used to turn the data into string that can be read.
+// Ordinarily you won't need this, as the keys won't need to be visible in the way this website wants them to be.
+// (Hint, this is very bad! Do not do this!)
+async function _exportKey(key, method) {
+ const exported = await window.crypto.subtle.exportKey(method, key);
+ if (exported.e) return JSON.stringify(exported, null, 2);
+ return String.fromCharCode.apply(null, new Uint8Array(exported));
+}
diff --git a/index.scss b/index.scss
new file mode 100644
index 0000000..b20631b
--- /dev/null
+++ b/index.scss
@@ -0,0 +1,117 @@
+body {
+ margin: 0;
+ display: flex;
+ height: 100vh;
+ flex-direction: column;
+ background-color: #20242b;
+ font-family: Verdana, Geneva, Tahoma, sans-serif;
+}
+
+.page {
+ width: 1200px;
+ margin: 0 auto;
+ padding: 1rem 0;
+ box-sizing: border-box;
+ margin-bottom: 1rem;
+
+ .disclaimer {
+ font-size: 18px;
+ }
+
+ .data-area {
+ width: 100%;
+ min-height: 10px;
+ background-color: #0d0f11;
+ padding: 10px;
+ box-sizing: border-box;
+ border-radius: 10px;
+ margin-bottom: 1rem;
+ color: white;
+
+ .data-title {
+ font-size: 24px;
+ margin-bottom: 10px;
+ }
+
+ textarea {
+ resize: vertical;
+ width: 100%;
+ margin: 0;
+ box-sizing: border-box;
+ font-family: Verdana, Geneva, Tahoma, sans-serif;
+ border-radius: 5px;
+ }
+ }
+
+ .action-area {
+ display: flex;
+ flex-direction: row;
+ margin-bottom: 1rem;
+ width: 100%;
+ padding: 5px;
+ box-sizing: border-box;
+ background-color: #0d0f11;
+ border-radius: 10px;
+
+ button {
+ width: 130px;
+ height: 100%;
+ margin: auto;
+ }
+ }
+
+ .result-area {
+ display: flex;
+ flex-direction: row;
+ flex-flow: row wrap;
+ place-content: space-around;
+
+ .result {
+ min-width: 150px;
+ max-width: 49%;
+ flex-grow: 1;
+ min-height: 100px;
+ background-color: #0d0f11;
+ border-radius: 10px;
+ padding: 5px;
+ box-sizing: border-box;
+ color: gray;
+ margin-bottom: 10px;
+ word-wrap: anywhere;
+
+ .result-title {
+ font-size: 20px;
+ text-align: center;
+ text-decoration: underline;
+ color: white;
+ }
+ }
+ }
+}
+
+@media screen and (max-width: 1210px) {
+ .page {
+ width: 95%;
+ .result-area {
+ .result {
+ min-width: initial;
+ max-width: initial;
+ width: 45%;
+ margin: 5px;
+ }
+ }
+ }
+}
+
+@media screen and (max-width: 1010px) {
+ .page {
+ width: 95%;
+ .result-area {
+ .result {
+ min-width: initial;
+ max-width: initial;
+ width: 100%;
+ }
+ }
+ }
+}