Вступ до SMS4:
Цей алгоритм є алгоритмом групування. Алгоритм має довжину пакета 128 біт, а довжина ключа — 128 біт, що становить 16 байт. І алгоритм шифрування, і алгоритм розширення ключа використовують структуру нелінійної ітерації з 32 раундами. Алгоритм дешифрування має ту ж структуру, що й алгоритм шифрування, за винятком того, що порядок використання ключа раунду змінюється, а ключ колеса розшифрування — це зворотний порядок ключа колеса шифрування. У всіх базових класах SMS4 ви побачите, що базові функції шифрування та дешифрування однакові, але для визначення шифрування чи розшифрування потрібен прапорецький біт типу int.
Основи алгоритму шифрування SMS4:
публічний клас SMS4 {
приватний статичний фінальний int ENCRYPT = 1; приватний статичний фінальний int DECRYPT = 0; публічний статичний фінальний інтелект РАУНД = 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 };
приватний 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) { повернення 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(byte[] Вхід, байт[] Вихід, int[] rk) { інтуїція R, середня, 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] = Input[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| Input[1+4*i]<<16| Input[2+4*i]<<8| Input[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); Output[j + 1] = (байт) (x[3 - j / 4] >>> 16 & 0xFF); Output[j + 2] = (байт) (x[3 - j / 4] >>> 8 & 0xFF); Output[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] = Key[1 + 4 * i] & 0xff; tmp[2] = Key[2 + 4 * i] & 0xff; tmp[3] = Key[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| Key[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; р < 16; r++) { середина = rk[r]; rk[r] = rk[31 - r]; rk[31 - r] = середній; } } }
public 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); байт[] вхід = новий байт[16]; байт[] вихід = новий байт[16];
тоді як (inLen >= БЛОК) { input = Arrays.copyOfRange(in, point, point + 16); output=Arrays.copyOfRange(out, point, point+16); SMS4Crypt(вхід, вихід, round_key); System.arraycopy (вихід, 0, вихід, точка, БЛОК); inLen -= БЛОК; точка += БЛОК; }
return 0; }
}
Упакований зовнішній інтерфейс:
На основі цього базового класу основні інтерфейси такі:
приватний статичний байт[] encode16(byte[] plain, byte[] key); приватний статичний байт[] декодування16(байт[] шифр, ключ byte[]); приватний статичний байт[] encode32(byte[] plain, byte[] key); приватний статичний байт[] декодування32(байт[] шифр, ключ byte[]); публічний статичний байт[] encodeSMS4(байт[] звичайний, ключ байт[]); публічний статичний байт[] декодування SMS4(байт[] шифр, ключ byte[]); публічний статичний рядковий декод, SMS4toString(байт[] шифр, байт[] ключ);
encode16(байт[], байт[]) — це інтерфейс для шифрування 16-бітного відкритого тексту та 16-бітних ключів; Приватний статичний байт[] декодування16(байт[] шифр, ключ байт[]): є інтерфейсом для розшифрування 16-бітного шифротексту та 16-бітного ключа; Приватний статичний байт[] encode32(byte[] plain, byte[] ключ): Це інтерфейс, який шифрує 32-бітний відкритий текст і 16-бітні ключі. Приватний статичний байт[] декодування32(байт[] шифр, ключ байт[]): Це інтерфейс для розшифрування 32-бітного шифротексту та 16-бітних ключів. публічний статичний байт[] encodeSMS4(byte[] plain, byte[] ключ): Це інтерфейс, який шифрує відкритий текст і 16-бітні ключі з необмеженою кількістю байтів. публічний статичний байт[] декодування SMS4(байт[] шифр, байт[] ключ): Це інтерфейс для дешифрування шифротексту та 16-бітних ключів з необмеженою кількістю байтів. публічний статичний рядковий декодSMS4toString(byte[] шифр, байт[] ключ): Це інтерфейс для дешифрування необмеженої кількості байтів шифротексту та 16-бітних ключів. Код методу інтерфейсу:
публічний статичний байт[] encodeSMS4(Рядковий відкритий текст, байт[] ключ) { якщо (відкритий текст == null || plaintext.equals()) { return null; } для (int i = plaintext.getBytes().довжина % 16; Мені < 16; i++) { відкритий текст += ''; }
повернути SMS4.encodeSMS4(plaintext.getBytes(), ключ); }
/** * Шифрування SMS4 з необмеженою довжиною відкритого тексту * * @param відкритий текст * @param тональність * @return */ публічний статичний байт[] encodeSMS4(байт[] відкритий текст, байт[] ключ) { байт[] шифротекст = новий байт[plaintext.length];
int k = 0; int plainLen = plaintext.length; тоді як (k + 16 <= plainLen) { байт[] 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 */ публічний статичний байт[] декодування SMS4(байт[] шифротекст, ключ byte[] { байт[] відкритий текст = новий байт[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 */ публічний статичний рядковий декодування SMS4toString(byte[] шифрований текст, ключ byte[] ) { байт[] відкритий текст = новий байт[ciphertext.length]; відкритий текст = декодування SMS4 (шифротекст, ключ); повернути новий рядок (відкритий текст); }
/** * Лише 16-бітний відкритий текст шифрується * * @param відкритий текст * @param тональність * @return */ Приватний статичний байт[] encode16(byte[] відкритий текст, ключ byte[] { байт[] шифр = новий байт[16]; SMS4 sm4 = новий SMS4(); sm4.sms4(відкритий текст, 16, ключ, шифр, ШИФРУВАННЯ);
шифр повернення; }
/** * Розшифровується лише 16-бітний шифротекст * * @param відкритий текст * @param тональність * @return */ Приватний статичний байт[] декодування16(байт[] шифротекст, ключ байт[] { байт[] простий = новий байт[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); |