Minimal teaching Java SM3 encryption algorithm

Before this article, a brief introduction to SM3 algorithm

SM3 algorithm: SM3 hash algorithm is a password hash algorithm independently designed in China, which is suitable for the generation and verification of digital signature and authentication message authentication code and the generation of random number in commercial cryptography applications. It can meet the security requirements of various cryptography applications. To ensure the security of the hash algorithm, the length of the hash value generated by the hash algorithm should not be too short. For example, if MD5 outputs a hash value of 128 bits, the output length of THE SHA-1 algorithm is 160 bits, and the output length of the SM3 algorithm is 256 bits. Therefore, SM3 algorithm is more secure than MD5 algorithm and SHA-1 algorithm.

This algorithm is suitable for digital signature and verification, message authentication code generation and random number generation in commercial cryptography applications, and can meet the security requirements of various cryptography applications. Used in SM2, SM9 standards. The algorithm generates a hash value of 256 bits by filling and iteratively compressing the input bit messages whose length is less than 2 ^ 64, using xOR, module, modular addition, shift, and, or, and not operations, which are composed of filling, iteration process, message expansion and compression functions. See SM3 standard for specific algorithms and examples.

If you are interested, you can go down to supplement yourself.

I used SM3 algorithm in the encryption of payment password

Situational encryption logic

First, the encryption logic, to show you:

First input a 6-digit password(password) by the numeric keypad, and then call the interface, and then get the password by the background, and then the password split, such as: 123456 disassemble 1,2,3,4,5,6 and then store the array

The specific decoding of the first step is then performed. For example, custom code table

The original data Converted data
0 aa
1 bb
2 cc
3 dd
4 ee
5 ff
6 gg
7 hh
8 ii
9 jj

According to different original data, it is first converted to the corresponding custom rules, and then assembled after encryption

For example: 1 Transcode to bb and then encrypt XXXXXX 2 Transcode to CC and then encrypt CCCCCC… In turn down

Then splice XXXXXXCCCCCC… In turn, joining together

Then do SM3 encryption for the last time after stitching the data

Figure out the EncryptionPassword that we finally need

All right, go straight to the code

Enter the theme

SM3 encryption requires pom.xml dependencies

There are two

<dependency> <groupId>org.bouncycastle</groupId> <artifactId>bcprov-jdk15on</artifactId> <version>1.62</version>  </dependency> <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-lang3</artifactId> < version > 3.9 < / version > < optional > true < / optional > < / dependency >Copy the code

After adding dependencies

My SM3 simple directory structure

Began to chew code

Speak from the top down

Sm3rule-class (Encryption rule class)

/** * Encryption rule *@author FYF
 * @date Created in 11:16 2020/6/4
 */
public enum SM3Rule {
    /** * transcoding rules correspond to */ as described above
    ZERO("0"."aa"),
    ONE("1"."bb"),
    TWO("2"."cc"),
    THREE("3"."dd"),
    FOUR("4"."ee"),
    FIVE("5"."ff"),
    SIX("6"."gg"),
    SEVEN("Seven"."hh"),
    EIGHT("8"."ii"),
    NINE("9"."jj");@Getter
    private String code;
    @Getter
    private String msg;

    SM3Rule(String code, String msg) {
        this.code = code;
        this.msg = msg;
    }

    public static String valueOfCode(String code) {
        for (SM3Rule sm3Rule : values()) {
            if (StringUtils.equals(code, sm3Rule.code)) {
                returnsm3Rule.msg; }}throw new IllegalStateException("Digital conversion exception"); }}Copy the code

This class is basically a simple enumeration class that encapsulates the transcoding rules that we want to use to extract the transcoding values through the valueOfCode method

Sm3util.class (SM3 algorithm tool class)

/** * SM3 encryption algorithm tools **@author FYF
 * @date Created in 16:02 2020/6/3
 */
@Slf4j
public class SM3Util {

    private static final String ENCODING = "UTF-8";

    static {
        Security.addProvider(new BouncyCastleProvider());
    }
    /** * Total of password encryption methods *@paramThe PWD password *@returnLogically encrypted return password */
    public static String pwdEncrypt(String pwd){
        if (StringUtils.isNotEmpty(pwd)){
            String pwdConvert = pwdEncryptAssembly(pwd);
            String encryptPwd = encrypt(pwdConvert);
            return encryptPwd;
        }
        throw new IllegalStateException("The password cannot be empty!");
    }

    /** * get the password number from the front end, then encrypt stitching *@paramThe PWD password *@returnEncrypted password */
    public static String pwdEncryptAssembly(String pwd) {
            StringBuffer stringPwd = new StringBuffer();
            for (char key : pwd.toCharArray()) {
                String s = SM3Rule.valueOfCode(String.valueOf(key));
                String encrypt = encrypt(s);
                stringPwd.append(encrypt);
            }
            String jsonPwd = stringPwd.toString();
            return jsonPwd.toUpperCase();
    }

    /** * sm3 algorithm encryption **@paramParamStr Specifies the string * to be encrypted@returnReturns an encrypted hexadecimal string of fixed length =32 */
    public static String encrypt(String paramStr) {
        // Converts the returned hash value to a hexadecimal string
        String resultHexString = "";
        try {
            // Convert a string to a byte array
            byte[] srcData = paramStr.getBytes(ENCODING);
            / / call the hash ()
            byte[] resultHash = hash(srcData);
            // Converts the returned hash value to a hexadecimal string
            resultHexString = ByteUtils.toHexString(resultHash);
            return resultHexString.toUpperCase();
        } catch (UnsupportedEncodingException e) {
           log.info("SM3 algorithm encryption failed:",e);
           throw new  IllegalStateException("SM3 algorithm encryption exception"); }}/** * returns a byte array of length =32 **@param srcData
     * @returnAn array of *@explainGenerates the corresponding hash value */
    public static byte[] hash(byte[] srcData) {

        try {
            SM3Digest digest = new SM3Digest();
            digest.update(srcData, 0, srcData.length);
            byte[] hash = new byte[digest.getDigestSize()];
            digest.doFinal(hash, 0);
            return hash;
        }catch (Exception e){
            log.info("Failed to return byte array:",e);
            throw new IllegalStateException("Return byte array exception"); }}/** * encrypt by key **@paramThe key key *@paramSrcData Encrypted byte array *@return
     * @explainSpecify key for encryption */
    public static byte[] hmac(byte[] key, byte[] srcData) {

        try {
            KeyParameter keyParameter = new KeyParameter(key);
            SM3Digest digest = new SM3Digest();
            HMac mac = new HMac(digest);
            mac.init(keyParameter);
            mac.update(srcData, 0, srcData.length);
            byte[] result = new byte[mac.getMacSize()];
            mac.doFinal(result, 0);
            return result;
        }catch (Exception e){
            log.info("Encryption by secret key failed:",e);
            throw new IllegalStateException("Encryption by secret key exception"); }}/** * Check whether the source data is consistent with the encrypted data **@paramSrcStr The original character string *@paramSm3HexString Hexadecimal string *@returnCheck result *@explainVerify that the original array and the generated hash array are the same array and that the two are the same data */
    public static boolean verify(String srcStr, String sm3HexString) {
        boolean flag = false;
        try {
            byte[] srcData = srcStr.getBytes(ENCODING);
            byte[] sm3Hash = ByteUtils.fromHexString(sm3HexString);
            byte[] newHash = hash(srcData);
            if (Arrays.equals(newHash, sm3Hash)) {
                flag = true;
            }
            return flag;
        } catch (UnsupportedEncodingException e) {
            log.info("Judge source data and encrypted data error:",e);
            throw new IllegalStateException("Determine source and encrypted data anomalies"); }}}Copy the code

This is the sm3Utils.class utility class that I’ve encapsulated, and the comments in it make each method very clear. And I’m done with exception catching.

The simple idea of encryption is: we take the foreground password, we divide it into an array, the array is looped and encrypted, and we put it into a StringBuffer, and when we’re done concatenating it, we take the StringBuffer that’s returned and we encrypt it, and the encryption turns the string into byte and then through certain hashing rules, Make the final layer of return. That’s the encrypted hash character that we end up with. (If you are interested, you can take a look at the underlying principles of the hash algorithm.)

The last word is our test class

Sm3utiltest.class (Test class)

I’m going to write a simple test class, which is not very formal, but actually write the main method to call the main function (pwdEncrypt method) and pass the parameters to encrypt. If YOU follow the TDD test specification, I’m going to lose a lot of things, but I’m sorry.

/ * * *@author FYF
 * @date Created in 15:27 2020/6/4
 */
@Slf4j
public class SM3UtilTest {

    public static final String PWD_LENGTH_EX_MSG = "The password must be 6 in length.";

    /** * Password */
    private String password;
    /** * Password length */
    private final Integer pwdLength=6;

    /** * after password encryption combination */
    private String pwdEncryptAssembly;

    /** * Password length */
    private Integer pwdSize;

    /** * Password encryption result */
    private String pwdEncrypt;

    @BeforeEach
    public void testbefore(a){
        password="135790";
        pwdSize=password.length();
        pwdEncryptAssembly=SM3Util.pwdEncryptAssembly(password);

    }

    @Test
    public void testEncrypt(a){
        if (pwdSize.equals(pwdLength)){
            assertAll("SM3 encryption",
            ()->{
                log.info("The password you entered :{}",password);
                log.info("Your password encryption combination and combination :{}",pwdEncryptAssembly);
                pwdEncrypt = SM3Util.pwdEncrypt(password);
                assertTrue(StringUtils.isNotBlank(pwdEncrypt));
                log.info("Final combination password result :{}",pwdEncrypt);
            });
        }else {
            log.info(Error message :{},PWD_LENGTH_EX_MSG); }}}Copy the code

Finally, my GitHub:

SM3 project algorithm complete project has been uploaded

Link: Fan Yifan’s GitHub (like to Star oh ~)

The author’s words

Mutual respect, mutual progress, thank you very much for everyone’s selfless spirit. Can let us Chinese IT more and more progress!

I am also very willing to listen to the opinions and suggestions of more leaders with an open mind, and communicate with everyone to make progress.

I’m Fan Yifan

A programmer who gets a little better every day

A programmer who doesn’t want to live on looks

== Your thumbs-up is my best encouragement! Thank you very much! = =