首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >如何在一个应用程序中加密数据,并在不同的Windows应用程序中使用与本地系统绑定的RSA密钥对其进行解密?

如何在一个应用程序中加密数据,并在不同的Windows应用程序中使用与本地系统绑定的RSA密钥对其进行解密?
EN

Stack Overflow用户
提问于 2022-07-29 22:43:14
回答 1查看 126关注 0票数 0

我有一个设置,我需要加密一个应用程序中的数据块,并在不同的应用程序中解密它。

我构建了一个示例应用程序,它创建了一个名为CngKey对象。然后使用RSACng对象创建一个CngKey。然后使用RSACng对象进行加密/解密。我发现,尽管应用程序是使用创建时使用的名称加载的,但在重新启动过程中会发生关键更改。我无法理解CngKey和RSACng对象之间的关系。

下面是描述我所要做的事情的代码片段:

代码语言:javascript
运行
复制
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] : "";

            try
            {
                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);
                }
                else
                {
                    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;
                }
                else
                {
                    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");
                else
                    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中确保密钥的安全。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2022-08-01 21:38:27

啊,再看一遍你的代码,你搞砸了。

代码语言:javascript
运行
复制
RSACng rsaKey = new RSACng(cngKey)
{
    KeySize = 2048
};

在KeySize上设置RSACng属性可以执行以下两项操作之一:

  1. 如果get_KeySize ==值忽略输入,什么也不做。
  2. ,从当前键中分离出来,下次使用该键时,生成一个新的get_KeySize键。

因此,您正在打开一个现有的密钥,然后丢弃它,生成一个新的临时密钥。(通过检查rsaKey.Key.Name,您可以看到它与您的输入不匹配)。

想必你这么做是为了一开始就用合适的大小创建密钥,但是你已经太迟了。正确的方法是

代码语言:javascript
运行
复制
CngKeyCreationParameters cng = new CngKeyCreationParameters
{
    KeyUsage = CngKeyUsages.AllUsages,
    KeyCreationOptions = CngKeyCreationOptions.MachineKey,
    Provider = CngProvider.MicrosoftSoftwareKeyStorageProvider,
    Parameters =
    {
        new CngProperty("Length", BitConverter.GetBytes(2048), CngPropertyOptions.Persist),
    },
};
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/73171621

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档