private static byte[] GetNamedCurveBlob( ref ECParameters parameters, Func <string, bool, KeyBlobMagicNumber> magicResolver) { Debug.Assert(parameters.Curve.IsNamed); bool includePrivateParameters = (parameters.D != null); byte[] blob; int offset; int blobSize; // We need to build a key blob structured as follows: // BCRYPT_ECCKEY_BLOB header // byte[cbKey] Q.X // byte[cbKey] Q.Y // -- Only if "includePrivateParameters" is true -- // byte[cbKey] D unsafe { blobSize = sizeof(BCRYPT_ECCKEY_BLOB) + parameters.Q.X.Length + parameters.Q.Y.Length; if (includePrivateParameters) { blobSize += parameters.D.Length; } blob = new byte[blobSize]; fixed(byte *pBlob = blob) { // Build the header BCRYPT_ECCKEY_BLOB *pBcryptBlob = (BCRYPT_ECCKEY_BLOB *)pBlob; pBcryptBlob->Magic = magicResolver(parameters.Curve.Oid.FriendlyName, includePrivateParameters); pBcryptBlob->cbKey = parameters.Q.X.Length; } offset = sizeof(BCRYPT_ECCKEY_BLOB); } // Emit the blob Interop.BCrypt.Emit(blob, ref offset, parameters.Q.X); Interop.BCrypt.Emit(blob, ref offset, parameters.Q.Y); if (includePrivateParameters) { Interop.BCrypt.Emit(blob, ref offset, parameters.D); } // We better have computed the right allocation size above! Debug.Assert(offset == blobSize, "offset == blobSize"); return(blob); }
internal static byte[] GetNamedCurveBlob(ref ECParameters parameters, bool ecdh) { Debug.Assert(parameters.Curve.IsNamed); bool includePrivateParameters = (parameters.D != null); byte[] blob; unsafe { // We need to build a key blob structured as follows: // BCRYPT_ECCKEY_BLOB header // byte[cbKey] Q.X // byte[cbKey] Q.Y // -- Only if "includePrivateParameters" is true -- // byte[cbKey] D int blobSize = sizeof(BCRYPT_ECCKEY_BLOB) + parameters.Q.X !.Length + parameters.Q.Y !.Length; if (includePrivateParameters) { blobSize += parameters.D !.Length; } blob = new byte[blobSize]; fixed(byte *pBlob = &blob[0]) { // Build the header BCRYPT_ECCKEY_BLOB *pBcryptBlob = (BCRYPT_ECCKEY_BLOB *)pBlob; pBcryptBlob->Magic = ecdh ? EcdhCurveNameToMagicNumber(parameters.Curve.Oid.FriendlyName, includePrivateParameters) : EcdsaCurveNameToMagicNumber(parameters.Curve.Oid.FriendlyName, includePrivateParameters); pBcryptBlob->cbKey = parameters.Q.X.Length; // Emit the blob int offset = sizeof(BCRYPT_ECCKEY_BLOB); Interop.BCrypt.Emit(blob, ref offset, parameters.Q.X); Interop.BCrypt.Emit(blob, ref offset, parameters.Q.Y); if (includePrivateParameters) { Interop.BCrypt.Emit(blob, ref offset, parameters.D !); } // We better have computed the right allocation size above! Debug.Assert(offset == blobSize, "offset == blobSize"); } } return(blob); }
internal static ECParameters ExportNamedCurveParameters(CngKey key, bool includePrivateParameters) { byte[] ecBlob = ExportKeyBlob(key, includePrivateParameters); // We now have a buffer laid out as follows: // BCRYPT_ECCKEY_BLOB header // byte[cbKey] Q.X // byte[cbKey] Q.Y // -- Private only -- // byte[cbKey] D ECParameters ecParams = new ECParameters(); KeyBlobMagicNumber magic = (KeyBlobMagicNumber)BitConverter.ToInt32(ecBlob, 0); // Check the magic value in the key blob header. If the blob does not have the required magic, // then throw a CryptographicException. CheckMagicValueOfKey(magic, includePrivateParameters); unsafe { // Fail-fast if a rogue provider gave us a blob that isn't even the size of the blob header. if (ecBlob.Length < sizeof(BCRYPT_ECCKEY_BLOB)) throw ErrorCode.E_FAIL.ToCryptographicException(); fixed(byte *pEcBlob = ecBlob) { BCRYPT_ECCKEY_BLOB *pBcryptBlob = (BCRYPT_ECCKEY_BLOB *)pEcBlob; int offset = sizeof(BCRYPT_ECCKEY_BLOB); ecParams.Q = new ECPoint { X = Interop.BCrypt.Consume(ecBlob, ref offset, pBcryptBlob->cbKey), Y = Interop.BCrypt.Consume(ecBlob, ref offset, pBcryptBlob->cbKey) }; if (includePrivateParameters) { ecParams.D = Interop.BCrypt.Consume(ecBlob, ref offset, pBcryptBlob->cbKey); } } } ecParams.Curve = ECCurve.CreateFromFriendlyName(key.GetCurveName()); return(ecParams); }
private static unsafe void FixupGenericBlob(byte[] blob) { if (blob.Length > sizeof(BCRYPT_ECCKEY_BLOB)) { fixed(byte *pBlob = blob) { BCRYPT_ECCKEY_BLOB *pBcryptBlob = (BCRYPT_ECCKEY_BLOB *)pBlob; switch ((KeyBlobMagicNumber)pBcryptBlob->Magic) { case KeyBlobMagicNumber.BCRYPT_ECDH_PUBLIC_P256_MAGIC: case KeyBlobMagicNumber.BCRYPT_ECDH_PUBLIC_P384_MAGIC: case KeyBlobMagicNumber.BCRYPT_ECDH_PUBLIC_P521_MAGIC: pBcryptBlob->Magic = KeyBlobMagicNumber.BCRYPT_ECDH_PUBLIC_GENERIC_MAGIC; break; case KeyBlobMagicNumber.BCRYPT_ECDH_PRIVATE_P256_MAGIC: case KeyBlobMagicNumber.BCRYPT_ECDH_PRIVATE_P384_MAGIC: case KeyBlobMagicNumber.BCRYPT_ECDH_PRIVATE_P521_MAGIC: pBcryptBlob->Magic = KeyBlobMagicNumber.BCRYPT_ECDH_PRIVATE_GENERIC_MAGIC; break; case KeyBlobMagicNumber.BCRYPT_ECDSA_PUBLIC_P256_MAGIC: case KeyBlobMagicNumber.BCRYPT_ECDSA_PUBLIC_P384_MAGIC: case KeyBlobMagicNumber.BCRYPT_ECDSA_PUBLIC_P521_MAGIC: pBcryptBlob->Magic = KeyBlobMagicNumber.BCRYPT_ECDSA_PUBLIC_GENERIC_MAGIC; break; case KeyBlobMagicNumber.BCRYPT_ECDSA_PRIVATE_P256_MAGIC: case KeyBlobMagicNumber.BCRYPT_ECDSA_PRIVATE_P384_MAGIC: case KeyBlobMagicNumber.BCRYPT_ECDSA_PRIVATE_P521_MAGIC: pBcryptBlob->Magic = KeyBlobMagicNumber.BCRYPT_ECDSA_PRIVATE_GENERIC_MAGIC; break; } } } }
private unsafe CngKey BuildEcKey(byte[] x, byte[] y, Asn1Token.KnownOid curve) { int headerSize = Marshal.SizeOf(typeof(BCRYPT_ECCKEY_BLOB)); int blobSize = headerSize + x.Length + y.Length; byte[] blobBytes = new byte[blobSize]; fixed(byte *pBlobBytes = blobBytes) { BCRYPT_ECCKEY_BLOB *pBcryptEccBlob = (BCRYPT_ECCKEY_BLOB *)pBlobBytes; pBcryptEccBlob->KeyBlobMagicNumber = GetMagicNumber(curve); pBcryptEccBlob->KeySizeBytes = x.Length; Buffer.BlockCopy(x, 0, blobBytes, headerSize, x.Length); Buffer.BlockCopy(y, 0, blobBytes, headerSize + x.Length, y.Length); } new KeyContainerPermission(KeyContainerPermissionFlags.Import).Assert(); var key = CngKey.Import(blobBytes, CngKeyBlobFormat.EccPublicBlob); CodeAccessPermission.RevertAssert(); return(key); }