Beispiel #1
0
        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
Beispiel #2
0
        /// <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));
        }
Beispiel #3
0
 public static byte[] Decrypt(SymDefObject symDef, byte[] key, byte[] iv,
                              byte[] dataToDecrypt)
 {
     using (SymCipher cipher = Create(symDef, key, iv))
     {
         return(cipher.Decrypt(dataToDecrypt));
     }
 }
Beispiel #4
0
        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));
            }
        }
Beispiel #5
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 #6
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 SensitiveFromDupBlob(TpmPrivate exportedPrivate,
                                                     SymDefObject encAlg, byte[] encKey,
                                                     TpmAlgId nameAlg, byte[] name)
        {
            byte[] dupBlob   = exportedPrivate.buffer;
            byte[] sensNoLen = null;
            using (SymCipher c = Create(encAlg, encKey))
            {
                byte[] innerObject = null;
                if (c == null)
                {
                    if (encAlg.Algorithm != TpmAlgId.Null)
                    {
                        return(null);
                    }
                    else
                    {
                        return(Marshaller.FromTpmRepresentation <Sensitive>(Marshaller.Tpm2BToBuffer(dupBlob)));
                    }
                }
                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("SensitiveFromDupBlob: Bad inner integrity");
                }

                sensNoLen = Marshaller.Tpm2BToBuffer(sensitive);
            }
            var sens = Marshaller.FromTpmRepresentation <Sensitive>(sensNoLen);

            return(sens);
        }
Beispiel #7
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 #8
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 #9
0
        /// <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()