How to Generate Unique Public and Private Key via RSA
我正在构建一个定制的购物车,在这个购物车中,cc编号和exp日期将存储在数据库中,直到进行处理(然后删除)。我需要加密这些数据(显然)。
我想使用rsacryptoServiceProvider类。
这是我创建密钥的代码。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | 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... } |
现在计划将私钥XML存储在连接到管理器密钥链的USB驱动器上。
每当经理离开公司时,我希望能够生成新的公钥和私钥(并用新的公钥重新加密当前存储的所有CC号码)。
我的问题是,这个代码生成的键总是相同的。我如何每次生成一组唯一的键?
更新。我的测试代码如下。:
注意:这里的"private key"参数是原始的私钥。为了更改密钥,我需要验证私钥是否有效。
在default.aspx.cs中
1 2 3 4 5 6 7 8 9 | 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)); } |
在crytopography.cs中:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 | 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); } |
当您使用这样的代码时:
1 2 3 4 5 | using (var rsa = new RSACryptoServiceProvider(1024)) { // Do something with the key... // Encrypt, export, etc. } |
.NET(实际上是Windows)将密钥永远存储在持久密钥容器中。容器由.NET随机生成
这意味着:
您为保护数据、创建自定义X.509证书等而生成的任何随机RSA/DSA密钥可能已在Windows文件系统中公开,而您对此一无所知。任何有权访问您帐户的人都可以访问。
您的磁盘正缓慢地充满数据。通常不是一个大问题,但它取决于您的应用程序(例如,它可能每分钟生成数百个密钥)。
要解决这些问题:
1 2 3 4 5 6 7 8 9 10 11 12 | using (var rsa = new RSACryptoServiceProvider(1024)) { try { // Do something with the key... // Encrypt, export, etc. } finally { rsa.PersistKeyInCsp = false; } } |
总是
听起来你好像对把钥匙放在机器上不感兴趣。
因此,使用
1 2 3 4 5 6 7 | 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... } |
编辑:
或者尝试将PersisteKeyNCP设置为false:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | 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... } |
当我需要创建一个新的密钥并将容器名和公钥保存到数据库时,我最终要做的是基于当前日期时间(datetime.now.ticks.toString())创建一个新的key container名称。此外,每当我创建新的密钥时,我都会执行以下操作:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | 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. } |
在创建新密钥之前。