public byte[] GetPrivateKeyBlob(IntPtr context, KeyDerivation derive) { bool result, shouldFree = false; NativeMethods.KeySpec addInfo = 0; IntPtr hProv = IntPtr.Zero, hExportKey = IntPtr.Zero, phSessionKey = IntPtr.Zero, userKey = IntPtr.Zero; try { result = NativeMethods.CryptAcquireCertificatePrivateKey(context, 0, IntPtr.Zero, ref hProv, ref addInfo, ref shouldFree); if (!result) { throw new Win32Exception(Marshal.GetLastWin32Error()); } result = NativeMethods.CryptGetUserKey(hProv, (uint)addInfo, ref userKey); if (!result) { throw new Win32Exception(Marshal.GetLastWin32Error()); } CheckPermission(userKey); result = NativeMethods.CryptGenKey(hProv, EphemAlgId, 0, out phSessionKey); if (!result) { throw new Win32Exception(Marshal.GetLastWin32Error()); } uint dhOIDsz = 50; var dhOID = new byte[dhOIDsz]; result = NativeMethods.CryptGetKeyParam(phSessionKey, NativeMethods.KP_DHOID, dhOID, ref dhOIDsz, 0); if (!result) { throw new Win32Exception(Marshal.GetLastWin32Error()); } dhOID = dhOID.Take((int)dhOIDsz - 1).ToArray(); var dhOIDstr = Encoding.ASCII.GetString(dhOID); uint hashOIDsz = 50; var hashOID = new byte[hashOIDsz]; result = NativeMethods.CryptGetKeyParam(phSessionKey, NativeMethods.KP_HASHOID, hashOID, ref hashOIDsz, 0); if (!result) { throw new Win32Exception(Marshal.GetLastWin32Error()); } hashOID = hashOID.Take((int)hashOIDsz - 1).ToArray(); var hashOIDstr = Encoding.ASCII.GetString(hashOID); uint pbdatalen = 0; result = NativeMethods.CryptExportKey(phSessionKey, IntPtr.Zero, NativeMethods.PUBLICKEYBLOB, 0, null, ref pbdatalen); if (!result) { throw new Win32Exception(Marshal.GetLastWin32Error()); } SessionKey = new byte[pbdatalen]; result = NativeMethods.CryptExportKey(phSessionKey, IntPtr.Zero, NativeMethods.PUBLICKEYBLOB, 0, SessionKey, ref pbdatalen); if (!result) { throw new Win32Exception(Marshal.GetLastWin32Error()); } var blob = new CRYPT_PUBLICKEYBLOB { reserved = 0, bType = 6, aiKeyAlg = (uint)KeyAlgId, bVersion = 0x20, Magic = NativeMethods.GR3410_1_MAGIC, BitLen = PublicKeyLength }; var dhOid = new DerObjectIdentifier(dhOIDstr); var hashOid = new DerObjectIdentifier(hashOIDstr); var seq = new DerSequence(dhOid, hashOid); var keyData = seq.GetDerEncoded(); Array.Resize(ref keyData, 24); blob.KeyData1 = BitConverter.ToUInt64(keyData, 0); blob.KeyData2 = BitConverter.ToUInt64(keyData, 8); blob.KeyData3 = BitConverter.ToUInt64(keyData, 16); var blobData = blob.GetBytes(); var pbdata2 = new byte[BlobLength]; for (int i = 0; i < KeyOffset; ++i) { pbdata2[i] = blobData[i]; } derive.Init(dhOid, hashOid); var genkey = derive.GetPublicKeyBytes(); for (int i = 0, j = KeyOffset; i < genkey.Length; ++i, ++j) { pbdata2[j] = genkey[i]; } result = NativeMethods.CryptImportKey(hProv, pbdata2, BlobLength, phSessionKey, 0, ref hExportKey); if (!result) { throw new Win32Exception(Marshal.GetLastWin32Error()); } result = NativeMethods.CryptSetKeyParam(hExportKey, (int)NativeMethods.KP_ALGID, BitConverter.GetBytes((uint)ExportAlgId), 0); if (!result) { throw new Win32Exception(Marshal.GetLastWin32Error()); } uint pkSize = 0; result = NativeMethods.CryptExportKey(userKey, hExportKey, NativeMethods.PRIVATEKEYBLOB, 0, null, ref pkSize); if (!result) { throw new Win32Exception(Marshal.GetLastWin32Error()); } var ret = new byte[pkSize]; result = NativeMethods.CryptExportKey(userKey, hExportKey, NativeMethods.PRIVATEKEYBLOB, 0, ret, ref pkSize); if (!result) { throw new Win32Exception(Marshal.GetLastWin32Error()); } return(ret); } catch (Win32Exception e) { throw new CryptographicException(e.Message, e); } finally { if (shouldFree) { NativeMethods.CryptReleaseContext(hProv, 0); } if (hExportKey != IntPtr.Zero) { NativeMethods.CryptDestroyKey(hExportKey); } if (phSessionKey != IntPtr.Zero) { NativeMethods.CryptDestroyKey(phSessionKey); } if (userKey != IntPtr.Zero) { NativeMethods.CryptDestroyKey(userKey); } } }
private static void ExportPrivateKey(SafeHandle context, byte[] genkey, out byte[] sessionKeyData, out byte[] privKeyData) { bool result, shouldFree = false; NativeMethods.KeySpec addInfo = 0; IntPtr provOrKey = IntPtr.Zero, hExportKey = IntPtr.Zero, phSessionKey = IntPtr.Zero, provInfoPtr = IntPtr.Zero, userKey = IntPtr.Zero; try { result = NativeMethods.CryptAcquireCertificatePrivateKey(context, 0, IntPtr.Zero, ref provOrKey, ref addInfo, ref shouldFree); if (!result) { throw new Win32Exception(Marshal.GetLastWin32Error()); } uint pcbData = 0; result = NativeMethods.CertGetCertificateContextProperty(context, NativeMethods.CERT_KEY_PROV_INFO_PROP_ID, provInfoPtr, ref pcbData); if (!result) { throw new Win32Exception(Marshal.GetLastWin32Error()); } provInfoPtr = Marshal.AllocHGlobal((int)pcbData); result = NativeMethods.CertGetCertificateContextProperty(context, NativeMethods.CERT_KEY_PROV_INFO_PROP_ID, provInfoPtr, ref pcbData); if (!result) { throw new Win32Exception(Marshal.GetLastWin32Error()); } var provInfo = (NativeMethods.CRYPT_KEY_PROV_INFO)Marshal.PtrToStructure(provInfoPtr, typeof(NativeMethods.CRYPT_KEY_PROV_INFO)); result = NativeMethods.CryptGetUserKey(provOrKey, (uint)addInfo, ref userKey); if (!result) { throw new Win32Exception(Marshal.GetLastWin32Error()); } CheckPermission(userKey); result = NativeMethods.CryptGenKey(provOrKey, NativeMethods.ALG_ID.CALG_DH_EL_EPHEM, 0, out phSessionKey); if (!result) { throw new Win32Exception(Marshal.GetLastWin32Error()); } uint pbdatalen = 100; sessionKeyData = new byte[pbdatalen]; result = NativeMethods.CryptExportKey(phSessionKey, IntPtr.Zero, NativeMethods.PUBLICKEYBLOB, 0, sessionKeyData, ref pbdatalen); if (!result) { throw new Win32Exception(Marshal.GetLastWin32Error()); } var blob = new CRYPT_PUBLICKEYBLOB { reserved = 0, bType = 6, aiKeyAlg = (uint)NativeMethods.ALG_ID.CALG_GR3410EL, bVersion = 0x20, Magic = NativeMethods.GR3410_1_MAGIC, BitLen = 512, // bASN1GostR3410_94_PublicKeyParameters KeyData1 = 0x07061230, KeyData2 = 0x0203852A, KeyData3 = 0x06002402, KeyData4 = 0x03852A07, KeyData5 = 0x011E0202 }; var blobData = blob.GetBytes(); var pbdata2 = new byte[100]; for (int i = 0; i < blobData.Length; ++i) { pbdata2[i] = blobData[i]; } for (int i = 0, j = 36; i < genkey.Length; ++i, ++j) { pbdata2[j] = genkey[i]; } result = NativeMethods.CryptImportKey(provOrKey, pbdata2, pbdatalen, phSessionKey, 0, ref hExportKey); if (!result) { throw new Win32Exception(Marshal.GetLastWin32Error()); } // export wrapped key var alg = BitConverter.GetBytes((uint)NativeMethods.ALG_ID.CALG_PRO_EXPORT); result = NativeMethods.CryptSetKeyParam(hExportKey, (int)NativeMethods.KP_ALGID, alg, 0); if (!result) { throw new Win32Exception(Marshal.GetLastWin32Error()); } uint pkSize = 0; result = NativeMethods.CryptExportKey(userKey, hExportKey, NativeMethods.PRIVATEKEYBLOB, 0, null, ref pkSize); if (!result) { throw new Win32Exception(Marshal.GetLastWin32Error()); } privKeyData = new byte[pkSize]; result = NativeMethods.CryptExportKey(userKey, hExportKey, NativeMethods.PRIVATEKEYBLOB, 0, privKeyData, ref pkSize); if (!result) { throw new Win32Exception(Marshal.GetLastWin32Error()); } } catch (Win32Exception e) { throw new CryptographicException(e.Message, e); } finally { if (shouldFree) { NativeMethods.CryptReleaseContext(provOrKey, 0); } if (provInfoPtr != IntPtr.Zero) { Marshal.FreeHGlobal(provInfoPtr); } if (hExportKey != IntPtr.Zero) { NativeMethods.CryptDestroyKey(hExportKey); } if (phSessionKey != IntPtr.Zero) { NativeMethods.CryptDestroyKey(phSessionKey); } if (userKey != IntPtr.Zero) { NativeMethods.CryptDestroyKey(userKey); } } }