Pengenalan SMS4:
Algoritma ini adalah algoritma pengelompokan. Algoritma ini memiliki panjang paket 128 bit dan panjang kunci 128 bit, yaitu 16 byte. Baik algoritma enkripsi maupun algoritma ekspansi kunci mengadopsi struktur iterasi nonlinier 32 putaran. Algoritma dekripsi memiliki struktur yang sama dengan algoritma enkripsi, kecuali bahwa urutan penggunaan kunci bulat dibalik, dan kunci roda dekripsi adalah urutan terbalik dari kunci roda enkripsi. Di semua kelas dasar SMS4, Anda akan melihat bahwa fungsi dasar enkripsi dan dekripsi adalah sama, tetapi bit bendera tipe int diperlukan untuk menentukan apakah itu dienkripsi atau didekripsi.
Dasar-dasar algoritma enkripsi SMS4:
kelas publik SMS4 {
int akhir statis pribadi ENCRYPT = 1; int final statis pribadi DECRYPT = 0; publik statis final int ROUND = 32; int akhir statis pribadi BLOK = 16;
private 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 };
pribadi 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) { mengembalikan x << y | x >>> (32 - y); }
private int ByteSub(int A) { kembali (Sbox[A >>> 24 & 0xFF] & 0xFF) << 24 | (Kotak [A >>> 16 & 0xFF] & 0xFF) << 16 | (Sbox[A >>> 8 & 0xFF] & 0xFF) << 8 | (Sbox[A & 0xFF] & 0xFF); }
private int L1(int B) { kembali B ^ Rotl(B, 2) ^ Rotl(B, 10) ^ Rotl(B, 18) ^ Rotl(B, 24); kembali B^(B<<2|B>>>30)^(B<<10|B>>>22)^(B<<18|B>>>14)^(B<<24|B>>>8); }
private int L2(int B) { kembali B ^ Rotl(B, 13) ^ Rotl(B, 23); kembali B^(B<<13|B>>>19)^(B<<23|B>>>9); }
void SMS4Crypt(byte[] Input, byte[] Output, int[] rk) { int r, pertengahan, x0, x1, x2, x3; int[] x = int[4] baru; int[] tmp = int baru[4]; untuk (int i = 0; saya < 4; i++) { tmp[0] = Masukan[0 + 4 * i] & 0xff; tmp[1] = Masukan[1 + 4 * i] & 0xff; tmp[2] = Masukan[2 + 4 * i] & 0xff; tmp[3] = Masukan[3 + 4 * i] & 0xff; x= tmp[0] << 24 | tmp[1] << 16 | tmp[2] << 8 | tmp[3]; x=(Masukan[0+4*i]<<24| Masukan[1+4*i]<<16| Masukan[2+4*i]<<8| Masukan [3 + 4 * i]); } untuk (r = 0; r < 32; r += 4) { tengah = x[1] ^ x[2] ^ x[3] ^ rk[r + 0]; mid = ByteSub(mid); x[0] = x[0] ^ L1(tengah); x4
tengah = x[2] ^ x[3] ^ x[0] ^ rk[r + 1]; mid = ByteSub(mid); x[1] = x[1] ^ L1(tengah); x5
tengah = x[3] ^ x[0] ^ x[1] ^ rk[r + 2]; mid = ByteSub(mid); x[2] = x[2] ^ L1(tengah); x6
tengah = x[0] ^ x[1] ^ x[2] ^ rk[r + 3]; mid = ByteSub(mid); x[3] = x[3] ^ L1(tengah); x7 }
Terbalik untuk (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); Keluaran[j + 2] = (byte) (x[3 - j / 4] >>> 8 & 0xFF); Keluaran[j + 3] = (byte) (x[3 - j / 4] & 0xFF); } }
private void SMS4KeyExt(byte[] Key, int[] rk, int CryptFlag) { int r, pertengahan; int[] x = int[4] baru; int[] tmp = int baru[4]; untuk (int i = 0; saya < 4; i++) { tmp[0] = Kunci[0 + 4 * i] & 0xFF; tmp[1] = Kunci[1 + 4 * i] & 0xff; tmp[2] = Kunci[2 + 4 * i] & 0xff; tmp[3] = Kunci[3 + 4 * i] & 0xff; x= tmp[0] << 24 | tmp[1] << 16 | tmp[2] << 8 | tmp[3]; x=Kunci[0+4*i]<<24| Kunci[1+4*i]<<16| Kunci[2+4*i]<<8| Kunci[3+4*i]; } x[0] ^= 0xa3b1bac6; x[1] ^= 0x56aa3350; x[2] ^= 0x677d9197; x[3] ^= 0xb27022dc; untuk (r = 0; r < 32; r += 4) { tengah = x[1] ^ x[2] ^ x[3] ^ CK[r + 0]; mid = ByteSub(mid); rk[r + 0] = x[0] ^= L2(tengah); rk0=K4
tengah = x[2] ^ x[3] ^ x[0] ^ CK[r + 1]; mid = ByteSub(mid); rk[r + 1] = x[1] ^= L2(tengah); rk1=K5
tengah = x[3] ^ x[0] ^ x[1] ^ CK[r + 2]; mid = ByteSub(mid); rk[r + 2] = x[2] ^= L2(tengah); rk2=K6
tengah = x[0] ^ x[1] ^ x[2] ^ CK[r + 3]; mid = ByteSub(mid); rk[r + 3] = x[3] ^= L2(tengah); rk3=K7 }
Dekripsi urutan kunci roda: rk31, rk30,...,rk0 if (CryptFlag == DECRYPT) { untuk (r = 0; r < 16; r++) { tengah = rk[r]; rk[r] = rk[31 - r]; rk[31 - r] = tengah; } } }
public int sms4(byte[] in, int inLen, byte[] key, byte[] out, int CryptFlag) { titik int = 0; int[] round_key = int[ROUND] baru; int[] round_key={0}; SMS4KeyExt(kunci, round_key, CryptFlag); byte[] input = byte baru[16]; keluaran byte[] = byte baru[16];
sementara (inLen >= BLOCK) { masukan = Arrays.copyOfRange(dalam, titik, titik + 16); output=Arrays.copyOfRange(keluar, titik, titik+16); SMS4Crypt (input, output, round_key); System.arraycopy (keluaran, 0, keluar, titik, BLOK); inLen -= BLOK; titik += BLOK; }
mengembalikan 0; }
}
Antarmuka eksternal yang dikemas:
Berdasarkan kelas dasar ini, antarmuka utamanya adalah sebagai berikut:
private static byte[] encode16(byte[] plain, byte[] key); byte statis pribadi[] decode16(sandi byte[], kunci byte[]); private static byte[] encode32(byte[] plain, byte[] key); byte statis pribadi[] decode32(sandi byte[], byte[], kunci byte[]); byte statis publik[] mengkodekan SMS4(byte[] polos, kunci byte[]); byte statis publik[] decodeSMS4(sandi byte[], byte[]); dekode String statis publikSMS4toString(sandi byte[], byte[]);
encode16(byte[], byte[]) adalah antarmuka untuk enkripsi untuk teks biasa 16-bit dan kunci 16-bit; Private Static Byte[] Decode16(Byte[] Cipher, Byte[] Key): adalah antarmuka untuk mendekripsi teks sandi 16-bit dan kunci 16-bit; private static byte[] encode32(byte[] plain, byte[] key): Ini adalah antarmuka yang mengenkripsi teks biasa 32-bit dan kunci 16-bit. private static byte[] decode32(byte[] cipher, byte[] key): Ini adalah antarmuka untuk mendekripsi ciphertext 32-bit dan kunci 16-bit. public static byte[] encodeSMS4(byte[] plain, byte[] key): Ini adalah antarmuka yang mengenkripsi teks biasa dan kunci 16-bit dengan jumlah byte yang tidak terbatas. public static byte[] decodeSMS4(byte[] cipher, byte[] key): Ini adalah antarmuka untuk mendekripsi ciphertext dan kunci 16-bit dengan jumlah byte yang tidak terbatas. dekode String statis publikSMS4toString(byte[] cipher, byte[] key): Ini adalah antarmuka untuk mendekripsi byte teks sandi dan kunci 16-bit tanpa batas. Kode metode antarmuka:
publik statis byte[] encodeSMS4(String plaintext, byte[] key) { if (plaintext == null || plaintext.equals()) { mengembalikan null; } for (int i = plaintext.getBytes().length % 16; saya < 16; i++) { teks biasa += ''; }
mengembalikan SMS4.encodeSMS4(plaintext.getBytes(), kunci); }
/** * Enkripsi SMS4 dengan panjang teks biasa tak terbatas * * @param teks biasa * Kunci @param * @return */ byte statis publik[] encodeSMS4(byte[] plaintext, byte[] key) { byte[] ciphertext = byte baru[plaintext.length];
int k = 0; int plainLen = plaintext.length; sementara (k + 16 <= plainLen) { byte[] cellPlain = byte baru[16]; untuk (int i = 0; saya < 16; i++) { selPolos= teks biasa[k + i]; } byte[] cellCipher = encode16(cellPlain, kunci); untuk (int i = 0; i < cellCipher.length; i++) { ciphertext[k + i] = cellCipher; }
k += 16; }
mengembalikan teks sandi; }
/** * Dekripsi SMS4 tanpa batasan panjang teks biasa * * @param ciphertext * Kunci @param * @return */ byte statis publik[] decodeSMS4(byte[] ciphertext, byte[] key) { byte[] plaintext = byte baru[ciphertext.length];
int k = 0; int cipherLen = ciphertext.length; sementara (k + 16 <= cipherLen) { byte[] cellCipher = byte baru[16]; untuk (int i = 0; saya < 16; i++) { selSencip= teks sandi[k + i]; } byte[] cellPlain = decode16(cellCipher, kunci); untuk (int i = 0; i < cellPlain.length; i++) { plaintext[k + i] = cellPlain; }
k += 16; }
mengembalikan teks biasa; }
/** * Dekripsi untuk mendapatkan string teks biasa * @param ciphertext * Kunci @param * @return */ publik statis String decodeSMS4toString(byte[] ciphertext, byte[] key) { byte[] plaintext = byte baru[ciphertext.length]; plaintext = decodeSMS4(ciphertext, kunci); mengembalikan String baru (teks biasa); }
/** * Hanya teks biasa 16-bit yang dienkripsi * * @param teks biasa * Kunci @param * @return */ private static byte[] encode16(byte[] plaintext, byte[] key) { byte[] cipher = byte baru[16]; SMS4 sm4 = new SMS4(); sm4.sms4(teks biasa, 16, kunci, sandi, ENKRIPSI);
sandi kembali; }
/** * Hanya teks sandi 16-bit yang didekripsi * * @param teks biasa * Kunci @param * @return */ byte statis privat[] decode16(byte[] ciphertext, kunci byte[]) { byte[] plain = byte baru[16]; SMS4 sm4 = new SMS4(); sm4.sms4(teks sandi, 16, kunci, polos, DEKRIPSI);
kembali polos; } Saya tidak akan hanya memperkenalkan enkripsi teks biasa 32-bit di sini, yang sangat mirip dengan metode teks biasa hanya 16-bit.
Algoritme dasar untuk enkripsi dan dekripsi tanpa membatasi panjang teks biasa didasarkan pada dasar ini untuk mengenkripsi dan mendekripsi hanya 16 bit. Untuk teks biasa yang lebih besar dari 16 bit, enkripsi paket digunakan di sini. Jika Anda menemukan teks biasa seperti 30 bit yang tidak dapat dibagi 16, cara untuk mengisinya adalah dengan membuatnya sampai habis dibagi 16. Pada prinsipnya, hanya angka terkecil yang dapat dibagi dengan 16, tentu saja, jika Anda senang, tidak masalah jika Anda membuatnya lebih besar, karena itu adalah simbol penutup.
Enkripsi paket adalah mengenkripsi setiap teks biasa 16-bit sekali, dan kemudian menyusun kembali teks sandi 16-bit terenkripsi menjadi teks sandi baru. Dalam proses dekripsi, itu juga dibagi menjadi satu bagian 16-bit, dan kemudian beberapa teks biasa yang didekripsi ini dirakit kembali menjadi teks biasa baru.
Demonstrasi penggunaan:
kunci kunci byte[] = { 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 = Pengkodean, halo!; Teks biasa
byte[] enOut = SMS4.encodeSMS4(newString, kunci); if (enOut == null) { kembali; }
System.out.println(hasil enkripsi:); printBit(enOut);
byte[] deOut = SMS4.decodeSMS4(enOut, kunci); Sistem.keluar.println( hasil dekripsi (kembalikan byte[]) :); printBit(deOut);
String deOutStr = SMS4.decodeSMS4toString(enOut, kunci); Sistem.keluar.println( Dekripsi hasilnya (kembalikan String): + deOutStr); |