Въведение в SMS4:
Този алгоритъм е алгоритъм за групиране. Алгоритъмът има дължина на пакета от 128 бита и дължина на ключа 128 бита, което е 16 байта. И алгоритъмът за криптиране, и алгоритъмът за разширяване на ключа приемат структура на нелинейна итерация от 32 рунда. Алгоритъмът за декриптиране има същата структура като алгоритъма за криптиране, с изключение на това, че редът на използване на кръглия ключ е обърнат, а ключът за колелото за декриптиране е обратният ред на ключа за криптиращото колело. Във всички базови класове на SMS4 ще видите, че основните функции на криптиране и декриптиране са еднакви, но е необходим int-тип флаг бит, за да се определи дали е криптиран или декриптиран.
Основи на алгоритъма за криптиране на SMS4:
публичен клас SMS4 {
private static final int ENCRYPT = 1; частен статичен финал int DECRYPT = 0; публичен статичен финален интелект ROUND = 32; частен статичен финален int BLOCK = 16;
private byte[] 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(byte[] Вход, байт[] Изход, 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| Вход[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
mid = 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
mid = 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) { Output[j] = (байт) (x[3 - j / 4] >>> 24 & 0xFF); Output[j + 1] = (байт) (x[3 - j / 4] >>> 16 & 0xFF); Изход[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] = Key[0 + 4 * i] & 0xFF; tmp[1] = Key[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| 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
mid = x[2] ^ x[3] ^ x[0] ^ CK[r + 1]; mid = ByteSub(mid); rk[r + 1] = x[1] ^= L2(среда); rk1=K5
mid = 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++) { mid = rk[r]; rk[r] = rk[31 - r]; RK[31 - R] = Мид; } } }
public int sms4(byte[] in, int inLen, byte[] key, byte[] out, int CryptFlag) { int точка = 0; int[] round_key = нов int[ROUND]; int[] round_key={0}; SMS4KeyExt(ключ, round_key, CryptFlag); байт[] вход = нов байт[16]; байт[] изход = нов байт[16];
докато (inLen >= БЛОК) { input = Arrays.copyOfRange(in, 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(байт[] шифър, ключ байт[]); публичен статичен байт[] encodeSMS4(byte[] обикновен, byte[] ключ); публичен статичен байт[] декодира SMS4(байт[] шифър, ключ байт[]); публичен статичен String декодиране SMS4toString(байт[] шифър, байт[] ключ);
encode16(байт[], байт[]) е интерфейс за криптиране на 16-битов открит текст и 16-битови ключове; Частен статичен байт[] декодиране16(байт[] шифър, байт[] ключ): е интерфейс за декриптиране на 16-битов 16-битов шифротекст и 16-битов ключ; Private static byte[] encode32(byte[] plain, byte[] key): Това е интерфейс, който криптира 32-битов открит текст и 16-битови ключове. Частен статичен байт[] декодиране32(байт[] шифър, байт[] ключ): Това е интерфейс за декриптиране на 32-битов шифротекст и 16-битови ключове. публичен статичен байт[] encodeSMS4(байт[] обикновен, байт[] ключ): Това е интерфейс, който криптира открит текст и 16-битови ключове с неограничен брой байтове. публичен статичен байт[] декодиране SMS4(байт[] шифър, байт[] ключ): Това е интерфейс за декриптиране на шифротекст и 16-битови ключове с неограничен брой байтове. публичен статичен String decodeSMS4toString(byte[] шифър, byte[] ключ): Това е интерфейс за декриптиране на неограничени байтове шифротекст и 16-битови ключове. Код на метода на интерфейса:
публичен статичен байт[] encodeSMS4(Низов открит текст, байт[] ключ) { ако (plaintext == null || plaintext.equals()) { return null; } за (int i = plaintext.getBytes().length % 16; < на 16; i++) { открит текст += ''; }
връща SMS4.encodeSMS4(plaintext.getBytes(), ключ); }
/** * SMS4 криптиране с неограничена дължина на открития текст * * @param открит текст * @param тоналност * @return */ публичен статичен байт[] encodeSMS4(байт[] открит текст, байт[] ключ) { byte[] ciphertext = нов байт[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[] 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++) { plaintext[k + i] = cellPlain; }
k += 16; }
върни открит текст; }
/** * Декриптиране за получаване на низове от открит текст * @param шифротекст * @param тоналност * @return */ публичен статичен String decodeSMS4toString(byte[] ciphertext, byte[] key) { byte[] plaintext = нов байт[ciphertext.length]; открит текст = декодиране SMS4 (шифротекст, ключ); връщане на нов String (открит текст); }
/** * Криптиран е само 16-битов открит текст * * @param открит текст * @param тоналност * @return */ Частен статичен байт[] encode16(byte[] plaintext, byte[] key) { byte[] cipher = нов байт[16]; SMS4 sm4 = нов SMS4(); sm4.sms4 (открит текст, 16, ключ, шифр, ENCRYPT);
шифър за връщане; }
/** * Само 16-битов шифротекст се декриптира * * @param открит текст * @param тоналност * @return */ Частен статичен байт[] декодиране16(байт[] шифротекст, ключ байт[] { байт[] plain = нов байт[16]; SMS4 sm4 = нов SMS4(); sm4.sms4(шифротекст, 16, ключ, обикновен, ДЕКРИПТ);
връщане на равнина; } Няма да въвеждам само 32-битово криптиране на открит текст, което е много подобно на метода с само 16-битов открит текст.
Основният алгоритъм за криптиране и декриптиране без ограничаване на дължината на открития текст се основава на криптиране и декриптиране само на 16 бита. За открит текст по-голям от 16 бита тук се използва пакетно криптиране. Ако срещнеш открит текст като 30 бита, които не могат да се делят на 16, начинът да го запълниш е да го компенсираш докато стане делимо на 16. По принцип само най-малкото число може да се дели на 16, разбира се, ако сте доволни, няма значение дали го направите по-голямо, защото това е символът за затваряне.
Пакетното криптиране означава да се криптира всеки 16-битов открит текст веднъж и след това криптираният 16-битов шифротекст да се сглоби отново в нов шифротекст. В процеса на декриптиране тя също се разделя на една 16-битова част, след което няколко от тези декриптирани открити текстове се сглобяват отново в нов открит текст.
Демонстрация на употреба:
Ключ byte[] ключ = { 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( резултат от декриптиране (return byte[]) :); printBit(deOut);
String deOutStr = SMS4.decodeSMS4toString(enOut, key); System.out.println( Декриптирайте резултата (връщане на низ): + deOutStr); |