import { KeyringNode , needs , NodeEncryptionMaterial , NodeDecryptionMaterial , EncryptedDataKey , KeyringTraceFlag , immutableClass , readOnlyProperty , unwrapDataKey , NodeAlgorithmSuite , } from '@aws-crypto/material-management-node' ; import { randomBytes , createCipheriv , createDecipheriv } from 'crypto' ; import { serializeFactory , concatBuffers } from '@aws-crypto/serialize' ; import { _onEncrypt , _onDecrypt , NodeRawAesMaterial , rawAesEncryptedDataKeyFactory , rawAesEncryptedPartsFactory , WrappingSuiteIdentifier , WrapKey , UnwrapKey , } from '@aws-crypto/raw-keyring' ; const fromUtf8 = ( input ) => Buffer . from ( input , 'utf8' ) ; const toUtf8 = ( input ) => Buffer . from ( input . buffer , input . byteOffset , input . byteLength ) . toString ( 'utf8' ) ; const { serializeEncryptionContext } = serializeFactory ( fromUtf8 ) ; const { rawAesEncryptedDataKey } = rawAesEncryptedDataKeyFactory ( toUtf8 , fromUtf8 ) ; const { rawAesEncryptedParts } = rawAesEncryptedPartsFactory ( fromUtf8 ) ; export type RawAesKeyringNodeInput = { keyNamespace : string ; keyName : string ; unencryptedMasterKey : Uint8Array ; wrappingSuite : WrappingSuiteIdentifier ; } ; export class RawAesKeyringNode extends KeyringNode { public declare keyNamespace : string ; public declare keyName : string ; declare _wrapKey : WrapKey < NodeAlgorithmSuite > ; declare _unwrapKey : UnwrapKey < NodeAlgorithmSuite > ; constructor ( input ) { super ( ) ; const { keyName , keyNamespace , unencryptedMasterKey , wrappingSuite } = input ; needs ( keyName && keyNamespace , 'Identifying information must be defined.' ) ; const wrappingMaterial = new NodeRawAesMaterial ( wrappingSuite ) . setUnencryptedDataKey ( unencryptedMasterKey , { keyNamespace , keyName , flags : KeyringTraceFlag . WRAPPING_KEY_GENERATED_DATA_KEY , } ) ; const _wrapKey = async ( material ) => { const { buffer , byteOffset , byteLength } = serializeEncryptionContext ( material . encryptionContext ) . slice ( 2 ) ; const aad = Buffer . from ( buffer , byteOffset , byteLength ) ; const { keyNamespace , keyName } = this ; return aesGcmWrapKey ( keyNamespace , keyName , material , aad , wrappingMaterial ) ; } ; const _unwrapKey = async ( material , edk ) => { const { keyNamespace , keyName } = this ; const { buffer , byteOffset , byteLength } = serializeEncryptionContext ( material . encryptionContext ) . slice ( 2 ) ; const aad = Buffer . from ( buffer , byteOffset , byteLength ) ; return aesGcmUnwrapKey ( keyNamespace , keyName , material , wrappingMaterial , edk , aad ) ; } ; readOnlyProperty ( this , 'keyName' , keyName ) ; readOnlyProperty ( this , 'keyNamespace' , keyNamespace ) ; readOnlyProperty ( this , '_wrapKey' , _wrapKey ) ; readOnlyProperty ( this , '_unwrapKey' , _unwrapKey ) ; } _filter ( { providerId , providerInfo } ) { const { keyNamespace , keyName } = this ; return providerId === keyNamespace && providerInfo . startsWith ( keyName ) ; } _onEncrypt = _onEncrypt < NodeAlgorithmSuite , RawAesKeyringNode > ( randomBytesAsync ) ; _onDecrypt = _onDecrypt < NodeAlgorithmSuite , RawAesKeyringNode > ( ) ; } immutableClass ( RawAesKeyringNode ) ; const encryptFlags = KeyringTraceFlag . WRAPPING_KEY_ENCRYPTED_DATA_KEY | KeyringTraceFlag . WRAPPING_KEY_SIGNED_ENC_CTX ; const decryptFlags = KeyringTraceFlag . WRAPPING_KEY_DECRYPTED_DATA_KEY | KeyringTraceFlag . WRAPPING_KEY_VERIFIED_ENC_CTX ; param keyNamespace param keyName param material param aad param wrappingMaterial returns function aesGcmWrapKey ( keyNamespace , keyName , material , aad , wrappingMaterial ) { const { encryption , ivLength } = wrappingMaterial . suite ; const iv = randomBytes ( ivLength ) ; const wrappingDataKey = wrappingMaterial . getUnencryptedDataKey ( ) ; const dataKey = unwrapDataKey ( material . getUnencryptedDataKey ( ) ) ; const cipher = createCipheriv ( encryption , wrappingDataKey , iv ) . setAAD ( aad ) ; const ciphertext = concatBuffers ( cipher . update ( dataKey ) , cipher . final ( ) ) ; const authTag = cipher . getAuthTag ( ) ; const edk = rawAesEncryptedDataKey ( keyNamespace , keyName , iv , ciphertext , authTag ) ; return material . addEncryptedDataKey ( edk , encryptFlags ) ; } param keyNamespace param keyName param material param wrappingMaterial param edk param aad returns function aesGcmUnwrapKey ( keyNamespace , keyName , material , wrappingMaterial , edk , aad ) { const { authTag , ciphertext , iv } = rawAesEncryptedParts ( material . suite , keyName , edk ) ; const { encryption } = wrappingMaterial . suite ; const decipher = createDecipheriv ( encryption , wrappingMaterial . getUnencryptedDataKey ( ) as any , iv ) . setAAD ( aad ) . setAuthTag ( authTag ) ; const unencryptedDataKey = concatBuffers ( decipher . update ( ciphertext ) , decipher . final ( ) ) ; const trace = { keyNamespace , keyName , flags : decryptFlags } ; return material . setUnencryptedDataKey ( unencryptedDataKey , trace ) ; } async function randomBytesAsync ( size ) { return new Promise ( ( resolve , reject ) => { randomBytes ( size , ( err , buffer ) => { if ( err ) return reject ( err ) ; resolve ( buffer ) ; } ) ; } ) ; }