首页 > 编程语言 >Java加解密-SM4国密算法

Java加解密-SM4国密算法

时间:2022-10-09 16:25:28浏览次数:54  
标签:Java ctx SM4 加解密 length new byte null

  • SM4国密算法简介
  • SM4依赖包
  • SM4类
  • SM4_Context类
  • SecuritySM4类

=================================== SM4国密算法简介

与DES和AES算法相似,国密SM4算法是一种分组加密算法。SM4分组密码算法是一种迭代分组密码算法,由加解密算法和密钥扩展算法组成。

SM4是一种Feistel结构的分组密码算法,其分组长度和密钥长度均为128bits。加密算法和密钥扩展算法迭代轮数均为32轮。SM4加解密过程的算法相同但是轮密钥的使用顺序相反。

SM4密码算法使用模2加和循环移位作为基本运算。

密钥扩展算法:SM4算法使用128位的加密密钥,并采用32轮迭代加密结构,每一轮加密使用一个32位的轮密钥,总共使用32个轮密钥。因此需要使用密钥扩展算法,从加密密钥中产生32个轮密钥。

=================================== SM4依赖包

<dependency>
    <groupId>org.bouncycastle</groupId>
    <artifactId>bcprov-jdk15on</artifactId>
    <version>1.56</version>
</dependency>

 

=================================== SM4类

package com.taoxw.utils.security.SM4;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;

public class SM4 {
    protected static final int SM4_ENCRYPT = 1;
    protected static final int SM4_DECRYPT = 0;
    protected static final byte[] SboxTable = new byte[]{-42, -112, -23, -2, -52, -31, 61, -73, 22, -74, 20, -62, 40, -5, 44, 5, 43, 103, -102, 118, 42, -66, 4, -61, -86, 68, 19, 38, 73, -122, 6, -103, -100, 66, 80, -12, -111, -17, -104, 122, 51, 84, 11, 67, -19, -49, -84, 98, -28, -77, 28, -87, -55, 8, -24, -107, -128, -33, -108, -6, 117, -113, 63, -90, 71, 7, -89, -4, -13, 115, 23, -70, -125, 89, 60, 25, -26, -123, 79, -88, 104, 107, -127, -78, 113, 100, -38, -117, -8, -21, 15, 75, 112, 86, -99, 53, 30, 36, 14, 94, 99, 88, -47, -94, 37, 34, 124, 59, 1, 33, 120, -121, -44, 0, 70, 87, -97, -45, 39, 82, 76, 54, 2, -25, -96, -60, -56, -98, -22, -65, -118, -46, 64, -57, 56, -75, -93, -9, -14, -50, -7, 97, 21, -95, -32, -82, 93, -92, -101, 52, 26, 85, -83, -109, 50, 48, -11, -116, -79, -29, 29, -10, -30, 46, -126, 102, -54, 96, -64, 41, 35, -85, 13, 83, 78, 111, -43, -37, 55, 69, -34, -3, -114, 47, 3, -1, 106, 114, 109, 108, 91, 81, -115, 27, -81, -110, -69, -35, -68, 127, 17, -39, 92, 65, 31, 16, 90, -40, 10, -63, 49, -120, -91, -51, 123, -67, 45, 116, -48, 18, -72, -27, -76, -80, -119, 105, -105, 74, 12, -106, 119, 126, 101, -71, -15, 9, -59, 110, -58, -124, 24, -16, 125, -20, 58, -36, 77, 32, 121, -18, 95, 62, -41, -53, 57, 72};
    protected static final int[] FK = new int[]{-1548633402, 1453994832, 1736282519, -1301273892};
    protected static final int[] CK = new int[]{462357, 472066609, 943670861, 1415275113, 1886879365, -1936483679, -1464879427, -993275175, -521670923, -66909679, 404694573, 876298825, 1347903077, 1819507329, -2003855715, -1532251463, -1060647211, -589042959, -117504499, 337322537, 808926789, 1280531041, 1752135293, -2071227751, -1599623499, -1128019247, -656414995, -184876535, 269950501, 741554753, 1213159005, 1684763257};
 
    public SM4() {
    }
 
    private long GET_ULONG_BE(byte[] b, int i) {
        long n = (long)(b[i] & 255) << 24 | (long)((b[i + 1] & 255) << 16) | (long)((b[i + 2] & 255) << 8) | (long)(b[i + 3] & 255) & 4294967295L;
        return n;
    }
 
    private void PUT_ULONG_BE(long n, byte[] b, int i) {
        b[i] = (byte)((int)(255L & n >> 24));
        b[i + 1] = (byte)((int)(255L & n >> 16));
        b[i + 2] = (byte)((int)(255L & n >> 8));
        b[i + 3] = (byte)((int)(255L & n));
    }
 
    private long SHL(long x, int n) {
        return (x & -1L) << n;
    }
 
    private long ROTL(long x, int n) {
        return this.SHL(x, n) | x >> 32 - n;
    }
 
    private void SWAP(long[] sk, int i) {
        long t = sk[i];
        sk[i] = sk[31 - i];
        sk[31 - i] = t;
    }
 
    private byte sm4Sbox(byte inch) {
        int i = inch & 255;
        byte retVal = SboxTable[i];
        return retVal;
    }
 
    private long sm4Lt(long ka) {
        long bb = 0L;
        long c = 0L;
        byte[] a = new byte[4];
        byte[] b = new byte[4];
        this.PUT_ULONG_BE(ka, a, 0);
        b[0] = this.sm4Sbox(a[0]);
        b[1] = this.sm4Sbox(a[1]);
        b[2] = this.sm4Sbox(a[2]);
        b[3] = this.sm4Sbox(a[3]);
        bb = this.GET_ULONG_BE(b, 0);
        c = bb ^ this.ROTL(bb, 2) ^ this.ROTL(bb, 10) ^ this.ROTL(bb, 18) ^ this.ROTL(bb, 24);
        return c;
    }
 
    private long sm4F(long x0, long x1, long x2, long x3, long rk) {
        return x0 ^ this.sm4Lt(x1 ^ x2 ^ x3 ^ rk);
    }
 
    private long sm4CalciRK(long ka) {
        long bb = 0L;
        long rk = 0L;
        byte[] a = new byte[4];
        byte[] b = new byte[4];
        this.PUT_ULONG_BE(ka, a, 0);
        b[0] = this.sm4Sbox(a[0]);
        b[1] = this.sm4Sbox(a[1]);
        b[2] = this.sm4Sbox(a[2]);
        b[3] = this.sm4Sbox(a[3]);
        bb = this.GET_ULONG_BE(b, 0);
        rk = bb ^ this.ROTL(bb, 13) ^ this.ROTL(bb, 23);
        return rk;
    }
 
    private void sm4_setkey(long[] SK, byte[] key) {
        long[] MK = new long[4];
        long[] k = new long[36];
        int i = 0;
        MK[0] = this.GET_ULONG_BE(key, 0);
        MK[1] = this.GET_ULONG_BE(key, 4);
        MK[2] = this.GET_ULONG_BE(key, 8);
        MK[3] = this.GET_ULONG_BE(key, 12);
        k[0] = MK[0] ^ (long)FK[0];
        k[1] = MK[1] ^ (long)FK[1];
        k[2] = MK[2] ^ (long)FK[2];
 
        for(k[3] = MK[3] ^ (long)FK[3]; i < 32; ++i) {
            k[i + 4] = k[i] ^ this.sm4CalciRK(k[i + 1] ^ k[i + 2] ^ k[i + 3] ^ (long)CK[i]);
            SK[i] = k[i + 4];
        }
 
    }
 
    private void sm4_one_round(long[] sk, byte[] input, byte[] output) {
        int i = 0;
        long[] ulbuf = new long[36];
        ulbuf[0] = this.GET_ULONG_BE(input, 0);
        ulbuf[1] = this.GET_ULONG_BE(input, 4);
        ulbuf[2] = this.GET_ULONG_BE(input, 8);
 
        for(ulbuf[3] = this.GET_ULONG_BE(input, 12); i < 32; ++i) {
            ulbuf[i + 4] = this.sm4F(ulbuf[i], ulbuf[i + 1], ulbuf[i + 2], ulbuf[i + 3], sk[i]);
        }
 
        this.PUT_ULONG_BE(ulbuf[35], output, 0);
        this.PUT_ULONG_BE(ulbuf[34], output, 4);
        this.PUT_ULONG_BE(ulbuf[33], output, 8);
        this.PUT_ULONG_BE(ulbuf[32], output, 12);
    }
 
    private byte[] padding(byte[] input, int mode) {
        if (input == null) {
            return null;
        } else if (input.length % 16 == 0) {
            return input;
        } else {
            byte[] ret = (byte[])null;
            if (mode == 1) {
                int p = 16 - input.length % 16;
                ret = new byte[input.length + p];
                System.arraycopy(input, 0, ret, 0, input.length);
 
                for(int i = 0; i < p; ++i) {
                    ret[input.length + i] = 0;
                }
            } else {
                int p = input[input.length - 1];
                ret = new byte[input.length - p];
                System.arraycopy(input, 0, ret, 0, input.length - p);
            }
 
            return ret;
        }
    }
 
    protected void sm4_setkey_enc(SM4_Context ctx, byte[] key) throws Exception {
        if (ctx == null) {
            throw new Exception("ctx is null!");
        } else if (key != null && key.length == 16) {
            ctx.mode = 1;
            this.sm4_setkey(ctx.sk, key);
        } else {
            throw new Exception("key error!");
        }
    }
 
    protected void sm4_setkey_dec(SM4_Context ctx, byte[] key) throws Exception {
        if (ctx == null) {
            throw new Exception("ctx is null!");
        } else if (key != null && key.length == 16) {
            ctx.mode = 0;
            this.sm4_setkey(ctx.sk, key);
 
            for(int i = 0; i < 16; ++i) {
                this.SWAP(ctx.sk, i);
            }
 
        } else {
            throw new Exception("key error!");
        }
    }
 
    protected byte[] sm4_crypt_ecb(SM4_Context ctx, byte[] input) throws Exception {
        if (input == null) {
            throw new Exception("input is null!");
        } else {
            if (ctx.isPadding && ctx.mode == 1) {
                input = this.padding(input, 1);
            }
 
            int length = input.length;
            ByteArrayInputStream bins = new ByteArrayInputStream(input);
 
            ByteArrayOutputStream bous;
            byte[] output;
            for(bous = new ByteArrayOutputStream(); length > 0; length -= 16) {
                output = new byte[16];
                byte[] out = new byte[16];
                bins.read(output);
                this.sm4_one_round(ctx.sk, output, out);
                bous.write(out);
            }
 
            output = bous.toByteArray();
            if (ctx.isPadding && ctx.mode == 0) {
                output = this.padding(output, 0);
            }
 
            bins.close();
            bous.close();
            return output;
        }
    }
 
    protected byte[] sm4_crypt_cbc(SM4_Context ctx, byte[] iv, byte[] input) throws Exception {
        if (iv != null && iv.length == 16) {
            if (input == null) {
                throw new Exception("input is null!");
            } else {
                if (ctx.isPadding && ctx.mode == 1) {
                    input = this.padding(input, 1);
                }
 
                int length = input.length;
                ByteArrayInputStream bins = new ByteArrayInputStream(input);
                ByteArrayOutputStream bous = new ByteArrayOutputStream();
                byte[] temp;
                byte[] out;
                int i;
                if (ctx.mode != 1) {
                    for(temp = new byte[16]; length > 0; length -= 16) {
                        out = new byte[16];
                        out = new byte[16];
                        byte[] out1 = new byte[16];
                        bins.read(out);
                        System.arraycopy(out, 0, temp, 0, 16);
                        this.sm4_one_round(ctx.sk, out, out);
 
                        for(i = 0; i < 16; ++i) {
                            out1[i] = (byte)(out[i] ^ iv[i]);
                        }
 
                        System.arraycopy(temp, 0, iv, 0, 16);
                        bous.write(out1);
                    }
                } else {
                    while(length > 0) {
                        temp = new byte[16];
                        out = new byte[16];
                        out = new byte[16];
                        bins.read(temp);
 
                        for(i = 0; i < 16; ++i) {
                            out[i] = (byte)(temp[i] ^ iv[i]);
                        }
 
                        this.sm4_one_round(ctx.sk, out, out);
                        System.arraycopy(out, 0, iv, 0, 16);
                        bous.write(out);
                        length -= 16;
                    }
                }
 
                temp = bous.toByteArray();
//                if (ctx.isPadding) {
//                    int var10000 = ctx.mode;
//                }
 
                bins.close();
                bous.close();
                return temp;
            }
        } else {
            throw new Exception("iv error!");
        } 
    }
}

 

=================================== SM4_Context类

package com.taoxw.utils.security.SM4;

public class SM4_Context {
    
    public int mode = 1;
    public long[] sk = new long[32];
    public boolean isPadding = true;
 
    protected SM4_Context() { }
 
    /**
     * 加密
     * @param plainText  参数
     * @param keyBytes  随机码
     * @return
     */
    public byte[] EncryptByte(byte[] plainText,byte[] keyBytes) {
        if (keyBytes != null && keyBytes.length == 16) {
            if (plainText != null && plainText.length > 0) {
                try {
                    SM4_Context ctx = new SM4_Context();
                    ctx.isPadding = true;
                    ctx.mode = 1;
                    SM4 sm4 = new SM4();
                    sm4.sm4_setkey_enc(ctx, keyBytes);
                    byte[] encrypted = sm4.sm4_crypt_ecb(ctx, plainText);
                    return encrypted;
                } catch (Exception var6) {
                    var6.printStackTrace();
                    return null;
                }
            } else {
                return null;
            }
        } else {
            return null;
        }
    }
 
    /**
     * 解密
     * @param cipherText 密文
     * @param keyBytes 随机码
     * @return
     */
    public byte[] DecryptStrByte(byte[] cipherText,byte[] keyBytes) {
        if (keyBytes != null && keyBytes.length == 16) {
            if (cipherText != null && cipherText.length > 0 && cipherText.length % 16 == 0) {
                try {
                    SM4_Context ctx = new SM4_Context();
                    ctx.isPadding = true;
                    ctx.mode = 0;
                    SM4 sm4 = new SM4();
                    sm4.sm4_setkey_dec(ctx, keyBytes);
                    byte[] decrypted = sm4.sm4_crypt_ecb(ctx, cipherText);
                    int decryptedLen = decrypted.length;
 
                    for (int i = decrypted.length - 1; i >= 0 && decrypted[i] == 0; --decryptedLen) {
                        --i;
                    }
 
                    byte[] temp = new byte[decryptedLen];
                    System.arraycopy(decrypted, 0, temp, 0, decryptedLen);
                    return temp;
                } catch (Exception var8) {
                    var8.printStackTrace();
                    return null;
                }
            } else {
                return null;
            }
        } else {
            return null;
        }
    }
 
    protected byte[] encryptData_CBC(byte[] ivBytes, byte[] keyBytes, byte[] plainText) {
        if (keyBytes != null && keyBytes.length != 0 && keyBytes.length % 16 == 0) {
            if (plainText != null && plainText.length > 0) {
                if (ivBytes != null && ivBytes.length > 0) {
                    try {
                        SM4_Context ctx = new SM4_Context();
                        ctx.isPadding = true;
                        ctx.mode = 1;
                        SM4 sm4 = new SM4();
                        sm4.sm4_setkey_enc(ctx, keyBytes);
                        byte[] encrypted = sm4.sm4_crypt_cbc(ctx, ivBytes, plainText);
                        return encrypted;
                    } catch (Exception var7) {
                        var7.printStackTrace();
                        return null;
                    }
                } else {
                    return null;
                }
            } else {
                return null;
            }
        } else {
            return null;
        }
    }
 
    protected byte[] decryptData_CBC(byte[] ivBytes, byte[] keyBytes, byte[] cipherText) {
        if (keyBytes != null && keyBytes.length != 0 && keyBytes.length % 16 == 0) {
            if (cipherText != null && cipherText.length > 0) {
                if (ivBytes != null && ivBytes.length > 0) {
                    try {
                        SM4_Context ctx = new SM4_Context();
                        ctx.isPadding = true;
                        ctx.mode = 0;
                        SM4 sm4 = new SM4();
                        sm4.sm4_setkey_dec(ctx, keyBytes);
                        byte[] decrypted = sm4.sm4_crypt_cbc(ctx, ivBytes, cipherText);
                        return decrypted;
                    } catch (Exception var7) {
                        var7.printStackTrace();
                        return null;
                    }
                } else {
                    return null;
                }
            } else {
                return null;
            }
        } else {
            return null;
        }
    }
}

 

=================================== SecuritySM4类

package com.taoxw.utils.security.SM4;

import javax.xml.bind.DatatypeConverter;

import org.bouncycastle.util.encoders.Hex;

public class SecuritySM4 {
    /**
     * SM4加密
     * @param str 参数
     * @param key 随机码
     * @return
     */
    public static String EncryptStr(String str,String key) {
        return DatatypeConverter.printHexBinary(new SM4_Context().EncryptByte(str.getBytes(),key.getBytes()));
    }
    /**
     * 解密
     * @param cipherStrings  密文
     * @param keyStr    随机码
     * @return
     */
    public static String DecryptStr(String cipherStrings,String keyStr) {
        String result = "";
        SM4_Context aa=new SM4_Context();
//      byte[] cc="00".getBytes();
        byte[] dd="00".getBytes();
 
        byte[] cipherText = Hex.decode(cipherStrings);
        byte[] keyBytes = keyStr.getBytes();
 
        try {
 
            dd= aa.DecryptStrByte(cipherText,keyBytes);
            result = new String(dd);
        } catch (Exception e) {
        }
        return result;
    }
}

 

=================================== SecuritySM4单元测试

        parms.put("custName", "张三");
        parms.put("certNum", "411322000000000000");
        String str = parms.toJSONString();
        System.out.println("参数:" + str);
        //key必须是16位
        String key ="TAxH5p1vs3ePYABC";
        String ncECBData = SecuritySM4.EncryptStr(str, key);
        System.out.println("加密:"+ncECBData);
        String plainTextEncripted = SecuritySM4.DecryptStr(ncECBData,key);
        System.out.println("解密:"+plainTextEncripted);

 

标签:Java,ctx,SM4,加解密,length,new,byte,null
From: https://www.cnblogs.com/taoxw/p/16772538.html

相关文章

  • Java 多线程(三)静态代理模式
    静态代理模式:1.真实角色和代理角色实现同一个接口2.代理角色要代理真实角色3.代理角色可以做真实角色做不了的事4.真实角色专注做自己的事publicclassStaticProxy......
  • Java开发页面接口过程中,应该注意的点
    列表接口1、查询条件是否需要去除前后空格;2、列表的时间格式是否正确;有的显示2022-07-28这种格式,有的显示:2022-07-2719:00:003、在前端传递时间的参数时,若定义的是Da......
  • Java语言中多态的机制
    1.方法解析Class文件的编译过程中,不包含传统编译中的连接步骤,一切方法的调用在Class文件中存储的都只是符号引用,而不是方法在实际运行时内存布局中的入口地址。这个特性......
  • 【Java复健指南03】递归思想
    【递归】递归重要规则1.执行一个方法时,就创建一个新的受保护的独立空间(栈空间)方法的局部变量是独立的,不会相互影响,比如n变量如果方法中使用的是引用类型变量(比......
  • java序列化
    一、序列化与反序列化序列化:指堆内存中的java对象数据,通过某种方式把对存储到磁盘文件中,或者传递给其他网络节点(网络传输)。这个过程称为序列化,通常是指将数据结构或对象转......
  • 003Java的诞生
    003Java的诞生1、计算机语言发展史(1)第一代语言机器语言我们都知道计算机的基本计算方式都是基于二进制的方式。二进制:010111001010110010110100这种代码是直接输......
  • Java虚拟机详解(五)------JVM参数
    JVM参数有很多,其实我们直接使用默认的JVM参数,不去修改都可以满足大多数情况。但是如果你想在有限的硬件资源下,部署的系统达到最大的运行效率,那么进行相关的JVM参数设置是必......
  • 【Java复健指南01】简介与数组
    写在最前学习Java已经是很久之前的事情了,因为技术栈的转变,很久没有使用Java正经地开发过项目。对于该语言的理解也是停留在表面,因此萌生了重新学习的念头。一方面是为刷......
  • Java实现多线程
    Java实现多线程的方式有4种分别是继承Thread类,实现Runnable,Callable接口和通过线程池提交线程任务。其中实现Callable接口的方式可以获取返回值。1.继承Thread类通过继......
  • 浏览器中javascript简易实现json数据保存到客户端
    思路很简单,就是利用Blob、URL.createObjectURL()方法和<a>便签的HTML5新属性download来模拟远端文件下载保存。下面直接上代码savePath:function(){varme......