blob: a7093a065268944e24c174eec545bfa514b2a78f [file] [log] [blame]
/**
* @license
* Copyright 2020 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/
import {Aead} from '../aead';
import {AeadConfig} from '../aead/aead_config';
import {SecurityException} from '../exception/security_exception';
import {PbAesCtrHmacAeadKey, PbAesCtrHmacAeadKeyFormat, PbAesGcmKey, PbAesGcmKeyFormat, PbKeyTemplate} from '../internal/proto';
import * as Registry from '../internal/registry';
import {EciesAeadHkdfDemHelper} from '../subtle/ecies_aead_hkdf_dem_helper';
/**
* @final
*/
export class RegistryEciesAeadHkdfDemHelper implements EciesAeadHkdfDemHelper {
private readonly key: PbAesCtrHmacAeadKey|PbAesGcmKey;
private readonly demKeyTypeUrl: string;
private readonly demKeySize: number;
private readonly aesCtrKeySize?: number;
constructor(keyTemplate: PbKeyTemplate) {
let demKeySize: number;
let aesCtrKeySize: number|undefined;
let keyFormat: PbAesCtrHmacAeadKeyFormat|PbAesGcmKeyFormat;
const keyTypeUrl = keyTemplate.getTypeUrl();
switch (keyTypeUrl) {
case AeadConfig.AES_CTR_HMAC_AEAD_TYPE_URL:
keyFormat =
RegistryEciesAeadHkdfDemHelper.getAesCtrHmacKeyFormat(keyTemplate);
const aesCtrKeyFormat = keyFormat.getAesCtrKeyFormat();
if (!aesCtrKeyFormat) {
throw new SecurityException('AES-CTR key format not set');
}
aesCtrKeySize = aesCtrKeyFormat.getKeySize();
const hmacKeyFormat = keyFormat.getHmacKeyFormat();
if (!hmacKeyFormat) {
throw new SecurityException('HMAC key format not set');
}
const hmacKeySize = hmacKeyFormat.getKeySize();
demKeySize = aesCtrKeySize + hmacKeySize;
break;
case AeadConfig.AES_GCM_TYPE_URL:
keyFormat =
RegistryEciesAeadHkdfDemHelper.getAesGcmKeyFormat(keyTemplate);
demKeySize = keyFormat.getKeySize();
break;
default:
throw new SecurityException(
'Key type URL ' + keyTypeUrl + ' is not supported.');
}
const keyFactory = Registry.getKeyManager(keyTypeUrl).getKeyFactory();
this.key =
(keyFactory.newKey(keyFormat) as PbAesCtrHmacAeadKey | PbAesGcmKey);
this.demKeyTypeUrl = keyTypeUrl;
this.demKeySize = demKeySize;
this.aesCtrKeySize = aesCtrKeySize;
}
/**
*/
getDemKeySizeInBytes() {
return this.demKeySize;
}
/**
*/
async getAead(demKey: Uint8Array): Promise<Aead> {
if (demKey.length !== this.demKeySize) {
throw new SecurityException(
`Key is not of the correct length, expected length: ${
this.demKeySize}, but got key of length: ${demKey.length}.`);
}
let key: PbAesCtrHmacAeadKey|PbAesGcmKey;
if (this.demKeyTypeUrl === AeadConfig.AES_CTR_HMAC_AEAD_TYPE_URL) {
key = this.replaceAesCtrHmacKeyValue(demKey);
} else {
key = this.replaceAesGcmKeyValue(demKey);
}
return Registry.getPrimitive<Aead>(Aead, key, this.demKeyTypeUrl);
}
private static getAesGcmKeyFormat(keyTemplate: PbKeyTemplate):
PbAesGcmKeyFormat {
let keyFormat: PbAesGcmKeyFormat;
try {
keyFormat =
PbAesGcmKeyFormat.deserializeBinary(keyTemplate.getValue_asU8());
} catch (e) {
throw new SecurityException(
'Could not parse the given Uint8Array as a serialized proto of ' +
AeadConfig.AES_GCM_TYPE_URL + '.');
}
if (!keyFormat.getKeySize()) {
throw new SecurityException(
'Could not parse the given Uint8Array as a serialized proto of ' +
AeadConfig.AES_GCM_TYPE_URL + '.');
}
return keyFormat;
}
private static getAesCtrHmacKeyFormat(keyTemplate: PbKeyTemplate):
PbAesCtrHmacAeadKeyFormat {
let keyFormat: PbAesCtrHmacAeadKeyFormat;
try {
keyFormat = PbAesCtrHmacAeadKeyFormat.deserializeBinary(
keyTemplate.getValue_asU8());
} catch (e) {
throw new SecurityException(
'Could not parse the given Uint8Array ' +
'as a serialized proto of ' + AeadConfig.AES_CTR_HMAC_AEAD_TYPE_URL +
'.');
}
if (!keyFormat.getAesCtrKeyFormat() || !keyFormat.getHmacKeyFormat()) {
throw new SecurityException(
'Could not parse the given Uint8Array as a serialized proto of ' +
AeadConfig.AES_CTR_HMAC_AEAD_TYPE_URL + '.');
}
return keyFormat;
}
private replaceAesGcmKeyValue(symmetricKey: Uint8Array): PbAesGcmKey {
if (!(this.key instanceof PbAesGcmKey)) {
throw new SecurityException('Key is not an AES-CTR key');
}
const key = this.key.setKeyValue(symmetricKey);
return key;
}
private replaceAesCtrHmacKeyValue(symmetricKey: Uint8Array):
PbAesCtrHmacAeadKey {
const key = (this.key as PbAesCtrHmacAeadKey);
const aesCtrKey = key.getAesCtrKey();
if (!aesCtrKey) {
throw new SecurityException('AES-CTR key not set');
}
const aesCtrKeyValue = symmetricKey.slice(0, this.aesCtrKeySize);
aesCtrKey.setKeyValue(aesCtrKeyValue);
const hmacKey = key.getHmacKey();
if (!hmacKey) {
throw new SecurityException('HMAC key not set');
}
const hmacKeyValue =
symmetricKey.slice(this.aesCtrKeySize, this.demKeySize);
hmacKey.setKeyValue(hmacKeyValue);
return key;
}
}