Introducere în SMS4:
Acest algoritm este un algoritm de grupare. Algoritmul are o lungime a pachetului de 128 de biți și o lungime a cheii de 128 biți, adică 16 octeți. Atât algoritmul de criptare, cât și algoritmul de extindere a cheilor adoptă o structură de iterație neliniară de 32 de runde. Algoritmul de decriptare are aceeași structură ca algoritmul de criptare, cu excepția faptului că ordinea de utilizare a cheii rotunde este inversată, iar cheia roții de decriptare este ordinea inversă a cheii roții de criptare. În toate clasele de bază ale SMS4, veți vedea că funcțiile de bază ale criptării și decriptării sunt aceleași, dar este necesar un bit de tip int pentru a determina dacă este criptat sau decriptat.
Elemente de bază ale algoritmului de criptare SMS4:
clasa publică SMS4 {
privat static final int ENCRYPT = 1; privat static final int DECRYPT = 0; public static final int ROUND = 32; bloc intern static privat final int BLOCK = 16;
octet privat[] 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) { returnează x << y | x >>> (32 - y); }
private int ByteSub(int A) { retur (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) { return B ^ Rotl(B, 2) ^ Rotl(B, 10) ^ Rotl(B, 18) ^ Rotl(B, 24); return B^(B<<2|B>>>30)^(B<<10|B>>>22)^(B<<18|B>>>14)^(B<<24|B>>>8); }
private int L2(int B) { return B ^ Rotl(B, 13) ^ Rotl(B, 23); returnează B^(B<<13|B>>>19)^(B<<23|B>>>9); }
void SMS4Crypt(byte[] Input, byte[] Output, int[] rk) { int r, mid, x0, x1, x2, x3; int[] x = nou int[4]; int[] tmp = nou int[4]; pentru (int i = 0; Am < 4; i++) { tmp[0] = Input[0 + 4 * i] & 0xff; tmp[1] = Input[1 + 4 * i] & 0xff; tmp[2] = Input[2 + 4 * i] & 0xff; tmp[3] = Input[3 + 4 * i] & 0xff; x= tmp[0] << 24 | tmp[1] << 16 | tmp[2] << 8 | tmp[3]; x=(Input[0+4*i]<<24| Input[1+4*i]<<16| Input[2+4*i]<<8| Input[3+4*i]); } pentru (r = 0; r < 32; r += 4) { mid = x[1] ^ x[2] ^ x[3] ^ rk[r + 0]; mid = ByteSub(mid); x[0] = x[0] ^ L1(mijloc); x4
mid = x[2] ^ x[3] ^ x[0] ^ rk[r + 1]; mid = ByteSub(mid); x[1] = x[1] ^ L1(mijloc); x5
mid = x[3] ^ x[0] ^ x[1] ^ rk[r + 2]; mid = ByteSub(mid); x[2] = x[2] ^ L1(mijloc); x6
mid = x[0] ^ x[1] ^ x[2] ^ rk[r + 3]; mid = ByteSub(mid); x[3] = x[3] ^ L1(mijloc); x7 }
Revers pentru (int j = 0; J < 16; j += 4) { Output[j] = (octet) (x[3 - j / 4] >>> 24 & 0xFF); Ieșire[j + 1] = (octet) (x[3 - j / 4] >>> 16 & 0xFF); Output[j + 2] = (octet) (x[3 - j / 4] >>> 8 & 0xFF); Ieșire[j + 3] = (octet) (x[3 - j / 4] & 0xFF); } }
private void SMS4KeyExt(byte[] Key, int[] rk, int CryptFlag) { int r, mid; int[] x = nou int[4]; int[] tmp = nou int[4]; pentru (int i = 0; Am < 4; i++) { tmp[0] = Tonalitate[0 + 4 * i] & 0xFF; tmp[1] = Cheie[1 + 4 * i] & 0xff; tmp[2] = Cheie[2 + 4 * i] & 0xff; tmp[3] = Cheie[3 + 4 * i] & 0xff; x= tmp[0] << 24 | tmp[1] << 16 | tmp[2] << 8 | tmp[3]; x=Key[0+4*i]<<24| Cheia[1+4*i]<<16| Cheia[2+4*i]<<8| Cheie[3+4*i]; } x[0] ^= 0xa3b1bac6; x[1] ^= 0x56aa3350; x[2] ^= 0x677d9197; x[3] ^= 0xb27022dc; pentru (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(mijloc); rk1=K5
mid = x[3] ^ x[0] ^ x[1] ^ CK[r + 2]; mid = ByteSub(mid); rk[r + 2] = x[2] ^= L2(mijloc); rk2=K6
mid = x[0] ^ x[1] ^ x[2] ^ CK[r + 3]; mid = ByteSub(mid); rk[r + 3] = x[3] ^= L2(mijloc); rk3=K7 }
Decriptează ordinea cheii roții: rk31, rk30,...,rk0 if (CryptFlag == DECRIPTARE) { pentru (r = 0; r < 16; r++) { mid = rk[r]; rk[r] = rk[31 - r]; rk[31 - r] = mid; } } }
public int sms4(byte[] in, int inLen, byte[] key, byte[] out, int CryptFlag) { punct int = 0; int[] round_key = noua int[RUNDĂ]; int[] round_key={0}; SMS4KeyExt (cheie, round_key, CryptFlag); Octet[] intrare = octet nou[16]; Ieșire octet[] = octet nou[16];
while (inLen >= BLOCK) { input = Arrays.copyOfRange(in, point, point + 16); output=Arrays.copyOfRange(ieșire, punct, punct+16); SMS4Crypt (intrare, ieșire, round_key); System.arraycopy(output, 0, out, point, BLOCK); inLen -= BLOCAJ; punct += BLOCAJ; }
returnează 0; }
}
Interfață externă ambalată:
Pe baza acestei clase de bază, principalele interfețe sunt următoarele:
byte static privat[] encode16(byte[] plain, byte[] key); octet static privat[] decodificare 16(cifru octet[] cheie); byte static privat[] encode32(byte[] plain, byte[] key); octet static privat[] decode32(cifru octet[] cheie); octet static public[] encodeSMS4(octet[] simplu, octet[] cheie); octet static public[] decodificare SMS4(cifru, cheie octet[]); decod static public StringSMS4toString(byte[] cifru, cheia byte[]);
encode16(octet[], octet[]) este o interfață pentru criptare pentru textul clar pe 16 biți și cheile pe 16 biți; Octet static privat[] decodificare 16(cifru octet[] cheie: este o interfață pentru decriptarea textului cifrat pe 16 biți și a cheii pe 16 biți; octet static privat[] encode32(byte[] plain, byte[] key): Aceasta este o interfață care criptează textul clar pe 32 de biți și cheile de 16 biți. Octet static privat[] decode32(octet[] cifru, cheie de octet[]): Aceasta este o interfață pentru decriptarea textului cifrat pe 32 de biți și cheilor pe 16 biți. byte static public[] encodeSMS4(byte[] plain, byte[] key): Aceasta este o interfață care criptează textul clar și cheile de 16 biți cu un număr nelimitat de octeți. octet static public[] decodeSMS4(octet[] cifru, cheia octet[]): Aceasta este o interfață pentru decriptarea textului cifrat și a cheilor de 16 biți cu un număr nelimitat de octeți. decodare publică statică a stringurilorSMS4toString(byte[] cifrare, cheia byte[]): Aceasta este o interfață pentru decriptarea unui număr nelimitat de octeți de text cifrat și chei pe 16 biți. Cod metodă de interfață:
octet static public[] encodeSMS4(String plaintext, byte[] key) { if (text clar == null || text clar.egal()) { returnează nul; } pentru (int i = text.flatGetBytes().length % 16; Am < 16 ani; i++) { text clar += ''; }
return SMS4.encodeSMS4(text.getBytes(), cheie); }
/** * Criptare SMS4 cu lungime nelimitată a textului clar * * @param text simplu * @param cheie * @return */ octet static public[] encodeSMS4(octet[] text clar, cheia octet[] { octet[] text cifrat = nou octet[wordtext.length];
int k = 0; int plainLen = textul clar.lungime; în timp ce (k + 16 <= plainLen) { octet[] cellPlain = octet nou[16]; pentru (int i = 0; Am < 16 ani; i++) { cellPlain= text clar[k + i]; } octet[] cellCipher = encode16(cellPlain, cheie); pentru (int i = 0; i < cellCipher.length; i++) { text cifrat[k + i] = Cifru celulă; }
k += 16; }
returnează textul cifrat; }
/** * Decriptare SMS4 fără limită de lungime a textului clar * * @param text cifrat * @param cheie * @return */ octet static public[] decodeSMS4(octet[] text cifrat, cheia octet[] { octet[] text clar = nou octet[cifrat.lungime];
int k = 0; int cipherLen = ciphertext.length; în timp ce (k + 16 <= cipherLen) { octet[] cellCipher = octet nou[16]; pentru (int i = 0; Am < 16 ani; i++) { cellCipher= text cifrat[k + i]; } octet[] cellPlain = decode16(cellCipher, cheie); pentru (int i = 0; i < cellPlain.length; i++) { text clar[k + i] = cellPlain; }
k += 16; }
returnează textul clar; }
/** * Decriptare pentru a obține șiruri de texte clare * @param text cifrat * @param cheie * @return */ public static String decodeSMS4toString(byte[] codhertext, byte[] key) { octet[] text clar = nou octet[cifrat.lungime]; text clar = decodeSMS4(text cifrat, cheie); return new String (text clar); }
/** * Doar textul clar pe 16 biți este criptat * * @param text simplu * @param cheie * @return */ Octet static privat[] encode16(octet[] text clar, octet[] cheie) { octet[] cifr = octet nou[16]; SMS4 sm4 = noul SMS4(); sm4.sms4(text clar, 16, cheie, cifru, CRIPTARE);
return cipher; }
/** * Doar textul cifrat pe 16 biți este decriptat * * @param text simplu * @param cheie * @return */ Octet static privat[] decode16(octet[] text cifrat, octet[] cheie) { byte[] plain = octet nou[16]; SMS4 sm4 = noul SMS4(); sm4.sms4(text cifrat, 16, cheie, simplu, DECRIPTARE);
să returneze pe plan de răspuns; } Nu voi introduce aici doar criptarea textului clar pe 32 de biți, care este foarte asemănătoare cu metoda textului clar doar pe 16 biți.
Algoritmul de bază pentru criptare și decriptare fără a limita lungimea textului clar se bazează pe această bază: criptarea și decriptarea doar a 16 biți. Pentru textul clar mai mare de 16 biți, aici se folosește criptarea pachetelor. Dacă întâlnești text clar ca 30 de biți care nu pot fi divizibili la 16, o modalitate de a-l completa este să-l compensezi până când devine divizibil cu 16. În principiu, doar cel mai mic număr poate fi împărțit la 16, desigur, dacă ești mulțumit, nu contează dacă îl mărești, pentru că este simbolul de închidere.
Criptarea pachetelor înseamnă să criptezi fiecare text clar de 16 biți o singură dată, apoi să reasamblezi textul cifrat de 16 biți într-un nou text cifrat. În procesul de decriptare, acesta este de asemenea împărțit într-o singură bucată de 16 biți, iar apoi mai multe dintre aceste texte clare decriptate sunt reasamblate în text clar nou.
Demonstrație de utilizare:
Cheie Octet[] cheia = { 0x01, 0x23, 0x45, 0x67, (octet) 0x89, (octet) 0xab, (octet) 0xcd, (octet) 0xef, (octet) 0xfe, (octet) 0xdc, (octet) 0xba, (octet) 0x98, 0x76, 0x54, 0x32, 0x10 };
String newString = Coding, salut!; Text simplu
octet[] enOut = SMS4.encodeSMS4(newString, cheie); if (enOut == null) { restitui; }
System.out.println (rezultat criptare:); printBit(enOut);
octet[] deOut = SMS4.decodeSMS4(enOut, cheie); System.out.println( Rezultat de decriptare (Return Byte[]) :); printBit(deOut);
String deOutStr = SMS4.decodeSMS4toString(enOut, cheie); System.out.println( Decriptează rezultatul (return String): + deOutStr); |