Úvod k SMS4:
Tento algoritmus je seskupovací algoritmus. Algoritmus má délku paketu 128 bitů a délku klíče 128 bitů, což je 16 bajtů. Jak šifrovací algoritmus, tak algoritmus rozšiřování klíče používají 32kolovou nelineární iterační strukturu. Dešifrovací algoritmus má stejnou strukturu jako šifrovací algoritmus, s tím rozdílem, že pořadí použití klíče kola je obrácené a klíč dešifrovacího kolečka je v opačném pořadí klíče šifrovacího kolečka. Ve všech základních třídách SMS4 uvidíte, že základní funkce šifrování a dešifrování jsou stejné, ale je potřeba bit int-typu pro určení, zda je šifrován nebo dešifrován.
Základy šifrovacího algoritmu SMS4:
veřejná třída SMS4 {
soukromý statický finální int ENCRYPT = 1; soukromý statický finální int DECRYPT = 0; veřejné statické finále int KOLO = 32; soukromý statický finální int BLOCK = 16;
soukromý 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, (byte) 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 };
soukromý 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) { vrátit 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); }
private 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]; pro (int i = 0; Jsem < 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]); } pro (r = 0; r < 32; r += 4) { střed = x[1] ^ x[2] ^ x[3] ^ rk[r + 0]; mid = ByteSub(mid); x[0] = x[0] ^ L1(střední); x4
střed = x[2] ^ x[3] ^ x[0] ^ rk[r + 1]; mid = ByteSub(mid); x[1] = x[1] ^ L1(střední); x5
střed = x[3] ^ x[0] ^ x[1] ^ rk[r + 2]; mid = ByteSub(mid); x[2] = x[2] ^ L1(střední); x6
střed = x[0] ^ x[1] ^ x[2] ^ rk[r + 3]; mid = ByteSub(mid); x[3] = x[3] ^ L1(střední); x7 }
Reverz pro (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]; pro (int i = 0; Jsem < 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] = Key[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| Key[3+4*i]; } x[0] ^= 0xa3b1bac6; x[1] ^= 0x56aa3350; x[2] ^= 0x677d9197; x[3] ^= 0xb27022dc; pro (r = 0; r < 32; r += 4) { střed = x[1] ^ x[2] ^ x[3] ^ CK[r + 0]; mid = ByteSub(mid); rk[r + 0] = x[0] ^= L2(střední); rk0=K4
mid = x[2] ^ x[3] ^ x[0] ^ CK[r + 1]; mid = ByteSub(mid); rk[r + 1] = x[1] ^= L2(střední); rk1=K5
střed = x[3] ^ x[0] ^ x[1] ^ CK[r + 2]; mid = ByteSub(mid); rk[r + 2] = x[2] ^= L2(střední); rk2=K6
mid = x[0] ^ x[1] ^ x[2] ^ CK[r + 3]; mid = ByteSub(mid); rk[r + 3] = x[3] ^= L2(střední); rk3=K7 }
Dešifrujte pořadí klíče kolečka: rk31, rk30,...,rk0 if (CryptFlag == DECRYPT) { pro (r = 0; r < 16; r++) { střed = rk[r]; rk[r] = rk[31 - r]; rk[31 - R] = střed; } } }
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); bajtem[] vstupem = nový bajt[16]; byte[] output = nový bajt[16];
while (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í rozhraní:
Na základě této základní třídy jsou hlavní rozhraní následující:
soukromý statický bajt[] encode16(byte[] plain, bajt[] klíč); soukromý statický bajt[] decode16(byte[] šifra, bajt[] klíč); soukromý statický bajt[] encode32(byte[] prostý, bajt[] klíč); soukromý statický bajt[] decode32(byte[] šifra, bajt[] klíč); veřejný statický bajt[] enkódovat SMS4(bajt[] prostý, bajt[] klíč); veřejný statický bajt[] dekódovat SMS4(bajt[] šifru, bajt[] klíč); veřejný statický řetězec dekódovat SMS4toString(byte[] šifra, bajt[] klíč);
encode16(byte[], byte[]) je rozhraní pro šifrování 16bitových otevřených a 16bitových klíčů; soukromý statický bajt[] decode16(byte[] šifra, bajt[] klíč): je rozhraní pro dešifrování 16bitového šifrovaného textu a 16bitového klíče; soukromý statický bajt[] encode32(byte[] prostý, bajt[] klíč): Toto je rozhraní, které šifruje 32bitový otevřený text a 16bitové klíče. soukromý statický bajt[] decode32(byte[] šifra, bajt[] klíč): Toto je rozhraní pro dešifrování 32bitového šifrovaného textu a 16bitových klíčů. veřejný statický bajt[] encodeSMS4(byte[] plain, bajt[] klíč): Toto je rozhraní, které šifruje otevřený text a 16bitové klíče s neomezeným počtem bajtů. public static byte[] decodeSMS4(byte[] cipher, byte[] key): Toto je rozhraní pro dešifrování šifrovaného textu a 16bitových klíčů s neomezeným počtem bajtů. public static String dekódovat SMS4toString(byte[] šifra, bajt[] klíč): Toto je rozhraní pro dešifrování neomezených bajtů šifrovaného textu a 16bitových klíčů. Kód metody rozhraní:
public static byte[] encodeSMS4(String plaintext, byte[] key) { if (plaintext == null || plaintext.equals()) { return null; } for (int i = plaintext.getBytes().length % 16; Je mi < 16; i++) { otevřený text += ''; }
return SMS4.encodeSMS4(plaintext.getBytes(), klíč); }
/** * Šifrování SMS4 s neomezenou délkou otevřeného textu * * @param otevřený text * @param klíč * @return */ veřejný statický bajt[] enkódovat SMS4(bajt[] otevřený text, bajt[] klíč) { bajt[] šifrovaný text = nový bajt[plaintext.length];
int k = 0; int plainLen = otevřený text.délka; zatímco (k + 16 <= plainLen) { byte[] cellPlain = nový byte[16]; pro (int i = 0; Je mi < 16; i++) { cellPlain= otevřený text[k + i]; } byte[] cellCipher = encode16(cellPlain, key); pro (int i = 0; i < cellCipher.length; i++) { šifrovaný text[k + i] = cellCipher; }
k += 16; }
vrátit šifrovaný text; }
/** * Dešifrování SMS4 bez omezení délky otevřeného textu * * @param šifrovaný text * @param klíč * @return */ veřejný statický bajt[] dekódovat SMS4(bajt[] šifrovaný text, bajt[] klíč) { byte[] otevřený text = nový bajt[ciphertext.length];
int k = 0; int cipherLen = šifrový text.length; zatímco (k + 16 <= cipherLen) { byte[] cellCipher = nový bajt[16]; pro (int i = 0; Je mi < 16; i++) { cellCipher= šifrovaný text[k + i]; } byte[] cellPlain = decode16(cellCipher, key); pro (int i = 0; i < buňkaPlain.délka; i++) { otevřený text[k + i] = buňka Plain; }
k += 16; }
vrátit otevřený text; }
/** * Dešifrovat pro získání řetězců otevřeného textu * @param šifrovaný text * @param klíč * @return */ public static String dekódovat SMS4toString(byte[] šifrovaný text, bajt[] klíč) { byte[] otevřený text = nový bajt[ciphertext.length]; otevřený text = dekódovat SMS4(šifrovaný text, klíč); vrátit nový řetězec (otevřený text); }
/** * Pouze 16bitový otevřený text je zašifrovaný * * @param otevřený text * @param klíč * @return */ Soukromý statický bajt[] encode16(byte[] otevřený text, bajt[] klíč) { bajt[] šifra = nový bajt[16]; SMS4 sm4 = nový SMS4(); sm4.sms4(otevřený text, 16, klíč, šifra, ENCRYPT);
return šifru; }
/** * Dešifrován je pouze 16bitový šifrovaný text * * @param otevřený text * @param klíč * @return */ Soukromý statický bajt[] decode16(byte[] šifrovaný text, bajt[] klíč) { bajt[] plain = nový byte[16]; SMS4 sm4 = nový SMS4(); sm4.sms4 (šifrovaný text, 16, klíč, čistý, DECRYPT);
Return plain; } Nebudu zde představovat pouze 32bitové šifrování otevřeného textu, které je velmi podobné metodě pouze 16bitového otevřeného textu.
Základní algoritmus pro šifrování a dešifrování bez omezení délky otevřeného textu je založen na tomto základu šifrování a dešifrování pouze 16 bitů. Pro otevřený text větší než 16 bitů se zde používá paketové šifrování. Pokud narazíte na otevřený text jako 30 bitů, který nelze dělit 16, jedním ze způsobů, jak ho zaplnit, je dělit ho tak, aby byl dělitelný 16. V zásadě lze dělit jen nejmenší číslo šestnácti, samozřejmě, pokud jste spokojení, nezáleží na tom, jestli ho zvětšíte, protože je to závěrečný symbol.
Paketové šifrování spočívá v jednom zašifrování každého 16bitového otevřeného textu a následném složení zašifrovaného 16bitového šifrovaného textu do nového šifrovaného textu. Při dešifrování je také rozdělen na jeden 16bitový kus a poté je několik těchto dešifrovaných otevřených textů znovu sestaveno do nového otevřeného textu.
Demonstrace použití:
Klíč bajt[] key = { 0x01, 0x23, 0x45, 0x67, (byte) 0x89, (byte) 0xab, (bajt) 0xcd, (bajt) 0xef, (bajt) 0xfe, (bajt) 0xdc, (bajt) 0xba, (bajt) 0x98, 0x76, 0x54, 0x32, 0x10 };
String newString = Kódování, ahoj!; Prostý text
byte[] enOut = SMS4.encodeSMS4(newString, key); if (enOut == null) { vrátit; }
System.out.println(výsledek šifrování:); printBit(enOut);
byte[] deOut = SMS4.decodeSMS4(enOut, klíč); System.out.println( výsledek dešifrování (return byte[]) :); printBit(deOut);
String deOutStr = SMS4.decodeSMS4toString(enOut, key); System.out.println( Dešifrujte výsledek (vrátit řetězec): + deOutStr); |