Java实现国密算法SM2,SM3,SM4,并且实现ECB和CBC模式

Java实现国密算法SM2,SM3,SM4,并且实现ECB和CBC模式代码中实现了电码本ECB模式和密文分组连接CBC模式,SM3.java和SM4.java为算法实现类,utils的都是根据实现类写的工具,可以根据需要调用杂凑算法SM3的杂凑功能获得杂凑值

代码中实现了电码本ECB模式和密文分组连接CBC模式,SM3.java和SM4.java为算法实现类,utils的都是根据实现类写的工具,可以根据需要调用杂凑算法SM3的杂凑功能获得杂凑值。

Java实现国密算法SM2,SM3,SM4,并且实现ECB和CBC模式

Java实现国密算法SM2,SM3,SM4,并且实现ECB和CBC模式

SM4.java中

sm4_crypt_ecb(SM4_Context ctx, byte[] input)      ECB模式加解密方法,根据密钥判断加解密功能

sm4_crypt_cbc(SM4_Context ctx, byte[] iv, byte[] input)      CBC模式加解密方法,根据密钥判断加解密功能

加密解密通过如下方法:

sm4_setkey_enc(SM4_Context ctx, byte[] key)  设置加密密钥调用上述方法,实现加密

sm4_setkey_dec(SM4_Context ctx, byte[] key)  设置解密密钥调用上述方法,实现解密

需要导入的包为bcprov-jdk16  我用的版本是bcprov-jdk16-1.46

maven中配置依赖:

<dependency>
	<groupId>org.bouncycastle</groupId>
	<artifactId></artifactId>
	<version>1.46</version>
</dependency>

package中class目录如下:

Java实现国密算法SM2,SM3,SM4,并且实现ECB和CBC模式

chiper.java

import java.math.BigInteger;  
import org.bouncycastle.crypto.AsymmetricCipherKeyPair;  
import org.bouncycastle.crypto.params.ECPrivateKeyParameters;  
import org.bouncycastle.crypto.params.ECPublicKeyParameters;  
import org.bouncycastle.math.ec.ECPoint; 

public class Cipher {
	 private int ct;  
	    private ECPoint p2;  
	    private SM3Digest sm3keybase;  
	    private SM3Digest sm3c3;  
	    private byte key[];  
	    private byte keyOff;  
	  
	    public Cipher()   
	    {  
	        this.ct = 1;  
	        this.key = new byte[32];  
	        this.keyOff = 0;  
	    }  
	  
	    private void Reset()   
	    {  
	        this.sm3keybase = new SM3Digest();  
	        this.sm3c3 = new SM3Digest();  
	          
	        byte p[] = Util.byteConvert32Bytes(p2.getX().toBigInteger());  
	        this.sm3keybase.update(p, 0, p.length);  
	        this.sm3c3.update(p, 0, p.length);  
	          
	        p = Util.byteConvert32Bytes(p2.getY().toBigInteger());  
	        this.sm3keybase.update(p, 0, p.length);  
	        this.ct = 1;  
	        NextKey();  
	    }  
	  
	    private void NextKey()   
	    {  
	        SM3Digest sm3keycur = new SM3Digest(this.sm3keybase);  
	        sm3keycur.update((byte) (ct >> 24 & 0xff));  
	        sm3keycur.update((byte) (ct >> 16 & 0xff));  
	        sm3keycur.update((byte) (ct >> 8 & 0xff));  
	        sm3keycur.update((byte) (ct & 0xff));  
	        sm3keycur.doFinal(key, 0);  
	        this.keyOff = 0;  
	        this.ct++;  
	    }  
	  
	    public ECPoint Init_enc(SM2 sm2, ECPoint userKey)   
	    {  
	        AsymmetricCipherKeyPair key = sm2.ecc_key_pair_generator.generateKeyPair();  
	        ECPrivateKeyParameters ecpriv = (ECPrivateKeyParameters) key.getPrivate();  
	        ECPublicKeyParameters ecpub = (ECPublicKeyParameters) key.getPublic();  
	        BigInteger k = ecpriv.getD();  
	        ECPoint c1 = ecpub.getQ();  
	        this.p2 = userKey.multiply(k);  
	        Reset();  
	        return c1;  
	    }  
	  
	    public void Encrypt(byte data[])   
	    {  
	        this.sm3c3.update(data, 0, data.length);  
	        for (int i = 0; i < data.length; i++)   
	        {  
	            if (keyOff == key.length)  
	            {  
	                NextKey();  
	            }  
	            data[i] ^= key[keyOff++];  
	        }  
	    }  
	  
	    public void Init_dec(BigInteger userD, ECPoint c1)  
	    {  
	        this.p2 = c1.multiply(userD);  
	        Reset();  
	    }  
	  
	    public void Decrypt(byte data[])   
	    {  
	        for (int i = 0; i < data.length; i++)  
	        {  
	            if (keyOff == key.length)  
	            {  
	                NextKey();  
	            }  
	            data[i] ^= key[keyOff++];  
	        }  
	  
	        this.sm3c3.update(data, 0, data.length);  
	    }  
	  
	    public void Dofinal(byte c3[])   
	    {  
	        byte p[] = Util.byteConvert32Bytes(p2.getY().toBigInteger());  
	        this.sm3c3.update(p, 0, p.length);  
	        this.sm3c3.doFinal(c3, 0);  
	        Reset();  
	    }  
}

SM2.java

import java.math.BigInteger;  
import java.security.SecureRandom;  
  
import org.bouncycastle.crypto.generators.ECKeyPairGenerator;  
import org.bouncycastle.crypto.params.ECDomainParameters;  
import org.bouncycastle.crypto.params.ECKeyGenerationParameters;  
import org.bouncycastle.math.ec.ECCurve;  
import org.bouncycastle.math.ec.ECFieldElement;  
import org.bouncycastle.math.ec.ECPoint;  
import org.bouncycastle.math.ec.ECFieldElement.Fp;  

public class SM2 {
	 //测试参数  
//  public static final String[] ecc_param = {  
//      "8542D69E4C044F18E8B92435BF6FF7DE457283915C45517D722EDB8B08F1DFC3",   
//      "787968B4FA32C3FD2417842E73BBFEFF2F3C848B6831D7E0EC65228B3937E498",   
//      "63E4C6D3B23B0C849CF84241484BFE48F61D59A5B16BA06E6E12D1DA27C5249A",   
//      "8542D69E4C044F18E8B92435BF6FF7DD297720630485628D5AE74EE7C32E79B7",   
//      "421DEBD61B62EAB6746434EBC3CC315E32220B3BADD50BDC4C4E6C147FEDD43D",   
//      "0680512BCBB42C07D47349D2153B70C4E5D7FDFCBFA36EA1A85841B9E46E09A2"   
//  };  
      
    //正式参数  
    public static String[] ecc_param = {   
        "FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFF",  
        "FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFC",  
        "28E9FA9E9D9F5E344D5A9E4BCF6509A7F39789F515AB8F92DDBCBD414D940E93",  
        "FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFF7203DF6B21C6052B53BBF40939D54123",  
        "32C4AE2C1F1981195F9904466A39C9948FE30BBFF2660BE1715A4589334C74C7",  
        "BC3736A2F4F6779C59BDCEE36B692153D0A9877CC62A474002DF32E52139F0A0"  
    };  
  
    public static SM2 Instance()   
    {  
        return new SM2();  
    }  
  
    public final BigInteger ecc_p;  
    public final BigInteger ecc_a;  
    public final BigInteger ecc_b;  
    public final BigInteger ecc_n;  
    public final BigInteger ecc_gx;  
    public final BigInteger ecc_gy;  
    public final ECCurve ecc_curve;  
    public final ECPoint ecc_point_g;  
    public final ECDomainParameters ecc_bc_spec;  
    public final ECKeyPairGenerator ecc_key_pair_generator;  
    public final ECFieldElement ecc_gx_fieldelement;  
    public final ECFieldElement ecc_gy_fieldelement;  
  
    public SM2()   
    {  
        this.ecc_p = new BigInteger(ecc_param[0], 16);  
        this.ecc_a = new BigInteger(ecc_param[1], 16);  
        this.ecc_b = new BigInteger(ecc_param[2], 16);  
        this.ecc_n = new BigInteger(ecc_param[3], 16);  
        this.ecc_gx = new BigInteger(ecc_param[4], 16);  
        this.ecc_gy = new BigInteger(ecc_param[5], 16);  
  
        this.ecc_gx_fieldelement = new Fp(this.ecc_p, this.ecc_gx);  
        this.ecc_gy_fieldelement = new Fp(this.ecc_p, this.ecc_gy);  
  
        this.ecc_curve = new ECCurve.Fp(this.ecc_p, this.ecc_a, this.ecc_b);  
        this.ecc_point_g = new ECPoint.Fp(this.ecc_curve, this.ecc_gx_fieldelement, this.ecc_gy_fieldelement);  
  
        this.ecc_bc_spec = new ECDomainParameters(this.ecc_curve, this.ecc_point_g, this.ecc_n);  
  
        ECKeyGenerationParameters ecc_ecgenparam;  
        ecc_ecgenparam = new ECKeyGenerationParameters(this.ecc_bc_spec, new SecureRandom());  
  
        this.ecc_key_pair_generator = new ECKeyPairGenerator();  
        this.ecc_key_pair_generator.init(ecc_ecgenparam);  
    }  
}

SM2Utils.java

import java.io.IOException;  
import java.math.BigInteger;  
import org.bouncycastle.crypto.AsymmetricCipherKeyPair;  
import org.bouncycastle.crypto.params.ECPrivateKeyParameters;  
import org.bouncycastle.crypto.params.ECPublicKeyParameters;  
import org.bouncycastle.math.ec.ECPoint; 

public class SM2Utils {
	  //生成随机秘钥对  
    public static void generateKeyPair(){  
        SM2 sm2 = SM2.Instance();  
        AsymmetricCipherKeyPair key = sm2.ecc_key_pair_generator.generateKeyPair();  
        ECPrivateKeyParameters ecpriv = (ECPrivateKeyParameters) key.getPrivate();  
        ECPublicKeyParameters ecpub = (ECPublicKeyParameters) key.getPublic();  
        BigInteger privateKey = ecpriv.getD();  
        ECPoint publicKey = ecpub.getQ();  
          
        System.out.println("公钥: " + Util.byteToHex(publicKey.getEncoded()));  
        System.out.println("私钥: " + Util.byteToHex(privateKey.toByteArray()));  
    }  
      
    //数据加密  
    public static String encrypt(byte[] publicKey, byte[] data) throws IOException  
    {  
        if (publicKey == null || publicKey.length == 0)  
        {  
            return null;  
        }  
          
        if (data == null || data.length == 0)  
        {  
            return null;  
        }  
          
        byte[] source = new byte[data.length];  
        System.arraycopy(data, 0, source, 0, data.length);  
          
        Cipher cipher = new Cipher();  
        SM2 sm2 = SM2.Instance();  
        ECPoint userKey = sm2.ecc_curve.decodePoint(publicKey);  
          
        ECPoint c1 = cipher.Init_enc(sm2, userKey);  
        cipher.Encrypt(source);  
        byte[] c3 = new byte[32];  
        cipher.Dofinal(c3);  
          
//      System.out.println("C1 " + Util.byteToHex(c1.getEncoded()));  
//      System.out.println("C2 " + Util.byteToHex(source));  
//      System.out.println("C3 " + Util.byteToHex(c3));  
        //C1 C2 C3拼装成加密字串  
        return Util.byteToHex(c1.getEncoded()) + Util.byteToHex(source) + Util.byteToHex(c3);  
          
    }  
      
    //数据解密  
    public static byte[] decrypt(byte[] privateKey, byte[] encryptedData) throws IOException  
    {  
        if (privateKey == null || privateKey.length == 0)  
        {  
            return null;  
        }  
          
        if (encryptedData == null || encryptedData.length == 0)  
        {  
            return null;  
        }  
        //加密字节数组转换为十六进制的字符串 长度变为encryptedData.length * 2  
        String data = Util.byteToHex(encryptedData);  
        /***分解加密字串 
         * (C1 = C1标志位2位 + C1实体部分128位 = 130) 
         * (C3 = C3实体部分64位  = 64) 
         * (C2 = encryptedData.length * 2 - C1长度  - C2长度) 
         */  
        byte[] c1Bytes = Util.hexToByte(data.substring(0,130));  
        int c2Len = encryptedData.length - 97;  
        byte[] c2 = Util.hexToByte(data.substring(130,130 + 2 * c2Len));  
        byte[] c3 = Util.hexToByte(data.substring(130 + 2 * c2Len,194 + 2 * c2Len));  
          
        SM2 sm2 = SM2.Instance();  
        BigInteger userD = new BigInteger(1, privateKey);  
          
        //通过C1实体字节来生成ECPoint  
        ECPoint c1 = sm2.ecc_curve.decodePoint(c1Bytes);  
        Cipher cipher = new Cipher();  
        cipher.Init_dec(userD, c1);  
        cipher.Decrypt(c2);  
        cipher.Dofinal(c3);  
          
        //返回解密结果  
        return c2;  
    }  
      
    public static void main(String[] args) throws Exception   
    {  
        //生成密钥对  
        generateKeyPair();  
          
        String plainText = "ererfeiisgod";  
        byte[] sourceData = plainText.getBytes();  
          
        //下面的秘钥可以使用generateKeyPair()生成的秘钥内容  
        // 国密规范正式私钥  
        String prik = "3690655E33D5EA3D9A4AE1A1ADD766FDEA045CDEAA43A9206FB8C430CEFE0D94";  
        // 国密规范正式公钥  
        String pubk = "04F6E0C3345AE42B51E06BF50B98834988D54EBC7460FE135A48171BC0629EAE205EEDE253A530608178A98F1E19BB737302813BA39ED3FA3C51639D7A20C7391A";  
          
        System.out.println("加密: ");  
        String cipherText = SM2Utils.encrypt(Util.hexToByte(pubk), sourceData);  
        System.out.println(cipherText);  
        System.out.println("解密: ");  
        plainText = new String(SM2Utils.decrypt(Util.hexToByte(prik), Util.hexToByte(cipherText)));  
        System.out.println(plainText);  
          
    }  
}

SM3.java

public class SM3 {
	 public static final byte[] iv = { 0x73, (byte) 0x80, 0x16, 0x6f, 0x49,  
		        0x14, (byte) 0xb2, (byte) 0xb9, 0x17, 0x24, 0x42, (byte) 0xd7,  
		        (byte) 0xda, (byte) 0x8a, 0x06, 0x00, (byte) 0xa9, 0x6f, 0x30,  
		        (byte) 0xbc, (byte) 0x16, 0x31, 0x38, (byte) 0xaa, (byte) 0xe3,  
		        (byte) 0x8d, (byte) 0xee, 0x4d, (byte) 0xb0, (byte) 0xfb, 0x0e,  
		        0x4e };  
		      
		    public static int[] Tj = new int[64];  
		      
		    static   
		    {  
		        for (int i = 0; i < 16; i++)   
		        {  
	

今天的文章Java实现国密算法SM2,SM3,SM4,并且实现ECB和CBC模式分享到此就结束了,感谢您的阅读。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://bianchenghao.cn/70458.html

(0)
编程小号编程小号

相关推荐

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注