internal static byte[] GetPrimeCurveBlob(ref ECParameters parameters, bool ecdh) { Debug.Assert(parameters.Curve.IsPrime); bool includePrivateParameters = (parameters.D != null); ECCurve curve = parameters.Curve; byte[] blob; unsafe { // We need to build a key blob structured as follows: // BCRYPT_ECCFULLKEY_BLOB header // byte[cbFieldLength] P // byte[cbFieldLength] A // byte[cbFieldLength] B // byte[cbFieldLength] G.X // byte[cbFieldLength] G.Y // byte[cbSubgroupOrder] Order (n) // byte[cbCofactor] Cofactor (h) // byte[cbSeed] Seed // byte[cbFieldLength] Q.X // byte[cbFieldLength] Q.Y // -- Only if "includePrivateParameters" is true -- // byte[cbSubgroupOrder] D int blobSize = sizeof(BCRYPT_ECCFULLKEY_BLOB) + curve.Prime.Length + curve.A.Length + curve.B.Length + curve.G.X.Length + curve.G.Y.Length + curve.Order.Length + curve.Cofactor.Length + (curve.Seed == null ? 0 : curve.Seed.Length) + 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_ECCFULLKEY_BLOB *pBcryptBlob = (BCRYPT_ECCFULLKEY_BLOB *)pBlob; pBcryptBlob->Version = 1; // No constant for this found in bcrypt.h pBcryptBlob->Magic = includePrivateParameters ? (ecdh ? KeyBlobMagicNumber.BCRYPT_ECDH_PRIVATE_GENERIC_MAGIC : KeyBlobMagicNumber.BCRYPT_ECDSA_PRIVATE_GENERIC_MAGIC) : (ecdh ? KeyBlobMagicNumber.BCRYPT_ECDH_PUBLIC_GENERIC_MAGIC : KeyBlobMagicNumber.BCRYPT_ECDSA_PUBLIC_GENERIC_MAGIC); pBcryptBlob->cbCofactor = curve.Cofactor.Length; pBcryptBlob->cbFieldLength = parameters.Q.X.Length; pBcryptBlob->cbSeed = curve.Seed == null ? 0 : curve.Seed.Length; pBcryptBlob->cbSubgroupOrder = curve.Order.Length; pBcryptBlob->CurveGenerationAlgId = GetHashAlgorithmId(curve.Hash); pBcryptBlob->CurveType = ConvertToCurveTypeEnum(curve.CurveType); // Emit the blob int offset = sizeof(BCRYPT_ECCFULLKEY_BLOB); Interop.BCrypt.Emit(blob, ref offset, curve.Prime); Interop.BCrypt.Emit(blob, ref offset, curve.A); Interop.BCrypt.Emit(blob, ref offset, curve.B); Interop.BCrypt.Emit(blob, ref offset, curve.G.X); Interop.BCrypt.Emit(blob, ref offset, curve.G.Y); Interop.BCrypt.Emit(blob, ref offset, curve.Order); Interop.BCrypt.Emit(blob, ref offset, curve.Cofactor); if (curve.Seed != null) { Interop.BCrypt.Emit(blob, ref offset, curve.Seed); } 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 void ExportPrimeCurveParameters(ref ECParameters ecParams, byte[] ecBlob, bool includePrivateParameters) { // We now have a buffer laid out as follows: // BCRYPT_ECCFULLKEY_BLOB header // byte[cbFieldLength] P // byte[cbFieldLength] A // byte[cbFieldLength] B // byte[cbFieldLength] G.X // byte[cbFieldLength] G.Y // byte[cbSubgroupOrder] Order (n) // byte[cbCofactor] Cofactor (h) // byte[cbSeed] Seed // byte[cbFieldLength] Q.X // byte[cbFieldLength] Q.Y // -- Private only -- // byte[cbSubgroupOrder] D 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_ECCFULLKEY_BLOB)) throw ErrorCode.E_FAIL.ToCryptographicException(); fixed(byte *pEcBlob = &ecBlob[0]) { BCRYPT_ECCFULLKEY_BLOB *pBcryptBlob = (BCRYPT_ECCFULLKEY_BLOB *)pEcBlob; var primeCurve = new ECCurve(); primeCurve.CurveType = ConvertToCurveTypeEnum(pBcryptBlob->CurveType); primeCurve.Hash = GetHashAlgorithmName(pBcryptBlob->CurveGenerationAlgId); int offset = sizeof(BCRYPT_ECCFULLKEY_BLOB); primeCurve.Prime = Interop.BCrypt.Consume(ecBlob, ref offset, pBcryptBlob->cbFieldLength); primeCurve.A = Interop.BCrypt.Consume(ecBlob, ref offset, pBcryptBlob->cbFieldLength); primeCurve.B = Interop.BCrypt.Consume(ecBlob, ref offset, pBcryptBlob->cbFieldLength); primeCurve.G = new ECPoint() { X = Interop.BCrypt.Consume(ecBlob, ref offset, pBcryptBlob->cbFieldLength), Y = Interop.BCrypt.Consume(ecBlob, ref offset, pBcryptBlob->cbFieldLength), }; primeCurve.Order = Interop.BCrypt.Consume(ecBlob, ref offset, pBcryptBlob->cbSubgroupOrder); primeCurve.Cofactor = Interop.BCrypt.Consume(ecBlob, ref offset, pBcryptBlob->cbCofactor); // Optional parameters primeCurve.Seed = pBcryptBlob->cbSeed == 0 ? null : Interop.BCrypt.Consume(ecBlob, ref offset, pBcryptBlob->cbSeed); ecParams.Q = new ECPoint { X = Interop.BCrypt.Consume(ecBlob, ref offset, pBcryptBlob->cbFieldLength), Y = Interop.BCrypt.Consume(ecBlob, ref offset, pBcryptBlob->cbFieldLength) }; if (includePrivateParameters) { ecParams.D = Interop.BCrypt.Consume(ecBlob, ref offset, pBcryptBlob->cbSubgroupOrder); } ecParams.Curve = primeCurve; } } }