Java SMS4 Encryption Algorithm

Source: Internet
Author: User

Java SMS4 Encryption Algorithm
Introduction to SMS4:

This algorithm is a grouping algorithm. The Group length of this algorithm is 128 bits, and the key length is 128 bits, that is, 16 bytes. Both the encryption algorithm and the key extension algorithm adopt a 32-round nonlinear iteration structure. The decryption algorithm has the same structure as the encryption algorithm, but the Use order of the wheel key is the opposite. The decryption wheel key is the reverse order of the encryption wheel key. In all the basic classes of SMS4, you will see that the basic functions of encryption and decryption are the same, but an int-type flag is required to determine whether encryption or decryption is performed.

Basic SMS4 encryption algorithm class:

 

Public class SMS4 {private static final int ENCRYPT = 1; private static final int DECRYPT = 0; public static final int ROUND = 32; private static final int 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}; private int [] CK = {0x00070e15, 0x1c232a31, clerk, clerk, 0x70777e85, 0x8c939aa1, clerk, 0xc4cbd2d9, clerk, 0xfc030a11, clerk, clerk, expires, 0xa4abb2b9, 0xc0c7ced5, expires, 0x848b9299, 0xa0a7aeb5, expires, 0x10171e25, expires, 0x484f565d, 0x646b7279}; private int Rotl (int x, int y) {return x <y | x> (32-y);} private int ByteSub (int) {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) {return 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) {return 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 = new int [4]; int [] tmp = new int [4]; for (int I = 0; I <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 [I] = tmp [0] <24 | tmp [1] <16 | tmp [2] <8 | tmp [3]; // x [I] = (Input [0 + 4 * I] <24 | Input [1 + 4 * I] <16 | Input [2 + 4 * I] <8 | Input [3 + 4 * I]);} for (r = 0; r <32; r + = 4) {mid = x [1] ^ x [2] ^ x [3] ^ rk [r + 0]; mid = ByteSub (mid); x [0] = x [0] ^ L1 (mid ); // x4 mid = x [2] ^ x [3] ^ x [0] ^ rk [r + 1]; mid = ByteSub (mid ); x [1] = x [1] ^ L1 (mid ); // x5 mid = x [3] ^ x [0] ^ x [1] ^ rk [r + 2]; mid = ByteSub (mid ); x [2] = x [2] ^ L1 (mid ); // x6 mid = x [0] ^ x [1] ^ x [2] ^ rk [r + 3]; mid = ByteSub (mid ); x [3] = x [3] ^ L1 (mid); // x7} // Reverse for (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 = new int [4]; int [] tmp = new int [4]; for (int I = 0; I <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 [I] = tmp [0] <24 | tmp [1] <16 | tmp [2] <8 | tmp [3]; // x [I] = 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; for (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} // the sequence in which the wheel keys are used for decryption: rk31, rk30 ,..., rk0 if (CryptFlag = DECRYPT) {for (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) {int point = 0; int [] round_key = new int [ROUND]; // int [] round_key = {0}; SMS4KeyExt (key, round_key, CryptFlag); byte [] input = new byte [16]; byte [] output = new byte [16]; while (inLen> = BLOCK) {input = Arrays. copyOfRange (in, point, point + 16); // output = Arrays. copyOfRange (out, point, point + 16); SMS4Crypt (input, output, round_key); System. arraycopy (output, 0, out, point, BLOCK); inLen-= BLOCK; point + = BLOCK;} return 0 ;}}

Encapsulate External Interfaces:

Encapsulate Interfaces Based on this basic class. The main interfaces are as follows:

 

private static byte[] encode16(byte[] plain, byte[] key);private static byte[] decode16(byte[] cipher, byte[] key);private static byte[] encode32(byte[] plain, byte[] key);private static byte[] decode32(byte[] cipher, byte[] key);public static byte[] encodeSMS4(byte[] plain, byte[] key);public static byte[] decodeSMS4(byte[] cipher, byte[] key);public static String decodeSMS4toString(byte[] cipher, byte[] key);

Encode16 (byte [], byte []) is an interface for 16-bit plaintext and 16-bit key encryption;
Private static byte [] decode16 (byte [] cipher, byte [] key): an interface for decryption of 16-bit passwords and 16-bit keys;
Private static byte [] encode32 (byte [] plain, byte [] key): an interface for encrypting 32-bit plain text and 16-bit keys;
Private static byte [] decode32 (byte [] cipher, byte [] key): an interface for decryption of 32-bit passwords and 16-bit keys;
Public static byte [] encodeSMS4 (byte [] plain, byte [] key): It is an interface for encrypting plaintext and 16-bit keys with no limit on the number of bytes;
Public static byte [] decodeSMS4 (byte [] cipher, byte [] key): It is an interface for decryption of non-limited-byte passwords and 16-bit keys;
Public static String decodeSMS4toString (byte [] cipher, byte [] key): It is an interface for decrypting non-limited bytes of passwords and 16-bit keys;
Interface Method Code:

 

Public static byte [] encodeSMS4 (String plaintext, byte [] key) {if (plaintext = null | plaintext. equals () {return null;} for (int I = plaintext. getBytes (). length % 16; I <16; I ++) {plaintext + = '';} return SMS4.encodeSMS4 (plaintext. getBytes (), key );} /*** SMS4 encryption with unlimited plaintext length ** @ param plaintext * @ param key * @ return */public static byte [] encodeSMS4 (byte [] plaintext, byte [] key) {byte [] ciphertext = new byte [plaintext. length]; int k = 0; int plainLen = plaintext. length; while (k + 16 <= plainLen) {byte [] cellPlain = new byte [16]; for (int I = 0; I <16; I ++) {cellPlain [I] = plaintext [k + I];} byte [] cellCipher = encode16 (cellPlain, key); for (int I = 0; I <cellCipher. length; I ++) {ciphertext [k + I] = cellCipher [I];} k + = 16;} return ciphertext ;} /*** decrypt SMS4 with unlimited plaintext length ** @ param ciphertext * @ param key * @ return */public static byte [] decodeSMS4 (byte [] ciphertext, byte [] key) {byte [] plaintext = new byte [ciphertext. length]; int k = 0; int cipherLen = ciphertext. length; while (k + 16 <= cipherLen) {byte [] cellCipher = new byte [16]; for (int I = 0; I <16; I ++) {cellCipher [I] = ciphertext [k + I];} byte [] cellPlain = decode16 (cellCipher, key); for (int I = 0; I <cellPlain. length; I ++) {plaintext [k + I] = cellPlain [I];} k + = 16;} return plaintext;}/*** decrypt, obtain the plaintext String * @ param ciphertext * @ param key * @ return */public static String decodeSMS4toString (byte [] ciphertext, byte [] key) {byte [] plaintext = new byte [ciphertext. length]; plaintext = decodeSMS4 (ciphertext, key); return new String (plaintext );} /*** only encrypt 16-bit plaintext ** @ param plaintext * @ param key * @ return */private static byte [] encode16 (byte [] plaintext, byte [] key) {byte [] cipher = new byte [16]; SMS4 sm4 = new SMS4 (); sm4.sms4 (plaintext, 16, key, cipher, ENCRYPT); return cipher ;} /*** only decrypt 16-bit ciphertext ** @ param plaintext * @ param key * @ return */private static byte [] decode16 (byte [] ciphertext, byte [] key) {byte [] plain = new byte [16]; SMS4 sm4 = new SMS4 (); sm4.sms4 (ciphertext, 16, key, plain, DECRYPT); return plain ;}
Only 32-bit plaintext encryption is not introduced here, which is similar to the 16-bit plaintext method.

 

The basic algorithm for encryption and decryption without the limit of the plaintext length is based on the 16-bit encryption and decryption. For more than 16-bit plain text, group encryption is used here. If there is a plain text that cannot be divisible by 16 characters such as 30 characters, here we use a complement method to complete it until it is divisible by 16 characters. In principle, it is to add only the smallest number that can be divided by 16. Of course, if you are happy, it doesn't matter if you increase the number, because it is the terminator ''.

In group encryption, each 16-bit plaintext is encrypted once, and then the 16-bit ciphertext encrypted is combined into a new ciphertext. In the decryption process, it is also first split into a single 16-bit, and then the decrypted plaintext is combined into a new plaintext.

 

Example:

 

// Key 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, hello !; // Plaintext byte [] enOut = SMS4.encodeSMS4 (newString, key); if (enOut = null) {return;} System. out. println (encryption result :); printBit (enOut); byte [] deOut = SMS4.decodeSMS4 (enOut, key); System. out. println (decryption result (return byte []) :); printBit (deOut); String deOutStr = SMS4.decodeSMS4toString (enOut, key); System. out. println (decryption result (return String): + deOutStr );

 

 

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.