C# 如何通过 RSA 生成唯一的公钥和私钥
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1307204/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to Generate Unique Public and Private Key via RSA
提问by David Murdoch
I am building a custom shopping cart where CC numbers and Exp date will be stored in a database until processing (then deleted). I need to encrypt this data (obviously).
我正在构建一个自定义购物车,其中 CC 编号和 Exp 日期将存储在数据库中,直到处理(然后删除)。我需要加密这些数据(显然)。
I want to use the RSACryptoServiceProvider class.
我想使用 RSACryptoServiceProvider 类。
Here is my code to create my keys.
这是我创建密钥的代码。
public static void AssignNewKey(){
const int PROVIDER_RSA_FULL = 1;
const string CONTAINER_NAME = "KeyContainer";
CspParameters cspParams;
cspParams = new CspParameters(PROVIDER_RSA_FULL);
cspParams.KeyContainerName = CONTAINER_NAME;
cspParams.Flags = CspProviderFlags.UseMachineKeyStore;
cspParams.ProviderName = "Microsoft Strong Cryptographic Provider";
rsa = new RSACryptoServiceProvider(cspParams);
string publicPrivateKeyXML = rsa.ToXmlString(true);
string publicOnlyKeyXML = rsa.ToXmlString(false);
// do stuff with keys...
}
Now the plan is to store the private key xml on a USB drive attached to the managers key chain.
现在的计划是将私钥 xml 存储在连接到管理人员钥匙链的 USB 驱动器上。
Whenever a manager leaves the company I want to be able to generate new public and private keys (and re-encrypt all currently stored CC numbers with the new public key).
每当经理离开公司时,我都希望能够生成新的公钥和私钥(并使用新的公钥重新加密所有当前存储的抄送号码)。
My problem is that the keys generated by this code are always the same. How would I generate a unique set of keys every time?
我的问题是这段代码生成的密钥总是相同的。我将如何每次生成一组唯一的密钥?
UPDATE.My test code is below.:
note: the "privatekey" parameter here is the original private key. In order for the keys to be changed I need to verify that the private key is valid.
更新。我的测试代码如下:
注意:这里的“privatekey”参数是原始私钥。为了更改密钥,我需要验证私钥是否有效。
In Default.aspx.cs
在 Default.aspx.cs
public void DownloadNewPrivateKey_Click(object sender, EventArgs e)
{
StreamReader reader = new StreamReader(fileUpload.FileContent);
string privateKey = reader.ReadToEnd();
Response.Clear();
Response.ContentType = "text/xml";
Response.End();
Response.Write(ChangeKeysAndReturnNewPrivateKey(privateKey));
}
In Crytpography.cs:
在 Cryptpography.cs 中:
public static privateKey;
public static publicKey;
public static RSACryptoServiceProvider rsa;
public static string ChangeKeysAndReturnNewPrivateKey(string _privatekey)
{
string testData = "TestData";
string testSalt = "salt";
// encrypt the test data using the exisiting public key...
string encryptedTestData = EncryptData(testData, testSalt);
try
{
// try to decrypt the test data using the _privatekey provided by user...
string decryptTestData = DecryptData(encryptedTestData, _privatekey, testSalt);
// if the data is successfully decrypted assign new keys...
if (decryptTestData == testData)
{
AssignNewKey();
// "AssignNewKey()" should set "privateKey" to the newly created private key...
return privateKey;
}
else
{
return string.Empty;
}
}
catch (Exception ex)
{
return string.Empty;
}
}
public static void AssignParameter(){
const int PROVIDER_RSA_FULL = 1;
const string CONTAINER_NAME = "KeyContainer";
CspParameters cspParams;
cspParams = new CspParameters(PROVIDER_RSA_FULL);
cspParams.KeyContainerName = CONTAINER_NAME;
cspParams.Flags = CspProviderFlags.UseMachineKeyStore;
cspParams.ProviderName = "Microsoft Strong Cryptographic Provider";
rsa = new RSACryptoServiceProvider(cspParams);
}
public static void AssignNewKey()
{
AssignParameter();
using (SqlConnection myConn = new SqlConnection(Utilities.ConnectionString))
{
SqlCommand myCmd = myConn.CreateCommand();
string publicPrivateKeyXML = rsa.ToXmlString(true);
privateKey = publicPrivateKeyXML; // sets the public variable privateKey to the new private key.
string publicOnlyKeyXML = rsa.ToXmlString(false);
publicKey = publicOnlyKeyXML; // sets the public variable publicKey to the new public key.
myCmd.CommandText = "UPDATE Settings SET PublicKey = @PublicKey";
myCmd.Parameters.AddWithValue("@PublicKey", publicOnlyKeyXML);
myConn.Open();
myComm.ExecuteScalar();
}
}
public static string EncryptData(string data2Encrypt, string salt)
{
AssignParameter();
using (SqlConnection myConn = new SqlConnection(Utilities.ConnectionString))
{
SqlCommand myCmd = myConn.CreateCommand();
myCmd.CommandText = "SELECT TOP 1 PublicKey FROM Settings";
myConn.Open();
using (SqlDataReader sdr = myCmd.ExecuteReader())
{
if (sdr.HasRows)
{
DataTable dt = new DataTable();
dt.Load(sdr);
rsa.FromXmlString(dt.Rows[0]["PublicKey"].ToString());
}
}
}
//read plaintext, encrypt it to ciphertext
byte[] plainbytes = System.Text.Encoding.UTF8.GetBytes(data2Encrypt + salt);
byte[] cipherbytes = rsa.Encrypt(plainbytes, false);
return Convert.ToBase64String(cipherbytes);
}
public static string DecryptData(string data2Decrypt, string privatekey, string salt)
{
AssignParameter();
byte[] getpassword = Convert.FromBase64String(data2Decrypt);
string publicPrivateKeyXML = privatekey;
rsa.FromXmlString(publicPrivateKeyXML);
//read ciphertext, decrypt it to plaintext
byte[] plain = rsa.Decrypt(getpassword, false);
string dataAndSalt = System.Text.Encoding.UTF8.GetString(plain);
return dataAndSalt.Substring(0, dataAndSalt.Length - salt.Length);
}
采纳答案by David Murdoch
What I ended up doing is create a new KeyContainer name based off of the current DateTime (DateTime.Now.Ticks.ToString()) whenever I need to create a new key and save the container name and public key to the database. Also, whenever I create a new key I would do the following:
我最终要做的是在需要创建新密钥并将容器名称和公钥保存到数据库时,基于当前日期时间 (DateTime.Now.Ticks.ToString()) 创建一个新的 KeyContainer 名称。此外,每当我创建一个新密钥时,我都会执行以下操作:
public static string ConvertToNewKey(string oldPrivateKey)
{
// get the current container name from the database...
rsa.PersistKeyInCsp = false;
rsa.Clear();
rsa = null;
string privateKey = AssignNewKey(true); // create the new public key and container name and write them to the database...
// re-encrypt existing data to use the new keys and write to database...
return privateKey;
}
public static string AssignNewKey(bool ReturnPrivateKey){
string containerName = DateTime.Now.Ticks.ToString();
// create the new key...
// saves container name and public key to database...
// and returns Private Key XML.
}
before creating the new key.
在创建新密钥之前。
回答by Rasmus Faber
The RSACryptoServiceProvider(CspParameters)
constructor creates a keypair which is stored in the keystore on the local machine. If you already have a keypair with the specified name, it uses the existing keypair.
该RSACryptoServiceProvider(CspParameters)
构造函数创建一个存储在本地计算机上的密钥库密钥对。如果您已经有一个具有指定名称的密钥对,它将使用现有的密钥对。
It sounds as if you are notinterested in having the key stored on the machine.
听起来好像您对将密钥存储在机器上不感兴趣。
So use the RSACryptoServiceProvider(Int32)
constructor:
所以使用RSACryptoServiceProvider(Int32)
构造函数:
public static void AssignNewKey(){
RSA rsa = new RSACryptoServiceProvider(2048); // Generate a new 2048 bit RSA key
string publicPrivateKeyXML = rsa.ToXmlString(true);
string publicOnlyKeyXML = rsa.ToXmlString(false);
// do stuff with keys...
}
EDIT:
编辑:
Alternatively try setting the PersistKeyInCsp to false:
或者尝试将 PersistKeyInCsp 设置为 false:
public static void AssignNewKey(){
const int PROVIDER_RSA_FULL = 1;
const string CONTAINER_NAME = "KeyContainer";
CspParameters cspParams;
cspParams = new CspParameters(PROVIDER_RSA_FULL);
cspParams.KeyContainerName = CONTAINER_NAME;
cspParams.Flags = CspProviderFlags.UseMachineKeyStore;
cspParams.ProviderName = "Microsoft Strong Cryptographic Provider";
rsa = new RSACryptoServiceProvider(cspParams);
rsa.PersistKeyInCsp = false;
string publicPrivateKeyXML = rsa.ToXmlString(true);
string publicOnlyKeyXML = rsa.ToXmlString(false);
// do stuff with keys...
}
回答by coder5
When you use a code like this:
当您使用这样的代码时:
using (var rsa = new RSACryptoServiceProvider(1024))
{
// Do something with the key...
// Encrypt, export, etc.
}
.NET (actually Windows) stores your key in a persistentkey container forever. The container is randomly generated by .NET
.NET(实际上是 Windows)将您的密钥永远存储在持久性密钥容器中。容器由.NET随机生成
This means:
这意味着:
Any random RSA/DSA key you have EVER generated for the purpose of protecting data, creating custom X.509 certificate, etc. may have been exposed without your awareness in the Windows file system. Accessible by anyone who has access to your account.
Your disk is being slowly filled with data. Normally not a big concern but it depends on your application (e.g. it might generates hundreds of keys every minute).
您为保护数据、创建自定义 X.509 证书等目的而生成的任何随机 RSA/DSA 密钥可能已在您不知情的情况下暴露在 Windows 文件系统中。任何有权访问您帐户的人都可以访问。
您的磁盘正在慢慢被数据填满。通常不是什么大问题,但这取决于您的应用程序(例如,它可能每分钟生成数百个密钥)。
To resolve these issues:
要解决这些问题:
using (var rsa = new RSACryptoServiceProvider(1024))
{
try
{
// Do something with the key...
// Encrypt, export, etc.
}
finally
{
rsa.PersistKeyInCsp = false;
}
}
ALWAYS
总是