Page MenuHomePhabricator

D7024.diff
No OneTemporary

D7024.diff

diff --git a/web/media/aes-crypto-utils.js b/web/media/aes-crypto-utils.js
new file mode 100644
--- /dev/null
+++ b/web/media/aes-crypto-utils.js
@@ -0,0 +1,74 @@
+// @flow
+
+const KEY_SIZE = 32; // bytes
+const IV_LENGTH = 12; // bytes - unique Initialization Vector (nonce)
+const TAG_LENGTH = 16; // bytes - GCM auth tag
+
+async function generateKey(): Promise<Uint8Array> {
+ const algorithm = { name: 'AES-GCM', length: 256 };
+ const key = await crypto.subtle.generateKey(algorithm, true, [
+ 'encrypt',
+ 'decrypt',
+ ]);
+ const keyData = await crypto.subtle.exportKey('raw', key);
+ return new Uint8Array(keyData);
+}
+
+async function encrypt(
+ keyBytes: Uint8Array,
+ plaintext: Uint8Array,
+): Promise<Uint8Array> {
+ if (keyBytes.length !== KEY_SIZE) {
+ throw new Error('Invalid AES key size');
+ }
+
+ // we're creating the buffer now so we can avoid reallocating it later
+ const outputBuffer = new ArrayBuffer(
+ plaintext.length + IV_LENGTH + TAG_LENGTH,
+ );
+ const ivBytes = new Uint8Array(outputBuffer, 0, IV_LENGTH);
+ const iv = crypto.getRandomValues(ivBytes);
+
+ const algorithm = { name: 'AES-GCM', iv: iv, tagLength: TAG_LENGTH * 8 };
+ const key = await crypto.subtle.importKey('raw', keyBytes, 'AES-GCM', false, [
+ 'encrypt',
+ ]);
+ const ciphertextWithTag = await crypto.subtle.encrypt(
+ algorithm,
+ key,
+ plaintext,
+ );
+
+ const result = new Uint8Array(outputBuffer);
+ result.set(new Uint8Array(ciphertextWithTag), iv.length);
+ return result;
+}
+
+async function decrypt(
+ keyBytes: Uint8Array,
+ sealedData: Uint8Array,
+): Promise<Uint8Array> {
+ if (keyBytes.length !== KEY_SIZE) {
+ throw new Error('Invalid AES key size');
+ }
+ if (sealedData.length < IV_LENGTH + TAG_LENGTH) {
+ throw new Error('Invalid ciphertext size');
+ }
+
+ const iv = sealedData.subarray(0, IV_LENGTH);
+ const ciphertextWithTag = sealedData.subarray(IV_LENGTH);
+
+ const algorithm = { name: 'AES-GCM', iv, tagLength: TAG_LENGTH * 8 };
+ const key = await crypto.subtle.importKey('raw', keyBytes, 'AES-GCM', false, [
+ 'decrypt',
+ ]);
+
+ const plaintextBuffer = await crypto.subtle.decrypt(
+ algorithm,
+ key,
+ ciphertextWithTag,
+ );
+ return new Uint8Array(plaintextBuffer);
+}
+
+export { generateKey, encrypt, decrypt };

File Metadata

Mime Type
text/plain
Expires
Sun, Nov 24, 7:12 AM (20 h, 59 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
2574455
Default Alt Text
D7024.diff (2 KB)

Event Timeline