it-swarm.com.de

Generieren eines eindeutigen öffentlichen und privaten Schlüssels über RSA

Ich erstelle einen benutzerdefinierten Warenkorb, in dem die CC-Nummern und das Ablaufdatum bis zur Verarbeitung in einer Datenbank gespeichert (dann gelöscht) werden. Ich muss diese Daten (offensichtlich) verschlüsseln.

Ich möchte die RSACryptoServiceProvider-Klasse verwenden.

Hier ist mein Code zum Erstellen meiner Schlüssel.

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...
}

Jetzt ist geplant, den privaten Schlüssel xml auf einem USB-Laufwerk zu speichern, das an die Schlüsselkette des Managers angeschlossen ist.

Wenn ein Manager das Unternehmen verlässt, möchte ich neue öffentliche und private Schlüssel generieren können (und alle derzeit gespeicherten CC-Nummern mit dem neuen öffentlichen Schlüssel neu verschlüsseln).

Mein Problem ist, dass die von diesem Code generierten Schlüssel immer gleich sind. Wie würde ich jedes Mal einen eindeutigen Schlüsselsatz generieren?

PDATE. Mein Testcode ist unten:
Hinweis: Der Parameter "privatekey" ist hier der ursprüngliche private Schlüssel. Damit die Schlüssel geändert werden können, muss überprüft werden, ob der private Schlüssel gültig ist.

In 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:

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);
}
64
David Murdoch

Am Ende habe ich einen neuen KeyContainer-Namen basierend auf der aktuellen DateTime (DateTime.Now.Ticks.ToString ()) erstellt, wenn ich einen neuen Schlüssel erstellen und den Containernamen und den öffentlichen Schlüssel in der Datenbank speichern muss. Außerdem würde ich beim Erstellen eines neuen Schlüssels Folgendes tun:

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.
}

bevor Sie den neuen Schlüssel erstellen.

8
David Murdoch

Wenn Sie einen Code wie diesen verwenden:

using (var rsa = new RSACryptoServiceProvider(1024))
{
   // Do something with the key...
   // Encrypt, export, etc.
}

.NET (eigentlich Windows) speichert Ihren Schlüssel für immer in einem permanenten Schlüsselcontainer. Der Container wird zufällig von .NET generiert

Das heisst:

  1. Jeder zufällige RSA/DSA-Schlüssel, den Sie zum Schutz von Daten, zum Erstellen eines benutzerdefinierten X.509-Zertifikats usw. generiert haben, wurde möglicherweise ohne Ihr Wissen im Windows-Dateisystem offengelegt. Zugänglich für jeden, der Zugriff auf Ihr Konto hat.

  2. Ihre Festplatte wird langsam mit Daten gefüllt. Normalerweise kein großes Problem, aber es hängt von Ihrer Anwendung ab (z. B. werden möglicherweise Hunderte von Schlüsseln pro Minute generiert).

So beheben Sie diese Probleme:

using (var rsa = new RSACryptoServiceProvider(1024))
{
   try
   {
      // Do something with the key...
      // Encrypt, export, etc.
   }
   finally
   {
      rsa.PersistKeyInCsp = false;
   }
}

IMMER

125
coder5

Der Konstruktor RSACryptoServiceProvider(CspParameters) erstellt ein Schlüsselpaar, das im Schlüsselspeicher auf dem lokalen Computer gespeichert ist. Wenn Sie bereits ein Schlüsselpaar mit dem angegebenen Namen haben, wird das vorhandene Schlüsselpaar verwendet.

Es hört sich so an, als ob Sie kein Interesse daran haben, den Schlüssel auf dem Computer zu speichern.

Also benutze den RSACryptoServiceProvider(Int32) Konstruktor:

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:

Alternativ können Sie PersistKeyInCsp auf false setzen:

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...
}
23
Rasmus Faber