Faire un vrai algorithme de cryptage

Description

Quelques aides pour obtenir un cryptage plutôt efficace.

Lorsque vous avez en projet de réaliser un algorithme de cryptage, définissez correctement son objectif :
- cryptage pour texte (ascii)
- cryptage pour fichier (binaire)
La différence entre un cryptage de texte et un cryptage de fichier est importante.

Le cryptage de texte doit être lisible après le cryptage : il s’agit de l’imprimer sur papier ou d’envoyer en tant que texte simple le message codé.

Le cryptage de fichier se contente de changer des octets. Le résultat est un nouveau fichier que l’on transférera uniquement sur support numérique (email, disquette, réseau, …)

Il est plus simple de créer un algorithme de cryptage de fichier car on utilise les fonctions mathématiques et logiques disponible dans l’ordinateur sans contraintes. Le cryptage de textes oblige à contrôler si le code ne sort pas de caractères « non imprimable » ou encore non prononçable. Le cryptage de textes peut aussi être intéressant dans la disposition du résultat : on peut présenter une suite de caractères, mais aussi des « pseudo-mots » ou encore une matrice de caractères… la présentation étant importante pour le décryptage…

La suite de ce guide s’intéresse au cryptage de fichiers.

Lorsque vous réfléchissez aux différentes étapes de l’algorithme de cryptage, pensez au décodage pirate. Pensez à la personne qui souhaite retrouver votre message. Pensez également qu’elle a accès à votre code source. Que faut-il en déduire ?
Mon algorithme prend la clé et réalise une opération octet par octet sur mon message, ce jusqu'à la fin de la clé puis recommence (tel que Vigénère). Il y a alors 255 possibilités par octet à tester pour décoder mon message, le tout élevé à la puissance du nombre d’octets de la clé (16 octets de clé donne 255^16 possibilités).
Pour casser un tel cryptage, il suffit de découvrir les 6 à 8 premiers octets. Cela crée environ 10^15 combinaisons à tester (environ 1 mois de calculs brute-force sur un ordinateur grand public).
Impressionnant, certes, mais lors du décodage on à recourt à certaines astuces. Astuces comme apprendre le comportement de l’algorithme, ou encore brûler des étapes de décryptage qui s’annulent ou rallonge inutilement le processus. Lors de cryptage de fichiers, si on sait a priori quel format de fichier est crypté, on sait quel seront les premiers octets, ce qui simplifie drastiquement les recherches !

Vérifions le comportement de l’algorithme dans ce petit test :

TEST : Comportement de l’algorithme de cryptage

Prendre comme clé :
A
Prendre comme texte :
AAAAAAAAAAAAAAAA

Si le résultat du cryptage est du type suivant :
0000000000000000
Cryptage en suite constante (type Xor simple). Tout décryptage nécessitera que 255 tests.
Si le résultat est du style :
13579ACEGIKMOQR
Fonction linéaire. En compensant cette fonction, le décryptage ne nécessitera que 255 tests, ou peut-être plus si la fonction dépend de la clé.

Si le résultat est :
eGy4yO5c9eoP71v
Pas d’indices. Essayez alors avec la clé suivante :
B

Si le résultat est :
fHz5zP6d0fpQ82w
Il y a un mélange mais un simple compteur incrémenté change les valeurs. En compensant le mélange, on peut réduire jusqu'à 65500 ou même 255 tests pour décoder.

Approfondissons le test.

Gardons notre texte, et prenons comme clé :
AAAA

Si le résultat est du style (peux parfois être plus discret):
Ed4tEs4tEs4tEs4t
Redondance cyclique, dépendant ou non de la clé. Le décodage se réduira sur une période, ou sur quelques caractères de début et fin de redondance. Cela permet de trouver facilement la clé.

Si votre algorithme ne se comporte pas comme dans ce test, alors vous avez déjà quelque chose de "présentable". Toutefois, il n’est pas qualifiable immédiatement de "sûr".

Faisons maintenant un autre test, celui du comportement au décryptage :
Cryptez votre texte en utilisant comme clé AAAA et comme texte AAAAAAAAAAAAAAAA.

Décryptons le message codé avec une clé approximative (situation de décodage en brute-force), avec une clé tel que AABA :
Si on obtient par exemple AA5dAAu7AA=HAA]# , cela montre que notre opération sur octet est très restrictive. Ainsi une clé partielle permet de dévoiler en parti le message, et un simple dictionnaire de mots croisés permet de retrouver le message ! (Ou dans le cas de fichiers, quelques indices sur le format d’origine suffisent).

D’autres comportements encore sont susceptibles d’être des pistes pour les casseurs de code, comme par exemple des groupes de caractères se répétant "au hasard". Plus discret encore, si on représente le message codé dans un graphique (en X l’offset et en Y la valeur de l’octet) et qu’on vois des périodicités complexes, polynomiales ou sinusoïdales, le casseur pourra compenser par leurs fonctions mathématiques inverse !

Maintenant, grâce aux tests de comportements de votre algorithme, vous pouvez en déduire les failles et les combler. Toutefois, calculez à chaque fois la variabilité qu’offre le cryptage. Brouillez aussi les pistes dans le code lui-même !

Exemple sur cet algorithme de consolidation :

La clé est dans le tableau mCle() de type Byte, cK le tampon de calcul
cK = &HAA
On initialise cK car si la clé vaux zéro, un cK égal à zéro aboutirai à zéro
For i = 1 To UBound(mCle())
cK = CLng(mCle(i)) + cK
En additionnant de façon cumulative, on assure une dépendance continue
If cK > 255 Then cK = cK - 255
mCle(i) = (cK Xor i)
On renforce le résultat avec l’offset de l’octet.
Next i
mCle(1) = mCle(1) Xor i
On modifie la premiere valeur

Cet algorithme augmente les possibilités de clés, car toutes clés de type "texte" (environ 64 possibilités par octet) sont alors étendues sur 255 possibilités par octet. Une attaque brute force est alors plus complexe.

Informations :

Un cryptage ne doit pas augmenter la taille du fichier d'origine (sauf pour l'arrondir au multiple de 2, 4, 8... au-dessus, selon le nombre de bits utilisés). Si votre algorithme double ou triple la longueur, ce n'est pas un cryptage : c'est un bogue! En effet, l'interêt d'un texte crypté est d'être quasiment identique à l'original de par la forme (longueur...), tout en étant incompréhensible.

Un cryptage sans clé s'appelle encodage, alors ne vous tromper pas dans l'énoncé de votre code source. Un encodage à la faculté d'être réversible sans clé, ce qui est pratique dans certaines applications, mais pas dans la sécurité.

Différence entre cryptage n bits et cryptage à clé de n bits :

Cryptage n bits :
L'algorithme utilise des blocs de n bits et réalise son processus de cryptage dessus. Par exemple, le cryptage de César ou Vigénère, transcrit en informatique, est sur 8 bits car il y a un travail que sur 1 octet à la fois.
Si on prélève des blocs de 4 octets et qu'on y réalise nos opérations, alors on a un cryptage 32bits. En utilisant la variable Long en VB, on peut faire du cryptage 32bits. Cela implique que pour décrypter, il faudra rechercher les possibilités sur ce bloc complet pour avoir le message en claire et non pas sur 1 seul octet du bloc. Du moins l'algorithme de cryptage dois être conçu ainsi.

Cryptage à clé de n bits :
Il s'agit en fait du nombre d'octets que la clé peut avoir, multiplié par huit. Si l'algorithme tronque la clé sur un nombre fini de bits, on indique ce nombre de bits.
La méthode Vigénère est donc un cryptage avec une clé étant au maximum aussi longue que le texte à codé, mais l'opération reste sur 1 octet à la fois. C'est un cryptage à clé variable, mais restera un cryptage 8bits.
Il est faux de penser que votre algorithme est puissant car il supporte jusqu'à 32 octets comme clé (256bits). Certes un brute force devra tester jusqu'à 256^32 (ou 2^256) possibilités pour trouver la bonne clé, mais si vous réalisez une opération octet par octet comme Vigénère, des indices seront repérable réduisant considérablement la recherche.

Autres formes de cryptage :
Il existe des cryptage faisant des opérations avec les bits de début et de fin du texte, ou un tableau d'un taille spécifié en fonction de la longueur de la clé... (plutôt que de le faire "de proche en proche"). On ne peux pas les classer en tant que "cryptage n bits" puisque le travail sur les bits dépendent directement de la clé.
Ces cryptages exotiques doivent prouver leurs robustesse en indiquant la moyenne des possibilités pour un message donné. Il faut l'évaluer en regardant le code source...

Trucs et Astuces

Pour réussir le test de "bon ou mauvais algo", voici quelques outils/astuces/solution...

- La bordélisation
Prenons une suite d'espace " " (ce qui donne en hexa : 20 20 20 20 20 20). Avec un cryptage par décalage d'octet, 3 bit par exemple, on obtient en hexa : 23 23 23 23 23 23 ... hum et pourtant l'auteur appelle ça du cryptage? de toute évidence ça n'en est pas...
Faisons intervenir la bordelisation!
Une bordélisation peut être (et est souvent basé sur...) une liste de taille fixe (ou de taille défini par la clé), contenant des valeur pseudo-aléatoire, tel que l'arrondi de la fonction sinus (voir partie code).
Notre chaine linéaire "crypté" (20+3 20+3 20+3 20+3 20+3 20+3) devient après calcul (20+3+234 20+3+243, 20+3+142, 20+3+31, 20+3+6, 20+3+92) la suite (en hexa) 14 23 180 66 41 127 : Youpi plus de redondance linéaire !!
Dans l'exemple CrypteTest (voir partie code), on réalise un test pour vérifié si on ne dépasse pas 255. Pourtant on peut éviter ce test... en faisant quoi ? simple : plutôt que de faire une addition (char+decalage+alea), on utilise Xor! cette fonction logique réversible permet de rester sur le même nombre de bits qu'avant : ((char Xor decalage) Xor alea) ne dépassera jamais 255 et ne sera jamais inférieur à 0 (et d'ailleur il y a peu de chance que ce soit un jour égal à zéro...) ... faites des essais...

- faire plusieurs passes :
Dans le cas de CryptTest, on ne fait qu'une seule passe. Mais on peux très bien se servir de la valeur n d'un caractère d'une clé pour faire autant de passe que cette valeur n. Attention toutefois si vous utiliser Xor (car utiliser 2 fois Xor avec les même valeurs rétabli le résutat d'avant : ben oui, c'est pour décrypter...). L'astuce est donc la suivante : alors qu'on fait les n passes, on change constament de valeur aléatoire.... (voir code, CryptTest2())

- Le BitShift (improprement appelé décalage de bit; c'est en fait : rotation de bit)
Au lieu de faire un décalage sur un octet, faites-le donc sur la valeur binaire d'un octet (ou sur la valeur binaire de plusieurs octets). Ca modifie énormément le résultat si le décalage est de 3 ou 6 bits... (voir BitShiftLeft dans le code)

Rappelons le dernier point qui permet de savoir si on a un bon algo :
- une infime différence de clé et/ou de texte doit créer un texte crypté totalement nouveau (et réciproquement, un texte crypté ayant un seul octet différent de l'original doit être incompréhensible)
Pour que ce comportement soit possible, il existe plusieurs solutions. Je ne parlerai que d'une solution, la plus simple à mes yeux :

La consolidation :
Pour qu'une infime différence change tout le résultat, il faut que chaque octet soi dépendant les uns des autres. Il faut donc réaliser une opération sur l'ensemble du texte à crypter : c'est une sorte de consolidation du texte.
Il faut impérativement vous servir de votre clé pour cette consolidation, sinon elle ne servira a rien puisque un piratin commençera par décoder la consolidation avant de décrypter!
C'est une étape assez difficile. Cet algorithme de consolidation, pour être valide, doit passer le test suivant :
r$ = Consolidation("AAAAAAAAAAAA")
admettons que r$ = "AdsfDgKu"
modifions un seul caractère (en faisant un décalage de "f" vers "e" par exemple)
r$ = "AdseDgKu"
l$ = DeConsolidation(r$)
Si l$ = "AAACBAAA", alors l'encodage de consolidation est franchement nul
Si l$ = "AABxRdEh", l'encodage de consolidation est mauvais (une partie de l'original est reconstitué/able)
Si l$ = "xCreGtER", bravo, vous avec une bonne consolidation!

Si vous commençer par l'algorithme de consolidation, vous aurez l'impression que votre cryptage est bon : il passera le test en début de ce tutorial sans trop de problèmes. L'encodage de consolidation est une assurance de complexifié le décryptage, mais attention car vous en publiez la source. Cet encodage dois donc être "non réversible" pour la clé, ou encore placé astucieusement pour qu'il ne soit pas une étape inutile lors du décodage (à vous de voir...).

-Le Checksum (ou le Digest, ou le Hash) :
C'est un numéro unique généré à partir d'un texte. Ce numéro dois être très sensible à toutes modifications de caractères. Contrairement à la consolidation, un checksum n'est par réversible : le numéro obtenu ne permet par de reconstituer le texte.
Utiliser le checksum pour initaliser le décalage de bit, la bordélisation ou les passes...

Note "légale" :
Attention! pour des raisons de sécurité d'Etat, la législation de votre pays peut restreindre l'utilisation du cryptage. Généralement la loi indique le nombre de bits maximales que l'algorithme gère (cryptage n bits). Pour éviter touts problèmes, renseignez-vous à la Mairie (en France, la CNIL est en charge de l'application de cette législation). en 2002 une personne ne devait pas utiliser d'algorithmes de plus de 128bits pour crypter ses données.

Source / Exemple :


'Juste deux petite fonctions très très utile pour crypté :
'La conversion valeur => binaire...
Function ValToBinString(ByVal Vl As Byte) As String
  For i = 0 To 7
    c = Vl Mod 2
    If c > 0 Then
      c = 1
      Vl = (Vl - 1) / 2
    Else
      Vl = Vl / 2
    End If
    ValToBinString = CStr(c) & ValToBinString  
  Next i
End Function

'...et la conversion binaire => valeur
Function BinToVal(Sbit As String) As Byte
  For i = 1 To 8
    BinToVal = BinToVal + (2 ^ (8 - i)) * Val(Mid(Sbit, i, 1))
  Next i
End Function

'Bordélisation :
Sub GenAlea(ByRef TblDeSortie() As Byte)
  ReDim TblDeSortie(1 To 128) As Byte
  'génère une suite pseudosinusoidale pour éviter les redondance linéaire
  For i = 1 To 128
    TblDeSortie(i) = CByte(Int(Sin(i) * 127) + 128)
  Next i
End Sub
'exemple bordéliseur du tutorial :
Sub CrypteTest()
  Dim TableAlea() As Byte
  GenAlea TableAlea()
  TestString$ = Space$(6)
  For i = 1 To Len(TestString$)
    Calc = Asc(Mid(TestString$, i, 1)) + 3 + TableAlea(i)
    If Calc > 255 Then Calc = Calc - 255
    StrCrypte$ = StrCrypte$ & Chr$(Calc)
  Next i
End Sub

'Plusieurs Passes, en fonction de la clé
Sub CrypteTest2(Cle As String)
  Dim TableAlea() As Byte
  GenAlea TableAlea()
  a = 0
  TestString$ = Space$(6)
  For i = 1 To Len(TestString$)
    For k = 0 to Asc(Mid(Cle,i,1))
      a = a + 1
      If a > Ubound(TableAlea) Then a = 1
      Calc = Asc(Mid(TestString$, i, 1)) Xor 3 Xor TableAlea(a)
    Next k
    StrCrypte$ = StrCrypte$ & Chr$(Calc)
  Next i
End Sub

'le BitShift
Private Sub BitShift(myByte As Byte, ByVal Decalage As Long)
'décalage de bit dans 1 byte
Dim eBit(1 To 8) As Long, r As Long
Dim i As Long

    'conversion octet vers bits (les bits sont dans un tableau)
    eBit(1) = Abs(CBool(myByte And 128))
    eBit(2) = Abs(CBool(myByte And 64))
    eBit(3) = Abs(CBool(myByte And 32))
    eBit(4) = Abs(CBool(myByte And 16))
    eBit(5) = Abs(CBool(myByte And 8))
    eBit(6) = Abs(CBool(myByte And 4))
    eBit(7) = Abs(CBool(myByte And 2))
    eBit(8) = Abs(CBool(myByte And 1))
    
    'décale "vers a gauche" ou "vers la droite" selon la valeur de Decalage
    If Decalage > 0 Then
        For i = 1 To Decalage
            r = eBit(8): eBit(8) = eBit(7): eBit(7) = eBit(6): eBit(6) = eBit(5)
            eBit(5) = eBit(4): eBit(4) = eBit(3): eBit(3) = eBit(2): eBit(2) = eBit(1): eBit(1) = r
        Next i
    ElseIf Decalage < 0 Then
        For i = 1 To Abs(Decalage)
            r = eBit(1): eBit(1) = eBit(2): eBit(2) = eBit(3): eBit(3) = eBit(4): eBit(4) = eBit(5)
            eBit(5) = eBit(6): eBit(6) = eBit(7): eBit(7) = eBit(8): eBit(8) = r
        Next i
    End If
        
    'conversion bits vers octet
    myByte = (2 ^ 7) * eBit(1) + (2 ^ 6) * eBit(2) + (2 ^ 5) * eBit(3) + (2 ^ 4) * eBit(4) + _
             (2 ^ 3) * eBit(5) + (2 ^ 2) * eBit(6) + (2 ^ 1) * eBit(7) + (2 ^ 0) * eBit(8)

End Sub

'CheckSum
Function XorCheck(TxZ As String) As Long
Dim Mediat As Long
Mediat = Val("&h" & Left(Hex(Len(TxZ)) & "0", 2) & "&")
For i = 1 To Len(TxZ)
    Mediat = i + Mediat + Mediat Xor Asc(Mid(TxZ, i, 1))
Next i
XorCheck = Mediat
End Function

'Dans le zip vous aurez un exemple d'utilisation de ces petits algos

Conclusion :


Voila, j'espère qu'avec ceci, vous aurez envie de vous creuser la tête pour faire des algos bien balèze ;)
Dans le zip, vous trouverez toutes les fonctions d'exemples, ainsi que beaucoup d'autres, le tout utilisé dans un algorithme de cryptage pour exemple (tout ça fait maison, bien sur).

Codes Sources

A voir également

Vous n'êtes pas encore membre ?

inscrivez-vous, c'est gratuit et ça prend moins d'une minute !

Les membres obtiennent plus de réponses que les utilisateurs anonymes.

Le fait d'être membre vous permet d'avoir un suivi détaillé de vos demandes et codes sources.

Le fait d'être membre vous permet d'avoir des options supplémentaires.