SMS4-introduktion:
Denna algoritm är en grupperingsalgoritm. Algoritmen har en paketlängd på 128 bitar och en nyckelstorlek på 128 bitar, vilket är 16 byte. Både krypteringsalgoritmen och nyckelexpansionsalgoritmen använder en 32-rundors icke-linjär iterationsstruktur. Dekrypteringsalgoritmen har samma struktur som krypteringsalgoritmen, förutom att ordningen för rundnyckelns användning är omvänd, och dekrypteringshjulnyckeln är den omvända ordningen av krypteringshjulnyckeln. I alla basklasser av SMS4 kommer du att se att basfunktionerna kryptering och dekryptering är desamma, men en int-typ flaggbit behövs för att avgöra om den är krypterad eller dekrypterad.
Grundläggande för SMS4-krypteringsalgoritmer:
public class SMS4 {
privat statisk final int ENCRYPT = 1; privat statisk slutint DECRYPT = 0; offentlig statisk final INT RUNDA = 32; privat statisk slutgiltig int BLOCK = 16;
privat byte[] Sbox = { (byte) 0xd6, (byte) 0x90, (byte) 0xe9, (byte) 0xfe, (byte) 0xcc, (byte) 0xe1, 0x3d, (byte) 0xb7, 0x16, (byte) 0xb6, 0x14, (byte) 0xc2, 0x28, (byte) 0xfb, 0x2c, 0x05, 0x2b, 0x67, (byte) 0x9a, 0x76, 0x2a, (byte) 0xbe, 0x04, (byte) 0xc3, (byte) 0xaa, 0x44, 0x13, 0x26, 0x49, (byte) 0x86, 0x06, (byte) 0x99, (byte) 0x9c, 0x42, 0x50, (byte) 0xf4, (byte) 0x91, (byte) 0xef, (byte) 0x98, 0x7a, 0x33, 0x54, 0x0b, 0x43, (byte) 0xed, (byte) 0xcf, (byte) 0xac, 0x62, (byte) 0xe4, (byte) 0xb3, 0x1c, (byte) 0xa9, (byte) 0xc9, 0x08, (byte) 0xe8, (byte) 0x95, (byte) 0x80, (byte) 0xdf, (byte) 0x94, (byte) 0xfa, 0x75, (byte) 0x8f, 0x3f, (byte) 0xa6, 0x47, 0x07, (byte) 0xa7, (byte) 0xfc, (byte) 0xf3, 0x73, 0x17, (byte) 0xba, (byte) 0x83, 0x59, 0x3c, 0x19, (byte) 0xe6, (byte) 0x85, 0x4f, (byte) 0xa8, 0x68, 0x6b, (byte) 0x81, (byte) 0xb2, 0x71, 0x64, (byte) 0xda, (byte) 0x8b, (byte) 0xf8, (byte) 0xeb, 0x0f, 0x4b, 0x70, 0x56, (byte) 0x9d, 0x35, 0x1e, 0x24, 0x0e, 0x5e, 0x63, 0x58, (byte) 0xd1, (byte) 0xa2, 0x25, 0x22, 0x7c, 0x3b, 0x01, 0x21, 0x78, (byte) 0x87, (byte) 0xd4, 0x00, 0x46, 0x57, (byte) 0x9f, (byte) 0xd3, 0x27, 0x52, 0x4c, 0x36, 0x02, (byte) 0xe7, (byte) 0xa0, (byte) 0xc4, (byte) 0xc8, (byte) 0x9e, (byte) 0xea, (byte) 0xbf, (byte) 0x8a, (byte) 0xd2, 0x40, (byte) 0xc7, 0x38, (byte) 0xb5, (byte) 0xa3, (byte) 0xf7, (byte) 0xf2, (byte) 0xce, (byte) 0xf9, 0x61, 0x15, (byte) 0xa1, (byte) 0xe0, (byte) 0xae, 0x5d, (byte) 0xa4, (byte) 0x9b, 0x34, 0x1a, 0x55, (byte) 0xad, (byte) 0x93, 0x32, 0x30, (byte) 0xf5, (byte) 0x8c, (byte) 0xb1, (byte) 0xe3, 0x1d, (byte) 0xf6, (byte) 0xe2, 0x2e, (byte) 0x82, 0x66, (byte) 0xca, 0x60, (byte) 0xc0, 0x29, 0x23, (byte) 0xab, 0x0d, 0x53, 0x4e, 0x6f, (byte) 0xd5, (byte) 0xdb, 0x37, 0x45, (byte) 0xde, (byte) 0xfd, (byte) 0x8e, 0x2f, 0x03, (byte) 0xff, 0x6a, 0x72, 0x6d, 0x6c, 0x5b, 0x51, (byte) 0x8d, 0x1b, (byte) 0xaf, (byte) 0x92, (byte) 0xbb, (byte) 0xdd, (byte) 0xbc, 0x7f, 0x11, (byte) 0xd9, 0x5c, 0x41, 0x1f, 0x10, 0x5a, (byte) 0xd8, 0x0a, (byte) 0xc1, 0x31, (byte) 0x88, (byte) 0xa5, (byte) 0xcd, 0x7b, (byte) 0xbd, 0x2d, 0x74, (byte) 0xd0, 0x12, (byte) 0xb8, (byte) 0xe5, (byte) 0xb4, (byte) 0xb0, (byte) 0x89, 0x69, (byte) 0x97, 0x4a, 0x0c, (byte) 0x96, 0x77, 0x7e, 0x65, (byte) 0xb9, (byte) 0xf1, 0x09, (byte) 0xc5, 0x6e, (byte) 0xc6, (byte) 0x84, 0x18, (byte) 0xf0, 0x7d, (byte) 0xec, 0x3a, (byte) 0xdc, 0x4d, 0x20, 0x79, (byte) 0xee, 0x5f, 0x3e, (byte) 0xd7, (byte) 0xcb, 0x39, 0x48 };
privat 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 };
privat int Rotl(int x, int y) { returnera x << y | x >>> (32 - y); }
private int ByteSub(int A) { återkomma (Sbox [A >>> 24 & 0xFF] & 0xFF) << 24 | (Sbox[A >>> 16 & 0xFF] & 0xFF) << 16 | (Sbox [A >>> 8 & 0xFF] & 0xFF) << 8 | (Sbox[A & 0xFF] & 0xFF); }
privat int L1(int B) { retur B ^ Rotl(B, 2) ^ Rotl(B, 10) ^ Rotl(B, 18) ^ Rotl(B, 24); returnera B^(B<<2|B>>>30)^(B<<10|B>>>22)^(B<<18|B>>>14)^(B<<24|B>>>8); }
privat int L2(int B) { retur B ^ Rotl(B, 13) ^ Rotl(B, 23); returnera 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 = ny int[4]; int[] tmp = ny int[4]; för (int i = 0; Jag < 4; i++) { tmp[0] = Input[0 + 4 * i] & 0xff; tmp[1] = Inmatning[1 + 4 * i] & 0xff; tmp[2] = Input[2 + 4 * i] & 0xff; tmp[3] = Ingång[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| Input[3+4*i]); } för (r = 0; r < 32; r += 4) { mid = x[1] ^ x[2] ^ x[3] ^ rk[r + 0]; mid = ByteSub(mid); x[0] = x[0] ^ L1(mitten); x4
mid = x[2] ^ x[3] ^ x[0] ^ rk[r + 1]; mid = ByteSub(mid); x[1] = x[1] ^ L1(mitten); x5
mid = x[3] ^ x[0] ^ x[1] ^ rk[r + 2]; mid = ByteSub(mid); x[2] = x[2] ^ L1(mitten); x6
mid = x[0] ^ x[1] ^ x[2] ^ rk[r + 3]; mid = ByteSub(mid); x[3] = x[3] ^ L1(mitten); x7 }
Baksidan för (int j = 0; j < 16; j += 4) { Output[j] = (byte) (x[3 - j / 4] >>> 24 & 0xFF); Output[j + 1] = (byte) (x[3 - j / 4] >>> 16 & 0xFF); Output[j + 2] = (byte) (x[3 - j / 4] >>> 8 & 0xFF); Output[j + 3] = (byte) (x[3 - j / 4] & 0xFF); } }
private void SMS4KeyExt(byte[] Key, int[] rk, int CryptFlag) { Int R, Mid; int[] x = ny int[4]; int[] tmp = ny int[4]; för (int i = 0; Jag < 4; i++) { tmp[0] = Nyckel[0 + 4 * i] & 0xFF; tmp[1] = Nyckel[1 + 4 * i] & 0xff; tmp[2] = Nyckel[2 + 4 * i] & 0xff; tmp[3] = Nyckel[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; för (r = 0; r < 32; r += 4) { mid = x[1] ^ x[2] ^ x[3] ^ CK[r + 0]; mid = ByteSub(mid); rk[r + 0] = x[0] ^= L2(mitt); rk0=K4
mid = x[2] ^ x[3] ^ x[0] ^ CK[r + 1]; mid = ByteSub(mid); rk[r + 1] = x[1] ^= L2(mitt); rk1=K5
mid = x[3] ^ x[0] ^ x[1] ^ CK[r + 2]; mid = ByteSub(mid); rk[r + 2] = x[2] ^= L2(mitt); rk2=K6
mid = x[0] ^ x[1] ^ x[2] ^ CK[r + 3]; mid = ByteSub(mid); rk[r + 3] = x[3] ^= L2(mitten); rk3=K7 }
Dekryptera ordningen på hjulnyckeln: rk31, rk30,...,rk0 om (CryptFlag == DEKRYPTERA) { för (r = 0; r < 16; r++) { mid = rk[r]; rk[r] = rk[31 - r]; rk[31 - r] = mitten; } } }
public int sms4(byte[] in, int inLen, byte[] key, byte[] out, int CryptFlag) { int point = 0; int[] round_key = ny int[RUNDA]; int[] round_key={0}; SMS4KeyExt(nyckel, round_key, CryptFlag); byte[] input = ny byte[16]; byte[] output = ny byte[16];
medan (inLen >= BLOCK) { input = Arrays.copyOfRange(in, punkt, punkt + 16); output=Arrays.copyOfRange(ut, punkt, punkt+16); SMS4Crypt (inmatning, utmatning, round_key); System.arraycopy (utdata, 0, ut, punkt, BLOCK); inLen -= BLOCK; punkt += BLOCK; }
returnera 0; }
}
Paketerat externt gränssnitt:
Baserat på denna grundläggande klass är huvudgränssnitten följande:
privat statisk byte[] encode16(byte[] plain, byte[] nyckel); privat statisk byte[] decode16(byte[] chiffer, byte[] nyckel); privat statisk byte[] encode32(byte[] plain, byte[] nyckel); privat statisk byte[] decode32(byte[] chiffer, byte[] nyckel); publik statisk byte[] encodeSMS4(byte[] plain, byte[] nyckel); publik statisk byte[] dekodningSMS4(byte[] chiffer, byte[] nyckel); offentlig statisk strängavkodningSMS4toString(byte[] chiffer, byte[]-nyckel);
encode16(byte[], byte[]) är ett gränssnitt för kryptering av 16-bitars klartext och 16-bitars nycklar; privat statisk byte[] decode16(byte[] chiffer, byte[] nyckel): är ett gränssnitt för att dekryptera 16-bitars chiffertext och 16-bitars nyckel; privat statisk byte[] encode32(byte[] plain, byte[] key): Detta är ett gränssnitt som krypterar 32-bitars klartext och 16-bitars nycklar. privat statisk byte[] decode32(byte[] chiffer, byte[] nyckel): Detta är ett gränssnitt för att dekryptera 32-bitars chiffertext och 16-bitars nycklar. public static byte[] encodeSMS4(byte[] plain, byte[] key): Detta är ett gränssnitt som krypterar klartext och 16-bitars nycklar med ett obegränsat antal byte. public static byte[] decodeSMS4(byte[] chiffer, byte[] nyckel): Detta är ett gränssnitt för att dekryptera chiffertext och 16-bitars nycklar med ett obegränsat antal byte. offentlig statisk strängavkodningSMS4toString(byte[] chiffer, byte[] nyckel): Detta är ett gränssnitt för att dekryptera obegränsade byte chiffertext och 16-bitars nycklar. Gränssnittsmetodkod:
publik statisk byte[] encodeSMS4(Sträng klartext, byte[] nyckel) { om (klartext == null || klartext.equals()) { återvända null; } för (int i = klartext.getBytes().length % 16; Jag < 16; i++) { klartext += ''; }
returnera SMS4.encodeSMS4(plaintext.getBytes(), nyckel); }
/** * SMS4-kryptering med obegränsad klartextlängd * * @param klartext * @param nyckel * @return */ publik statisk byte[] encodeSMS4(byte[] klartext, byte[] nyckel) { byte[] chiffertext = ny byte[klartext.längd];
int k = 0; int plainLen = klartext.längd; medan (k + 16 <= plainLen) { byte[] cellPlain = ny byte[16]; för (int i = 0; Jag < 16; i++) { cellPlain= klartext[k + i]; } byte[] cellCipher = kod16(cellPlain, nyckel); för (int i = 0; i < cellCipher.length; i++) { ciphertext[k + i] = cellCipher; }
k += 16; }
returnera chiffertext; }
/** * SMS4-dekryptering utan begränsning av klartextlängd * * @param chiffertext * @param nyckel * @return */ publik statisk byte[] decodeSMS4(byte[] ciphertext, byte[] key) { byte[] klartext = ny byte[chiffertext.length];
int k = 0; int cipherLen = ciphertext.length; medan (k + 16 <= chifferLen) { byte[] cellCipher = ny byte[16]; för (int i = 0; Jag < 16; i++) { cellCipher= chiffertext[k + i]; } byte[] cellPlain = decode16(cellCipher, key); för (int i = 0; i < cellPlain.length; i++) { klartext[k + i] = cellPlain; }
k += 16; }
returnera klartext; }
/** * Dekryptera för att få klartextsträngar * @param chiffertext * @param nyckel * @return */ publik statisk String decodeSMS4toString(byte[] ciphertext, byte[] key) { byte[] klartext = ny byte[chiffertext.length]; klartext = dekoda SMS4 (chiffertext, nyckel); returnera ny sträng (klartext); }
/** * Endast 16-bitars klartext är krypterad * * @param klartext * @param nyckel * @return */ privat statisk byte[] encode16(byte[] klartext, byte[] nyckel) { byte[] chiffer = ny byte[16]; SMS4 sm4 = ny SMS4(); sm4.sms4 (klartext, 16, nyckel, chiffer, ENCRYPT);
returnera chiffer; }
/** * Endast 16-bitars chiffertext dekrypteras * * @param klartext * @param nyckel * @return */ privat statisk byte[] decode16(byte[] ciphertext, byte[] key) { byte[] plain = ny byte[16]; SMS4 sm4 = ny SMS4(); sm4.sms4 (ciphertext, 16, key, plain, DECRYPT);
återvänd rakt ut; } Jag kommer inte att införa endast 32-bitars klartextkryptering här, vilket är mycket likt metoden med endast 16-bitars klartext.
Den grundläggande algoritmen för kryptering och dekryptering utan att begränsa klartextens längd baseras på denna grund, där endast 16 bitar krypteras och dekrypteras. För klartext större än 16 bitar används paketkryptering här. Om du stöter på klartext som 30 bitar som inte kan delas med 16, är ett sätt att fylla på det att göra det så långt att det är delbart med 16. I princip kan bara det minsta talet delas med 16, men om du är nöjd spelar det ingen roll om du gör det större, eftersom det är avslutningssymbolen.
Paketkryptering innebär att varje 16-bitars klartext krypteras en gång och sedan sammanställs den krypterade 16-bitars chiffertexten till en ny chiffertext. I dekrypteringsprocessen delas den också upp i en enda 16-bitars del, och sedan återsätts flera av dessa dekrypterade klartexter till ny klartext.
Användningsdemonstration:
Nyckel byte[] nyckel = { 0x01, 0x23, 0x45, 0x67, (byte) 0x89, (byte) 0xab, (byte) 0xcd, (byte) 0xef, (byte) 0xfe, (byte) 0xdc, (byte) 0xba, (byte) 0x98, 0x76, 0x54, 0x32, 0x10 };
String newString = Kodning, hej!; Klartext
byte[] enOut = SMS4.encodeSMS4(newString, key); om (enOut == null) { återvända; }
System.out.println(krypteringsresultat:); printBit(enOut);
byte[] deOut = SMS4.decodeSMS4(enOut, key); System.out.println( dekrypteringsresultat (return byte[]) :); printBit(deOut);
String deOutStr = SMS4.decodeSMS4toString(enOut, key); System.out.println( Dekryptera resultatet (returnera sträng): + deOutStr); |