失眠网,内容丰富有趣,生活中的好帮手!
失眠网 > SM? SM1? SM2? SM3? SM4?

SM? SM1? SM2? SM3? SM4?

时间:2022-12-19 03:19:43

相关推荐

SM? SM1? SM2? SM3? SM4?

最近看了一个项目的代码,用到了SM2,SM3,SM4,瞬间懵逼,一会用SM2,一会用SM3,一会又用SM4SM???

简单来说,SM2,SM3,SM4是国家密码局认定的国产密码算法,当然除了这几个算法,还有SM1,SM7,SM9,祖冲之密码算法等。

本文重点是SM算法的Java实现,并不是研究这几种算法的原理以及和其他算法的比较等。

这里简单介绍下这几种SM算法,先有个大概的印象:

SM1

它是一种对称加密算法中的分组加密算法,分组长度、秘钥长度都是128位,和国际上通用的AES, DES一样,SM1 算法目前还没公开,只能集成在芯片中。

SM2

和国际上通过的RSA一样,是一种非对称加密算法,使用公钥加密,私钥解密,在安全性和运算速度方面要优于RSA算法。

SM3

可以用来生成信息摘要,如MD5,生成的信息摘要长度为256位。

SM4

是一种对称加密算法,可用于替代DES/AES等国际算法, SM4算法与AES算法具有相同的密钥长度和分组长度,都是128位。

当然这些算法的源码可以在商用密码检测中心中下载,我已经下载好了,公众号回复【SM】即可下载。

了解了SM2, SM3, SM4这些算法之后,在我们的系统中就可以应用这些算法来对传输的报文进行加解密;一个简单的流程图如下所示:

SM2

下面将来重点介绍SM2算法

SM2算法是国家密码管理局发布的椭圆曲线公钥密码算法,推荐使用素数域256位椭圆曲线

椭圆曲线方程:曲线参数为:如果你数学够屌,文档给你准备好了,公众号回复【SM】即可下载。

SM2 java实现

既然SM2算法那么厉害,接下来我们就使用Java来实现下吧。

首先在项目中引入对应的jar包:

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

首先第一步,是要创建 SM2 的椭圆曲线参数,用到的类为「SM2P256V1Curve」,它是代表国密SM2推荐参数定义的椭圆曲线,源码如下:可以看到和上面所提供的推荐参数是一样的。

由于「SM2P256V1Curve」没有实现Gx 和 Gy,即基点G的x,y坐标,我们需要自行创建,参数为推荐的参数即可,然后使用x,y 坐标创建基点G,代码如下:第一步创建 SM2 的椭圆曲线参数的代码如下:第二步,由于SM2算法基于 ECC,所以需要根据曲线参数来生成 ECC密钥对,代码如下:第三步,通过 ECC 密钥对获取SM2公钥和私钥,代码如下:

第四步,获取到公钥之后,就可以使用公钥对报文进行加密了,代码如下:第五步,加密之后,需要使用私钥来进行解密,代码如下:第六步,现在来测试一下吧。运行结果如下:

到这里使用Java来实现SM2加解密算法已经结束了,是不是很简单,你学废了吗?

完成代码如下:

生成SM2公私钥:

privatestaticMap<String,ECKeyParameters>getSm2PrivateKeyOrPublicKey(){//P256V1Curve代表国密SM2推荐参数定义的椭圆曲线:SM2P256V1Curvesm2P256V1Curve=newSM2P256V1Curve();BigIntegersm2N=sm2P256V1Curve.getOrder();BigIntegersm2H=sm2P256V1Curve.getCofactor();//由于gx,gy没有提供,需要自己创建默认参数BigIntegersm2Gx=newBigInteger("32C4AE2C1F1981195F9904466A39C9948FE30BBFF2660BE1715A4589334C74C7",16);BigIntegersm2Gy=newBigInteger("BC3736A2F4F6779C59BDCEE36B692153D0A9877CC62A474002DF32E52139F0A0",16);//根据gx,gy坐标创建一个G点,即为椭圆的基点ECPointsm2Gpoint=sm2P256V1Curve.createPoint(sm2Gx,sm2Gy);//设置椭圆曲线参数ECDomainParametersecDomainParameters=newECDomainParameters(sm2P256V1Curve,sm2Gpoint,sm2N,sm2H);//生成ECC密钥对ECKeyGenerationParameterskeyGenerationParameters=newECKeyGenerationParameters(ecDomainParameters,newSecureRandom());ECKeyPairGeneratorkeyPairGenerator=newECKeyPairGenerator();keyPairGenerator.init(keyGenerationParameters);//ECC密钥对AsymmetricCipherKeyPairasymmetricCipherKeyPair=keyPairGenerator.generateKeyPair();//通过ECC密钥对获取SM2公钥和私钥//私钥ECPrivateKeyParameterssm2PrivateKey=(ECPrivateKeyParameters)asymmetricCipherKeyPair.getPrivate();Stringx=ByteUtils.toHexString(sm2PrivateKey.getParameters().getG().getAffineXCoord().getEncoded());Stringy=ByteUtils.toHexString(sm2PrivateKey.getParameters().getG().getAffineYCoord().getEncoded());System.out.println("生成的SM2私钥为:"+x+"-"+y);//公钥ECPublicKeyParameterssm2PublicKey=(ECPublicKeyParameters)asymmetricCipherKeyPair.getPublic();Stringx1=ByteUtils.toHexString(sm2PublicKey.getQ().getAffineYCoord().getEncoded());Stringy1=ByteUtils.toHexString(sm2PublicKey.getQ().getAffineXCoord().getEncoded());System.out.println("生成的SM2公钥为:"+x1+"-"+y1);Map<String,ECKeyParameters>map=newHashMap<>(2);map.put("private",sm2PrivateKey);map.put("public",sm2PublicKey);returnmap;}

加密:

/***公钥加密**@paramsm2PublicKeySM2公钥*@parampack加密的报文*@return加密后的保温*@throwsExceptione*/privatestaticStringsm2Encrypt(ECPublicKeyParameterssm2PublicKey,Stringpack)throwsException{SM2Enginesm2PublicEngine=newSM2Engine();ParametersWithRandomwithRandom=newParametersWithRandom(sm2PublicKey,newSecureRandom());sm2PublicEngine.init(true,withRandom);byte[]encryResult=sm2PublicEngine.processBlock(pack.getBytes(StandardCharsets.UTF_8),0,pack.getBytes(StandardCharsets.UTF_8).length);StringencryResultStr=Base64.getEncoder().encodeToString(encryResult);System.out.println("加密后的报文为:"+encryResultStr);returnencryResultStr;}

解密:

/***SM2私钥解密**@paramsm2PrivateKeySM2私钥*@parampack解密报文*@throwsExceptione*/privatestaticvoidsm2Decrypt(ECPrivateKeyParameterssm2PrivateKey,Stringpack)throwsException{SM2Enginesm2PrivateEngine=newSM2Engine();sm2PrivateEngine.init(false,sm2PrivateKey);byte[]decodePackByte=Base64.getDecoder().decode(pack);byte[]decryptResult=sm2PrivateEngine.processBlock(decodePackByte,0,decodePackByte.length);StringdecryptResultStr=newString(decryptResult,StandardCharsets.UTF_8);System.out.println("解密后的报文为:"+decryptResultStr);}

测试:

static{Security.addProvider(newBouncyCastleProvider());}publicstaticvoidmain(String[]args)throwsException{Map<String,ECKeyParameters>sm2Key=getSm2PrivateKeyOrPublicKey();Stringpack="公众号搜索【Java技术编程】,公众号搜索【Java技术编程】,公众号搜索【Java技术编程】";System.out.println("原始报文为:"+pack);//对报文进行加密StringencryResult=sm2Encrypt((ECPublicKeyParameters)sm2Key.get("public"),pack);//对报文进行解密sm2Decrypt((ECPrivateKeyParameters)sm2Key.get("private"),encryResult);}

SM3 Java 实现

下一篇,敬请期待。

SM4 Java 实现

下下一篇,敬请期待。

如果觉得《SM? SM1? SM2? SM3? SM4?》对你有帮助,请点赞、收藏,并留下你的观点哦!

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。