This article is a mirror article of machine translation, please click here to jump to the original article.

View: 16332|Reply: 4

[Algorithm] SMS4 algorithm, which is a symmetric block cryptography algorithm

[Copy link]
Posted on 12/8/2015 9:49:35 PM | | |
This is a block cryptography algorithm, but he uses a lot of things, and now there is a specific source code on the Internet, but this code still has a certain research value, if you are also interested in this, you can come in and communicate and learn together. In fact, it doesn't make any sense to give you a complete code, but I still attach the full code address to the http://www.2cto.com/kf/201501/369374.html
There is also an S box in it, which is very important, which is used in the DES algorithm, so my colleague's suggestion to me is to understand the S box of the DES algorithm clearly, so that I can know what the specification in this SMS4 algorithm is talking about? The specification is not attached.





Previous:It seems that this place has not been updated for a long time, and I will update the C language every day in the future.
Next:C language, full version video
Posted on 12/8/2015 10:19:05 PM |

SMS4 Introduction:

This algorithm is a grouping algorithm. The algorithm has a packet length of 128 bits and a key length of 128 bits, which is 16 bytes. Both the encryption algorithm and the key expansion algorithm adopt a 32-round nonlinear iteration structure. The decryption algorithm has the same structure as the encryption algorithm, except that the order of use of the round key is reversed, and the decryption wheel key is the reverse order of the encryption wheel key. In all the base classes of SMS4, you will see that the base functions of encryption and decryption are the same, but an int-type flag bit is needed to determine whether it is encrypted or decrypted.

SMS4 encryption algorithm basics:



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, 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) {
        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= tmp[0] << 24 | tmp[1] << 16 | tmp[2] << 8 | tmp[3];
            // x=(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= 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;
        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
        }

        Decrypt the order of the wheel key: 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;
    }
}

Packaged external interface:

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 encryption for 16-bit plaintext and 16-bit keys;
private static byte[] decode16(byte[] cipher, byte[] key): is an interface for decrypting 16-bit ciphertext and 16-bit key;
private static byte[] encode32(byte[] plain, byte[] key): This is an interface that encrypts 32-bit plaintext and 16-bit keys.
private static byte[] decode32(byte[] cipher, byte[] key): This is an interface for decrypting 32-bit ciphertext and 16-bit keys.
public static byte[] encodeSMS4(byte[] plain, byte[] key): This is an interface that encrypts plaintext and 16-bit keys with an unlimited number of bytes.
public static byte[] decodeSMS4(byte[] cipher, byte[] key): This is an interface for decrypting ciphertext and 16-bit keys with an unlimited number of bytes.
public static String decodeSMS4toString(byte[] cipher, byte[] key): This is an interface for decrypting unlimited bytes of ciphertext 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= plaintext[k + i];
            }
            byte[] cellCipher = encode16(cellPlain, key);
            for (int i = 0; i < cellCipher.length; i++) {
                ciphertext[k + i] = cellCipher;
            }
            
            k += 16;
        }

        return ciphertext;
    }

    /**
     * SMS4 decryption with no limit on 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= ciphertext[k + i];
            }
            byte[] cellPlain = decode16(cellCipher, key);
            for (int i = 0; i < cellPlain.length; i++) {
                plaintext[k + i] = cellPlain;
            }
            
            k += 16;
        }
        
        return plaintext;
    }

    /**
     * Decrypt to obtain plaintext strings
     * @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 16-bit plaintext is encrypted
     *
     * @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 16-bit ciphertext is decrypted
     *
     * @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;
    }
I won't introduce only 32-bit plaintext encryption here, which is very similar to the method of only 16-bit plaintext.


The basic algorithm for encryption and decryption without limiting the length of the plaintext is based on this basis of encrypting and decrypting only 16 bits. For plaintext larger than 16 bits, packet encryption is used here. If you encounter plaintext like 30 bits that cannot be divisible by 16, a way to fill it up is to make it up until it is divisible by 16. In principle, only the smallest number can be divided by 16, of course, if you are happy, it doesn't matter if you make it bigger, because it is the closing symbol.

Packet encryption is to encrypt each 16-bit plaintext once, and then reassemble the encrypted 16-bit ciphertext into a new ciphertext. In the process of decryption, it is also split into a single 16-bit piece, and then several of these decrypted plaintext are reassembled into new plaintext.



Usage demonstration:



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!; Plain text
        
        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(
Decrypt the result (return String):
+ deOutStr);
 Landlord| Posted on 12/8/2015 10:25:41 PM |
Xiao Zhazha Posted on 2015-12-8 22:19
SMS4 Introduction:

This algorithm is a grouping algorithm. The algorithm has a packet length of 128 bits and a key length of 128 bits, which is 16 bytes. ...

Are you copying the face inside? I have run this algorithm on the computer several times, but I am still not familiar with C# in Java debugging, and I may not know his every step in detail, and I have not yet figured out the principle of his work details. java, know how to debug every variable of it?
Posted on 12/8/2015 10:40:48 PM |

It should be to set the breakpoint, myeclipse breakpoint F5 key and F6 key are single-step debugging, F5 is step into, that is, enter the line code to execute, F6 is step over, that is, execute the line code, jump to the next line
 Landlord| Posted on 12/8/2015 11:07:37 PM |
Published on 2015-12-8 22:40
It should be to set the breakpoint, myeclipse breakpoint F5 key and F6 key are both single-step debugging, F5 is step into, that is, enter the code of this line to execute ...

I definitely know, but I don't know his specific process, and I don't know when and where I will get to what step in the specification. It would be nice if you understood
Disclaimer:
All software, programming materials or articles published by Code Farmer Network are only for learning and research purposes; The above content shall not be used for commercial or illegal purposes, otherwise, users shall bear all consequences. The information on this site comes from the Internet, and copyright disputes have nothing to do with this site. You must completely delete the above content from your computer within 24 hours of downloading. If you like the program, please support genuine software, purchase registration, and get better genuine services. If there is any infringement, please contact us by email.

Mail To:help@itsvse.com