Updates referencesource to .NET 4.7
[mono-project.git] / mcs / class / referencesource / mscorlib / system / security / cryptography / cryptoapitransform.cs
blob89ddba5b8f9f3e74e4577070487f70c7d593996f
1 // ==++==
2 //
3 // Copyright (c) Microsoft Corporation. All rights reserved.
4 //
5 // ==--==
6 // <OWNER>Microsoft</OWNER>
7 //
9 //
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
23 [Serializable]
24 internal enum CryptoAPITransformMode {
25 Encrypt = 0,
26 Decrypt = 1
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) {
50 int dwValue;
51 byte[] rgbValue;
53 BlockSizeValue = blockSize;
54 ModeValue = cipherChainingMode;
55 PaddingValue = padding;
56 encryptOrDecrypt = encDecMode;
58 // Copy the input args
59 int _cArgs = cArgs;
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;
72 continue;
74 if (rgArgValues[j] is int) {
75 _rgArgValues[j] = (int) rgArgValues[j];
76 continue;
78 if (rgArgValues[j] is CipherMode) {
79 _rgArgValues[j] = (int) rgArgValues[j];
80 continue;
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]) {
93 case Constants.KP_IV:
94 IVValue = (byte[]) _rgArgValues[i];
95 rgbValue = IVValue;
96 Utils.SetKeyParamRgb(_safeKeyHandle, _rgArgIds[i], rgbValue, rgbValue.Length);
97 break;
99 case Constants.KP_MODE:
100 ModeValue = (CipherMode) _rgArgValues[i];
101 dwValue = (Int32) _rgArgValues[i];
102 SetAsDWord:
103 Utils.SetKeyParamDw(_safeKeyHandle, _rgArgIds[i], dwValue);
104 break;
106 case Constants.KP_MODE_BITS:
107 dwValue = (Int32) _rgArgValues[i];
108 goto SetAsDWord;
110 case Constants.KP_EFFECTIVE_KEYLEN:
111 dwValue = (Int32) _rgArgValues[i];
112 goto SetAsDWord;
114 default:
115 throw new CryptographicException(Environment.GetResourceString("Cryptography_InvalidKeyParameter"), "_rgArgIds[i]");
120 public void Dispose() {
121 Clear();
124 [System.Security.SecuritySafeCritical] // auto-generated
125 public void Clear() {
126 Dispose(true);
127 GC.SuppressFinalize(this);
130 [System.Security.SecurityCritical] // auto-generated
131 private void Dispose(bool disposing) {
132 if (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);
136 _rgbKey = null;
138 if (IVValue != null) {
139 Array.Clear(IVValue,0,IVValue.Length);
140 IVValue = null;
142 if (_depadBuffer != null) {
143 Array.Clear(_depadBuffer, 0, _depadBuffer.Length);
144 _depadBuffer = null;
147 if (_safeKeyHandle != null && !_safeKeyHandle.IsClosed) {
148 _safeKeyHandle.Dispose();
150 if (_safeProvHandle != null && !_safeProvHandle.IsClosed) {
151 _safeProvHandle.Dispose();
157 // public properties
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); }
183 // public methods
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() {
190 _depadBuffer = null;
191 // just ensure we've called CryptEncrypt with the true flag
192 byte[] temp = null;
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);
213 } else {
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);
219 } else {
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);
228 } else {
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);
253 Reset();
254 return transformedBytes;
255 } else {
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);
262 Reset();
263 return transformedBytes;
264 } else {
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);
270 Reset();
271 return transformedBytes;
276 #endif // FEATURE_MACL && FEATURE_CRYPTO
278 [Serializable]
279 [System.Runtime.InteropServices.ComVisible(true)]
280 [Flags]
281 public enum CspProviderFlags {
282 NoFlags = 0x0000,
283 UseMachineKeyStore = 0x0001,
284 UseDefaultKeyContainer = 0x0002,
285 UseNonExportableKey = 0x0004,
286 UseExistingKey = 0x0008,
287 UseArchivableKey = 0x0010,
288 UseUserProtectedKey = 0x0020,
289 NoPrompt = 0x0040,
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;
302 private int m_flags;
303 public CspProviderFlags Flags {
304 get { return (CspProviderFlags) m_flags; }
305 set {
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");
319 m_flags = flags;
323 #if FEATURE_MACL || MONO
324 private CryptoKeySecurity m_cryptoKeySecurity;
325 public CryptoKeySecurity CryptoKeySecurity {
326 get {
327 return m_cryptoKeySecurity;
329 set {
330 m_cryptoKeySecurity = value;
333 #endif
335 #if (FEATURE_CRYPTO && FEATURE_X509_SECURESTRINGS) || FEATURE_CORECLR
336 private SecureString m_keyPassword;
337 public SecureString KeyPassword {
338 get {
339 return m_keyPassword;
341 set {
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)]
351 get {
352 return m_parentWindowHandle;
354 [ResourceExposure(ResourceScope.Machine)]
355 set {
356 m_parentWindowHandle = value;
357 // Parent handle and PIN are mutually exclusive.
358 m_keyPassword = null;
361 #endif
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;
405 KeyNumber = -1;
406 Flags = flags;
409 // copy constructor
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