Beispiel #1
0
        /// <summary>
        /// Create a simple bound but unseeded session.
        /// </summary>
        public AuthSession StartAuthSessionEx(
            TpmHandle boundEntity,
            TpmSe sessionType,
            TpmAlgId authHash,
            SessionAttr initialialAttrs = SessionAttr.ContinueSession,
            SymDef symDef       = null,
            int nonceCallerSize = 0)
        {
            byte[] nonceTpm;
            var    EmptySalt = new byte[0];

            if (nonceCallerSize == 0)
            {
                nonceCallerSize = CryptoLib.DigestSize(authHash);
            }

            AuthSession sess = StartAuthSession(TpmRh.Null, boundEntity,
                                                GetRandomBytes(nonceCallerSize),
                                                EmptySalt, sessionType,
                                                symDef ?? new SymDef(),
                                                authHash, out nonceTpm)
                               + initialialAttrs;

            _InitializeSession(sess);
            return(sess);
        }
Beispiel #2
0
        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);
        }
Beispiel #3
0
        /// <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);
        }
Beispiel #4
0
        } // 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);
        }
Beispiel #5
0
        /// <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);
        }
Beispiel #6
0
        /// <summary>
        /// Return a TpmHash of the specified algorithm with value set to 0x01010101...  Note that this
        /// is not a 'real' hash value, but is the initialization value of some resettable PCR
        /// </summary>
        /// <param name="alg"></param>
        /// <returns></returns>
        public static TpmHash AllOnesHash(TpmAlgId alg)
        {
            int len = CryptoLib.DigestSize(alg);
            var bb  = new byte[len];

            for (int j = 0; j < bb.Length; j++)
            {
                bb[j] = 0xFF;
            }
            return(new TpmHash(alg, bb));
        }
Beispiel #7
0
 internal override void ToNet(Marshaller m)
 {
     if (CryptoLib.DigestSize(HashAlg) != HashData.Length)
     {
         if (!Tpm2._TssBehavior.Passthrough)
         {
             throw new Exception("Hash data length does not match the algorithm");
         }
     }
     m.Put(HashAlg, "HashAlg");
     m.Put(HashData, "HashData");
 }
Beispiel #8
0
        internal override void ToHost(Marshaller m)
        {
            var id = (TpmAlgId)m.Get(typeof(TpmAlgId), "HashAlg");

            if (id == TpmAlgId.Null)
            {
                _HashAlg = id;
                HashData = new byte[0];
                return;
            }
            _HashAlg = id;
            int hashLength = CryptoLib.DigestSize(id);

            HashData = m.GetArray <byte>(hashLength, "HashData");
        }
Beispiel #9
0
        /// <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);
        }
Beispiel #10
0
        /// <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);
        }
Beispiel #11
0
        // 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)));
        }
Beispiel #12
0
        /// <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>
        /// 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);
        }
Beispiel #14
0
        /// <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));
        }
Beispiel #15
0
        /// <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);
        }
Beispiel #17
0
        public static bool OaepDecode(byte[] eMx, byte[] encodingParms, TpmAlgId hashAlg, out byte[] decoded)
        {
            decoded = new byte[0];

            var em = new byte[eMx.Length + 1];

            Array.Copy(eMx, 0, em, 1, eMx.Length);

            int hLen = CryptoLib.DigestSize(hashAlg);
            int k    = em.Length;

            // a.
            byte[] lHash = CryptoLib.HashData(hashAlg, encodingParms);

            // b.
            byte y = em[0];

            byte[] maskedSeed = Globs.CopyData(em, 1, hLen);
            byte[] maskedDB   = Globs.CopyData(em, 1 + hLen);

            // c.
            byte[] seedMask = CryptoLib.MGF(maskedDB, hLen, hashAlg);

            // d.
            byte[] seed = XorEngine.Xor(maskedSeed, seedMask);

            // e.
            byte[] dbMask = CryptoLib.MGF(seed, k - hLen - 1, hashAlg);

            // f.
            byte[] db = XorEngine.Xor(maskedDB, dbMask);

            // g.
            byte[] lHashPrime = Globs.CopyData(db, 0, hLen);

            // Look for the zero..
            int j;

            for (j = hLen; j < db.Length; j++)
            {
                if (db[j] == 0)
                {
                    continue;
                }

                if (db[j] == 1)
                {
                    break;
                }

                return(false);
            }

            if (j == db.Length - 1)
            {
                return(false);
            }

            byte[] m = Globs.CopyData(db, j + 1);

            if (y != 0)
            {
                return(false);
            }

            if (!Globs.ArraysAreEqual(lHash, lHashPrime))
            {
                return(false);
            }

            decoded = m;
            return(true);
        }
Beispiel #18
0
        /// <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);
        }
Beispiel #19
0
        /// <summary>
        /// Implements unmarshaling logic for most of the TPM object types.
        /// Can be overridden if a custom unmarshaling logic is required (e.g.
        /// when unmarshaling of a field depends on other field's value).
        /// </summary>
        /// <param name="m"></param>
        /// <returns></returns>
        internal virtual void ToHost(Marshaller m)
        {
            dbg.Indent();
            var  members      = GetFieldsToMarshal(true);
            uint mshlStartPos = m.GetGetPos();

            for (int i = 0; i < members.Length; ++i)
            {
                TpmStructMemberInfo memInfo = members[i];
                Type memType  = Globs.GetMemberType(memInfo);
                var  wireType = memInfo.WireType;
                int  size     = -1;
                switch (wireType)
                {
                case MarshalType.Union:
                {
                    dbg.Trace("Union " + memType.Name +
                              " with selector " + memInfo.Tag.Value);
                    var elt = UnionElementFromSelector(memType, memInfo.Tag.Value);
                    memInfo.Value = m.Get(elt, memType.Name);
                    break;
                }

                case MarshalType.FixedLengthArray:
                {
                    object arr = Globs.GetMember(memInfo, this);
                    memInfo.Value = m.GetArray(memType.GetElementType(),
                                               (arr as Array).Length, memInfo.Name);
                    break;
                }

                case MarshalType.SpecialVariableLengthArray:
                {
                    size = CryptoLib.DigestSize((TpmAlgId)members[i - 1].Value);
                    UnmarshalArray(m, memInfo, memType, size);
                    break;
                }

                case MarshalType.VariableLengthArray:
                {
                    size = m.GetSizeTag(memInfo.SizeLength, memInfo.SizeName);
                    UnmarshalArray(m, memInfo, memType, size);
                    break;
                }

                case MarshalType.EncryptedVariableLengthArray:
                {
                    uint unmarshaled = m.GetGetPos() - mshlStartPos;
                    size = m.SizedStructLen[m.SizedStructLen.Count - 1] - (int)unmarshaled;
                    UnmarshalArray(m, memInfo, memType, size);
                    break;
                }

                case MarshalType.SizedStruct:
                {
                    size = m.GetSizeTag(memInfo.SizeLength, memInfo.SizeName);
                    if (size == 0)
                    {
                        break;
                    }
                    m.SizedStructLen.Add(size);
                    memInfo.Value = m.Get(memType, memInfo.Name);
                    int unmSize = Marshaller.GetTpmRepresentation(memInfo.Value).Length;
                    if (unmSize != size)
                    {
                        if (unmSize < size && memType.Name == "TpmPublic")
                        {
                            var pub     = memInfo.Value as TpmPublic;
                            var label   = Marshaller.GetTpmRepresentation(pub.unique);
                            var context = m.GetArray(typeof(byte), size - unmSize, "")
                                          as byte[];
                            pub.unique = new TpmDerive(label, context);
                        }
                        else
                        {
                            var msg = string.Format("Invalid size {0} (instead of "
                                                    + "{1}) for unmarshaled {2}.{3}",
                                                    unmSize, size, this.GetType(), memInfo.Name);
                            throw new TssException(msg);
                        }
                    }
                    m.SizedStructLen.RemoveAt(m.SizedStructLen.Count - 1);
                    break;
                }

                default:
                    // Only attempt unmarshaling a field, if it is not sized or
                    // if its size is non-zero.
                    if (memInfo.Tag == null ||
                        memInfo.Tag.GetValueAsUInt() != 0)
                    {
                        memInfo.Value = m.Get(memType, memInfo.Name);
                    }
                    break;
                }
                dbg.Trace((i + 1) + ": " + wireType + " " + memInfo.Name +
                          (size != -1 ? " of size " + size : ""));
                // Some property values are dynamically obtained from their linked fields.
                // Correspondingly, they do not have a setter, so we bypass them here.
                Debug.Assert(wireType != MarshalType.LengthOfStruct && wireType != MarshalType.ArrayCount);
                if (wireType != MarshalType.UnionSelector)
                {
                    Globs.SetMember(memInfo, this, memInfo.Value);
                }
            }
            dbg.Unindent();
        }
Beispiel #20
0
 /// <summary>
 /// Return the length of the output of the hash function in bytes
 /// </summary>
 /// <param name="hashAlg"></param>
 /// <returns></returns>
 public static ushort DigestSize(TpmAlgId hashAlg)
 {
     return((ushort)CryptoLib.DigestSize(hashAlg));
 }
Beispiel #21
0
        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);
        }
Beispiel #22
0
        /// <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));
        }
Beispiel #23
0
        /// <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));
        }