mirror of
https://github.com/bitwarden/browser
synced 2025-12-14 23:33:31 +00:00
[PM-3732] Use subtle to make aes keys (#6162)
* Provide `aesGenerateKey` to make aes keys * Use aesGenerateKey when generating a key data * Fix device test
This commit is contained in:
@@ -66,5 +66,14 @@ export abstract class CryptoFunctionService {
|
||||
) => Promise<Uint8Array>;
|
||||
rsaExtractPublicKey: (privateKey: Uint8Array) => Promise<Uint8Array>;
|
||||
rsaGenerateKeyPair: (length: 1024 | 2048 | 4096) => Promise<[Uint8Array, Uint8Array]>;
|
||||
/**
|
||||
* Generates a key of the given length suitable for use in AES encryption
|
||||
*/
|
||||
aesGenerateKey: (bitLength: 128 | 192 | 256 | 512) => Promise<CsprngArray>;
|
||||
/**
|
||||
* Generates a random array of bytes of the given length. Uses a cryptographically secure random number generator.
|
||||
*
|
||||
* Do not use this for generating encryption keys. Use aesGenerateKey or rsaGenerateKeyPair instead.
|
||||
*/
|
||||
randomBytes: (length: number) => Promise<CsprngArray>;
|
||||
}
|
||||
|
||||
@@ -119,7 +119,7 @@ export class CryptoService implements CryptoServiceAbstraction {
|
||||
throw new Error("No Master Key found.");
|
||||
}
|
||||
|
||||
const newUserKey = await this.cryptoFunctionService.randomBytes(64);
|
||||
const newUserKey = await this.cryptoFunctionService.aesGenerateKey(512);
|
||||
return this.buildProtectedSymmetricKey(masterKey, newUserKey);
|
||||
}
|
||||
|
||||
@@ -367,7 +367,7 @@ export class CryptoService implements CryptoServiceAbstraction {
|
||||
throw new Error("No key provided");
|
||||
}
|
||||
|
||||
const newSymKey = await this.cryptoFunctionService.randomBytes(64);
|
||||
const newSymKey = await this.cryptoFunctionService.aesGenerateKey(512);
|
||||
return this.buildProtectedSymmetricKey(key, newSymKey);
|
||||
}
|
||||
|
||||
@@ -458,7 +458,7 @@ export class CryptoService implements CryptoServiceAbstraction {
|
||||
}
|
||||
|
||||
async makeOrgKey<T extends OrgKey | ProviderKey>(): Promise<[EncString, T]> {
|
||||
const shareKey = await this.cryptoFunctionService.randomBytes(64);
|
||||
const shareKey = await this.cryptoFunctionService.aesGenerateKey(512);
|
||||
const publicKey = await this.getPublicKey();
|
||||
const encShareKey = await this.rsaEncrypt(shareKey, publicKey);
|
||||
return [encShareKey, new SymmetricCryptoKey(shareKey) as T];
|
||||
@@ -731,8 +731,8 @@ export class CryptoService implements CryptoServiceAbstraction {
|
||||
publicKey: string;
|
||||
privateKey: EncString;
|
||||
}> {
|
||||
const randomBytes = await this.cryptoFunctionService.randomBytes(64);
|
||||
const userKey = new SymmetricCryptoKey(randomBytes) as UserKey;
|
||||
const rawKey = await this.cryptoFunctionService.aesGenerateKey(512);
|
||||
const userKey = new SymmetricCryptoKey(rawKey) as UserKey;
|
||||
const [publicKey, privateKey] = await this.makeKeyPair(userKey);
|
||||
await this.setUserKey(userKey);
|
||||
await this.stateService.setEncryptedPrivateKey(privateKey.encryptedString);
|
||||
|
||||
@@ -354,6 +354,20 @@ describe("WebCrypto Function Service", () => {
|
||||
).toBeTruthy();
|
||||
});
|
||||
});
|
||||
|
||||
describe("aesGenerateKey", () => {
|
||||
it.each([128, 192, 256, 512])("Should make a key of %s bits long", async (length) => {
|
||||
const cryptoFunctionService = getWebCryptoFunctionService();
|
||||
const key = await cryptoFunctionService.aesGenerateKey(length);
|
||||
expect(key.byteLength * 8).toBe(length);
|
||||
});
|
||||
|
||||
it("should not repeat itself for 512 length special case", async () => {
|
||||
const cryptoFunctionService = getWebCryptoFunctionService();
|
||||
const key = await cryptoFunctionService.aesGenerateKey(512);
|
||||
expect(key.slice(0, 32)).not.toEqual(key.slice(32, 64));
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
function testPbkdf2(
|
||||
|
||||
@@ -347,6 +347,23 @@ export class WebCryptoFunctionService implements CryptoFunctionService {
|
||||
return new Uint8Array(buffer);
|
||||
}
|
||||
|
||||
async aesGenerateKey(bitLength = 128 | 192 | 256 | 512): Promise<CsprngArray> {
|
||||
if (bitLength === 512) {
|
||||
// 512 bit keys are not supported in WebCrypto, so we concat two 256 bit keys
|
||||
const key1 = await this.aesGenerateKey(256);
|
||||
const key2 = await this.aesGenerateKey(256);
|
||||
return new Uint8Array([...key1, ...key2]) as CsprngArray;
|
||||
}
|
||||
const aesParams = {
|
||||
name: "AES-CBC",
|
||||
length: bitLength,
|
||||
};
|
||||
|
||||
const key = await this.subtle.generateKey(aesParams, true, ["encrypt", "decrypt"]);
|
||||
const rawKey = await this.subtle.exportKey("raw", key);
|
||||
return new Uint8Array(rawKey) as CsprngArray;
|
||||
}
|
||||
|
||||
async rsaGenerateKeyPair(length: 1024 | 2048 | 4096): Promise<[Uint8Array, Uint8Array]> {
|
||||
const rsaParams = {
|
||||
name: "RSA-OAEP",
|
||||
@@ -355,10 +372,7 @@ export class WebCryptoFunctionService implements CryptoFunctionService {
|
||||
// Have to specify some algorithm
|
||||
hash: { name: this.toWebCryptoAlgorithm("sha1") },
|
||||
};
|
||||
const keyPair = (await this.subtle.generateKey(rsaParams, true, [
|
||||
"encrypt",
|
||||
"decrypt",
|
||||
])) as CryptoKeyPair;
|
||||
const keyPair = await this.subtle.generateKey(rsaParams, true, ["encrypt", "decrypt"]);
|
||||
const publicKey = await this.subtle.exportKey("spki", keyPair.publicKey);
|
||||
const privateKey = await this.subtle.exportKey("pkcs8", keyPair.privateKey);
|
||||
return [new Uint8Array(publicKey), new Uint8Array(privateKey)];
|
||||
|
||||
Reference in New Issue
Block a user