public static byte[] PssEncode(byte[] m, TpmAlgId hashAlg, int sLen, int emBits) { var emLen = (int)Math.Ceiling(1.0 * emBits / 8); int hLen = CryptoLib.DigestSize(hashAlg); // 1 - Ignore // 2 byte[] mHash = TpmHash.FromData(hashAlg, m); // 3 if (emLen < hLen + sLen + 2) { if (Tpm2._TssBehavior.Passthrough) { return(new byte[0]); } else { throw new Exception("Encoding error"); } } // 4 byte[] salt = Globs.GetRandomBytes(sLen); // 5 byte[] mPrime = Globs.Concatenate(new[] { Globs.ByteArray(8, 0), mHash, salt }); // 6 byte[] h = CryptoLib.HashData(hashAlg, mPrime); // 7 byte[] ps = Globs.GetZeroBytes(emLen - sLen - hLen - 2); // 8 byte[] db = Globs.Concatenate(new[] { ps, new byte[] { 0x01 }, salt }); // 9 byte[] dbMask = CryptoLib.MGF(h, emLen - hLen - 1, hashAlg); // 10 byte[] maskedDb = XorEngine.Xor(db, dbMask); // 11 int numZeroBits = 8 * emLen - emBits; byte mask = GetByteMask(numZeroBits); maskedDb[0] &= mask; // 12 byte[] em = Globs.Concatenate(new[] { maskedDb, h, new byte[] { 0xbc } }); // 13 return(em); }
} // 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 activation blobs that can be passed to ActivateCredential. Two blobs are returned - /// (a) - encryptedSecret - is the symmetric key cfb-symmetrically encrypted with an enveloping key /// (b) credentialBlob (the return value of this function) - is the enveloping key OEAP (RSA) encrypted /// by the public part of this key. /// </summary> /// <param name="secret"></param> /// <param name="nameAlgId"></param> /// <param name="nameOfKeyToBeActivated"></param> /// <param name="encryptedSecret"></param> /// <returns>CredentialBlob (</returns> public byte[] CreateActivationCredentials( byte[] secret, TpmAlgId nameAlgId, byte[] nameOfKeyToBeActivated, out byte[] encryptedSecret) { byte[] seed, encSecret; switch (type) { case TpmAlgId.Rsa: // The seed should be the same size as the symmKey seed = Globs.GetRandomBytes((CryptoLib.DigestSize(nameAlg) + 7) / 8); encSecret = EncryptOaep(seed, ActivateEncodingParms); break; case TpmAlgId.Ecc: EccPoint pubEphem; seed = EcdhGetKeyExchangeKey(ActivateEncodingParms, nameAlg, out pubEphem); encSecret = Marshaller.GetTpmRepresentation(pubEphem); break; default: Globs.Throw <NotImplementedException>("CreateActivationCredentials: Unsupported algorithm"); encryptedSecret = new byte[0]; return(new byte[0]); } var cvx = new Tpm2bDigest(secret); byte[] cvTpm2B = Marshaller.GetTpmRepresentation(cvx); SymDefObject symDef = TssObject.GetSymDef(this); byte[] symKey = KDF.KDFa(nameAlg, seed, "STORAGE", nameOfKeyToBeActivated, new byte[0], symDef.KeyBits); byte[] encIdentity; using (SymmCipher symm2 = SymmCipher.Create(symDef, symKey)) { encIdentity = symm2.Encrypt(cvTpm2B); } var hmacKeyBits = CryptoLib.DigestSize(nameAlg); byte[] hmacKey = KDF.KDFa(nameAlg, seed, "INTEGRITY", new byte[0], new byte[0], hmacKeyBits * 8); byte[] outerHmac = CryptoLib.HmacData(nameAlg, hmacKey, Globs.Concatenate(encIdentity, nameOfKeyToBeActivated)); byte[] activationBlob = Globs.Concatenate( Marshaller.ToTpm2B(outerHmac), encIdentity); encryptedSecret = encSecret; return(activationBlob); }
public static byte[] Pkcs15Encode(byte[] m, int emLen, TpmAlgId hashAlg) { byte[] prefix; switch (hashAlg) { case TpmAlgId.Sha1: prefix = new byte[] { 0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x0e, 0x03, 0x02, 0x1a, 0x05, 0x00, 0x04, 0x14 }; break; case TpmAlgId.Sha256: prefix = new byte[] { 0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05, 0x00, 0x04, 0x20 }; break; case TpmAlgId.Sha384: prefix = new byte[] { 0x30, 0x41, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02, 0x05, 0x00, 0x04, 0x30 }; break; case TpmAlgId.Sha512: prefix = new byte[] { 0x30, 0x51, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, 0x05, 0x00, 0x04, 0x40 }; break; default: Globs.Throw <ArgumentException>("Pkcs15Encode: Unsupported hashAlg"); return(new byte[0]); } byte[] messageHash = TpmHash.FromData(hashAlg, m); byte[] T = Globs.Concatenate(prefix, messageHash); int tLen = T.Length; if (emLen < tLen + 11) { Globs.Throw <ArgumentException>("Pkcs15Encode: Encoded message is too short"); return(new byte[0]); } byte[] ps = Globs.ByteArray(emLen - tLen - 3, 0xff); byte[] em = Globs.Concatenate(new[] { new byte[] { 0x00, 0x01 }, ps, new byte[] { 0x00 }, T }); return(em); }
TkVerified SignApproval(Tpm2 tpm, byte[] approvedPolicy, byte[] policyRef, TpmHandle hSigKey, ISigSchemeUnion scheme = null) { byte[] name, qname; TpmPublic pub = tpm.ReadPublic(hSigKey, out name, out qname); byte[] dataToSign = Globs.Concatenate(approvedPolicy, policyRef); byte[] aHash = CryptoLib.HashData(pub.nameAlg, dataToSign); // Create an authorization certificate for the "approvedPolicy" var sig = tpm.Sign(hSigKey, aHash, scheme, new TkHashcheck()); return(tpm.VerifySignature(hSigKey, aHash, sig)); }
/// <summary> /// Calculate the qualified name of an object presumed loaded under the provided ancestral chain /// in a given hierarchy. /// </summary> /// <param name="hierarchyHandle"></param> /// <param name="children"></param> /// <returns></returns> public static byte[] GetQualifiedName(TpmHandle hierarchyHandle, TpmPublic[] children) { byte[] runningName = Marshaller.GetTpmRepresentation(hierarchyHandle); foreach (TpmPublic pub in children) { byte[] thisName = pub.GetName(); runningName = Globs.Concatenate ( Marshaller.GetTpmRepresentation(pub.nameAlg), CryptoLib.HashData(pub.nameAlg, new[] { runningName, thisName }) ); } return(runningName); }
/// <summary> /// Calculate and return the auth-hmac (or plaintext auth if it is a policy session with PlaintextAuth set) /// based on the current session parms. /// </summary> /// <param name="parmHash"></param> /// <param name="direction"></param> /// <param name="nonceDec"></param> /// <param name="nonceEnc"></param> /// <returns></returns> internal byte[] GetAuthHmac(byte[] parmHash, Direction direction, byte[] nonceDec = null, byte[] nonceEnc = null) { // special case. If this is a policy session and the session includes PolicyPassword the // TPM expects and assumes that the HMAC field will have the plaintext entity field as in // a PWAP session (the related PolicyAuthValue demands an HMAC as usual) if (PlaintextAuth) { return(Handle.Auth ?? AuthHandle.Auth); } byte[] nonceNewer, nonceOlder; if (direction == Direction.Command) { nonceNewer = NonceCaller; nonceOlder = NonceTpm; } else { nonceNewer = NonceTpm; nonceOlder = NonceCaller; } byte[] sessionAttrs = Marshaller.GetTpmRepresentation(Attrs); byte[] auth = Handle.Auth; if (AuthHandle != null && Handle != TpmRh.TpmRsPw && auth == null && ((SessionType != TpmSe.Policy && BindObject != AuthHandle) || (SessionType == TpmSe.Policy && SessIncludesAuth))) { auth = Globs.TrimTrailingZeros(AuthHandle.Auth); } byte[] hmacKey = Globs.Concatenate(SessionKey, auth); byte[] bufToHmac = Globs.Concatenate(new[] { parmHash, nonceNewer, nonceOlder, nonceDec, nonceEnc, sessionAttrs }); byte[] hmac = CryptoLib.Hmac(AuthHash, hmacKey, bufToHmac); #if false Console.WriteLine(Globs.FormatBytesCompact("hmacKey: ", hmacKey)); Console.WriteLine(Globs.FormatBytesCompact("nonceNewer: ", nonceNewer)); Console.WriteLine(Globs.FormatBytesCompact("nonceOlder: ", nonceOlder)); Console.WriteLine(Globs.FormatBytesCompact("nonceDec: ", nonceDec)); Console.WriteLine(Globs.FormatBytesCompact("nonceEnc: ", nonceEnc)); Console.WriteLine(Globs.FormatBytesCompact("attrs: ", sessionAttrs)); Console.WriteLine(Globs.FormatBytesCompact("HMAC: ", hmac)); #endif return(hmac); }
// ReSharper disable once InconsistentNaming public static byte[] KDFa(TpmAlgId hmacHash, byte[] hmacKey, string label, byte[] contextU, byte[] contextV, uint numBitsRequired) { int bitsPerLoop = CryptoLib.DigestSize(hmacHash) * 8; long numLoops = (numBitsRequired + bitsPerLoop - 1) / bitsPerLoop; var kdfStream = new byte[numLoops * bitsPerLoop / 8]; for (int j = 0; j < numLoops; j++) { byte[] toHmac = Globs.Concatenate(new[] { Globs.HostToNet(j + 1), Encoding.UTF8.GetBytes(label), Globs.HostToNet((byte)0), contextU, contextV, Globs.HostToNet(numBitsRequired) }); byte[] fragment = CryptoLib.HmacData(hmacHash, hmacKey, toHmac); Array.Copy(fragment, 0, kdfStream, j * bitsPerLoop / 8, fragment.Length); } return(Globs.ShiftRight(kdfStream, (int)(bitsPerLoop * numLoops - numBitsRequired))); }
/// <summary> /// Calculate the session-key from the nonces and salt/bound values (if present) /// </summary> public void CalcSessionKey() { if (Salt == SaltNeeded) { Globs.Throw("Unencrypted salt value must be provided for the session" + Handle.handle.ToString("X8")); } // Compute Handle.Auth in accordance with Part 1, 19.6.8. if (Salt == null && BindObject == TpmRh.Null) { SessionKey = new byte[0]; return; } byte[] auth = Globs.TrimTrailingZeros(BindObject.Auth); byte[] hmacKey = Globs.Concatenate(auth, Salt); SessionKey = KDF.KDFa(AuthHash, hmacKey, "ATH", NonceTpm, NonceCaller, TpmHash.DigestSize(AuthHash) * 8); }
/// <summary> /// Calculate the session-key from the nonces and salt/bound values (if present) /// </summary> internal void CalcSessionKey() { Debug.Assert(SessionKey == null, "Attempt to repeatedly calculate session key"); if (Salt == SaltNeeded) { Globs.Throw(string.Format("Unencrypted salt value must be provided for the session {0:x}", Handle.handle)); } // Compute Handle.Auth in accordance with Part 1, 19.6.8. if (Salt == null && BindObject == TpmRh.Null) { SessionKey = new byte[0]; return; } byte[] auth = Globs.TrimTrailingZeros(BindObject.Auth); byte[] hmacKey = Globs.Concatenate(auth, Salt); SessionKey = KDF.KDFa(AuthHash, hmacKey, "ATH", NonceTpm, NonceCaller, TpmHash.DigestSize(AuthHash) * 8); }
public static byte[] HashData(TpmAlgId alg, byte[][] dataToHash) { byte[] temp = Globs.Concatenate(dataToHash); return(HashData(alg, temp)); }
/// <summary> /// PSS verify. Note: we expect the caller to do the hash. /// </summary> /// <param name="m"></param> /// <param name="em"></param> /// <param name="sLen"></param> /// <param name="emBits"></param> /// <param name="hashAlg"></param> /// <returns></returns> public static bool PssVerify(byte[] m, byte[] em, int sLen, int emBits, TpmAlgId hashAlg) { var emLen = (int)Math.Ceiling(1.0 * emBits / 8); int hLen = CryptoLib.DigestSize(hashAlg); // 1 - Skip // 2 byte[] mHash = TpmHash.FromData(hashAlg, m); // 3 if (emLen < hLen + sLen + 2) { return(false); } // 4 if (em[em.Length - 1] != 0xbc) { return(false); } // 5 byte[] maskedDB = Globs.CopyData(em, 0, emLen - hLen - 1); byte[] h = Globs.CopyData(em, emLen - hLen - 1, hLen); // 6 int numZeroBits = 8 * emLen - emBits; // First numZero bits is zero in mask byte mask = GetByteMask(numZeroBits); if ((maskedDB[0] & mask) != maskedDB[0]) { return(false); } // 7 byte[] dbMask = CryptoLib.MGF(h, emLen - hLen - 1, hashAlg); // 8 byte[] db = XorEngine.Xor(maskedDB, dbMask); // 9 int numZeroBits2 = 8 * emLen - emBits; byte mask2 = GetByteMask(numZeroBits2); db[0] &= mask2; // 10 for (int j = 0; j < emLen - hLen - sLen - 2; j++) { if (db[j] != 0) { return(false); } } if (db[emLen - hLen - sLen - 1 - 1] != 1) { return(false); } // 11 byte[] salt = Globs.CopyData(db, db.Length - sLen); // 12 byte[] mPrime = Globs.Concatenate(new[] { Globs.ByteArray(8, 0), mHash, salt }); // 13 byte[] hPrime = TpmHash.FromData(hashAlg, mPrime); // 14 bool match = Globs.ArraysAreEqual(h, hPrime); if (match == false) { return(false); } return(true); }
} // 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); }
public static byte[] HmacData(TpmAlgId underlyingHash, byte[] key, byte[][] dataToHash) { byte[] temp = Globs.Concatenate(dataToHash); return(HmacData(underlyingHash, key, temp)); }
/// <summary> /// Creates a duplication blob for the current key that can be Imported as a child /// of newParent. Three forms are possible. GetPlaintextDuplicationBlob() allows /// plaintext-import. This function enables duplication with and without an /// inner wrapper (depending on whether innerWrapper is null) /// </summary> /// <param name="newParent"></param> /// <param name="innerWrapper"></param> /// <param name="encSecret"></param> /// <returns></returns> public TpmPrivate GetDuplicationBlob( TpmPublic pubNewParent, SymCipher innerWrapper, out byte[] encSecret) { byte[] encSensitive; if (innerWrapper == null) { // No inner wrapper encSensitive = Marshaller.ToTpm2B(Sensitive.GetTpmRepresentation()); Transform(encSensitive); } else { byte[] sens = Marshaller.ToTpm2B(Sensitive.GetTpmRepresentation()); byte[] toHash = Globs.Concatenate(sens, GetName()); Transform(toHash); byte[] innerIntegrity = Marshaller.ToTpm2B(CryptoLib.HashData( Public.nameAlg, toHash)); byte[] innerData = Globs.Concatenate(innerIntegrity, sens); Transform(innerData); encSensitive = innerWrapper.Encrypt(innerData); Transform(encSensitive); } byte[] seed; SymDefObject symDef = GetSymDef(pubNewParent).Copy(); // TPM duplication procedures always use CFB mode symDef.Mode = TpmAlgId.Cfb; using (var swNewParent = AsymCryptoSystem.CreateFrom(pubNewParent)) { switch (pubNewParent.type) { case TpmAlgId.Rsa: // The seed should be the same size as the scheme hash LastSeed = seed = Globs.GetRandomBytes( CryptoLib.DigestSize(swNewParent.OaepHash)); encSecret = swNewParent.EncryptOaep(seed, DuplicateEncodingParms); break; case TpmAlgId.Ecc: EccPoint pubEphem; seed = swNewParent.EcdhGetKeyExchangeKey(DuplicateEncodingParms, pubNewParent.nameAlg, out pubEphem); encSecret = Marshaller.GetTpmRepresentation(pubEphem); break; default: Globs.Throw <NotImplementedException>( "GetDuplicationBlob: Unsupported algorithm"); encSecret = new byte[0]; return(new TpmPrivate()); } } Transform(seed); Transform(encSecret); byte[] symKey = KDF.KDFa(pubNewParent.nameAlg, seed, "STORAGE", Public.GetName(), new byte[0], symDef.KeyBits); Transform(symKey); byte[] dupSensitive; using (SymCipher enc2 = SymCipher.Create(symDef, symKey)) { if (enc2 == null) { return(null); } dupSensitive = enc2.Encrypt(encSensitive); } Transform(dupSensitive); var npNameNumBits = CryptoLib.DigestSize(pubNewParent.nameAlg) * 8; byte[] hmacKey = KDF.KDFa(pubNewParent.nameAlg, seed, "INTEGRITY", new byte[0], new byte[0], npNameNumBits); byte[] outerDataToHmac = Globs.Concatenate(dupSensitive, Public.GetName()); Transform(outerDataToHmac); byte[] outerHmac = Marshaller.ToTpm2B(CryptoLib.Hmac(pubNewParent.nameAlg, hmacKey, outerDataToHmac)); Transform(outerHmac); byte[] dupBlob = Globs.Concatenate(outerHmac, dupSensitive); Transform(dupBlob); return(new TpmPrivate(dupBlob)); }
/// <summary> /// Create activation blobs that can be passed to ActivateCredential. Two /// blobs are returned: /// 1) encryptedSecret - symmetric key cfb-symmetrically encrypted with the /// enveloping key; /// 2) credentialBlob - the enveloping key OEAP (RSA) encrypted by the public /// part of this key. This is the return value of this /// function /// </summary> /// <param name="secret"></param> /// <param name="nameOfKeyToBeActivated"></param> /// <param name="encryptedSecret"></param> /// <returns>CredentialBlob (</returns> public IdObject CreateActivationCredentials(byte[] secret, byte[] nameOfKeyToBeActivated, out byte[] encryptedSecret) { byte[] seed, encSecret; switch (type) { case TpmAlgId.Rsa: // The seed should be the same size as the name algorithmdigest seed = Globs.GetRandomBytes(CryptoLib.DigestSize(nameAlg)); encSecret = EncryptOaep(seed, ActivateEncodingParms); break; case TpmAlgId.Ecc: EccPoint ephemPubPt; seed = EcdhGetKeyExchangeKey(ActivateEncodingParms, out ephemPubPt); encSecret = Marshaller.GetTpmRepresentation(ephemPubPt); break; default: Globs.Throw <NotImplementedException>( "CreateActivationCredentials: Unsupported algorithm"); encryptedSecret = new byte[0]; return(null); } Transform(seed); Transform(encSecret); var cvx = new Tpm2bDigest(secret); byte[] cvTpm2B = Marshaller.GetTpmRepresentation(cvx); Transform(cvTpm2B); SymDefObject symDef = TssObject.GetSymDef(this); byte[] symKey = KDF.KDFa(nameAlg, seed, "STORAGE", nameOfKeyToBeActivated, new byte[0], symDef.KeyBits); Transform(symKey); byte[] encIdentity; // TPM only uses CFB mode in its command implementations var sd = symDef.Copy(); sd.Mode = TpmAlgId.Cfb; using (var sym = SymCipher.Create(sd, symKey)) { // Not all keys specs are supported by SW crypto if (sym == null) { encryptedSecret = null; return(null); } encIdentity = sym.Encrypt(cvTpm2B); } Transform(encIdentity); var hmacKeyBits = CryptoLib.DigestSize(nameAlg); byte[] hmacKey = KDF.KDFa(nameAlg, seed, "INTEGRITY", new byte[0], new byte[0], hmacKeyBits * 8); Transform(hmacKey); byte[] outerHmac = CryptoLib.Hmac(nameAlg, hmacKey, Globs.Concatenate(encIdentity, nameOfKeyToBeActivated)); Transform(outerHmac); encryptedSecret = encSecret; return(new IdObject(outerHmac, encIdentity)); }
/// <summary> /// Creates a duplication blob for the current key that can be Imported as a child /// of newParent. Three forms are possible. GetPlaintextDuplicationBlob() allows /// plaintext-import. This function enables duplication with and without an /// inner wrapper (depending on whether innerWrapper is null) /// </summary> /// <param name="newParent"></param> /// <param name="innerWrapper"></param> /// <param name="encryptedWrappingKey"></param> /// <returns></returns> public TpmPrivate GetDuplicationBlob( TpmPublic newParent, SymmCipher innerWrapper, out byte[] encryptedWrappingKey) { byte[] encSensitive; if (innerWrapper == null) { // No inner wrapper encSensitive = Marshaller.ToTpm2B(sensitivePart.GetTpmRepresentation()); } else { byte[] sens = Marshaller.ToTpm2B(sensitivePart.GetTpmRepresentation()); byte[] toHash = Globs.Concatenate(sens, GetName()); byte[] innerIntegrity = Marshaller.ToTpm2B(CryptoLib.HashData(publicPart.nameAlg, toHash)); byte[] innerData = Globs.Concatenate(innerIntegrity, sens); encSensitive = innerWrapper.Encrypt(innerData); } byte[] seed, encSecret; SymDefObject symDef = GetSymDef(newParent); using (AsymCryptoSystem newParentPubKey = AsymCryptoSystem.CreateFrom(newParent)) { switch (newParent.type) { case TpmAlgId.Rsa: // The seed should be the same size as the symmKey seed = Globs.GetRandomBytes((symDef.KeyBits + 7) / 8); encSecret = newParentPubKey.EncryptOaep(seed, DuplicateEncodingParms); break; case TpmAlgId.Ecc: EccPoint pubEphem; seed = newParentPubKey.EcdhGetKeyExchangeKey(DuplicateEncodingParms, newParent.nameAlg, out pubEphem); encSecret = Marshaller.GetTpmRepresentation(pubEphem); break; default: Globs.Throw <NotImplementedException>("GetDuplicationBlob: Unsupported algorithm"); encryptedWrappingKey = new byte[0]; return(new TpmPrivate()); } } encryptedWrappingKey = encSecret; byte[] symKey = KDF.KDFa(newParent.nameAlg, seed, "STORAGE", publicPart.GetName(), new byte[0], symDef.KeyBits); byte[] dupSensitive; using (SymmCipher enc2 = SymmCipher.Create(symDef, symKey)) { dupSensitive = enc2.Encrypt(encSensitive); } var npNameNumBits = CryptoLib.DigestSize(newParent.nameAlg) * 8; byte[] hmacKey = KDF.KDFa(newParent.nameAlg, seed, "INTEGRITY", new byte[0], new byte[0], npNameNumBits); byte[] outerDataToHmac = Globs.Concatenate(dupSensitive, publicPart.GetName()); byte[] outerHmac = Marshaller.ToTpm2B(CryptoLib.HmacData(newParent.nameAlg, hmacKey, outerDataToHmac)); byte[] dupBlob = Globs.Concatenate(outerHmac, dupSensitive); return(new TpmPrivate(dupBlob)); }
private bool VerifySignature(byte[] data, bool dataIsDigest, ISignatureUnion signature, TpmAlgId sigHash) { var rsaParams = PublicParms.parameters as RsaParms; if (rsaParams != null) { var sig = signature as SignatureRsa; TpmAlgId sigScheme = sig.GetUnionSelector(); TpmAlgId keyScheme = rsaParams.scheme.GetUnionSelector(); if (keyScheme != TpmAlgId.Null && keyScheme != sigScheme) { Globs.Throw <ArgumentException>("Key scheme and signature scheme do not match"); return(false); } if (sigHash == TpmAlgId.Null) { sigHash = (rsaParams.scheme as SchemeHash).hashAlg; } if (sigHash != sig.hash) { Globs.Throw <ArgumentException>("Key scheme hash and signature scheme hash do not match"); return(false); } byte[] digest = dataIsDigest ? data : CryptoLib.HashData(sigHash, data); if (sigScheme == TpmAlgId.Rsassa) { return(CryptographicEngine.VerifySignatureWithHashInput(Key, CryptographicBuffer.CreateFromByteArray(digest), CryptographicBuffer.CreateFromByteArray(sig.sig))); } if (sigScheme == TpmAlgId.Rsapss) { Globs.Throw <ArgumentException>("VerifySignature(): PSS scheme is not supported"); return(false); } Globs.Throw <ArgumentException>("VerifySignature(): Unrecognized scheme"); return(false); } var eccParms = PublicParms.parameters as EccParms; if (eccParms != null) { if (eccParms.scheme.GetUnionSelector() != TpmAlgId.Ecdsa) { Globs.Throw <ArgumentException>("Unsupported ECC sig scheme"); return(false); } if (sigHash == TpmAlgId.Null) { sigHash = (eccParms.scheme as SigSchemeEcdsa).hashAlg; } byte[] digest = dataIsDigest ? data : CryptoLib.HashData(sigHash, data); var sig = signature as SignatureEcdsa; byte[] sigBlob = Globs.Concatenate(sig.signatureR, sig.signatureS); return(CryptographicEngine.VerifySignatureWithHashInput(Key, CryptographicBuffer.CreateFromByteArray(digest), CryptographicBuffer.CreateFromByteArray(sigBlob))); } // Should never be here Globs.Throw("VerifySignature: Unrecognized asymmetric algorithm"); return(false); } // VerifySignature()
public static byte[] HashData(TpmAlgId alg, byte[] data1, byte[] data2) { return(HashData(alg, Globs.Concatenate(data1, data2))); }
/// <summary> /// Verifies the signature over data or a digest. /// The data will be hashed internall by the method using hash algorithm from /// the signing scheme digest computed from the specified data buffer. /// The signing scheme is retrieved from the signature. The verification key /// shall have either compatible or null scheme. /// </summary> /// <param name="data">Byte buffer containing either digest or data to check against the signature</param> /// <param name="dataIsDigest">Specifies the type of 'data' parameter contents</param> /// <param name="signature">The signature</param> /// <returns>True if the verification succeeds.</returns> private bool VerifySignature(byte[] data, bool dataIsDigest, ISignatureUnion sig) { #if TSS_USE_BCRYPT Debug.Assert(Key != UIntPtr.Zero); #endif TpmAlgId sigScheme = sig.GetUnionSelector(); TpmAlgId sigHash = CryptoLib.SchemeHash(sig); var rsaParams = PublicParms.parameters as RsaParms; if (rsaParams != null) { #if !TSS_USE_BCRYPT Debug.Assert(RsaProvider != null); #endif var s = sig as SignatureRsa; TpmAlgId keyScheme = rsaParams.scheme.GetUnionSelector(); if (keyScheme != TpmAlgId.Null && keyScheme != sigScheme) { Globs.Throw <ArgumentException>("Key scheme and signature scheme do not match"); return(false); } byte[] digest = dataIsDigest ? data : CryptoLib.HashData(sigHash, data); if (sigScheme == TpmAlgId.Rsassa) { #if TSS_USE_BCRYPT return(Key.VerifySignature(digest, s.sig, sigHash, true)); #else return(RsaProvider.VerifyHash(digest, CryptoLib.GetHashName(sigHash), s.sig)); #endif } if (sigScheme == TpmAlgId.Rsapss) { #if true Globs.Throw <ArgumentException>("VerifySignature(): PSS scheme is not supported"); return(false); #else #if TSS_USE_BCRYPT return(BCryptInterface.VerifySignature(KeyHandle, digest, sig.sig, sigHash, false)); #else var rr = new RawRsa(RsaProvider.ExportParameters(false), RsaProvider.KeySize); return(rr.PssVerify(digest, sig.sig, sigHash)); #endif #endif // false } Globs.Throw <ArgumentException>("VerifySignature(): Unrecognized scheme"); return(false); } var eccParams = PublicParms.parameters as EccParms; if (eccParams != null) { if (eccParams.scheme.GetUnionSelector() != TpmAlgId.Ecdsa) { Globs.Throw <ArgumentException>("Unsupported ECC sig scheme"); return(false); } TpmAlgId keyScheme = eccParams.scheme.GetUnionSelector(); if (keyScheme != TpmAlgId.Null && keyScheme != sigScheme) { Globs.Throw <ArgumentException>("Key scheme and signature scheme do not match"); return(false); } var s = sig as SignatureEcdsa; byte[] digest = dataIsDigest ? data : CryptoLib.HashData(sigHash, data); byte[] sigBlob = Globs.Concatenate(s.signatureR, s.signatureS); #if TSS_USE_BCRYPT return(Key.VerifySignature(digest, sigBlob)); #elif !__MonoCS__ Debug.Assert(EcdsaProvider != null); EcdsaProvider.HashAlgorithm = GetCngAlgorithm(sigHash); return(EcdsaProvider.VerifyHash(digest, sigBlob)); #endif // !TSS_USE_BCRYPT && !__MonoCS__ } // Should never be here Globs.Throw("VerifySignature: Unrecognized asymmetric algorithm"); return(false); } // VerifySignature()