Skip to content

Instantly share code, notes, and snippets.

@larsw
Last active April 26, 2018 11:22
Show Gist options
  • Save larsw/2c45147a242ceb079f5d to your computer and use it in GitHub Desktop.
Save larsw/2c45147a242ceb079f5d to your computer and use it in GitHub Desktop.
Stuff that stopped working in Win10 but works in Win7/Win8.1. Running on NET 4.6 on both Win7/8.1 and Win10.
// reference xunit
// reference BouncyCastle
// reference Security.Cryptography.dll (CLR Security project @ Codeplex)
public static byte[] ConvertToNCryptEccPrivateBlob(BigInteger d, ECPoint q)
{
// from bcrypt.h: #define BCRYPT_ECDSA_PRIVATE_P384_MAGIC 0x34534345 // ECS4
var magic = new byte[] { 0x45, 0x43, 0x53, 0x34 };
var len = new byte[] { 0x30, 0, 0, 0 }; // key length - 384 bit / 8
var db = d.ToByteArrayUnsigned();
var qx = q.AffineXCoord.GetEncoded();
var qy = q.AffineYCoord.GetEncoded();
return (new[] {magic, len, qx, qy, db}).SelectMany(_ => _).ToArray();
}
[Fact]
public void ShouldImportCustomBakedEccPrivateBlobIntoCng()
{
// Generate ECDSA (X9.62) key pair (p384) with Bouncy Castle.
var secureRandom = new SecureRandom();
var ecKeyPairGenerator = new ECKeyPairGenerator("ECDSA");
var keyGenParams = new ECKeyGenerationParameters(NistNamedCurves.GetOid("P-384"), secureRandom);
ecKeyPairGenerator.Init(keyGenParams);
var keyPair = ecKeyPairGenerator.GenerateKeyPair();
var ecPublicKey = keyPair.Public as ECPublicKeyParameters;
var privateBytes = ConvertToNCryptEccPrivateBlob(keyPair);
// Import generated private key into a Cng Key Store & get reference.
var cngPrivKey = CngKey.Import(privateBytes, CngKeyBlobFormat.EccPrivateBlob);
Assert.NotNull(cngPrivKey);
}
// reference xunit
// reference Security.Cryptography.dll (CLR Security project @ Codeplex)
// reference Bouncycastle (patched to emit key usage as an attribute in the PKCS#8 PrivateKeyInfo structure (to get Windows to realize it's a ECDSA and not a ECDH key)
[Fact]
public void ShouldGenerateECKeyPairWithBouncyCastleAndImportIntoDefaultCngKeyStorageProvider_PukesInWin10WithUnknownError()
{
// Generate ECDSA (X9.62) key pair (p384) with Bouncy Castle.
var secureRandom = new SecureRandom();
var ecKeyPairGenerator = new ECKeyPairGenerator("ECDSA");
var keyGenParams = new ECKeyGenerationParameters(NistNamedCurves.GetOid("P-384"), secureRandom);
ecKeyPairGenerator.Init(keyGenParams);
var keyPair = ecKeyPairGenerator.GenerateKeyPair();
var ecPublicKey = keyPair.Public as ECPublicKeyParameters;
var pki = PrivateKeyInfoFactory.CreatePrivateKeyInfo(keyPair.Private);
var privateBytes = pki.GetDerEncoded(); // incl custom attribute fix that adds Key Usage
Console.WriteLine(Asn1Dump.DumpAsString(Asn1Object.FromByteArray(privateBytes)));
// Import generated private key into a Cng Key Store & get reference.
var cngPrivKey = CngKey.Import(privateBytes, CngKeyBlobFormat.Pkcs8PrivateBlob);
Assert.NotNull(cngPrivKey);
}
[Fact]
public void ShouldGetCngKeyAssociatedWithImportedCertificatePlusPrivateKeyReadFromPkcs12File_PukesInWin10_KeySetNotFound()
{
var nc = new NetworkCredential("", "Passw0rd");
var cert = new X509Certificate2(File.ReadAllBytes(@"c:\temp\self-signed.p12"), nc.SecurePassword, X509KeyStorageFlags.UserKeySet | X509KeyStorageFlags.Exportable | X509KeyStorageFlags.PersistKeySet);
var cngPrivateKey = cert.GetCngPrivateKey();
Assert.NotNull(cngPrivateKey);
}
@larsw
Copy link
Author

larsw commented Mar 10, 2017

Note: this gist was created when testing against a pre-RTM version of Win10 - I haven't tested lately.

@Snipe3000
Copy link

I know I'm a bit late to the party, but in "WorksOnWin10.cs" your ConvertToNCryptEccPrivateBlob(keyPair) call is impossible.

@larsw
Copy link
Author

larsw commented Apr 26, 2018

use keyPair.D and ecPublicKey.Q as the parameters.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment