SMS4 Εισαγωγή:
Αυτός ο αλγόριθμος είναι ένας αλγόριθμος ομαδοποίησης. Ο αλγόριθμος έχει μήκος πακέτου 128 bit και μήκος κλειδιού 128 bit, που είναι 16 byte. Τόσο ο αλγόριθμος κρυπτογράφησης όσο και ο αλγόριθμος επέκτασης κλειδιού υιοθετούν μια μη γραμμική δομή επανάληψης 32 γύρων. Ο αλγόριθμος αποκρυπτογράφησης έχει την ίδια δομή με τον αλγόριθμο κρυπτογράφησης, με τη διαφορά ότι η σειρά χρήσης του στρογγυλού κλειδιού αντιστρέφεται και το κλειδί τροχού αποκρυπτογράφησης είναι η αντίστροφη σειρά του κλειδιού τροχού κρυπτογράφησης. Σε όλες τις βασικές του SMS4, θα δείτε ότι οι βασικές λειτουργίες κρυπτογράφησης και αποκρυπτογράφησης είναι οι ίδιες, αλλά απαιτείται ένα bit σημαίας τύπου int για να προσδιοριστεί εάν είναι κρυπτογραφημένο ή αποκρυπτογραφημένο.
Βασικά στοιχεία αλγορίθμου κρυπτογράφησης SMS4:
SMS4 δημόσιας τάξης {
ιδιωτικό στατικό τελικό int ENCRYPT = 1; ιδιωτικό στατικό τελικό int DECRYPT = 0; δημόσιος στατικός τελικός int ROUND = 32; ιδιωτικό στατικό τελικό 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) { επιστροφή x << y | x >>> (32 - y); }
private int ByteSub(int A) { επιστροφή (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) { επιστροφή B ^ Rotl(B, 2) ^ Rotl(B, 10) ^ Rotl(B, 18) ^ Rotl(B, 24); επιστροφή B^(B<<2|B>>>30)^(B<<10|B>>>22)^(B<<18|B>>>14)^(B<<24|B>>>8); }
ιδιωτικό int L2(int B) { επιστροφή B ^ Rotl(B, 13) ^ Rotl(B, 23); επιστροφή B^(B<<13|B>>>19)^(B<<23|B>>>9); }
void SMS4Crypt(byte[] Είσοδος, byte[] Έξοδος, int[] rk) { int r, μεσαίο, x0, x1, x2, x3; int[] x = νέος int[4]; int[] tmp = νέο int[4]; για (int i = 0; i < 4; i++) { tmp[0] = Είσοδος[0 + 4 * i] &; 0xff; tmp[1] = Είσοδος[1 + 4 * i] &; 0xff; tmp[2] = Είσοδος[2 + 4 * i] &; 0xff; tmp[3] = Είσοδος[3 + 4 * i] &; 0xff; x= tmp[0] << 24 | TMP[1] << 16 | TMP[2] << 8 | tmp[3]; Χ=(Είσοδος[0+4*i]<<24| Είσοδος[1+4*i]<<16| Είσοδος[2+4*i]<<8| Είσοδος[3+4*i]); } για (r = 0; r < 32; r += 4) { mid = x[1] ^ x[2] ^ x[3] ^ rk[r + 0]; mid = ByteSub(mid); x[0] = x[0] ^ L1(μεσαία); Χ4
mid = x[2] ^ x[3] ^ x[0] ^ rk[r + 1]; mid = ByteSub(mid); x[1] = x[1] ^ L1(μεσαία); Χ5
mid = x[3] ^ x[0] ^ x[1] ^ rk[r + 2]; mid = ByteSub(mid); x[2] = x[2] ^ L1(μεσαίο); Χ6
mid = x[0] ^ x[1] ^ x[2] ^ rk[r + 3]; mid = ByteSub(mid); x[3] = x[3] ^ L1(μεσαία); Χ7 }
ΑΝΤΙΣΤΡΟΦΗ για (int j = 0; j < 16; j += 4) { Έξοδος[j] = (byte) (x[3 - j / 4] >>> 24 &; 0xFF); Έξοδος[j + 1] = (byte) (x[3 - j / 4] >>> 16 &; 0xFF); Έξοδος[j + 2] = (byte) (x[3 - j / 4] >>> 8 &; 0xFF); Έξοδος[j + 3] = (byte) (x[3 - j / 4] &; 0xFF); } }
ιδιωτικό κενό SMS4KeyExt(byte[] Κλειδί, int[] rk, int CryptFlag) { int r, μεσαία; int[] x = νέος int[4]; int[] tmp = νέο int[4]; για (int i = 0; i < 4; i++) { tmp[0] = Κλειδί[0 + 4 * i] &; 0xFF; tmp[1] = Κλειδί[1 + 4 * i] &; 0xff; tmp[2] = Κλειδί[2 + 4 * i] &; 0xff; tmp[3] = Κλειδί[3 + 4 * i] &; 0xff; x= tmp[0] << 24 | TMP[1] << 16 | TMP[2] << 8 | tmp[3]; Χ=Κλειδί[0+4*i]<<24| Κλειδί[1+4*i]<<16| Κλειδί[2+4*i]<<8| Κλειδί[3+4*i]; } x[0] ^= 0xa3b1bac6; x[1] ^= 0x56aa3350; x[2] ^= 0x677d9197; x[3] ^= 0xb27022dc; για (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(μεσαία); rk0=Κ4
mid = x[2] ^ x[3] ^ x[0] ^ CK[r + 1]; mid = ByteSub(mid); rk[r + 1] = x[1] ^= L2(μεσαίο); rk1=K5
mid = x[3] ^ x[0] ^ x[1] ^ CK[r + 2]; mid = ByteSub(mid); rk[r + 2] = x[2] ^= L2(μεσαία); rk2=K6
mid = x[0] ^ x[1] ^ x[2] ^ CK[r + 3]; mid = ByteSub(mid); rk[r + 3] = x[3] ^= L2(μεσαία); rk3=K7 }
Αποκρυπτογραφήστε τη σειρά του κλειδιού τροχού: rk31, rk30,...,rk0 αν (CryptFlag == ΑΠΟΚΡΥΠΤΟΓΡΑΦΗΣΗ) { για (r = 0; r < 16; r++) { mid = rk[r]; rk[r] = rk[31 - r]; rk[31 - r] = μεσαία; } } }
public int sms4(byte[] in, int inLen, byte[] key, byte[] out, int CryptFlag) { int σημείο = 0; int[] round_key = νέος int[ROUND]; int[] round_key={0}; SMS4KeyExt(κλειδί, round_key, CryptFlag); byte[] input = νέο byte[16]; byte[] έξοδος = νέο byte[16];
ενώ (inLen >= BLOCK) { είσοδος = Arrays.copyOfRange(σε, σημείο, σημείο + 16); output=Arrays.copyOfRange(έξω, σημείο, σημείο+16); SMS4Crypt (είσοδος, έξοδος, round_key); System.arraycopy(έξοδος, 0, έξοδος, σημείο, BLOCK); inLen -= ΜΠΛΟΚ; σημείο += BLOCK; }
επιστροφή 0; }
}
Συσκευασμένη εξωτερική διεπαφή:
Με βάση αυτή τη βασική κλάση, οι κύριες διεπαφές είναι οι εξής:
ιδιωτικό στατικό byte[] encode16(byte[] απλό, byte[] κλειδί); ιδιωτικό στατικό byte[] decode16(byte[] κρυπτογράφηση, byte[] κλειδί); ιδιωτικό στατικό byte[] encode32(byte[] απλό, byte[] κλειδί); ιδιωτικό στατικό byte[] decode32(byte[] κρυπτογράφηση, κλειδί byte[]); δημόσιο στατικό byte[] encodeSMS4(byte[] απλό, byte[] κλειδί); δημόσιο στατικό byte[] αποκωδικοποίησηSMS4(byte[] κρυπτογράφηση, byte[] κλειδί); δημόσια στατική αποκωδικοποίηση συμβολοσειράςSMS4toString(byte[] κρυπτογράφηση, byte[] κλειδί);
Το encode16(byte[], byte[]) είναι μια διεπαφή για κρυπτογράφηση για 16-bit απλό κείμενο και κλειδιά 16-bit. ιδιωτικό στατικό byte[] decode16(byte[] κρυπτογράφηση, byte[] κλειδί): είναι μια διεπαφή για την αποκρυπτογράφηση κρυπτογραφημένου κειμένου 16-bit και κλειδιού 16-bit. ιδιωτικό στατικό byte[] encode32(byte[] απλό, byte[] κλειδί): Αυτή είναι μια διεπαφή που κρυπτογραφεί κλειδιά απλού κειμένου 32-bit και 16-bit. private static byte[] decode32(byte[] cipher, byte[] key): Αυτή είναι μια διεπαφή για την αποκρυπτογράφηση κρυπτογραφημένου κειμένου 32-bit και κλειδιών 16-bit. δημόσιο στατικό byte[] encodeSMS4(byte[] απλό, byte[] κλειδί): Αυτή είναι μια διεπαφή που κρυπτογραφεί απλό κείμενο και κλειδιά 16-bit με απεριόριστο αριθμό byte. δημόσιο στατικό byte[] decodeSMS4(byte[] κρυπτογράφηση, byte[] κλειδί): Αυτή είναι μια διεπαφή για την αποκρυπτογράφηση κρυπτογραφημένου κειμένου και κλειδιών 16-bit με απεριόριστο αριθμό byte. δημόσια στατική αποκωδικοποίηση συμβολοσειράςSMS4toString(byte[] κρυπτογράφηση, byte[] κλειδί): Αυτή είναι μια διεπαφή για την αποκρυπτογράφηση απεριόριστων byte κρυπτογραφημένου κειμένου και κλειδιών 16 bit. Κωδικός μεθόδου διεπαφής:
δημόσιο στατικό byte[] encodeSMS4(Συμβολοσειρά απλού κειμένου, κλειδί byte[]) { if (απλό κείμενο == null || plaintext.equals()) { επιστροφή null; } για (int i = plaintext.getBytes().length % 16; i < 16; i++) { απλό κείμενο += ''; }
επιστροφή SMS4.encodeSMS4(plaintext.getBytes(), κλειδί); }
/** * Κρυπτογράφηση SMS4 με απεριόριστο μήκος απλού κειμένου * * @param απλό κείμενο * @param κλειδί * @return */ δημόσιο στατικό byte[] encodeSMS4(byte[] απλό κείμενο, byte[] κλειδί) { byte[] ciphertext = νέο byte[plaintext.length];
ακέραιο k = 0; int plainLen = απλό κείμενο.μήκος; ενώ (k + 16 <= plainLen) { byte[] cellPlain = νέο byte[16]; για (int i = 0; i < 16; i++) { κελίΠεδιάδα= απλό κείμενο[k + i]; } byte[] cellCipher = encode16(cellPlain, κλειδί); για (int i = 0; i < cellCipher.length; i++) { κρυπτογραφημένο κείμενο[k + i] = cellCipher; }
k += 16; }
επιστροφή κρυπτογραφημένου κειμένου. }
/** * Αποκρυπτογράφηση SMS4 χωρίς περιορισμό στο μήκος απλού κειμένου * * @param κρυπτογραφημένο κείμενο * @param κλειδί * @return */ δημόσιο στατικό byte[] αποκωδικοποίησηSMS4(byte[] κρυπτογραφημένο κείμενο, byte[] κλειδί) { byte[] plaintext = νέο byte[ciphertext.length];
ακέραιο k = 0; int cipherLen = ciphertext.length; ενώ (k + 16 <= cipherLen) { byte[] cellCipher = νέο byte[16]; για (int i = 0; i < 16; i++) { cellΚρυπτογράφηση= κρυπτογραφημένο κείμενο[k + i]; } byte[] cellPlain = αποκωδικοποίηση16(cellCipher, κλειδί); για (int i = 0; i < cellPlain.length; i++) { απλό κείμενο[k + i] = κελίΑπλό; }
k += 16; }
επιστροφή απλού κειμένου. }
/** * Αποκρυπτογράφηση για λήψη συμβολοσειρών απλού κειμένου * @param κρυπτογραφημένο κείμενο * @param κλειδί * @return */ δημόσια στατική αποκωδικοποίηση συμβολοσειράςSMS4toString(byte[] κρυπτογραφημένο κείμενο, byte[] κλειδί) { byte[] plaintext = νέο byte[ciphertext.length]; απλό κείμενο = αποκωδικοποίησηSMS4 (κρυπτογραφημένο κείμενο, κλειδί); επιστροφή νέα συμβολοσειρά(απλό κείμενο); }
/** * Μόνο το απλό κείμενο 16-bit είναι κρυπτογραφημένο * * @param απλό κείμενο * @param κλειδί * @return */ ιδιωτικό στατικό byte[] encode16(byte[] απλό κείμενο, byte[] κλειδί) { byte[] κρυπτογράφηση = νέο byte[16]; SMS4 sm4 = νέο SMS4(); sm4.sms4 (απλό κείμενο, 16, κλειδί, κρυπτογράφηση, κρυπτογράφηση);
κρυπτογράφηση επιστροφής? }
/** * Μόνο το κρυπτογραφημένο κείμενο 16-bit αποκρυπτογραφείται * * @param απλό κείμενο * @param κλειδί * @return */ ιδιωτικό στατικό byte[] decode16(byte[] κρυπτογραφημένο κείμενο, byte[] κλειδί) { byte[] απλό = νέο byte[16]; SMS4 sm4 = νέο SMS4(); sm4.sms4 (κρυπτογραφημένο κείμενο, 16, κλειδί, απλό, ΑΠΟΚΡΥΠΤΟΓΡΑΦΗΣΗ);
Επιστροφή σκέτη. } Δεν θα εισαγάγω μόνο κρυπτογράφηση απλού κειμένου 32-bit εδώ, η οποία μοιάζει πολύ με τη μέθοδο μόνο απλού κειμένου 16-bit.
Ο βασικός αλγόριθμος κρυπτογράφησης και αποκρυπτογράφησης χωρίς περιορισμό του μήκους του απλού κειμένου βασίζεται σε αυτή τη βάση κρυπτογράφησης και αποκρυπτογράφησης μόνο 16 bit. Για απλό κείμενο μεγαλύτερο από 16 bit, εδώ χρησιμοποιείται κρυπτογράφηση πακέτων. Εάν συναντήσετε απλό κείμενο όπως 30 bit που δεν μπορούν να διαιρεθούν με το 16, ένας τρόπος για να το γεμίσετε είναι να το φτιάξετε μέχρι να διαιρεθεί με το 16. Κατ' αρχήν, μόνο ο μικρότερος αριθμός μπορεί να διαιρεθεί με το 16, φυσικά, αν είστε ευχαριστημένοι, δεν έχει σημασία αν τον κάνετε μεγαλύτερο, γιατί είναι το σύμβολο κλεισίματος.
Η κρυπτογράφηση πακέτων είναι η κρυπτογράφηση κάθε απλού κειμένου 16-bit μία φορά και, στη συνέχεια, η επανασυναρμολόγηση του κρυπτογραφημένου κειμένου 16-bit σε ένα νέο κρυπτογραφημένο κείμενο. Κατά τη διαδικασία της αποκρυπτογράφησης, χωρίζεται επίσης σε ένα ενιαίο κομμάτι 16-bit και, στη συνέχεια, πολλά από αυτά τα αποκρυπτογραφημένα απλά κείμενα επανασυναρμολογούνται σε νέο απλό κείμενο.
Επίδειξη χρήσης:
Κλειδί 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 };
Συμβολοσειρά newString = Κωδικοποίηση, γεια!; Απλό κείμενο
byte[] enOut = SMS4.encodeSMS4(newString, κλειδί); αν (enOut == null) { επιστροφή; }
System.out.println(αποτέλεσμα κρυπτογράφησης:); printBit(enOut);
byte[] deOut = SMS4.decodeSMS4(enOut, κλειδί); System.out.println( αποτέλεσμα αποκρυπτογράφησης (byte επιστροφής[]) :); printBit(deOut);
Συμβολοσειρά deOutStr = SMS4.decodeSMS4toString(enOut, κλειδί); System.out.println( Αποκρυπτογράφηση του αποτελέσματος (return String): + deOutStr); |