SMS4-Einführung:
Dieser Algorithmus ist ein Gruppierungsalgorithmus. Der Algorithmus hat eine Paketlänge von 128 Bit und eine Schlüssellänge von 128 Bits, also 16 Bytes. Sowohl der Verschlüsselungsalgorithmus als auch der Schlüsselerweiterungsalgorithmus verwenden eine nichtlineare Iterationsstruktur mit 32 Runden. Der Entschlüsselungsalgorithmus hat dieselbe Struktur wie der Verschlüsselungsalgorithmus, mit der Ausnahme, dass die Reihenfolge der Verwendung des Rundschlüssels umgekehrt ist und der Entschlüsselungsradschlüssel die umgekehrte Reihenfolge des Verschlüsselungsradschlüssels ist. In allen Basisklassen von SMS4 werden Sie feststellen, dass die Grundfunktionen Verschlüsselung und Entschlüsselung dieselben sind, aber ein Int-Typ-Flagbit benötigt wird, um zu bestimmen, ob es verschlüsselt oder entschlüsselt ist.
Basics zum SMS4-Verschlüsselungsalgorithmus:
öffentliche Klasse SMS4 {
private statische End-INT ENCRYPT = 1; private statische Endintellekt DECRYPT = 0; öffentliche statische Finalrunde (INT ROUND) = 32; private statische End-BLOCK = 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 };
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) { Rückgabe x << y | x >>> (32 - y); }
private int ByteSub(int A) { Rückkehr (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) { Rückgabe B ^ Rotl(B, 2) ^ Rotl(B, 10) ^ Rotl(B, 18) ^ Rotl(B, 24); zurück B^(B<<2|B>>>30)^(B<<10|B>>>22)^(B<<18|B>>>14)^(B<<24|B>>>8); }
private int L2(int B) { Rückkehr 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 = neue int[4]; int[] tmp = neue int[4]; für (int i = 0; Ich < 4; i++) { tmp[0] = Eingabe[0 + 4 * i] & 0xff; tmp[1] = Eingabe[1 + 4 * i] & 0xff; tmp[2] = Eingabe[2 + 4 * i] & 0xff; tmp[3] = Eingabe[3 + 4 * i] & 0xff; x= tmp[0] << 24 | tmp[1] << 16 | tmp[2] << 8 | TMP[3]; x=(Eingabe[0+4*i]<<24| Eingabe[1+4*i]<<16| Eingabe[2+4*i]<<8| Eingabe[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(mitte); x4
mid = x[2] ^ x[3] ^ x[0] ^ rk[r + 1]; mid = ByteSub(mid); x[1] = x[1] ^ L1(mitte); x5
mid = x[3] ^ x[0] ^ x[1] ^ rk[r + 2]; mid = ByteSub(mid); x[2] = x[2] ^ L1(mitte); x6
mid = x[0] ^ x[1] ^ x[2] ^ rk[r + 3]; mid = ByteSub(mid); x[3] = x[3] ^ L1(mitte); x7 }
Rückwärts für (int j = 0; J < 16; j += 4) { Ausgabe[j] = (Byte) (x[3 - j / 4] >>> 24 & 0xFF); Ausgabe[j + 1] = (Byte) (x[3 - j / 4] >>> 16 & 0xFF); Ausgabe[j + 2] = (Byte) (x[3 - j / 4] >>> 8 & 0xFF); Ausgabe[j + 3] = (Byte) (x[3 - j / 4] & 0xFF); } }
private void SMS4KeyExt(byte[] Key, int[] rk, int CryptFlag) { Int R, Mid; int[] x = neue int[4]; int[] tmp = neue int[4]; für (int i = 0; Ich < 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; 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(mitte); rk0=K4
mid = x[2] ^ x[3] ^ x[0] ^ CK[r + 1]; mid = ByteSub(mid); rk[r + 1] = x[1] ^= L2(mitten); rk1=K5
mid = x[3] ^ x[0] ^ x[1] ^ CK[r + 2]; mid = ByteSub(mid); rk[r + 2] = x[2] ^= L2(mitten); rk2=K6
mid = x[0] ^ x[1] ^ x[2] ^ CK[r + 3]; mid = ByteSub(mid); rk[r + 3] = x[3] ^= L2(mitte); rk3=K7 }
Entschlüssele die Reihenfolge des Radschlüssels: rk31, rk30,...,rk0 if (CryptFlag == DECRYPT) { für (r = 0; r < 16; r++) { mid = rk[r]; rk[r] = rk[31 - r]; rk[31 - r] = mittler; } } }
public int sms4(byte[] in, int inLen, byte[] key, byte[] out, int CryptFlag) { Int Point = 0; int[] round_key = neue int[RUNDE]; int[] round_key={0}; SMS4KeyExt(schlüssel, round_key, CryptFlag); byte[] eingabe = neues Byte[16]; byte[] output = neues Byte[16];
während (inLen >= BLOCK) { eingabe = Arrays.copyOfRange(in, Punkt, Punkt + 16); output=Arrays.copyOfRange(out, point, point+16); SMS4Crypt (Eingabe, Ausgabe, round_key); System.arraycopy (Ausgabe, 0, Aus, Punkt, BLOCK); inLen -= BLOCK; Punkt += BLOCK; }
0 zurückzugeben; }
}
Paketierte externe Schnittstelle:
Basierend auf dieser Grundklasse sind die Hauptschnittstellen wie folgt:
private statische Byte[] encode16(byte[] plain, byte[] key); private statische Byte[] Decode16(byte[] Chiffre, Byte[] Schlüssel); private statische Byte[] encode32(byte[] plain, byte[] schlüssel); private statische Byte[] Decode32(byte[] Chiffre, Byte[] Schlüssel); öffentliche statische Byte[] encodeSMS4(byte[] plain, byte[] schlüssel); öffentliches statisches Byte[] dekodierenSMS4(byte[] Chiffre, Byte[] Schlüssel); öffentliche statische Zeichenkettendecodierung SMS4toString(byte[] Chiffre, Byte[] Schlüssel);
encode16(byte[], byte[]) ist eine Schnittstelle zur Verschlüsselung von 16-Bit-Klartext- und 16-Bit-Schlüsseln; Private statische Byte[] Decode16(byte[] Chiffre, Byte[] Schlüssel): ist eine Schnittstelle zur Entschlüsselung von 16-Bit-Chiffretext und 16-Bit-Schlüssel; Private Static Byte[] encode32(byte[] plain, byte[] key): Dies ist eine Schnittstelle, die 32-Bit-Klartext- und 16-Bit-Schlüssel verschlüsselt. Private Static Byte[] Decode32(byte[] Chiffre, Byte[] Key): Dies ist eine Schnittstelle zur Entschlüsselung von 32-Bit-Chiffretext- und 16-Bit-Schlüsseln. public static byte[] encodeSMS4(byte[] plain, byte[] key): Dies ist eine Schnittstelle, die Klartext- und 16-Bit-Schlüssel mit einer unbegrenzten Anzahl von Bytes verschlüsselt. public static byte[] decodeSMS4(byte[] cipher, byte[] key): Dies ist eine Schnittstelle zur Entschlüsselung von Chiffretext- und 16-Bit-Schlüsseln mit einer unbegrenzten Anzahl von Bytes. öffentliche statische Zeichenkette dekodierenSMS4toString(byte[] Chiffre, Byte[] Schlüssel): Dies ist eine Schnittstelle zur Entschlüsselung unbegrenzter Bytes Chiffretext und 16-Bit-Schlüssel. Schnittstellenmethodencode:
public static byte[] encodeSMS4(String-Klartext, byte[]-Schlüssel) { wenn (Klartext == null || Klartext.gleich()) { Null zurück; } für (int i = klartext.getBytes().length % 16; Ich < 16; i++) { Klartext += ''; }
return SMS4.encodeSMS4(plaintext.getBytes(), key); }
/** * SMS4-Verschlüsselung mit unbegrenzter Klartextlänge * * @param Klartext * @param Schlüssel * @return */ public static byte[] encodeSMS4(byte[] Klartext, byte[] key) { byte[] ciphertext = neues byte[plaintext.length];
int k = 0; int plainLen = klartext.länge; während (k + 16 <= plainLen) { byte[] cellPlain = neues Byte[16]; für (int i = 0; Ich < 16; i++) { cellPlain= Klartext[k + i]; } byte[] cellCipher = encode16(cellPlain, key); für (int i = 0; i < cellCipher.length; i++) { ciphertext[k + i] = cellCipher; }
k += 16; }
Return-Ciphertext; }
/** * SMS4-Entschlüsselung ohne Begrenzung der Klartextlänge * * @param Chiffretext * @param Schlüssel * @return */ public static byte[] decodeSMS4(byte[] ciphertext, byte[] key) { byte[] Klartext = neues Byte[ciphertext.length];
int k = 0; int cipherLen = ciphertext.length; während (k + 16 <= cipherLen) { byte[] cellCipher = neues Byte[16]; für (int i = 0; Ich < 16; i++) { cellCipher= Chiffretext[k + i]; } byte[] cellPlain = decode16(cellCipher, key); für (int i = 0; i < cellPlain.length; i++) { plaintext[k + i] = cellPlain; }
k += 16; }
Klartext zurückgeben; }
/** * Entschlüsseln, um Klartextstrings zu erhalten * @param Chiffretext * @param Schlüssel * @return */ öffentliche statische Zeichenkettendecodierung SMS4toString(byte[] ciphertext, byte[] key) { byte[] Klartext = neues Byte[ciphertext.length]; Klartext = DekodierungsSMS4 (Chiffretext, Schlüssel); return new String (Klartext); }
/** * Nur 16-Bit-Klartext ist verschlüsselt * * @param Klartext * @param Schlüssel * @return */ private statische Byte[] encode16(byte[] Klartext, byte[] key) { byte[] Chiffre = neues Byte[16]; SMS4 sm4 = neue SMS4(); sm4.sms4 (Klartext, 16, Schlüssel, Chiffre, VERSCHLÜSSELN);
Return-Chiffre; }
/** * Nur 16-Bit-Chiffretext wird entschlüsselt * * @param Klartext * @param Schlüssel * @return */ private statische byte[] decode16(byte[] ciphertext, byte[] key) { byte[] plain = neues Byte[16]; SMS4 sm4 = neue SMS4(); sm4.sms4 (Ciphertext, 16, Schlüssel, Plain, DECRYPT);
kehrt unauffällig zurück; } Ich werde hier nicht nur 32-Bit-Klartextverschlüsselung einführen, die der Methode mit nur 16-Bit-Klartext sehr ähnlich ist.
Der grundlegende Algorithmus für Verschlüsselung und Entschlüsselung ohne Begrenzung der Länge des Klartexts basiert auf dieser Grundlage, nur 16 Bit zu verschlüsseln und zu entschlüsseln. Für Klartext größer als 16 Bit wird hier die Paketverschlüsselung verwendet. Wenn du auf Klartext wie 30 Bits triffst, die nicht durch 16 teilbar sind, ist eine Möglichkeit, sie zu füllen, indem du sie so lange ausfüllst, bis sie durch 16 teilbar ist. Grundsätzlich kann nur die kleinste Zahl durch 16 geteilt werden, natürlich, wenn man glücklich ist, spielt es keine Rolle, ob man sie größer macht, denn es ist das Abschlusssymbol.
Paketverschlüsselung besteht darin, jeden 16-Bit-Klartext einmal zu verschlüsseln und dann den verschlüsselten 16-Bit-Chiffretext zu einem neuen Chiffretext zusammenzusetzen. Im Verfahren der Entschlüsselung wird es zudem in ein einziges 16-Bit-Stück aufgeteilt, und dann werden mehrere dieser entschlüsselten Klartexte zu neuem Klartext wieder zusammengesetzt.
Anwendungsdemonstration:
Legende 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 };
String newString = Coding, hallo!; Klartext
byte[] enOut = SMS4.encodeSMS4(newString, key); wenn (enOut == null) { Rückgabe; }
System.out.println(Verschlüsselungsergebnis:); printBit(enOut);
byte[] deOut = SMS4.decodeSMS4(enOut, key); System.out.println( Entschlüsselungsergebnis (Return Byte[]) :); printBit(deOut);
String deOutStr = SMS4.decodeSMS4toString(enOut, key); System.out.println( Entschlüsseln Sie das Ergebnis (Return String): + deOutStr); |