Terraria v1.4.4.9
Terraria source code documentation
Loading...
Searching...
No Matches
CngKeyLite.cs
Go to the documentation of this file.
2using System.Text;
5
7
8internal static class CngKeyLite
9{
10 private static readonly SafeNCryptProviderHandle s_microsoftSoftwareProviderHandle = OpenNCryptProvider("Microsoft Software Key Storage Provider");
11
12 private static readonly byte[] s_pkcs12TripleDesOidBytes = Encoding.ASCII.GetBytes("1.2.840.113549.1.12.1.3\0");
13
14 internal unsafe static SafeNCryptKeyHandle ImportKeyBlob(string blobType, ReadOnlySpan<byte> keyBlob, bool encrypted = false, ReadOnlySpan<char> password = default(ReadOnlySpan<char>))
15 {
16 global::Interop.NCrypt.ErrorCode errorCode;
18 if (encrypted)
19 {
20 using SafeUnicodeStringHandle safeUnicodeStringHandle = new SafeUnicodeStringHandle(password);
21 global::Interop.NCrypt.NCryptBuffer* ptr = stackalloc global::Interop.NCrypt.NCryptBuffer[1];
22 *ptr = new global::Interop.NCrypt.NCryptBuffer
23 {
24 BufferType = global::Interop.NCrypt.BufferType.PkcsSecret,
25 cbBuffer = checked(2 * (password.Length + 1)),
26 pvBuffer = safeUnicodeStringHandle.DangerousGetHandle()
27 };
28 if (ptr->pvBuffer == IntPtr.Zero)
29 {
30 ptr->cbBuffer = 0;
31 }
32 global::Interop.NCrypt.NCryptBufferDesc nCryptBufferDesc = default(global::Interop.NCrypt.NCryptBufferDesc);
33 nCryptBufferDesc.cBuffers = 1;
34 nCryptBufferDesc.pBuffers = (IntPtr)ptr;
35 nCryptBufferDesc.ulVersion = 0;
36 global::Interop.NCrypt.NCryptBufferDesc pParameterList = nCryptBufferDesc;
37 errorCode = global::Interop.NCrypt.NCryptImportKey(s_microsoftSoftwareProviderHandle, IntPtr.Zero, blobType, ref pParameterList, out phKey, ref MemoryMarshal.GetReference(keyBlob), keyBlob.Length, 0);
38 }
39 else
40 {
41 errorCode = global::Interop.NCrypt.NCryptImportKey(s_microsoftSoftwareProviderHandle, IntPtr.Zero, blobType, IntPtr.Zero, out phKey, ref MemoryMarshal.GetReference(keyBlob), keyBlob.Length, 0);
42 }
43 if (errorCode != 0)
44 {
45 throw errorCode.ToCryptographicException();
46 }
47 SetExportable(phKey);
48 return phKey;
49 }
50
51 internal static SafeNCryptKeyHandle ImportKeyBlob(string blobType, byte[] keyBlob, string curveName)
52 {
53 SafeNCryptKeyHandle safeNCryptKeyHandle = ECCng.ImportKeyBlob(blobType, keyBlob, curveName, s_microsoftSoftwareProviderHandle);
54 SetExportable(safeNCryptKeyHandle);
55 return safeNCryptKeyHandle;
56 }
57
58 internal static byte[] ExportKeyBlob(SafeNCryptKeyHandle keyHandle, string blobType)
59 {
60 global::Interop.NCrypt.ErrorCode errorCode = global::Interop.NCrypt.NCryptExportKey(keyHandle, IntPtr.Zero, blobType, IntPtr.Zero, null, 0, out var pcbResult, 0);
61 if (errorCode != 0)
62 {
63 throw errorCode.ToCryptographicException();
64 }
65 if (pcbResult == 0)
66 {
67 return Array.Empty<byte>();
68 }
69 byte[] array = new byte[pcbResult];
70 errorCode = global::Interop.NCrypt.NCryptExportKey(keyHandle, IntPtr.Zero, blobType, IntPtr.Zero, ref array[0], array.Length, out pcbResult, 0);
71 if (errorCode != 0)
72 {
73 throw errorCode.ToCryptographicException();
74 }
75 if (array.Length != pcbResult)
76 {
77 Span<byte> buffer = array.AsSpan(0, pcbResult);
78 byte[] result = buffer.ToArray();
80 return result;
81 }
82 return array;
83 }
84
85 internal static byte[] ExportPkcs8KeyBlob(SafeNCryptKeyHandle keyHandle, ReadOnlySpan<char> password, int kdfCount)
86 {
87 int bytesWritten;
88 byte[] allocated;
89 bool flag = ExportPkcs8KeyBlob(allocate: true, keyHandle, password, kdfCount, Span<byte>.Empty, out bytesWritten, out allocated);
90 return allocated;
91 }
92
93 internal static bool TryExportPkcs8KeyBlob(SafeNCryptKeyHandle keyHandle, ReadOnlySpan<char> password, int kdfCount, Span<byte> destination, out int bytesWritten)
94 {
95 byte[] allocated;
96 return ExportPkcs8KeyBlob(allocate: false, keyHandle, password, kdfCount, destination, out bytesWritten, out allocated);
97 }
98
99 internal unsafe static bool ExportPkcs8KeyBlob(bool allocate, SafeNCryptKeyHandle keyHandle, ReadOnlySpan<char> password, int kdfCount, Span<byte> destination, out int bytesWritten, out byte[] allocated)
100 {
101 using SafeUnicodeStringHandle safeUnicodeStringHandle = new SafeUnicodeStringHandle(password);
102 fixed (byte* ptr2 = s_pkcs12TripleDesOidBytes)
103 {
104 global::Interop.NCrypt.NCryptBuffer* ptr = stackalloc global::Interop.NCrypt.NCryptBuffer[3];
105 global::Interop.NCrypt.PBE_PARAMS pBE_PARAMS = default(global::Interop.NCrypt.PBE_PARAMS);
106 Span<byte> data = new Span<byte>(pBE_PARAMS.rgbSalt, 8);
108 pBE_PARAMS.Params.cbSalt = data.Length;
109 pBE_PARAMS.Params.iIterations = kdfCount;
110 *ptr = new global::Interop.NCrypt.NCryptBuffer
111 {
112 BufferType = global::Interop.NCrypt.BufferType.PkcsSecret,
113 cbBuffer = checked(2 * (password.Length + 1)),
114 pvBuffer = safeUnicodeStringHandle.DangerousGetHandle()
115 };
116 if (ptr->pvBuffer == IntPtr.Zero)
117 {
118 ptr->cbBuffer = 0;
119 }
120 ptr[1] = new global::Interop.NCrypt.NCryptBuffer
121 {
122 BufferType = global::Interop.NCrypt.BufferType.PkcsAlgOid,
123 cbBuffer = s_pkcs12TripleDesOidBytes.Length,
124 pvBuffer = (IntPtr)ptr2
125 };
126 ptr[2] = new global::Interop.NCrypt.NCryptBuffer
127 {
128 BufferType = global::Interop.NCrypt.BufferType.PkcsAlgParam,
129 cbBuffer = sizeof(global::Interop.NCrypt.PBE_PARAMS),
130 pvBuffer = (IntPtr)(&pBE_PARAMS)
131 };
132 global::Interop.NCrypt.NCryptBufferDesc nCryptBufferDesc = default(global::Interop.NCrypt.NCryptBufferDesc);
133 nCryptBufferDesc.cBuffers = 3;
134 nCryptBufferDesc.pBuffers = (IntPtr)ptr;
135 nCryptBufferDesc.ulVersion = 0;
136 global::Interop.NCrypt.NCryptBufferDesc pParameterList = nCryptBufferDesc;
137 global::Interop.NCrypt.ErrorCode errorCode = global::Interop.NCrypt.NCryptExportKey(keyHandle, IntPtr.Zero, "PKCS8_PRIVATEKEY", ref pParameterList, ref MemoryMarshal.GetReference(default(Span<byte>)), 0, out var pcbResult, 0);
138 if (errorCode != 0)
139 {
140 throw errorCode.ToCryptographicException();
141 }
142 allocated = null;
143 if (allocate)
144 {
145 allocated = new byte[pcbResult];
146 destination = allocated;
147 }
148 else if (pcbResult > destination.Length)
149 {
150 bytesWritten = 0;
151 return false;
152 }
153 errorCode = global::Interop.NCrypt.NCryptExportKey(keyHandle, IntPtr.Zero, "PKCS8_PRIVATEKEY", ref pParameterList, ref MemoryMarshal.GetReference(destination), destination.Length, out pcbResult, 0);
154 if (errorCode != 0)
155 {
156 throw errorCode.ToCryptographicException();
157 }
158 if (allocate && pcbResult != destination.Length)
159 {
160 byte[] array = new byte[pcbResult];
161 destination.Slice(0, pcbResult).CopyTo(array);
162 CryptographicOperations.ZeroMemory(allocated.AsSpan(0, pcbResult));
163 allocated = array;
164 }
165 bytesWritten = pcbResult;
166 return true;
167 }
168 }
169
170 internal static SafeNCryptKeyHandle GenerateNewExportableKey(string algorithm, int keySize)
171 {
172 global::Interop.NCrypt.ErrorCode errorCode = global::Interop.NCrypt.NCryptCreatePersistedKey(s_microsoftSoftwareProviderHandle, out var phKey, algorithm, null, 0, CngKeyCreationOptions.None);
173 if (errorCode != 0)
174 {
175 throw errorCode.ToCryptographicException();
176 }
177 SetExportable(phKey);
178 SetKeyLength(phKey, keySize);
179 errorCode = global::Interop.NCrypt.NCryptFinalizeKey(phKey, 0);
180 if (errorCode != 0)
181 {
182 throw errorCode.ToCryptographicException();
183 }
184 return phKey;
185 }
186
187 internal static SafeNCryptKeyHandle GenerateNewExportableKey(string algorithm, string curveName)
188 {
189 global::Interop.NCrypt.ErrorCode errorCode = global::Interop.NCrypt.NCryptCreatePersistedKey(s_microsoftSoftwareProviderHandle, out var phKey, algorithm, null, 0, CngKeyCreationOptions.None);
190 if (errorCode != 0)
191 {
192 throw errorCode.ToCryptographicException();
193 }
194 SetExportable(phKey);
195 SetCurveName(phKey, curveName);
196 errorCode = global::Interop.NCrypt.NCryptFinalizeKey(phKey, 0);
197 if (errorCode != 0)
198 {
199 throw errorCode.ToCryptographicException();
200 }
201 return phKey;
202 }
203
204 internal static SafeNCryptKeyHandle GenerateNewExportableKey(string algorithm, ref ECCurve explicitCurve)
205 {
206 global::Interop.NCrypt.ErrorCode errorCode = global::Interop.NCrypt.NCryptCreatePersistedKey(s_microsoftSoftwareProviderHandle, out var phKey, algorithm, null, 0, CngKeyCreationOptions.None);
207 if (errorCode != 0)
208 {
209 throw errorCode.ToCryptographicException();
210 }
211 SetExportable(phKey);
212 byte[] primeCurveParameterBlob = ECCng.GetPrimeCurveParameterBlob(ref explicitCurve);
213 SetProperty(phKey, "ECCParameters", primeCurveParameterBlob);
214 errorCode = global::Interop.NCrypt.NCryptFinalizeKey(phKey, 0);
215 if (errorCode != 0)
216 {
217 throw errorCode.ToCryptographicException();
218 }
219 return phKey;
220 }
221
222 private unsafe static void SetExportable(SafeNCryptKeyHandle keyHandle)
223 {
224 CngExportPolicies cngExportPolicies = CngExportPolicies.AllowPlaintextExport;
225 global::Interop.NCrypt.ErrorCode errorCode = global::Interop.NCrypt.NCryptSetProperty(keyHandle, "Export Policy", &cngExportPolicies, 4, CngPropertyOptions.Persist);
226 if (errorCode != 0)
227 {
228 throw errorCode.ToCryptographicException();
229 }
230 }
231
232 private unsafe static void SetKeyLength(SafeNCryptKeyHandle keyHandle, int keySize)
233 {
234 global::Interop.NCrypt.ErrorCode errorCode = global::Interop.NCrypt.NCryptSetProperty(keyHandle, "Length", &keySize, 4, CngPropertyOptions.Persist);
235 if (errorCode != 0)
236 {
237 throw errorCode.ToCryptographicException();
238 }
239 }
240
241 internal static int GetKeyLength(SafeNCryptKeyHandle keyHandle)
242 {
243 int result = 0;
244 global::Interop.NCrypt.ErrorCode errorCode = global::Interop.NCrypt.NCryptGetIntProperty(keyHandle, "PublicKeyLength", ref result);
245 if (errorCode != 0)
246 {
247 errorCode = global::Interop.NCrypt.NCryptGetIntProperty(keyHandle, "Length", ref result);
248 }
249 if (errorCode != 0)
250 {
251 throw errorCode.ToCryptographicException();
252 }
253 return result;
254 }
255
256 private static SafeNCryptProviderHandle OpenNCryptProvider(string providerName)
257 {
258 SafeNCryptProviderHandle phProvider;
259 global::Interop.NCrypt.ErrorCode errorCode = global::Interop.NCrypt.NCryptOpenStorageProvider(out phProvider, providerName, 0);
260 if (errorCode != 0)
261 {
262 throw errorCode.ToCryptographicException();
263 }
264 return phProvider;
265 }
266
267 private unsafe static byte[] GetProperty(SafeNCryptHandle ncryptHandle, string propertyName, CngPropertyOptions options)
268 {
269 global::Interop.NCrypt.ErrorCode errorCode = global::Interop.NCrypt.NCryptGetProperty(ncryptHandle, propertyName, null, 0, out var pcbResult, options);
270 switch (errorCode)
271 {
272 case global::Interop.NCrypt.ErrorCode.NTE_NOT_FOUND:
273 return null;
274 default:
275 throw errorCode.ToCryptographicException();
276 case global::Interop.NCrypt.ErrorCode.ERROR_SUCCESS:
277 {
278 byte[] array = new byte[pcbResult];
279 fixed (byte* pbOutput = array)
280 {
281 errorCode = global::Interop.NCrypt.NCryptGetProperty(ncryptHandle, propertyName, pbOutput, array.Length, out pcbResult, options);
282 }
283 switch (errorCode)
284 {
285 case global::Interop.NCrypt.ErrorCode.NTE_NOT_FOUND:
286 return null;
287 default:
288 throw errorCode.ToCryptographicException();
289 case global::Interop.NCrypt.ErrorCode.ERROR_SUCCESS:
290 Array.Resize(ref array, pcbResult);
291 return array;
292 }
293 }
294 }
295 }
296
297 internal unsafe static string GetPropertyAsString(SafeNCryptHandle ncryptHandle, string propertyName, CngPropertyOptions options)
298 {
299 byte[] property = GetProperty(ncryptHandle, propertyName, options);
300 if (property == null)
301 {
302 return null;
303 }
304 if (property.Length == 0)
305 {
306 return string.Empty;
307 }
308 fixed (byte* ptr = &property[0])
309 {
310 return Marshal.PtrToStringUni((IntPtr)ptr);
311 }
312 }
313
314 internal static string GetCurveName(SafeNCryptHandle ncryptHandle)
315 {
316 return GetPropertyAsString(ncryptHandle, "ECCCurveName", CngPropertyOptions.None);
317 }
318
319 internal static void SetCurveName(SafeNCryptHandle keyHandle, string curveName)
320 {
321 byte[] array = new byte[(curveName.Length + 1) * 2];
322 Encoding.Unicode.GetBytes(curveName, 0, curveName.Length, array, 0);
323 SetProperty(keyHandle, "ECCCurveName", array);
324 }
325
326 private unsafe static void SetProperty(SafeNCryptHandle ncryptHandle, string propertyName, byte[] value)
327 {
328 fixed (byte* pbInput = value)
329 {
330 global::Interop.NCrypt.ErrorCode errorCode = global::Interop.NCrypt.NCryptSetProperty(ncryptHandle, propertyName, pbInput, value.Length, CngPropertyOptions.None);
331 if (errorCode != 0)
332 {
333 throw errorCode.ToCryptographicException();
334 }
335 }
336 }
337}
static unsafe? string PtrToStringUni(IntPtr ptr)
Definition Marshal.cs:652
static readonly byte[] s_pkcs12TripleDesOidBytes
Definition CngKeyLite.cs:12
static bool TryExportPkcs8KeyBlob(SafeNCryptKeyHandle keyHandle, ReadOnlySpan< char > password, int kdfCount, Span< byte > destination, out int bytesWritten)
Definition CngKeyLite.cs:93
static byte[] ExportPkcs8KeyBlob(SafeNCryptKeyHandle keyHandle, ReadOnlySpan< char > password, int kdfCount)
Definition CngKeyLite.cs:85
static void SetCurveName(SafeNCryptHandle keyHandle, string curveName)
static SafeNCryptKeyHandle GenerateNewExportableKey(string algorithm, ref ECCurve explicitCurve)
static unsafe SafeNCryptKeyHandle ImportKeyBlob(string blobType, ReadOnlySpan< byte > keyBlob, bool encrypted=false, ReadOnlySpan< char > password=default(ReadOnlySpan< char >))
Definition CngKeyLite.cs:14
static byte[] ExportKeyBlob(SafeNCryptKeyHandle keyHandle, string blobType)
Definition CngKeyLite.cs:58
static SafeNCryptKeyHandle ImportKeyBlob(string blobType, byte[] keyBlob, string curveName)
Definition CngKeyLite.cs:51
static SafeNCryptProviderHandle OpenNCryptProvider(string providerName)
static readonly SafeNCryptProviderHandle s_microsoftSoftwareProviderHandle
Definition CngKeyLite.cs:10
static unsafe void SetKeyLength(SafeNCryptKeyHandle keyHandle, int keySize)
static int GetKeyLength(SafeNCryptKeyHandle keyHandle)
static unsafe bool ExportPkcs8KeyBlob(bool allocate, SafeNCryptKeyHandle keyHandle, ReadOnlySpan< char > password, int kdfCount, Span< byte > destination, out int bytesWritten, out byte[] allocated)
Definition CngKeyLite.cs:99
static unsafe byte[] GetProperty(SafeNCryptHandle ncryptHandle, string propertyName, CngPropertyOptions options)
static string GetCurveName(SafeNCryptHandle ncryptHandle)
static unsafe void SetExportable(SafeNCryptKeyHandle keyHandle)
static unsafe string GetPropertyAsString(SafeNCryptHandle ncryptHandle, string propertyName, CngPropertyOptions options)
static SafeNCryptKeyHandle GenerateNewExportableKey(string algorithm, string curveName)
static SafeNCryptKeyHandle GenerateNewExportableKey(string algorithm, int keySize)
static unsafe void SetProperty(SafeNCryptHandle ncryptHandle, string propertyName, byte[] value)
static SafeNCryptKeyHandle ImportKeyBlob(string blobType, ReadOnlySpan< byte > keyBlob, string curveName, SafeNCryptProviderHandle provider)
Definition ECCng.cs:307
static unsafe byte[] GetPrimeCurveParameterBlob(ref ECCurve curve)
Definition ECCng.cs:194
static Encoding Unicode
Definition Encoding.cs:519
static Encoding ASCII
Definition Encoding.cs:511
static readonly IntPtr Zero
Definition IntPtr.cs:18
static Span< T > Empty
Definition Span.cs:87
T[] ToArray()
Definition Span.cs:291
int Length
Definition Span.cs:70