Введение в SMS4:
Этот алгоритм является алгоритмом группировки. Алгоритм имеет длину пакета 128 бит, а длину ключа — 128 бит, что составляет 16 байт. И алгоритм шифрования, и алгоритм расширения ключа используют 32-раундовую нелинейную итерационную структуру. Алгоритм расшифровки имеет ту же структуру, что и алгоритм шифрования, за исключением того, что порядок использования круглого ключа обратный, а ключ колеса дешифрования — обратный порядок ключа колеса шифрования. Во всех базовых классах SMS4 вы увидите, что базовые функции шифрования и расшифровки одинаковы, но для определения того, зашифрован ли он или расшифрован, нужен бит флага типа int.
Основы алгоритма шифрования SMS4:
общественный класс SMS4 {
приватный статический финальный int ENCRYPT = 1; приватный статический финал int DECRYPT = 0; публичный статический финальный интеллект ROUND = 32; приватный статический финальный int BLOCK = 16;
приватный байт[] Sbox = { (байт) 0xd6, (байт) 0x90, (байт) 0xe9, (байт) 0xfe, (байт) 0xcc, (байт) 0xe1, 0x3d, (байт) 0xb7, 0x16, (байт) 0xb6, 0x14, (байт) 0xc2, 0x28, (байт) 0xfb, 0x2c, 0x05, 0x2b, 0x67, (байт) 0x9a, 0x76, 0x2a, (байт) 0xbe, 0x04, (байт) 0xc3, (байт) 0xaa, 0x44, 0x13, 0x26, 0x49, (байт) 0x86, 0x06, (байт) 0x99, (байт) 0x9c, 0x42, 0x50, (байт) 0xf4, (байт) 0x91, (байт) 0xef, (байт) 0x98, 0x7a, 0x33, 0x54, 0x0b, 0x43, (байт) 0xed, (байт) 0xcf, (байт) 0xac, 0x62, (байт) 0xe4, (байт) 0xb3, 0x1c, (байт) 0xa9, (байт) 0xc9, 0x08, (байт) 0xe8, (байт) 0x95, (байт) 0x80, (байт) 0xdf, (байт) 0x94, (байт) 0xfa, 0x75, (байт) 0x8f, 0x3f, (байт) 0xa6, 0x47, 0x07, (байт) 0xa7, (байт) 0xfc, (байт) 0xf3, 0x73, 0x17, (байт) 0xba, (байт) 0x83, 0x59, 0x3c, 0x19, (байт) 0xe6, (байт) 0x85, 0x4f, (байт) 0xa8, 0x68, 0x6b, (байт) 0x81, (байт) 0xb2, 0x71, 0x64, (байт) 0xda, (байт) 0x8b, (байт) 0xf8, (байт) 0xeb, 0x0f, 0x4b, 0x70, 0x56, (байт) 0x9d, 0x35, 0x1e, 0x24, 0x0e, 0x5e, 0x63, 0x58, (байт) 0xd1, (байт) 0xa2, 0x25, 0x22, 0x7c, 0x3b, 0x01, 0x21, 0x78, (байт) 0x87, (байт) 0xd4, 0x00, 0x46, 0x57, (байт) 0x9f, (байт) 0xd3, 0x27, 0x52, 0x4c, 0x36, 0x02, (байт) 0xe7, (байт) 0xa0, (байт) 0xc4, (байт) 0xc8, (байт) 0x9e, (байт) 0xea, (байт) 0xbf, (байт) 0x8a, (байт) 0xd2, 0x40, (байт) 0xc7, 0x38, (байт) 0xb5, (байт) 0xa3, (байт) 0xf7, (байт) 0xf2, (байт) 0xce, (байт) 0xf9, 0x61, 0x15, (байт) 0xa1, (байт) 0xe0, (байт) 0xae, 0x5d, (байт) 0xa4, (байт) 0x9b, 0x34, 0x1a, 0x55, (байт) 0xad, (байт) 0x93, 0x32, 0x30, (байт) 0xf5, (байт) 0x8c, (байт) 0xb1, (байт) 0xe3, 0x1d, (байт) 0xf6, (байт) 0xe2, 0x2e, (байт) 0x82, 0x66, (байт) 0xca, 0x60, (байт) 0xc0, 0x29, 0x23, (байт) 0xab, 0x0d, 0x53, 0x4e, 0x6f, (байт) 0xd5, (байт) 0xdb, 0x37, 0x45, (байт) 0xde, (байт) 0xfd, (байт) 0x8e, 0x2f, 0x03, (байт) 0xff, 0x6a, 0x72, 0x6d, 0x6c, 0x5b, 0x51, (байт) 0x8d, 0x1b, (байт) 0xaf, (байт) 0x92, (байт) 0xbb, (байт) 0xdd, (байт) 0xbc, 0x7f, 0x11, (байт) 0xd9, 0x5c, 0x41, 0x1f, 0x10, 0x5a, (байт) 0xd8, 0x0a, (байт) 0xc1, 0x31, (байт) 0x88, (байт) 0xa5, (байт) 0xcd, 0x7b, (байт) 0xbd, 0x2d, 0x74, (байт) 0xd0, 0x12, (байт) 0xb8, (байт) 0xe5, (байт) 0xb4, (байт) 0xb0, (байт) 0x89, 0x69, (байт) 0x97, 0x4a, 0x0c, (байт) 0x96, 0x77, 0x7e, 0x65, (байт) 0xb9, (байт) 0xf1, 0x09, (байт) 0xc5, 0x6e, (байт) 0xc6, (байт) 0x84, 0x18, (байт) 0xf0, 0x7d, (байт) 0xec, 0x3a, (байт) 0xdc, 0x4d, 0x20, 0x79, (байт) 0xee, 0x5f, 0x3e, (байт) 0xd7, (байт) 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) { возврат 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); возвращать B^(B<<2|B>>>30)^(B<<10|B>>>22)^(B<<18|B>>>14)^(B<<24|B>>>8); }
private int L2(int B) { возврат B ^ Rotl(B, 13) ^ Rotl(B, 23); возврат B^(B<<13|B>>>19)^(B<<23|B>>>9); }
void SMS4Crypt(байт[] Вход, байт[] Вывод, int[] rk) { Интеллект R, Mid, X0, X1, X2, X3; int[] x = новый int[4]; int[] tmp = новый int[4]; для (int i = 0; I < 4; i++) { tmp[0] = Вход[0 + 4 * i] & 0xff; tmp[1] = Вход[1 + 4 * i] и 0xff; tmp[2] = Вход[2 + 4 * i] & 0xff; tmp[3] = Вход[3 + 4 * i] & 0xff; x= tmp[0] << 24 | tmp[1] << 16 | tmp[2] << 8 | tmp[3]; x=(Вход[0+4*i]<<24| Вход[1+4*i]<<16| Input[2+4*i]<<8| Вход[3+4*i]); } для (r = 0; r < 32; r += 4) { середина = x[1] ^ x[2] ^ x[3] ^ rk[r + 0]; mid = ByteSub(mid); x[0] = x[0] ^ L1(середина); x4
середина = x[2] ^ x[3] ^ x[0] ^ rk[r + 1]; mid = ByteSub(mid); x[1] = x[1] ^ L1(середина); x5
середина = x[3] ^ x[0] ^ x[1] ^ rk[r + 2]; mid = ByteSub(mid); x[2] = x[2] ^ L1(середина); x6
середина = x[0] ^ x[1] ^ x[2] ^ rk[r + 3]; mid = ByteSub(mid); x[3] = x[3] ^ L1(середина); x7 }
Реверс для (int j = 0; j < 16; j += 4) { Выход[j] = (байт) (x[3 - j / 4] >>> 24 и 0xFF); Выход[j + 1] = (байт) (x[3 - j / 4] >>> 16 и 0xFF); Выход[j + 2] = (байт) (x[3 - j / 4] >>> 8 и 0xFF); Выход[j + 3] = (байт) (x[3 - j / 4] & 0xFF); } }
private void SMS4KeyExt(byte[] Key, int[] rk, int CryptFlag) { Интеллект Р, Мид; int[] x = новый int[4]; int[] tmp = новый int[4]; для (int i = 0; I < 4; i++) { tmp[0] = Ключ[0 + 4 * i] & 0xFF; tmp[1] = Ключ[1 + 4 * i] и 0xff; tmp[2] = Ключ[2 + 4 * i] и 0xff; tmp[3] = Ключ[3 + 4 * i] и 0xff; x= tmp[0] << 24 | tmp[1] << 16 | tmp[2] << 8 | tmp[3]; x=Ключ[0+4*i]<<24| Ключ[1+4*i]<<16| Ключ[2+4*i]<<8| Ключ[3+4*i]; } x[0] ^= 0xa3b1bac6; x[1] ^= 0x56aa3350; x[2] ^= 0x677d9197; x[3] ^= 0xb27022dc; для (r = 0; r < 32; r += 4) { середина = x[1] ^ x[2] ^ x[3] ^ CK[r + 0]; mid = ByteSub(mid); rk[r + 0] = x[0] ^= L2(середина); rk0=K4
середина = x[2] ^ x[3] ^ x[0] ^ CK[r + 1]; mid = ByteSub(mid); rk[r + 1] = x[1] ^= L2(середина); rk1=K5
середина = x[3] ^ x[0] ^ x[1] ^ CK[r + 2]; mid = ByteSub(mid); rk[r + 2] = x[2] ^= L2(середина); rk2=K6
середина = x[0] ^ x[1] ^ x[2] ^ CK[r + 3]; mid = ByteSub(mid); rk[r + 3] = x[3] ^= L2(середина); rk3=K7 }
Расшифровать порядок клавиши колеса: rk31, rk30,...,rk0 если (CryptFlag == РАСШИФРОВАТЬ) { для (r = 0; R < 16; r++) { mid = rk[r]; rk[r] = rk[31 - r]; rk[31 - r] = средний; } } }
публичный int sms4(byte[] in, int inLen, byte[] key, byte[] out, int CryptFlag) { int point = 0; int[] round_key = новый int[ROUND]; int[] round_key={0}; SMS4KeyExt(ключ, round_key, CryptFlag); байт[] input = новый байт[16]; байт[] выход = новый байт[16];
а (inLen >= БЛОК) { input = Arrays.copyOfRange(в, точка, точка + 16); output=Arrays.copyOfRange(выход, точка, точка+16); SMS4Crypt (вход, выход, round_key); System.arraycopy (выход, 0, выход, точка, БЛОК); inLen -= БЛОК; точка += БЛОК; }
возврат 0; }
}
Включённый внешний интерфейс:
На основе этого базового класса основные интерфейсы выглядят следующим образом:
частный статический байт[] encode16(byte[] plain, byte[] key); частный статический байт[] декодирование16(байт[] шифр, ключ byte[]); частный статический байт[] encode32(byte[] plain, byte[] key); частный статический байт[] декодирование32(байт[] шифр, ключ byte[]); публичный статический байт[] encodeSMS4(байт[] обычный, ключ byte[]); публичный статический байт[] декодирует SMS4(байт[] шифр, ключ byte[]); публичный статический декод строк SMS4toString(byte[] шифр, ключ byte[]);
encode16(байт[], байт[]) — это интерфейс для шифрования 16-битных открытых и 16-битных ключей; Частный статический байт[] декодирование16(байт[] шифр, ключ байт[]): — интерфейс для расшифровки 16-битного и 16-битного ключа; Private static byte[] encode32(byte[] plain, byte[] key): Это интерфейс, который шифрует 32-битный открытый и 16-битный ключи. Частный статический байт[] декодирование32(байт[] шифр, ключ байт[]): Это интерфейс для расшифровки 32-битного шифротекста и 16-битных ключей. публичный статический байт[] encodeSMS4(byte[] plain, byte[] ключ): Это интерфейс, который шифрует открытый текст и 16-битные ключи с неограниченным количеством байт. public static byte[] decodeSMS4(byte[] шифр, ключ byte[]): Это интерфейс для расшифровки шифротекста и 16-битных ключей с неограниченным количеством байт. публичный статический Строковый декодSMS4toString(byte[] шифр, ключ byte[]): Это интерфейс для расшифровки неограниченного количества байт шифротекста и 16-битных ключей. Код метода интерфейса:
публичный статический байт[] encodeSMS4(String plaintext, byte[] key) { если (открытый текст == null || plaintext.equals()) { возврат нуля; } для (int i = plaintext.getBytes().length % 16; Мне < 16; i++) { открытый текст += ''; }
возврат SMS4.encodeSMS4(plaintext.getBytes(), ключ); }
/** * Шифрование SMS4 с неограниченной длиной открытого текста * * @param открытый текст * @param тональность * @return */ публичный статический байт[] encodeSMS4(байт[] открытый текст, ключ byte[] { byte[] шифротекст = новый байт[plaintext.length];
int k = 0; int plainLen = plaintext.length; в то время как (k + 16 <= plainLen) { byte[] cellPlain = новый байт[16]; для (int i = 0; Мне < 16; i++) { cellPlain= открытый текст[k + i]; } byte[] cellCipher = encode16(cellPlain, key); для (int i = 0; i < cellCipher.length; i++) { ciphertext[k + i] = cellCipher; }
k += 16; }
возврат шифротекста; }
/** * Расшифровка SMS4 без ограничения по длине открытого текста * * @param шифротекст * @param тональность * @return */ публичный статический байт[] decodeSMS4(байт[] шифротекст, ключ byte[] { byte[] plaintext = новый байт[ciphertext.length];
int k = 0; int cipherLen = ciphertext.length; в то время как (k + 16 <= cipherLen) { byte[] cellCipher = новый байт[16]; для (int i = 0; Мне < 16; i++) { cellCipher= шифротекст[k + i]; } byte[] cellPlain = decode16(cellCipher, ключ); для (int i = 0; i < cellPlain.length; i++) { открытый текст[k + i] = cellPlain; }
k += 16; }
вернуть открытый текст; }
/** * Расшифровать для получения строк открытого текста * @param шифротекст * @param тональность * @return */ публичный статический String decodeSMS4toString(byte[] шифротекст, ключ byte[] byte[] plaintext = новый байт[ciphertext.length]; открытый текст = декодировать SMS4 (шифротекст, ключ); вернуть новую строку (открытый текст); }
/** * Шифруется только 16-битный открытый текст * * @param открытый текст * @param тональность * @return */ Частный статический байт[] encode16(byte[] открытый текст, ключ byte[] { byte[] шифр = новый байт[16]; SMS4 sm4 = новый SMS4(); sm4.sms4 (открытый текст, 16, ключ, шифр, ШИФРОВАНИЕ);
возвратный шифр; }
/** * Расшифровывается только 16-битный шифротекст * * @param открытый текст * @param тональность * @return */ Частный статический байт[] декодирование16(байт[] шифротекст, ключ byte[] { byte[] plain = новый байт[16]; SMS4 sm4 = новый SMS4(); sm4.sms4 (шифротекст, 16, ключ, простой, РАСШИФРОВАН);
возврат на равнину; } Я не буду вводить только 32-битное открытое шифрование, которое очень похоже на метод только 16-битного открытого текста.
Базовый алгоритм шифрования и расшифровки без ограничения длины открытого текста основан на этой основе шифрования и расшифровки всего 16 бит. Для открытого текста больше 16 бит здесь используется шифрование пакетов. Если вы столкнётесь с открытым текстом, например 30 бит, которые нельзя делить на 16, один из способов заполнить его — довести до того, чтобы он делился на 16. В принципе, только наименьшее число можно разделить на 16, конечно, если вы довольны, неважно, увеличите ли вы его, ведь это завершающий символ.
Шифрование пакетов — это шифрование каждого 16-битного открытого текста один раз, а затем сборка зашифрованного 16-битного шифротекста в новый шифротекст. В процессе расшифровки он также делится на одну 16-битную часть, после чего несколько из этих расшифрованных открытых текстов собираются в новый открытый текст.
Демонстрация использования:
Ключ byte[] key = { 0x01, 0x23, 0x45, 0x67, (байт) 0x89, (байт) 0xab, (байт) 0xcd, (байт) 0xef, (байт) 0xfe, (байт) 0xdc, (байт) 0xba, (байт) 0x98, 0x76, 0x54, 0x32, 0x10 };
String newString = Кодирование, привет!; Открытый текст
byte[] enOut = SMS4.encodeSMS4(newString, key); если (enOut == null) { возвращать; }
System.out.println(результат шифрования:); printBit(enOut);
byte[] deOut = SMS4.decodeSMS4(enOut, ключ); System.out.println( результат расшифровки (возвращаемый байт[]) :); printBit(deOut);
String deOutStr = SMS4.decodeSMS4toString(enOut, key); System.out.println( Расшифровать результат (вернуть строку): + deOutStr); |