Esempio n. 1
0
        public static CngKey ToECDHCngKey(this byte[] publicKey)
        {
            var key = publicKey.Length == 64 ? ByteHelper.Combine(P256PublicMagic, publicKey) : publicKey;

            return(CngKey.Import(key, CngKeyBlobFormat.EccPublicBlob));
        }
Esempio n. 2
0
        public static unsafe byte[] ForceExport(this CngKey key, CngKeyBlobFormat format)
        {
            if ((key.ExportPolicy & CngExportPolicies.AllowPlaintextExport) != 0)
            {
                return(key.Export(format));
            }

            // The key is not exportable, lets hack. Thanks @bartonjs
            // https://stackoverflow.com/questions/57269726/x509certificate2-import-with-ncrypt-allow-plaintext-export-flag
            // https://stackoverflow.com/questions/55236230/export-private-key-pkcs8-of-cng-rsa-certificate-with-oldschool-net

            string blobType = "PKCS8_PRIVATEKEY";

            try
            {
                byte[] exported;

                fixed(byte *oidPtr = CryptNativeHelpers.PKCS12_3DES_OID)
                {
                    var salt      = ByteHelper.GetRandom(CryptNativeHelpers.NCrypt.PbeParams.RgbSaltSize);
                    var pbeParams = new CryptNativeHelpers.NCrypt.PbeParams();

                    pbeParams.Params.iIterations = 1;
                    pbeParams.Params.cbSalt      = salt.Length;
                    Marshal.Copy(salt, 0, (IntPtr)pbeParams.rgbSalt, salt.Length);

                    var buffers = stackalloc CryptNativeHelpers.NCrypt.NCryptBuffer[3];

                    buffers[0] = new CryptNativeHelpers.NCrypt.NCryptBuffer
                    {
                        BufferType = CryptNativeHelpers.NCrypt.BufferType.PkcsSecret,
                        cbBuffer   = 0,
                        pvBuffer   = IntPtr.Zero,
                    };
                    buffers[1] = new CryptNativeHelpers.NCrypt.NCryptBuffer
                    {
                        BufferType = CryptNativeHelpers.NCrypt.BufferType.PkcsAlgOid,
                        cbBuffer   = CryptNativeHelpers.PKCS12_3DES_OID.Length,
                        pvBuffer   = (IntPtr)oidPtr,
                    };
                    buffers[2] = new CryptNativeHelpers.NCrypt.NCryptBuffer
                    {
                        BufferType = CryptNativeHelpers.NCrypt.BufferType.PkcsAlgParam,
                        cbBuffer   = sizeof(CryptNativeHelpers.NCrypt.PbeParams),
                        pvBuffer   = (IntPtr)(&pbeParams),
                    };
                    var desc = new CryptNativeHelpers.NCrypt.NCryptBufferDesc
                    {
                        cBuffers  = 3,
                        pBuffers  = (IntPtr)buffers,
                        ulVersion = 0,
                    };

                    if (CryptNativeHelpers.NCrypt.NCryptExportKey(key.Handle, IntPtr.Zero, blobType, ref desc, null, 0, out int bytesNeeded, 0) != 0)
                    {
                        return(null);
                    }

                    exported = new byte[bytesNeeded];
                    if (CryptNativeHelpers.NCrypt.NCryptExportKey(key.Handle, IntPtr.Zero, blobType, ref desc, exported, exported.Length, out bytesNeeded, 0) != 0)
                    {
                        return(null);
                    }
                }

                fixed(char *keyNamePtr = key.KeyName)
                fixed(byte *blobPtr = exported)
                {
                    var buffers = stackalloc CryptNativeHelpers.NCrypt.NCryptBuffer[2];

                    buffers[0] = new CryptNativeHelpers.NCrypt.NCryptBuffer
                    {
                        BufferType = CryptNativeHelpers.NCrypt.BufferType.PkcsSecret,
                        cbBuffer   = 0,
                        pvBuffer   = IntPtr.Zero,
                    };
                    buffers[1] = new CryptNativeHelpers.NCrypt.NCryptBuffer
                    {
                        BufferType = CryptNativeHelpers.NCrypt.BufferType.PkcsName,
                        cbBuffer   = checked (2 * (key.KeyName.Length + 1)),
                        pvBuffer   = new IntPtr(keyNamePtr),
                    };
                    var desc = new CryptNativeHelpers.NCrypt.NCryptBufferDesc
                    {
                        cBuffers  = 2,
                        pBuffers  = (IntPtr)buffers,
                        ulVersion = 0,
                    };

                    SafeNCryptKeyHandle keyHandle;

                    if (CryptNativeHelpers.NCrypt.NCryptImportKey(key.ProviderHandle, IntPtr.Zero, blobType, ref desc, out keyHandle, new IntPtr(blobPtr), exported.Length,
                                                                  CryptNativeHelpers.NCrypt.NCryptImportFlags.NCRYPT_OVERWRITE_KEY_FLAG | CryptNativeHelpers.NCrypt.NCryptImportFlags.NCRYPT_DO_NOT_FINALIZE_FLAG) != 0)
                    {
                        keyHandle.Dispose();
                        return(null);
                    }

                    using (keyHandle)
                        using (CngKey cngKey = CngKey.Open(keyHandle, CngKeyHandleOpenOptions.None))
                        {
                            cngKey.SetProperty(new CngProperty("Export Policy", BitConverter.GetBytes((int)CngExportPolicies.AllowPlaintextExport), CngPropertyOptions.Persist));

                            if (CryptNativeHelpers.NCrypt.NCryptFinalizeKey(keyHandle, 0) != 0)
                            {
                                return(null);
                            }

                            return(cngKey.Export(format));
                        }
                }
            }
            catch (Exception)
            {
                return(null);
            }
        }