Added Mono.Tasklets test
[mono.git] / mcs / class / referencesource / System.Core / System / Security / Cryptography / BCryptNative.cs
1 // ==++==
2 // 
3 //   Copyright (c) Microsoft Corporation.  All rights reserved.
4 // 
5 // ==--==
6
7 using System;
8 using System.Diagnostics;
9 using System.Diagnostics.CodeAnalysis;
10 using System.Runtime.CompilerServices;
11 using System.Runtime.ConstrainedExecution;
12 using System.Runtime.InteropServices;
13 using System.Diagnostics.Contracts;
14 using Microsoft.Win32;
15 using Microsoft.Win32.SafeHandles;
16 using System.Security.Cryptography.X509Certificates;
17
18 namespace System.Security.Cryptography {
19
20     internal enum AsymmetricPaddingMode {
21         /// <summary>
22         ///     No padding
23         /// </summary>
24         None = 1,                       // BCRYPT_PAD_NONE
25
26         /// <summary>
27         ///     PKCS #1 padding
28         /// </summary>
29         Pkcs1 = 2,                      // BCRYPT_PAD_PKCS1
30
31         /// <summary>
32         ///     Optimal Asymmetric Encryption Padding
33         /// </summary>
34         Oaep = 4,                       // BCRYPT_PAD_OAEP
35
36         /// <summary>
37         ///     Probabilistic Signature Scheme padding
38         /// </summary>
39         Pss = 8                         // BCRYPT_PAD_PSS
40     }
41     /// <summary>
42     ///     Native interop with CNG's BCrypt layer. Native definitions can be found in bcrypt.h
43     /// </summary>
44     internal static class BCryptNative {
45         /// <summary>
46         ///     Well known algorithm names
47         /// </summary>
48         internal static class AlgorithmName {
49             public const string ECDHP256 = "ECDH_P256";         // BCRYPT_ECDH_P256_ALGORITHM
50             public const string ECDHP384 = "ECDH_P384";         // BCRYPT_ECDH_P384_ALGORITHM
51             public const string ECDHP521 = "ECDH_P521";         // BCRYPT_ECDH_P521_ALGORITHM
52             public const string ECDsaP256 = "ECDSA_P256";       // BCRYPT_ECDSA_P256_ALGORITHM
53             public const string ECDsaP384 = "ECDSA_P384";       // BCRYPT_ECDSA_P384_ALGORITHM
54             public const string ECDsaP521 = "ECDSA_P521";       // BCRYPT_ECDSA_P521_ALGORITHM
55             public const string MD5 = "MD5";                    // BCRYPT_MD5_ALGORITHM
56             public const string Sha1 = "SHA1";                  // BCRYPT_SHA1_ALGORITHM
57             public const string Sha256 = "SHA256";              // BCRYPT_SHA256_ALGORITHM
58             public const string Sha384 = "SHA384";              // BCRYPT_SHA384_ALGORITHM
59             public const string Sha512 = "SHA512";              // BCRYPT_SHA512_ALGORITHM
60             internal const string Rsa = "RSA";                  // BCRYPT_RSA_ALGORITHM
61         }
62
63         /// <summary>
64         ///     Well known key blob tyes
65         /// </summary>
66         internal static class KeyBlobType {
67             //During Win8 Windows introduced  BCRYPT_PUBLIC_KEY_BLOB L"PUBLICBLOB"  
68             //and #define BCRYPT_PRIVATE_KEY_BLOB L"PRIVATEBLOB". We should use the 
69             //same on ProjectN and ProjectK 
70             internal const string RsaFullPrivateBlob = "RSAFULLPRIVATEBLOB";    // BCRYPT_RSAFULLPRIVATE_BLOB
71             internal const string RsaPrivateBlob = "RSAPRIVATEBLOB";            // BCRYPT_RSAPRIVATE_BLOB
72             internal const string RsaPublicBlob = "RSAPUBLICBLOB";              // BCRYPT_PUBLIC_KEY_BLOB
73         }
74
75         [StructLayout(LayoutKind.Sequential)]
76         internal struct BCRYPT_RSAKEY_BLOB {
77             internal KeyBlobMagicNumber Magic;
78             internal int BitLength;
79             internal int cbPublicExp;
80             internal int cbModulus;
81             internal int cbPrime1;
82             internal int cbPrime2;
83         }
84
85         /// <summary>
86         ///     Result codes from BCrypt APIs
87         /// </summary>
88         internal enum ErrorCode {
89             Success = 0x00000000,                               // STATUS_SUCCESS
90             BufferToSmall = unchecked((int)0xC0000023),         // STATUS_BUFFER_TOO_SMALL
91             ObjectNameNotFound = unchecked((int)0xC0000034)     // SATUS_OBJECT_NAME_NOT_FOUND
92         }
93
94         /// <summary>
95         ///     Well known BCrypt hash property names
96         /// </summary>
97         internal static class HashPropertyName {
98             public const string HashLength = "HashDigestLength";        // BCRYPT_HASH_LENGTH
99         }
100
101         /// <summary>
102         ///     Magic numbers identifying blob types
103         /// </summary>
104         internal enum KeyBlobMagicNumber {
105             ECDHPublicP256 = 0x314B4345,                        // BCRYPT_ECDH_PUBLIC_P256_MAGIC
106             ECDHPublicP384 = 0x334B4345,                        // BCRYPT_ECDH_PUBLIC_P384_MAGIC
107             ECDHPublicP521 = 0x354B4345,                        // BCRYPT_ECDH_PUBLIC_P521_MAGIC
108             ECDsaPublicP256 = 0x31534345,                       // BCRYPT_ECDSA_PUBLIC_P256_MAGIC
109             ECDsaPublicP384 = 0x33534345,                       // BCRYPT_ECDSA_PUBLIC_P384_MAGIC
110             ECDsaPublicP521 = 0x35534345,                       // BCRYPT_ECDSA_PUBLIC_P521_MAGIC
111             RsaPublic = 0x31415352,                             // BCRYPT_RSAPUBLIC_MAGIC
112             RsaPrivate = 0x32415352,                            // BCRYPT_RSAPRIVATE_MAGIC
113             RsaFullPrivateMagic = 0x33415352,                    //BCRYPT_RSAFULLPRIVATE_MAGIC   
114             KeyDataBlob = 0x4d42444b                            // BCRYPT_KEY_DATA_BLOB_MAGIC
115         }
116
117         [StructLayout(LayoutKind.Sequential)]
118         internal struct BCRYPT_OAEP_PADDING_INFO {
119             [MarshalAs(UnmanagedType.LPWStr)]
120             internal string pszAlgId;
121
122             internal IntPtr pbLabel;
123
124             internal int cbLabel;
125         }
126
127         [StructLayout(LayoutKind.Sequential)]
128         internal struct BCRYPT_PKCS1_PADDING_INFO {
129             [MarshalAs(UnmanagedType.LPWStr)]
130             internal string pszAlgId;
131         }
132
133         [StructLayout(LayoutKind.Sequential)]
134         internal struct BCRYPT_PSS_PADDING_INFO {
135             [MarshalAs(UnmanagedType.LPWStr)]
136             internal string pszAlgId;
137
138             internal int cbSalt;
139         }
140
141         /// <summary>
142         ///     Well known KDF names
143         /// </summary>
144         internal static class KeyDerivationFunction {
145             public const string Hash = "HASH";                  // BCRYPT_KDF_HASH
146             public const string Hmac = "HMAC";                  // BCRYPT_KDF_HMAC
147             public const string Tls = "TLS_PRF";                // BCRYPT_KDF_TLS_PRF
148         }
149
150         internal const string BCRYPT_ECCPUBLIC_BLOB = "ECCPUBLICBLOB";
151         internal const string BCRYPT_ECCPRIVATE_BLOB = "ECCPRIVATEBLOB";
152
153         /// <summary>
154         ///     Well known BCrypt provider names
155         /// </summary>
156         internal static class ProviderName {
157             public const string MicrosoftPrimitiveProvider = "Microsoft Primitive Provider";    // MS_PRIMITIVE_PROVIDER
158         }
159
160         /// <summary>
161         ///     Well known BCrypt object property names
162         /// </summary>
163         internal static class ObjectPropertyName {
164             public const string ObjectLength = "ObjectLength";          // BCRYPT_OBJECT_LENGTH
165         }
166
167 #pragma warning disable 618    // Have not migrated to v4 transparency yet
168         [SecurityCritical(SecurityCriticalScope.Everything)]
169 #pragma warning restore 618
170         [SuppressUnmanagedCodeSecurity]
171         internal static class UnsafeNativeMethods {
172             /// <summary>
173             ///     Create a hash object
174             /// </summary>
175             [DllImport("bcrypt.dll", CharSet = CharSet.Unicode)]
176             internal static extern ErrorCode BCryptCreateHash(SafeBCryptAlgorithmHandle hAlgorithm,
177                                                               [Out] out SafeBCryptHashHandle phHash,
178                                                               IntPtr pbHashObject,
179                                                               int cbHashObject,
180                                                               IntPtr pbSecret,
181                                                               int cbSecret,
182                                                               int dwFlags);
183
184             /// <summary>
185             ///     Get a property from a BCrypt algorithm object
186             /// </summary>
187             [DllImport("bcrypt.dll", CharSet = CharSet.Unicode)]
188             internal static extern ErrorCode BCryptGetProperty(SafeBCryptAlgorithmHandle hObject,
189                                                                string pszProperty,
190                                                                [MarshalAs(UnmanagedType.LPArray), In, Out] byte[] pbOutput,
191                                                                int cbOutput,
192                                                                [In, Out] ref int pcbResult,
193                                                                int flags);
194
195             /// <summary>
196             ///     Get a property from a BCrypt algorithm object
197             /// </summary>
198             [DllImport("bcrypt.dll", EntryPoint = "BCryptGetProperty", CharSet = CharSet.Unicode)]
199             internal static extern ErrorCode BCryptGetAlgorithmProperty(SafeBCryptAlgorithmHandle hObject,
200                                                                         string pszProperty,
201                                                                         [MarshalAs(UnmanagedType.LPArray), In, Out] byte[] pbOutput,
202                                                                         int cbOutput,
203                                                                         [In, Out] ref int pcbResult,
204                                                                         int flags);
205
206             /// <summary>
207             ///     Get a property from a BCrypt hash object
208             /// </summary>
209             [DllImport("bcrypt.dll", EntryPoint = "BCryptGetProperty", CharSet = CharSet.Unicode)]
210             internal static extern ErrorCode BCryptGetHashProperty(SafeBCryptHashHandle hObject,
211                                                                    string pszProperty,
212                                                                    [MarshalAs(UnmanagedType.LPArray), In, Out] byte[] pbOutput,
213                                                                    int cbOutput,
214                                                                    [In, Out] ref int pcbResult,
215                                                                    int flags);
216
217             /// <summary>
218             ///     Get the hash value of the data
219             /// </summary>
220             [DllImport("bcrypt.dll")]
221             internal static extern ErrorCode BCryptFinishHash(SafeBCryptHashHandle hHash,
222                                                               [MarshalAs(UnmanagedType.LPArray), Out] byte[] pbInput,
223                                                               int cbInput,
224                                                               int dwFlags);
225
226             /// <summary>
227             ///     Hash a block of data
228             /// </summary>
229             [DllImport("bcrypt.dll")]
230             internal static extern ErrorCode BCryptHashData(SafeBCryptHashHandle hHash,
231                                                             [MarshalAs(UnmanagedType.LPArray), In] byte[] pbInput,
232                                                             int cbInput,
233                                                             int dwFlags);
234
235             /// <summary>
236             ///     Get a handle to an algorithm provider
237             /// </summary>
238             [DllImport("bcrypt.dll", CharSet = CharSet.Unicode)]
239             internal static extern ErrorCode BCryptOpenAlgorithmProvider([Out] out SafeBCryptAlgorithmHandle phAlgorithm,
240                                                                          string pszAlgId,             // BCryptAlgorithm
241                                                                          string pszImplementation,    // ProviderNames
242                                                                          int dwFlags);
243
244             [DllImport("bcrypt.dll", SetLastError = true)]
245             internal static extern ErrorCode BCryptExportKey([In]SafeBCryptKeyHandle hKey,
246                                                              [In]IntPtr hExportKey,
247                                                              [In][MarshalAs(UnmanagedType.LPWStr)] string pszBlobType,
248                                                              [Out, MarshalAs(UnmanagedType.LPArray)] byte[] pbOutput,
249                                                              [In]int cbOutput,
250                                                              [In]ref int pcbResult,
251                                                              [In] int dwFlags);
252
253             [DllImport("Crypt32.dll", SetLastError = true)]
254             internal static extern int CryptImportPublicKeyInfoEx2([In] uint dwCertEncodingType,
255                                                    [In] ref X509Native.CERT_PUBLIC_KEY_INFO pInfo,
256                                                    [In] int dwFlags,
257                                                    [In] IntPtr pvAuxInfo,
258                                                    [Out] out SafeBCryptKeyHandle phKey);
259         }
260
261         //
262         // Wrapper and utility functions
263         //
264
265         /// <summary>
266         ///     Adapter to wrap specific BCryptGetProperty P/Invokes with a generic handle type
267         /// </summary>
268 #pragma warning disable 618 // System.Core.dll still uses SecurityRuleSet.Level1
269         [SecurityCritical(SecurityCriticalScope.Everything)]
270 #pragma warning restore 618
271         private delegate ErrorCode BCryptPropertyGetter<T>(T hObject,
272                                                            string pszProperty,
273                                                            byte[] pbOutput,
274                                                            int cbOutput,
275                                                            ref int pcbResult,
276                                                            int dwFlags) where T : SafeHandle;
277
278         private static volatile bool s_haveBcryptSupported;
279         private static volatile bool s_bcryptSupported;
280
281         /// <summary>
282         ///     Determine if BCrypt is supported on the current machine
283         /// </summary>
284         internal static bool BCryptSupported {
285             [SecuritySafeCritical]
286             [SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands", Justification = "Reviewed")]
287             get {
288                 if (!s_haveBcryptSupported)
289                 {
290                     // Attempt to load bcrypt.dll to see if the BCrypt CNG APIs are available on the machine
291                     using (SafeLibraryHandle bcrypt = Microsoft.Win32.UnsafeNativeMethods.LoadLibraryEx("bcrypt", IntPtr.Zero, 0)) {
292                         s_bcryptSupported = !bcrypt.IsInvalid;
293                         s_haveBcryptSupported = true;
294                     }
295                 }
296
297                 return s_bcryptSupported;
298             }
299         }
300
301         /// <summary>
302         ///     Get the value of a DWORD property of a BCrypt object
303         /// </summary>
304         [System.Security.SecurityCritical]
305         internal static int GetInt32Property<T>(T algorithm, string property) where T : SafeHandle {
306             Contract.Requires(algorithm != null);
307             Contract.Requires(property == HashPropertyName.HashLength ||
308                               property == ObjectPropertyName.ObjectLength);
309
310             return BitConverter.ToInt32(GetProperty(algorithm, property), 0);
311         }
312
313         /// <summary>
314         ///     Get the value of a property of a BCrypt object
315         /// </summary>
316         [System.Security.SecurityCritical]
317         internal static byte[] GetProperty<T>(T algorithm, string property) where T : SafeHandle {
318             Contract.Requires(algorithm != null);
319             Contract.Requires(!String.IsNullOrEmpty(property));
320             Contract.Ensures(Contract.Result<byte[]>() != null);
321
322             BCryptPropertyGetter<T> getter = null;
323             if (typeof(T) == typeof(SafeBCryptAlgorithmHandle)) {
324                 getter = new BCryptPropertyGetter<SafeBCryptAlgorithmHandle>(UnsafeNativeMethods.BCryptGetAlgorithmProperty)
325                     as BCryptPropertyGetter<T>;
326             }
327             else if (typeof(T) == typeof(SafeBCryptHashHandle)) {
328                 getter = new BCryptPropertyGetter<SafeBCryptHashHandle>(UnsafeNativeMethods.BCryptGetHashProperty)
329                     as BCryptPropertyGetter<T>;
330             }
331
332             Debug.Assert(getter != null, "Unknown handle type");
333
334             // Figure out how big the property is
335             int bufferSize = 0;
336             ErrorCode error = getter(algorithm, property, null, 0, ref bufferSize, 0);
337
338             if (error != ErrorCode.BufferToSmall && error != ErrorCode.Success) {
339                 throw new CryptographicException((int)error);
340             }
341
342             // Allocate the buffer, and return the property
343             Debug.Assert(bufferSize > 0, "bufferSize > 0");
344             byte[] buffer = new byte[bufferSize];
345             error = getter(algorithm, property, buffer, buffer.Length, ref bufferSize, 0);
346
347             if (error != ErrorCode.Success) {
348                 throw new CryptographicException((int)error);
349             }
350
351             return buffer;
352         }
353
354
355         /// <summary>
356         ///     Map an algorithm identifier to a key size and magic number
357         /// </summary>
358         internal static void MapAlgorithmIdToMagic(string algorithm,
359                                                    out KeyBlobMagicNumber algorithmMagic,
360                                                    out int keySize) {
361             Contract.Requires(!String.IsNullOrEmpty(algorithm));
362
363             switch (algorithm) {
364                 case AlgorithmName.ECDHP256:
365                     algorithmMagic = KeyBlobMagicNumber.ECDHPublicP256;
366                     keySize = 256;
367                     break;
368
369                 case AlgorithmName.ECDHP384:
370                     algorithmMagic = KeyBlobMagicNumber.ECDHPublicP384;
371                     keySize = 384;
372                     break;
373
374                 case AlgorithmName.ECDHP521:
375                     algorithmMagic = KeyBlobMagicNumber.ECDHPublicP521;
376                     keySize = 521;
377                     break;
378
379                 case AlgorithmName.ECDsaP256:
380                     algorithmMagic = KeyBlobMagicNumber.ECDsaPublicP256;
381                     keySize = 256;
382                     break;
383
384                 case AlgorithmName.ECDsaP384:
385                     algorithmMagic = KeyBlobMagicNumber.ECDsaPublicP384;
386                     keySize = 384;
387                     break;
388
389                 case AlgorithmName.ECDsaP521:
390                     algorithmMagic = KeyBlobMagicNumber.ECDsaPublicP521;
391                     keySize = 521;
392                     break;
393
394                 default:
395                     throw new ArgumentException(SR.GetString(SR.Cryptography_UnknownEllipticCurveAlgorithm));
396             }
397         }
398
399         /// <summary>
400         ///     Open a handle to an algorithm provider
401         /// </summary>
402         [System.Security.SecurityCritical]
403         internal static SafeBCryptAlgorithmHandle OpenAlgorithm(string algorithm, string implementation) {
404             Contract.Requires(!String.IsNullOrEmpty(algorithm));
405             Contract.Requires(!String.IsNullOrEmpty(implementation));
406             Contract.Ensures(Contract.Result<SafeBCryptAlgorithmHandle>() != null &&
407                              !Contract.Result<SafeBCryptAlgorithmHandle>().IsInvalid &&
408                              !Contract.Result<SafeBCryptAlgorithmHandle>().IsClosed);
409
410             SafeBCryptAlgorithmHandle algorithmHandle = null;
411             ErrorCode error = UnsafeNativeMethods.BCryptOpenAlgorithmProvider(out algorithmHandle,
412                                                                               algorithm,
413                                                                               implementation,
414                                                                               0);
415
416             if (error != ErrorCode.Success) {
417                 throw new CryptographicException((int)error);
418             }
419
420             return algorithmHandle;
421         }
422
423         [SecuritySafeCritical]
424         internal static SafeBCryptKeyHandle ImportAsymmetricPublicKey(X509Native.CERT_PUBLIC_KEY_INFO certPublicKeyInfo, int dwFlag) {
425             SafeBCryptKeyHandle keyHandle = null;            
426             int error = UnsafeNativeMethods.CryptImportPublicKeyInfoEx2(
427                                                         X509Native.X509_ASN_ENCODING,
428                                                         ref certPublicKeyInfo,
429                                                         dwFlag,
430                                                         IntPtr.Zero,
431                                                         out keyHandle);
432             if (error == 0) {
433                 throw new CryptographicException(Marshal.GetLastWin32Error());
434             }
435             return keyHandle;
436         }
437
438         [SecuritySafeCritical]
439         internal static byte[] ExportBCryptKey(SafeBCryptKeyHandle hKey, string blobType) {
440             byte[] keyBlob = null;
441             int length = 0;
442
443             ErrorCode error = UnsafeNativeMethods.BCryptExportKey(hKey, IntPtr.Zero, blobType, null, 0, ref length, 0);
444
445             if (error != ErrorCode.BufferToSmall && error != ErrorCode.Success)
446             {
447                 throw new CryptographicException(Marshal.GetLastWin32Error());
448             }
449
450             keyBlob = new byte[length];
451             error = UnsafeNativeMethods.BCryptExportKey(hKey, IntPtr.Zero, blobType, keyBlob, length, ref length, 0);
452             if (error != ErrorCode.Success) {
453                 throw new CryptographicException(Marshal.GetLastWin32Error());
454             }
455             return keyBlob;
456         }
457     }
458 }