Wprowadzenie do SMS4:
Ten algorytm jest algorytmem grupowania. Algorytm ma długość pakietu 128 bitów i długość klucza 128 bitów, co daje 16 bajtów. Zarówno algorytm szyfrowania, jak i algorytm rozszerzania klucza przyjmują 32-rundową nieliniową strukturę iteracji. Algorytm deszyfrowania ma taką samą strukturę jak algorytm szyfrowania, z tą różnicą, że kolejność użycia klucza rundy jest odwrócona, a klucz koła deszyfrującego jest odwróconą kolejnością klucza koła szyfrującego. We wszystkich podstawowych klasach SMS4 zauważysz, że podstawowe funkcje szyfrowania i deszyfrowania są takie same, ale potrzebny jest bit flagi typu int, aby określić, czy jest szyfrowany czy odszyfrowany.
Podstawy algorytmu szyfrowania SMS4:
public class SMS4 {
prywatny statyczny final int ENCRYPT = 1; prywatny statyczny final int DECRYPT = 0; publiczny finał statyczny inter RUNDA = 32; prywatny statyczny końcowy int BLOCK = 16;
bajt prywatny[] Sbox = { (bajt) 0xd6, (bajt) 0x90, (bajt) 0xe9, (bajt) 0xfe, (bajt) 0xcc, (bajt) 0xe1, 0x3d, (bajt) 0xb7, 0x16, (bajt) 0xb6, 0x14, (bajt) 0xc2, 0x28, (bajt) 0xfb, 0x2c, 0x05, 0x2b, 0x67, (bajt) 0x9a, 0x76, 0x2a, (bajt) 0xbe, 0x04, (bajt) 0xc3, (bajt) 0xaa, 0x44, 0x13, 0x26, 0x49, (bajt) 0x86, 0x06, (bajt) 0x99, (bajt) 0x9c, 0x42, 0x50, (bajt) 0xf4, (bajt) 0x91, (bajt) 0xef, (bajt) 0x98, 0x7a, 0x33, 0x54, 0x0b, 0x43, (bajt) 0xed, (bajt) 0xcf, (bajt) 0xac, 0x62, (bajt) 0xe4, (bajt) 0xb3, 0x1c, (bajt) 0xa9, (bajt) 0xc9, 0x08, (bajt) 0xe8, (bajt) 0x95, (bajt) 0x80, (bajt) 0xdf, (bajt) 0x94, (bajt) 0xfa, 0x75, (bajt) 0x8f, 0x3f, (bajt) 0xa6, 0x47, 0x07, (bajt) 0xa7, (bajt) 0xfc, (bajt) 0xf3, 0x73, 0x17, (bajt) 0xba, (bajt) 0x83, 0x59, 0x3c, 0x19, (bajt) 0xe6, (bajt) 0x85, 0x4f, (bajt) 0xa8, 0x68, 0x6b, (bajt) 0x81, (bajt) 0xb2, 0x71, 0x64, (bajt) 0xda, (bajt) 0x8b, (bajt) 0xf8, (bajt) 0xeb, 0x0f, 0x4b, 0x70, 0x56, (bajt) 0x9d, 0x35, 0x1e, 0x24, 0x0e, 0x5e, 0x63, 0x58, (bajt) 0xd1, (bajt) 0xa2, 0x25, 0x22, 0x7c, 0x3b, 0x01, 0x21, 0x78, (bajt) 0x87, (bajt) 0xd4, 0x00, 0x46, 0x57, (bajt) 0x9f, (bajt) 0xd3, 0x27, 0x52, 0x4c, 0x36, 0x02, (bajt) 0xe7, (bajt) 0xa0, (bajt) 0xc4, (bajt) 0xc8, (bajt) 0x9e, (bajt) 0xea, (bajt) 0xbf, (bajt) 0x8a, (bajt) 0xd2, 0x40, (bajt) 0xc7, 0x38, (bajt) 0xb5, (bajt) 0xa3, (bajt) 0xf7, (bajt) 0xf2, (bajt) 0xce, (bajt) 0xf9, 0x61, 0x15, (bajt) 0xa1, (bajt) 0xe0, (bajt) 0xae, 0x5d, (bajt) 0xa4, (bajt) 0x9b, 0x34, 0x1a, 0x55, (bajt) 0xad, (bajt) 0x93, 0x32, 0x30, (bajt) 0xf5, (bajt) 0x8c, (bajt) 0xb1, (bajt) 0xe3, 0x1d, (bajt) 0xf6, (bajt) 0xe2, 0x2e, (bajt) 0x82, 0x66, (bajt) 0xca, 0x60, (bajt) 0xc0, 0x29, 0x23, (bajt) 0xab, 0x0d, 0x53, 0x4e, 0x6f, (bajt) 0xd5, (bajt) 0xdb, 0x37, 0x45, (bajt) 0xde, (bajt) 0xfd, (bajt) 0x8e, 0x2f, 0x03, (bajt) 0xff, 0x6a, 0x72, 0x6d, 0x6c, 0x5b, 0x51, (bajt) 0x8d, 0x1b, (bajt) 0xaf, (bajt) 0x92, (bajt) 0xbb, (bajt) 0xdd, (bajt) 0xbc, 0x7f, 0x11, (bajt) 0xd9, 0x5c, 0x41, 0x1f, 0x10, 0x5a, (bajt) 0xd8, 0x0a, (bajt) 0xc1, 0x31, (bajt) 0x88, (bajt) 0xa5, (bajt) 0xcd, 0x7b, (bajt) 0xbd, 0x2d, 0x74, (bajt) 0xd0, 0x12, (bajt) 0xb8, (bajt) 0xe5, (bajt) 0xb4, (bajt) 0xb0, (bajt) 0x89, 0x69, (bajt) 0x97, 0x4a, 0x0c, (bajt) 0x96, 0x77, 0x7e, 0x65, (bajt) 0xb9, (bajt) 0xf1, 0x09, (bajt) 0xc5, 0x6e, (bajt) 0xc6, (bajt) 0x84, 0x18, (bajt) 0xf0, 0x7d, (bajt) 0xec, 0x3a, (bajt) 0xdc, 0x4d, 0x20, 0x79, (bajt) 0xee, 0x5f, 0x3e, (bajt) 0xd7, (bajt) 0xcb, 0x39, 0x48 };
prywatny 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) { zwróć x << y | x >>> (32 - y); }
private int ByteSub(int A) { return (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); }
prywatny int L2(int B) { return B ^ Rotl(B, 13) ^ Rotl(B, 23); return 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 = nowy int[4]; int[] tmp = nowy int[4]; dla (int i = 0; Mam < 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]); } dla (r = 0; r < 32; r += 4) { środek = x[1] ^ x[2] ^ x[3] ^ rk[r + 0]; mid = ByteSub(mid); x[0] = x[0] ^ L1(środek); x4
środek = x[2] ^ x[3] ^ x[0] ^ rk[r + 1]; mid = ByteSub(mid); x[1] = x[1] ^ L1(środek); x5
mid = x[3] ^ x[0] ^ x[1] ^ rk[r + 2]; mid = ByteSub(mid); x[2] = x[2] ^ L1(środek); x6
środek = x[0] ^ x[1] ^ x[2] ^ rk[r + 3]; mid = ByteSub(mid); x[3] = x[3] ^ L1(środek); x7 }
Rewers dla (int j = 0; j < 16; j += 4) { Wyjście[j] = (bajt) (x[3 - j / 4] >>> 24 & 0xFF); Wyjście[j + 1] = (bajt) (x[3 - j / 4] >>> 16 & 0xFF); Wyjście[j + 2] = (bajt) (x[3 - j / 4] >>> 8 & 0xFF); Wyjście[j + 3] = (bajt) (x[3 - j / 4] & 0xFF); } }
private void SMS4KeyExt(byte[] Key, int[] rk, int CryptFlag) { int r, mid; int[] x = nowy int[4]; int[] tmp = nowy int[4]; dla (int i = 0; Mam < 4; i++) { tmp[0] = Klucz[0 + 4 * i] & 0xFF; tmp[1] = Key[1 + 4 * i] & 0xff; tmp[2] = Klucz[2 + 4 * i] & 0xff; tmp[3] = Klucz[3 + 4 * i] & 0xff; x= tmp[0] << 24 | TMP[1] << 16 | TMP[2] << 8 | TMP[3]; x=Key[0+4*i]<<24| Key[1+4*i]<<16| Key[2+4*i]<<8| Klucz[3+4*i]; } x[0] ^= 0xa3b1bac6; x[1] ^= 0x56aa3350; x[2] ^= 0x677d9197; x[3] ^= 0xb27022dc; dla (r = 0; r < 32; r += 4) { środek = x[1] ^ x[2] ^ x[3] ^ CK[r + 0]; mid = ByteSub(mid); rk[r + 0] = x[0] ^= L2(środek); rk0=K4
środek = x[2] ^ x[3] ^ x[0] ^ CK[r + 1]; mid = ByteSub(mid); rk[r + 1] = x[1] ^= L2(środek); rk1=K5
środek = x[3] ^ x[0] ^ x[1] ^ CK[r + 2]; mid = ByteSub(mid); rk[r + 2] = x[2] ^= L2(środek); rk2=K6
środek = x[0] ^ x[1] ^ x[2] ^ CK[r + 3]; mid = ByteSub(mid); rk[r + 3] = x[3] ^= L2(środek); rk3=K7 }
Odszyfrowanie kolejności koła: rk31, rk30,...,rk0 if (CryptFlag == DECRYPT) { dla (r = 0; r < 16; r++) { mid = rk[r]; rk[r] = rk[31 - r]; rk[31 - R] = środek; } } }
public int sms4(byte[] in, int inLen, byte[] key, byte[] out, int CryptFlag) { int point = 0; int[] round_key = nowy int[ROUND]; int[] round_key={0}; SMS4KeyExt(key, round_key, CryptFlag); bajt[] wejście = nowy bajt[16]; bajt[] output = nowy bajt[16];
while (inLen >= BLOCK) { input = Arrays.copyOfRange(in, point, point + 16); output=Arrays.copyOfRange(out, point, point+16); SMS4Crypt (wejście, wyjście, round_key); System.arraycopy(output, 0, out, point, BLOCK); inLen -= BLOK; punkt += BLOK; }
return 0; }
}
Zintegrowany zewnętrzny interfejs:
Na podstawie tej podstawowej klasy główne interfejsy są następujące:
prywatny bajt statyczny[] encode16(byte[] plain, bajt[] key); prywatny bajt statyczny[] decode16(bajt[] szyfr, bajt[] klucz); prywatny bajt statyczny[] encode32(bajt[] prosty, bajt[] klucz); prywatny bajt statyczny[] decode32(bajt[] szyfr, bajt[] klucz); publiczny bajt statyczny[] kodować SMS4(bajt[] prosty, bajt[] klucz); publiczny bajt statyczny[] dekodować SMS4(bajt[] szyfr, bajt[] klucz); publiczny statyczny String dekoduje SMS4toString(byte[] szyfr, bajt[] klucz);
encode16(byte[], byte[]) to interfejs do szyfrowania kluczy jawnych 16-bitowego i 16-bitowego; prywatny statyczny bajt[] decode16(byte[] szyfr, bajt[] klucz): to interfejs do odszyfrowania 16-bitowego szyfrogramu i klucza 16-bitowego; prywatny bajt statyczny[] encode32(byte[] prosty, bajt[] klucz): To interfejs szyfrujący klucze zwykłe 32-bitowe i 16-bitowe. prywatny statyczny bajt[] decode32(byte[] szyfr, bajt[] klucz): To interfejs do odszyfrowywania 32-bitowego szyfrogramu i kluczy 16-bitowych. public static byte[] encodeSMS4(byte[] plain, byte[] key): To interfejs szyfrujący tekst jawny i klucze 16-bitowe z nieograniczoną liczbą bajtów. public static byte[] decodeSMS4(byte[] szyfr, bajt[] klucz): To interfejs do odszyfrowywania tekstów zaszyfrowanych i kluczy 16-bitowych z nieograniczoną liczbą bajtów. publiczny statyczny String dekoduje SMS4toString(byte[] szyfr, bajt[] klucz): To interfejs do odszypywania nieograniczonej liczby bajtów szyfrogramu i kluczy 16-bitowych. Kod metody interfejsu:
public static byte[] encodeSMS4(String plaintext, byte[] key) { if (plaintext == null || plaintext.equals()) { return null; } for (int i = jawny tekst.getBytes().długość % 16; < 16 lat; i++) { tekst jawny += ''; }
return SMS4.encodeSMS4(plaintext.getBytes(), klucz); }
/** * Szyfrowanie SMS4 z nieograniczoną długością tekstu jawnego * * @param tekst jawny * @param klucz * @return */ publiczny bajt statyczny[] enkoduj SMS4(bajt[] tekst jawny, bajt[] klucz) { bajt[] szyfrogram = nowy bajt[plaintext.length];
int k = 0; int plainLen = jawny tekst.długość; while (k + 16 <= plainLen) { bajt[] cellPlain = nowy bajt[16]; dla (int i = 0; < 16 lat; i++) { cellPlain= tekst jawny[k + i]; } bajt[] cellCipher = encode16(cellPlain, key); dla (int i = 0; i < cellCipher.length; i++) { Szyfr [k + i] = cellCipher; }
k += 16; }
zwróć szyfrogram; }
/** * Deszyfrowanie SMS4 bez ograniczenia długości tekstu jawnego * * @param szyfrogram * @param klucz * @return */ public static byte[] dekodować SMS4(byte[] szyfr, bajt[] klucz) { bajt[] tekst jawny = nowy bajt[szyfrowany tekst.długość];
int k = 0; int cipherLen = tekst szyfrowy. długość; while (k + 16 <= cipherLen) { bajt[] cellCipher = nowy bajt[16]; dla (int i = 0; < 16 lat; i++) { cellCipher= tekst szyfrogram[k + i]; } bajt[] cellPlain = decode16(cellCipher, key); dla (int i = 0; i < komórkaPlain.length; i++) { jawny tekst[k + i] = komórkaPlain; }
k += 16; }
zwróć tekst jawny; }
/** * Deszyfruj, aby uzyskać ciągi tekstu jawnego * @param szyfrogram * @param klucz * @return */ public static String dekoduj SMS4toString(byte[] szyfru, bajt[] key) { bajt[] tekst jawny = nowy bajt[szyfrowany tekst.długość]; tekst jawny = dekodować SMS4(szyfrogram, klucz); zwróć nowy String(tekst jawny); }
/** * Szyfrowany jest tylko 16-bitowy tekst jawny * * @param tekst jawny * @param klucz * @return */ Prywatny bajt statyczny[] encode16(byte[] tekst jawny, bajt[] klucz) { bajt[] szyfr = nowy bajt[16]; SMS4 sm4 = nowy SMS4(); sm4.sms4 (tekst jawny, 16, klucz, szyfr, ENCRYPT);
szyfr zwrotny; }
/** * Odszyfrowuje się tylko 16-bitowy szyfrogram * * @param tekst jawny * @param klucz * @return */ Prywatny bajt statyczny[] decode16(byte[] szyfrogram, bajt[] klucz) { bajt[] plain = nowy bajt[16]; SMS4 sm4 = nowy SMS4(); sm4.sms4 (tekst szyfrowy, 16, klucz, prosty, DESZYFROWANY);
powrót gładki; } Nie będę tu wprowadzał tylko 32-bitowego szyfrowania tekstu jawnego, które jest bardzo podobne do metody używania samego 16-bitowego tekstu jawnego.
Podstawowy algorytm szyfrowania i deszyfrowania bez ograniczania długości tekstu jawnego opiera się na tej zasadzie szyfrowania i deszyfrowania tylko 16 bitów. Dla tekstu jawnego większego niż 16 bitów stosuje się tutaj szyfrowanie pakietów. Jeśli napotkasz tekst jawny, na przykład 30 bitów, którego nie da się podzielić przez 16, jednym ze sposobów na wypełnienie go jest podkreślenie go do poziomu podzielności przez 16. Zasadniczo tylko najmniejszą liczbę można podzielić przez 16, oczywiście, jeśli jesteś zadowolony, nie ma znaczenia, czy ją powiększysz, bo to symbol zamykający.
Szyfrowanie pakietów polega na jednokrotnym zaszyfrowaniu każdego 16-bitowego tekstu jawnego, a następnie ponownym złożeniu zaszyfrowanego 16-bitowego tekstu zaszyfrowanego w nowy szyfrogram. W trakcie deszyfrowania jest on również dzielony na pojedynczy 16-bitowy fragment, a następnie kilka z tych odszyfrowanych tekstów jawnych jest ponownie składanych w nowy tekst jawny.
Demonstracja użycia:
Klucz bajt[] key = { 0x01, 0x23, 0x45, 0x67, (bajt) 0x89, (bajt) 0xab, (bajt) 0xcd, (bajt) 0xef, (bajt) 0xfe, (bajt) 0xdc, (bajt) 0xba, (bajt) 0x98, 0x76, 0x54, 0x32, 0x10 };
String newString = Kodowanie, hello!; Tekst jawny
bajt[] enOut = SMS4.encodeSMS4(newString, key); if (enOut == null) { wrócić; }
System.out.println(wynik szyfrowania:); printBit(enOut);
bajt[] deOut = SMS4.decodeSMS4(enOut, klucz); System.out.println( wynik deszyfrowania (bajt zwrotny[]) :); printBit(deOut);
String deOutStr = SMS4.decodeSMS4toString(enOut, key); System.out.println( Odszyfruj wynik (zwróć String): + deOutStr); |