2011-12-07 23 views
6

Bu benim ilk yazı, umarım önemli bir şey kaçırmadım. Bir iletiyi şifrelemek ve sonra bir SSL bağlantısı üzerinden göndermek için genel/özel anahtar şifrelemeyi kullanmam gereken C# içinde bir proje yapıyorum.RSA C büyük veri şifreleme C#

Verileri şifrelemek için kullanılan tek asimetrik şifreleme şeması olan belgelere göre RSACryptoService'u kullanmayı seçtim. Sorun şu ki bu konuda çok fazla sorun yaşıyorum. (Simetrik şifreleme yapmak istedim, ama öğretmenimin yapmamı istediği şey bu değil ve ona göre bir blok boyutunu belirlemek kolay olmalı ve sonra tüm işi sizin için yapmalı.) Peki, çok uzak hiçbir şans ve bazı farklı yaklaşımlar denedim fakat şimdi geri temelleri ve yeniden denemeden için, bu da benim şimdiki kodudur: Gördüğünüz gibi

public string[] GenerateKeysToStrings(string uniqueIdentifier) 
    { 
     string[] keys; 
     using (var rsa = new RSACryptoServiceProvider(4096)) 
     { 
      try 
      { 
       string privateKey = rsa.ToXmlString(true); 
       string publicKey = rsa.ToXmlString(false); 

       this.pki.StoreKey(publicKey, uniqueIdentifier); 

       keys = new string[2]; 
       keys[0] = privateKey; 
       keys[1] = publicKey; 
      } 
      finally 
      { 
       //// Clear the RSA key container, deleting generated keys. 
       rsa.PersistKeyInCsp = false; 
      } 
     } 
     return keys; 
    } 

, anahtarları oluşturmak ve PKI mimmick Ortak anahtarı, onu depolayan basit bir sınıfa göndererek ve sonra özel anahtar bir dosyaya yazılır. (Aynı zamanda bunu yapan ancak bir dizi yerine saklayan başka bir yönteme sahip olduğumu farkettim, sadece test etmek istediğim için) ve ben No such key exceptions olsun ve bazen eskide gösterilen şekilde kriptografik istisnalar alıyorum gibi şeyleri basitleştirmek bol, bu yüzden sadece dizideki bir dize, ancak hiçbir şans olarak, rsa.ToXmlString dize saklayarak onu basitleştirmek istedi) Şimdi

Bir şifrelemek ve aşağıdaki gibi bir yöntem şifresini:.

public string Encrypt(string keyString, string message) 
    { 
     string encryptedMessage; 
     using (var rsa = new RSACryptoServiceProvider()) 
     { 
      try 
      { 
       //// Load the key from the specified path 
       var encryptKey = new XmlDocument(); 
       encryptKey.Load(@"C:\Test\PrivateKeyInfo.xml"); 
       rsa.FromXmlString(encryptKey.OuterXml); 


       //// Conver the string message to a byte array for encryption 
       //// var encoder = new UTF8Encoding(); 
       ASCIIEncoding byteConverter = new ASCIIEncoding(); 
       byte[] dataToEncrypt = byteConverter.GetBytes(message); 

       byte[] encryptedData = rsa.Encrypt(dataToEncrypt, false); 

       //// Convert the byte array back to a string message 
       encryptedMessage = byteConverter.GetString(encryptedData); 
      } 
      finally 
      { 
       //// Clear the RSA key container, deleting generated keys. 
       rsa.PersistKeyInCsp = false; 
      } 
     } 
     return encryptedMessage; 
    } 

Şifre çözme :

public string Decrypt(string keyString, string message) 
    { 
     string decryptedText; 
     using (var rsa = new RSACryptoServiceProvider()) 
     { 
      try 
      { 
       //// Loads the keyinfo into the rsa parameters from the keyfile 
       /* 
       var privateKey = new XmlDocument(); 
       privateKey.Load(keyString); 
       */ 
       rsa.FromXmlString(keyString); 

       //// Convert the text from string to byte array for decryption 
       ASCIIEncoding byteConverter = new ASCIIEncoding(); 
       var encryptedBytes = byteConverter.GetBytes(message); 

       //// Create an aux array to store all the encrypted bytes 
       byte[] decryptedBytes = rsa.Decrypt(encryptedBytes, false); 

       decryptedText = byteConverter.GetString(decryptedBytes); 
      } 
      finally 
      { 
       //// Clear the RSA key container, deleting generated keys. 
       rsa.PersistKeyInCsp = false; 
      } 
     } 
     return decryptedText; 
    } 

Ben bu metnin bir duvar olduğunu biliyorum, ama ben kafamı duvara vurarak oldum çünkü bana yardım umut kadar uzun şimdi komik değil :)

sorun Birlikte şifreleme mesajlar hakkında gitmek nasıl olduğunu RSA (veya başka bir kamu/özel anahtar şifreleme) İşte

Testi istemcisidir:
public static void Main(string[] args) 
    { 
     PublicKeyInfrastructure pki = new PublicKeyInfrastructure(); 
     Cryptograph crypto = new Cryptograph(); 
     string[] keys = crypto.GenerateKeysToStrings("[email protected]"); 


     string plainText = "Hello play with me, please"; 
     string publicKey = crypto.GetPublicKey("[email protected]"); 

     string encryptedText = crypto.Encrypt(keys[0], plainText); 


     string decryptedText = crypto.Decrypt(keys[1], encryptedText); 

    } 

Ben de belirtildiği gibi

, dize diziler var XML belgelerinden hatalı ayrıştırma hatasını ortadan kaldırmak istediğim için ...

Test istemcisini çalıştırdığımda, şifrelemek için özel anahtarı ve şifreyi çözmek için ortak anahtarı kullanırsam, bir "Anahtar var istisnası yok" alıyorum ve Bunu diğer yoldan yaparsam, kötü bir veri istisnası olur. Lütfen iyi bir kılavuzdan haberdar olursanız ya da dize mesajlarında kamu/özel anahtar şifrelemeyi nasıl düzeltebileceğimi bana anlatabilirseniz lütfen bana yardımcı olun, lütfen bana yardımcı olun.

Yardımlarınız için minnettarım.

cevap

5

Bu, RSA şifrelemenin nasıl yapılması gerektiği değildir.

RSA her şey matematikle ilgili. Şifrelediğiniz şey bir sayıdır, dolayısıyla sonlu uzunlukta ve kullandığınız RSA anahtarlık uzunluğuna uygun olmalıdır. Kullanılan dolgu malzemesiyle (PKCS # 1 veya OAEP) daha fazla uzunluk sınırlamaları uygulanır. yani büyük verileri şifrelemek ve RSA genel anahtar kullanarak bu anahtarı şifrelemek için bir simetrik anahtar kullanmak -

Eğer dolaylı yapmanız gerekir RSA ile büyük verileri şifrelemek istiyorsanız

.

Bunu uygulama hakkında blog sayfasından okuyabilirsiniz.

+0

Profesörümle konuştum ve o sırada bakış açım bir anahtarı şifrelemek, anahtarı değiştirmek ve sonra, şifreli/şifrelemek için rijndael gibi simetrik bir algoritma için temel olarak kullanın, ancak simetrik şifrelemeyi kullanmamızı istemiyordu, bu yüzden şu an için sorta off-limit olan bir pozisyondayım. Performans bilgisi, kullanıcı adı ve parola içeren HTTP mesajları hakkında konuştuğumuzda, iletileri (5096 bit RSA anahtarları kullanarak) 501 bayta şifrelemek ne kadar zaman alırdı? blok bloğu ile bloke olsun ya da olmasın, hala RSA kullanarak problemlerim var :( –

+0

RSA şifreleme/şifre çözme işlemini boyut sınırının altında kalmak (döngü dahil) yapabilir ve sonucu birleştirebilir/bölebilirsiniz. CPU'nuz, eski bir akıllı telefon ve yeni 8 çekirdekli bir sunucu mu? ;-) ama doğru bir alternatiften çok daha uzun. – poupou

+0

Keşke zamana bakabilseydim, ama şimdi bunu herhangi bir veri için çalışmaya bile başaramıyorum. Basitleştirilmiş bir sürüm aldım ve bunu kullanmaya devam ettim, ancak hala "Anahtar yok" hatası alıyorum ve tek yaptığım tasarımları, yöntemleri ayırmak için tek bir ana yöntemden yeniden yapılandırmaktı. Belki yapıcıyı doğru kullanıyorum? Anahtar ayarlarını aldığım kısım? Bir blok şifresinin simetrik bir algoritmadan 1000 kat daha yavaş olduğunu biliyorum, ama şu anda sadece çalışmasını istiyorum, her bir veri bloğunu parçalara ayırmam gerekirse (keysize/8 - 11 (dolgu için)) bayt. –

0

Belki bir şeyleri özlüyorum, ancak Encrypt() işlevinizin keyString parametresinden veya encryptKey içeriğinden yararlanamadığı anlaşılıyor.

+0

Evet, bu konuda çok üzüldüm ama onu oraya koymayı unutmuş olmalıyım, ama sizi temin ederim ki, anahtarı yükledim. Şimdi OP'yi güncelledim. Verileri bir çok kez yüklemeyi denedim, bazı sürümleri karıştırmam gerekiyordu ve görmedim :) Sorunum hala devam ediyor. Şu anda sahip olduğum sorun, şifrelemek için özel anahtarımı ve halkın şifresini çözdüğümde, bir keyDoesn'tExist istisnası almamdır. Ancak bunu başka bir şekilde yaparsam, "kötü veri" istisnası alırım. –

1

Tamam, sonunda orijinal yazımda belirttiğim soruna bir çözüm buldum. Bu, tam olarak test edilmediğim bir şey ya da bir şey, ama küçük bir deneme ve hata sürecinden anladığım bir şey. İşte

Ben geçerli kod: Ben, ben ve blok-boyutun üzerindeki aşağıda boyutları dışındaki çok test etmedim, ama bu ne yapıyor gibi görünüyor dediği gibi

public static string Encrypt(string dataToEncrypt, RSAParameters publicKeyInfo) 
    { 
     //// Our bytearray to hold all of our data after the encryption 
     byte[] encryptedBytes = new byte[0]; 
     using (var RSA = new RSACryptoServiceProvider()) 
     { 
      try 
      { 
       //Create a new instance of RSACryptoServiceProvider. 
       UTF8Encoding encoder = new UTF8Encoding(); 

       byte[] encryptThis = encoder.GetBytes(dataToEncrypt); 

       //// Importing the public key 
       RSA.ImportParameters(publicKeyInfo); 

       int blockSize = (RSA.KeySize/8) - 32; 

       //// buffer to write byte sequence of the given block_size 
       byte[] buffer = new byte[blockSize]; 

       byte[] encryptedBuffer = new byte[blockSize]; 

       //// Initializing our encryptedBytes array to a suitable size, depending on the size of data to be encrypted 
       encryptedBytes = new byte[encryptThis.Length + blockSize - (encryptThis.Length % blockSize) + 32]; 

       for (int i = 0; i < encryptThis.Length; i += blockSize) 
       { 
        //// If there is extra info to be parsed, but not enough to fill out a complete bytearray, fit array for last bit of data 
        if (2 * i > encryptThis.Length && ((encryptThis.Length - i) % blockSize != 0)) 
        { 
         buffer = new byte[encryptThis.Length - i]; 
         blockSize = encryptThis.Length - i; 
        } 

        //// If the amount of bytes we need to decrypt isn't enough to fill out a block, only decrypt part of it 
        if (encryptThis.Length < blockSize) 
        { 
         buffer = new byte[encryptThis.Length]; 
         blockSize = encryptThis.Length; 
        } 

        //// encrypt the specified size of data, then add to final array. 
        Buffer.BlockCopy(encryptThis, i, buffer, 0, blockSize); 
        encryptedBuffer = RSA.Encrypt(buffer, false); 
        encryptedBuffer.CopyTo(encryptedBytes, i); 
       } 
      } 
      catch (CryptographicException e) 
      { 
       Console.Write(e); 
      } 
      finally 
      { 
       //// Clear the RSA key container, deleting generated keys. 
       RSA.PersistKeyInCsp = false; 
      } 
     } 
     //// Convert the byteArray using Base64 and returns as an encrypted string 
     return Convert.ToBase64String(encryptedBytes); 
    } 

    /// <summary> 
    /// Decrypt this message using this key 
    /// </summary> 
    /// <param name="dataToDecrypt"> 
    /// The data To decrypt. 
    /// </param> 
    /// <param name="privateKeyInfo"> 
    /// The private Key Info. 
    /// </param> 
    /// <returns> 
    /// The decrypted data. 
    /// </returns> 
    public static string Decrypt(string dataToDecrypt, RSAParameters privateKeyInfo) 
    { 
     //// The bytearray to hold all of our data after decryption 
     byte[] decryptedBytes; 

     //Create a new instance of RSACryptoServiceProvider. 
     using (RSACryptoServiceProvider RSA = new RSACryptoServiceProvider()) 
     { 
      try 
      { 
       byte[] bytesToDecrypt = Convert.FromBase64String(dataToDecrypt); 

       //// Import the private key info 
       RSA.ImportParameters(privateKeyInfo); 

       //// No need to subtract padding size when decrypting (OR do I?) 
       int blockSize = RSA.KeySize/8; 

       //// buffer to write byte sequence of the given block_size 
       byte[] buffer = new byte[blockSize]; 

       //// buffer containing decrypted information 
       byte[] decryptedBuffer = new byte[blockSize]; 

       //// Initializes our array to make sure it can hold at least the amount needed to decrypt. 
       decryptedBytes = new byte[dataToDecrypt.Length]; 

       for (int i = 0; i < bytesToDecrypt.Length; i += blockSize) 
       { 
        if (2 * i > bytesToDecrypt.Length && ((bytesToDecrypt.Length - i) % blockSize != 0)) 
        { 
         buffer = new byte[bytesToDecrypt.Length - i]; 
         blockSize = bytesToDecrypt.Length - i; 
        } 

        //// If the amount of bytes we need to decrypt isn't enough to fill out a block, only decrypt part of it 
        if (bytesToDecrypt.Length < blockSize) 
        { 
         buffer = new byte[bytesToDecrypt.Length]; 
         blockSize = bytesToDecrypt.Length; 
        } 

        Buffer.BlockCopy(bytesToDecrypt, i, buffer, 0, blockSize); 
        decryptedBuffer = RSA.Decrypt(buffer, false); 
        decryptedBuffer.CopyTo(decryptedBytes, i); 
       } 
      } 
      finally 
      { 
       //// Clear the RSA key container, deleting generated keys. 
       RSA.PersistKeyInCsp = false; 
      } 
     } 

     //// We encode each byte with UTF8 and then write to a string while trimming off the extra empty data created by the overhead. 
     var encoder = new UTF8Encoding(); 
     return encoder.GetString(decryptedBytes).TrimEnd(new[] { '\0' }); 

    } 

olması gerekiyor. Ben hala bir acemi değilim, bu yüzden benim kodumu incelemenizi isterim :)