Example #1
0
        private static unsafe byte[] ExportPkcs8KeyBlob(
            SafeNCryptKeyHandle keyHandle,
            string password,
            int kdfCount)
        {
            var pbeParams = new NativeMethods.NCrypt.PbeParams();

            NativeMethods.NCrypt.PbeParams *pbeParamsPtr = &pbeParams;

            var salt = new byte[NativeMethods.NCrypt.PbeParams.RgbSaltSize];

            RandomNumberGenerator.GetBytes(salt);

            pbeParams.Params.cbSalt = salt.Length;
            Marshal.Copy(salt, 0, (IntPtr)pbeParams.rgbSalt, salt.Length);
            pbeParams.Params.iIterations = kdfCount;
            var keyName = Guid.NewGuid().ToString("D");

            fixed(char *passwordPtr = password)
            fixed(char *keyNamePtr = keyName)
            fixed(byte *oidPtr     = s_pkcs12TripleDesOidBytes)
            {
                NativeMethods.NCrypt.NCryptBuffer *buffers =
                    stackalloc NativeMethods.NCrypt.NCryptBuffer[3];

                buffers[0] = new NativeMethods.NCrypt.NCryptBuffer
                {
                    BufferType = NativeMethods.NCrypt.BufferType.PkcsSecret,
                    cbBuffer   = checked (2 * (password.Length + 1)),
                    pvBuffer   = (IntPtr)passwordPtr,
                };

                if (buffers[0].pvBuffer == IntPtr.Zero)
                {
                    buffers[0].cbBuffer = 0;
                }

                buffers[1] = new NativeMethods.NCrypt.NCryptBuffer
                {
                    BufferType = NativeMethods.NCrypt.BufferType.PkcsAlgOid,
                    cbBuffer   = s_pkcs12TripleDesOidBytes.Length,
                    pvBuffer   = (IntPtr)oidPtr,
                };

                buffers[2] = new NativeMethods.NCrypt.NCryptBuffer
                {
                    BufferType = NativeMethods.NCrypt.BufferType.PkcsAlgParam,
                    cbBuffer   = sizeof(NativeMethods.NCrypt.PbeParams),
                    pvBuffer   = (IntPtr)pbeParamsPtr,
                };

                var desc = new NativeMethods.NCrypt.NCryptBufferDesc
                {
                    cBuffers  = 3,
                    pBuffers  = (IntPtr)buffers,
                    ulVersion = 0,
                };

                int result = NativeMethods.NCrypt.NCryptExportKey(
                    keyHandle,
                    IntPtr.Zero,
                    NCRYPT_PKCS8_PRIVATE_KEY_BLOB,
                    ref desc,
                    null,
                    0,
                    out int bytesNeeded,
                    0);

                if (result != 0)
                {
                    throw new Win32Exception(result);
                }

                byte[] exported = new byte[bytesNeeded];

                result = NativeMethods.NCrypt.NCryptExportKey(
                    keyHandle,
                    IntPtr.Zero,
                    NCRYPT_PKCS8_PRIVATE_KEY_BLOB,
                    ref desc,
                    exported,
                    exported.Length,
                    out bytesNeeded,
                    0);

                if (result != 0)
                {
                    throw new Win32Exception(result);
                }

                if (bytesNeeded != exported.Length)
                {
                    Array.Resize(ref exported, bytesNeeded);
                }


                NativeMethods.NCrypt.NCryptOpenStorageProvider(
                    out var safeNCryptProviderHandle,
                    MicrosoftSoftwareKeyStorageProvider,
                    0);

                NativeMethods.NCrypt.NCryptBuffer *buffers2 =
                    stackalloc NativeMethods.NCrypt.NCryptBuffer[4];

                buffers2[0] = new NativeMethods.NCrypt.NCryptBuffer
                {
                    BufferType = NativeMethods.NCrypt.BufferType.PkcsSecret,
                    cbBuffer   = checked (2 * (password.Length + 1)),
                    pvBuffer   = (IntPtr)passwordPtr,
                };

                if (buffers2[0].pvBuffer == IntPtr.Zero)
                {
                    buffers2[0].cbBuffer = 0;
                }

                buffers2[1] = new NativeMethods.NCrypt.NCryptBuffer
                {
                    BufferType = NativeMethods.NCrypt.BufferType.PkcsAlgOid,
                    cbBuffer   = s_pkcs12TripleDesOidBytes.Length,
                    pvBuffer   = (IntPtr)oidPtr,
                };

                buffers2[2] = new NativeMethods.NCrypt.NCryptBuffer
                {
                    BufferType = NativeMethods.NCrypt.BufferType.PkcsAlgParam,
                    cbBuffer   = sizeof(NativeMethods.NCrypt.PbeParams),
                    pvBuffer   = (IntPtr)pbeParamsPtr,
                };

                buffers2[3] = new NativeMethods.NCrypt.NCryptBuffer
                {
                    BufferType = NativeMethods.NCrypt.BufferType.PkcsKeyName,
                    cbBuffer   = checked (2 * (keyName.Length + 1)),
                    pvBuffer   = (IntPtr)keyNamePtr,
                };

                var desc2 = new NativeMethods.NCrypt.NCryptBufferDesc
                {
                    cBuffers  = 4,
                    pBuffers  = (IntPtr)buffers2,
                    ulVersion = 0,
                };

                result = NativeMethods.NCrypt.NCryptImportKey(
                    safeNCryptProviderHandle,
                    IntPtr.Zero,
                    NCRYPT_PKCS8_PRIVATE_KEY_BLOB,
                    ref desc2,
                    out var safeNCryptKeyHandle,
                    exported,
                    exported.Length,
                    NCRYPT_DO_NOT_FINALIZE_FLAG);

                if (result != 0)
                {
                    throw new Win32Exception(result);
                }

                var exportPolicyBytes = BitConverter.GetBytes(
                    (int)(CngExportPolicies.AllowExport |
                          CngExportPolicies.AllowPlaintextExport |
                          CngExportPolicies.AllowArchiving |
                          CngExportPolicies.AllowPlaintextArchiving));

                NativeMethods.NCrypt.NCryptSetProperty(
                    safeNCryptKeyHandle,
                    "Export Policy",
                    exportPolicyBytes,
                    exportPolicyBytes.Length,
                    CngPropertyOptions.Persist);

                NativeMethods.NCrypt.NCryptFinalizeKey(
                    safeNCryptKeyHandle,
                    0);

                using (var key2 = CngKey.Open(keyName))
                {
                    Trace.WriteLine(key2.ExportPolicy);

                    var plainTextBytes =
                        key2.Export(CngKeyBlobFormat.Pkcs8PrivateBlob);
                    key2.Delete();
                    return(plainTextBytes);
                }
            }
        }
Example #2
0
    private static unsafe byte[] ExportEncryptedPkcs8(
        CngKey cngKey,
        string password,
        int kdfCount)
    {
        var pbeParams = new NativeMethods.NCrypt.PbeParams();

        NativeMethods.NCrypt.PbeParams *pbeParamsPtr = &pbeParams;
        byte[] salt = new byte[NativeMethods.NCrypt.PbeParams.RgbSaltSize];
        using (RandomNumberGenerator rng = RandomNumberGenerator.Create())
        {
            rng.GetBytes(salt);
        }
        pbeParams.Params.cbSalt = salt.Length;
        Marshal.Copy(salt, 0, (IntPtr)pbeParams.rgbSalt, salt.Length);
        pbeParams.Params.iIterations = kdfCount;
        fixed(char *stringPtr = password)
        fixed(byte *oidPtr = s_pkcs12TripleDesOidBytes)
        {
            NativeMethods.NCrypt.NCryptBuffer *buffers =
                stackalloc NativeMethods.NCrypt.NCryptBuffer[3];
            buffers[0] = new NativeMethods.NCrypt.NCryptBuffer
            {
                BufferType = NativeMethods.NCrypt.BufferType.PkcsSecret,
                cbBuffer   = checked (2 * (password.Length + 1)),
                pvBuffer   = (IntPtr)stringPtr,
            };
            if (buffers[0].pvBuffer == IntPtr.Zero)
            {
                buffers[0].cbBuffer = 0;
            }
            buffers[1] = new NativeMethods.NCrypt.NCryptBuffer
            {
                BufferType = NativeMethods.NCrypt.BufferType.PkcsAlgOid,
                cbBuffer   = s_pkcs12TripleDesOidBytes.Length,
                pvBuffer   = (IntPtr)oidPtr,
            };
            buffers[2] = new NativeMethods.NCrypt.NCryptBuffer
            {
                BufferType = NativeMethods.NCrypt.BufferType.PkcsAlgParam,
                cbBuffer   = sizeof(NativeMethods.NCrypt.PbeParams),
                pvBuffer   = (IntPtr)pbeParamsPtr,
            };
            var desc = new NativeMethods.NCrypt.NCryptBufferDesc
            {
                cBuffers  = 3,
                pBuffers  = (IntPtr)buffers,
                ulVersion = 0,
            };

            using (var keyHandle = cngKey.Handle)
            {
                int result = NativeMethods.NCrypt.NCryptExportKey(
                    keyHandle,
                    IntPtr.Zero,
                    NCRYPT_PKCS8_PRIVATE_KEY_BLOB,
                    ref desc,
                    null,
                    0,
                    out int bytesNeeded,
                    0);
                if (result != 0)
                {
                    throw new Win32Exception(result);
                }
                byte[] exported = new byte[bytesNeeded];
                result = NativeMethods.NCrypt.NCryptExportKey(
                    keyHandle,
                    IntPtr.Zero,
                    NCRYPT_PKCS8_PRIVATE_KEY_BLOB,
                    ref desc,
                    exported,
                    exported.Length,
                    out bytesNeeded,
                    0);
                if (result != 0)
                {
                    throw new Win32Exception(result);
                }
                if (bytesNeeded != exported.Length)
                {
                    Array.Resize(ref exported, bytesNeeded);
                }
                return(exported);
            }
        }
    }