SM2椭圆曲线公钥密码算法的JAVA实现-程序员宅基地

技术标签: python  java  操作系统  

package com.zpc.cryptography;


import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.math.BigInteger;
import java.util.Enumeration;


import org.bouncycastle.asn1.ASN1EncodableVector;
import org.bouncycastle.asn1.ASN1InputStream;
import org.bouncycastle.asn1.ASN1Integer;
import org.bouncycastle.asn1.ASN1Primitive;
import org.bouncycastle.asn1.ASN1Sequence;
import org.bouncycastle.asn1.DERInteger;
import org.bouncycastle.asn1.DEROctetString;
import org.bouncycastle.asn1.DEROutputStream;
import org.bouncycastle.asn1.DERSequence;
import org.bouncycastle.math.ec.ECPoint;
import org.bouncycastle.util.encoders.Base64;


public class SM2Utils {


public static byte[] 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);

    DERInteger x = new DERInteger(c1.getX().toBigInteger());
    DERInteger y = new DERInteger(c1.getY().toBigInteger());
    DEROctetString derDig = new DEROctetString(c3);
    DEROctetString derEnc = new DEROctetString(source);
    ASN1EncodableVector v = new ASN1EncodableVector();
    v.add(x);
    v.add(y);
    v.add(derDig);
    v.add(derEnc);
    DERSequence seq = new DERSequence(v);
    ByteArrayOutputStream bos = new ByteArrayOutputStream();
    DEROutputStream dos = new DEROutputStream(bos);
    dos.writeObject(seq);
    return bos.toByteArray();
}

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;
    }

    byte[] enc = new byte[encryptedData.length];
    System.arraycopy(encryptedData, 0, enc, 0, encryptedData.length);

    SM2 sm2 = SM2.Instance();
    BigInteger userD = new BigInteger(1, privateKey);

    ByteArrayInputStream bis = new ByteArrayInputStream(enc);
    ASN1InputStream dis = new ASN1InputStream(bis);
    ASN1Primitive derObj = dis.readObject();
    //DERObject derObj = dis.readObject();
    ASN1Sequence asn1 = (ASN1Sequence) derObj;
    //DERInteger x = (DERInteger) asn1.getObjectAt(0);
    //DERInteger y = (DERInteger) asn1.getObjectAt(1);
    ASN1Integer x = (ASN1Integer) asn1.getObjectAt(0);
    ASN1Integer y = (ASN1Integer) asn1.getObjectAt(1);
    ECPoint c1 = sm2.ecc_curve.createPoint(x.getValue(), y.getValue(), true);

    Cipher cipher = new Cipher();
    cipher.Init_dec(userD, c1);
    DEROctetString data = (DEROctetString) asn1.getObjectAt(3);
    enc = data.getOctets();
    cipher.Decrypt(enc);
    byte[] c3 = new byte[32];
    cipher.Dofinal(c3);
    return enc;
}

/**
 * 签名
 *
 * @param userId
 * @param privateKey
 * @param sourceData
 * @return
 * @throws IOException
 */
public static byte[] sign(byte[] userId, byte[] privateKey, byte[] sourceData) throws IOException {

    if (privateKey == null || privateKey.length == 0) {
        return null;
    }

    if (sourceData == null || sourceData.length == 0) {
        return null;
    }

    SM2 sm2 = SM2.Instance();
    BigInteger userD = new BigInteger(privateKey);
    //System.out.println("userD: " + userD.toString(16));
    //System.out.println("");

    ECPoint userKey = sm2.ecc_point_g.multiply(userD);
    //System.out.println("椭圆曲线点X: " + userKey.getX().toBigInteger().toString(16));
    //System.out.println("椭圆曲线点Y: " + userKey.getY().toBigInteger().toString(16));
    //System.out.println("");


    byte[] z = sm2.sm2GetZ(userId, userKey);
    //System.out.println("SM3摘要Z: " + Util.getHexString(z));
    //System.out.println("");

    //System.out.println("M: " + Util.getHexString(sourceData));
    //System.out.println("");

    SM3Digest sm3 = new SM3Digest();
    sm3.update(z, 0, z.length);
    sm3.update(sourceData, 0, sourceData.length);
    byte[] md = new byte[32];
    sm3.doFinal(md, 0);

    //System.out.println("SM3摘要值: " + Util.getHexString(md));
    //System.out.println("");

    SM2Result sm2Result = new SM2Result();
    sm2.sm2Sign(md, userD, userKey, sm2Result);
    //System.out.println("r: " + sm2Result.r.toString(16));
    //System.out.println("s: " + sm2Result.s.toString(16));
    //System.out.println("");

    DERInteger d_r = new DERInteger(sm2Result.r);
    DERInteger d_s = new DERInteger(sm2Result.s);
    ASN1EncodableVector v2 = new ASN1EncodableVector();
    v2.add(d_r);
    v2.add(d_s);
    DERSequence sign = new DERSequence(v2);
    //DERObject sign = new DERSequence(v2);
    //byte[] signdata = sign.getDEREncoded();
    byte[] signdata = sign.getEncoded();

    return signdata;
}

@SuppressWarnings("unchecked")
public static boolean verifySign(byte[] userId, byte[] publicKey, byte[] sourceData, byte[] signData) throws IOException {

    if (publicKey == null || publicKey.length == 0) {
        return false;
    }

    if (sourceData == null || sourceData.length == 0) {
        return false;
    }

    SM2 sm2 = SM2.Instance();
    ECPoint userKey = sm2.ecc_curve.decodePoint(publicKey);

    SM3Digest sm3 = new SM3Digest();
    byte[] z = sm2.sm2GetZ(userId, userKey);
    sm3.update(z, 0, z.length);
    sm3.update(sourceData, 0, sourceData.length);
    byte[] md = new byte[32];
    sm3.doFinal(md, 0);
    //System.out.println("SM3摘要值: " + Util.getHexString(md));
    //System.out.println("");

    ByteArrayInputStream bis = new ByteArrayInputStream(signData);
    ASN1InputStream dis = new ASN1InputStream(bis);
    //DERObject derObj = dis.readObject();
    ASN1Primitive derObj = dis.readObject();
    Enumeration<ASN1Integer> e = ((ASN1Sequence) derObj).getObjects();
    BigInteger r = e.nextElement().getValue();
    BigInteger s = e.nextElement().getValue();
    SM2Result sm2Result = new SM2Result();
    sm2Result.r = r;
    sm2Result.s = s;
    //System.out.println("r: " + sm2Result.r.toString(16));
    //System.out.println("s: " + sm2Result.s.toString(16));
    //System.out.println("");


    sm2.sm2Verify(md, userKey, sm2Result.r, sm2Result.s, sm2Result);
    return sm2Result.r.equals(sm2Result.R);
}

public static void main(String[] args) throws Exception {


    String plainText = "message digest";
    //1.源数据数组
    byte[] sourceData = plainText.getBytes();

    // 国密规范测试私钥
    String prik = "128B2FA8BD433C6C068C8D803DFF79792A519A55171B1B650C23661D15897263";
    //2.私钥先转十六进制,然后进行Base64编码
    String prikS = new String(Base64.encode(Util.hexToByte(prik)));
    System.out.println("转换后的私钥:prikS====" + prikS);
    //System.out.println("");

    // 国密规范测试用户ID
    String userId = "[email protected]";

    //获取userId十六进制字符串
    System.out.println("十六进制userId: " + Util.getHexString(userId.getBytes()));
    //System.out.println("");

    //System.out.println("签名: ");
    //3.用userId和私钥,对明文数据签名(userid、prik、sourceData)
    byte[] c = SM2Utils.sign(userId.getBytes(), Base64.decode(prikS.getBytes()), sourceData);
    System.out.println("SM2签名后值====" + Util.getHexString(c));
    //System.out.println("");

    // 国密规范测试公钥
    String pubk = "040AE4C7798AA0F119471BEE11825BE46202BB79E2A5844495E97C04FF4DF2548A7C0240F88F1CD4E16352A73C17B7F16F07353E53A176D684A9FE0C6BB798E857";
    String pubkS = new String(Base64.encode(Util.hexToByte(pubk)));
    System.out.println("转换后的公钥pubkS====" + pubkS);
    //System.out.println("");


    //System.out.println("验签: ");
    //4.用公钥进行验签(userId、pubk、sourceData、签名数据c)
    boolean vs = SM2Utils.verifySign(userId.getBytes(), Base64.decode(pubkS.getBytes()), sourceData, c);
    System.out.println("验签结果: " + vs);
    //System.out.println("");

    //System.out.println("加密: ");
    //5.SM2加密算法
    byte[] cipherText = SM2Utils.encrypt(Base64.decode(pubkS.getBytes()), sourceData);
    System.out.println("SM2加密后结果===" + new String(Base64.encode(cipherText)));
    System.out.println("");

    //System.out.println("解密: ");
    //6.SM2解密算法
    plainText = new String(SM2Utils.decrypt(Base64.decode(prikS.getBytes()), cipherText));
    System.out.println("解密后获取的结果===" + plainText);

}
}

 两个相关JAR从这里下载

https://pan.baidu.com/s/1ggDmn3H

https://pan.baidu.com/s/1mkcK3nM

转载于:https://my.oschina.net/u/568367/blog/1605097

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/weixin_34205826/article/details/92005152

智能推荐

2022年全网最细 AndroidStudio 安装配置学习笔记_android studio 2022-程序员宅基地

文章浏览阅读3.2k次,点赞4次,收藏22次。超详细的 AndroidStudio 安装笔记_android studio 2022

cache(三)——Cache实例的get与set_cache.getcache-程序员宅基地

文章浏览阅读7.6k次。在Spring中配置了Ehcache,由EhCacheManagerFactoryBean创建并且启用了一个CacheManager实例来管理Cache,那么CacheManager是怎么管理Cache的?Cache是由谁创建的?org.springframework.cache. CacheManager:源码public interface CacheManager { @N..._cache.getcache

安全函数之缓冲区溢出_安全函数缓冲区大小-程序员宅基地

文章浏览阅读2.4k次。公司的大佬说之前某大厂为了安全函数的替换耗资10亿美金。可想安全很重要,安全函数很重要,对于我们做系统软件的来说很重要。为什么要替换成安全函数,这里面就涉及到了一种漏洞攻击,缓冲区溢出攻击。缓冲区溢出是指当计算机向缓冲区内填充数据位数时超过了缓冲区本身的容量,溢出的数据覆盖在合法数据上。理想的情况是:程序会检查数据长度,而且并不允许输入超过缓冲区长度的字符。但是绝大多数程序都会假设数据长度总是与所分配的储存空间相匹配,这就为缓冲区溢出埋下隐患。操作系统所使用的缓冲区,又被称为**“堆栈”**,在各个._安全函数缓冲区大小

thinkphp6 基于redis 的消息队列 queue_php redis 消息队列-程序员宅基地

文章浏览阅读474次。注意: 必须要带任务名,我这边不带任务名,无法监听到消息。可配合supervisor使用,保证进程常驻。使用 listen 监听。_php redis 消息队列

Lombok注解_lombok链式注解-程序员宅基地

文章浏览阅读3.7k次。Lombok注解val: final 像动态语言一样,声明一个fianl的变量。 var: 同JDK10 @Data:注解在类上,将类提供的所有属性都添加get、set方法,并添加、equals、canEquals、hashCode、toString方法 @Setter:注解在类上,为所有属性添加set方法、注解在属性上为该属性提供set方法 @Getter:注解在类上,为所有的属性添..._lombok链式注解

乙太网接口芯片-百兆PHY芯片-RPC8201F,替换RTL8201F-程序员宅基地

文章浏览阅读1k次。乙太网接口芯片-百兆PHY芯片-RPC8201F,替换RTL8201F_rpc8201f

随便推点

java StringTokenizer_stringtokenizer tokenizer = new stringtokenizer(da-程序员宅基地

文章浏览阅读413次。StringTokenizer是一个用来分隔String的应用类,相当于VB的split函数。1.构造函数public StringTokenizer(String str)public StringTokenizer(String str, String delim)public StringTokenizer(String str, String delim, boolean _stringtokenizer tokenizer = new stringtokenizer(data, "_"); 的意思

Springboot 中接口服务重试机制_微信小程序回调sprngboot支持重试-程序员宅基地

文章浏览阅读533次,点赞9次,收藏9次。使用起来很简单,只需要在引入相关jar,并且在启动的时候进行开启,这是springboot 的老套路,在我们服务层进行 @Retryable 的配置,在重试机制完成后我们可以配置一个兜底服务@Recover,我们可以接收请求参数,以此我们后续还可以进行补偿服务的延伸扩展使我们的服务更加的灵活健硕。在平时开发中可能在调用服务时会遇到调用失败的情况,在springboot 中retery 机制可以很好的满足我们的开发场景,下面举个简单的例子模拟第三方调用。_微信小程序回调sprngboot支持重试

异常检测——基于统计学的方法(学习blog))_使用直方图检测异常点-程序员宅基地

文章浏览阅读114次。异常检测——基于统计学方法概述统计学方法对数据的正常性做出假定。**它们假定正常的数据对象由一个统计模型产生,而不遵守该模型的数据是异常点。**统计学方法的有效性高度依赖于对给定数据所做的统计模型假定是否成立。异常检测的统计学方法的一般思想是:学习一个拟合给定数据集的生成模型,然后识别该模型低概率区域中的对象,把它们作为异常点。即利用统计学方法建立一个模型,然后考虑对象有多大可能符合该模型。根据如何指定和学习模型,异常检测的统计学方法可以划分为两个主要类型:参数方法和非参数方法。参数方法假定正常_使用直方图检测异常点

阿里架构师八年Java开发的学习经历自述,希望新人少走弯路-程序员宅基地

文章浏览阅读200次。做JAVA有8年的时间了,我从高一就开始接触JAVA,家里亲戚有从事这方面工作经常给分享这方面的职业发展,自己对编程也是非常感兴趣,今天讲述一下我是怎么学习JAVA的,此文章不可以太短,显得没有诚意,也不可以太长,那样很多人看不下去,精简了如下文字:刚开始学习JAVA的时候是看书,一页页的看书,因为身边有一个好的资源,有问题可以问亲戚,学起来相..._阿里java经历

IDENTITY属性的使用详解_isidentity-程序员宅基地

文章浏览阅读1.3w次。IDENTITY属性的使用1.创建查看IDENTITY创建 IF OBJECT_ID('test','U') IS NOT NULL DROP TABLE test GO CREATE TABLE test ( id int IDENTITY(1, 1), --如果直接写IDENTITY则默认为(1, 1) c1 ch_isidentity

python画图_locator attempting to generate 20421 ticks from 11-程序员宅基地

文章浏览阅读3.7k次,点赞2次,收藏7次。1.使用python的pyplot绘制函数:https://blog.csdn.net/huuinn/article/details/789752232.非连续图,折线图https://www.cnblogs.com/chaoren399/p/5792168.html3.Python可视化中Matplotlib(3.线条的详细样式及线性、保存图片、plot的详细风格和样式)、背景色..._locator attempting to generate 20421 ticks from 1152.0 to 9320.0: exceeds locator.maxticks

推荐文章

热门文章

相关标签