2013-07-07 4 views
4

Je travaille avec SagePay Forms et convertit actuellement les exemples de VB qu'ils ont en C#. J'ai bien progressé et la partie chiffrement de mon projet fonctionne bien (SagePay peut le décrypter).C# AES Decryption

Le problème que je rencontre est que lorsque je tente de décrypter la chaîne, elle se transforme en ordures. Si quelqu'un l'a fait avant, j'apprécierais vraiment de l'aide avec mon code de décryptage. J'ai inclus le code de cryptage qui fonctionne et les deux premières lignes sont la configuration et l'appel d'une autre méthode.

Je n'ai pas ajouté le code VB mais si cela est nécessaire je pourrais l'ajouter. Je ne voulais pas un poste énorme si ce n'est pas nécessaire.

Méthodes utilitaires:

public string byteArrayToHexString(byte[] ba) 
    { 
    return BitConverter.ToString(ba).Replace("-", ""); 
    } 

public static byte[] StringToByteArray(string hex) 
    { 
     return Enumerable.Range(0, hex.Length) 
         .Where(x => x % 2 == 0) 
         .Select(x => Convert.ToByte(hex.Substring(x, 2), 16)) 
         .ToArray(); 
    } 

cryptage principale méthode avec deux premières lignes étant l'appel de celui-ci extrait d'une méthode plus grande.

string crypt = "blahblahblah" 
string EncryptAndEncode = "@" + byteArrayToHexString(aesEncrypt(crypt)); 


     private byte[] aesEncrypt(string inputText) 
    { 

     RijndaelManaged AES = new RijndaelManaged(); 

     //set the mode, padding and block size for the key 
     AES.Padding = PaddingMode.PKCS7; 
     AES.Mode = CipherMode.CBC; 
     AES.KeySize = 128; 
     AES.BlockSize = 128; 

     //convert key and plain text input into byte arrays 
     Byte[] keyAndIvBytes = UTF8Encoding.UTF8.GetBytes("tR7nR6wZHGjYMCuV"); 
     Byte[] inputBytes = UTF8Encoding.UTF8.GetBytes(inputText);//AbHLlc5uLone0D1q 

     //create streams and encryptor object 
     MemoryStream memoryStream = new MemoryStream(); 
     CryptoStream cryptoStream = new CryptoStream(memoryStream, AES.CreateEncryptor(keyAndIvBytes, keyAndIvBytes), CryptoStreamMode.Write); 

     //perform encryption 
     cryptoStream.Write(inputBytes, 0, inputBytes.Length); 
     cryptoStream.FlushFinalBlock(); 

     //get encrypted stream into byte array 
     Byte[] outBytes = memoryStream.ToArray(); 

     //close streams 
     memoryStream.Close(); 
     cryptoStream.Close(); 
     AES.Clear(); 

     return outBytes; 
    } 

Décodage et méthodes Déchiffrement

public string DecodeAndDecrypt(string strIn) 
    { 
     //** HEX decoding then AES decryption, CBC blocking with PKCS5 padding - DEFAULT ** 


     string DecodeAndDecrypt = aesDecrypt(StringToByteArray(strIn.Substring(1))); 
     return (DecodeAndDecrypt); 
    } 

    private string aesDecrypt(Byte[] inputBytes) 
    { 
    RijndaelManaged AES = new RijndaelManaged(); 
    Byte[] keyAndIvBytes = UTF8Encoding.UTF8.GetBytes("tR7nR6wZHGjYMCuV"); 
    Byte[] outputBytes = inputBytes;//Convert.FromBase64String(inputBytes); 

    //set the mode, padding and block size 
    AES.Padding = PaddingMode.PKCS7; 
    AES.Mode = CipherMode.CBC; 
    AES.KeySize = 128; 
    AES.BlockSize = 128; 

    //create streams and decryptor object 
    MemoryStream memoryStream = new MemoryStream(outputBytes); 
    CryptoStream cryptoStream = new CryptoStream(memoryStream, AES.CreateEncryptor(keyAndIvBytes, keyAndIvBytes), CryptoStreamMode.Read); 
    //perform decryption 
    cryptoStream.Read(outputBytes, 0, outputBytes.Length); 
    Trace.WriteLine(outputBytes); 
    //close streams 
    memoryStream.Close(); 
    cryptoStream.Close(); 
    AES.Clear(); 
    //return System.Text.Encoding.UTF8.GetString(outputBytes); 

    string plainText = Encoding.UTF8.GetString(outputBytes, 
            0, 
            outputBytes.Length); 

    return plainText; 
    } 
+0

Où avez-vous trouvé les spécifications? Peut-être que vous pouvez inclure un lien vers eux. –

+2

Si vous faites le décryptage peut-être vous devriez utiliser 'AES.CreateDecryptor' au lieu de' AES.CreateEncryptor' –

+0

Merci Greg, votre dernier commentaire a maintenant abouti à une chaîne lisible, mais encore quelques conneries à la fin pour une raison quelconque. Sorte d'évident maintenant je pense à ce sujet mais je ne pouvais pas le voir pour regarder. Je vais donner un autre coup pour analyser la ficelle et voir comment je m'entends. Merci beaucoup, Steve. –

Répondre

6

Il y a en fait plusieurs problèmes avec votre code. D'abord dans votre méthode de décryptage que vous créez un chiffreur, cela devrait être un décrypteur. Deuxièmement, vous lisez le bloc entier, y compris le remplissage de votre algorithme dans le tampon lorsque vous faites le décryptage. Ci-dessous est une classe avec les éléments fixés et devrait renvoyer le résultat approprié. Je vous suggère cependant de trouver une meilleure façon de stocker la clé, de mettre votre code et de le générer comme vous le dites, c'est un non non. Vous devez générer votre clé avec un RNG (RNGCryptoServiceProvider) puis le hacher avec un algorithme de hachage sécurisé tel que SHA512, utilisez cette sortie pour votre clé. Vous devez alors trouver un bon endroit pour le stocker, je chercherais à crypter votre fichier web.config.

public static class EncryptionHelper 
{ 
    private static byte[] keyAndIvBytes; 

    static EncryptionHelper() 
    { 
     // You'll need a more secure way of storing this, I hope this isn't 
     // the real key 
     keyAndIvBytes = UTF8Encoding.UTF8.GetBytes("tR7nR6wZHGjYMCuV"); 
    } 

    public static string ByteArrayToHexString(byte[] ba) 
    { 
     return BitConverter.ToString(ba).Replace("-", ""); 
    } 

    public static byte[] StringToByteArray(string hex) 
    { 
     return Enumerable.Range(0, hex.Length) 
         .Where(x => x % 2 == 0) 
         .Select(x => Convert.ToByte(hex.Substring(x, 2), 16)) 
         .ToArray(); 
    } 

    public static string DecodeAndDecrypt(string cipherText) 
    { 
     string DecodeAndDecrypt = AesDecrypt(StringToByteArray(cipherText)); 
     return (DecodeAndDecrypt); 
    } 

    public static string EncryptAndEncode(string plaintext) 
    { 
     return ByteArrayToHexString(AesEncrypt(plaintext)); 
    } 

    public static string AesDecrypt(Byte[] inputBytes) 
    { 
     Byte[] outputBytes = inputBytes; 

     string plaintext = string.Empty; 

     using (MemoryStream memoryStream = new MemoryStream(outputBytes)) 
     { 
      using (CryptoStream cryptoStream = new CryptoStream(memoryStream, GetCryptoAlgorithm().CreateDecryptor(keyAndIvBytes, keyAndIvBytes), CryptoStreamMode.Read)) 
      { 
       using (StreamReader srDecrypt = new StreamReader(cryptoStream)) 
       { 
        plaintext = srDecrypt.ReadToEnd(); 
       } 
      } 
     } 

     return plaintext; 
    } 

    public static byte[] AesEncrypt(string inputText) 
    { 
     byte[] inputBytes = UTF8Encoding.UTF8.GetBytes(inputText);//AbHLlc5uLone0D1q 

     byte[] result = null; 
     using (MemoryStream memoryStream = new MemoryStream()) 
     { 
      using (CryptoStream cryptoStream = new CryptoStream(memoryStream, GetCryptoAlgorithm().CreateEncryptor(keyAndIvBytes, keyAndIvBytes), CryptoStreamMode.Write)) 
      { 
       cryptoStream.Write(inputBytes, 0, inputBytes.Length); 
       cryptoStream.FlushFinalBlock(); 

       result = memoryStream.ToArray(); 
      } 
     } 

     return result; 
    } 


    private static RijndaelManaged GetCryptoAlgorithm() 
    { 
     RijndaelManaged algorithm = new RijndaelManaged(); 
     //set the mode, padding and block size 
     algorithm.Padding = PaddingMode.PKCS7; 
     algorithm.Mode = CipherMode.CBC; 
     algorithm.KeySize = 128; 
     algorithm.BlockSize = 128; 
     return algorithm; 
    } 
} 

appel, il est facile:

string crypt = "blahblahblah"; 
string EncryptAndEncode = EncryptionHelper.EncryptAndEncode(crypt);    
Console.WriteLine(EncryptAndEncode); 

Console.WriteLine(EncryptionHelper.DecodeAndDecrypt(EncryptAndEncode)); 

Console.ReadLine(); 
+0

Merci Moe, la clé est dans le web.config et sera cryptée à un stade ultérieur, j'ai juste codé en dur pour l'affichage de sake. Je l'ai travaille maintenant et examinera contre votre poste pour regarder les améliorations. –

+1

L'utilisation du même IV pour chaque chaîne cryptée est une ** mauvaise idée **. Surtout avec une plus petite taille de bloc. Si vous cryptez deux chaînes de plus de 16 octets mais que leurs 16 premiers octets vont être identiques, le texte chiffré aura également les 16 premiers octets identiques. C'est pourquoi les gens ont créé le vecteur d'initialisation (IV) - si vous en utilisez un au hasard pour chaque chaîne (et le stockez à côté du texte chiffré), cela n'arrivera pas. – JanHudecek

+0

@JanHudecek Je suis totalement d'accord. Je ne suis pas sûr de ce que SagePay fait cependant en termes de la façon dont il décrypte le texte chiffré, il ne peut pas être une option dans leur protocole. Donc, cet exemple est juste pour * corriger * le code qui a été posté.Mais je suis absolument d'accord que vous ne devriez pas utiliser le même IV pour les chaînes cryptées si possible. – nerdybeardo