@@ -18,7 +18,7 @@ public override bool SupportsOperation(KeyOperation operation)
1818 {
1919 if ( KeyMaterial != null )
2020 {
21- if ( operation == KeyOperation . WrapKey || operation == KeyOperation . UnwrapKey )
21+ if ( operation == KeyOperation . Encrypt || operation == KeyOperation . Decrypt || operation == KeyOperation . WrapKey || operation == KeyOperation . UnwrapKey )
2222 {
2323 return KeyMaterial . SupportsOperation ( operation ) ;
2424 }
@@ -27,26 +27,122 @@ public override bool SupportsOperation(KeyOperation operation)
2727 return false ;
2828 }
2929
30+ public override DecryptResult Decrypt ( DecryptOptions options , CancellationToken cancellationToken = default )
31+ {
32+ Argument . AssertNotNull ( options , nameof ( options ) ) ;
33+
34+ ThrowIfTimeInvalid ( ) ;
35+
36+ EncryptionAlgorithm algorithm = options . Algorithm ;
37+ if ( algorithm . GetAesCbcEncryptionAlgorithm ( ) is AesCbc aesCbc )
38+ {
39+ using ICryptoTransform decryptor = aesCbc . CreateDecryptor ( KeyMaterial . K , options . Iv ) ;
40+
41+ byte [ ] ciphertext = options . Ciphertext ;
42+ byte [ ] plaintext = decryptor . TransformFinalBlock ( ciphertext , 0 , ciphertext . Length ) ;
43+
44+ return new DecryptResult
45+ {
46+ Algorithm = algorithm ,
47+ KeyId = KeyMaterial . Id ,
48+ Plaintext = plaintext ,
49+ } ;
50+ }
51+ else if ( algorithm . IsAesGcm ( ) && AesGcmProxy . TryCreate ( KeyMaterial . K , out AesGcmProxy aesGcm ) )
52+ {
53+ using ( aesGcm )
54+ {
55+ byte [ ] ciphertext = options . Ciphertext ;
56+ byte [ ] plaintext = new byte [ ciphertext . Length ] ;
57+
58+ aesGcm . Decrypt ( options . Iv , ciphertext , options . AuthenticationTag , plaintext , options . AdditionalAuthenticatedData ) ;
59+
60+ return new DecryptResult
61+ {
62+ Algorithm = algorithm ,
63+ KeyId = KeyMaterial . Id ,
64+ Plaintext = plaintext ,
65+ } ;
66+ }
67+ }
68+ else
69+ {
70+ KeysEventSource . Singleton . AlgorithmNotSupported ( nameof ( Decrypt ) , algorithm ) ;
71+ return null ;
72+ }
73+ }
74+
75+ public override EncryptResult Encrypt ( EncryptOptions options , CancellationToken cancellationToken = default )
76+ {
77+ Argument . AssertNotNull ( options , nameof ( options ) ) ;
78+
79+ ThrowIfTimeInvalid ( ) ;
80+
81+ EncryptionAlgorithm algorithm = options . Algorithm ;
82+ if ( algorithm . GetAesCbcEncryptionAlgorithm ( ) is AesCbc aesCbc )
83+ {
84+ using ICryptoTransform encryptor = aesCbc . CreateEncryptor ( KeyMaterial . K , options . Iv ) ;
85+
86+ byte [ ] plaintext = options . Plaintext ;
87+ byte [ ] ciphertext = encryptor . TransformFinalBlock ( plaintext , 0 , plaintext . Length ) ;
88+
89+ return new EncryptResult
90+ {
91+ Algorithm = algorithm ,
92+ KeyId = KeyMaterial . Id ,
93+ Ciphertext = ciphertext ,
94+ Iv = options . Iv ,
95+ } ;
96+ }
97+ else if ( algorithm . IsAesGcm ( ) && AesGcmProxy . TryCreate ( KeyMaterial . K , out AesGcmProxy aesGcm ) )
98+ {
99+ using ( aesGcm )
100+ {
101+ byte [ ] plaintext = options . Plaintext ;
102+ byte [ ] ciphertext = new byte [ plaintext . Length ] ;
103+ byte [ ] tag = new byte [ AesGcmProxy . NonceByteSize ] ;
104+
105+ // Generate an nonce only for local AES-GCM; Managed HSM will do it service-side and err if serialized.
106+ byte [ ] iv = Crypto . GenerateIv ( AesGcmProxy . NonceByteSize ) ;
107+
108+ aesGcm . Encrypt ( iv , plaintext , ciphertext , tag , options . AdditionalAuthenticatedData ) ;
109+
110+ return new EncryptResult
111+ {
112+ Algorithm = algorithm ,
113+ KeyId = KeyMaterial . Id ,
114+ Ciphertext = ciphertext ,
115+ Iv = iv ,
116+ AuthenticationTag = tag ,
117+ AdditionalAuthenticatedData = options . AdditionalAuthenticatedData ,
118+ } ;
119+ }
120+ }
121+ else
122+ {
123+ KeysEventSource . Singleton . AlgorithmNotSupported ( nameof ( Encrypt ) , algorithm ) ;
124+ return null ;
125+ }
126+ }
127+
30128 public override UnwrapResult UnwrapKey ( KeyWrapAlgorithm algorithm , byte [ ] encryptedKey , CancellationToken cancellationToken )
31129 {
32130 Argument . AssertNotNull ( encryptedKey , nameof ( encryptedKey ) ) ;
33131
34- int algorithmKeySizeBytes = algorithm . GetKeySizeInBytes ( ) ;
35- if ( algorithmKeySizeBytes == 0 )
132+ AesKw keyWrapAlgorithm = algorithm . GetAesKeyWrapAlgorithm ( ) ;
133+ if ( keyWrapAlgorithm == null )
36134 {
37135 KeysEventSource . Singleton . AlgorithmNotSupported ( nameof ( UnwrapKey ) , algorithm ) ;
38136 return null ;
39137 }
40138
41139 int keySizeBytes = GetKeySizeInBytes ( ) ;
42- if ( keySizeBytes < algorithmKeySizeBytes )
140+ if ( keySizeBytes < keyWrapAlgorithm . KeySizeInBytes )
43141 {
44- throw new ArgumentException ( $ "Key wrap algorithm { algorithm } key size { algorithmKeySizeBytes } is greater than the underlying key size { keySizeBytes } ") ;
142+ throw new ArgumentException ( $ "Key wrap algorithm { algorithm } key size { keyWrapAlgorithm . KeySizeInBytes } is greater than the underlying key size { keySizeBytes } ") ;
45143 }
46144
47- byte [ ] sizedKey = ( keySizeBytes == algorithmKeySizeBytes ) ? KeyMaterial . K : KeyMaterial . K . Take ( algorithmKeySizeBytes ) ;
48-
49- using ICryptoTransform decryptor = AesKw . CreateDecryptor ( sizedKey ) ;
145+ using ICryptoTransform decryptor = keyWrapAlgorithm . CreateDecryptor ( KeyMaterial . K ) ;
50146
51147 byte [ ] key = decryptor . TransformFinalBlock ( encryptedKey , 0 , encryptedKey . Length ) ;
52148 return new UnwrapResult
@@ -63,22 +159,20 @@ public override WrapResult WrapKey(KeyWrapAlgorithm algorithm, byte[] key, Cance
63159
64160 ThrowIfTimeInvalid ( ) ;
65161
66- int algorithmKeySizeBytes = algorithm . GetKeySizeInBytes ( ) ;
67- if ( algorithmKeySizeBytes == 0 )
162+ AesKw keyWrapAlgorithm = algorithm . GetAesKeyWrapAlgorithm ( ) ;
163+ if ( keyWrapAlgorithm == null )
68164 {
69165 KeysEventSource . Singleton . AlgorithmNotSupported ( nameof ( WrapKey ) , algorithm ) ;
70166 return null ;
71167 }
72168
73169 int keySizeBytes = GetKeySizeInBytes ( ) ;
74- if ( keySizeBytes < algorithmKeySizeBytes )
170+ if ( keySizeBytes < keyWrapAlgorithm . KeySizeInBytes )
75171 {
76- throw new ArgumentException ( $ "Key wrap algorithm { algorithm } key size { algorithmKeySizeBytes } is greater than the underlying key size { keySizeBytes } ") ;
172+ throw new ArgumentException ( $ "Key wrap algorithm { algorithm } key size { keyWrapAlgorithm . KeySizeInBytes } is greater than the underlying key size { keySizeBytes } ") ;
77173 }
78174
79- byte [ ] sizedKey = ( keySizeBytes == algorithmKeySizeBytes ) ? KeyMaterial . K : KeyMaterial . K . Take ( algorithmKeySizeBytes ) ;
80-
81- using ICryptoTransform encryptor = AesKw . CreateEncryptor ( sizedKey ) ;
175+ using ICryptoTransform encryptor = keyWrapAlgorithm . CreateEncryptor ( KeyMaterial . K ) ;
82176
83177 byte [ ] encryptedKey = encryptor . TransformFinalBlock ( key , 0 , key . Length ) ;
84178 return new WrapResult
@@ -89,11 +183,6 @@ public override WrapResult WrapKey(KeyWrapAlgorithm algorithm, byte[] key, Cance
89183 } ;
90184 }
91185
92- private int GetKeySizeInBits ( )
93- {
94- return GetKeySizeInBytes ( ) << 3 ;
95- }
96-
97186 private int GetKeySizeInBytes ( )
98187 {
99188 if ( KeyMaterial . K != null )
@@ -102,7 +191,6 @@ private int GetKeySizeInBytes()
102191 }
103192
104193 return 0 ;
105-
106194 }
107195 }
108196}
0 commit comments