2013-03-29 25 views
9

Byłem nad artykule na CodeProject A za chwilę, która wyjaśnia, jak do szyfrowania i deszyfrowania przy użyciu dostawcy RSA:publicznego klucza szyfrującego z RSACryptoServiceProvider

RSA Private Key Encryption

Podczas gdy stara wersja z 2009 roku była wadliwa, nowa wersja 2012 (z obsługą System.Numerics.BigInteger) wydaje się bardziej niezawodna. Co w tej wersji brakuje choć jest sposobem szyfrowania z publicznego klucza i odszyfrować pomocą klawisza prywatny.

Próbowałem tego sam, ale odszyfruję. Nie znam dostawcy RSA, więc jestem w ciemności. Trudno znaleźć więcej informacji na temat tego, jak to działa.

Czy ktoś widzi, co jest z tym nie tak? Poniżej szyfrowanie z kluczem publicznym:

// 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(); 

Czy mogę używać duże „D” od dostawcy, kiedy to zrobić? Prawdopodobnie nie, ponieważ jest to klucz publiczny, który nie ma litery "D".

Następnie odpowiednik (odszyfrowanie za pomocą klucza prywatnego):

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; 

muszę "D" lub wykładnik tutaj?

Oczywiście potrzebuję kryptografii do pracy w obie strony prywatno-publicznej publiczno-prywatnej. Każda pomoc jest doceniana!

Odpowiedz

10

tutaj jest dla was przykładem:

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

elementem 'd' nie znajduje się w kluczu publicznym. jest ustawiany tylko przy użyciu klucza prywatnego do odszyfrowania, a zatem twój przykład zawiedzie, chyba że klucz prywatny zostanie rozprowadzony z aplikacją. –

+0

uhm ... może być fakt, że nie można odszyfrować klucza prywatnego, gdy go nie masz ... tak ... co to ma wspólnego z przykładem obliczeniowym, który pokazuje, jak zrobić matematykę za RSA? – DarkSquirrel42

+0

Nieprawidłowo, możesz odszyfrować dane, które zostały zaszyfrowane przy użyciu klucza prywatnego, używając TYLKO klucza publicznego w procesie odszyfrowywania. Twój powyższy przykład wymaga klucza prywatnego, niezależnie od tego, czy odszyfrowujesz przy użyciu publicznego czy prywatnego do odszyfrowania. Proszę spojrzeć na swoją próbkę, a zrozumiesz. Dla wszystkich, potrzebujesz BOTH publicznych i prywatnych, aby każda z metod odszyfrowywania działa, co jest złe. –

15

Weźmy ten przykład kodowania/dekodowania

 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

Pierwotne pytanie dotyczyło przykładów obu kierunków. Twój kod pokazuje sposób deszyfrowania za pomocą klucza prywatnego, a nie odszyfrowywania za pomocą klucza publicznego. –

+1

W przypadku RSA nie jest konieczne odszyfrowywanie za pomocą klucza publicznego. Poza tym, że masz na myśli podpisywanie RS. –

+0

Nie, mam na myśli deszyfrowanie za pomocą klucza publicznego. Na przykład w php, używając openssl_private_encrypt() - zachowując prywatny klucz PRIVATE na serwerze, tak jak być powinien. Teraz w "kliencie" trzeba to odszyfrować za pomocą klucza publicznego (przykładami klientów byłby program napisany w języku C# i "podpisany" przy pomocy AuthentiCode). Wygodne, aby certyfikat publiczny był osadzony w programie (część procesu rejestracji). Teraz wyobraź to sobie w inny sposób - epicką porażkę. I przetaczanie skrótu, który musisz przeanalizować, aby "zweryfikować" dane --- tak łatwo zhackować. –