我有一个设置,我需要加密一个应用程序中的数据块,并在不同的应用程序中解密它。
我构建了一个示例应用程序,它创建了一个名为CngKey对象。然后使用RSACng对象创建一个CngKey。然后使用RSACng对象进行加密/解密。我发现,尽管应用程序是使用创建时使用的名称加载的,但在重新启动过程中会发生关键更改。我无法理解CngKey和RSACng对象之间的关系。
下面是描述我所要做的事情的代码片段:
using System; using System.IO; using System.Security.Cryptography; namespace TPMCrypto class Program static byte[] data = { 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20 }; static byte[] privateKey; private static byte[] encrypted; private static byte[] decrypted; static void Main(string[] args) const string MyKey = "MyRSAKey"; CngKey cngKey = null; string cmd = args.Length > 0 ? args[0] : ""; CngKeyCreationParameters cng = new CngKeyCreationParameters KeyUsage = CngKeyUsages.AllUsages, KeyCreationOptions = CngKeyCreationOptions.MachineKey, Provider = CngProvider.MicrosoftSoftwareKeyStorageProvider if (!CngKey.Exists(MyKey, CngProvider.MicrosoftSoftwareKeyStorageProvider, CngKeyOpenOptions.MachineKey)) Console.WriteLine("Creating rsaKey"); cngKey = CngKey.Create(CngAlgorithm.Rsa, MyKey, cng); Console.WriteLine("Opening rsaKey"); cngKey = CngKey.Open(MyKey, CngProvider.MicrosoftSoftwareKeyStorageProvider, CngKeyOpenOptions.MachineKey); RSACng rsaKey = new RSACng(cngKey) KeySize = 2048 privateKey = rsaKey.Key.Export(CngKeyBlobFormat.GenericPrivateBlob); string prvResult = ByteArrayToHexString(privateKey, 0, privateKey.Length); Console.WriteLine("\nPrivate key - length = " + privateKey.Length + "\n" + prvResult + "\n"); const string FILE_PATH = @"\temp\tpmtests\encryptedblob.dat"; // Encrypt / decrypt if (cmd == "readfromfile") Directory.CreateDirectory(Path.GetDirectoryName(FILE_PATH)); encrypted = File.ReadAllBytes(FILE_PATH); else if (cmd == "deletekey") cngKey.Delete(); return; encrypted = Encrypt(rsaKey, data); Console.WriteLine("The encrypted blob: "); Console.WriteLine(ByteArrayToHexString(encrypted, 0, encrypted.Length)); File.WriteAllBytes(FILE_PATH, encrypted); decrypted = Decrypt(rsaKey, encrypted); bool result = ByteArrayCompare(data, decrypted); if (result) Console.WriteLine("Encrypt / decrypt works"); Console.WriteLine("Encrypt / decrypt fails"); catch (Exception e) Console.WriteLine("Exception " + e.Message); finally if (cngKey != null) cngKey.Dispose(); Console.ReadLine(); static bool ByteArrayCompare(byte[] a1, byte[] a2) if (a1.Length != a2.Length) return false; for (int i = 0; i < a1.Length; i++) if (a1[i] != a2[i]) return false; return true; public static string ByteArrayToHexString(byte[] bytes, int start, int length) string delimitedStringValue = BitConverter.ToString(bytes, start, length); return delimitedStringValue.Replace("-", ""); public static byte[] Sign512(byte[] data, byte[] privateKey) CngKey key = CngKey.Import(privateKey, CngKeyBlobFormat.GenericPrivateBlob); RSACng crypto = new RSACng(key); return crypto.SignData(data, HashAlgorithmName.SHA512, RSASignaturePadding.Pkcs1); public static bool VerifySignature512(byte[] data, byte[] signature, byte[] publicKey) CngKey key = CngKey.Import(publicKey, CngKeyBlobFormat.GenericPublicBlob); RSACng crypto = new RSACng(key); return crypto.VerifyData(data, signature, HashAlgorithmName.SHA512, RSASignaturePadding.Pkcs1); public static byte[] Encrypt(byte[] publicKey, byte[] data) CngKey key = CngKey.Import(publicKey, CngKeyBlobFormat.GenericPublicBlob); RSACng crypto = new RSACng(key); var result = Encrypt(crypto, data); return result; public static byte[] Encrypt(RSACng crypto, byte[] data) if (null == crypto) return null; var result = crypto.Encrypt(data, RSAEncryptionPadding.OaepSHA512); return result; public static byte[] Decrypt(byte[] privateKey, byte[] data) CngKey key = CngKey.Import(privateKey, CngKeyBlobFormat.GenericPrivateBlob); RSACng crypto = new RSACng(key); var result = Decrypt(crypto, data); return result; public static byte[] Decrypt(RSACng aKey, byte[] data) if (null == aKey) return null; var result = aKey.Decrypt(data, RSAEncryptionPadding.OaepSHA512); return result; }
我知道dpapi以及如何使用它来完成这个任务。我不想用它来做这个,请不要指给我那个方向。我正在使用CNG风格的密码迫使C#使用NCryptXYZ密码调用,并希望在TPM中确保密钥的安全。
上云精选
2核2G云服务器 每月9.33元起,个人开发者专属3年机 低至2.3折
啊,再看一遍你的代码,你搞砸了。
RSACng rsaKey = new RSACng(cngKey) KeySize = 2048 };
在KeySize上设置RSACng属性可以执行以下两项操作之一:
因此,您正在打开一个现有的密钥,然后丢弃它,生成一个新的临时密钥。(通过检查rsaKey.Key.Name,您可以看到它与您的输入不匹配)。
想必你这么做是为了一开始就用合适的大小创建密钥,但是你已经太迟了。正确的方法是
CngKeyCreationParameters cng = new CngKeyCreationParameters KeyUsage = CngKeyUsages.AllUsages, KeyCreationOptions = CngKeyCreationOptions.MachineKey,