import { KeyringWebCrypto , needs , WebCryptoEncryptionMaterial , WebCryptoDecryptionMaterial , EncryptedDataKey , KeyringTrace , KeyringTraceFlag , immutableClass , readOnlyProperty , bytes2JWK , keyUsageForMaterial , importForWebCryptoEncryptionMaterial , unwrapDataKey , MixedBackendCryptoKey , WebCryptoAlgorithmSuite , AwsEsdkJsCryptoKey , } from '@aws-crypto/material-management-browser' ; import { getWebCryptoBackend , getNonZeroByteBackend , isFullSupportWebCryptoBackend , } from '@aws-crypto/web-crypto-backend' ; import { _onEncrypt , _onDecrypt , WrapKey , UnwrapKey , } from '@aws-crypto/raw-keyring' ; import { randomValuesOnly } from '@aws-crypto/random-source-browser' ; import { RawRsaKeyringWebCryptoInput , RsaImportableKey } from './types' ; import { getImportOptions , getWrappingAlgorithm , flattenMixedCryptoKey , } from './get_import_options' ; export class RawRsaKeyringWebCrypto extends KeyringWebCrypto { public declare keyNamespace : string ; public declare keyName : string ; declare _wrapKey : WrapKey < WebCryptoAlgorithmSuite > ; declare _unwrapKey : UnwrapKey < WebCryptoAlgorithmSuite > ; constructor ( input ) { super ( ) ; const { publicKey , privateKey , keyName , keyNamespace } = input ; needs ( publicKey || privateKey , 'No Key provided.' ) ; needs ( keyName && keyNamespace , 'Identifying information must be defined.' ) ; const wrappingAlgorithm = getWrappingAlgorithm ( publicKey , privateKey ) ; const _wrapKey = async ( material ) => { if ( ! publicKey ) throw new Error ( 'No publicKey configured, encrypt not supported.' ) ; const subtle = getNonZeroByteBackend ( await getWebCryptoBackend ( ) ) ; const extractable = true ; const { encryption } = material . suite ; const importFormat = 'jwk' ; const keyUsages = [ 'wrapKey' ] ; const jwk = bytes2JWK ( unwrapDataKey ( material . getUnencryptedDataKey ( ) ) ) ; const cryptoKey = await subtle . importKey ( importFormat , jwk , encryption , extractable , keyUsages ) ; const wrapFormat = 'raw' ; const encryptedArrayBuffer = await subtle . wrapKey ( wrapFormat , cryptoKey , publicKey , wrappingAlgorithm ) ; const edk = new EncryptedDataKey ( { providerId : keyNamespace , providerInfo : keyName , encryptedDataKey : new Uint8Array ( encryptedArrayBuffer ) , } ) ; return material . addEncryptedDataKey ( edk , KeyringTraceFlag . WRAPPING_KEY_ENCRYPTED_DATA_KEY ) ; } ; const privateKeys = flattenMixedCryptoKey ( privateKey ) ; const _unwrapKey = async ( material , edk ) => { if ( ! privateKey ) throw new Error ( 'No privateKey configured, decrypt not supported.' ) ; const backend = await getWebCryptoBackend ( ) ; const { suite } = material ; const trace = { keyName : this . keyName , keyNamespace : this . keyNamespace , flags : KeyringTraceFlag . WRAPPING_KEY_DECRYPTED_DATA_KEY , } ; const format = 'raw' ; const extractable = false ; const algorithm = suite . kdf ? suite . kdf : suite . encryption ; const keyUsages = [ keyUsageForMaterial ( material ) ] ; const importArgs = [ format , edk . encryptedDataKey , privateKeys [ 0 ] , wrappingAlgorithm , algorithm , extractable , keyUsages , ] ; if ( isFullSupportWebCryptoBackend ( backend ) ) { const cryptoKey = await backend . subtle . unwrapKey ( ... importArgs ) ; return material . setCryptoKey ( cryptoKey , trace ) ; } else { const importZeroBackend = [ ... importArgs ] as Parameters < SubtleCrypto [ 'unwrapKey' ] > ; importZeroBackend [ 2 ] = privateKeys [ 1 ] ; const mixedDataKey = await Promise . all ( [ backend . nonZeroByteSubtle . unwrapKey ( ... importArgs ) , backend . zeroByteSubtle . unwrapKey ( ... importZeroBackend ) , ] ) . then ( ( [ nonZeroByteCryptoKey , zeroByteCryptoKey ] ) => ( { nonZeroByteCryptoKey , zeroByteCryptoKey , } ) ) ; return material . setCryptoKey ( mixedDataKey , trace ) ; } } ; 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 ) ; } _rawOnEncrypt = _onEncrypt < WebCryptoAlgorithmSuite , RawRsaKeyringWebCrypto > ( randomValuesOnly ) ; _onEncrypt = async ( material ) => { const _material = await this . _rawOnEncrypt ( material ) ; return importForWebCryptoEncryptionMaterial ( _material ) ; } ; _onDecrypt = _onDecrypt < WebCryptoAlgorithmSuite , RawRsaKeyringWebCrypto > ( ) ; static async importPublicKey ( publicKey ) { const op = getImportOptions ( publicKey ) ; const backend = await getWebCryptoBackend ( ) ; const subtle = getNonZeroByteBackend ( backend ) ; return ImportKeyTypeOverload ( op , subtle , [ 'wrapKey' ] ) ; } static async importPrivateKey ( privateKey ) { const op = getImportOptions ( privateKey ) ; const backend = await getWebCryptoBackend ( ) ; if ( isFullSupportWebCryptoBackend ( backend ) ) { return ImportKeyTypeOverload ( op , backend . subtle , [ 'unwrapKey' ] ) ; } else { return Promise . all ( [ ImportKeyTypeOverload ( op , backend . nonZeroByteSubtle , [ 'unwrapKey' ] ) , ImportKeyTypeOverload ( op , backend . zeroByteSubtle , [ 'unwrapKey' ] ) , ] ) . then ( ( [ nonZeroByteCryptoKey , zeroByteCryptoKey ] ) => ( { nonZeroByteCryptoKey , zeroByteCryptoKey , } ) ) ; } } } immutableClass ( RawRsaKeyringWebCrypto ) ; async function ImportKeyTypeOverload ( op , subtle , keyUsages ) { return op . format == 'jwk' ? subtle . importKey ( op . format , op . key , op . wrappingAlgorithm , false , keyUsages ) : subtle . importKey ( op . format , op . key , op . wrappingAlgorithm , false , keyUsages ) ; }