Introduzione a SMS4:
Questo algoritmo è un algoritmo di raggruppamento. L'algoritmo ha una lunghezza del pacchetto di 128 bit e una lunghezza della chiave di 128 bit, cioè 16 byte. Sia l'algoritmo di cifratura che quello di espansione delle chiavi adottano una struttura di iterazione non lineare su 32 round. L'algoritmo di decrittazione ha la stessa struttura dell'algoritmo di cifratura, tranne per il fatto che l'ordine di utilizzo della chiave a round è invertito, e la chiave della ruota di decrittazione è l'ordine inverso della chiave della ruota di crittografia. In tutte le classi base di SMS4, vedrai che le funzioni base di crittografia e decrittazione sono le stesse, ma è necessario un bit di flag di tipo int per determinare se è criptato o decifrato.
Nozioni di base sull'algoritmo di crittografia SMS4:
classe pubblica SMS4 {
privato static final int ENCRYPT = 1; privato statico finale int DECRYPT = 0; pubblico statico finale int ROUND = 32; blocco privato statico finale, int BLOCK = 16;
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 };
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) { ritorna x << y | x >>> (32 - y); }
private int ByteSub(int A) { ritorno (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); ritorna 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); ritorno 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 = nuovo int[4]; int[] tmp = nuovo int[4]; per (int i = 0; Ho < 4; i++) { tmp[0] = Input[0 + 4 * i] & 0xff; tmp[1] = Input[1 + 4 * i] & 0xff; tmp[2] = Input[2 + 4 * i] & 0xff; tmp[3] = Input[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]); } per (r = 0; r < 32; r += 4) { mid = x[1] ^ x[2] ^ x[3] ^ rk[r + 0]; mid = ByteSub(mid); x[0] = x[0] ^ L1(medio); x4
mid = x[2] ^ x[3] ^ x[0] ^ rk[r + 1]; mid = ByteSub(mid); x[1] = x[1] ^ L1(medio); x5
mid = x[3] ^ x[0] ^ x[1] ^ rk[r + 2]; mid = ByteSub(mid); x[2] = x[2] ^ L1(medio); x6
mid = x[0] ^ x[1] ^ x[2] ^ rk[r + 3]; mid = ByteSub(mid); x[3] = x[3] ^ L1(medio); x7 }
Retromarcia per (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 = nuovo int[4]; int[] tmp = nuovo int[4]; per (int i = 0; Ho < 4; i++) { tmp[0] = Tonalità[0 + 4 * i] & 0xFF; tmp[1] = Tonalità[1 + 4 * i] & 0xff; tmp[2] = Tonalità[2 + 4 * i] & 0xff; tmp[3] = Tonalità[3 + 4 * i] & 0xff; x= tmp[0] << 24 | TMP[1] << 16 | TMP[2] << 8 | TMP[3]; x=Key[0+4*i]<<24| Tonalità[1+4*i]<<16| Key[2+4*i]<<8| Tonalità[3+4*i]; } x[0] ^= 0xa3b1bac6; x[1] ^= 0x56aa3350; x[2] ^= 0x677d9197; x[3] ^= 0xb27022dc; per (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(mid); rk0=K4
mid = x[2] ^ x[3] ^ x[0] ^ CK[r + 1]; mid = ByteSub(mid); rk[r + 1] = x[1] ^= L2(mid); rk1=K5
mid = x[3] ^ x[0] ^ x[1] ^ CK[r + 2]; mid = ByteSub(mid); rk[r + 2] = x[2] ^= L2(mid); rk2=K6
mid = x[0] ^ x[1] ^ x[2] ^ CK[r + 3]; mid = ByteSub(mid); rk[r + 3] = x[3] ^= L2(mid); rk3=K7 }
Decripta l'ordine della chiave della ruota: rk31, rk30,...,rk0 if (CryptFlag == DECRYPT) { per (r = 0; r < 16; r++) { mid = rk[r]; rk[r] = rk[31 - r]; rk[31 - r] = mid; } } }
public int sms4(byte[] in, int inLen, byte[] key, byte[] out, int CryptFlag) { punto int = 0; int[] round_key = nuovo int[ROUND]; int[] round_key={0}; SMS4KeyExt (chiave, round_key, CryptFlag); Ingresso byte[] = nuovo byte[16]; byte[] output = nuovo byte[16];
while (inLen >= BLOCK) { input = Arrays.copyOfRange(in, punto, punto + 16); output=Arrays.copyOfRange(uscita, punto, punto+16); SMS4Crypt (input, output, round_key); System.arraycopy(output, 0, out, point, BLOCK); inLen -= BLOCCO; punto += BLOCCO; }
ritorno 0; }
}
Interfaccia esterna confezionata:
Basandosi su questa classe di base, le interfacce principali sono le seguenti:
byte statico privato[] encode16(byte[] plain, byte[] key); byte statico privato[] decode16(byte[] cifrario, chiave byte[]); byte statico privato[] encode32(byte[] plain, byte[] key); byte statico privato[] decode32(byte[] cifrario, byte[] key); byte statico pubblico[] encodeSMS4(byte[] plain, byte[] key); byte statico pubblico[] decodeSMS4(cifrario byte[], chiave byte[]); decodeo statico pubblico StringaSMS4toString(cifrario, chiave byte[]);
encode16(byte[], byte[]) è un'interfaccia per la crittografia di chiavi a 16 bit e chiavi a 16 bit; Byte statico privato[] Decode16(cifrario byte[] chiave: è un'interfaccia per decifrare testo cifrato a 16 bit e chiave a 16 bit; Byte statico privato[] encode32(byte[] chiave, chiave byte[]): Questa è un'interfaccia che cifra chiavi a 32 bit e chiavi a 16 bit. Byte statico privato[] decode32(byte[] cifrato, chiave byte[]): Questa è un'interfaccia per decifrare chiavi cifrate a 32 bit e chiavi a 16 bit. byte statico pubblico[] encodeSMS4(byte[] plain, byte[] key): Questa è un'interfaccia che cifra il testo in chiaro e le chiavi a 16 bit con un numero illimitato di byte. byte statico pubblico[] decodeSMS4(byte[] cifrario, chiave byte[]): Questa è un'interfaccia per decifrare il testo cifrato e le chiavi a 16 bit con un numero illimitato di byte. decodifica statica pubblica StringSMS4toString(byte[] cifratura, chiave byte[]): Questa è un'interfaccia per decifrare byte illimitati di testo cifrato e chiavi a 16 bit. Codice metodo dell'interfaccia:
byte statico pubblico[] encodeSMS4(Testo in chiaro stringa, chiave byte[]) { if (testo in chiaro == null || testo.in chiaro.uguali()) { return null; } per (int i = wordtext.getBytes().length % 16; Ho < 16 anni; i++) { testo in chiaro += ''; }
return SMS4.encodeSMS4(keytext.getBytes(), key); }
/** * Crittografia SMS4 con lunghezza illimitata del testo in chiaro * * @param testo in chiaro * @param chiave * @return */ byte statico pubblico[] encodeSMS4(byte[] testo in chiaro, chiave byte[] { byte[] testo cifrato = nuovo byte[wordtext.length];
int k = 0; int plainLen = wordtext.length; mentre (k + 16 <= plainLen) { byte[] cellPlain = nuovo byte[16]; per (int i = 0; Ho < 16 anni; i++) { cellPlain= testo in chiaro[k + i]; } byte[] cellCipher = encode16(cellPlain, key); per (int i = 0; i < cellCipher.length; i++) { testo cifrato[k + i] = cellCifrario; }
k += 16; }
restituire testo cifrato; }
/** * Decrittazione SMS4 senza limite di lunghezza del testo in chiaro * * @param testo cifrato * @param chiave * @return */ byte statico pubblico[] decodeSMS4(byte[] testo cifrato, chiave byte[] { byte[] testo in chiaro = nuovo byte[cifrato.lunghe];
int k = 0; int cifraturaLen = cifrato.length; mentre (k + 16 <= cipherLen) { byte[] cellCipher = nuovo byte[16]; per (int i = 0; Ho < 16 anni; i++) { cellCipher= testo cifrato[k + i]; } byte[] cellPlain = decode16(cellCipher, key); per (int i = 0; i < cellPlain.length; i++) { testoscritto[k + i] = cellPlain; }
k += 16; }
restituisci testo in chiaro; }
/** * Decrittare per ottenere stringhe di testo in chiaro * @param testo cifrato * @param chiave * @return */ decodeo statico pubblico StringaSMS4toString(byte[] testo cifrato, chiave byte[] { byte[] testo in chiaro = nuovo byte[cifrato.lunghe]; testo in chiaro = decodeSMS4(testo cifrato, chiave); return new String(testo in chiaro); }
/** * Solo il testo in chiaro a 16 bit è criptato * * @param testo in chiaro * @param chiave * @return */ Byte statico privato[] encode16(byte[] chiave, chiave byte[] byte[] cifrario = nuovo byte[16]; SMS4 sm4 = nuovo SMS4(); sm4.sms4(testo in chiaro, 16, chiave, cifrario, CRITTO);
return cifrario; }
/** * Solo il testo cifrato a 16 bit viene decifrato * * @param testo in chiaro * @param chiave * @return */ Byte statico privato[] decode16(byte[] testo cifrato, chiave byte[] { byte[] plain = nuovo byte[16]; SMS4 sm4 = nuovo SMS4(); sm4.sms4(testo cifrato, 16, chiave, chiave, DECRITTA);
ritorno pianeggiante; } Non introducerò qui solo la crittografia del testo in chiaro a 32 bit, che è molto simile al metodo del testo in chiaro a solo 16 bit.
L'algoritmo di base per la crittografia e la decrittografia senza limitare la lunghezza del testo in chiaro si basa su questa base di crittografia e decrittografia di soli 16 bit. Per il testo in chiaro superiore a 16 bit, qui si utilizza la crittografia dei pacchetti. Se incontri testo in chiaro come 30 bit che non può essere divisibile per 16, un modo per riempirlo è compensarlo fino a renderlo divisibile per 16. In linea di principio, solo il numero più piccolo può essere diviso per 16, ovviamente, se sei soddisfatto, non importa se lo ingrandisci, perché è il simbolo di chiusura.
La crittografia dei pacchetti consiste nel cifrare ogni testo in chiaro a 16 bit una sola volta, per poi riassemblare il testo cifrato a 16 bit in un nuovo testo cifrato. Nel processo di decrittazione, viene anche suddiviso in un unico pezzo a 16 bit, e poi diversi di questi testi in chiaro decriptati vengono riassemblati in nuovo testo in chiaro.
Dimostrazione di utilizzo:
Chiave Byte[] key = { 0x01, 0x23, 0x45, 0x67, (byte) 0x89, (byte) 0xab, (byte) 0xcd, (byte) 0xef, (byte) 0xfe, (byte) 0xdc, (byte) 0xba, (byte) 0x98, 0x76, 0x54, 0x32, 0x10 };
Stringa nuovaStringa = Programmazione, ciao!; Testo semplice
byte[] enOut = SMS4.encodeSMS4(newString, key); if (enOut == null) { ritorno; }
System.out.println(risultato crittografia:); printBit(enOut);
byte[] deOut = SMS4.decodeSMS4(enOut, chiave); System.out.println( risultato di decrittazione (return byte[]) :); printBit(deOut);
Stringa deOutStr = SMS4.decodeSMS4toString(enOut, chiave); System.out.println( Decripta il risultato (return String): + deOutStr); |