SMS4 Giriş:
Bu algoritma bir gruplama algoritmasıdır. Algoritmanın paket uzunluğu 128 bit, anahtar uzunluğu ise 128 bit, yani 16 bayttır. Hem şifreleme algoritması hem de anahtar genişletme algoritması 32 turluk doğrusal olmayan bir yineleme yapısını benimser. Şifre çözme algoritması, şifreleme algoritmasıyla aynı yapıya sahiptir, ancak yuvarlak anahtarın kullanım sırası tersine çevrilir ve şifreleme çarkı anahtarı şifreleme çarkı anahtarının tersine sırasıdır. SMS4'ün tüm temel sınıflarında, şifreleme ve şifre çözme gibi temel işlevlerin aynı olduğunu göreceksiniz, ancak şifrelenip şifrelenmediğini belirlemek için bir int-tipi bayrak biti gereklidir.
SMS4 şifreleme algoritması temelleri:
public class SMS4 {
özel statik son zeka ENCRYPT = 1; özel statik final int DECRYPT = 0; public static final int ROUND = 32; özel statik final int BLOCK = 16;
özel bayt[] Sbox = { (bayt) 0xd6, (bayt) 0x90, (bayt) 0xe9, (bayt) 0xfe, (bayt) 0xcc, (bayt) 0xe1, 0x3d, (bayt) 0xb7, 0x16, (bayt) 0xb6, 0x14, (bayt) 0xc2, 0x28, (bayt) 0xfb, 0x2c, 0x05, 0x2b, 0x67, (bayt) 0x9a, 0x76, 0x2a, (bayt) 0xbe, 0x04, (bayt) 0xc3, (bayt) 0xaa, 0x44, 0x13, 0x26, 0x49, (bayt) 0x86, 0x06, (bayt) 0x99, (bayt) 0x9c, 0x42, 0x50, (bayt) 0xf4, (bayt) 0x91, (bayt) 0xef, (bayt) 0x98, 0x7a, 0x33, 0x54, 0x0b, 0x43, (bayt) 0xed, (bayt) 0xcf, (bayt) 0xac, 0x62, (bayt) 0xe4, (bayt) 0xb3, 0x1c, (bayt) 0xa9, (bayt) 0xc9, 0x08, (bayt) 0xe8, (bayt) 0x95, (bayt) 0x80, (bayt) 0xdf, (bayt) 0x94, (bayt) 0xfa, 0x75, (bayt) 0x8f, 0x3f, (bayt) 0xa6, 0x47, 0x07, (bayt) 0xa7, (bayt) 0xfc, (bayt) 0xf3, 0x73, 0x17, (bayt) 0xba, (bayt) 0x83, 0x59, 0x3c, 0x19, (bayt) 0xe6, (bayt) 0x85, 0x4f, (bayt) 0xa8, 0x68, 0x6b, (bayt) 0x81, (bayt) 0xb2, 0x71, 0x64, (bayt) 0xda, (bayt) 0x8b, (bayt) 0xf8, (bayt) 0xeb, 0x0f, 0x4b, 0x70, 0x56, (bayt) 0x9d, 0x35, 0x1e, 0x24, 0x0e, 0x5e, 0x63, 0x58, (bayt) 0xd1, (bayt) 0xa2, 0x25, 0x22, 0x7c, 0x3b, 0x01, 0x21, 0x78, (bayt) 0x87, (bayt) 0xd4, 0x00, 0x46, 0x57, (bayt) 0x9f, (bayt) 0xd3, 0x27, 0x52, 0x4c, 0x36, 0x02, (bayt) 0xe7, (bayt) 0xa0, (bayt) 0xc4, (bayt) 0xc8, (bayt) 0x9e, (bayt) 0xea, (bayt) 0xbf, (bayt) 0x8a, (bayt) 0xd2, 0x40, (bayt) 0xc7, 0x38, (bayt) 0xb5, (bayt) 0xa3, (bayt) 0xf7, (bayt) 0xf2, (bayt) 0xce, (bayt) 0xf9, 0x61, 0x15, (bayt) 0xa1, (bayt) 0xe0, (bayt) 0xae, 0x5d, (bayt) 0xa4, (bayt) 0x9b, 0x34, 0x1a, 0x55, (bayt) 0xad, (bayt) 0x93, 0x32, 0x30, (bayt) 0xf5, (bayt) 0x8c, (bayt) 0xb1, (bayt) 0xe3, 0x1d, (bayt) 0xf6, (bayt) 0xe2, 0x2e, (bayt) 0x82, 0x66, (bayt) 0xca, 0x60, (bayt) 0xc0, 0x29, 0x23, (bayt) 0xab, 0x0d, 0x53, 0x4e, 0x6f, (bayt) 0xd5, (bayt) 0xdb, 0x37, 0x45, (bayt) 0xde, (bayt) 0xfd, (bayt) 0x8e, 0x2f, 0x03, (bayt) 0xff, 0x6a, 0x72, 0x6d, 0x6c, 0x5b, 0x51, (bayt) 0x8d, 0x1b, (bayt) 0xaf, (bayt) 0x92, (bayt) 0xbb, (bayt) 0xdd, (bayt) 0xbc, 0x7f, 0x11, (bayt) 0xd9, 0x5c, 0x41, 0x1f, 0x10, 0x5a, (bayt) 0xd8, 0x0a, (bayt) 0xc1, 0x31, (bayt) 0x88, (bayt) 0xa5, (bayt) 0xcd, 0x7b, (bayt) 0xbd, 0x2d, 0x74, (bayt) 0xd0, 0x12, (bayt) 0xb8, (bayt) 0xe5, (bayt) 0xb4, (bayt) 0xb0, (bayt) 0x89, 0x69, (bayt) 0x97, 0x4a, 0x0c, (bayt) 0x96, 0x77, 0x7e, 0x65, (bayt) 0xb9, (bayt) 0xf1, 0x09, (bayt) 0xc5, 0x6e, (bayt) 0xc6, (bayt) 0x84, 0x18, (bayt) 0xf0, 0x7d, (bayt) 0xec, 0x3a, (bayt) 0xdc, 0x4d, 0x20, 0x79, (bayt) 0xee, 0x5f, 0x3e, (bayt) 0xd7, (bayt) 0xcb, 0x39, 0x48 };
özel 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) { return 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) { dönüş 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) { dönüş B ^ Rotl(B, 13) ^ Rotl(B, 23); dönüş B^(B<<13|B>>>19)^(B<<23|B>>>9); }
void SMS4Crypt(bayt[] Giriş, bayt[] Çıkış, int[] rk) { int r, mid, x0, x1, x2, x3; int[] x = yeni int[4]; int[] tmp = yeni int[4]; için (int i = 0; I < 4; i++) { tmp[0] = Giriş[0 + 4 * i] & 0xff; tmp[1] = Giriş[1 + 4 * i] & 0xff; tmp[2] = Giriş[2 + 4 * i] & 0xff; tmp[3] = Giriş[3 + 4 * i] & 0xff; x= tmp[0] << 24 | TMP[1] << 16 | TMP[2] << 8 | TMP[3]; x=(Giriş[0+4*i]<<24| Input[1+4*i]<<16| Input[2+4*i]<<8| giriş[3+4*i]); } için (r = 0; r < 32; r += 4) { mid = x[1] ^ x[2] ^ x[3] ^ rk[r + 0]; mid = ByteSub(mid); x[0] = x[0] ^ L1(orta); x4
mid = x[2] ^ x[3] ^ x[0] ^ rk[r + 1]; mid = ByteSub(mid); x[1] = x[1] ^ L1(orta); x5
mid = x[3] ^ x[0] ^ x[1] ^ rk[r + 2]; mid = ByteSub(mid); x[2] = x[2] ^ L1(orta); x6
mid = x[0] ^ x[1] ^ x[2] ^ rk[r + 3]; mid = ByteSub(mid); x[3] = x[3] ^ L1(orta); x7 }
Ters için (int j = 0; j < 16; j += 4) { Çıktı[j] = (bayt) (x[3 - j / 4] >>> 24 & 0xFF); Çıktı[j + 1] = (bayt) (x[3 - j / 4] >>> 16 & 0xFF); Çıktı[j + 2] = (bayt) (x[3 - j / 4] >>> 8 & 0xFF); Output[j + 3] = (bayt) (x[3 - j / 4] & 0xFF); } }
private void SMS4KeyExt(byte[] Key, int[] rk, int CryptFlag) { int r, orta; int[] x = yeni int[4]; int[] tmp = yeni int[4]; için (int i = 0; I < 4; i++) { tmp[0] = Anahtar[0 + 4 * i] & 0xFF; tmp[1] = Anahtar[1 + 4 * i] & 0xff; tmp[2] = Anahtar[2 + 4 * i] & 0xff; tmp[3] = Anahtar[3 + 4 * i] & 0xff; x= tmp[0] << 24 | TMP[1] << 16 | TMP[2] << 8 | TMP[3]; x=Anahtar[0+4*i]<<24| Key[1+4*i]<<16| Key[2+4*i]<<8| Anahtar[3+4*i]; } x[0] ^= 0xa3b1bac6; x[1] ^= 0x56aa3350; x[2] ^= 0x677d9197; x[3] ^= 0xb27022dc; için (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(orta); rk0=K4
mid = x[2] ^ x[3] ^ x[0] ^ CK[r + 1]; mid = ByteSub(mid); rk[r + 1] = x[1] ^= L2(orta); rk1=K5
mid = x[3] ^ x[0] ^ x[1] ^ CK[r + 2]; mid = ByteSub(mid); rk[r + 2] = x[2] ^= L2(orta); rk2=K6
mid = x[0] ^ x[1] ^ x[2] ^ CK[r + 3]; mid = ByteSub(mid); rk[r + 3] = x[3] ^= L2(orta); rk3=K7 }
Tekerlek anahtarının sırasını çöz: rk31, rk30,...,rk0 if (CryptFlag == DECRYPT) { için (r = 0; r < 16; r++) { mid = rk[r]; rk[r] = rk[31 - r]; rk[31 - r] = orta; } } }
public int sms4(byte[] in, int inLen, byte[] key, byte[] out, int CryptFlag) { int noktası = 0; int[] round_key = yeni int[ROUND]; int[] round_key={0}; SMS4KeyExt(key, round_key, CryptFlag); byte[] input = yeni bayt[16]; byte[] output = yeni bayt[16];
while (inLen >= BLOCK) { input = Arrays.copyOfRange(in, point, point + 16); output=Arrays.copyOfRange(out, point, point+16); SMS4Crypt (giriş, çıkış, round_key); System.arraycopy (çıktı, 0, çıkış, nokta, BLOCK); inLen -= BLOCK; nokta += BLOK; }
dönüş 0; }
}
Paketlenmiş harici arayüz:
Bu temel sınıfa dayanan ana arayüzler şunlardır:
özel statik bayt[] encode16(bayt[] sade, bayt[] anahtar); özel statik bayt[] decode16(bayt[] şifre, bayt[] anahtar); özel statik bayt[] encode32(bayt[] sade, bayt[] anahtar); özel statik bayt[] decode32(bayt[] şifre, bayt[] anahtar); public static byte[] encodeSMS4(byte[] plain, byte[] key); public static byte[] decodeSMS4(byte[] şifre, bayt[] anahtar); public statik String decodeSMS4toString(byte[] şifre, bayt[] anahtar);
encode16(bayt[], bayt[]), 16 bitlik düz metin ve 16 bit anahtarlar için şifreleme için bir arayüzdür; özel statik bayt[] decode16(bayt[] şifre, bayt[] anahtar): 16 bitlik şifreli metin ve 16 bitlik anahtarın şifresini çözmek için bir arayüzdür; özel statik bayt[] encode32(bayt[] sade, bayt[] anahtar): Bu, 32-bit düz metin ve 16-bit anahtarları şifreleyen bir arayüzdür. özel statik bayt[] decode32(bayt[] şifre, bayt[] anahtar): Bu, 32-bit şifreli metin ve 16-bit anahtarların şifrelenmesi için kullanılan bir arayüzdür. public static byte[] encodeSMS4(byte[] sade, bayt[] anahtar): Bu, açık metin ve 16-bit anahtarları sınırsız sayıda baytla şifreleyen bir arayüzdür. public static byte[] decodeSMS4(byte[] şifre, bayt[] anahtar): Bu, sınırsız sayıda baytla şifreli metin ve 16-bit anahtarların şifresini çözmek için bir arayüzdür. public static String decodeSMS4toString(byte[] cipher, byte[] key): Bu, sınırsız baytlar şifreli metin ve 16-bit anahtarların şifresini çözmek için bir arayüzdür. Arayüz yöntemi kodu:
public static byte[] encodeSMS4(Dizi plaintext, byte[] anahtar) { if (plaintext == null || plaintext.equals()) { return null; } for (int i = plaintext.getBytes().length % 16; I < 16; i++) { açık metin += ''; }
SMS4.encodeSMS4(plaintext.getBytes(), anahtarı) geri döner; }
/** * Sınırsız açık metin uzunluğuyla SMS4 şifreleme * * @param açık metin * @param anahtarı * @return */ public static byte[] encodeSMS4(byte[] plaintext, byte[] key) { byte[] ciphertext = yeni bayt[plaintext.length];
int k = 0; int plainLen = açık metin.uzunluk; while (k + 16 <= plainLen) { byte[] cellPlain = yeni bayt[16]; için (int i = 0; I < 16; i++) { cellPlain= açık metin[k + i]; } byte[] cellCipher = encode16(cellPlain, key); için (int i = 0; i cellCipher.length <; i++) { ciphertext[k + i] = cellCipher; }
k += 16; }
şifreli metin geri dönmek; }
/** * Açık metin uzunluğunda sınır olmadan SMS4 şifre çözme * * @param şifreli metin * @param anahtarı * @return */ public static byte[] decodeSMS4(byte[] ciphertext, byte[] key) { byte[] plaintext = yeni bayt[ciphertext.length];
int k = 0; int cipherLen = ciphertext.length; while (k + 16 <= cipherLen) { byte[] cellCipher = yeni bayt[16]; için (int i = 0; I < 16; i++) { cellCipher= şifreli metin[k + i]; } byte[] cellPlain = decode16(cellCipher, key); için (int i = 0; i cellPlain.length <; i++) { plaintext[k + i] = cellPlain; }
k += 16; }
açık metin geri döndürmek; }
/** * Düz metin dizelerini elde etmek için şifre çözme * @param şifreli metin * @param anahtarı * @return */ public static String decodeSMS4toString(byte[] ciphertext, byte[] key) { byte[] plaintext = yeni bayt[ciphertext.length]; açık metin = SMS4 (şifreli metin, anahtar) kod çözmek; return new String (açık metin); }
/** * Sadece 16-bit açık metin şifrelenmiştir * * @param açık metin * @param anahtarı * @return */ özel statik bayt[] encode16(bayt[] açık metin, bayt[] anahtar) { byte[] cipher = yeni bayt[16]; SMS4 sm4 = yeni SMS4(); sm4.sms4(açık metin, 16, anahtar, şifre, ŞİFOLA);
dönüş şifresi; }
/** * Sadece 16-bit şifreli metin çözülür * * @param açık metin * @param anahtarı * @return */ özel statik bayt[] decode16(byte[] şifreli metin, bayt[] anahtar) { byte[] plain = yeni bayt[16]; SMS4 sm4 = yeni SMS4(); sm4.sms4(şifreli metin, 16, anahtar, sade, ÇÖZ);
düz dönüş; } Burada sadece 32-bit düz metin şifrelemesini tanıtmayacağım, ki bu da sadece 16-bit açık metin yöntemine çok benziyor.
Şifreleme ve şifre çözme için basit algoritma, açık metnin uzunluğunu sınırlamadan yalnızca 16 bitin şifrelenmesi ve çözülmesi temeline dayanır. 16 bitten büyük açık metin için burada paket şifreleme kullanılır. Eğer 30 bit gibi açık metin ile karşılaşırsanız ve 16'ya bölünemezse, doldurmanın bir yolu 16'ya bölünebilen kadar telafi etmektir. Prensipte, sadece en küçük sayı 16'ya bölünebilir, tabii ki, mutluysanız, büyütmeniz önemli değil, çünkü kapanış sembolüdür.
Paket şifreleme, her 16 bitlik düz metni bir kez şifrelemek ve ardından şifrelenmiş 16 bitlik şifreli metni yeni bir şifreli metne dönüştürmektir. Şifre çözme sürecinde, ayrıca tek bir 16-bit parçaya bölünür ve ardından bu çözülmüş düz metinlerden birkaçı yeni açık metne dönüştürülür.
Kullanım gösterimi:
Anahtar bayt[] anahtarı = { 0x01, 0x23, 0x45, 0x67, (bayt) 0x89, (bayt) 0xab, (bayt) 0xcd, (bayt) 0xef, (bayt) 0xfe, (bayt) 0xdc, (bayt) 0xba, (bayt) 0x98, 0x76, 0x54, 0x32, 0x10 };
String newString = Kodlama, merhaba!; Düz metin
byte[] enOut = SMS4.encodeSMS4(newString, key); if (enOut == null) { dönmek; }
System.out.println (şifreleme sonucu:); printBit(enOut);
byte[] deOut = SMS4.decodeSMS4(enOut, key); System.out.println( şifre çözme sonucu (bayt dönüşü[]) :); printBit(deOut);
String deOutStr = SMS4.decodeSMS4toString(enOut, key); System.out.println( Sonucu çözün (return String): + deOutStr); |