Skip to content
This repository was archived by the owner on Jan 23, 2023. It is now read-only.

Commit 1f20371

Browse files
committed
Merge pull request #2615 from AtsushiKan/cngkey
Implement System.Security.Cryptography.CngKey
2 parents b6db52e + 93e8bbf commit 1f20371

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

47 files changed

+4120
-392
lines changed
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
2+
Microsoft Visual Studio Solution File, Format Version 12.00
3+
# Visual Studio 14
4+
VisualStudioVersion = 14.0.23107.0
5+
MinimumVisualStudioVersion = 10.0.40219.1
6+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "System.Security.Cryptography.Cng", "src\System.Security.Cryptography.Cng.csproj", "{4C1BD451-6A99-45E7-9339-79C77C42EE9E}"
7+
EndProject
8+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "System.Security.Cryptography.Cng.Tests", "tests\System.Security.Cryptography.Cng.Tests.csproj", "{FF53459F-66F7-4F00-8D36-DF440CE18419}"
9+
EndProject
10+
Global
11+
GlobalSection(SolutionConfigurationPlatforms) = preSolution
12+
Debug|Any CPU = Debug|Any CPU
13+
Release|Any CPU = Release|Any CPU
14+
EndGlobalSection
15+
GlobalSection(ProjectConfigurationPlatforms) = postSolution
16+
{4C1BD451-6A99-45E7-9339-79C77C42EE9E}.Windows_Debug|Any CPU.ActiveCfg = Windows_Debug|Any CPU
17+
{4C1BD451-6A99-45E7-9339-79C77C42EE9E}.Windows_Debug|Any CPU.Build.0 = Windows_Debug|Any CPU
18+
{4C1BD451-6A99-45E7-9339-79C77C42EE9E}.Windows_Release|Any CPU.ActiveCfg = Windows_Release|Any CPU
19+
{4C1BD451-6A99-45E7-9339-79C77C42EE9E}.Windows_Release|Any CPU.Build.0 = Windows_Release|Any CPU
20+
{FF53459F-66F7-4F00-8D36-DF440CE18419}.Windows_Debug|Any CPU.ActiveCfg = Windows_Debug|Any CPU
21+
{FF53459F-66F7-4F00-8D36-DF440CE18419}.Windows_Debug|Any CPU.Build.0 = Windows_Debug|Any CPU
22+
{FF53459F-66F7-4F00-8D36-DF440CE18419}.Windows_Release|Any CPU.ActiveCfg = Windows_Release|Any CPU
23+
{FF53459F-66F7-4F00-8D36-DF440CE18419}.Windows_Release|Any CPU.Build.0 = Windows_Release|Any CPU
24+
EndGlobalSection
25+
GlobalSection(SolutionProperties) = preSolution
26+
HideSolutionNode = FALSE
27+
EndGlobalSection
28+
EndGlobal

src/System.Security.Cryptography.Cng/src/ContractStubs.cs

Lines changed: 0 additions & 203 deletions
This file was deleted.
Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
1+
// Copyright (c) Microsoft. All rights reserved.
2+
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
3+
4+
using System;
5+
using System.Diagnostics;
6+
using System.Globalization;
7+
using System.Security.Cryptography;
8+
using System.Runtime.InteropServices;
9+
10+
using Microsoft.Win32.SafeHandles;
11+
12+
using ErrorCode = Interop.NCrypt.ErrorCode;
13+
14+
namespace Internal.Cryptography
15+
{
16+
internal static class Helpers
17+
{
18+
public static byte[] CloneByteArray(this byte[] src)
19+
{
20+
return (byte[])(src.Clone());
21+
}
22+
23+
//
24+
// The C# construct
25+
//
26+
// fixed (byte* p = new byte[0])
27+
//
28+
// sets "p" to 0 rather than a valid address. Sometimes, we actually want a non-NULL pointer instead. (Some CNG apis actually care whether the buffer pointer is
29+
// NULL or not, even if the accompanying size argument is 0.)
30+
//
31+
// This helper enables the syntax:
32+
//
33+
// fixed (byte* p = new byte[0].MapZeroLengthArrayToNonNullPointer())
34+
//
35+
// which always sets "p" to a non-NULL pointer for a non-null byte array.
36+
//
37+
public static byte[] MapZeroLengthArrayToNonNullPointer(this byte[] src)
38+
{
39+
if (src != null && src.Length == 0)
40+
return new byte[1];
41+
return src;
42+
}
43+
44+
public static CryptographicException ToCryptographicException(this ErrorCode errorCode)
45+
{
46+
return new CryptographicException((int)errorCode);
47+
}
48+
49+
public static SafeNCryptProviderHandle OpenStorageProvider(this CngProvider provider)
50+
{
51+
string providerName = provider.Provider;
52+
SafeNCryptProviderHandle providerHandle;
53+
ErrorCode errorCode = Interop.NCrypt.NCryptOpenStorageProvider(out providerHandle, providerName, 0);
54+
if (errorCode != ErrorCode.ERROR_SUCCESS)
55+
throw errorCode.ToCryptographicException();
56+
return providerHandle;
57+
}
58+
59+
/// <summary>
60+
/// Returns a CNG key property.
61+
/// </summary>
62+
/// <returns>
63+
/// null - if property not defined on key.
64+
/// throws - for any other type of error.
65+
/// </returns>
66+
public static byte[] GetProperty(this SafeNCryptHandle ncryptHandle, string propertyName, CngPropertyOptions options)
67+
{
68+
unsafe
69+
{
70+
int numBytesNeeded;
71+
ErrorCode errorCode = Interop.NCrypt.NCryptGetProperty(ncryptHandle, propertyName, null, 0, out numBytesNeeded, options);
72+
if (errorCode == ErrorCode.NTE_NOT_FOUND)
73+
return null;
74+
if (errorCode != ErrorCode.ERROR_SUCCESS)
75+
throw errorCode.ToCryptographicException();
76+
77+
byte[] propertyValue = new byte[numBytesNeeded];
78+
fixed (byte* pPropertyValue = propertyValue)
79+
{
80+
errorCode = Interop.NCrypt.NCryptGetProperty(ncryptHandle, propertyName, pPropertyValue, numBytesNeeded, out numBytesNeeded, options);
81+
}
82+
if (errorCode == ErrorCode.NTE_NOT_FOUND)
83+
return null;
84+
if (errorCode != ErrorCode.ERROR_SUCCESS)
85+
throw errorCode.ToCryptographicException();
86+
87+
return propertyValue;
88+
}
89+
}
90+
91+
/// <summary>
92+
/// Retrieve a well-known CNG string property. (Note: desktop compat: this helper likes to return special values rather than throw exceptions for missing
93+
/// or ill-formatted property values. Only use it for well-known properties that are unlikely to be ill-formatted.)
94+
/// </summary>
95+
public static string GetPropertyAsString(this SafeNCryptHandle ncryptHandle, string propertyName, CngPropertyOptions options)
96+
{
97+
byte[] value = ncryptHandle.GetProperty(propertyName, options);
98+
if (value == null)
99+
return null; // Desktop compat: return null if key not present.
100+
if (value.Length == 0)
101+
return string.Empty; // Desktop compat: return empty if property value is 0-length.
102+
unsafe
103+
{
104+
fixed (byte* pValue = value)
105+
{
106+
string valueAsString = Marshal.PtrToStringUni((IntPtr)pValue);
107+
return valueAsString;
108+
}
109+
}
110+
}
111+
112+
/// <summary>
113+
/// Retrieve a well-known CNG dword property. (Note: desktop compat: this helper likes to return special values rather than throw exceptions for missing
114+
/// or ill-formatted property values. Only use it for well-known properties that are unlikely to be ill-formatted.)
115+
/// </summary>
116+
public static int GetPropertyAsDword(this SafeNCryptHandle ncryptHandle, string propertyName, CngPropertyOptions options)
117+
{
118+
byte[] value = ncryptHandle.GetProperty(propertyName, options);
119+
if (value == null)
120+
return 0; // Desktop compat: return 0 if key not present.
121+
return BitConverter.ToInt32(value, 0);
122+
}
123+
124+
/// <summary>
125+
/// Retrieve a well-known CNG pointer property. (Note: desktop compat: this helper likes to return special values rather than throw exceptions for missing
126+
/// or ill-formatted property values. Only use it for well-known properties that are unlikely to be ill-formatted.)
127+
/// </summary>
128+
public static IntPtr GetPropertyAsIntPtr(this SafeNCryptHandle ncryptHandle, string propertyName, CngPropertyOptions options)
129+
{
130+
unsafe
131+
{
132+
int numBytesRequired;
133+
IntPtr value;
134+
ErrorCode errorCode = Interop.NCrypt.NCryptGetProperty(ncryptHandle, propertyName, &value, IntPtr.Size, out numBytesRequired, options);
135+
if (errorCode == ErrorCode.NTE_NOT_FOUND)
136+
return IntPtr.Zero;
137+
if (errorCode != ErrorCode.ERROR_SUCCESS)
138+
throw errorCode.ToCryptographicException();
139+
return value;
140+
}
141+
}
142+
}
143+
}
144+
145+
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
// Copyright (c) Microsoft. All rights reserved.
2+
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
3+
4+
using System;
5+
using System.Diagnostics;
6+
7+
namespace Internal.Cryptography
8+
{
9+
/// <summary>
10+
/// Well known names of key properties
11+
/// </summary>
12+
internal static class KeyPropertyName
13+
{
14+
internal const string Algorithm = "Algorithm Name"; // NCRYPT_ALGORITHM_PROPERTY
15+
internal const string AlgorithmGroup = "Algorithm Group"; // NCRYPT_ALGORITHM_GROUP_PROPERTY
16+
internal const string ExportPolicy = "Export Policy"; // NCRYPT_EXPORT_POLICY_PROPERTY
17+
internal const string KeyType = "Key Type"; // NCRYPT_KEY_TYPE_PROPERTY
18+
internal const string KeyUsage = "Key Usage"; // NCRYPT_KEY_USAGE_PROPERTY
19+
internal const string Length = "Length"; // NCRYPT_LENGTH_PROPERTY
20+
internal const string Name = "Name"; // NCRYPT_NAME_PROPERTY
21+
internal const string ParentWindowHandle = "HWND Handle"; // NCRYPT_WINDOW_HANDLE_PROPERTY
22+
internal const string ProviderHandle = "Provider Handle"; // NCRYPT_PROVIDER_HANDLE_PROPERTY
23+
internal const string UIPolicy = "UI Policy"; // NCRYPT_UI_POLICY_PROPERTY
24+
internal const string UniqueName = "Unique Name"; // NCRYPT_UNIQUE_NAME_PROPERTY
25+
internal const string UseContext = "Use Context"; // NCRYPT_USE_CONTEXT_PROPERTY
26+
27+
//
28+
// Properties defined by the CLR
29+
//
30+
31+
/// <summary>
32+
/// Is the key a CLR created ephemeral key, it will contain a single byte with value 1 if the
33+
/// key was created by the CLR as an ephemeral key.
34+
/// </summary>
35+
internal const string ClrIsEphemeral = "CLR IsEphemeral";
36+
}
37+
}
38+
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
// Copyright (c) Microsoft. All rights reserved.
2+
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
3+
4+
using System;
5+
using System.Diagnostics;
6+
7+
namespace Internal.Cryptography
8+
{
9+
/// <summary>
10+
/// Well known names of provider properties
11+
/// </summary>
12+
internal static class ProviderPropertyName
13+
{
14+
internal const string Name = "Name"; // NCRYPT_NAME_PROPERTY
15+
}
16+
}
17+
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
// Copyright (c) Microsoft. All rights reserved.
2+
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
3+
4+
internal static partial class Interop
5+
{
6+
internal static class Libraries
7+
{
8+
internal const string NCrypt = "ncrypt.dll";
9+
}
10+
}
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
// Copyright (c) Microsoft. All rights reserved.
2+
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
3+
4+
using System;
5+
using System.Diagnostics;
6+
using System.Diagnostics.Contracts;
7+
using System.Runtime.InteropServices;
8+
using System.Security.Cryptography;
9+
10+
using Microsoft.Win32.SafeHandles;
11+
12+
internal static partial class Interop
13+
{
14+
internal static partial class NCrypt
15+
{
16+
17+
[DllImport(Interop.Libraries.NCrypt, CharSet = CharSet.Unicode)]
18+
internal static extern ErrorCode NCryptOpenStorageProvider(out SafeNCryptProviderHandle phProvider, string pszProviderName, int dwFlags);
19+
20+
[DllImport(Interop.Libraries.NCrypt, CharSet = CharSet.Unicode)]
21+
internal static extern ErrorCode NCryptOpenKey(SafeNCryptProviderHandle hProvider, out SafeNCryptKeyHandle phKey, string pszKeyName, int dwLegacyKeySpec, CngKeyOpenOptions dwFlags);
22+
23+
[DllImport(Interop.Libraries.NCrypt, CharSet = CharSet.Unicode)]
24+
internal static extern ErrorCode NCryptImportKey(SafeNCryptProviderHandle hProvider, IntPtr hImportKey, string pszBlobType, IntPtr pParameterList, [Out] out SafeNCryptKeyHandle phKey, [In] byte[] pbData, int cbData, int dwFlags);
25+
26+
[DllImport(Interop.Libraries.NCrypt, CharSet = CharSet.Unicode)]
27+
internal static extern ErrorCode NCryptExportKey(SafeNCryptKeyHandle hKey, IntPtr hExportKey, string pszBlobType, IntPtr pParameterList, [Out] byte[] pbOutput, int cbOutput, [Out] out int pcbResult, int dwFlags);
28+
29+
[DllImport(Interop.Libraries.NCrypt, CharSet = CharSet.Unicode)]
30+
internal static extern ErrorCode NCryptDeleteKey(SafeNCryptKeyHandle hKey, int dwFlags);
31+
32+
[DllImport(Interop.Libraries.NCrypt, CharSet = CharSet.Unicode)]
33+
internal static extern ErrorCode NCryptFreeObject(IntPtr hObject);
34+
35+
[DllImport(Interop.Libraries.NCrypt, CharSet = CharSet.Unicode)]
36+
internal static extern unsafe ErrorCode NCryptGetProperty(SafeNCryptHandle hObject, string pszProperty, [Out] void* pbOutput, int cbOutput, out int pcbResult, CngPropertyOptions dwFlags);
37+
38+
[DllImport(Interop.Libraries.NCrypt, CharSet = CharSet.Unicode)]
39+
internal static extern unsafe ErrorCode NCryptSetProperty(SafeNCryptHandle hObject, string pszProperty, [In] void* pbInput, int cbInput, CngPropertyOptions dwFlags);
40+
41+
[DllImport(Interop.Libraries.NCrypt, CharSet = CharSet.Unicode)]
42+
internal static extern ErrorCode NCryptCreatePersistedKey(SafeNCryptProviderHandle hProvider, out SafeNCryptKeyHandle phKey, string pszAlgId, string pszKeyName, int dwLegacyKeySpec, CngKeyCreationOptions dwFlags);
43+
44+
[DllImport(Interop.Libraries.NCrypt, CharSet = CharSet.Unicode)]
45+
internal static extern ErrorCode NCryptFinalizeKey(SafeNCryptKeyHandle hKey, int dwFlags);
46+
47+
/// <summary>
48+
/// Result codes from NCrypt APIs
49+
/// </summary>
50+
internal enum ErrorCode : int
51+
{
52+
ERROR_SUCCESS = 0,
53+
NTE_BAD_SIGNATURE = unchecked((int)0x80090006),
54+
NTE_NOT_FOUND = unchecked((int)0x80090011),
55+
NTE_BAD_KEYSET = unchecked((int)0x80090016),
56+
NTE_INVALID_PARAMETER = unchecked((int)0x80090027),
57+
NTE_BUFFER_TOO_SMALL = unchecked((int)0x80090028),
58+
NTE_NO_MORE_ITEMS = unchecked((int)0x8009002a),
59+
E_FAIL = unchecked((int)0x80004005),
60+
}
61+
62+
[StructLayout(LayoutKind.Sequential)]
63+
internal struct NCRYPT_UI_POLICY
64+
{
65+
public int dwVersion;
66+
public CngUIProtectionLevels dwFlags;
67+
public IntPtr pszCreationTitle;
68+
public IntPtr pszFriendlyName;
69+
public IntPtr pszDescription;
70+
}
71+
}
72+
}

0 commit comments

Comments
 (0)