public byte[] EncryptDecrypt(byte[] data, bool decrypt, ref byte[] ivIn, out byte[] ivOut) { ivOut = null; if (Public.type != TpmAlgId.Symcipher) { Globs.Throw <ArgumentException>("Only symmetric encryption/decryption is " + "supported by this overloaded version"); return(null); } var symDef = GetSymDef(); using (var sym = SymCipher.Create(symDef, (Sensitive.sensitive as Tpm2bSymKey).buffer)) { if (sym == null) { Globs.Throw <ArgumentException>("Unsupported symmetric key configuration"); return(null); } if (Globs.IsEmpty(ivIn)) { ivIn = (symDef.Mode == TpmAlgId.Ecb) ? new byte[0] : Globs.GetRandomBytes(SymCipher.GetBlockSize(symDef)); } ivOut = Globs.CopyData(ivIn); return(decrypt ? sym.Decrypt(data, ivOut) : sym.Encrypt(data, ivOut)); } } // EncryptDecrypt
/// <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> /// 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[] 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); }
/// <summary> /// Return a new TpmHash that is the hash of random data /// </summary> /// <param name="hashAlg"></param> /// <returns></returns> public static TpmHash FromRandom(TpmAlgId hashAlg) { if (!CryptoLib.IsHashAlgorithm(hashAlg)) { Globs.Throw <ArgumentException>("TpmHash.FromRandom: Not a hash algorithm"); } return(new TpmHash(hashAlg, CryptoLib.HashData(hashAlg, Globs.GetRandomBytes((int)DigestSize(hashAlg))))); }
/// <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); }
/// <summary> /// Creates an auth value comprising the specified number of random bytes. /// Since the TPM removes trailing zeros, this routine makes sure that the last /// byte is non-zero. /// </summary> /// <param name="numBytes"></param> /// <returns></returns> public static AuthValue FromRandom(int numBytes) { if (numBytes == 0) { return(new AuthValue(new byte[0])); } byte[] trial = null; do { trial = Globs.GetRandomBytes(numBytes); } while (trial[numBytes - 1] == 0); return(new AuthValue(trial)); }
/// <summary> /// Creates a *software* key. The key will be random (not created from /// a seed). The key can be used as the root of a software hierarchy that /// can be translated into a duplication blob ready for import into a TPM. /// Depending on the type of key, the software root key can be a parent for /// other root keys that can comprise a migration group. The caller should /// specify necessary key parameters in Public. /// /// Parameter keyData is used only with symmetric or HMAC keys. If non-null /// on entry, it contains the key bytes supplied by the caller, otherwise the /// key will be randomly generated. For asymmetric keys keyData must be null. /// /// Parameter authVal specifies the authorization value associated with the key. /// If it is null, then an random value will be used. /// </summary> /// <param name="pub"></param> /// <param name="authVal"></param> /// <param name="keyData"></param> /// <returns></returns> public static TssObject Create(TpmPublic pub, AuthValue authVal = null, byte[] keyData = null) { var newKey = new TssObject(); // Create a new key from the supplied parameters IPublicIdUnion publicId; var sensData = CreateSensitiveComposite(pub, ref keyData, out publicId); var nameSize = CryptoLib.DigestSize(pub.nameAlg); // Create the associated seed value byte[] seed = Globs.GetRandomBytes(nameSize); // Fill in the fields for the symmetric private-part of the asymmetric key var sens = new Sensitive(authVal ?? AuthValue.FromRandom(nameSize), seed, sensData); newKey.Sensitive = sens; newKey.Private = new TpmPrivate(sens.GetTpm2BRepresentation()); // fill in the public data newKey.Public = pub.Copy(); if (pub.type == TpmAlgId.Keyedhash || pub.type == TpmAlgId.Symcipher) { byte[] unique = null; if (pub.objectAttributes.HasFlag(ObjectAttr.Restricted | ObjectAttr.Decrypt)) { unique = CryptoLib.Hmac(pub.nameAlg, seed, keyData); } else { unique = CryptoLib.HashData(pub.nameAlg, seed, keyData); } newKey.Public.unique = pub.type == TpmAlgId.Keyedhash ? new Tpm2bDigestKeyedhash(unique) as IPublicIdUnion : new Tpm2bDigestSymcipher(unique); } else { newKey.Public.unique = publicId; } // And return the new key return(newKey); }
internal async Task <Tpm2CreatePrimaryResponse> CreatePrimaryRsaAsyncInternal( int keyLen, byte[] useAuth, byte[] policyAuth, PcrSelection[] pcrSel) { ObjectAttr attr = ObjectAttr.Restricted | ObjectAttr.Decrypt | ObjectAttr.FixedParent | ObjectAttr.FixedTPM | ObjectAttr.SensitiveDataOrigin; var theUseAuth = new byte[0]; if (useAuth != null) { theUseAuth = useAuth; attr |= ObjectAttr.UserWithAuth; } var thePolicyAuth = new byte[0]; if (policyAuth != null) { thePolicyAuth = policyAuth; attr |= ObjectAttr.AdminWithPolicy; } var theSelection = new PcrSelection[0]; if (pcrSel != null) { theSelection = pcrSel; } var sensCreate = new SensitiveCreate(theUseAuth, new byte[0]); var parms = new TpmPublic(H.NameHash, attr, thePolicyAuth, new RsaParms(new SymDefObject(TpmAlgId.Aes, 128, TpmAlgId.Cfb), new NullAsymScheme(), (ushort)keyLen, 0), new Tpm2bPublicKeyRsa()); byte[] outsideInfo = Globs.GetRandomBytes(8); return(await H.Tpm.CreatePrimaryAsync(TpmRh.Owner, sensCreate, parms, outsideInfo, theSelection)); }
/// <summary> /// Creates a *software* root key. The key will be random (not created from a seed). The key can be used /// as the root of a software hierarchy that can be translated into a duplication blob ready for import into /// a TPM. Depending on the type of key, the software root key can be a parent for other root keys that can /// comprise a migration group. The caller should specify necessary key parameters in Public. /// </summary> /// <returns></returns> public static TssObject CreateStorageParent(TpmPublic keyParameters, AuthValue authVal) { var newKey = new TssObject(); // Create a new asymmetric key from the supplied parameters IPublicIdUnion publicId; ISensitiveCompositeUnion sensitiveData = CreateSensitiveComposite(keyParameters, out publicId); // fill in the public data newKey.publicPart = keyParameters.Copy(); newKey.publicPart.unique = publicId; // Create the associated symmetric key byte[] symmKey = Globs.GetRandomBytes(CryptoLib.DigestSize(keyParameters.nameAlg)); // Fill in the fields for the symmetric private-part of the asymmetric key var sens = new Sensitive(authVal.AuthVal, symmKey, sensitiveData); newKey.sensitivePart = sens; // And return the new key return(newKey); }
/// <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)); }
CreateSensitiveComposite(TpmPublic pub, ref byte[] keyData, out IPublicIdUnion publicId) { ISensitiveCompositeUnion newSens = null; publicId = null; if (pub.type == TpmAlgId.Rsa) { if (keyData != null) { Globs.Throw <ArgumentException>("Cannot specify key data for an RSA key"); return(null); } var newKeyPair = new RawRsa((pub.parameters as RsaParms).keyBits); // Put the key bits into the required structure envelopes newSens = new Tpm2bPrivateKeyRsa(newKeyPair.Private); publicId = new Tpm2bPublicKeyRsa(newKeyPair.Public); } else if (pub.type == TpmAlgId.Symcipher) { var symDef = (SymDefObject)pub.parameters; if (symDef.Algorithm != TpmAlgId.Aes) { Globs.Throw <ArgumentException>("Unsupported symmetric algorithm"); return(null); } int keySize = (symDef.KeyBits + 7) / 8; if (keyData == null) { keyData = Globs.GetRandomBytes(keySize); } else if (keyData.Length != keySize) { keyData = Globs.CopyData(keyData); } else { Globs.Throw <ArgumentException>("Wrong symmetric key length"); return(null); } newSens = new Tpm2bSymKey(keyData); } else if (pub.type == TpmAlgId.Keyedhash) { var scheme = (pub.parameters as KeyedhashParms).scheme; TpmAlgId hashAlg = scheme is SchemeHash ? (scheme as SchemeHash).hashAlg : scheme is SchemeXor ? (scheme as SchemeXor).hashAlg : pub.nameAlg; var digestSize = CryptoLib.DigestSize(hashAlg); if (keyData == null) { keyData = Globs.GetRandomBytes(digestSize); } else if (keyData.Length <= CryptoLib.BlockSize(hashAlg)) { keyData = Globs.CopyData(keyData); } else { Globs.Throw <ArgumentException>("HMAC key is too big"); return(null); } newSens = new Tpm2bSensitiveData(keyData); } else { Globs.Throw <ArgumentException>("Unsupported key type"); } return(newSens); }
/// <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)); }
public void NewNonceCaller() { // Make a new nonce as big as the last NonceCaller = Globs.GetRandomBytes(NonceCaller.Length); }
/// <summary> /// Create a new SymCipher object with a random key based on the alg and mode supplied. /// </summary> /// <param name="symDef"></param> /// <param name="keyData"></param> /// <param name="iv"></param> /// <returns></returns> public static SymCipher Create(SymDefObject symDef = null, byte[] keyData = null, byte[] iv = null) { if (symDef == null) { symDef = new SymDefObject(TpmAlgId.Aes, 128, TpmAlgId.Cfb); } #if TSS_USE_BCRYPT BCryptAlgorithm alg = null; switch (symDef.Algorithm) { case TpmAlgId.Aes: alg = new BCryptAlgorithm(Native.BCRYPT_AES_ALGORITHM); break; case TpmAlgId.Tdes: alg = new BCryptAlgorithm(Native.BCRYPT_3DES_ALGORITHM); break; default: Globs.Throw <ArgumentException>("Unsupported symmetric algorithm " + symDef.Algorithm); return(null); } if (keyData == null) { keyData = Globs.GetRandomBytes(symDef.KeyBits / 8); } var key = alg.GenerateSymKey(symDef, keyData, GetBlockSize(symDef)); //key = BCryptInterface.ExportSymKey(keyHandle); //keyHandle = alg.LoadSymKey(key, symDef, GetBlockSize(symDef)); alg.Close(); return(key == null ? null : new SymCipher(key, keyData, iv, GetBlockSize(symDef))); #else // !TSS_USE_BCRYPT if (symDef.Mode == TpmAlgId.Ofb) { return(null); } var mode = GetCipherMode(symDef.Mode); if (mode == CipherMode_None) { return(null); } SymmetricAlgorithm alg = null; // = new RijndaelManaged(); bool limitedSupport = false; int feedbackSize = 0; switch (symDef.Algorithm) { case TpmAlgId.Aes: alg = new RijndaelManaged(); alg.Mode = mode == CipherMode.CFB ? CipherMode.ECB : mode; break; case TpmAlgId.Tdes: // DES and __3DES are not supported in TPM 2.0 rev. < 1.32 alg = new TripleDESCryptoServiceProvider(); alg.Mode = mode; if (mode == CipherMode.CFB) { feedbackSize = 8; } limitedSupport = true; break; default: //Globs.Throw<ArgumentException>("Unsupported symmetric algorithm " + symDef.Algorithm); return(null); } int blockSize = GetBlockSize(symDef); alg.KeySize = symDef.KeyBits; alg.BlockSize = blockSize * 8; alg.Padding = PaddingMode.None; alg.FeedbackSize = feedbackSize == 0 ? alg.BlockSize : feedbackSize; if (keyData == null) { // Generate random key alg.IV = Globs.GetZeroBytes(blockSize); try { alg.GenerateKey(); } catch (Exception) { alg.Dispose(); throw; } } else { // Use supplied key bits alg.Key = keyData; if (iv == null) { iv = Globs.GetZeroBytes(blockSize); } else if (iv.Length != blockSize) { Array.Resize(ref iv, blockSize); } alg.IV = iv; } var symCipher = new SymCipher(alg, mode); symCipher.LimitedSupport = limitedSupport; return(symCipher); #endif // !TSS_USE_BCRYPT } // Create()
/// <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> /// EME-OAEP PKCS1.2, section 9.1.1.1. /// </summary> /// <param name="message"></param> /// <param name="encodingParameters"></param> /// <param name="hashAlg"></param> /// <param name="modulusNumBytes"></param> /// <returns></returns> public static byte[] OaepEncode(byte[] message, byte[] encodingParameters, TpmAlgId hashAlg, int modulusNumBytes) { int encodedMessageLength = modulusNumBytes - 1; int messageLength = message.Length; int hashLength = CryptoLib.DigestSize(hashAlg); // 1 (Step numbers from RSA labs spec.) // Ignore the ParametersLength limitation // 2 if (messageLength > encodedMessageLength - 2 * hashLength - 1) { if (Tpm2._TssBehavior.Passthrough) { return(new byte[0]); } else { throw new ArgumentException("input message too long"); } } int psLen = encodedMessageLength - messageLength - 2 * hashLength - 1; var ps = new byte[psLen]; // 3 (Not needed.) for (int j = 0; j < psLen; j++) { ps[j] = 0; } // 4 byte[] pHash = CryptoLib.HashData(hashAlg, encodingParameters); // 5 var db = new byte[hashLength + psLen + 1 + messageLength]; var one = new byte[1]; one[0] = 1; pHash.CopyTo(db, 0); ps.CopyTo(db, pHash.Length); one.CopyTo(db, pHash.Length + ps.Length); message.CopyTo(db, pHash.Length + ps.Length + 1); // 6 byte[] seed = Globs.GetRandomBytes(hashLength); // 7 byte[] dbMask = CryptoLib.MGF(seed, encodedMessageLength - hashLength, hashAlg); // 8 byte[] maskedDb = XorEngine.Xor(db, dbMask); // 9 byte[] seedMask = CryptoLib.MGF(maskedDb, hashLength, hashAlg); // 10 byte[] maskedSeed = XorEngine.Xor(seed, seedMask); //11 var encodedMessage = new byte[maskedSeed.Length + maskedDb.Length]; maskedSeed.CopyTo(encodedMessage, 0); maskedDb.CopyTo(encodedMessage, maskedSeed.Length); // 12 return(encodedMessage); }
/// <summary> /// Create a new SymmCipher object with a random key based on the alg and mode supplied. /// </summary> /// <param name="algId"></param> /// <param name="numBits"></param> /// <param name="mode"></param> /// <returns></returns> public static SymmCipher Create(SymDefObject symDef = null, byte[] keyData = null, byte[] iv = null) { if (symDef == null) { symDef = new SymDefObject(TpmAlgId.Aes, 128, TpmAlgId.Cfb); } string algName = ""; switch (symDef.Algorithm) { case TpmAlgId.Aes: switch (symDef.Mode) { case TpmAlgId.Cbc: algName = SymmetricAlgorithmNames.AesCbc; break; case TpmAlgId.Ecb: algName = SymmetricAlgorithmNames.AesEcb; break; case TpmAlgId.Cfb: algName = SymmetricAlgorithmNames.AesCbcPkcs7; break; default: Globs.Throw <ArgumentException>("Unsupported mode (" + symDef.Mode + ") for algorithm " + symDef.Algorithm); break; } break; case TpmAlgId.Tdes: switch (symDef.Mode) { case TpmAlgId.Cbc: algName = SymmetricAlgorithmNames.TripleDesCbc; break; case TpmAlgId.Ecb: algName = SymmetricAlgorithmNames.TripleDesEcb; break; default: Globs.Throw <ArgumentException>("Unsupported mode (" + symDef.Mode + ") for algorithm " + symDef.Algorithm); break; } break; default: Globs.Throw <ArgumentException>("Unsupported symmetric algorithm " + symDef.Algorithm); break; } if (keyData == null) { keyData = Globs.GetRandomBytes(symDef.KeyBits / 8); } SymmetricKeyAlgorithmProvider algProvider = SymmetricKeyAlgorithmProvider.OpenAlgorithm(algName); var key = algProvider.CreateSymmetricKey(CryptographicBuffer.CreateFromByteArray(keyData)); return(key == null ? null : new SymmCipher(key, keyData, iv)); }
/// <summary> /// Create a new SymmCipher object with a random key based on the alg and mode supplied. /// </summary> /// <param name="algId"></param> /// <param name="numBits"></param> /// <param name="mode"></param> /// <returns></returns> public static SymmCipher Create(SymDefObject symDef = null, byte[] keyData = null, byte[] iv = null) { if (symDef == null) { symDef = new SymDefObject(TpmAlgId.Aes, 128, TpmAlgId.Cfb); } else if (symDef.Algorithm != TpmAlgId.Aes) { Globs.Throw <ArgumentException>("Unsupported symmetric algorithm " + symDef.Algorithm); return(null); } #if TSS_USE_BCRYPT var alg = new BCryptAlgorithm(Native.BCRYPT_AES_ALGORITHM); if (keyData == null) { keyData = Globs.GetRandomBytes(symDef.KeyBits / 8); } var key = alg.GenerateSymKey(symDef, keyData, GetBlockSize(symDef)); //key = BCryptInterface.ExportSymKey(keyHandle); //keyHandle = alg.LoadSymKey(key, symDef, GetBlockSize(symDef)); alg.Close(); return(new SymmCipher(key, keyData, iv)); #else SymmetricAlgorithm alg = new RijndaelManaged(); // DES and __3DES are not supported in TPM 2.0 v 0.96 and above //switch (algId) { // case TpmAlgId.Aes: alg = new RijndaelManaged(); break; // case TpmAlgId.__3DES: alg = new TripleDESCryptoServiceProvider(); break; // case TpmAlgId.Des: alg = new DESCryptoServiceProvider(); break; //} int blockSize = GetBlockSize(symDef); alg.KeySize = symDef.KeyBits; alg.BlockSize = blockSize * 8; alg.Padding = PaddingMode.None; alg.Mode = GetCipherMode(symDef.Mode); // REVISIT: Get this right for other modes alg.FeedbackSize = alg.BlockSize; if (keyData == null) { // Generate random key alg.IV = Globs.GetZeroBytes(blockSize); try { alg.GenerateKey(); } catch (Exception) { alg.Dispose(); throw; } } else { // Use supplied key bits alg.Key = keyData; if (iv == null) { iv = Globs.GetZeroBytes(blockSize); } else if (iv.Length != blockSize) { Array.Resize(ref iv, blockSize); } alg.IV = iv; } return(new SymmCipher(alg)); #endif }