Skip to content

Commit ed02466

Browse files
author
Will Bamberg
committed
Add deriveBits examples
1 parent 2f4e902 commit ed02466

File tree

4 files changed

+255
-0
lines changed

4 files changed

+255
-0
lines changed

web-crypto/derive-bits/ecdh.js

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
(() => {
2+
3+
async function deriveSharedSecret(privateKey, publicKey) {
4+
const sharedSecret = await window.crypto.subtle.deriveBits(
5+
{
6+
name: "ECDH",
7+
namedCurve: "P-384",
8+
public: publicKey
9+
},
10+
privateKey,
11+
128
12+
);
13+
14+
const buffer = new Uint8Array(sharedSecret, 0, 5);
15+
const sharedSecretValue = document.querySelector(".ecdh .derived-bits-value");
16+
sharedSecretValue.classList.add("fade-in");
17+
sharedSecretValue.addEventListener("animationend", () => {
18+
sharedSecretValue.classList.remove("fade-in");
19+
});
20+
sharedSecretValue.textContent = `${buffer}...[${sharedSecret.byteLength} bytes total]`;
21+
}
22+
23+
// Generate 2 ECDH key pairs: one for Alice and one for Bob
24+
// In more normal usage, they would generate their key pairs
25+
// separately and exchange public keys securely
26+
const generateAlicesKeyPair = window.crypto.subtle.generateKey(
27+
{
28+
name: "ECDH",
29+
namedCurve: "P-384"
30+
},
31+
false,
32+
["deriveBits"]
33+
);
34+
35+
const generateBobsKeyPair = window.crypto.subtle.generateKey(
36+
{
37+
name: "ECDH",
38+
namedCurve: "P-384"
39+
},
40+
false,
41+
["deriveBits"]
42+
);
43+
44+
Promise.all([generateAlicesKeyPair, generateBobsKeyPair]).then(values => {
45+
const alicesKeyPair = values[0];
46+
const bobsKeyPair = values[1];
47+
48+
const deriveBitsButton = document.querySelector(".ecdh .derive-bits-button");
49+
deriveBitsButton.addEventListener("click", () => {
50+
// Alice then generates a secret using her private key and Bob's public key.
51+
// Bob could generate the same secret using his private key and Alice's public key.
52+
deriveSharedSecret(alicesKeyPair.privateKey, bobsKeyPair.publicKey);
53+
});
54+
});
55+
56+
})();

web-crypto/derive-bits/index.html

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
<!DOCTYPE html>
2+
<html>
3+
<head>
4+
<meta charset="utf-8">
5+
<title>Web Crypto API example</title>
6+
<link rel="stylesheet" href="style.css">
7+
</head>
8+
9+
<body>
10+
<main>
11+
<h1>Web Crypto: deriveBits</h1>
12+
13+
<section class="description">
14+
<p>This page shows how to use the <code>deriveBits()</code> function of the <a href="https://developer.mozilla.org/en-US/docs/Web/API/Web_Crypto_API">Web Crypto API</a>. It contains two separate examples, one for PBKDF2 and one for ECDH.</p>
15+
16+
<p>It's important to note that although both are defined in the API as key derivation functions, PBKDF2 and ECDH have very different use cases and characteristics.</p>
17+
18+
<hr/>
19+
<h2>PBKDF2 example</h2>
20+
<p>The PBKDF2 algorithm is used here to derive some bits from a password.</p>
21+
<p>When you click "Derive bits" the example prompts you for a password and then derives some bits from the password using PBKDF2, and a representation of the derived bits is displayed.</p>
22+
23+
<hr/>
24+
<h2>ECDH example</h2>
25+
<p>The ECDH algorithm is more commonly called a "key agreement" algorithm. It enables two parties (conventionally called "Alice" and "Bob"), each of whom has a public/private key pair, to establish a shared secret key.</p>
26+
<p>With this example we've created two ECDH key pairs, one for Alice and one for Bob.</p>
27+
<p>When you click "Derive bits" the example uses Alice's private key and Bob's public key to derive a shared secret, and a representation of the shared secret is displayed.</p>
28+
29+
</section>
30+
31+
<section class="examples">
32+
33+
<section class="derive-bits pbkdf2">
34+
<h2>PBKDF2</h2>
35+
<section class="derive-bits-controls">
36+
<div class="derived-bits">Derived bits:<span class="derived-bits-value"></span></div>
37+
<input class="derive-bits-button" type="button" value="Derive bits">
38+
</section>
39+
</section>
40+
41+
<section class="derive-bits ecdh">
42+
<h2>ECDH</h2>
43+
<section class="derive-bits-controls">
44+
<div class="derived-bits">Shared secret:<span class="derived-bits-value"></span></div>
45+
<input class="derive-bits-button" type="button" value="Derive bits">
46+
</section>
47+
</section>
48+
49+
</section>
50+
</main>
51+
52+
</body>
53+
<script src="pbkdf2.js"></script>
54+
<script src="ecdh.js"></script>
55+
</html>

web-crypto/derive-bits/pbkdf2.js

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
(() => {
2+
3+
let salt;
4+
5+
/*
6+
Get some key material to use as input to the deriveBits method.
7+
The key material is a password supplied by the user.
8+
*/
9+
function getKeyMaterial() {
10+
const password = window.prompt("Enter your password");
11+
const enc = new TextEncoder();
12+
return window.crypto.subtle.importKey(
13+
"raw",
14+
enc.encode(password),
15+
{name: "PBKDF2"},
16+
false,
17+
["deriveBits", "deriveKey"]
18+
);
19+
}
20+
21+
/*
22+
Derive some bits from a password supplied by the user.
23+
*/
24+
async function getDerivedBits() {
25+
const keyMaterial = await getKeyMaterial();
26+
salt = window.crypto.getRandomValues(new Uint8Array(16));
27+
const derivedBits = await window.crypto.subtle.deriveBits(
28+
{
29+
"name": "PBKDF2",
30+
salt: salt,
31+
"iterations": 100000,
32+
"hash": "SHA-256"
33+
},
34+
keyMaterial,
35+
256
36+
);
37+
38+
const buffer = new Uint8Array(derivedBits, 0, 5);
39+
const derivedBitsValue = document.querySelector(".pbkdf2 .derived-bits-value");
40+
derivedBitsValue.classList.add("fade-in");
41+
derivedBitsValue.addEventListener("animationend", () => {
42+
derivedBitsValue.classList.remove("fade-in");
43+
});
44+
derivedBitsValue.textContent = `${buffer}...[${derivedBits.byteLength} bytes total]`;
45+
}
46+
47+
const deriveBitsButton = document.querySelector(".pbkdf2 .derive-bits-button");
48+
deriveBitsButton.addEventListener("click", () => {
49+
getDerivedBits();
50+
});
51+
})();

web-crypto/derive-bits/style.css

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
/* General setup */
2+
3+
* {
4+
box-sizing: border-box;
5+
}
6+
7+
html,body {
8+
font-family: sans-serif;
9+
line-height: 1.2rem;
10+
}
11+
12+
/* Layout and styles */
13+
14+
h1 {
15+
color: green;
16+
margin-left: .5rem;
17+
}
18+
19+
.description, .derive-bits {
20+
margin: 0 .5rem;
21+
}
22+
23+
.description > p {
24+
margin-top: 0;
25+
}
26+
27+
.derive-bits {
28+
box-shadow: -1px 2px 5px gray;
29+
padding: .5rem;
30+
margin-bottom: 2rem;
31+
}
32+
33+
input[type="button"] {
34+
width: 5rem;
35+
}
36+
37+
.derived-bits-value {
38+
padding-left: .5rem;
39+
font-family: monospace;
40+
}
41+
42+
/* Whole page grid */
43+
main {
44+
display: grid;
45+
grid-template-columns: 40rem 1fr;
46+
grid-template-rows: 4rem 1fr;
47+
}
48+
49+
h1 {
50+
grid-column: 1/2;
51+
grid-row: 1;
52+
}
53+
54+
.examples {
55+
grid-column: 1;
56+
grid-row: 2;
57+
}
58+
59+
.description {
60+
grid-column: 2;
61+
grid-row: 2;
62+
}
63+
64+
/* derive-bits controls grid */
65+
.derive-bits-controls {
66+
display: grid;
67+
grid-template-columns: 1fr 5rem;
68+
grid-template-rows: 1fr;
69+
}
70+
71+
.derived-bits {
72+
grid-column-start: 1;
73+
grid-row-start: 1;
74+
}
75+
76+
.derive-bits-button {
77+
grid-column-start: 2;
78+
grid-row-start: 1;
79+
}
80+
81+
/* Animate output display */
82+
.fade-in {
83+
animation: fadein .5s;
84+
}
85+
86+
@keyframes fadein {
87+
from {
88+
opacity: 0;
89+
}
90+
to {
91+
opacity: 1;
92+
}
93+
}

0 commit comments

Comments
 (0)