Page Menu
Home
Phorge
Search
Configure Global Search
Log In
Files
F32399735
D8602.1765340110.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Flag For Later
Award Token
Size
10 KB
Referenced Files
None
Subscribers
None
D8602.1765340110.diff
View Options
diff --git a/web/account/qr-code-login.react.js b/web/account/qr-code-login.react.js
--- a/web/account/qr-code-login.react.js
+++ b/web/account/qr-code-login.react.js
@@ -4,10 +4,10 @@
import * as React from 'react';
import { qrCodeLinkURL } from 'lib/facts/links.js';
+import { generateKeyCommon } from 'lib/media/aes-crypto-utils-common.js';
import { uintArrayToHexString } from 'lib/media/data-utils.js';
import css from './qr-code-login.css';
-import { generateKey } from '../media/aes-crypto-utils.js';
import { useSelector } from '../redux/redux-utils.js';
function QrCodeLogin(): React.Node {
@@ -22,7 +22,7 @@
return;
}
- const rawAESKey: Uint8Array = await generateKey();
+ const rawAESKey: Uint8Array = await generateKeyCommon(crypto);
const aesKeyAsHexString: string = uintArrayToHexString(rawAESKey);
const url = qrCodeLinkURL(aesKeyAsHexString, ed25519Key);
diff --git a/web/media/aes-crypto-utils.js b/web/media/aes-crypto-utils.js
deleted file mode 100644
--- a/web/media/aes-crypto-utils.js
+++ /dev/null
@@ -1,74 +0,0 @@
-// @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 };
diff --git a/web/media/aes-crypto-utils.test.js b/web/media/aes-crypto-utils.test.js
--- a/web/media/aes-crypto-utils.test.js
+++ b/web/media/aes-crypto-utils.test.js
@@ -1,6 +1,10 @@
// @flow
-import { generateKey, encrypt, decrypt } from './aes-crypto-utils.js';
+import {
+ generateKeyCommon,
+ encryptCommon,
+ decryptCommon,
+} from 'lib/media/aes-crypto-utils-common.js';
// some mock data
const testPlaintext = new Uint8Array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]);
@@ -20,69 +24,77 @@
describe('generateKey', () => {
it('generates 32-byte AES key', async () => {
- const key = await generateKey();
+ const key = await generateKeyCommon(crypto);
expect(key.length).toBe(32);
});
});
describe('encrypt', () => {
it('generates ciphertext with IV and tag included', async () => {
- const encrypted = await encrypt(testEncryptionKey, testPlaintext);
+ const encrypted = await encryptCommon(
+ crypto,
+ testEncryptionKey,
+ testPlaintext,
+ );
// IV and tag are randomly generated, so we can't check the exact value
// IV + plaintext + tag = 12 + 11 + 16 = 39
expect(encrypted.length).toBe(testPlaintext.length + 12 + 16);
});
it('is decryptable by decrypt()', async () => {
- const key = await generateKey();
- const encrypted = await encrypt(key, randomData);
- const decrypted = await decrypt(key, encrypted);
+ const key = await generateKeyCommon(crypto);
+ const encrypted = await encryptCommon(crypto, key, randomData);
+ const decrypted = await decryptCommon(crypto, key, encrypted);
expect(decrypted).toEqual(randomData);
});
});
describe('decrypt', () => {
it('decrypts ciphertext', async () => {
- const decrypted = await decrypt(testEncryptionKey, testSealedData);
+ const decrypted = await decryptCommon(
+ crypto,
+ testEncryptionKey,
+ testSealedData,
+ );
expect(decrypted).toEqual(testPlaintext);
});
it('fails with wrong key', async () => {
- const key = await generateKey();
- const encrypted = await encrypt(key, randomData);
+ const key = await generateKeyCommon(crypto);
+ const encrypted = await encryptCommon(crypto, key, randomData);
- const wrongKey = await generateKey();
- await expect(decrypt(wrongKey, encrypted)).rejects.toThrow();
+ const wrongKey = await generateKeyCommon(crypto);
+ await expect(decryptCommon(crypto, wrongKey, encrypted)).rejects.toThrow();
});
it('fails with wrong ciphertext', async () => {
- const key = await generateKey();
- const encrypted = await encrypt(key, randomData);
+ const key = await generateKeyCommon(crypto);
+ const encrypted = await encryptCommon(crypto, key, randomData);
// change the first byte of the ciphertext (it's 13th byte in the buffer)
// first 12 bytes are IV, so changing the first byte of the ciphertext
encrypted[12] = encrypted[12] ^ 1;
- await expect(decrypt(key, encrypted)).rejects.toThrow();
+ await expect(decryptCommon(crypto, key, encrypted)).rejects.toThrow();
});
it('fails with wrong IV', async () => {
- const key = await generateKey();
- const encrypted = await encrypt(key, randomData);
+ const key = await generateKeyCommon(crypto);
+ const encrypted = await encryptCommon(crypto, key, randomData);
// change the first byte of the IV (it's 1st byte in the buffer)
encrypted[0] = encrypted[0] ^ 1;
- await expect(decrypt(key, encrypted)).rejects.toThrow();
+ await expect(decryptCommon(crypto, key, encrypted)).rejects.toThrow();
});
it('fails with wrong tag', async () => {
- const key = await generateKey();
- const encrypted = await encrypt(key, randomData);
+ const key = await generateKeyCommon(crypto);
+ const encrypted = await encryptCommon(crypto, key, randomData);
// change the last byte of the tag (tag is the last 16 bytes of the buffer)
encrypted[encrypted.length - 1] = encrypted[encrypted.length - 1] ^ 1;
- await expect(decrypt(key, encrypted)).rejects.toThrow();
+ await expect(decryptCommon(crypto, key, encrypted)).rejects.toThrow();
});
});
diff --git a/web/media/encryption-utils.js b/web/media/encryption-utils.js
--- a/web/media/encryption-utils.js
+++ b/web/media/encryption-utils.js
@@ -3,6 +3,7 @@
import invariant from 'invariant';
import { thumbHashToDataURL } from 'thumbhash';
+import * as AES from 'lib/media/aes-crypto-utils-common.js';
import { hexToUintArray, uintArrayToHexString } from 'lib/media/data-utils.js';
import { fileInfoFromData } from 'lib/media/file-utils.js';
import { fetchableMediaURI } from 'lib/media/media-utils.js';
@@ -13,7 +14,6 @@
import { getMessageForException } from 'lib/utils/errors.js';
import { calculatePaddedLength, pad, unpad } from 'lib/utils/pkcs7-padding.js';
-import * as AES from './aes-crypto-utils.js';
import { base64DecodeBuffer } from '../utils/base64-utils.js';
const PADDING_THRESHOLD = 5000000; // 5MB
@@ -61,8 +61,8 @@
let key, encryptedData, sha256;
try {
const plaintextData = shouldPad ? pad(data) : data;
- key = await AES.generateKey();
- encryptedData = await AES.encrypt(key, plaintextData);
+ key = await AES.generateKeyCommon(crypto);
+ encryptedData = await AES.encryptCommon(crypto, key, plaintextData);
const hashBytes = await crypto.subtle.digest('SHA-256', encryptedData);
sha256 = btoa(String.fromCharCode(...new Uint8Array(hashBytes)));
@@ -182,7 +182,7 @@
const decryptStartTime = Date.now();
try {
const keyBytes = hexToUintArray(encryptionKey);
- const plaintext = await AES.decrypt(keyBytes, data);
+ const plaintext = await AES.decryptCommon(crypto, keyBytes, data);
decryptedData =
plaintext.byteLength > PADDING_THRESHOLD ? plaintext : unpad(plaintext);
} catch (e) {
@@ -243,7 +243,8 @@
keyHex: string,
): Promise<string> {
const encryptedData = base64DecodeBuffer(encryptedThumbHash);
- const thumbhashBytes = await AES.decrypt(
+ const thumbhashBytes = await AES.decryptCommon(
+ crypto,
hexToUintArray(keyHex),
encryptedData,
);
diff --git a/web/media/image-utils.js b/web/media/image-utils.js
--- a/web/media/image-utils.js
+++ b/web/media/image-utils.js
@@ -3,6 +3,7 @@
import EXIF from 'exif-js';
import { rgbaToThumbHash } from 'thumbhash';
+import * as AES from 'lib/media/aes-crypto-utils-common.js';
import { hexToUintArray } from 'lib/media/data-utils.js';
import type {
GetOrientationMediaMissionStep,
@@ -11,7 +12,6 @@
} from 'lib/types/media-types.js';
import { getMessageForException } from 'lib/utils/errors.js';
-import * as AES from './aes-crypto-utils.js';
import { preloadImage } from './media-utils.js';
import { base64EncodeBuffer } from '../utils/base64-utils.js';
@@ -103,7 +103,8 @@
if (encryptionKey) {
try {
- const encryptedThumbHash = await AES.encrypt(
+ const encryptedThumbHash = await AES.encryptCommon(
+ crypto,
hexToUintArray(encryptionKey),
binaryThumbHash,
);
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Wed, Dec 10, 4:15 AM (17 h, 59 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
5859993
Default Alt Text
D8602.1765340110.diff (10 KB)
Attached To
Mode
D8602: Remove aes-crypto-utils.js from media and use common API to avoid redundent layer of abstraction
Attached
Detach File
Event Timeline
Log In to Comment