IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Framework .NET Discussion :

Problème de chiffrement avec AES : argument (apparemment) null


Sujet :

Framework .NET

  1. #1
    Membre habitué
    Inscrit en
    Mai 2006
    Messages
    397
    Détails du profil
    Informations forums :
    Inscription : Mai 2006
    Messages : 397
    Points : 130
    Points
    130
    Par défaut Problème de chiffrement avec AES : argument (apparemment) null
    Bonjour,

    J'ai implémenté une classe pour faire le déchiffrement en AES qui se présente comme ceci:

    Code C# : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    public string decryptWithAES(string cypherText, string passPhrase, byte[] randomNumber)
            {
                string decryptedData = null;
                AesCryptoServiceProvider aes;
                try
                {
                    aes = new AesCryptoServiceProvider();
                }
                catch (System.PlatformNotSupportedException PlatNotSupExc)
                {
                    throw;
                }
     
                try
                {
                    aes.BlockSize = 128;
                    aes.KeySize = 256;
                    aes.Mode = CipherMode.CFB;
                    aes.Padding = PaddingMode.PKCS7;
                }
                catch (System.Security.Cryptography.CryptographicException CryptoExc)
                {
                    throw;
                }
     
                Rfc2898DeriveBytes derivedBytes;
                try
                {
                    derivedBytes = new Rfc2898DeriveBytes(passPhrase, randomNumber, 20000);
                }
                catch (System.ArgumentNullException ArgNullExc)
                {
                    throw;
                }
                catch (System.ArgumentException ArgExc)
                {
                    throw;
                }
     
                try
                {
                    aes.Key = derivedBytes.GetBytes(32);
                    aes.IV = derivedBytes.GetBytes(16);
                }
                catch (System.Security.Cryptography.CryptographicException CryptoExc)
                {
                    throw;
                }
                catch (System.ArgumentNullException ArgNullExc)
                {
                    throw;
                }
                catch (System.ArgumentOutOfRangeException ArgOutOfRangeExc)
                {
                    throw;
                }
     
                byte[] myData;
                try
                {
                    myData = System.Text.Encoding.UTF8.GetBytes(cypherText);
                }
                catch (System.ArgumentNullException ArgNullExc)
                {
                    throw;
                }
                catch (System.Text.EncoderFallbackException EncFallBackExc)
                {
                    throw;
                }
     
                try
                {
                    ICryptoTransform decryptor = aes.CreateDecryptor(aes.Key, aes.IV);
     
                    using (MemoryStream msDecrypt = new MemoryStream(myData))
                    {
                        using (CryptoStream csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read))
                        {
                            using (StreamReader swDecrypt = new StreamReader(csDecrypt))
                            {
                                decryptedData = swDecrypt.ReadToEnd();
                            }
                            csDecrypt.Close();
                        }
                        msDecrypt.Close();
                    }
                }
                catch (System.OutOfMemoryException OutOfMemExc)
                {
                    throw;
                }
                catch (System.IO.IOException IOExc)
                {
                    throw;
                }
                catch (System.ArgumentNullException ArgNullExc)
                {
                    throw;
                }
                catch (System.ArgumentException ArgExc)
                {
                    throw;
                }
     
                return decryptedData;
            }

    J'ai une erreur lorsque j'arrive dans ce bloque-ci :

    Code C# : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    using (StreamReader swDecrypt = new StreamReader(csDecrypt))
                            {
                                decryptedData = swDecrypt.ReadToEnd();
                            }

    Ou j'obtiens l'erreur suivante:

    Code C# : Sélectionner tout - Visualiser dans une fenêtre à part
    Value cannot be null. Parameter name: inputBuffer

    Est-ce que vous avez une idée de l'erreur? Serait-il possible qu'AES ait une limitation de la taille du cipher? Car je ne vois absolument pas ou est mon erreur :/

    Merci bien

    L.

  2. #2
    Membre habitué
    Inscrit en
    Mai 2006
    Messages
    397
    Détails du profil
    Informations forums :
    Inscription : Mai 2006
    Messages : 397
    Points : 130
    Points
    130
    Par défaut
    Bon je crois avoir trouver d'ou vient mon erreur. Quand je stock mes valeurs encryptée, j'utilise Convert.ToBase64String, ce qui je pense ne prend pas la totalité du array byte[].

    Quelle est la bonne méthode du coup pour stocker du texte chiffré ?

  3. #3
    Rédacteur/Modérateur


    Homme Profil pro
    Développeur .NET
    Inscrit en
    Février 2004
    Messages
    19 875
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Développeur .NET
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Février 2004
    Messages : 19 875
    Points : 39 749
    Points
    39 749
    Par défaut
    Poste la stacktrace de l'exception, qu'on voit un peu mieux d'où ça vient

  4. #4
    Membre habitué
    Inscrit en
    Mai 2006
    Messages
    397
    Détails du profil
    Informations forums :
    Inscription : Mai 2006
    Messages : 397
    Points : 130
    Points
    130
    Par défaut
    Et voilà le stacktrace :

    Code C# : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    System.ArgumentNullException was caught
      HResult=-2147467261
      Message=Value cannot be null.
    Parameter name: inputBuffer
      Source=System.Core
      ParamName=inputBuffer
      StackTrace:
           at System.Security.Cryptography.CapiSymmetricAlgorithm.TransformFinalBlock(Byte[] inputBuffer, Int32 inputOffset, Int32 inputCount)
           at System.Security.Cryptography.CryptoStream.FlushFinalBlock()
           at System.Security.Cryptography.CryptoStream.Dispose(Boolean disposing)
           at System.IO.Stream.Close()
           at System.IO.Stream.Dispose()
           at MyProject.Security.CryptographyUtility.decryptWithAES(String cypherText, String passPhrase, Byte[] randomNumber) in (...)\CryptographyUtility.cs:line 347
      InnerException:

    Ca arrive quand je suis sur cette ligne : decryptedData = swDecrypt.ReadToEnd();

    Mais par contre, je pense que cette erreur est due à une mauvaise conversation des bytes pour le stockage dans la base de donnée. Du coup je ne sais pas trop quelle conversion utiliser pour stocker ça de la bonne manière :/

    Merci bien,

    L.

  5. #5
    Rédacteur/Modérateur


    Homme Profil pro
    Développeur .NET
    Inscrit en
    Février 2004
    Messages
    19 875
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Développeur .NET
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Février 2004
    Messages : 19 875
    Points : 39 749
    Points
    39 749
    Par défaut
    Bon, la stacktrace n'aide pas beaucoup...

    Citation Envoyé par Leelith Voir le message
    Quand je stock mes valeurs encryptée, j'utilise Convert.ToBase64String, ce qui je pense ne prend pas la totalité du array byte[].
    Qu'est-ce qui te fait dire ça ? ToBase64String donne une représentation fidèle des données d'entrée, il n'y a pas de perte... La seule possibilité pour que ça ne prenne pas la totalité du tableau de byte, ce serait que tu aies précisé les paramètres offset et length avec de mauvaises valeurs

  6. #6
    Membre habitué
    Inscrit en
    Mai 2006
    Messages
    397
    Détails du profil
    Informations forums :
    Inscription : Mai 2006
    Messages : 397
    Points : 130
    Points
    130
    Par défaut
    Non je n'ai pas précisé de valeurs particulières. Ou alors le problème serait comment je récupère les données ?

    Actuellement je le fais avec System.Text.Encoding.UTF8.GetBytes(cypherText), est-ce que c'est correct?

    L.

  7. #7
    Rédacteur/Modérateur


    Homme Profil pro
    Développeur .NET
    Inscrit en
    Février 2004
    Messages
    19 875
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Développeur .NET
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Février 2004
    Messages : 19 875
    Points : 39 749
    Points
    39 749
    Par défaut
    Citation Envoyé par Leelith Voir le message
    Actuellement je le fais avec System.Text.Encoding.UTF8.GetBytes(cypherText), est-ce que c'est correct?
    non, si tu as utilisé Convert.ToBase64String pour encoder les données cryptées, il faut utiliser Convert.FromBase64String pour convertir dans l'autre sens

  8. #8
    Membre habitué
    Inscrit en
    Mai 2006
    Messages
    397
    Détails du profil
    Informations forums :
    Inscription : Mai 2006
    Messages : 397
    Points : 130
    Points
    130
    Par défaut
    Je me suis trompé, j'ai fais System.Text.Encoding.UTF8.GetBytes(plainText), et la même chose lors de la dechiffrement pour le texte chiffré (cf. code du premier poste).

    Du coup il se pourrait que cette méthode ne fasse pas une conversion fidèle des données?

    Voici le code de ma classe de chiffrement :

    Code C# : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    public string encryptWithAES(string plainText, string passPhrase, byte[] randomNumber)
            {
                byte[] encryptedData = null;
                AesCryptoServiceProvider aes;
                try
                {
                    aes = new AesCryptoServiceProvider();
                }
                catch (System.PlatformNotSupportedException platNotSupExc)
                {
                    throw;
                }
     
                try
                {
                    aes.BlockSize = 128;
                    aes.KeySize = 256;
                    aes.Mode = CipherMode.CFB;
                    aes.Padding = PaddingMode.PKCS7;
                }
                catch (System.Security.Cryptography.CryptographicException CryptoExc)
                {
                    throw;
                }
     
                Rfc2898DeriveBytes derivedBytes;
                try
                {
                    derivedBytes = new Rfc2898DeriveBytes(passPhrase, randomNumber, 20000);
                }
                catch (System.ArgumentNullException ArgNullExc)
                {
                    throw;
                }
                catch (System.ArgumentException ArgExc)
                {
                    throw;
                }
                try
                {
                    aes.Key = derivedBytes.GetBytes(32);
                    aes.IV = derivedBytes.GetBytes(16);
                }
                catch (System.Security.Cryptography.CryptographicException CryptoExc)
                {
                    throw;
                }
                catch (System.ArgumentNullException ArgNullExc)
                {
                    throw;
                }
                catch (System.ArgumentOutOfRangeException ArgOutOfRangeExc)
                {
                    throw;
                }
     
                try
                {
                    byte[] myData = System.Text.Encoding.UTF8.GetBytes(plainText);
                }
                catch (System.ArgumentNullException ArgNullExc)
                {
                    throw;
                }
                catch (System.Text.EncoderFallbackException EncFallExc)
                {
                    throw;
                }
     
                ICryptoTransform encryptor;
                try
                {
                    encryptor = aes.CreateEncryptor(aes.Key, aes.IV);
                }
                catch (System.ArgumentNullException ArgNullExc)
                {
                    throw;
                }
                catch (System.ArgumentException ArgExc)
                {
                    throw;
                }
     
                using (MemoryStream msEncrypt = new MemoryStream())
                {
                    try
                    {
                        using (CryptoStream csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write))
                        {
                            using (StreamWriter swEncrypt = new StreamWriter(csEncrypt))
                            {
                                swEncrypt.Write(plainText);
                                csEncrypt.FlushFinalBlock();
                            }
                            encryptedData = msEncrypt.ToArray();
                            csEncrypt.Close();
                        }
                        msEncrypt.Close();
                    }
                    catch (System.Security.Cryptography.CryptographicException ArgExc)
                    {
                        throw;
                    }
                    catch (System.ObjectDisposedException ObjDisExc)
                    {
                        throw;
                    }
                    catch (System.NotSupportedException NotSupExc)
                    {
                        throw;
                    }
                    catch (System.IO.IOException IOExc)
                    {
                        throw;
                    }
                    catch (System.ArgumentNullException ArgNullExc)
                    {
                        throw;
                    }
                    catch (System.ArgumentException ArgExc)
                    {
                        throw;
                    }
                }
                try
                {
                    return Convert.ToBase64String(encryptedData);
                }
                catch (System.ArgumentNullException ArgNullExc)
                {
                    throw;
                }
            }

  9. #9
    Rédacteur/Modérateur


    Homme Profil pro
    Développeur .NET
    Inscrit en
    Février 2004
    Messages
    19 875
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Développeur .NET
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Février 2004
    Messages : 19 875
    Points : 39 749
    Points
    39 749
    Par défaut
    J'ai l'impression que tu te mélanges un peu les pinceaux... donc je résume ce qu'il faut faire :

    Chiffrement :

    plainText -> (UTF8.GetBytes) -> plainBytes
              -> (chiffrement) -> cypherBytes
              -> (ToBase64) -> cipherText
    Déchiffrement :

    cipherText -> (FromBase64) -> cipherBytes
               -> (déchiffrement) -> plainBytes
               -> (UTF8.GetString) -> plainText
    (comme tu as fait avec un StreamReader, ça devrait marcher aussi)

    Du coup il se pourrait que cette méthode ne fasse pas une conversion fidèle des données?
    Toutes ces méthodes font une conversion fidèle des données, mais elles travaillent chacune sur un certain type de données, et si tu passes des données qui ne sont pas celles qui sont attendues, tu vas forcément obtenir n'importe quoi. Par exemple appeler UTF8.GetString sur des données binaires chiffrées n'a pas de sens, puisque ces données ne représentent pas du texte en UTF8. De même, appeler UTF8.GetBytes sur une chaine base64 va te donner quelque chose, mais qui ne correspond pas aux données binaires représentées par la chaine base64...

    Après, il se peut qu'il y ait d'autres erreurs dans l'utilisation des classes de cryptographie... là dessus je ne peux pas vraiment t'aider, je ne suis pas du tout expert dans ce domaine. La méthode de chiffrement me semble correcte à première vue, mais chez moi elle pète une erreur ("The input data is not a complete block")

    Au fait, pourquoi tous ces blocs catch avec juste un throw ? Si c'est pour mettre des breakpoints, il y a un moyen plus simple... Menu Debug -> Exceptions, et cocher la checkbox correspondant aux exceptions CLR. Le debugger s'arrêtera automatiquement quand une exception se produit

  10. #10
    Membre habitué
    Inscrit en
    Mai 2006
    Messages
    397
    Détails du profil
    Informations forums :
    Inscription : Mai 2006
    Messages : 397
    Points : 130
    Points
    130
    Par défaut
    Citation Envoyé par tomlev Voir le message
    J'ai l'impression que tu te mélanges un peu les pinceaux... donc je résume ce qu'il faut faire :

    Chiffrement :

    plainText -> (UTF8.GetBytes) -> plainBytes
              -> (chiffrement) -> cypherBytes
              -> (ToBase64) -> cipherText
    Déchiffrement :

    cipherText -> (FromBase64) -> cipherBytes
               -> (déchiffrement) -> plainBytes
               -> (UTF8.GetString) -> plainText
    (comme tu as fait avec un StreamReader, ça devrait marcher aussi)


    Toutes ces méthodes font une conversion fidèle des données, mais elles travaillent chacune sur un certain type de données, et si tu passes des données qui ne sont pas celles qui sont attendues, tu vas forcément obtenir n'importe quoi. Par exemple appeler UTF8.GetString sur des données binaires chiffrées n'a pas de sens, puisque ces données ne représentent pas du texte en UTF8. De même, appeler UTF8.GetBytes sur une chaine base64 va te donner quelque chose, mais qui ne correspond pas aux données binaires représentées par la chaine base64...
    Effectivement, c'est même logique de devoir refaire les opérations en ordre inverse... C'est ça de coder jusqu'à pas d'heure

    Citation Envoyé par tomlev Voir le message
    Après, il se peut qu'il y ait d'autres erreurs dans l'utilisation des classes de cryptographie... là dessus je ne peux pas vraiment t'aider, je ne suis pas du tout expert dans ce domaine. La méthode de chiffrement me semble correcte à première vue, mais chez moi elle pète une erreur ("The input data is not a complete block")

    Au fait, pourquoi tous ces blocs catch avec juste un throw ? Si c'est pour mettre des breakpoints, il y a un moyen plus simple... Menu Debug -> Exceptions, et cocher la checkbox correspondant aux exceptions CLR. Le debugger s'arrêtera automatiquement quand une exception se produit
    J'ai trouvé d'ou vient l'erreur de padding:

    Code C# : Sélectionner tout - Visualiser dans une fenêtre à part
    aes.Padding = PaddingMode.PKCS7;

    Si tu ne mets pas de padding :

    Code C# : Sélectionner tout - Visualiser dans une fenêtre à part
    aes.Padding = PaddingMode.None;

    Là il n'y a pas de problème... bizarre car je ne comprend pas du coup car il me semblait que c'était conseillé d'ajouter du padding à la fin?

  11. #11
    Rédacteur/Modérateur


    Homme Profil pro
    Développeur .NET
    Inscrit en
    Février 2004
    Messages
    19 875
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Développeur .NET
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Février 2004
    Messages : 19 875
    Points : 39 749
    Points
    39 749
    Par défaut
    Citation Envoyé par Leelith Voir le message
    il me semblait que c'était conseillé d'ajouter du padding à la fin?
    Aucune idée... comme je te l'ai dit, je n'y connais pas grand chose en crypto

  12. #12
    Membre habitué
    Inscrit en
    Mai 2006
    Messages
    397
    Détails du profil
    Informations forums :
    Inscription : Mai 2006
    Messages : 397
    Points : 130
    Points
    130
    Par défaut
    Ok, je vais demander à quelqu'un qui s'y connait bien Je posterais la réponse si jamais ça t'intéresse ou si ça peut intéresser quelqu'un

  13. #13
    Membre habitué
    Inscrit en
    Mai 2006
    Messages
    397
    Détails du profil
    Informations forums :
    Inscription : Mai 2006
    Messages : 397
    Points : 130
    Points
    130
    Par défaut
    J'ai trouvé le problème!

    En fait, si tu choisi mode CFB (AesCryptoServiceProvider.Mode = CipherMode.CFB), tu peux spécifier un padding de type PKCS7 par exemple. Le mode de fonctionnement du CFB fait en sorte qu'il va gérer les blocks qui ne sont pas multiple de la taille de block définit (AesCryptoServiceProvider.BlockSize). Donc avec CFB, vu qu'il gère ça de manière autonome il n'y a pas besoin de faire appel à la méthode FlushFinalBlock() du stream

    Voilà voilà

    L.

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Réponses: 10
    Dernier message: 09/03/2012, 15h38
  2. Problème avec l'argument DISTINCT en SQL
    Par Jeankiki dans le forum Bases de données
    Réponses: 2
    Dernier message: 20/04/2006, 12h27
  3. [débutant] problème avec les arguments de fopen
    Par Anouschka dans le forum C++
    Réponses: 13
    Dernier message: 23/02/2006, 14h56
  4. Problème de "select" avec des valeurs a null
    Par SchpatziBreizh dans le forum MS SQL Server
    Réponses: 2
    Dernier message: 01/07/2005, 16h08

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo