2013-03-29 33 views
9

Sono stato più di un articolo su CodeProject un per un po 'che spiega come per cifrare e decifrare utilizzando il provider RSA:crittografia a chiave pubblica con RSACryptoServiceProvider

RSA Private Key Encryption

Mentre la vecchia versione dal 2009 è stato buggy, la nuova versione 2012 (con supporto System.Numerics.BigInteger) sembra più affidabile. Ciò che questa versione manca, però, è un modo per cifrare con una chiave pubblica e decifrare utilizzando la chiave privata .

Quindi, l'ho provato io stesso ma mi sono immondizia quando decritto. Non ho familiarità con il provider RSA, quindi sono al buio qui. È difficile trovare maggiori informazioni su come dovrebbe funzionare.

Qualcuno vede cosa c'è di sbagliato in questo? Quello che segue è la crittografia con una chiave pubblica:

// Add 4 byte padding to the data, and convert to BigInteger struct 
BigInteger numData = GetBig(AddPadding(data)); 
RSAParameters rsaParams = rsa.ExportParameters(false); 
//BigInteger D = GetBig(rsaParams.D); //only for private key 
BigInteger Exponent = GetBig(rsaParams.Exponent); 
BigInteger Modulus = GetBig(rsaParams.Modulus); 
BigInteger encData = BigInteger.ModPow(numData, Exponent, Modulus);  
return encData.ToByteArray(); 

si utilizza la grande "D" dal provider quando faccio questo? Probabilmente no dato che è la chiave pubblica che non ha la "D".

Poi la controparte (la decrittografia utilizzando la chiave privata):

BigInteger numEncData = new BigInteger(cipherData); 

RSAParameters rsaParams = rsa.ExportParameters(true); 
BigInteger D = GetBig(rsaParams.D); 
//BigInteger Exponent = GetBig(rsaParams.Exponent); 
BigInteger Modulus = GetBig(rsaParams.Modulus); 

BigInteger decData = BigInteger.ModPow(numEncData, D, Modulus); 

byte[] data = decData.ToByteArray(); 
byte[] result = new byte[ data.Length - 1 ]; 
Array.Copy(data, result, result.Length); 
result = RemovePadding(result); 

Array.Reverse(result); 
return result; 

'ho bisogno del "D" o l'Esponente qui?

Ovviamente ho bisogno che la crittografia funzioni in entrambi i modi pubblico-privato pubblico-privato. Qualsiasi aiuto è molto apprezzato!

risposta

10

qui è un esempio per voi:

public static void rsaPlayground() 
    { 
     byte[] data = new byte[] { 1, 2, 3, 4, 5 }; 
     RSACryptoServiceProvider csp = new RSACryptoServiceProvider();//make a new csp with a new keypair 
     var pub_key = csp.ExportParameters(false); // export public key 
     var priv_key = csp.ExportParameters(true); // export private key 

     var encData = csp.Encrypt(data, false); // encrypt with PKCS#1_V1.5 Padding 
     var decBytes = MyRSAImpl.plainDecryptPriv(encData, priv_key); //decrypt with own BigInteger based implementation 
     var decData = decBytes.SkipWhile(x => x != 0).Skip(1).ToArray();//strip PKCS#1_V1.5 padding 

    } 

    public class MyRSAImpl 
    { 

     private static byte[] rsaOperation(byte[] data, BigInteger exp, BigInteger mod) 
     { 
      BigInteger bData = new BigInteger(
       data //our data block 
       .Reverse() //BigInteger has another byte order 
       .Concat(new byte[] { 0 }) // append 0 so we are allways handling positive numbers 
       .ToArray() // constructor wants an array 
      ); 
      return 
       BigInteger.ModPow(bData, exp, mod) // the RSA operation itself 
       .ToByteArray() //make bytes from BigInteger 
       .Reverse() // back to "normal" byte order 
       .ToArray(); // return as byte array 

      /* 
      * 
      * A few words on Padding: 
      * 
      * you will want to strip padding after decryption or apply before encryption 
      * 
      */ 
     } 

     public static byte[] plainEncryptPriv(byte[] data, RSAParameters key) 
     { 
      MyRSAParams myKey = MyRSAParams.fromRSAParameters(key); 
      return rsaOperation(data, myKey.privExponent, myKey.Modulus); 
     } 
     public static byte[] plainEncryptPub(byte[] data, RSAParameters key) 
     { 
      MyRSAParams myKey = MyRSAParams.fromRSAParameters(key); 
      return rsaOperation(data, myKey.pubExponent, myKey.Modulus); 
     } 
     public static byte[] plainDecryptPriv(byte[] data, RSAParameters key) 
     { 
      MyRSAParams myKey = MyRSAParams.fromRSAParameters(key); 
      return rsaOperation(data, myKey.privExponent, myKey.Modulus); 
     } 
     public static byte[] plainDecryptPub(byte[] data, RSAParameters key) 
     { 
      MyRSAParams myKey = MyRSAParams.fromRSAParameters(key); 
      return rsaOperation(data, myKey.pubExponent, myKey.Modulus); 
     } 

    } 

    public class MyRSAParams 
    { 
     public static MyRSAParams fromRSAParameters(RSAParameters key) 
     { 
      var ret = new MyRSAParams(); 
      ret.Modulus = new BigInteger(key.Modulus.Reverse().Concat(new byte[] { 0 }).ToArray()); 
      ret.privExponent = new BigInteger(key.D.Reverse().Concat(new byte[] { 0 }).ToArray()); 
      ret.pubExponent = new BigInteger(key.Exponent.Reverse().Concat(new byte[] { 0 }).ToArray()); 

      return ret; 
     } 
     public BigInteger Modulus; 
     public BigInteger privExponent; 
     public BigInteger pubExponent; 
    } 
+0

elemento del 'D' non si trova in chiave pubblica. è impostato solo quando si utilizza una chiave privata per la decrittografia, e quindi l'esempio fallirà a meno che la chiave privata non sia distribuita con l'applicazione. –

+0

uhm ... potrebbe essere un fatto che non puoi decifrare con la chiave privata, quando non ce l'hai ... sì ... cosa ha a che fare con un esempio di calcolo che mostra solo come fai la matematica dietro RSA? – DarkSquirrel42

+0

Non corretto, è possibile decodificare i dati che sono stati crittografati utilizzando la chiave privata utilizzando la chiave pubblica SOLO nel processo di decrittografia. Il tuo esempio precedente richiede la chiave privata, non importa se decifrare usando pubblico o privato per la decodifica. Dai un'occhiata al tuo campione e capirai. Per tutti, è necessario ESSERE PUBBLICI e privati ​​per far funzionare i propri metodi di decrittografia, il che è sbagliato. –

15

Prendete questo esempio di codifica/decodifica

 byte[] toEncryptData = Encoding.ASCII.GetBytes("hello world"); 

     //Generate keys 
     RSACryptoServiceProvider rsaGenKeys = new RSACryptoServiceProvider(); 
     string privateXml = rsaGenKeys.ToXmlString(true); 
     string publicXml = rsaGenKeys.ToXmlString(false); 

     //Encode with public key 
     RSACryptoServiceProvider rsaPublic = new RSACryptoServiceProvider(); 
     rsaPublic.FromXmlString(publicXml); 
     byte[] encryptedRSA = rsaPublic.Encrypt(toEncryptData, false); 
     string EncryptedResult = Encoding.Default.GetString(encryptedRSA); 


     //Decode with private key 
     var rsaPrivate = new RSACryptoServiceProvider(); 
     rsaPrivate.FromXmlString(privateXml); 
     byte[] decryptedRSA = rsaPrivate.Decrypt(encryptedRSA, false); 
     string originalResult = Encoding.Default.GetString(decryptedRSA); 
+0

La domanda originale stava chiedendo esempi di entrambe le direzioni. Il tuo codice, mostra come eseguire la decrittazione solo con la chiave privata, e non come decifrare usando la chiave pubblica. –

+1

In caso di RSA, non è necessario decifrare con chiave pubblica. Tranne che intendi la firma rsa. –

+0

No, intendo decifrare usando la chiave pubblica. Ad esempio, in php, usando openssl_private_encrypt() - mantenendo la chiave privata PRIVATE sul server come dovrebbe essere. Ora nel "client", questo dovrebbe essere decrittografato usando la chiave pubblica (i client di esempio sarebbero un programma scritto in C# e "firmato" con AuthentiCode). Conveniente per includere il certificato pubblico nel programma (parte del processo di firma). Ora, immagina questo nell'altro senso --- fallimento epico. E arrotolando un hash che devi analizzare per "verificare" i dati --- così facilmente hackerati. –

Problemi correlati