Úvod k SMS4:
Tento algoritmus je zoskupovací algoritmus. Algoritmus má dĺžku paketu 128 bitov a dĺžku kľúča 128 bitov, čo je 16 bajtov. Šifrovací algoritmus aj algoritmus rozširovania kľúčov používajú 32-kolovú nelineárnu iteráciu. Dešifrovací algoritmus má rovnakú štruktúru ako šifrovací algoritmus, s tým rozdielom, že poradie použitia kľúča kola je obrátené a kľúč koliesa na dešifrovanie je v opačnom poradí kľúča na šifrovacie koliesko. Vo všetkých základných triedach SMS4 uvidíte, že základné funkcie šifrovania a dešifrovania sú rovnaké, ale na určenie, či ide o šifrovanie alebo dešifrovanie, je potrebný bit int-typu flagu.
Základy šifrovacieho algoritmu SMS4:
verejná trieda SMS4 {
súkromný statický konečný int ENCRYPT = 1; súkromný statický finálny int DECRYPT = 0; verejné statické finále int KOLO = 32; súkromný statický finálny int BLOCK = 16;
súkromný bajt[] 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 };
súkromný 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 };
súkromný int Rotl(int x, int y) { vrátiť 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); }
súkromný 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 = nový int[4]; int[] tmp = nový int[4]; pre (int i = 0; Mám < 4; i++) { tmp[0] = Vstup[0 + 4 * i] & 0xff; tmp[1] = Vstup[1 + 4 * i] & 0xff; tmp[2] = Vstup[2 + 4 * i] & 0xff; tmp[3] = Vstup[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| vstup[3+4*i]); } pre (r = 0; r < 32; r += 4) { stred = x[1] ^ x[2] ^ x[3] ^ rk[r + 0]; mid = ByteSub(mid); x[0] = x[0] ^ L1(stred); x4
stred = x[2] ^ x[3] ^ x[0] ^ rk[r + 1]; mid = ByteSub(mid); x[1] = x[1] ^ L1(stred); x5
stred = x[3] ^ x[0] ^ x[1] ^ rk[r + 2]; mid = ByteSub(mid); x[2] = x[2] ^ L1(stred); x6
stred = x[0] ^ x[1] ^ x[2] ^ rk[r + 3]; mid = ByteSub(mid); x[3] = x[3] ^ L1(stred); x7 }
Reverz pre (int j = 0; j < 16; j += 4) { Výstup[j] = (bajt) (x[3 - j / 4] >>> 24 & 0xFF); Výstup[j + 1] = (bajt) (x[3 - j / 4] >>> 16 & 0xFF); Výstup[j + 2] = (bajt) (x[3 - j / 4] >>> 8 & 0xFF); Výstup[j + 3] = (bajt) (x[3 - j / 4] & 0xFF); } }
private void SMS4KeyExt(byte[] Key, int[] rk, int CryptFlag) { int r, mid; int[] x = nový int[4]; int[] tmp = nový int[4]; pre (int i = 0; Mám < 4; i++) { tmp[0] = Key[0 + 4 * i] & 0xFF; tmp[1] = Key[1 + 4 * i] & 0xff; tmp[2] = Key[2 + 4 * i] & 0xff; tmp[3] = Kľúč[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| Kľúč[3+4*i]; } x[0] ^= 0xa3b1bac6; x[1] ^= 0x56aa3350; x[2] ^= 0x677d9197; x[3] ^= 0xb27022dc; pre (r = 0; r < 32; r += 4) { stred = x[1] ^ x[2] ^ x[3] ^ CK[r + 0]; mid = ByteSub(mid); rk[r + 0] = x[0] ^= L2(stred); rk0=K4
stred = x[2] ^ x[3] ^ x[0] ^ CK[r + 1]; mid = ByteSub(mid); rk[r + 1] = x[1] ^= L2(stred); rk1=K5
stred = x[3] ^ x[0] ^ x[1] ^ CK[r + 2]; mid = ByteSub(mid); rk[r + 2] = x[2] ^= L2(stred); rk2=K6
stred = x[0] ^ x[1] ^ x[2] ^ CK[r + 3]; mid = ByteSub(mid); rk[r + 3] = x[3] ^= L2(stred); rk3=K7 }
Dešifrovanie poradia kľúča kolieskom: rk31, rk30,...,rk0 ak (CryptFlag == DECRYPT) { pre (r = 0; r < 16; r++) { stred = rk[r]; rk[r] = rk[31 - r]; rk[31 - R] = stred; } } }
public int sms4(byte[] in, int inLen, byte[] key, byte[] out, int CryptFlag) { int bod = 0; int[] round_key = nový int[ROUND]; int[] round_key={0}; SMS4KeyExt(key, round_key, CryptFlag); bajt[] vstup = nový bajt[16]; bajt[] output = nový bajt[16];
zatiaľ čo (inLen >= BLOCK) { input = Arrays.copyOfRange(in, point, point + 16); output=Arrays.copyOfRange(out, point, point+16); SMS4Crypt (vstup, výstup, round_key); System.arraycopy(output, 0, out, point, BLOCK); inLen -= BLOK; bod += BLOK; }
return 0; }
}
Balené externé rozhranie:
Na základe tejto základnej triedy sú hlavné rozhrania nasledovné:
súkromný statický bajt[] encode16(byte[] plain, bajt[] kľúč); súkromný statický bajt[] decode16(byte[] šifra, bajt[] kľúč); súkromný statický bajt[] encode32(byte[] plain, bajt[] kľúč); súkromný statický bajt[] decode32(bajt[] šifra, bajt[] kľúč); verejný statický bajt[] enkódovať SMS4(bajt[] obyčajný, bajt[] kľúč); verejný statický bajt[] dekódovať SMS4(bajt[] šifra, bajt[] kľúč); public static String dekódovať SMS4toString(byte[] šifra, bajt[] kľúč);
encode16(byte[], byte[]) je rozhranie na šifrovanie pre 16-bitový otvorený text a 16-bitové kľúče; súkromný statický bajt[] decode16(byte[] šifra, bajt[] kľúč): je rozhranie na dešifrovanie 16-bitového šifrovaného textu a 16-bitového kľúča; súkromný statický bajt[] encode32(byte[] plain, bajt[] kľúč): Toto je rozhranie, ktoré šifruje 32-bitový otvorený text a 16-bitové kľúče. súkromný statický bajt[] decode32(byte[] šifra, bajt[] kľúč): Toto je rozhranie na dešifrovanie 32-bitového šifrovaného textu a 16-bitových kľúčov. public static byte[] encodeSMS4(byte[] plain, byte[] key): Toto je rozhranie, ktoré šifruje otvorený text a 16-bitové kľúče s neobmedzeným počtom bajtov. public static byte[] decodeSMS4(byte[] cipher, byte[] key): Toto je rozhranie na dešifrovanie šifrovaného textu a 16-bitových kľúčov s neobmedzeným počtom bajtov. public static String decodeSMS4toString(byte[] cipher, byte[] key): Toto je rozhranie na dešifrovanie neobmedzeného počtu bajtov šifrovaného textu a 16-bitových kľúčov. Kód metódy rozhrania:
public static byte[] encodeSMS4(String plaintext, byte[] key) { if (plaintext == null || plaintext.equals()) { return null; } for (int i = plaintext.getBytes().length % 16; Mám < 16; i++) { otvorený text += ''; }
return SMS4.encodeSMS4(plaintext.getBytes(), kľúč); }
/** * Šifrovanie SMS4 s neobmedzenou dĺžkou otvoreného textu * * @param otvorený text * @param kľúč * @return */ verejný statický bajt[] enkódovať SMS4(byte[] otvorený text, bajt[] kľúč) { bajt[] šifrovaný text = nový bajt[plaintext.length];
int k = 0; int plainLen = otvorený text.dĺžka; zatiaľ čo (k + 16 <= plainLen) { bajt[] cellPlain = nový bajt[16]; pre (int i = 0; Mám < 16; i++) { cellPlain= otvorený text[k + i]; } byte[] cellCipher = encode16(cellPlain, key); pre (int i = 0; i < cellCipher.length; i++) { šifrovaný text[k + i] = cellCipher; }
k += 16; }
vrátiť šifrovaný text; }
/** * Dešifrovanie SMS4 bez obmedzenia dĺžky otvoreného textu * * @param šifrovaný text * @param kľúč * @return */ verejný statický bajt[] dekódovať SMS4(bajt[] šifrovaný text, bajt[] kľúč) { bajt[] otvorený text = nový bajt[cyfertext.dĺžka];
int k = 0; int cipherLen = šifrovaný text.length; zatiaľ čo (k + 16 <= cipherLen) { byte[] cellCipher = nový bajt[16]; pre (int i = 0; Mám < 16; i++) { cellCipher= šifrovaný text[k + i]; } byte[] cellPlain = decode16(cellCipher, key); pre (int i = 0; i < bunkaPlain.dĺžka; i++) { otvorený text[k + i] = cellPlain; }
k += 16; }
vrátiť otvorený text; }
/** * Dešifrovanie na získanie reťazcov otvoreného textu * @param šifrovaný text * @param kľúč * @return */ public static String dekódovať SMS4toString(byte[] šifrovaný text, bajt[] kľúč) { bajt[] otvorený text = nový bajt[cyfertext.dĺžka]; otvorený text = dekódovať SMS4(šifrovaný text, kľúč); vrátiť nový reťazec (otvorený text); }
/** * Iba 16-bitový otvorený text je šifrovaný * * @param otvorený text * @param kľúč * @return */ Súkromný statický bajt[] encode16(byte[] otvorený text, bajt[] kľúč) { bajt[] šifra = nový bajt[16]; SMS4 sm4 = nový SMS4(); sm4.sms4(otvorený text, 16, kľúč, šifra, ENCRYPT);
return šifra; }
/** * Dešifrovaný je iba 16-bitový šifrovaný text * * @param otvorený text * @param kľúč * @return */ súkromný statický bajt[] decode16(byte[] šifrovaný text, bajt[] kľúč) { bajt[] plain = nový bajt[16]; SMS4 sm4 = nový SMS4(); sm4.sms4 (šifrovaný text, 16, kľúč, čistý, DECRYPT);
vráť hladko; } Nebudem tu predstavovať len 32-bitové šifrovanie otvoreného textu, ktoré je veľmi podobné metóde iba 16-bitového otvoreného textu.
Základný algoritmus šifrovania a dešifrovania bez obmedzenia dĺžky otvoreného textu je založený na tomto princípe šifrovania a dešifrovania iba 16 bitov. Pre otvorený text väčší ako 16 bitov sa tu používa šifrovanie paketov. Ak narazíte na otvorený text ako 30 bitov, ktorý sa nedá deliť 16, spôsob, ako ho zaplniť, je vyplniť ho tak, že bude deliteľný 16. V princípe sa dá deliť len najmenšie číslo 16, samozrejme, ak ste spokojní, nezáleží na tom, či ho zväčšíte, pretože je to záverečný symbol.
Paketové šifrovanie spočíva v jednom zašifrovaní každého 16-bitového otvoreného textu a následnom zložení zašifrovaného 16-bitového šifrovaného textu do nového šifrovaného textu. Pri dešifrovaní sa tiež rozdelí na jeden 16-bitový kus a potom sa niekoľko z týchto dešifrovaných otvorených textov znovu poskladá do nového otvoreného textu.
Demonštrácia používania:
Kľúč bajt[] kľúč = { 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 = Kódovanie, ahoj!; Neobyčajný text
byte[] enOut = SMS4.encodeSMS4(newString, key); ak (enOut == null) { vrátiť; }
System.out.println(výsledok šifrovania:); printBit(enOut);
bajt[] deOut = SMS4.dekódovať SMS4(enOut, kľúč); System.out.println( výsledok dešifrovania (return byte[]) :); printBit(deOut);
String deOutStr = SMS4.decodeSMS4toString(enOut, key); System.out.println( Dešifrovať výsledok (vrátiť reťazec): + deOutStr); |