Cet article détaillera l'algorithme de chiffrement de bloc défini dans GOST R 34.12-2015 comme Grasshopper. Sur quoi est-il basé, quelles sont les mathématiques des algorithmes de chiffrement par blocs et comment cet algorithme est implémenté en java.
Qui, comment, quand et pourquoi a dĂ©veloppĂ© cet algorithme restera en dehors du champ d'application de l'article, car dans ce cas, nous avons peu d'intĂ©rĂȘt, sauf:
Sauterelle = Kuznetsov, Nechaev AND Company.

Ătant donnĂ© que la cryptographie est principalement basĂ©e sur les mathĂ©matiques, de sorte qu'une explication supplĂ©mentaire ne pose pas beaucoup de questions, vous devez d'abord analyser les concepts de base et les fonctions mathĂ©matiques sur lesquels cet algorithme est construit.
Champs Galois
L'arithmétique des champs de Galois est une arithmétique polynomiale, c'est-à -dire que chaque élément de ce champ est un polynÎme. Le résultat de toute opération est également un élément de ce champ. Un champ de Galois particulier se compose d'une plage fixe de nombres. La caractéristique de champ est appelée un nombre premier p. Ordre sur le terrain, c'est-à -dire la quantité de ses éléments est un certain degré naturel de caractéristique
pm , oĂč m Ï” N. Pour m = 1, le champ est appelĂ© simple. Dans les cas oĂč m> 1, pour la formation d'un champ, un polynĂŽme gĂ©nĂ©rateur de degrĂ© m est Ă©galement requis; un tel champ est appelĂ© Ă©tendu.
Gf(pm) - dĂ©signation du champ Galois. Le polynĂŽme gĂ©nĂ©rateur est irrĂ©ductible, c'est-Ă -dire simple (par analogie avec les nombres premiers, il est divisible par 1 et par lui-mĂȘme sans reste). Puisque travailler avec n'importe quelle information, c'est travailler avec des octets, et qu'un octet fait 8 bits, prenez comme champ
Gf(28) et le polynÎme générateur:
x8+x7+x6+x+1.
Cependant, pour commencer, nous analyserons les opérations de base dans un domaine plus simple
Gf(23) avec génération d'un polynÎme
f(x)=x3+x+1 .
Opération d'addition
La plus simple est l'opération d'addition, qui dans l'arithmétique du champ de Galois est un simple module d'addition au niveau du bit 2 (R).
J'attire immédiatement l'attention sur le fait que le signe "+" ici et ci-aprÚs se réfÚre au fonctionnement de XOR au niveau du bit, et non à l'addition sous la forme habituelle.
La table de vérité de la fonction HOR

Un exemple:

Sous forme polynomiale, cette opĂ©ration ressemblera Ă
(x2+1)+(x+1)=x2+x=1102=610
Opération de multiplication
Pour effectuer l'opération de multiplication, il est nécessaire de convertir les nombres sous forme polynomiale:

Comme vous pouvez le voir, le nombre sous forme polynomiale est un polynÎme dont les coefficients sont les valeurs des chiffres dans la représentation binaire du nombre.
Multipliez deux nombres sous forme polynomiale:

=x4+x3+x+1=110112=2710
Le résultat de multiplication 27 n'est pas dans le champ utilisé.
Gf(23) (il se compose de chiffres de 0 à 7, comme mentionné ci-dessus). Pour lutter contre ce problÚme, il est nécessaire d'utiliser un polynÎme générateur.
On suppose également que x satisfait l'équation
f(x)=x3+x+1=0 alors

Faisons une table de multiplication:

Le tableau des degrés des éléments du champ de Galois est d'une grande importance. L'augmentation à une puissance est également réalisée sous forme polynomiale, similaire à la multiplication.
Un exemple:

=x(x3+x+1)+x2+x+1=x2+x+1=1112=710
Ainsi, nous compilons un tableau de degrés:

La table des degrés est cyclique: le septiÚme degré correspond à zéro, donc le huitiÚme correspond au premier, etc. Vous pouvez vérifier cela si vous le souhaitez.
Dans les champs de Galois, il y a le concept d'un terme primitif - un élément d'un champ dont les degrés contiennent tous les éléments non nuls du champ. On voit que tous les éléments correspondent à cette condition (enfin, sauf 1, naturellement). Mais ce n'est pas toujours le cas.
Pour les champs que nous considĂ©rons, c'est-Ă -dire avec la caractĂ©ristique 2, choisissez toujours 2. En tant que membre primitif, Ă©tant donnĂ© sa propriĂ©tĂ©, tout Ă©lĂ©ment du champ peut ĂȘtre exprimĂ© en termes de degrĂ© du membre primitif.

Un exemple:

En utilisant cette propriété, et en tenant compte de la cyclicité de la table des degrés, nous allons essayer de multiplier à nouveau les nombres:

Le résultat coïncidait avec ce que nous avions calculé plus tÎt.
Faisons maintenant la division:

Le résultat obtenu est également vrai.
Eh bien, par souci d'exhaustivité, regardons élever à un pouvoir:

Une telle approche de la multiplication et de la division est beaucoup plus simple que les opérations réelles utilisant des polynÎmes, et pour eux, il n'est pas nécessaire de stocker une grande table de multiplication, mais juste une rangée de degrés d'un membre de champ primitif.
Revenons maintenant Ă notre domaine
Gf(28)L'Ă©lĂ©ment zĂ©ro du champ est un, le 1er est un deux, chaque Ă©lĂ©ment suivant du 2e au 254e Ă©lĂ©ment est calculĂ© comme le prĂ©cĂ©dent, multipliĂ© par 2, et si l'Ă©lĂ©ment est en dehors du champ, c'est-Ă -dire que sa valeur est supĂ©rieure Ă
(28â1) alors XOR se fait avec le nombre
19510 , ce nombre représente le polynÎme irréductible du champ
x8+x7+x6+x+1=28+27++26+2+1=451 , nous apportons ce numéro sur le terrain

. Et le 255e élément est à nouveau 1. Nous avons donc un champ contenant 256 éléments, c'est-à -dire un ensemble complet d'octets, et nous avons analysé les opérations de base qui sont effectuées dans ce champ.

Tableau des puissances de deux pour le terrain
Gf(28)Pourquoi était-il nécessaire - une partie des calculs de l'algorithme Grasshopper est effectuée dans le champ Galois, et les résultats des calculs, respectivement, sont des éléments de ce champ.
Réseau Feistel
Feistel Network est une méthode de chiffrement par blocs développée par Horst Feistel chez IBM en 1971. Aujourd'hui, le réseau de Feistel est à la base d'un grand nombre de protocoles cryptographiques.
Le réseau Feistel fonctionne avec des blocs en texte clair:
- Le bloc est divisé en deux parties égales - gauche L et droite R.
- Le sous-bloc gauche L est modifié par la fonction f à l'aide de la touche K: X = f (L, K). En fonction, il peut y avoir n'importe quelle transformation.
- Le sous-bloc X résultant est ajouté modulo 2 avec le sous-bloc droit R, qui reste inchangé: X = X + R.
- Les piÚces résultantes sont échangées et collées.
Cette séquence d'actions est appelée cellule Feistel.
Figure 1. Cellule FeistelLe réseau Feistel est composé de plusieurs cellules. Les sous-blocs obtenus en sortie de la premiÚre cellule vont à l'entrée de la deuxiÚme cellule, les sous-blocs résultants de la deuxiÚme cellule vont à l'entrée de la troisiÚme cellule, et ainsi de suite.
Algorithme de chiffrement
Maintenant, nous nous sommes familiarisés avec les opérations utilisées et pouvons passer au sujet principal - à savoir, le cryptoalgorithme Grasshopper.
La base de l'algorithme est le réseau dit SP - réseau de substitution-permutation. Le chiffrement basé sur le réseau SP reçoit un bloc et une clé en entrée et effectue plusieurs tours alternés constitués d'étages de substitution et d'étages de permutation. Grasshopper effectue neuf tours complets, chacun comprenant trois opérations consécutives:
- L'opération d'application d'une clé ronde ou XOR au niveau du bit d'une clé et d'un bloc de données d'entrée;
- Conversion non linéaire, qui est un simple remplacement d'un octet par un autre conformément au tableau;
- Transformation linéaire. Chaque octet du bloc est multiplié dans le champ de Galois par l'un des coefficients de la série (148, 32, 133, 16, 194, 192, 1, 251, 1, 192, 194, 16, 133, 32, 148, 1) selon l'ordinal numéros d'octets (une série est présentée pour les numéros de série du 15 au 0, comme indiqué sur la figure). Les octets sont ajoutés ensemble modulo 2, et les 16 octets du bloc sont décalés vers le bas, et le nombre résultant est écrit à la place de l'octet lu.

Le dernier dixiÚme round n'est pas terminé, il ne comprend que la premiÚre opération XOR.
Grasshopper est un algorithme de bloc, il fonctionne avec des blocs de données de 128 bits ou 16 octets de long. La longueur de clé est de 256 bits (32 octets).
Figure 2. SchĂ©ma de chiffrement et de dĂ©chiffrement du bloc de donnĂ©esLe diagramme montre la sĂ©quence d'opĂ©rations, oĂč S est une transformation non linĂ©aire, L est une transformation linĂ©aire, Ki sont des clĂ©s rondes. La question se pose immĂ©diatement - d'oĂč viennent les touches rondes.
Formation de clé ronde
Les clés itératives (ou rondes) sont obtenues par certaines transformations basées sur une clé principale, dont la longueur, comme nous le savons déjà , est de 256 bits. Ce processus commence par diviser la clé principale en deux, de sorte que la premiÚre paire de clés rondes est obtenue. Huit itérations du réseau Feistel sont utilisées pour générer chaque paire suivante de clés rondes, une constante est utilisée à chaque itération, qui est calculée en appliquant une transformation linéaire de l'algorithme à la valeur du nombre d'itérations.
Le schéma d'obtention des clés itératives (rondes)Si nous rappelons la figure 1, alors le sous-bloc gauche L est la moitié gauche de la clé d'origine, le sous-bloc droit R est la moitié droite de la clé d'origine, K est la constante Ci, la fonction f est la séquence d'opérations R XOR Ci, transformation non linéaire, transformation linéaire.
Les constantes d'itération Ci sont obtenues en utilisant la transformation L du numéro de séquence d'itération.
Ainsi, afin de crypter un bloc de texte, nous devons d'abord calculer 32 constantes itératives, puis calculer 10 clés rondes en fonction de la clé, puis effectuer la séquence d'opérations illustrée à la figure 2.
Commençons par calculer les constantes:
Premier const
C1=110=000000012=0116 , cependant, toutes les transformations de notre algorithme sont effectuées avec des blocs de 16 octets de long, il est donc nécessaire de compléter la constante avec la longueur du bloc, c'est-à -dire d'ajouter 15 octets zéro à droite, nous obtenons
C1=01000000000000000000000000000000
Multipliez-le par une série (1, 148, 32, 133, 16, 194, 192, 1, 251, 1, 192, 194, 16, 133, 32, 148) comme suit:
a15=a15â148+a14â32+a13â133+a12â16+
+a11â194+a10â192+a9â1+a8â251+a7â1+a6â192+
+a5â194+a4â16+a3â133+a2â32+a1â148+a0â1
(cette égalité est donnée dans les opérations des champs de Galois)
Puisque tout sauf l'octet zéro est égal à 0 et que l'octet zéro est multiplié par 1, nous obtenons 1 et l'écrivons dans l'ordre supérieur du nombre, en décalant tous les octets dans l'ordre bas, nous obtenons:
C1=00000000000000000000000000000001
RĂ©pĂ©tez les mĂȘmes opĂ©rations. Cette fois
a15=1 , tous les autres octets sont à 0, par conséquent, seul le premier reste des termes
a15â148=1â148=14810=9416 nous obtenons:
C1=00000000000000000000000000000194
Nous faisons la troisiÚme itération, voici deux termes non nuls:
a15â148+a14â32=148â148+1â32=
=10010100â10010100+00000001â00100000=
=(x7+x4+x2)â(x7+x4+x2)+1âx5=x14+x8+x4+x5=
=x6(x8+x7+x6+x+1)+x13+x12+x7+x6+x8+x4+x5=
=x5(x8+x7+x6+x+1)+x11+x5+x7+x8+x4+x5=
=x3(x8+x7+x6+x+1)+x10+x9+x3+x8+x7=
=x2(x8+x7+x6+x+1)+x2+x7=x7+x2=13210

Selon le tableau des degrĂ©s, cela pourrait ĂȘtre rĂ©solu beaucoup plus facilement:

C1=00000000000000000000000000019484
De plus, tout est exactement le mĂȘme, seulement 16 itĂ©rations pour chaque constante
C1=000000000000000000000000019484DD
C1=0000000000000000000000019484DD10
C1=00000000000000000000019484DD10BD
C1=000000000000000000019484DD10BD27
C1=0000000000000000019484DD10BD275D
C1=00000000000000019484DD10BD275DB8
C1=000000000000019484DD10BD275DB87A
C1=0000000000019484DD10BD275DB87A48
C1=00000000019484DD10BD275DB87A486C
C1=000000019484DD10BD275DB87A486C72
C1=0000019484DD10BD275DB87A486C727
C1=00019484DD10BD275DB87A486C7276A2
Et la constante finale:
C1=019484DD10BD275DB87A486C7276A2E6
Autres constantes:
C2=02EBCB7920B94EBAB3F490D8E4EC87DC
C3=037F4FA4300469E70B8ED8B4969A25B2
C4=041555F240B19CB7A52BE3730B1BCD7B
C5=0581D12F500CBBEA1D51AB1F796D6F15
C6=06FE9E8B6008D20D16DF73ABEFF74AA7
C7=076A1A5670B5F550AEA53BC79D81E8C9
C8=082AAA2780A1FBAD895605E6163659F6
C9=09BE2EFA901CDCF0312C4D8A6440FB98
C10=0AC1615EA018B5173AA2953EF2DADE2A
C11=0B55E583B0A5924A82D8DD5280AC7C44
C12=0C3FFFD5C010671A2C7DE6951D2D948D
C13=0DAB7B08D0AD40479407AEF96F5B36E3
C14=0ED434ACE0A929A09F89764DF9C11351
C15=0F40B071F0140EFD27F33E218BB7B13F
C16=1054974EC3813599D1AC0A0F2C6CB22F
C17=11C01393D33C12C469D642635E1A1041
C18=12BF5C37E3387B2362589AD7C88035F3
C19=132BD8EAF3855C7EDA22D2BBBAF6979D
C20=1441C2BC8330A92E7487E97C27777F54
C21=15D54661938D8E73CCFDA1105501DD3A
C22=16AA09C5A389E794C77379A4C39BF888
C23=173E8D18B334C0C97F0931C8B1ED5AE6
C24=187E3D694320CE3458FA0FE93A5AEBD9
C25=19EAB9B4539DE969E0804785482C49B7
C26=1A95F6106399808EEB0E9F31DEB66C05
C27=1B0172CD7324A7D35374D75DACC0CE6B
C28=1C6B689B03915283FDD1EC9A314126A2
C29=1DFFEC46132C75DE45ABA4F6433784CC
C30=1E80A3E223281C394E257C42D5ADA17E
C31=1F14273F33953B64F65F342EA7DB0310
C32=20A8ED9C45C16AF1619B141E58D8A75E
Maintenant, nous allons calculer les clés rondes selon le schéma présenté ci-dessus, prenez la clé de cryptage:
K=7766554433221100FFEEDDCCBBAA9988
EFCDAB89674523011032547698BADCFE
Alors
K1=7766554433221100FFEEDDCCBBAA9988
K2=EFCDAB89674523011032547698BADCFE
K1 sera le sous-bloc gauche du réseau Feistel, et
K2 - Ă droite.
Faisons l'opération
K1+C1Premier octet
K1 est Ă©gal Ă

Premier octet
C1 est Ă©gal Ă
0116=000000012
les octets restants sont convertis de la mĂȘme maniĂšre, par consĂ©quent
X(K1,C1)=K1+C1 :
X(K1,C1)=76F2D199239F365D479495A0C9DC3BE6
Ensuite, nous effectuons une transformation non linéaire
S(X(K1,C1)) . Elle est réalisée selon le tableau:
Table de conversion non linéaireLe nombre 0 est remplacé par 252, 1 par 238, 17 par 119, etc.

S(118)=13810=8A16
S(X(K1,C1))=8A741BE85A4A8FB7AB7A94A737CA9809
Effectuez maintenant une transformation linéaire
L(S(X(K1,C1))) , il a été considéré en détail lors du calcul des constantes itératives, nous ne donnons donc ici que le résultat final:
L(S(X(K1,C1)))=A644615E1D0757926A5DB79D9940093D
Selon le schéma de la cellule Feistel, nous effectuons XOR avec le sous-bloc droit, c'est-à -dire avec
K2 :
X(L(S(X(K1,C1)))),K2)=4989CAD77A4274937A6FE3EB01FAD5C3
Et le résultat obtenu en sortie de la premiÚre cellule Feistel:
EFCDAB89674523011032547698BADCFE4989CAD77A4274937A6FE3EB01FAD5C3
Cette valeur est divisĂ©e par deux et va Ă l'entrĂ©e de la deuxiĂšme cellule Feistel, oĂč la deuxiĂšme constante est dĂ©jĂ utilisĂ©e
C2 . AprÚs avoir parcouru huit cellules, nous obtenons les 2 clés suivantes
K3 et
K4 . Nous effectuerons avec eux huit itérations du réseau Feistel, obtiendrons la prochaine paire de clés, etc. Huit itérations par paire de clés, puisque nous avons initialement la premiÚre paire, puis 32 itérations sont effectuées au total, chacune avec sa propre constante.
Clés restantes:
K3=448CC78CEF6A8D2243436915534831DB
K4=04FD9F0AC4ADEB1568ECCFE9D853453D
K5=ACF129F44692E5D3285E4AC468646457
K6=1B58DA3428E832B532645C16359407BD
K7=B198005A26275770DE45877E7540E651
K8=84F98622A2912AD73EDD9F7B0125795A
K9=17E5B6CD732FF3A52331C77853E244BB
K10=43404A8EA8BA5D755BF4BC1674DDE972
Bloquer le chiffrement
Nous avons calculé toutes les clés et maintenant nous pouvons enfin passer directement au cryptage du bloc de texte et si vous lisez attentivement tout ce qui est écrit ci-dessus, le cryptage du texte ne sera pas difficile, car toutes les opérations utilisées dans ce processus et leur séquence ont été examinées en détail.
Prenez le bloc de texte en clair:
T=8899AABBCCDDEEFF0077665544332211
exécuter la séquence d'opérations X, S, L
X(T,K1)=FFFFFFFFFFFFFFFFFFF99BB99FF99BB99
S(X(T,K1))=B6B6B6B6B6B6B6B6B6E87DE8B6E87DE8
L(S(X(T,K1)))=30081449922F4ACFA1B055E386B697E2
T1=30081449922F4ACFA1B055E386B697E2
X(T1,K2)=DFC5BFC0F56A69CEB18201951E0C4B1C
S(X(T1,K2))=61AC3B07F47891E74524EE945F23A214
L(S(X(T1,K2)))=7290C6A158426FB396D562087A495E28
T2=7290C6A158426FB396D562087A495E28
et ainsi de suite, le résultat final ressemblera à ceci:
T10=CDEDD4B9428D465A3024BCBE909D677F
Bloquer le déchiffrement
Pour déchiffrer le texte, vous devez utiliser les opérations inverses dans l'ordre inverse (voir Fig. 2).
L'opĂ©ration XOR est inversĂ©e Ă elle-mĂȘme, l'inverse de l'opĂ©ration S est la substitution selon le tableau suivant:
Tableau de transformation non linéaire inverseLa transformation inverse en fonction L sera:
a0=a15â148+a14â32+a13â133+a12â16+
+a11â194+a10â192+a9â1+a8â251+a7â1+a6â192+a5â194+
+a4â16+a3â133+a2â32+a1â148+a0â1
et un changement dans la direction du niveau supérieur. (Répéter l'opération 16 fois)
Implémentation Java
Tout d'abord, nous définissons les constantes nécessaires
static final int BLOCK_SIZE = 16;
Créons toutes les fonctions principales:
Pour implémenter la fonction L, nous avons besoin de plusieurs fonctions auxiliaires, une pour calculer la multiplication des nombres dans le champ de Galois, et une pour le décalage.
Fonctions inverses:
Eh bien, et la fonction principale
static byte[] key_1 = {0x77, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11, 0x00, (byte) 0xff, (byte) 0xee, (byte) 0xdd, (byte) 0xcc, (byte) 0xbb, (byte) 0xaa, (byte) 0x99, (byte) 0x88}; static byte[] key_2 = {(byte) 0xef, (byte) 0xcd, (byte) 0xab, (byte) 0x89, 0x67, 0x45, 0x23, 0x01, 0x10, 0x32, 0x54, 0x76, (byte) 0x98, (byte) 0xba, (byte) 0xdc, (byte) 0xfe}; static byte[] blk = DatatypeConverter.parseHexBinary("8899aabbccddeeff0077665544332211"); public static void main(String[] args) { GOST_Kuz_Expand_Key(key_1, key_2); byte[] encriptBlok = GOST_Kuz_Encript(blk); System.out.println(DatatypeConverter.printHexBinary(encriptBlok)); byte[] decriptBlok = GOST_Kuz_Decript(encriptBlok); System.out.println(DatatypeConverter.printHexBinary(decriptBlok)); }
Nous avons appris à crypter un bloc de données afin de crypter du texte dont la longueur est plus longue que la longueur du bloc; il existe plusieurs modes décrits dans la norme - GOST 34.13-2015:
- mode de remplacement simple (Electronic Codebook, ECB);
- mode gamma (compteur, CTR);
- mode gamma avec retour de sortie (Output Feedback, OFB);
- mode d'engrenage de remplacement simple (Cipher Block Chaining, CBC);
- mode gamma avec rétroaction en texte chiffré (Cipher Feedback, CFB);
- Mode de code d'authentification de message (MAC).
Dans tous les modes, la longueur du texte doit toujours ĂȘtre un multiple de la longueur du bloc, de sorte que le texte est toujours complĂ©tĂ© Ă droite avec un seul bit et des zĂ©ros Ă la longueur du bloc.
Le mode le plus simple est le mode de remplacement simple. Dans ce mode, le texte est divisé en blocs, puis chaque bloc est chiffré séparément des autres, puis les blocs du texte chiffré sont collés ensemble et nous obtenons un message chiffré. Ce mode est à la fois le plus simple et le plus vulnérable et n'est pratiquement jamais appliqué en pratique.
D'autres modes pourront ĂȘtre examinĂ©s en dĂ©tail ultĂ©rieurement.