public static byte[] Xor(byte[] data, TpmAlgId hashAlg, byte[] key, byte[] contextU, byte[] contextV) { byte[] mask = KDF.KDFa(hashAlg, key, "XOR", contextU, contextV, data.Length * 8); byte[] encData = Xor(mask, data); return(encData); }
/// <summary> /// Creates a Private area for this key so that it can be loaded into a TPM by /// TPM2_Load() if the target TPM already has the storage key 'parent' loaded. /// This function lets an application to create key hierarchies in software /// that can be loaded into a TPM once the parent has been TPM2_Import'ed. /// TPM2_Import() supports plaintext import. To get this sort of import blob, /// set 'parent' to null. /// </summary> /// <param name="parent"></param> /// <returns></returns> public TpmPrivate GetPrivate(TssObject parent) { SymDefObject symDef = GetSymDef(parent.Public); // Figure out how many bits we will need from the KDF byte[] parentSymSeed = parent.Sensitive.seedValue; Transform(parentSymSeed); byte[] iv = (symDef.Mode == TpmAlgId.Ecb) ? new byte[0] : Globs.GetRandomBytes(SymCipher.GetBlockSize(symDef)); // The encryption key is calculated with a KDF byte[] symKey = KDF.KDFa(parent.Public.nameAlg, parentSymSeed, "STORAGE", GetName(), new byte[0], symDef.KeyBits); Transform(symKey); byte[] newPrivate = KeyWrapper.CreatePrivateFromSensitive( symDef, symKey, iv, Sensitive, Public.nameAlg, Public.GetName(), parent.Public.nameAlg, parent.Sensitive.seedValue, TransformerCallback); Transform(newPrivate); return(new TpmPrivate(newPrivate)); }
/// <summary> /// De-envelope inner-wrapped duplication blob. /// TODO: Move this to TpmPublic and make it fully general /// </summary> /// <param name="exportedPrivate"></param> /// <param name="encAlg"></param> /// <param name="encKey"></param> /// <param name="nameAlg"></param> /// <param name="name"></param> /// <returns></returns> public static Sensitive SensitiveFromDuplicateBlob(TpmPrivate exportedPrivate, SymDefObject encAlg, byte[] encKey, TpmAlgId nameAlg, byte[] name) { byte[] dupBlob = exportedPrivate.buffer; byte[] sensNoLen; using (SymmCipher c = Create(encAlg, encKey)) { byte[] innerObject = c.Decrypt(dupBlob); byte[] innerIntegrity, sensitive; KDF.Split(innerObject, 16 + CryptoLib.DigestSize(nameAlg) * 8, out innerIntegrity, 8 * (innerObject.Length - CryptoLib.DigestSize(nameAlg) - 2), out sensitive); byte[] expectedInnerIntegrity = Marshaller.ToTpm2B(CryptoLib.HashData(nameAlg, sensitive, name)); if (!Globs.ArraysAreEqual(expectedInnerIntegrity, innerIntegrity)) { Globs.Throw("SensitiveFromDuplicateBlob: Bad inner integrity"); } sensNoLen = Marshaller.Tpm2BToBuffer(sensitive); } var sens = Marshaller.FromTpmRepresentation <Sensitive>(sensNoLen); return(sens); }
/// <summary> /// Creates a Private area for this key that will be loadable on a TPM though TPM2_Load() if the target TPM already has the parent /// storage key "parent" loaded. This function lets applications create key-hierarchies in software that can be loaded into /// a TPM once the parent has been "TPM2_Import'ed." /// TPM2_Import() supports plaintext import. To get this sort of import blob set intendedParent /// to null /// </summary> /// <param name="intendedParent"></param> /// <returns></returns> public TpmPrivate GetPrivate(TssObject intendedParent) { SymDefObject symDef = GetSymDef(intendedParent.publicPart); // Figure out how many bits we will need from the KDF byte[] parentSymValue = intendedParent.sensitivePart.seedValue; byte[] iv = Globs.GetRandomBytes(SymmCipher.GetBlockSize(symDef)); // The encryption key is calculated with a KDF byte[] symKey = KDF.KDFa(intendedParent.publicPart.nameAlg, parentSymValue, "STORAGE", GetName(), new byte[0], symDef.KeyBits); byte[] newPrivate = KeyWrapper.CreatePrivateFromSensitive(symDef, symKey, iv, sensitivePart, publicPart.nameAlg, publicPart.GetName(), intendedParent.publicPart.nameAlg, intendedParent.sensitivePart.seedValue); return(new TpmPrivate(newPrivate)); }
public static byte[] KdfThenXor(TpmAlgId hashAlg, byte[] key, byte[] contextU, byte[] contextV, byte[] data) { var mask = KDF.KDFa(hashAlg, key, "XOR", contextU, contextV, data.Length * 8); return(XorEngine.Xor(data, mask)); }
private static void FillRandBuf() { // Fill the buffer with random data byte[] contextU = HostToNet(_randRound); byte[] data = KDF.KDFa(TpmAlgId.Sha256, _randSeed, "RNG", contextU, new byte[0], (uint)RandMaxBytes * 8); _randRound++; _randBuf = new ByteBuf(data); }
private void FillRandBuf() { // Fill the buffer with random data byte[] data = KDF.KDFa(TpmAlgId.Sha256, Seed, "RNG", BitConverter.GetBytes(Round), new byte[0], RandMaxBytes * 8); Round++; Buf = new ByteBuf(data); }
/// <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); }
internal byte[] ParmEncrypt(byte[] parm, Direction inOrOut) { if (Symmetric == null) { Globs.Throw("parameter encryption cipher not defined"); return(parm); } if (Symmetric.Algorithm == TpmAlgId.Null) { return(parm); } byte[] nonceNewer, nonceOlder; if (inOrOut == Direction.Command) { nonceNewer = NonceCaller; nonceOlder = NonceTpm; } else { nonceNewer = NonceTpm; nonceOlder = NonceCaller; } byte[] encKey = (AuthHandle != null && AuthHandle.Auth != null) ? SessionKey.Concat(Globs.TrimTrailingZeros(AuthHandle.Auth)).ToArray() : SessionKey; if (Symmetric.Algorithm == TpmAlgId.Xor) { return(CryptoLib.KdfThenXor(AuthHash, encKey, nonceNewer, nonceOlder, parm)); } int keySize = (Symmetric.KeyBits + 7) / 8, blockSize = SymCipher.GetBlockSize(Symmetric), bytesRequired = keySize + blockSize; byte[] keyInfo = KDF.KDFa(AuthHash, encKey, "CFB", nonceNewer, nonceOlder, bytesRequired * 8); var key = new byte[keySize]; Array.Copy(keyInfo, 0, key, 0, keySize); var iv = new byte[blockSize]; Array.Copy(keyInfo, keySize, iv, 0, blockSize); // Make a new SymCipher from the key and IV and do the encryption. using (SymCipher s = SymCipher.Create(Symmetric, key, iv)) { return(inOrOut == Direction.Command ? s.Encrypt(parm) : s.Decrypt(parm)); } }
/// <summary> /// Create an enveloped (encrypted and integrity protected) private area from a provided sensitive. /// </summary> /// <param name="iv"></param> /// <param name="sens"></param> /// <param name="nameHash"></param> /// <param name="publicName"></param> /// <param name="symWrappingAlg"></param> /// <param name="symKey"></param> /// <param name="parentNameAlg"></param> /// <param name="parentSeed"></param> /// <param name="f"></param> /// <returns></returns> public static byte[] CreatePrivateFromSensitive( SymDefObject symWrappingAlg, byte[] symKey, byte[] iv, Sensitive sens, TpmAlgId nameHash, byte[] publicName, TpmAlgId parentNameAlg, byte[] parentSeed, TssObject.Transformer f = null) { // ReSharper disable once InconsistentNaming byte[] tpm2bIv = Marshaller.ToTpm2B(iv); Transform(tpm2bIv, f); byte[] sensitive = sens.GetTpmRepresentation(); Transform(sensitive, f); // ReSharper disable once InconsistentNaming byte[] tpm2bSensitive = Marshaller.ToTpm2B(sensitive); Transform(tpm2bSensitive, f); byte[] encSensitive = SymCipher.Encrypt(symWrappingAlg, symKey, iv, tpm2bSensitive); Transform(encSensitive, f); byte[] decSensitive = SymCipher.Decrypt(symWrappingAlg, symKey, iv, encSensitive); Debug.Assert(f != null || Globs.ArraysAreEqual(decSensitive, tpm2bSensitive)); var hmacKeyBits = CryptoLib.DigestSize(parentNameAlg) * 8; byte[] hmacKey = KDF.KDFa(parentNameAlg, parentSeed, "INTEGRITY", new byte[0], new byte[0], hmacKeyBits); Transform(hmacKey, f); byte[] dataToHmac = Marshaller.GetTpmRepresentation(tpm2bIv, encSensitive, publicName); Transform(dataToHmac, f); byte[] outerHmac = CryptoLib.Hmac(parentNameAlg, hmacKey, dataToHmac); Transform(outerHmac, f); byte[] priv = Marshaller.GetTpmRepresentation(Marshaller.ToTpm2B(outerHmac), tpm2bIv, encSensitive); Transform(priv, f); return(priv); }
/// <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); }
/// <summary> /// Create an enveloped (encrypted and integrity protected) private area from a provided sensitive. /// </summary> /// <param name="iv"></param> /// <param name="sens"></param> /// <param name="nameHash"></param> /// <param name="publicName"></param> /// <param name="symWrappingAlg"></param> /// <param name="symKey"></param> /// <param name="parentNameAlg"></param> /// <param name="parentSeed"></param> /// <param name="f"></param> /// <returns></returns> public static byte[] CreatePrivateFromSensitive( SymDefObject symWrappingAlg, byte[] symKey, byte[] iv, Sensitive sens, TpmAlgId nameHash, byte[] publicName, TpmAlgId parentNameAlg, byte[] parentSeed) { // ReSharper disable once InconsistentNaming byte[] tpm2bIv = Marshaller.ToTpm2B(iv); byte[] sensitive = sens.GetTpmRepresentation(); // ReSharper disable once InconsistentNaming byte[] tpm2bSensitive = Marshaller.ToTpm2B(sensitive); byte[] encSensitive = SymmCipher.Encrypt(symWrappingAlg, symKey, iv, tpm2bSensitive); byte[] decSensitive = SymmCipher.Decrypt(symWrappingAlg, symKey, iv, encSensitive); var hmacKeyBits = CryptoLib.DigestSize(parentNameAlg) * 8; byte[] hmacKey = KDF.KDFa(parentNameAlg, parentSeed, "INTEGRITY", new byte[0], new byte[0], hmacKeyBits); byte[] dataToHmac = Marshaller.GetTpmRepresentation(tpm2bIv, encSensitive, publicName); byte[] outerHmac = CryptoLib.HmacData(parentNameAlg, hmacKey, dataToHmac); byte[] priv = Marshaller.GetTpmRepresentation(Marshaller.ToTpm2B(outerHmac), tpm2bIv, encSensitive); return(priv); }
/// <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)); }