0


加密与安全

一,URL编码

为什么要使用URL编码?

我们都知道Http协议中参数的传输是

"key=value"

这种简直对形式的,如果要传多个参数就需要用

“&”

符号对键值对进行分割。如

 "?name1=value1&name2=value2"

,这样在服务端在收到这种字符串的时候,会用

“&”

分割出每一个参数,然后再用

“=”

来分割出参数值。

现在有这样一个问题,如果我的参数值中就包含=或&这种特殊字符的时候该怎么办。
比如说

“name1=value1”

,其中value1的值是

“va&lu=e1”

字符串,那么实际在传输过程中就会变成这样

“name1=va&lu=e1”

。我们的本意是就只有一个键值对,但是服务端会解析成两个键值对,这样就产生了奇异。

如何解决上述问题带来的歧义呢?解决的办法就是对参数进行URL编码?

URL编码只是简单的在特殊字符的各个字节前加上%,例如,我们对上述会产生奇异的字符进行URL编码后结果:

“name1=va%26lu%3D”

,这样服务端会把紧跟在“%”后的字节当成普通的字节,就是不会把它当成各个参数或键值对的分隔符。

类似于这种

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-yyMpbzea-1577957094515)(加密与安全/1577150995264.png)]

实际操作

publicstaticvoidmain(String[] args){//url编码String str="测试";String urlStr=URLEncoder.encode(str);System.out.println("url编码之后:"+urlStr);String deStr=URLDecoder.decode(urlStr);System.out.println("url解码之后:"+deStr);}

打印

url编码之后:%E6%B5%8B%E8%AF%95
url解密之后:测试

二,Base64编码

实际操作

String str="测试";String b64=Base64.getEncoder().encodeToString(str.getBytes("utf-8"));System.out.println("base64编码之后:"+b64);String ori=newString(Base64.getDecoder().decode(b64),"utf-8");System.out.println("base64解码之后:"+ori);

打印

base64编码之后:5rWL6K+V
base64解码之后:测试

url

base64

编码

只需要把Base64.getEncoder()改为Base64.getUrlEncoder(),Base64.getDecoder()改为Base64.getUrlDecoder()即可。

Base64

算法是编码算法,不是加密算法。

Base64

编码的目的是把任意二进制数据编码为文本(长度增加 1/3 ).

三,MD5加密

MD5

是一种摘要算法,所谓摘要算法,就是输入任意长度数据,而输出的是固定长度数据。

举例:

java

Object.hashCode()

方法就是摘要算法。

有没有可能两个不同的输入得到了相同的输出?是有可能的,这也称之为碰撞!

常用的摘要算法

算法长度一长度二MD5128bits16bitsSHA-1160bits20bitsSHA-256256bits32bitsRipeMD160bits20bits 实际操作

String str="测试";//得到md5的实例MessageDigest md=MessageDigest.getInstance("MD5");//update的是byte类型的数组
    md.update(str.getBytes());//加密后返回byte[] r=md.digest();System.out.println(String.format("%032x",newBigInteger(1,r)));

打印

24f93872e1db308f75eb317e3649e814

说明:

MD5

的输入参数是

byte

数组,不是字符串。

四,SHA-1算法

SHA-1

MD5

其实加密过程是一样的,不过前者比后者安全一些,但是运行速度削微慢了那么一丢丢(约25%)。

只是把上面的

MD5

改为

SHA-1

即可。

实际操作

String str="测试";//得到md5的实例MessageDigest md=MessageDigest.getInstance("SHA-1");//update的是byte类型的数组
    md.update(str.getBytes());//加密后返回byte[] r=md.digest();System.out.println(String.format("%040x",newBigInteger(1,r)));

打印

0b5d7ed54bee16756a7579c6718ab01e3d1b75eb

五,对称加密算法

什么是对称加密?对称加密就是加密和解密使用的是同一个密钥。

通过传入一个密钥

key

和代加密的字符串进行加密。

解密:encrypt(key,message)—>得到加密后的结果

解密:decrypt(key,加密后的结果)---->解密后的结果

常用的对称加密算法
算法密钥长度DES56/64AES128/192/256密钥长度越长,该算法的加密力度越大,说明越安全!由于DES加密算法的密钥长度太短,以至于可以被人暴力破解,因此被淘汰弃用。

AES加密

实际操作

String str="测试";//################## 加密  ######################//加密模式String CIPHER_NAME="AES/ECB/PKCS5Padding";//得到cipher实例Cipher cipher=Cipher.getInstance(CIPHER_NAME);//设置密钥byte[] keys="1234567890abcdef".getBytes();//得到key实例   参数是密钥(byte[]类型的)  和"AES"加密算法名SecretKeySpec key=newSecretKeySpec(keys,"AES");
    cipher.init(Cipher.ENCRYPT_MODE, key);//进行加密,得到的byte类型的byte[] b=cipher.doFinal(str.getBytes());System.out.println("加密后的密文(转化为Base64显示):"+Base64.getEncoder().encodeToString(b));//################### 解密   ########################//得到cipher实例Cipher ciphers=Cipher.getInstance(CIPHER_NAME);//得到key实例SecretKeySpec key1=newSecretKeySpec(keys,"AES");
    cipher.init(Cipher.DECRYPT_MODE, key1);//解密byte[] c=cipher.doFinal(b);System.out.println("解密后的明文:"+newString(c));

打印

加密后的密文(转化为Base64显示):6BIemWfPl6FUC/dqx79LVw==
解密后的明文:测试

六,非对称加密算法

RSA加密

RSA非对称加密认证

前提:A和B在私底下要互换对方的公钥,而私钥则自己持有!

加密:A给B发送消息,使用B的公钥加密,然后B收到消息后使用自己的私钥解密。

签名:A使用自己的私钥对数据进行签名,然后发送给B,然后B使用A的公钥进行验签,校验数据的完整性。

说明

使用公钥加密,使用私钥解密;使用私钥签名,使用公钥验签。

签名的作用:

A给B发送消息,加密之后发送给B,此时,一个黑客使用B的公钥加密了一些数据也发送给了B,那么B怎么才能知道收到的加密数据是A发送的而不是黑客?

这时就需要签名了,A加密后并对加密后的数据进行签名,使用A自己的私钥进行签名,发送到B之后,B再使用A的公钥进行验签,如果验签通过则说明加密数据是由A发送过来的。

朕给你们提供一个

RSAUtil

工具类,一切加密的起源都可以源于这个工具类。

本工具类说明书

方法一:string2PublicKey()将Base64编码的公钥转化为公钥对象

参数:(Base64格式的)公钥字符串 返回值:公钥对象

方法二:string2PrivateKey()将Base64编码的私钥转化为私钥对象

参数:(Base64格式的)私钥字符串 返回值:私钥对象

方法三:encrypt() 加密方法

参数:待加密的内容(字符串) 加密使用的密钥(对方公钥) 加密使用的模式(RSA)

返回值:内容加密后的Base64编码形式的字符串

方法四:decrypt() 解密方法

参数:待解密的内容的Base64编码形式的字符串 解密使用的密钥(自己私钥) 解密使用的模式(RSA)

返回值:原文字符串

方法五:handleData()分段处理加解密数据,放到输出流中(这里不做解释)

方法六:sign() 签名算法

参数:要签名的数据(原文或密文均可) 签名使用的密钥(自己私钥) 签名使用的模式(SHA1withRSA)

返回值:签名字符串

方法七:verifySign() 验签算法

参数:签名字符串 验签使用的密钥(对方公钥) 签名使用的模式(SHA1withRSA)

返回值:布尔类型

publicclassRSAUtil{//加密算法privatestaticfinalString KEY_ALGORITHM ="RSA";//密钥长度privatestaticfinalint KEY_SIZE =1024;//分块加密,单块明文的最大字节数 (KEY_SIZE/8) - 11privatestaticfinalint MAX_ENCRYPT_BLOCK =117;//分块解密,单块密文的最大字节数 KEY_SIZE/8privatestaticfinalint MAX_DECRYPT_BLOCK =128;//加密算法publicstaticfinalString encryptAlgorithm="RSA/ECB/PKCS1Padding";//签名算法publicstaticfinalString signAlgorithm="SHA1withRSA";/**
     * 将Base64编码的公钥转化为公钥对象
     * create time: 2019年4月18日下午3:46:01
     * @param publicKeyStr
     * @return
     * @throws IOException
     * @throws NoSuchAlgorithmException
     * @throws InvalidKeySpecException
     */publicstaticPublicKeystring2PublicKey(String publicKeyStr)throwsIOException,NoSuchAlgorithmException,InvalidKeySpecException{//把base64格式的公钥进行base64解码转为byte类型byte[] keyBytes =Base64.decodeBase64(publicKeyStr);//根据给定的编码密钥创建一个新的 X509EncodedKeySpec对象X509EncodedKeySpec keySpec =newX509EncodedKeySpec(keyBytes);//getInstance  api解释:返回转换指定算法的 public/private 关键字的 KeyFactory 对象//keyFactory是密钥规范KeyFactory keyFactory =KeyFactory.getInstance(KEY_ALGORITHM);//参数是加密算法RSA//根据提供的密钥规范(密钥材料)生成公钥对象PublicKey publicKey = keyFactory.generatePublic(keySpec);return publicKey;}/**
     * 将Base64编码的私钥转化为私钥对象
     * create time: 2019年4月18日下午3:46:32
     * @param privateKeystr
     * @return
     * @throws IOException
     * @throws NoSuchAlgorithmException
     * @throws InvalidKeySpecException
     */publicstaticPrivateKeystring2PrivateKey(String privateKeystr)throwsIOException,NoSuchAlgorithmException,InvalidKeySpecException{//把base64格式的私钥进行base64解码转为byte类型byte[] keyBytes =Base64.decodeBase64(privateKeystr);//根据给定的编码密钥创建一个新的 PKCS8EncodedKeySpec对象PKCS8EncodedKeySpec keySpec =newPKCS8EncodedKeySpec(keyBytes);//getInstance  api解释:返回转换指定算法的 public/private 关键字的 KeyFactory 对象//keyFactory是密钥规范KeyFactory keyFactory =KeyFactory.getInstance(KEY_ALGORITHM);//参数是加密算法RSA//根据提供的密钥规范(密钥材料)生成私钥对象PrivateKey privateKey = keyFactory.generatePrivate(keySpec);return privateKey;}/**
     * RSA加密方法
     * create time: 2019年4月18日下午3:38:18
     * @param plainData     待加密的内容
     * @param key             加密使用的秘钥(对方的公钥)
     * @param algorithm     加密使用的模式
     * @return    内容加密后的Base64编码形式
     * @throws Exception
     */publicstaticStringencrypt(String plainData,Key key,String algorithm)throwsException{//字节数组输出流在内存中创建一个字节数组缓冲区,所有发送到输出流的数据保存在该字节数组缓冲区中ByteArrayOutputStream out =newByteArrayOutputStream();byte[] chiperDataBytes;try{//得到cipher实例Cipher cipher =Cipher.getInstance(algorithm);//参数:加密算法RSA//初始化   ENCRYPT_MODE:用于将 Cipher 初始化为加密模式的常量   key:密钥(对方公钥)
            cipher.init(Cipher.ENCRYPT_MODE, key);//把要加密的字符串转换为byte数组byte[] plainDataBytes = plainData.getBytes("UTF-8");//调用分段加密方法进行加密//MAX_ENCRYPT_BLOCK:单块明文最大字节数//out 字节数组缓冲区,和stringbuffer类似用法handleData(out, cipher, plainDataBytes, MAX_ENCRYPT_BLOCK);//把字节数组输出流转为byte数组
            chiperDataBytes = out.toByteArray();}catch(Exception e){thrownewException(e);}finally{
            out.close();}//再把byte数组转为Base64编码格式的字符串并返回(加密后的Base64字符串)returnBase64.encodeBase64String(chiperDataBytes);}/**
     * RSA分段解密方法
     * create time: 2019年4月18日下午3:40:52
     * @param cipherData    待解密的内容的Base64编码形式的数据
     * @param key            解密使用的秘钥    
     * @param algorithm        解密使用的模式
     * @return    解密后的内容
     * @throws Exception
     */publicstaticStringdecrypt(String cipherData,Key key,String algorithm)throwsException,IOException{//字节数组输出流在内存中创建一个字节数组缓冲区,所有发送到输出流的数据保存在该字节数组缓冲区中ByteArrayOutputStream out =newByteArrayOutputStream();byte[] plainDataBytes;try{//得到cipher实例Cipher cipher =Cipher.getInstance(algorithm);//参数:加密算法RSA//初始化   DECRYPT_MODE:用于将 Cipher 初始化为解密模式的常量   key:密钥(自己私钥)
            cipher.init(Cipher.DECRYPT_MODE, key);//把要解密的字符串转换为byte数组byte[] chiperDataBytes =Base64.decodeBase64(cipherData);//调用分段解密方法进行解密handleData(out, cipher, chiperDataBytes, MAX_DECRYPT_BLOCK);//把byte 数组输出流转为byte数组
            plainDataBytes = out.toByteArray();}catch(Exception e){thrownewException(e);}finally{
            out.close();}//再把byte数组转为字符串并返回(解密后的字符串)returnnewString(plainDataBytes);}/**
     * 分段处理加解密数据,放到输出流中
     * create time: 2019年4月18日下午3:42:37
     * @param out        输出流
     * @param cipher    加解密工具
     * @param dataBytes    要处理的数据
     * @param maxBlock    处理的块的最大字节数
     * @throws IllegalBlockSizeException
     * @throws BadPaddingException
     */privatestaticvoidhandleData(ByteArrayOutputStream out,Cipher cipher,byte[] dataBytes,int maxBlock)throwsIllegalBlockSizeException,BadPaddingException{//计算待加密的byte数组的长度int inputLen = dataBytes.length;int offSet =0;int i =0;byte[] cache;//循环减去已经被加密的长度(剩余长度)while(inputLen - offSet >0){if(inputLen - offSet > maxBlock){//加密操作//处理dataBytes字节数组的缓冲区从offset开始(包含)的前maxBlock个字节
                cache = cipher.doFinal(dataBytes, offSet, maxBlock);}else{
                cache = cipher.doFinal(dataBytes, offSet, inputLen - offSet);}//将指定 byte 数组中从偏移量 off 开始的 len 个字节写入此 byte 数组输出流
            out.write(cache,0, cache.length);
            i++;
            offSet = i * maxBlock;}}/**
     * 签名算法
     * @param attributes    属性数据   要签名的字符串
     * @param privateKey    签名使用的密钥   自己的私钥
     * @param algorithm        签名使用的模式  SHA1withRSA
     * @return
     * @throws NoSuchAlgorithmException
     * @throws InvalidKeyException
     * @throws SignatureException
     */publicstaticStringsign(String attributes,PrivateKey privateKey,String algorithm)throwsNoSuchAlgorithmException,InvalidKeyException,SignatureException{//Signature对象可用来生成和验证数字签名Signature signature =Signature.getInstance(algorithm);//初始化这个用于签名的对象
        signature.initSign(privateKey);//使用指定的 byte 数组更新要签名或验证的数据
        signature.update(attributes.getBytes());//sign()方法:返回所有已更新数据的签名字节byte[] signedData = signature.sign();//把签名字节转为Base64编码格式的字符串returnBase64.encodeBase64String(signedData);}/**
     * 验签算法
     * @param attributes    属性数据明文
     * @param signData        签名
     * @param publicKey        验签使用的公钥
     * @param algorithm        验签使用的模式
     * @return
     * @throws NoSuchAlgorithmException
     * @throws InvalidKeyException
     * @throws SignatureException
     */publicstaticbooleanverifySign(String attributes,String signData,PublicKey publicKey,String algorithm)throwsNoSuchAlgorithmException,InvalidKeyException,SignatureException{//Signature对象可用来生成和验证数字签名Signature signCheck =Signature.getInstance(algorithm);//使用来自给定证书的公钥初始化此用于验证的对象
        signCheck.initVerify(publicKey);//使用指定的 byte 数组更新要签名或验证的数据。
        signCheck.update(attributes.getBytes());//验证传入的签名return signCheck.verify(Base64.decodeBase64(signData));}}

如果使用 RSA,对消息摘要算法则会有多种选择,因此,可以将签名算法指定为

MD2withRSA

MD5withRSA

SHA1withRSA

。因为没有默认的算法名称,所以必须为其指定名称。

开始加密签名

首先定义一下自己的私钥和对方的公钥。

//自己的私钥publicstaticfinalString privateKey="MIICdwIBADANBg.....";//对方的公钥publicstaticfinalString thirdPublicKey="MIGfMA0GCSq.....";

加密和签名(传进的参数是待加密的数据【json串】)

publicMapjmqm(String jcxx)throwsException{//得到PublicKey对象PublicKey publicKey =RSAUtil.string2PublicKey(thirdPublicKey);//进行加密并得到加密后的字符串String encryptParam =RSAUtil.encrypt(jcxx, publicKey,"RSA");//签名(这里对原文签名)PrivateKey privateKey =RSAUtil.string2PrivateKey(privateKey);String signature =RSAUtil.sign(jcxx, privateKey,"SHA1withRSA");Map map=newHashMap();
        map.put("encryptParam",encryptParam);
        map.put("signature",signature);return map;}

解密和验签

publicStringdecryptData(String encryptData)throwsException{JSONObject jsonObject =JSONObject.parseObject(encryptData);String encryptParam=(String) jsonObject.get("encryptParam");String signature=(String) jsonObject.get("signature");//第三方公钥转为Key对象PublicKey publicKey =RSAUtil.string2PublicKey(thirdPublicKey);//自己私钥转为Key对象PrivateKey privateKey =RSAUtil.string2PrivateKey(privateKey);//进行解密,返回解密后的原文字符串String plainData =RSAUtil.decrypt(encryptParam, privateKey,"RSA");
        log.info("反馈信息解密内容:"+plainData);//对原文进行验签boolean isTrue =RSAUtil.verifySign(plainData, signature, publicKey,"SHA1withRSA");if(isTrue){
            log.info("验签通过");return plainData;}else{
            log.info("验签失败");return"";}}

结束语:其实只要利用好

RSAUtil

这一个工具类即可,然后加解密以及签名验签的过程可以任意封装。

RSAUtil

工具类中定义了一些静态变量,这些变量是要视情况而改变的。

KEY_ALGORITHM=“RSA” 这是加解密算法

KEY_SIZE=1024 这是使用密钥的长度(1024 or 2048)

MAX_ENCRYPT_BLOCK 这是单块明文的最大字节数 (KEY_SIZE 除以 8 然后减去 11 )

MAX_DECRYPT_BLOCK 这是单块密文的最大字节数 (KEY_SIZE 除以 8 )

encryptAlgorithm=“RSA/ECB/PKCS1Padding” 加密算法(这个没用到,用到的是第一个加密算法【RSA】)

signAlgorithm=“SHA1withRSA” 这是签名算法

以上的所有静态变量都是调用加解密方法和签名验签方法时的参数,具体的

RSA

加密机制可以找时间抽空了解下,包括分段加解密,不过在这个

RSAUtil

工具类中已经写好了,不用过多操心这个问题了。

重点:当密钥使用的是1024位长度时,

KEY_SIZE

要设为1024,

MAX_ENCRYPT_BLOCK

要设为117,

MAX_DECRYPT_BLOCK

要设为128;当密钥使用的是2048位长度时,

KEY_SIZE

要设为2048,

MAX_ENCRYPT_BLOCK

要设为245,

MAX_DECRYPT_BLOCK

要设为256;

RSA加密明文最大长度117字节,解密要求密文最大长度为128字节,所以在加密和解密的过程中需要分块进行。RSA加密对明文的长度是有限制的,如果加密数据过大会抛出如下异常:

Exception in thread "main"javax.crypto.IllegalBlockSizeException:Data must not be longer than 117 bytes  
    at com.sun.crypto.provider.RSACipher.a(DashoA13*..)  
    at com.sun.crypto.provider.RSACipher.engineDoFinal(DashoA13*..)  
    at javax.crypto.Cipher.doFinal(DashoA13*..)

转自网上的一篇帖子,对最大明文长度和最大密文长度做了详细的解释!

不管明文长度是多少,RSA 生成的密文长度总是固定的。但是明文长度不能超过密钥长度。比如 Java 默认的 RSA 加密实现不允许明文长度超过密钥长度减去 11(单位是字节,也就是 byte)。也就是说,如果我们定义的密钥(我们可以通过

java.security.KeyPairGenerator.initialize(int keysize) 

来定义密钥长度)长度为 1024(单位是位,也就是 bit),生成的密钥长度就是 1024位 / 8位/字节 = 128字节,那么我们需要加密的明文长度不能超过 128字节 -11 字节 = 117字节。也就是说,我们最大能将 117 字节长度的明文进行加密,否则会出问题(抛诸如

javax.crypto.IllegalBlockSizeException: Data must not be longer than 53 bytes 

的异常)。

自己总结

相反,如果密钥长度使用的是2048位 /(8位/字节) = 256字节 的话,那么最大单块密文长度就是256字节,最大单块明文长度就是256 - 11 = 245(字节)。

这里提供一个密钥对生成工具,在 <我的下载> 列表中,可以下载使用!

RSA分段加解密

上面引入网上的帖子可以看出,

RSA

加密一次最多只能加密明文的117字节(如果key长度为1024位的话),那么明文太多怎么办?只能分段加密了,很好懂的道理,把明文结成一段一段的,分别进行加密,加密之后把加密后的结果再进行拼接。

下面是分段加解密的过程。

/**
     * 分段处理加解密数据,放到输出流中
     * create time: 2019年4月18日下午3:42:37
     * @param out        输出流
     * @param cipher    加解密工具
     * @param dataBytes    要处理的数据
     * @param maxBlock    处理的块的最大字节数
     * @throws IllegalBlockSizeException
     * @throws BadPaddingException
     */privatestaticvoidhandleData(ByteArrayOutputStream out,Cipher cipher,byte[] dataBytes,int maxBlock)throwsIllegalBlockSizeException,BadPaddingException{//计算待加密的byte数组的长度int inputLen = dataBytes.length;int offSet =0;int i =0;byte[] cache;//循环减去已经被加密的长度(剩余长度)while(inputLen - offSet >0){if(inputLen - offSet > maxBlock){//加密操作//处理dataBytes字节数组的缓冲区从offset开始(包含)的前maxBlock个字节
                cache = cipher.doFinal(dataBytes, offSet, maxBlock);}else{
                cache = cipher.doFinal(dataBytes, offSet, inputLen - offSet);}//将指定 byte 数组中从偏移量 off 开始的 len 个字节写入此 byte 数组输出流
            out.write(cache,0, cache.length);
            i++;
            offSet = i * maxBlock;}}

了解原理即可,会使用工具类就好啦!

七,SM4加密

SM4

使用的国密算法。

SM4Util工具类

publicclassSM4Util{publicstaticfinalString ALGORITHM_NAME ="SM4";publicstaticfinalString ALGORITHM_NAME_ECB_PADDING ="SM4/ECB/PKCS5Padding";publicstaticfinalint DEFAULT_KEY_SIZE =128;publicstaticbyte[]encrypt_Ecb_Padding(byte[] key,byte[] data)throwsInvalidKeyException,NoSuchAlgorithmException,NoSuchProviderException,NoSuchPaddingException,IllegalBlockSizeException,BadPaddingException{Cipher cipher =generateEcbCipher(ALGORITHM_NAME_ECB_PADDING,Cipher.ENCRYPT_MODE, key);return cipher.doFinal(data);}publicstaticbyte[]decrypt_Ecb_Padding(byte[] key,byte[] cipherText)throwsIllegalBlockSizeException,BadPaddingException,InvalidKeyException,NoSuchAlgorithmException,NoSuchProviderException,NoSuchPaddingException{Cipher cipher =generateEcbCipher(ALGORITHM_NAME_ECB_PADDING,Cipher.DECRYPT_MODE, key);return cipher.doFinal(cipherText);}privatestaticCiphergenerateEcbCipher(String algorithmName,int mode,byte[] key)throwsNoSuchAlgorithmException,NoSuchProviderException,NoSuchPaddingException,InvalidKeyException{Cipher cipher =Cipher.getInstance(algorithmName,BouncyCastleProvider.PROVIDER_NAME);Key sm4Key =newSecretKeySpec(key, ALGORITHM_NAME);
        cipher.init(mode, sm4Key);return cipher;}publicstaticbyte[]generateKey()throwsNoSuchAlgorithmException,NoSuchProviderException{returngenerateKey(DEFAULT_KEY_SIZE);}publicstaticbyte[]generateKey(int keySize)throwsNoSuchAlgorithmException,NoSuchProviderException{KeyGenerator kg =KeyGenerator.getInstance(ALGORITHM_NAME,BouncyCastleProvider.PROVIDER_NAME);
        kg.init(keySize,newSecureRandom());return kg.generateKey().getEncoded();}}

SM3Util工具类

publicclassSM3Util{publicstaticbyte[]hash(byte[] srcData){SM3Digest digest =newSM3Digest();
        digest.update(srcData,0, srcData.length);byte[] hash =newbyte[digest.getDigestSize()];
        digest.doFinal(hash,0);return hash;}}

测试类

publicclassDemoTest{publicstaticfinalString demo ="SM4加解密测试DEMO";publicstaticfinalString sortparam ="参数根据key的 ASCII 码从小到大排序(字典序)";//排序使用treemap,key1=value1&key2=value2publicstaticfinalString appsecret ="ba22726d-14aa-11ea-9b2d-b888e3ebf769";publicstaticvoidmain(String[] args)throwsException{// SM4加密原文byte[] bKey =SM4Util.generateKey();byte[] sm4 =SM4Util.encrypt_Ecb_Padding(bKey,demo.getBytes("UTF-8"));String encData =Base64.encodeBase64String(sm4);System.out.println("密文:"+ encData);byte[] dd =SM4Util.decrypt_Ecb_Padding(bKey,Base64.decodeBase64(encData));String datainfo =newString(dd,"UTF-8");System.out.println("解密后的原文:"+ datainfo);//sign签名
        sortparam+="&appsecret="+appsecret;byte[] signHash=SM3Util.hash(sortparam.getBytes("UTF-8"));StringBuilder signature =newStringBuilder();for(byte b : signHash){
            signature.append(byteToHexString(b));}String sign=signature.toString();System.out.println("签名String值为:"+ sign);}publicstaticStringbyteToHexString(byte ib){char[]Digit={'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};char[] ob =newchar[2];
        ob[0]=Digit[(ib >>>4)&0X0f];
        ob[1]=Digit[ib &0X0F];String str =newString(ob);return str;}}
标签: 安全

本文转载自: https://blog.csdn.net/weixin_44001965/article/details/143613669
版权归原作者 刻苦的樊同学 所有, 如有侵权,请联系我们删除。

“加密与安全”的评论:

还没有评论