modules/material-management/src/keyring.ts (56 lines of code) (raw):

// Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 import { EncryptedDataKey } from './encrypted_data_key' import { immutableBaseClass, immutableClass } from './immutable_class' import { isEncryptionMaterial, isDecryptionMaterial, } from './cryptographic_material' import { EncryptionMaterial, DecryptionMaterial, SupportedAlgorithmSuites, } from './types' import { needs } from './needs' import { NodeAlgorithmSuite } from './node_algorithms' import { WebCryptoAlgorithmSuite } from './web_crypto_algorithms' /* * This public interface to the Keyring object is provided for * developers of CMMs and keyrings only. If you are a user of the AWS Encryption * SDK and you are not developing your own CMMs and/or keyrings, you do not * need to use it and you should not do so. */ export abstract class Keyring<S extends SupportedAlgorithmSuites> { async onEncrypt( material: EncryptionMaterial<S> ): Promise<EncryptionMaterial<S>> { /* Precondition: material must be a type of isEncryptionMaterial. * There are several security properties that NodeEncryptionMaterial and WebCryptoEncryptionMaterial * posses. * The unencryptedDataKey can only be written once. * If a data key has not already been generated, there must be no EDKs. * See cryptographic_materials.ts */ needs(isEncryptionMaterial(material), 'Unsupported type of material.') const _material = await this._onEncrypt(material) /* Postcondition: The EncryptionMaterial objects must be the same. * See cryptographic_materials.ts. The CryptographicMaterial objects * provide several security properties, including immutability of * the unencrypted data key and the ability to zero the data key. * This is insured by returning the same material. */ needs( material === _material, 'New EncryptionMaterial instances can not be created.' ) /* Postcondition UNTESTED: If this keyring generated data key, it must be the right length. * See cryptographic_materials.ts This is handled in setUnencryptedDataKey * this condition is listed here to keep help keep track of important conditions */ return material } abstract _onEncrypt( material: EncryptionMaterial<S> ): Promise<EncryptionMaterial<S>> /* NOTE: The order of EDK's passed to the onDecrypt function is a clear * intent on the part of the person who did the encryption. * The EDK's should always correspond to the order serialized. * It is the Keyrings responsibility to maintain this order. * The most clear example is from KMS. KMS is a regional service. * This means that a call to decrypt an EDK must go to the * region that "owns" this EDK. If the decryption is done * in a different region. To control this behavior the person * who called encrypt can control the order of EDK and in the * configuration of the KMS Keyring. */ async onDecrypt( material: DecryptionMaterial<S>, encryptedDataKeys: EncryptedDataKey[] ): Promise<DecryptionMaterial<S>> { /* Precondition: material must be DecryptionMaterial. */ needs(isDecryptionMaterial(material), 'Unsupported material type.') /* Precondition: Attempt to decrypt iif material does not have an unencrypted data key. */ if (material.hasValidKey()) return material /* Precondition: encryptedDataKeys must all be EncryptedDataKey. */ needs( encryptedDataKeys.every((edk) => edk instanceof EncryptedDataKey), 'Unsupported EncryptedDataKey type' ) const _material = await this._onDecrypt(material, encryptedDataKeys) /* Postcondition: The DecryptionMaterial objects must be the same. * See cryptographic_materials.ts. The CryptographicMaterial objects * provide several security properties, including immutability of * the unencrypted data key and the ability to zero the data key. * This is insured by returning the same material. */ needs( material === _material, 'New DecryptionMaterial instances can not be created.' ) /* See cryptographic_materials.ts The length condition is handled there. * But the condition is important and so repeated here. * The postcondition is "If an EDK was decrypted, its length must agree with algorithm specification." * If this is not the case, it either means ciphertext was tampered * with or the keyring implementation is not setting the length properly. */ return material } abstract _onDecrypt( material: DecryptionMaterial<S>, encryptedDataKeys: EncryptedDataKey[] ): Promise<DecryptionMaterial<S>> } immutableBaseClass(Keyring) export abstract class KeyringNode extends Keyring<NodeAlgorithmSuite> {} immutableClass(KeyringNode) export abstract class KeyringWebCrypto extends Keyring<WebCryptoAlgorithmSuite> {} immutableClass(KeyringWebCrypto)