3 // Copyright (c) Microsoft Corporation. All rights reserved.
6 // <OWNER>Microsoft</OWNER>
10 // CryptoAPITransform.cs
13 namespace System
.Security
.Cryptography
{
15 using System
.Security
.AccessControl
;
16 using System
.Security
.Permissions
;
17 using System
.Runtime
.InteropServices
;
18 using System
.Runtime
.Versioning
;
19 using System
.Diagnostics
.Contracts
;
21 #if FEATURE_MACL && FEATURE_CRYPTO && !MONO
24 internal enum CryptoAPITransformMode
{
29 [System
.Runtime
.InteropServices
.ComVisible(true)]
30 public sealed class CryptoAPITransform
: ICryptoTransform
{
31 private int BlockSizeValue
;
32 private byte[] IVValue
;
33 private CipherMode ModeValue
;
34 private PaddingMode PaddingValue
;
35 private CryptoAPITransformMode encryptOrDecrypt
;
36 private byte[] _rgbKey
;
37 private byte[] _depadBuffer
= null;
38 [System
.Security
.SecurityCritical
] // auto-generated
39 private SafeKeyHandle _safeKeyHandle
;
40 [System
.Security
.SecurityCritical
] // auto-generated
41 private SafeProvHandle _safeProvHandle
;
43 private CryptoAPITransform () {}
44 [System
.Security
.SecurityCritical
] // auto-generated
45 internal CryptoAPITransform(int algid
, int cArgs
, int[] rgArgIds
,
46 Object
[] rgArgValues
, byte[] rgbKey
, PaddingMode padding
,
47 CipherMode cipherChainingMode
, int blockSize
,
48 int feedbackSize
, bool useSalt
,
49 CryptoAPITransformMode encDecMode
) {
53 BlockSizeValue
= blockSize
;
54 ModeValue
= cipherChainingMode
;
55 PaddingValue
= padding
;
56 encryptOrDecrypt
= encDecMode
;
58 // Copy the input args
60 int[] _rgArgIds
= new int[rgArgIds
.Length
];
61 Array
.Copy(rgArgIds
, _rgArgIds
, rgArgIds
.Length
);
62 _rgbKey
= new byte[rgbKey
.Length
];
63 Array
.Copy(rgbKey
, _rgbKey
, rgbKey
.Length
);
64 Object
[] _rgArgValues
= new Object
[rgArgValues
.Length
];
65 // an element of rgArgValues can only be an int or a byte[]
66 for (int j
= 0; j
< rgArgValues
.Length
; j
++) {
67 if (rgArgValues
[j
] is byte[]) {
68 byte[] rgbOrig
= (byte[]) rgArgValues
[j
];
69 byte[] rgbNew
= new byte[rgbOrig
.Length
];
70 Array
.Copy(rgbOrig
, rgbNew
, rgbOrig
.Length
);
71 _rgArgValues
[j
] = rgbNew
;
74 if (rgArgValues
[j
] is int) {
75 _rgArgValues
[j
] = (int) rgArgValues
[j
];
78 if (rgArgValues
[j
] is CipherMode
) {
79 _rgArgValues
[j
] = (int) rgArgValues
[j
];
84 _safeProvHandle
= Utils
.AcquireProvHandle(new CspParameters(Utils
.DefaultRsaProviderType
));
86 SafeKeyHandle safeKeyHandle
= SafeKeyHandle
.InvalidHandle
;
87 // _ImportBulkKey will check for failures and throw an exception
88 Utils
._ImportBulkKey(_safeProvHandle
, algid
, useSalt
, _rgbKey
, ref safeKeyHandle
);
89 _safeKeyHandle
= safeKeyHandle
;
91 for (int i
=0; i
<cArgs
; i
++) {
92 switch (rgArgIds
[i
]) {
94 IVValue
= (byte[]) _rgArgValues
[i
];
96 Utils
.SetKeyParamRgb(_safeKeyHandle
, _rgArgIds
[i
], rgbValue
, rgbValue
.Length
);
99 case Constants
.KP_MODE
:
100 ModeValue
= (CipherMode
) _rgArgValues
[i
];
101 dwValue
= (Int32
) _rgArgValues
[i
];
103 Utils
.SetKeyParamDw(_safeKeyHandle
, _rgArgIds
[i
], dwValue
);
106 case Constants
.KP_MODE_BITS
:
107 dwValue
= (Int32
) _rgArgValues
[i
];
110 case Constants
.KP_EFFECTIVE_KEYLEN
:
111 dwValue
= (Int32
) _rgArgValues
[i
];
115 throw new CryptographicException(Environment
.GetResourceString("Cryptography_InvalidKeyParameter"), "_rgArgIds[i]");
120 public void Dispose() {
124 [System
.Security
.SecuritySafeCritical
] // auto-generated
125 public void Clear() {
127 GC
.SuppressFinalize(this);
130 [System
.Security
.SecurityCritical
] // auto-generated
131 private void Dispose(bool disposing
) {
133 // We need to always zeroize the following fields because they contain sensitive data
134 if (_rgbKey
!= null) {
135 Array
.Clear(_rgbKey
,0,_rgbKey
.Length
);
138 if (IVValue
!= null) {
139 Array
.Clear(IVValue
,0,IVValue
.Length
);
142 if (_depadBuffer
!= null) {
143 Array
.Clear(_depadBuffer
, 0, _depadBuffer
.Length
);
147 if (_safeKeyHandle
!= null && !_safeKeyHandle
.IsClosed
) {
148 _safeKeyHandle
.Dispose();
150 if (_safeProvHandle
!= null && !_safeProvHandle
.IsClosed
) {
151 _safeProvHandle
.Dispose();
160 public IntPtr KeyHandle
{
161 [System
.Security
.SecuritySafeCritical
] // auto-generated
162 [SecurityPermissionAttribute(SecurityAction
.Demand
, Flags
=SecurityPermissionFlag
.UnmanagedCode
)]
163 get { return _safeKeyHandle.DangerousGetHandle(); }
166 public int InputBlockSize
{
167 get { return(BlockSizeValue/8); }
170 public int OutputBlockSize
{
171 get { return(BlockSizeValue/8); }
174 public bool CanTransformMultipleBlocks
{
175 get { return(true); }
178 public bool CanReuseTransform
{
179 get { return(true); }
186 // This routine resets the internal state of the CryptoAPITransform
187 [System
.Security
.SecuritySafeCritical
] // auto-generated
188 [System
.Runtime
.InteropServices
.ComVisible(false)]
189 public void Reset() {
191 // just ensure we've called CryptEncrypt with the true flag
193 Utils
._EncryptData(_safeKeyHandle
, EmptyArray
<Byte
>.Value
, 0, 0, ref temp
, 0, PaddingValue
, true);
196 [System
.Security
.SecuritySafeCritical
] // auto-generated
197 public int TransformBlock(byte[] inputBuffer
, int inputOffset
, int inputCount
, byte[] outputBuffer
, int outputOffset
) {
198 // Note: special handling required if decrypting & using padding because the padding adds to the end of the last
199 // block, we have to buffer an entire block's worth of bytes in case what I just transformed turns out to be
200 // the last block Then in TransformFinalBlock we strip off the padding.
202 if (inputBuffer
== null) throw new ArgumentNullException("inputBuffer");
203 if (outputBuffer
== null) throw new ArgumentNullException("outputBuffer");
204 if (inputOffset
< 0) throw new ArgumentOutOfRangeException("inputOffset", Environment
.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
205 if ((inputCount
<= 0) || (inputCount
% InputBlockSize
!= 0) || (inputCount
> inputBuffer
.Length
)) throw new ArgumentException(Environment
.GetResourceString("Argument_InvalidValue"));
206 if ((inputBuffer
.Length
- inputCount
) < inputOffset
) throw new ArgumentException(Environment
.GetResourceString("Argument_InvalidOffLen"));
207 Contract
.EndContractBlock();
209 if (encryptOrDecrypt
== CryptoAPITransformMode
.Encrypt
) {
210 // if we're encrypting we can always push out the bytes because no padding mode
211 // removes bytes during encryption
212 return Utils
._EncryptData(_safeKeyHandle
, inputBuffer
, inputOffset
, inputCount
, ref outputBuffer
, outputOffset
, PaddingValue
, false);
214 if (PaddingValue
== PaddingMode
.Zeros
|| PaddingValue
== PaddingMode
.None
) {
215 // like encryption, if we're using None or Zeros padding on decrypt we can write out all
216 // the bytes. Note that we cannot depad a block partially padded with Zeros because
217 // we can't tell if those zeros are plaintext or pad.
218 return Utils
._DecryptData(_safeKeyHandle
, inputBuffer
, inputOffset
, inputCount
, ref outputBuffer
, outputOffset
, PaddingValue
, false);
220 // OK, now we're in the special case. Check to see if this is the *first* block we've seen
221 // If so, buffer it and return null zero bytes
222 if (_depadBuffer
== null) {
223 _depadBuffer
= new byte[InputBlockSize
];
224 // copy the last InputBlockSize bytes to _depadBuffer everything else gets processed and returned
225 int inputToProcess
= inputCount
- InputBlockSize
;
226 Buffer
.InternalBlockCopy(inputBuffer
, inputOffset
+inputToProcess
, _depadBuffer
, 0, InputBlockSize
);
227 return Utils
._DecryptData(_safeKeyHandle
, inputBuffer
, inputOffset
, inputToProcess
, ref outputBuffer
, outputOffset
, PaddingValue
, false);
229 // we already have a depad buffer, so we need to decrypt that info first & copy it out
230 int r
= Utils
._DecryptData(_safeKeyHandle
, _depadBuffer
, 0, _depadBuffer
.Length
, ref outputBuffer
, outputOffset
, PaddingValue
, false);
231 outputOffset
+= OutputBlockSize
;
232 int inputToProcess
= inputCount
- InputBlockSize
;
233 Buffer
.InternalBlockCopy(inputBuffer
, inputOffset
+inputToProcess
, _depadBuffer
, 0, InputBlockSize
);
234 r
= Utils
._DecryptData(_safeKeyHandle
, inputBuffer
, inputOffset
, inputToProcess
, ref outputBuffer
, outputOffset
, PaddingValue
, false);
235 return (OutputBlockSize
+ r
);
241 [System
.Security
.SecuritySafeCritical
] // auto-generated
242 public byte[] TransformFinalBlock(byte[] inputBuffer
, int inputOffset
, int inputCount
) {
243 if (inputBuffer
== null) throw new ArgumentNullException("inputBuffer");
244 if (inputOffset
< 0) throw new ArgumentOutOfRangeException("inputOffset", Environment
.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
245 if ((inputCount
< 0) || (inputCount
> inputBuffer
.Length
)) throw new ArgumentException(Environment
.GetResourceString("Argument_InvalidValue"));
246 if ((inputBuffer
.Length
- inputCount
) < inputOffset
) throw new ArgumentException(Environment
.GetResourceString("Argument_InvalidOffLen"));
247 Contract
.EndContractBlock();
249 if (encryptOrDecrypt
== CryptoAPITransformMode
.Encrypt
) {
250 // If we're encrypting we can always return what we compute because there's no _depadBuffer
251 byte[] transformedBytes
= null;
252 Utils
._EncryptData(_safeKeyHandle
, inputBuffer
, inputOffset
, inputCount
, ref transformedBytes
, 0, PaddingValue
, true);
254 return transformedBytes
;
256 if (inputCount
%InputBlockSize
!= 0)
257 throw new CryptographicException(Environment
.GetResourceString("Cryptography_SSD_InvalidDataSize"));
259 if (_depadBuffer
== null) {
260 byte[] transformedBytes
= null;
261 Utils
._DecryptData(_safeKeyHandle
, inputBuffer
, inputOffset
, inputCount
, ref transformedBytes
, 0, PaddingValue
, true);
263 return transformedBytes
;
265 byte[] temp
= new byte[_depadBuffer
.Length
+ inputCount
];
266 Buffer
.InternalBlockCopy(_depadBuffer
, 0, temp
, 0, _depadBuffer
.Length
);
267 Buffer
.InternalBlockCopy(inputBuffer
, inputOffset
, temp
, _depadBuffer
.Length
, inputCount
);
268 byte[] transformedBytes
= null;
269 Utils
._DecryptData(_safeKeyHandle
, temp
, 0, temp
.Length
, ref transformedBytes
, 0, PaddingValue
, true);
271 return transformedBytes
;
276 #endif // FEATURE_MACL && FEATURE_CRYPTO
279 [System
.Runtime
.InteropServices
.ComVisible(true)]
281 public enum CspProviderFlags
{
283 UseMachineKeyStore
= 0x0001,
284 UseDefaultKeyContainer
= 0x0002,
285 UseNonExportableKey
= 0x0004,
286 UseExistingKey
= 0x0008,
287 UseArchivableKey
= 0x0010,
288 UseUserProtectedKey
= 0x0020,
290 CreateEphemeralKey
= 0x0080
293 [System
.Runtime
.InteropServices
.ComVisible(true)]
294 public sealed class CspParameters
296 public int ProviderType
;
297 public string ProviderName
;
298 [ResourceExposure(ResourceScope
.Machine
)]
299 public string KeyContainerName
;
300 public int KeyNumber
;
303 public CspProviderFlags Flags
{
304 get { return (CspProviderFlags) m_flags; }
306 int allFlags
= 0x00FF; // this should change if more values are added to CspProviderFlags
307 Contract
.Assert((CspProviderFlags
.UseMachineKeyStore
|
308 CspProviderFlags
.UseDefaultKeyContainer
|
309 CspProviderFlags
.UseNonExportableKey
|
310 CspProviderFlags
.UseExistingKey
|
311 CspProviderFlags
.UseArchivableKey
|
312 CspProviderFlags
.UseUserProtectedKey
|
313 CspProviderFlags
.NoPrompt
|
314 CspProviderFlags
.CreateEphemeralKey
) == (CspProviderFlags
)allFlags
, "allFlags does not match all CspProviderFlags");
316 int flags
= (int) value;
317 if ((flags
& ~allFlags
) != 0)
318 throw new ArgumentException(Environment
.GetResourceString("Arg_EnumIllegalVal", (int)value), "value");
323 #if FEATURE_MACL || MONO
324 private CryptoKeySecurity m_cryptoKeySecurity
;
325 public CryptoKeySecurity CryptoKeySecurity
{
327 return m_cryptoKeySecurity
;
330 m_cryptoKeySecurity
= value;
335 #if (FEATURE_CRYPTO && FEATURE_X509_SECURESTRINGS) || FEATURE_CORECLR
336 private SecureString m_keyPassword
;
337 public SecureString KeyPassword
{
339 return m_keyPassword
;
342 m_keyPassword
= value;
343 // Parent handle and PIN are mutually exclusive.
344 m_parentWindowHandle
= IntPtr
.Zero
;
348 private IntPtr m_parentWindowHandle
;
349 public IntPtr ParentWindowHandle
{
350 [ResourceExposure(ResourceScope
.Machine
)]
352 return m_parentWindowHandle
;
354 [ResourceExposure(ResourceScope
.Machine
)]
356 m_parentWindowHandle
= value;
357 // Parent handle and PIN are mutually exclusive.
358 m_keyPassword
= null;
363 [ResourceExposure(ResourceScope
.None
)]
364 [ResourceConsumption(ResourceScope
.Machine
, ResourceScope
.Machine
)]
365 public CspParameters () : this(Utils
.DefaultRsaProviderType
, null, null) {}
367 [ResourceExposure(ResourceScope
.None
)]
368 [ResourceConsumption(ResourceScope
.Machine
, ResourceScope
.Machine
)]
369 public CspParameters (int dwTypeIn
) : this(dwTypeIn
, null, null) {}
371 [ResourceExposure(ResourceScope
.None
)]
372 [ResourceConsumption(ResourceScope
.Machine
, ResourceScope
.Machine
)]
373 public CspParameters (int dwTypeIn
, string strProviderNameIn
) : this(dwTypeIn
, strProviderNameIn
, null) {}
375 [ResourceExposure(ResourceScope
.Machine
)]
376 [ResourceConsumption(ResourceScope
.Machine
)]
377 public CspParameters (int dwTypeIn
, string strProviderNameIn
, string strContainerNameIn
) :
378 this (dwTypeIn
, strProviderNameIn
, strContainerNameIn
, CspProviderFlags
.NoFlags
) {}
380 #if MONO || (FEATURE_MACL && FEATURE_CRYPTO && FEATURE_X509_SECURESTRINGS)
381 [ResourceExposure(ResourceScope
.Machine
)]
382 [ResourceConsumption(ResourceScope
.Machine
)]
383 public CspParameters (int providerType
, string providerName
, string keyContainerName
,
384 CryptoKeySecurity cryptoKeySecurity
, SecureString keyPassword
)
385 : this (providerType
, providerName
, keyContainerName
) {
386 m_cryptoKeySecurity
= cryptoKeySecurity
;
387 m_keyPassword
= keyPassword
;
390 [ResourceExposure(ResourceScope
.Machine
)]
391 [ResourceConsumption(ResourceScope
.Machine
)]
392 public CspParameters (int providerType
, string providerName
, string keyContainerName
,
393 CryptoKeySecurity cryptoKeySecurity
, IntPtr parentWindowHandle
)
394 : this (providerType
, providerName
, keyContainerName
) {
395 m_cryptoKeySecurity
= cryptoKeySecurity
;
396 m_parentWindowHandle
= parentWindowHandle
;
398 #endif // #if FEATURE_MACL && FEATURE_CRYPTO && FEATURE_X509_SECURESTRINGS
400 [ResourceExposure(ResourceScope
.Machine
)]
401 internal CspParameters (int providerType
, string providerName
, string keyContainerName
, CspProviderFlags flags
) {
402 ProviderType
= providerType
;
403 ProviderName
= providerName
;
404 KeyContainerName
= keyContainerName
;
410 internal CspParameters (CspParameters parameters
) {
411 ProviderType
= parameters
.ProviderType
;
412 ProviderName
= parameters
.ProviderName
;
413 KeyContainerName
= parameters
.KeyContainerName
;
414 KeyNumber
= parameters
.KeyNumber
;
415 Flags
= parameters
.Flags
;
416 #if FEATURE_MACL || MONO
417 m_cryptoKeySecurity
= parameters
.m_cryptoKeySecurity
;
418 #endif // FEATURE_MACL
419 #if FEATURE_CRYPTO && FEATURE_X509_SECURESTRINGS
420 m_keyPassword
= parameters
.m_keyPassword
;
421 m_parentWindowHandle
= parameters
.m_parentWindowHandle
;
422 #endif // FEATURE_CRYPTO && FEATURE_X509_SECURESTRINGS