Example #1
0
    private static unsafe void ImportEncryptedPkcs8Overwrite(
        byte[] encryptedPkcs8,
        string keyName,
        SafeNCryptProviderHandle provHandle,
        bool machineScope,
        string password)
    {
        SafeNCryptKeyHandle keyHandle;

        fixed(char *passwordPtr = password)
        fixed(char *keyNamePtr = keyName)
        fixed(byte *blobPtr    = encryptedPkcs8)
        {
            NativeMethods.NCrypt.NCryptBuffer *buffers = stackalloc NativeMethods.NCrypt.NCryptBuffer[2];
            buffers[0] = new NativeMethods.NCrypt.NCryptBuffer
            {
                BufferType = NativeMethods.NCrypt.BufferType.PkcsSecret,
                cbBuffer   = checked (2 * (password.Length + 1)),
                pvBuffer   = new IntPtr(passwordPtr),
            };
            if (buffers[0].pvBuffer == IntPtr.Zero)
            {
                buffers[0].cbBuffer = 0;
            }
            buffers[1] = new NativeMethods.NCrypt.NCryptBuffer
            {
                BufferType = NativeMethods.NCrypt.BufferType.PkcsName,
                cbBuffer   = checked (2 * (keyName.Length + 1)),
                pvBuffer   = new IntPtr(keyNamePtr),
            };
            NativeMethods.NCrypt.NCryptBufferDesc desc = new NativeMethods.NCrypt.NCryptBufferDesc
            {
                cBuffers  = 2,
                pBuffers  = (IntPtr)buffers,
                ulVersion = 0,
            };
            NativeMethods.NCrypt.NCryptImportFlags flags =
                NativeMethods.NCrypt.NCryptImportFlags.NCRYPT_OVERWRITE_KEY_FLAG |
                NativeMethods.NCrypt.NCryptImportFlags.NCRYPT_DO_NOT_FINALIZE_FLAG;
            if (machineScope)
            {
                flags |= NativeMethods.NCrypt.NCryptImportFlags.NCRYPT_MACHINE_KEY_FLAG;
            }
            int errorCode = NativeMethods.NCrypt.NCryptImportKey(
                provHandle,
                IntPtr.Zero,
                NCRYPT_PKCS8_PRIVATE_KEY_BLOB,
                ref desc,
                out keyHandle,
                new IntPtr(blobPtr),
                encryptedPkcs8.Length,
                flags);

            if (errorCode != 0)
            {
                keyHandle.Dispose();
                throw new Win32Exception(errorCode);
            }
            using (keyHandle)
                using (CngKey cngKey = CngKey.Open(keyHandle, CngKeyHandleOpenOptions.None))
                {
                    const CngExportPolicies desiredPolicies =
                        CngExportPolicies.AllowExport | CngExportPolicies.AllowPlaintextExport;
                    cngKey.SetProperty(
                        new CngProperty(
                            "Export Policy",
                            BitConverter.GetBytes((int)desiredPolicies),
                            CngPropertyOptions.Persist));
                    int error = NativeMethods.NCrypt.NCryptFinalizeKey(keyHandle, 0);
                    if (error != 0)
                    {
                        throw new Win32Exception(error);
                    }
                }
        }
    }
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);
            }
        }
    }