} // VerifySignature() /// <summary> /// Generates the key exchange key and the public part of the ephemeral key /// using specified encoding parameters in the KDF (ECC only). /// </summary> /// <param name="encodingParms"></param> /// <param name="decryptKeyNameAlg"></param> /// <param name="ephemPub"></param> /// <returns>key exchange key blob</returns> public byte[] EcdhGetKeyExchangeKey(byte[] encodingParms, TpmAlgId decryptKeyNameAlg, out EccPoint ephemPub) { byte[] keyExchangeKey = null; ephemPub = null; #if !__MonoCS__ var eccParms = (EccParms)PublicParms.parameters; int keyBits = RawEccKey.GetKeyLength(eccParms.curveID); // Make a new ephemeral key #if TSS_USE_BCRYPT var ephKey = Generate(RawEccKey.GetEccAlg(PublicParms), (uint)keyBits); byte[] ephPub = ephKey.Export(Native.BCRYPT_ECCPUBLIC_BLOB); byte[] otherPub = Key.Export(Native.BCRYPT_ECCPUBLIC_BLOB); #else using (var eph = new ECDiffieHellmanCng(keyBits)) { byte[] otherPub = EcDhProvider.PublicKey.ToByteArray(); byte[] ephPub = eph.PublicKey.ToByteArray(); eph.KeyDerivationFunction = ECDiffieHellmanKeyDerivationFunction.Hash; eph.HashAlgorithm = GetCngAlgorithm(decryptKeyNameAlg); #endif // !TSS_USE_BCRYPT byte[] herPubX, herPubY; RawEccKey.KeyInfoFromPublicBlob(otherPub, out herPubX, out herPubY); byte[] myPubX, myPubY; RawEccKey.KeyInfoFromPublicBlob(ephPub, out myPubX, out myPubY); byte[] otherInfo = Globs.Concatenate(new[] { encodingParms, myPubX, herPubX }); // The TPM uses the following number of bytes from the KDF int bytesNeeded = CryptoLib.DigestSize(decryptKeyNameAlg); keyExchangeKey = new byte[bytesNeeded]; for (int pos = 0, count = 1, bytesToCopy = 0; pos < bytesNeeded; ++count, pos += bytesToCopy) { byte[] secretPrepend = Marshaller.GetTpmRepresentation((UInt32)count); #if TSS_USE_BCRYPT byte[] fragment = ephKey.DeriveKey(Key, decryptKeyNameAlg, secretPrepend, otherInfo); #else eph.SecretAppend = otherInfo; eph.SecretPrepend = secretPrepend; byte[] fragment = eph.DeriveKeyMaterial(EcDhProvider.Key); #endif // !TSS_USE_BCRYPT bytesToCopy = Math.Min(bytesNeeded - pos, fragment.Length); Array.Copy(fragment, 0, keyExchangeKey, pos, bytesToCopy); } ephemPub = new EccPoint(myPubX, myPubY); #if !TSS_USE_BCRYPT } #endif #endif // !__MonoCS__ return(keyExchangeKey); }
/// <summary> /// Create a new random software key (public and private) matching the parameters in keyParams. /// </summary> /// <param name="keyParams"></param> /// <returns></returns> public AsymCryptoSystem(TpmPublic keyParams) { TpmAlgId keyAlgId = keyParams.type; PublicParms = keyParams.Copy(); switch (keyAlgId) { case TpmAlgId.Rsa: { var rsaParams = keyParams.parameters as RsaParms; AsymmetricKeyAlgorithmProvider RsaProvider = AsymmetricKeyAlgorithmProvider.OpenAlgorithm(AsymmetricAlgorithmNames.RsaOaepSha256); Key = RsaProvider.CreateKeyPair(rsaParams.keyBits); IBuffer keyBlobBuffer = Key.ExportPublicKey(CryptographicPublicKeyBlobType.BCryptPublicKey); byte[] blob; CryptographicBuffer.CopyToByteArray(keyBlobBuffer, out blob); var m = new Marshaller(blob, DataRepresentation.LittleEndian); var header = m.Get <BCryptRsaKeyBlob>(); var modulus = m.GetArray <byte>((int)header.cbModulus); var pubId = new Tpm2bPublicKeyRsa(modulus); PublicParms.unique = pubId; break; } case TpmAlgId.Ecc: { var eccParms = keyParams.parameters as EccParms; var alg = RawEccKey.GetEccAlg(keyParams); if (alg == null) { Globs.Throw <ArgumentException>("Unknown ECC curve"); return; } AsymmetricKeyAlgorithmProvider EccProvider = AsymmetricKeyAlgorithmProvider.OpenAlgorithm(alg); Key = EccProvider.CreateKeyPair((uint)RawEccKey.GetKeyLength(eccParms.curveID)); break; } default: Globs.Throw <ArgumentException>("Algorithm not supported"); break; } }
/// <summary> /// Create a new random software key (public and private) matching the parameters in keyParams. /// </summary> /// <param name="keyParams"></param> /// <returns></returns> public AsymCryptoSystem(TpmPublic keyParams) { TpmAlgId keyAlgId = keyParams.type; PublicParms = keyParams.Copy(); switch (keyAlgId) { case TpmAlgId.Rsa: { var rsaParams = keyParams.parameters as RsaParms; #if TSS_USE_BCRYPT Key = Generate(Native.BCRYPT_RSA_ALGORITHM, rsaParams.keyBits); if (Key == UIntPtr.Zero) { Globs.Throw("Failed to generate RSA key"); return; } byte[] blob = Export(Native.BCRYPT_RSAPUBLIC_BLOB); var m = new Marshaller(blob, DataRepresentation.LittleEndian); var header = m.Get <BCryptRsaKeyBlob>(); /*var exponent = */ m.GetArray <byte>((int)header.cbPublicExp); var modulus = m.GetArray <byte>((int)header.cbModulus); #else RsaProvider = new RSACryptoServiceProvider(rsaParams.keyBits); var modulus = RsaProvider.ExportParameters(true).Modulus; #endif var pubId = new Tpm2bPublicKeyRsa(modulus); PublicParms.unique = pubId; break; } #if !__MonoCS__ case TpmAlgId.Ecc: { var eccParms = keyParams.parameters as EccParms; var alg = RawEccKey.GetEccAlg(keyParams); if (alg == null) { Globs.Throw <ArgumentException>("Unknown ECC curve"); return; } #if TSS_USE_BCRYPT Key = Generate(alg, (uint)RawEccKey.GetKeyLength(eccParms.curveID)); #else var keyParmsX = new CngKeyCreationParameters { ExportPolicy = CngExportPolicies.AllowPlaintextExport }; using (CngKey key = CngKey.Create(alg, null, keyParmsX)) { byte[] keyIs = key.Export(CngKeyBlobFormat.EccPublicBlob); CngKey.Import(keyIs, CngKeyBlobFormat.EccPublicBlob); if (keyParams.objectAttributes.HasFlag(ObjectAttr.Sign)) { EcdsaProvider = new ECDsaCng(key); } else { EcDhProvider = new ECDiffieHellmanCng(key); } } #endif // !TSS_USE_BCRYPT && !__MonoCS__ break; } #endif // !__MonoCS__ default: Globs.Throw <ArgumentException>("Algorithm not supported"); break; } }
/// <summary> /// Create a new AsymCryptoSystem from TPM public parameter. This can then /// be used to validate TPM signatures or encrypt data destined for a TPM. /// </summary> /// <param name="pubKey"></param> /// <param name="privKey"></param> /// <returns></returns> public static AsymCryptoSystem CreateFrom(TpmPublic pubKey, TpmPrivate privKey = null) { var cs = new AsymCryptoSystem(); TpmAlgId keyAlgId = pubKey.type; cs.PublicParms = pubKey.Copy(); // Create an algorithm provider from the provided PubKey switch (keyAlgId) { case TpmAlgId.Rsa: { RawRsa rr = null; byte[] prime1 = null, prime2 = null; if (privKey != null) { rr = new RawRsa(pubKey, privKey); prime1 = RawRsa.ToBigEndian(rr.P); prime2 = RawRsa.ToBigEndian(rr.Q); } var rsaParams = (RsaParms)pubKey.parameters; var exponent = rsaParams.exponent != 0 ? Globs.HostToNet(rsaParams.exponent) : RsaParms.DefaultExponent; var modulus = (pubKey.unique as Tpm2bPublicKeyRsa).buffer; #if TSS_USE_BCRYPT var alg = new BCryptAlgorithm(Native.BCRYPT_RSA_ALGORITHM); cs.Key = alg.LoadRSAKey(exponent, modulus, prime1, prime2); alg.Close(); #else var dotNetPubParms = new RSAParameters() { Exponent = exponent, Modulus = modulus }; if (privKey != null) { dotNetPubParms.P = prime1; dotNetPubParms.Q = prime2; dotNetPubParms.D = RawRsa.ToBigEndian(rr.D); dotNetPubParms.InverseQ = RawRsa.ToBigEndian(rr.InverseQ); dotNetPubParms.DP = RawRsa.ToBigEndian(rr.DP); dotNetPubParms.DQ = RawRsa.ToBigEndian(rr.DQ); } cs.RsaProvider = new RSACryptoServiceProvider(); cs.RsaProvider.ImportParameters(dotNetPubParms); #endif break; } #if !__MonoCS__ case TpmAlgId.Ecc: { var eccParms = (EccParms)pubKey.parameters; var eccPub = (EccPoint)pubKey.unique; var algId = RawEccKey.GetEccAlg(pubKey); if (algId == null) { return(null); } bool isEcdsa = eccParms.scheme.GetUnionSelector() == TpmAlgId.Ecdsa; byte[] keyBlob = RawEccKey.GetKeyBlob(eccPub.x, eccPub.y, keyAlgId, !isEcdsa, eccParms.curveID); #if TSS_USE_BCRYPT var alg = new BCryptAlgorithm(algId); cs.Key = alg.ImportKeyPair(Native.BCRYPT_ECCPUBLIC_BLOB, keyBlob); alg.Close(); if (cs.Key == UIntPtr.Zero) { Globs.Throw("Failed to create new RSA key"); return(null); } #else CngKey eccKey = CngKey.Import(keyBlob, CngKeyBlobFormat.EccPublicBlob); if (pubKey.objectAttributes.HasFlag(ObjectAttr.Sign)) { cs.EcdsaProvider = new ECDsaCng(eccKey); } else { cs.EcDhProvider = new ECDiffieHellmanCng(eccKey); } #endif // !TSS_USE_BCRYPT break; } #endif // !__MonoCS__ default: Globs.Throw <ArgumentException>("Algorithm not supported"); cs = null; break; } return(cs); }
} // VerifySignature() /// <summary> /// Generates the key exchange key and the public part of the ephemeral key /// using specified encoding parameters in the KDF (ECC only). /// </summary> /// <param name="encodingParms"></param> /// <param name="decryptKeyNameAlg"></param> /// <param name="ephemPub"></param> /// <returns>key exchange key blob</returns> public byte[] EcdhGetKeyExchangeKey(byte[] encodingParms, TpmAlgId decryptKeyNameAlg, out EccPoint ephemPub) { var eccParms = (EccParms)PublicParms.parameters; int keyBits = RawEccKey.GetKeyLength(eccParms.curveID); byte[] keyExchangeKey = null; ephemPub = new EccPoint(); // Make a new ephemeral key var prov = AsymmetricKeyAlgorithmProvider.OpenAlgorithm(RawEccKey.GetEccAlg(PublicParms)); var ephKey = prov.CreateKeyPair((uint)keyBits); IBuffer ephPubBuf = ephKey.ExportPublicKey(CryptographicPublicKeyBlobType.BCryptEccFullPublicKey); byte[] ephPub; CryptographicBuffer.CopyToByteArray(ephPubBuf, out ephPub); IBuffer otherPubBuf = Key.ExportPublicKey(CryptographicPublicKeyBlobType.BCryptEccFullPublicKey); byte[] otherPub; CryptographicBuffer.CopyToByteArray(otherPubBuf, out otherPub); byte[] herPubX, herPubY; RawEccKey.KeyInfoFromPublicBlob(otherPub, out herPubX, out herPubY); byte[] myPubX, myPubY; RawEccKey.KeyInfoFromPublicBlob(ephPub, out myPubX, out myPubY); byte[] otherInfo = Globs.Concatenate(new[] { encodingParms, myPubX, herPubX }); // The TPM uses the following number of bytes from the KDF int bytesNeeded = CryptoLib.DigestSize(decryptKeyNameAlg); keyExchangeKey = new byte[bytesNeeded]; for (int pos = 0, count = 1, bytesToCopy = 0; pos < bytesNeeded; ++count, pos += bytesToCopy) { byte[] secretPrepend = Marshaller.GetTpmRepresentation((UInt32)count); string algName; KeyDerivationParameters deriveParams; switch (decryptKeyNameAlg) { case TpmAlgId.Kdf1Sp800108: algName = KeyDerivationAlgorithmNames.Sp800108CtrHmacSha256; deriveParams = KeyDerivationParameters.BuildForSP800108(CryptographicBuffer.CreateFromByteArray(secretPrepend), CryptographicBuffer.CreateFromByteArray(otherInfo)); break; case TpmAlgId.Kdf1Sp80056a: algName = KeyDerivationAlgorithmNames.Sp80056aConcatSha256; deriveParams = KeyDerivationParameters.BuildForSP80056a(CryptographicBuffer.ConvertStringToBinary(algName, BinaryStringEncoding.Utf8), CryptographicBuffer.ConvertStringToBinary("TPM", BinaryStringEncoding.Utf8), CryptographicBuffer.CreateFromByteArray(secretPrepend), CryptographicBuffer.ConvertStringToBinary("", BinaryStringEncoding.Utf8), CryptographicBuffer.CreateFromByteArray(otherInfo)); break; case TpmAlgId.Kdf2: algName = KeyDerivationAlgorithmNames.Pbkdf2Sha256; deriveParams = KeyDerivationParameters.BuildForPbkdf2(CryptographicBuffer.CreateFromByteArray(secretPrepend), 1000); break; default: Globs.Throw <ArgumentException>("wrong KDF name"); return(null); } KeyDerivationAlgorithmProvider deriveProv = KeyDerivationAlgorithmProvider.OpenAlgorithm(algName); IBuffer keyMaterial = CryptographicEngine.DeriveKeyMaterial(Key, deriveParams, (uint)keyBits); byte[] fragment; CryptographicBuffer.CopyToByteArray(keyMaterial, out fragment); bytesToCopy = Math.Min(bytesNeeded - pos, fragment.Length); Array.Copy(fragment, 0, keyExchangeKey, pos, bytesToCopy); } ephemPub = new EccPoint(myPubX, myPubY); return(keyExchangeKey); }
/// <summary> /// Create a new AsymCryptoSystem from TPM public parameter. This can then /// be used to validate TPM signatures or encrypt data destined for a TPM. /// </summary> /// <param name="pubKey"></param> /// <returns></returns> public static AsymCryptoSystem CreateFrom(TpmPublic pubKey, TpmPrivate privKey = null) { var cs = new AsymCryptoSystem(); TpmAlgId keyAlgId = pubKey.type; cs.PublicParms = pubKey.Copy(); // Create an algorithm provider from the provided PubKey switch (keyAlgId) { case TpmAlgId.Rsa: { RawRsa rr = null; byte[] prime1 = null, prime2 = null; if (privKey != null) { rr = new RawRsa(pubKey, privKey); prime1 = RawRsa.ToBigEndian(rr.P); prime2 = RawRsa.ToBigEndian(rr.Q); } var rsaParams = (RsaParms)pubKey.parameters; var exponent = rsaParams.exponent != 0 ? Globs.HostToNet(rsaParams.exponent) : RsaParms.DefaultExponent; var modulus = (pubKey.unique as Tpm2bPublicKeyRsa).buffer; AsymmetricKeyAlgorithmProvider rsaProvider = AsymmetricKeyAlgorithmProvider.OpenAlgorithm(AsymmetricAlgorithmNames.RsaOaepSha256); uint primeLen1 = 0, primeLen2 = 0; // Compute the size of BCRYPT_RSAKEY_BLOB int rsaKeySize = exponent.Length + modulus.Length + 24; if (prime1 != null && prime1.Length > 0) { if (prime2 == null || prime2.Length == 0) { Globs.Throw <ArgumentException>("LoadRSAKey(): The second prime is missing"); return(null); } primeLen1 = (uint)prime1.Length; primeLen2 = (uint)prime2.Length; rsaKeySize += prime1.Length + prime2.Length; } else if (prime2 != null && prime2.Length > 0) { Globs.Throw <ArgumentException>("LoadRSAKey(): The first prime is missing"); return(null); } var rsaKey = new byte[rsaKeySize]; // Initialize BCRYPT_RSAKEY_BLOB int offset = 0; WriteToBuffer(ref rsaKey, ref offset, primeLen1 == 0 ? BCRYPT_RSAPUBLIC_MAGIC : BCRYPT_RSAPRIVATE_MAGIC); WriteToBuffer(ref rsaKey, ref offset, (uint)modulus.Length * 8); WriteToBuffer(ref rsaKey, ref offset, (uint)exponent.Length); WriteToBuffer(ref rsaKey, ref offset, (uint)modulus.Length); WriteToBuffer(ref rsaKey, ref offset, primeLen1); WriteToBuffer(ref rsaKey, ref offset, primeLen1); WriteToBuffer(ref rsaKey, ref offset, exponent); WriteToBuffer(ref rsaKey, ref offset, modulus); if (primeLen1 != 0) { WriteToBuffer(ref rsaKey, ref offset, prime1); WriteToBuffer(ref rsaKey, ref offset, prime2); } IBuffer rsaBuffer = CryptographicBuffer.CreateFromByteArray(rsaKey); if (primeLen1 == 0) { cs.Key = rsaProvider.ImportPublicKey(rsaBuffer, CryptographicPublicKeyBlobType.BCryptPublicKey); } else { cs.Key = rsaProvider.ImportKeyPair(rsaBuffer, CryptographicPrivateKeyBlobType.BCryptPrivateKey); } break; } case TpmAlgId.Ecc: { var eccParms = (EccParms)pubKey.parameters; var eccPub = (EccPoint)pubKey.unique; var algId = RawEccKey.GetEccAlg(pubKey); if (algId == null) { return(null); } bool isEcdsa = eccParms.scheme.GetUnionSelector() == TpmAlgId.Ecdsa; byte[] keyBlob = RawEccKey.GetKeyBlob(eccPub.x, eccPub.y, keyAlgId, !isEcdsa, eccParms.curveID); AsymmetricKeyAlgorithmProvider eccProvider = AsymmetricKeyAlgorithmProvider.OpenAlgorithm(algId); cs.Key = eccProvider.ImportKeyPair(CryptographicBuffer.CreateFromByteArray(keyBlob)); break; } default: Globs.Throw <ArgumentException>("Algorithm not supported"); cs = null; break; } return(cs); }