Introduction à SMS4 :
Cet algorithme est un algorithme de regroupement. L’algorithme a une longueur de paquet de 128 bits et une longueur de clé de 128 bits, soit 16 octets. L’algorithme de chiffrement et l’algorithme d’expansion de clé adoptent tous deux une structure d’itération non linéaire de 32 tours. L’algorithme de déchiffrement a la même structure que l’algorithme de chiffrement, sauf que l’ordre d’utilisation de la clé ronde est inversé, et la clé de la roue de déchiffrement est l’ordre inverse de la clé de la roue de chiffrement. Dans toutes les classes de base de SMS4, vous verrez que les fonctions de base du chiffrement et du déchiffrement sont les mêmes, mais qu’un bit de drapeau de type int est nécessaire pour déterminer s’il est chiffré ou déchiffré.
Bases de l’algorithme de chiffrement SMS4 :
classe publique SMS4 {
Statique privé final int ENCRYPT = 1 ; internement statique privé final int DECRYPT = 0 ; TOUR FINAL public statique = 32 ; bloc privé statique final int BLOCK = 16 ;
octet privé[] Sbox = { (octet) 0xd6, (octet) 0x90, (octet) 0xe9, (octet) 0xfe, (octet) 0xcc, (octet) 0xe1, 0x3d, (octet) 0xb7, 0x16, (octet) 0xb6, 0x14, (octet) 0xc2, 0x28, (octet) 0xfb, 0x2c, 0x05, 0x2b, 0x67, (octet) 0x9a, 0x76, 0x2a, (octet) 0xbe, 0x04, (octet) 0xc3, (octet) 0xaa, 0x44, 0x13, 0x26, 0x49, (octet) 0x86, 0x06, (octet) 0x99, (octet) 0x9c, 0x42, 0x50, (octet) 0xf4, (octet) 0x91, (octet) 0xef, (octet) 0x98, 0x7a, 0x33, 0x54, 0x0b, 0x43, (octet) 0xed, (octet) 0xcf, (octet) 0xac, 0x62, (octet) 0xe4, (octet) 0xb3, 0x1c, (octet) 0xa9, (octet) 0xc9, 0x08, (octet) 0xe8, (octet) 0x95, (octet) 0x80, (octet) 0xdf, (octet) 0x94, (octet) 0xfa, 0x75, (octet) 0x8f, 0x3f, (octet) 0xa6, 0x47, 0x07, (octet) 0xa7, (octet) 0xfc, (octet) 0xf3, 0x73, 0x17, (octet) 0xba, (octet) 0x83, 0x59, 0x3c, 0x19, (octet) 0xe6, (octet) 0x85, 0x4f, (octet) 0xa8, 0x68, 0x6b, (octet) 0x81, (octet) 0xb2, 0x71, 0x64, (octet) 0xda, (octet) 0x8b, (octet) 0xf8, (octet) 0xeb, 0x0f, 0x4b, 0x70, 0x56, (octet) 0x9d, 0x35, 0x1e, 0x24, 0x0e, 0x5e, 0x63, 0x58, (octet) 0xd1, (octet) 0xa2, 0x25, 0x22, 0x7c, 0x3b, 0x01, 0x21, 0x78, (octet) 0x87, (octet) 0xd4, 0x00, 0x46, 0x57, (octet) 0x9f, (octet) 0xd3, 0x27, 0x52, 0x4c, 0x36, 0x02, (octet) 0xe7, (octet) 0xa0, (octet) 0xc4, (octet) 0xc8, (octet) 0x9e, (octet) 0xea, (octet) 0xbf, (octet) 0x8a, (octet) 0xd2, 0x40, (octet) 0xc7, 0x38, (octet) 0xb5, (octet) 0xa3, (octet) 0xf7, (octet) 0xf2, (octet) 0xce, (octet) 0xf9, 0x61, 0x15, (octet) 0xa1, (octet) 0xe0, (octet) 0xae, 0x5d, (octet) 0xa4, (octet) 0x9b, 0x34, 0x1a, 0x55, (octet) 0xad, (octet) 0x93, 0x32, 0x30, (octet) 0xf5, (octet) 0x8c, (octet) 0xb1, (octet) 0xe3, 0x1d, (octet) 0xf6, (octet) 0xe2, 0x2e, (octet) 0x82, 0x66, (octet) 0xca, 0x60, (octet) 0xc0, 0x29, 0x23, (octet) 0xab, 0x0d, 0x53, 0x4e, 0x6f, (octet) 0xd5, (octet) 0xdb, 0x37, 0x45, (octet) 0xde, (octet) 0xfd, (octet) 0x8e, 0x2f, 0x03, (octet) 0xff, 0x6a, 0x72, 0x6d, 0x6c, 0x5b, 0x51, (octet) 0x8d, 0x1b, (octet) 0xaf, (octet) 0x92, (octet) 0xbb, (octet) 0xdd, (octet) 0xbc, 0x7f, 0x11, (octet) 0xd9, 0x5c, 0x41, 0x1f, 0x10, 0x5a, (octet) 0xd8, 0x0a, (octet) 0xc1, 0x31, (octet) 0x88, (octet) 0xa5, (octet) 0xcd, 0x7b, (octet) 0xbd, 0x2d, 0x74, (octet) 0xd0, 0x12, (octet) 0xb8, (octet) 0xe5, (octet) 0xb4, (octet) 0xb0, (octet) 0x89, 0x69, (octet) 0x97, 0x4a, 0x0c, (octet) 0x96, 0x77, 0x7e, 0x65, (octet) 0xb9, (octet) 0xf1, 0x09, (octet) 0xc5, 0x6e, (octet) 0xc6, (octet) 0x84, 0x18, (octet) 0xf0, 0x7d, (octet) 0xec, 0x3a, (octet) 0xdc, 0x4d, 0x20, 0x79, (octet) 0xee, 0x5f, 0x3e, (octet) 0xd7, (octet) 0xcb, 0x39, 0x48 } ;
private int[] CK = { 0x00070e15, 0x1c232a31, 0x383f464d, 0x545b6269, 0x70777e85, 0x8c939aa1, 0xa8afb6bd, 0xc4cbd2d9, 0xe0e7eef5, 0xfc030a11, 0x181f262d, 0x343b4249, 0x50575e65, 0x6c737a81, 0x888f969d, 0xa4abb2b9, 0xc0c7ced5, 0xdce3eaf1, 0xf8ff060d, 0x141b2229, 0x30373e45, 0x4c535a61, 0x686f767d, 0x848b9299, 0xa0a7aeb5, 0xbcc3cad1, 0xd8dfe6ed, 0xf4fb0209, 0x10171e25, 0x2c333a41, 0x484f565d, 0x646b7279 } ;
private int Rotl(int x, int y) { retourner x << y | x >>> (32 - y) ; }
private int ByteSub(int A) { retour (Sbox[A >>> 24 & 0xFF] & 0xFF) << 24 | (Sbox[A >>> 16 & 0xFF] & 0xFF) << 16 | (Sbox[A >>> 8 & 0xFF] & 0xFF) << 8 | (Sbox[A & 0xFF] & 0xFF) ; }
private int L1(int B) { retour B ^ Rotl(B, 2) ^ Rotl(B, 10) ^ Rotl(B, 18) ^ Rotl(B, 24) ; retour B^(B<<2|B>>>30)^(B<<10|B>>>22)^(B<<18|B>>>14)^(B<<24|B>>>8) ; }
private int L2(int B) { retour B ^ Rotl(B, 13) ^ Rotl(B, 23) ; retour B^(B<<13|B>>>19)^(B<<23|B>>>9) ; }
void SMS4Crypt(octet[] Entrée, octet[] Sortie, int[] rk) { int r, mid, x0, x1, x2, x3 ; int[] x = nouveau int[4] ; int[] tmp = new int[4] ; pour (int i = 0 ; J’ai < 4 ; i++) { tmp[0] = Entrée[0 + 4 * i] & 0xff ; tmp[1] = Entrée[1 + 4 * i] & 0xff ; tmp[2] = Entrée[2 + 4 * i] & 0xff ; tmp[3] = Entrée[3 + 4 * i] & 0xff ; x= tmp[0] << 24 | TMP[1] << 16 | TMP[2] << 8 | tmp[3] ; x=(Entrée[0+4*i]<<24| Entrée[1+4*i]<<16| Input[2+4*i]<<8| Entrée[3+4*i]) ; } pour (r = 0 ; r < 32 ; r += 4) { mid = x[1] ^ x[2] ^ x[3] ^ rk[r + 0] ; mid = ByteSub(mid) ; x[0] = x[0] ^ L1(milieu) ; x4
mid = x[2] ^ x[3] ^ x[0] ^ rk[r + 1] ; mid = ByteSub(mid) ; x[1] = x[1] ^ L1(milieu) ; x5
mid = x[3] ^ x[0] ^ x[1] ^ rk[r + 2] ; mid = ByteSub(mid) ; x[2] = x[2] ^ L1(milieu) ; x6
mid = x[0] ^ x[1] ^ x[2] ^ rk[r + 3] ; mid = ByteSub(mid) ; x[3] = x[3] ^ L1(milieu) ; x7 }
Revers pour (int j = 0 ; j < 16 ; j += 4) { Sortie[j] = (octet) (x[3 - j / 4] >>> 24 & 0xFF) ; Sortie[j + 1] = (octet) (x[3 - j / 4] >>> 16 & 0xFF) ; Sortie[j + 2] = (octet) (x[3 - j / 4] >>> 8 & 0xFF) ; Sortie[j + 3] = (octet) (x[3 - j / 4] & 0xFF) ; } }
private void SMS4KeyExt(byte[] Key, int[] rk, int CryptFlag) { int r, mid ; int[] x = nouveau int[4] ; int[] tmp = new int[4] ; pour (int i = 0 ; J’ai < 4 ; i++) { tmp[0] = Clé[0 + 4 * i] & 0xFF ; tmp[1] = Tonalité[1 + 4 * i] & 0xff ; tmp[2] = Tonalité[2 + 4 * i] & 0xff ; tmp[3] = Tonalité[3 + 4 * i] & 0xff ; x= tmp[0] << 24 | TMP[1] << 16 | TMP[2] << 8 | tmp[3] ; x=Clé[0+4*i]<<24| Clé[1+4*i]<<16| Clé[2+4*i]<<8| Clé[3+4*i] ; } x[0] ^= 0xa3b1bac6 ; x[1] ^= 0x56aa3350 ; x[2] ^= 0x677d9197 ; x[3] ^= 0xb27022dc ; pour (r = 0 ; r < 32 ; r += 4) { mid = x[1] ^ x[2] ^ x[3] ^ CK[r + 0] ; mid = ByteSub(mid) ; rk[r + 0] = x[0] ^= L2(mid) ; rk0=K4
mid = x[2] ^ x[3] ^ x[0] ^ CK[r + 1] ; mid = ByteSub(mid) ; rk[r + 1] = x[1] ^= L2(mid) ; rk1=K5
mid = x[3] ^ x[0] ^ x[1] ^ CK[r + 2] ; mid = ByteSub(mid) ; rk[r + 2] = x[2] ^= L2(mid) ; rk2=K6
mid = x[0] ^ x[1] ^ x[2] ^ CK[r + 3] ; mid = ByteSub(mid) ; rk[r + 3] = x[3] ^= L2(mid) ; rk3=K7 }
Déchiffrer l’ordre de la clé de la roue : rk31, rk30,...,rk0 if (CryptFlag == DECRYPT) { pour (r = 0 ; r < 16 ; r++) { mid = rk[r] ; rk[r] = rk[31 - r] ; rk[31 - r] = mid ; } } }
public int sms4(octet[] entrée, int inLen, octet[] clé, octet[] sortie, int CryptFlag) { point d’intelligence = 0 ; int[] round_key = nouvelle int[ROUND] ; int[] round_key={0} ; SMS4KeyExt (clé, round_key, CryptFlag) ; Octet[] entrée = nouvel octet[16] ; Sortie octet[] = nouvel octet[16] ;
while (inLen >= BLOCK) { entrée = Tableaux.copieDeRange(in, point, point + 16) ; sortie=Tableaux.copieDeRange(sortie, point, point+16) ; SMS4Crypt (entrée, sortie, round_key) ; System.arraycopy (sortie, 0, sortie, point, BLOCK) ; inLen -= BLOC ; point += BLOCAGE ; }
retour 0 ; }
}
Interface externe intégrée :
Sur la base de cette classe de base, les interfaces principales sont les suivantes :
octet statique privé[] encode16(octet[] plain, octet[] clé) ; octet statique privé[] décode16(chiffre d’octet[] clé, clé d’octet[]) ; octet statique privé[] encode32(byte[] plain, byte[] key) ; octet statique privé[] décode32(chiffre d’octet, clé d’octet[] ; octet statique public[] encodeSMS4(octet[] plain, clé d’octet[] ; octet statique public[] decodeSMS4(octet[] chiffre, clé d’octet[] ; décodeur statique public StringSMS4toString(byte[] chiffre, clé d’octet[] ;
encode16(octet[], octet[]) est une interface pour le chiffrement des clés de texte clair 16 bits et 16 bits ; Octet statique privé[] Decode16(Chiffre d’octet[] clé d’octet[]) : est une interface pour déchiffrer le texte chiffré 16 bits et la clé 16 bits ; Octet statique privé[] encode32(octet[] plain, clé d’octet[] : Il s’agit d’une interface qui chiffre le texte clair 32 bits et les clés 16 bits. Byte statique privé[] décode32(octet[] chiffre, clé d’octet[] : Il s’agit d’une interface pour déchiffrer le texte chiffré 32 bits et les clés 16 bits. octet statique public[] encodeSMS4(octet[] plain, clé d’octet[] : Il s’agit d’une interface qui chiffre le texte clair et les clés de 16 bits avec un nombre illimité d’octets. octet statique public[] decodesSMS4(octet[] chiffre, clé d’octet[] : Il s’agit d’une interface pour déchiffrer le texte chiffré et les clés 16 bits avec un nombre illimité d’octets. décodeage statique public StringSMS4toString(byte[] chiffre, clé d’octet[] : Il s’agit d’une interface pour déchiffrer des octets illimités de texte chiffré et de clés 16 bits. Code de méthode d’interface :
byte statique public[] encodeSMS4(String wordtext, byte[] key) { if (texte clair == null || texte clair.égales()) { retourner nul ; } pour (int i = texte clair.getBytes().length % 16 ; J'< 16 ans ; i++) { texte clair += '' ; }
return SMS4.encodeSMS4(wordtext.getBytes(), key) ; }
/** * Chiffrement SMS4 avec longueur illimitée de texte en clair * * @param texte en clair * @param clé * @return */ octet statique public[] encodeSMS4(octet[] texte clair, clé d’octet[] { octet[] texte chiffré = nouvel octet[wordtext.length] ;
int k = 0 ; int plainLen = wordtext.length ; tandis que (k + 16 <= plainLen) { octet[] cellPlain = nouvel octet[16] ; pour (int i = 0 ; J'< 16 ans ; i++) { cellPlain= texte clair[k + i] ; } octet[] cellCipher = encode16(cellPlain, clé) ; pour (int i = 0 ; i < cellCipher.length ; i++) { texte chiffré[k + i] = chiffre de cellule; }
k += 16 ; }
retourner le texte chiffré ; }
/** * Déchiffrement SMS4 sans limite de longueur du texte clair * * @param texte chiffré * @param clé * @return */ octet statique public[] decodeSMS4(octet[] texte chiffré, clé d’octet[] { octet[] texte clair = nouvel octet[crithertext.length] ;
int k = 0 ; int chiffre Len = chiffretexte.longueur ; tandis que (k + 16 <= cipherLen) { octet[] cellCipher = nouvel octet[16] ; pour (int i = 0 ; J'< 16 ans ; i++) { cellCipher= texte chiffré[k + i] ; } octet[] cellPlain = decode16(cellCipher, key) ; pour (int i = 0 ; i < cellPlain.length ; i++) { texte clair[k + i] = cellPlain; }
k += 16 ; }
retourner le texte en clair ; }
/** * Déchiffrer pour obtenir des chaînes de texte clair * @param texte chiffré * @param clé * @return */ public static String decodeSMS4toString(byte[] crithertext, byte[] key) { octet[] texte clair = nouvel octet[crithertext.length] ; texte clair = decodeSMS4(texte chiffré, clé) ; retourner nouvelle chaîne (texte clair) ; }
/** * Seul le texte clair 16 bits est chiffré * * @param texte en clair * @param clé * @return */ Octet statique privé[] encode16(octet[] texte clair, octet[] clé) { Octet[] chiffre = nouvel octet[16] ; SMS4 sm4 = nouveau SMS4() ; sm4.sms4 (texte clair, 16, clé, chiffre, CRYPTAGE) ;
chiffrer à retourner ; }
/** * Seul le texte chiffré 16 bits est déchiffré * * @param texte en clair * @param clé * @return */ Octet statique privé[] Decode16(octet[] texte chiffré, octet[] key) { byte[] plain = nouvel octet[16] ; SMS4 sm4 = nouveau SMS4() ; sm4.sms4 (texte chiffré, 16, clé, plain, DECRYPT) ;
retour plain ; } Je n’introduirai pas ici uniquement le chiffrement du texte clair 32 bits, qui est très similaire à la méthode du texte clair seulement 16 bits.
L’algorithme de base pour le chiffrement et le déchiffrement sans limiter la longueur du texte clair repose sur cette base de chiffrement et déchiffrement de seulement 16 bits. Pour le texte clair de plus de 16 bits, le chiffrement des paquets est utilisé ici. Si vous rencontrez du texte clair comme 30 bits qui ne peut pas être divisible par 16, une façon de le remplir est de le faire divisible par 16. En principe, seul le plus petit nombre peut être divisé par 16, bien sûr, si vous êtes satisfait, peu importe si vous l’agrandissez, car c’est le symbole de fermeture.
Le chiffrement des paquets consiste à chiffrer chaque texte clair de 16 bits une fois, puis à réassembler le texte chiffré de 16 bits en un nouveau texte chiffré. Lors du processus de déchiffrement, il est également divisé en une seule pièce de 16 bits, puis plusieurs de ces textes déchiffrés sont réassemblés en un nouveau texte clair.
Démonstration d’utilisation :
Clé Octet[] clé = { 0x01, 0x23, 0x45, 0x67, (octet) 0x89, (octet) 0xab, (octet) 0xcd, (octet) 0xef, (octet) 0xfe, (octet) 0xdc, (octet) 0xba, (octet) 0x98, 0x76, 0x54, 0x32, 0x10 } ;
Nouvelle chaîne = Codage, bonjour ! ; Texte clair
octet[] enOut = SMS4.encodeSMS4(newString, clé) ; if (enOut == null) { rendre; }
System.out.println (résultat du chiffrement :) ; printBit(enOut) ;
octet[] deOut = SMS4.decodeSMS4(enOut, clé) ; System.out.println( résultat de déchiffrement (octet de retour[]) :) ; printBit(deOut) ;
String deOutStr = SMS4.decodeSMS4toString(enOut, key) ; System.out.println( Déchiffrer le résultat (retourner la chaîne) : + deOutStr) ; |