/// <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 - SymDefObject symDef = GetSymDef(keyParameters); byte[] symmKey; if (symDef.Algorithm != TpmAlgId.Null) { using (var symmCipher = SymmCipher.Create(symDef)) { symmKey = symmCipher.KeyData; } } else { symmKey = new byte[0]; } // 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 *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); }
/// <summary> /// Create a new random software key (public and private) matching the parameters in keyParams. /// </summary> /// <param name="keyParams"></param> /// <returns></returns> public AsymCryptoSystem(TpmPublic keyParams) { TpmAlgId keyAlgId = keyParams.type; PublicParms = keyParams.Copy(); switch (keyAlgId) { case TpmAlgId.Rsa: { var rsaParams = keyParams.parameters as RsaParms; AsymmetricKeyAlgorithmProvider RsaProvider = AsymmetricKeyAlgorithmProvider.OpenAlgorithm(AsymmetricAlgorithmNames.RsaOaepSha256); Key = RsaProvider.CreateKeyPair(rsaParams.keyBits); IBuffer keyBlobBuffer = Key.ExportPublicKey(CryptographicPublicKeyBlobType.BCryptPublicKey); byte[] blob; CryptographicBuffer.CopyToByteArray(keyBlobBuffer, out blob); var m = new Marshaller(blob, DataRepresentation.LittleEndian); var header = m.Get <BCryptRsaKeyBlob>(); var modulus = m.GetArray <byte>((int)header.cbModulus); var pubId = new Tpm2bPublicKeyRsa(modulus); PublicParms.unique = pubId; break; } case TpmAlgId.Ecc: { var eccParms = keyParams.parameters as EccParms; var alg = RawEccKey.GetEccAlg(keyParams); if (alg == null) { Globs.Throw <ArgumentException>("Unknown ECC curve"); return; } AsymmetricKeyAlgorithmProvider EccProvider = AsymmetricKeyAlgorithmProvider.OpenAlgorithm(alg); Key = EccProvider.CreateKeyPair((uint)RawEccKey.GetKeyLength(eccParms.curveID)); break; } default: Globs.Throw <ArgumentException>("Algorithm not supported"); break; } }
/// <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 a new random software key (public and private) matching the parameters in keyParams. /// </summary> /// <param name="keyParams"></param> /// <returns></returns> public AsymCryptoSystem(TpmPublic keyParams) { TpmAlgId keyAlgId = keyParams.type; PublicParms = keyParams.Copy(); switch (keyAlgId) { case TpmAlgId.Rsa: { var rsaParams = keyParams.parameters as RsaParms; #if TSS_USE_BCRYPT Key = Generate(Native.BCRYPT_RSA_ALGORITHM, rsaParams.keyBits); if (Key == UIntPtr.Zero) { Globs.Throw("Failed to generate RSA key"); return; } byte[] blob = Export(Native.BCRYPT_RSAPUBLIC_BLOB); var m = new Marshaller(blob, DataRepresentation.LittleEndian); var header = m.Get <BCryptRsaKeyBlob>(); /*var exponent = */ m.GetArray <byte>((int)header.cbPublicExp); var modulus = m.GetArray <byte>((int)header.cbModulus); #else RsaProvider = new RSACryptoServiceProvider(rsaParams.keyBits); var modulus = RsaProvider.ExportParameters(true).Modulus; #endif var pubId = new Tpm2bPublicKeyRsa(modulus); PublicParms.unique = pubId; break; } #if !__MonoCS__ case TpmAlgId.Ecc: { var eccParms = keyParams.parameters as EccParms; var alg = RawEccKey.GetEccAlg(keyParams); if (alg == null) { Globs.Throw <ArgumentException>("Unknown ECC curve"); return; } #if TSS_USE_BCRYPT Key = Generate(alg, (uint)RawEccKey.GetKeyLength(eccParms.curveID)); #else var keyParmsX = new CngKeyCreationParameters { ExportPolicy = CngExportPolicies.AllowPlaintextExport }; using (CngKey key = CngKey.Create(alg, null, keyParmsX)) { byte[] keyIs = key.Export(CngKeyBlobFormat.EccPublicBlob); CngKey.Import(keyIs, CngKeyBlobFormat.EccPublicBlob); if (keyParams.objectAttributes.HasFlag(ObjectAttr.Sign)) { EcdsaProvider = new ECDsaCng(key); } else { EcDhProvider = new ECDiffieHellmanCng(key); } } #endif // !TSS_USE_BCRYPT && !__MonoCS__ break; } #endif // !__MonoCS__ default: Globs.Throw <ArgumentException>("Algorithm not supported"); break; } }
/// <summary> /// Create a new AsymCryptoSystem from TPM public parameter. This can then /// be used to validate TPM signatures or encrypt data destined for a TPM. /// </summary> /// <param name="pubKey"></param> /// <param name="privKey"></param> /// <returns></returns> public static AsymCryptoSystem CreateFrom(TpmPublic pubKey, TpmPrivate privKey = null) { var cs = new AsymCryptoSystem(); TpmAlgId keyAlgId = pubKey.type; cs.PublicParms = pubKey.Copy(); // Create an algorithm provider from the provided PubKey switch (keyAlgId) { case TpmAlgId.Rsa: { RawRsa rr = null; byte[] prime1 = null, prime2 = null; if (privKey != null) { rr = new RawRsa(pubKey, privKey); prime1 = RawRsa.ToBigEndian(rr.P); prime2 = RawRsa.ToBigEndian(rr.Q); } var rsaParams = (RsaParms)pubKey.parameters; var exponent = rsaParams.exponent != 0 ? Globs.HostToNet(rsaParams.exponent) : RsaParms.DefaultExponent; var modulus = (pubKey.unique as Tpm2bPublicKeyRsa).buffer; #if TSS_USE_BCRYPT var alg = new BCryptAlgorithm(Native.BCRYPT_RSA_ALGORITHM); cs.Key = alg.LoadRSAKey(exponent, modulus, prime1, prime2); alg.Close(); #else var dotNetPubParms = new RSAParameters() { Exponent = exponent, Modulus = modulus }; if (privKey != null) { dotNetPubParms.P = prime1; dotNetPubParms.Q = prime2; dotNetPubParms.D = RawRsa.ToBigEndian(rr.D); dotNetPubParms.InverseQ = RawRsa.ToBigEndian(rr.InverseQ); dotNetPubParms.DP = RawRsa.ToBigEndian(rr.DP); dotNetPubParms.DQ = RawRsa.ToBigEndian(rr.DQ); } cs.RsaProvider = new RSACryptoServiceProvider(); cs.RsaProvider.ImportParameters(dotNetPubParms); #endif break; } #if !__MonoCS__ case TpmAlgId.Ecc: { var eccParms = (EccParms)pubKey.parameters; var eccPub = (EccPoint)pubKey.unique; var algId = RawEccKey.GetEccAlg(pubKey); if (algId == null) { return(null); } bool isEcdsa = eccParms.scheme.GetUnionSelector() == TpmAlgId.Ecdsa; byte[] keyBlob = RawEccKey.GetKeyBlob(eccPub.x, eccPub.y, keyAlgId, !isEcdsa, eccParms.curveID); #if TSS_USE_BCRYPT var alg = new BCryptAlgorithm(algId); cs.Key = alg.ImportKeyPair(Native.BCRYPT_ECCPUBLIC_BLOB, keyBlob); alg.Close(); if (cs.Key == UIntPtr.Zero) { Globs.Throw("Failed to create new RSA key"); return(null); } #else CngKey eccKey = CngKey.Import(keyBlob, CngKeyBlobFormat.EccPublicBlob); if (pubKey.objectAttributes.HasFlag(ObjectAttr.Sign)) { cs.EcdsaProvider = new ECDsaCng(eccKey); } else { cs.EcDhProvider = new ECDiffieHellmanCng(eccKey); } #endif // !TSS_USE_BCRYPT break; } #endif // !__MonoCS__ default: Globs.Throw <ArgumentException>("Algorithm not supported"); cs = null; break; } return(cs); }
/// <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 - SymDefObject symDef = GetSymDef(keyParameters); byte[] symmKey; if (symDef.Algorithm != TpmAlgId.Null) { using (var symmCipher = SymmCipher.Create(symDef)) { symmKey = symmCipher.KeyData; } } else { symmKey = new byte[0]; } // 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 a new AsymCryptoSystem from TPM public parameter. This can then /// be used to validate TPM signatures or encrypt data destined for a TPM. /// </summary> /// <param name="pubKey"></param> /// <returns></returns> public static AsymCryptoSystem CreateFrom(TpmPublic pubKey, TpmPrivate privKey = null) { var cs = new AsymCryptoSystem(); TpmAlgId keyAlgId = pubKey.type; cs.PublicParms = pubKey.Copy(); // Create an algorithm provider from the provided PubKey switch (keyAlgId) { case TpmAlgId.Rsa: { RawRsa rr = null; byte[] prime1 = null, prime2 = null; if (privKey != null) { rr = new RawRsa(pubKey, privKey); prime1 = RawRsa.ToBigEndian(rr.P); prime2 = RawRsa.ToBigEndian(rr.Q); } var rsaParams = (RsaParms)pubKey.parameters; var exponent = rsaParams.exponent != 0 ? Globs.HostToNet(rsaParams.exponent) : RsaParms.DefaultExponent; var modulus = (pubKey.unique as Tpm2bPublicKeyRsa).buffer; AsymmetricKeyAlgorithmProvider rsaProvider = AsymmetricKeyAlgorithmProvider.OpenAlgorithm(AsymmetricAlgorithmNames.RsaOaepSha256); uint primeLen1 = 0, primeLen2 = 0; // Compute the size of BCRYPT_RSAKEY_BLOB int rsaKeySize = exponent.Length + modulus.Length + 24; if (prime1 != null && prime1.Length > 0) { if (prime2 == null || prime2.Length == 0) { Globs.Throw <ArgumentException>("LoadRSAKey(): The second prime is missing"); return(null); } primeLen1 = (uint)prime1.Length; primeLen2 = (uint)prime2.Length; rsaKeySize += prime1.Length + prime2.Length; } else if (prime2 != null && prime2.Length > 0) { Globs.Throw <ArgumentException>("LoadRSAKey(): The first prime is missing"); return(null); } var rsaKey = new byte[rsaKeySize]; // Initialize BCRYPT_RSAKEY_BLOB int offset = 0; WriteToBuffer(ref rsaKey, ref offset, primeLen1 == 0 ? BCRYPT_RSAPUBLIC_MAGIC : BCRYPT_RSAPRIVATE_MAGIC); WriteToBuffer(ref rsaKey, ref offset, (uint)modulus.Length * 8); WriteToBuffer(ref rsaKey, ref offset, (uint)exponent.Length); WriteToBuffer(ref rsaKey, ref offset, (uint)modulus.Length); WriteToBuffer(ref rsaKey, ref offset, primeLen1); WriteToBuffer(ref rsaKey, ref offset, primeLen1); WriteToBuffer(ref rsaKey, ref offset, exponent); WriteToBuffer(ref rsaKey, ref offset, modulus); if (primeLen1 != 0) { WriteToBuffer(ref rsaKey, ref offset, prime1); WriteToBuffer(ref rsaKey, ref offset, prime2); } IBuffer rsaBuffer = CryptographicBuffer.CreateFromByteArray(rsaKey); if (primeLen1 == 0) { cs.Key = rsaProvider.ImportPublicKey(rsaBuffer, CryptographicPublicKeyBlobType.BCryptPublicKey); } else { cs.Key = rsaProvider.ImportKeyPair(rsaBuffer, CryptographicPrivateKeyBlobType.BCryptPrivateKey); } break; } case TpmAlgId.Ecc: { var eccParms = (EccParms)pubKey.parameters; var eccPub = (EccPoint)pubKey.unique; var algId = RawEccKey.GetEccAlg(pubKey); if (algId == null) { return(null); } bool isEcdsa = eccParms.scheme.GetUnionSelector() == TpmAlgId.Ecdsa; byte[] keyBlob = RawEccKey.GetKeyBlob(eccPub.x, eccPub.y, keyAlgId, !isEcdsa, eccParms.curveID); AsymmetricKeyAlgorithmProvider eccProvider = AsymmetricKeyAlgorithmProvider.OpenAlgorithm(algId); cs.Key = eccProvider.ImportKeyPair(CryptographicBuffer.CreateFromByteArray(keyBlob)); break; } default: Globs.Throw <ArgumentException>("Algorithm not supported"); cs = null; break; } return(cs); }
/// <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; }