车海快讯

支付对接常用的加密方式介绍以及java代码实现

admin 95

京东科技姚永健

导读:金融场景里如何让收银和支付更安全?背后的基础原件是加密方式的设计架构。本文重点讲解在京东金融中,我们如何用Java来实现支付加密。

一、术语表:1.对称算法

加密解密密钥是相同的。这些算法也叫秘密密钥算法或单密钥算法,它要求发送者和接收者在安全通信之前,商定一个密钥。对称算法的安全性依赖于密钥,泄漏密钥就意味着任何人都能对消息进行加密解密。只要通信需要保密,密钥就必须保密。

对称算法可分为两类。一次只对明文中的单个位(有时对字节)运算的算法称为序列算法或序列密码。另一类算法是对明文的一组位进行运算,这些位组称为分组,相应的算法称为分组算法或分组密码。现代计算机密码算法的典型分组长度为64位――这个长度大到足以防止分析破译,但又小到足以方便作用。

2.非对称算法

非对称算法也叫公开密钥加密,它是用两个数学相关的密钥对信息进行编码。在此系统中,其中一个密钥叫公开密钥,可随意发给期望与密钥持有者进行安全通信的人。公开密钥用于对信息加密。第二个密钥是私有密钥,属于密钥持有者,此人要仔细保存私有密钥。密钥持有者用私有密钥对收到的信息进行解密。

一般来说,都是公钥加密,私钥解密。如果系统双方需要相互通讯,可以生成两对密钥对。各自保存好自己的私钥和对方的公钥,用公钥加密,私钥进行解密

3.可逆加密算法

一般来说,涉及秘钥之类的算法,都是可逆的。意思就是通过算法和秘钥加密之后,可以再次通过解密算法还原。常见的有DES、3DES、AES128、AES192、AES256。其中AES后面的数字代表的是密钥长度。对称加密算法的安全性相对较低,比较适用的场景就是内网环境中的加解密。

4.不可逆算法

常见的不可逆加密算法有MD5,HMAC,SHA1、SHA-224、SHA-256、SHA-384,和SHA-512,其中SHA-224、SHA-256、SHA-384,和SHA-512我们可以统称为SHA2加密算法,SHA加密算法的安全性要比MD5更高,而SHA2加密算法比SHA1的要高。其中SHA后面的数字表示的是加密后的字符串长度,SHA1默认会产生一个160位的信息摘要。

不可逆加密算法最大的特点就是不需要密钥

5.加密盐

加密盐也是比较常听到的一个概念,盐就是一个随机字符串用来和我们的加密串拼接后进行加密。加盐主要是为了保证加密字符串的安全性。假如有一个加盐后的加密串,黑客通过一定手段得到这个加密串,他解密后拿到的明文,并不是我们加密前的字符串,而是加密前的字符串和盐组合的字符串,这样相对来说又增加了字符串的安全性

或者也可以用在签名,例如签名是对明文或者密文加盐后的签名,有人想串改数据,如果不知道这个盐和规则,那么接收方验签就会不通过,从而保证通讯的安全。

二、传统加密算法介绍DES(DataEncryptionStandard):

对称算法,数据加密标准,速度较快,适用于加密大量数据的场合。

AES算法:

是DES的升级版,属于对称算法。可逆

代码:AESUtil

packageAES;;;;;;;;;;;;;;publicclassAESUtil{/***AES加密字符串**@paramcontent*需要被加密的字符串*@parampassword*加密需要的密码*@return密文*/publicstaticbyte[]encrypt(Stringcontent,Stringpassword){try{KeyGeneratorkgen=("AES");//创建AES的Key生产者(128,newSecureRandom(()));//利用用户密码作为随机数初始化出//加密没关系,SecureRandom是生成安全随机数序列,()是种子,只要种子相同,序列就一样,所以解密只要有password就行SecretKeysecretKey=();//根据用户密码,生成一个密钥byte[]enCodeFormat=();//返回基本编码格式的密钥,如果此密钥不支持编码,则返回SecretKeySpeckey=newSecretKeySpec(enCodeFormat,"AES");//转换为AES专用密钥Ciphercipher=("AES");//创建密码器byte[]byteContent=("utf-8");(_MODE,key);//初始化为加密模式的密码器byte[]result=(byteContent);//加密returnresult;}catch(NoSuchPaddingExceptione){();}catch(NoSuchAlgorithmExceptione){();}catch(UnsupportedEncodingExceptione){();}catch(InvalidKeyExceptione){();}catch(IllegalBlockSizeExceptione){();}catch(BadPaddingExceptione){();}returnnull;}/***解密AES加密过的字符串**@paramcontent*AES加密过过的内容*@parampassword*加密时的密码*@return明文*/publicstaticbyte[]decrypt(byte[]content,Stringpassword){try{KeyGeneratorkgen=("AES");//创建AES的Key生产者(128,newSecureRandom(()));SecretKeysecretKey=();//根据用户密码,生成一个密钥byte[]enCodeFormat=();//返回基本编码格式的密钥SecretKeySpeckey=newSecretKeySpec(enCodeFormat,"AES");//转换为AES专用密钥Ciphercipher=("AES");//创建密码器(_MODE,key);//初始化为解密模式的密码器byte[]result=(content);returnresult;//明文}catch(NoSuchAlgorithmExceptione){();}catch(NoSuchPaddingExceptione){();}catch(InvalidKeyExceptione){();}catch(IllegalBlockSizeExceptione){();}catch(BadPaddingExceptione){();}returnnull;}publicstaticvoidmain(String[]args)throwsException{Stringa=().encodeToString("435678(**^*^%^$%^!@34;.getBytes(_8));Stringb=newString(().decode((_8)));(a+":"+b);Stringcontent="{'aaa':'111','bbb':'222'}";StringsecretKey="43567890|8752#34;;("需要加密的内容:"+content);byte[]encrypt=encrypt(content,secretKey);("加密后的2进制密文:");(newString(encrypt));StringhexStr=().encodeToString(encrypt);("base64编码后密文:"+hexStr);byte[]byte2=().decode(hexStr);("解码后转换为2进制后密文:");(newString(byte2));byte[]decrypt=decrypt(byte2,secretKey);("解密后的内容:"+newString(decrypt,"utf-8"));}}
RSA算法:

公钥加密算法,非对称,可逆

代码:RSAUtil

packageRSASha256;;;;;;*;;;;;;;;;publicclassRSAUtil{privatestaticfinalintDEFAULT_RSA_KEY_SIZE=2048;privatestaticfinalStringKEY_ALGORITHM="RSA";privatestaticfinalStringSIGNATURE_ALGORITHM="MD5withRSA";publicstaticvoidmain(String[]args){MapString,Stringresult=generateRsaKey(DEFAULT_RSA_KEY_SIZE);StringpublicKey=("publicKey");StringprivateKey=("privateKey");//StringpublicKey="MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuazymB25s/ueIfwMM2H74736dQQE4bvRDgNfWltM4PzduNC84ntav41qEgbZtby47O57m/YDVf6vMXJH25ejlsBBhls7FD7xHTkOrskZqLekH0xCs2xa/akdwllbewUNzvWMuQy8X3j2VnrILXzVjvqYxkFY0itMo8fq1xSO6B/S5/RaeKpTtIepFB2cIU9vMrtLoCsnjVoTuPdWcoC79LtS0g1Q5BV4dn+Uca+8/gUbhS7vbth3oLZt6gXTRjJrPxhT4lqWsCZqwkQHPG/8JQgnFqs7+R0KcyemG/411IaZI9WYRGTsQji8sQ2q7HAlZRXvJn+As7jJPvyi67JGKwIDAQAB";//StringprivateKey="MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQC5rPKYHbmz+54h/AwzYfvjvfp1BAThu9EOA19aW0zg/N240Lzie1q/jWoSBtm1vLjs7nub9gNV/q8xckfbl6OWwEGGWzsUPvEdOQ6uyRmot6QfTEKzbFr9qR3CWVt7BQ3O9Yy5DLxfePZWesgtfNWO+pjGQVjSK0yjx+rXFI7oH9Ln9Fp4qlO0h6kUHZwhT28yu0ugKyeNWhO491ZygLv0u1LSDVDkFXh2f5Rxr7z+BRuFLu9u2Hegtm3qBdNGMms/GFPiWpawJmrCRAc8b/wlCCcWqzv5HQpzJ6Yb/jXUhpkj1ZhEZOxCOLyxDarscCVlFe8mf4CzuMk+/KLrskYrAgMBAAECggEABjC+8dVj4J1N+2IU4g2tQT2PQSF+LCx/3tC7+B49JO8pUUUcVwy3zNUhKTKzRXziSXv2ARAlslNIcgSWYrreiGMmjB00jgs/LLM/SxKHWXmt7iEzxBmjuvtNc7JY+3QCrti+9Vh4W1KEHAQB8opL8HVobIu3M2KgLoG20a7syM5gPiCUb3EQ6P30u47y7I2wsbMnMmu79rPu3Q7lSNeoB9KdVV6EA6vukL3chY1QxFh6oFZS1yNjFjxy5RxT8U5Juhr5LYRnOP8MEVptbtrh34SSm0uyckkgJ6jOsrDJqo/DJxjPxixj+BWgG5/XbNq3PFEyEAqkrTZY+FMHSufoaQKBgQDpqPxpl05mDUXCnc7I6F8LZqjnjZU1h9zwKuQe94Fs3I3siWS62sJx1pZ66P9eeIOsT0T4Ye9nDx2x04yyfUcENhydFTQ5M5M9e2q1kKdNeBUT6Xy4WcRibKozUq07mLYSn0kDbuimp/Erp2w3hl5nZu/eLKDjt7yM0otv3uPp5wKBgQDLbYC4hcvk+f1kd/xJQ2ljwF+c8kHHFrlLRipf7qTB24dcrauWXbAGbbcKXx2G+3Waswyf09NdALiWab/jUUUHJm0YGxyr0k5lHci0/eC7hD3tWTL/HRyeF3umKZEkBQypzNeymE6t0lSqjL3MXFQLqumu4h677qA9/DNh7DYhHQKBgQCfAm/bj6s7iba6jVfmozPi91bkVRaAWlgBXL7nT/nU0ncGzC0vd6WxgJ3hQORgLtU0krFV8pfP45qKpHNwGA8XD5gDUiW68500zuM8chdYgeqeJVvJvNUHQfnFeXMIRpFJNPqkCnrqxwk5cvMTCi7+YS/FW0uWDDiVAMcBN4aUawKBgCOgvAiVNk6WEfEEqqTSL6UOzjAYpbiOnEk4src2fpiNMDnlGMYvBmM51/LzEaLQa5p6fV2Ipd4GAE4nmznew+4qprSwGudk3+IJw1sfk7qDwKzPEIVpvddaWYeShB8A22TpwWVAE5eR3M459AvUp8ubVW4RoDxd4Ka6gu1Fh31pAoGAYNPKJNCrdOsQH0nkH0Ld44cH6HD+zcZtoad2eQk0T2SPnKBsIS1S9W0adreOXUv1edO/hN3P/BcTuCaax7ijTscS2f0atc/NIa6LjBnK7oUBBzib9v21L72ZVZ5st4c/H7IzbQCXfS81489a7TTHP+e1HzS/XePftO0pAkr1GJ0=";("公钥为:"+publicKey);("私钥为:"+privateKey);Stringplaintext="{'a':'1111','b':'2222'}";Stringciphertext=null;try{("开始加密明文:"+plaintext);ciphertext=encrypt(plaintext,publicKey);}catch(Exceptione){("加密失败");thrownewRuntimeException(e);}("得到的密文为:"+ciphertext);Stringdeciphering=decrypt(ciphertext,privateKey);("解密后:"+deciphering);}/***生成RSA公私钥,可选长度为1025,2048位.*/publicstaticMapString,StringgenerateRsaKey(intkeySize){MapString,Stringresult=newHashMap(2);try{KeyPairGeneratorkeyPairGen=(KEY_ALGORITHM);//初始化密钥对生成器,密钥大小为10242048位(keySize,newSecureRandom());//生成一个密钥对,保存在keyPair中KeyPairkeyPair=();//得到公钥字符串("publicKey",newString(().encode(().getEncoded())));//得到私钥字符串("privateKey",newString(().encode(().getEncoded())));}catch(GeneralSecurityExceptione){();}returnresult;}/***RSA私钥解密*@paramstr解密字符串*@paramprivateKey私钥*@return明文*/publicstaticStringdecrypt(Stringstr,StringprivateKey){//64位解码加密后的字符串byte[]inputByte;StringoutStr="";try{inputByte=().decode(("UTF-8"));//base64编码的私钥byte[]decoded=().decode(privateKey);RSAPrivateKeypriKey=(RSAPrivateKey)("RSA").generatePrivate(newPKCS8EncodedKeySpec(decoded));//RSA解密Ciphercipher=("RSA");(_MODE,priKey);outStr=newString((inputByte));}catch(UnsupportedEncodingException|NoSuchPaddingException|InvalidKeyException|IllegalBlockSizeException|BadPaddingException|InvalidKeySpecException|NoSuchAlgorithmExceptione){();}returnoutStr;}/***RSA公钥加密*@paramstr需要加密的字符串*@parampublicKey公钥*@return密文*@throwsException加密过程中的异常信息*/publicstaticStringencrypt(Stringstr,StringpublicKey)throwsException{//base64编码的公钥byte[]decoded=().decode(publicKey);RSAPublicKeypubKey=(RSAPublicKey)("RSA").generatePublic(newX509EncodedKeySpec(decoded));//RSA加密Ciphercipher=("RSA");(_MODE,pubKey);StringoutStr=().encodeToString((("UTF-8")));returnoutStr;}publicstaticStringsign(Stringdata,StringpriKey)throwsException{byte[]decoded=().decode(priKey);KeyFactorykeyFactory=("RSA");PrivateKeyprivateKey=(newX509EncodedKeySpec(decoded));Signaturesignature=("MD5withRSA");(privateKey);(());returnnewString(().encode(()));}publicstaticbooleanverify(StringpubKey,Stringsign,Stringdata)throwsException{//获取KeyFactory,指定RSA算法KeyFactorykeyFactory=("RSA");//将BASE64编码的公钥字符串进行解码byte[]encodeByte=().decode(pubKey);//将BASE64解码后的字节数组,构造成X509EncodedKeySpec对象,生成公钥对象PublicKeypublicKey=(newX509EncodedKeySpec(encodeByte));Signaturesignature=("MD5withRSA");//加载公钥(publicKey);//更新原数据(("UTF-8"));//公钥验签(true-验签通过;false-验签失败)(().decode(sign));}}
MD5算法:

信息摘要(Hash安全散列)算法,也叫哈希算法,哈希值也叫散列值,不可逆,不需要秘钥。

代码:MD5Util

packageMD5;;;;publicclassMD5Util{publicstaticvoidmain(String[]args){Stringsha256Str=getSha256Str("123456");(sha256Str);}/***sha256加密**@paramstr要加密的字符串*@return加密后的字符串*/publicstaticStringgetSha256Str(Stringstr){MessageDigestmessageDigest;StringencodeStr="";try{messageDigest=("MD5");((_8));encodeStr=byte2Hex(());}catch(NoSuchAlgorithmExceptione){();}returnencodeStr;}/***sha256加密将byte转为16进制**@parambytes字节码*@return加密后的字符串*/privatestaticStringbyte2Hex(byte[]bytes){StringBuilderstringBuilder=newStringBuilder();Stringtemp;for(byteaByte:bytes){temp=(aByte0xFF);if(()==1){//1得到一位的进行补0操作("0");}(temp);}();}}
SHA-256算法:

sha256算法也是一种密码散列函数,对于任意长度的消息,SHA256都会产生一个256bit长的散列值(哈希值),用于确保信息传输完整一致,称作消息摘要。这个摘要相当于是个长度为32个字节的数组,通常用一个长度为64的十六进制字符串来表示。

和MD5算法对比

相同点:

1、都是密码散列函数,加密不可逆。

2、都可以实现对任意长度对象加密,都不能防止碰撞。

安全性方面:

1、SHA256(称SHA2)的安全性最高,但是耗时要其他两种多很多。

2、md5相对来说比较容易碰撞,安全性没这么高。

性能方面:

以个60M的件为测试样本,经过1000次的测试平均值,这两种算法的表现如下:

MD5算法运1000次的平均时间为:226ms

SHA256算法运1000次的平均时间为:473ms

总而言之,md5和sha256都是密码散列函数,加密不可逆。虽然都不能防止碰撞,但是相对而言,md5比较容易碰撞,安全性没有sha256高。

代码:SHA256Util

packageRSASha256;;;;publicclassSHA256Util{publicstaticvoidmain(String[]args){Stringsha256Str=getSha256Str("123456");(sha256Str);}/***sha256加密**@paramstr要加密的字符串*@return加密后的字符串*/publicstaticStringgetSha256Str(Stringstr){MessageDigestmessageDigest;StringencodeStr="";try{messageDigest=("SHA-256");((_8));encodeStr=byte2Hex(());}catch(NoSuchAlgorithmExceptione){();}returnencodeStr;}/***sha256加密将byte转为16进制**@parambytes字节码*@return加密后的字符串*/privatestaticStringbyte2Hex(byte[]bytes){StringBuilderstringBuilder=newStringBuilder();Stringtemp;for(byteaByte:bytes){temp=(aByte0xFF);if(()==1){//1得到一位的进行补0操作("0");}(temp);}();}}
三、国密算法介绍简介:

为保障国家密码应用安全,2011年GJMM管理局发布《关于做好公钥密码算法升级工作的通知》,

要求自2011年3月1日起在建和拟建公钥密码基础设施电子认证系统和密钥管理系统应使用国密算法。

《金融和重要领域密码应用与创新发展工作规划(2018-2022年)》以及相关法规文件也要求我国金融

和重要领域密码应用采用SM2国产密码算法体系。

国密算法是指GJMM管理局认定的一系列国产密码算法,包括SM1-SM9以及ZUC等。

其中SM1、SM4、SM5、SM6、SM7、SM8、ZUC等属于对称密码,SM2、SM9等属于公钥密码,SM3属于单向散列函数。

目前我国主要使用公开的SM2、SM3、SM4作为商用密码。

SM1:

SM1也叫商密1号算法,是一种国产的对称算法,分组长度和密钥长度都为128比特,该算法不公开,调用该算法时,需要通过加密芯片的接口进行调用。算法安全保密强度及相关软硬件实现性能与AES相当

SM2:

SM2算法和RSA算法都是公钥密码算法,SM2算法是一种更先进安全的算法,在我们国家商用密码体系中被用来替换RSA算法。

随着密码技术和计算机技术的发展,目前常用的1024位RSA算法面临严重的安全威胁,我们国家密码管理部门经过研究,决定采用SM2椭圆曲线算法替换RSA算法。

代码:SM2Util

packageGMSM;;;;;;*;;;;;;;;;;;;;;;/***SM2工具类**/publicclassSM2Util{//SM2推荐曲线名称staticStringSM2_CURVE_NAME="sm2p256v1";publicstaticfinalCharsetUTF_8=("utf-8");/***生成密钥**@return*@throwsException*/publicstaticKeyPairgenKeyPair()throwsException{finalECGenParameterSpecsm2Spec=newECGenParameterSpec(SM2_CURVE_NAME);//获取一个椭圆曲线类型的密钥对生成器finalKeyPairGeneratorkpg=("EC",newBouncyCastleProvider());SecureRandomrandom=newSecureRandom();//使用SM2的算法区域初始化密钥生成器(sm2Spec,random);//获取密钥对KeyPairkeyPair=();returnkeyPair;}/**SM2根据公钥加密*param:message待加密内容,publicKey加密公钥(BASE64编码)*return:加密信息的Base64编码*@throwsInvalidCipherTextException**/publicstaticStringencryptBySM2(Stringmessage,StringpublicKey)throwsInvalidCipherTextException{ECDomainParametersdomin=getDomain();//公钥对象ECPublicKeyParameterspubKeyParameters=getPubKey(publicKey,domin);byte[]cipherBytes=newbyte[0];cipherBytes=encrypt(,pubKeyParameters,(UTF_8));(cipherBytes);}/***SM2根据私钥解密*param:cipherText待解密密文privateKey-私钥(BASE64编码)**/publicstaticStringdecryptBySM2(StringcipherText,StringprivateKey)throwsInvalidCipherTextException{BigIntegerd=newBigInteger(1,(privateKey));ECDomainParametersdomin=getDomain();//私钥对象ECPrivateKeyParametersecPrivateKeyParameters=newECPrivateKeyParameters(d,domin);byte[]decrypt=decrypt(,ecPrivateKeyParameters,(cipherText));returnnewString(decrypt,UTF_8);}/***根据公钥字符串创建公钥对象***/publicstaticECPublicKeyParametersgetPubKey(StringpublicKey,ECDomainParametersdomain){ECCurvecurve=();ECPointpoint=((publicKey));ECPublicKeyParametersPublicKey=newECPublicKeyParameters(point,domain);returnPublicKey;}/***@parammode指定密文结构,旧标准的为C1C2C3,新的[《SM2密码算法使用规范》GM/T0009-2012]标准为C1C3C2*@parampubKeyParameters公钥*@paramsrcData原文*@return根据mode不同,输出的密文C1C2C3排列顺序不同。C1为65字节第1字节为压缩标识,这里固定为0x04,后面64字节为xy分量各32字节。C3为32字节。C2长度与原文一致。*@throwsInvalidCipherTextException*/publicstaticbyte[]encrypt(,ECPublicKeyParameterspubKeyParameters,byte[]srcData)throwsInvalidCipherTextException{SM2Engineengine=newSM2Engine(mode);ParametersWithRandompwr=newParametersWithRandom(pubKeyParameters,newSecureRandom());(true,pwr);(srcData,0,);}/***@parammode指定密文结构,旧标准的为C1C2C3,新的[《SM2密码算法使用规范》GM/T0009-2012]标准为C1C3C2*@parampriKeyParameters私钥*@paramsm2Cipher根据mode不同,需要输入的密文C1C2C3排列顺序不同。C1为65字节第1字节为压缩标识,这里固定为0x04,后面64字节为xy分量各32字节。C3为32字节。C2长度与原文一致。*@return原文。SM2解密返回了数据则一定是原文,因为SM2自带校验,如果密文被篡改或者密钥对不上,都是会直接报异常的。*@throwsInvalidCipherTextException*/publicstaticbyte[]decrypt(,ECPrivateKeyParameterspriKeyParameters,byte[]sm2Cipher)throwsInvalidCipherTextException{SM2Engineengine=newSM2Engine(mode);(false,priKeyParameters);(sm2Cipher,0,);}publicstaticECDomainParametersgetDomain(){//获取一条SM2曲线参数X9ECParametersx9ECParameters=(SM2_CURVE_NAME);//构造domain参数ECDomainParametersdomain=newECDomainParameters((),(),(),());returndomain;}/***私钥签名*@paramprivateKey私钥*@paramcontent待签名内容*@return*/publicstaticStringsign(StringprivateKey,Stringcontent)throwsCryptoException,CryptoException{//待签名内容转为字节数组byte[]message=();BigIntegerdomainParameters=newBigInteger(1,(privateKey));ECDomainParametersdomin=getDomain();//私钥对象ECPrivateKeyParametersprivateKeyParameters=newECPrivateKeyParameters(domainParameters,domin);//创建签名实例SM2Signersm2Signer=newSM2Signer();//初始化签名实例,带上ID,国密的要求,ID默认值:1234567812345678try{(true,newParametersWithID(newParametersWithRandom(privateKeyParameters,("SHA1PRNG")),("1234567812345678")));}catch(NoSuchAlgorithmExceptione){();}(message,0,);//生成签名,签名分为两部分r和s,分别对应索引0和1的数组byte[]signBytes=();Stringsign=(signBytes);returnsign;}/***验证签名*@parampublicKey公钥*@paramcontent待签名内容*@paramsign签名值*@return*/publicstaticbooleanverify(StringpublicKey,Stringcontent,Stringsign){//待签名内容byte[]message=();byte[]signData=(sign);//获取一条SM2曲线参数X9ECParameterssm2ECParameters=(SM2_CURVE_NAME);//构造domain参数ECDomainParametersdomainParameters=newECDomainParameters((),(),());//提取公钥点ECPointpukPoint=().decodePoint(().decode(publicKey));//公钥前面的02或者03表示是压缩公钥,04表示未压缩公钥,04的时候,可以去掉前面的04ECPublicKeyParameterspublicKeyParameters=newECPublicKeyParameters(pukPoint,domainParameters);//创建签名实例SM2Signersm2Signer=newSM2Signer();ParametersWithIDparametersWithID=newParametersWithID(publicKeyParameters,("1234567812345678"));(false,parametersWithID);(message,0,);//验证签名结果booleanverify=(signData);returnverify;}}
SM3:

国产哈希算法,也叫消息摘要算法,可以用MD5作为对比理解。该算法已公开。校验结果为256位。SM3是中华人民共和国政府采用的一种密码散列函数标准,由GJMM管理局于2010年12月17日发布。相关标准为“GM/T0004-2012《SM3密码杂凑算法》”。

在商用密码体系中,SM3主要用于数字签名及验证、消息认证码生成及验证、随机数生成等,其算法公开。据GJMM管理局表示,其安全性及效率与SHA-256相当。

代码:SM3Util

packageGMSM;;;;publicclassSM3Util{/***计算SM3摘要值**@paramsrcData原文*@return摘要值,对于SM3算法来说是32字节*/publicstaticbyte[]hash(byte[]srcData){SM3Digestdigest=newSM3Digest();(srcData,0,);byte[]hash=newbyte[()];(hash,0);returnhash;}/***验证摘要**@paramsrcData原文*@paramsm3Hash摘要值*@return返回true标识验证成功,false标识验证失败*/publicstaticbooleanverify(byte[]srcData,byte[]sm3Hash){byte[]newHash=hash(srcData);((newHash));((sm3Hash));if((newHash,sm3Hash)){returntrue;}else{returnfalse;}}}
SM4:

无线局域网标准的分组数据算法。对称加密,密钥长度和分组长度均为128位。对标AES

代码:SM4Util

packageGMSM;;;;;;*;publicclassSM4Util{static{(newBouncyCastleProvider());}publicstaticfinalStringALGORITHM_NAME="SM4";//AESpublicstaticfinalStringDEFAULT_KEY="random_seed";//128-32位16进制;256-64位16进制publicstaticfinalintDEFAULT_KEY_SIZE=128;publicstaticbyte[]generateKey()throwsNoSuchAlgorithmException,NoSuchProviderException{returngenerateKey(DEFAULT_KEY,DEFAULT_KEY_SIZE);}publicstaticbyte[]generateKey(Stringseed)throwsNoSuchAlgorithmException,NoSuchProviderException{returngenerateKey(seed,DEFAULT_KEY_SIZE);}publicstaticbyte[]generateKey(Stringseed,intkeySize)throwsNoSuchAlgorithmException,NoSuchProviderException{KeyGeneratorkg=(ALGORITHM_NAME,_NAME);SecureRandomrandom=("SHA1PRNG");if(null!=seed!"".equals(seed)){(());}(keySize,random);().getEncoded();}/***@description加密*/publicstaticbyte[]encrypt(StringalgorithmName,byte[]key,byte[]iv,byte[]data)throwsException{returnsm4core(algorithmName,_MODE,key,iv,data);}/***@description解密*/publicstaticbyte[]decrypt(StringalgorithmName,byte[]key,byte[]iv,byte[]data)throwsException{returnsm4core(algorithmName,_MODE,key,iv,data);}privatestaticbyte[]sm4core(StringalgorithmName,inttype,byte[]key,byte[]iv,byte[]data)throwsException{Ciphercipher=(algorithmName,_NAME);Keysm4Key=newSecretKeySpec(key,ALGORITHM_NAME);if(("/ECB/")){(type,sm4Key);}else{if(iv==null){(type,sm4Key);}else{IvParameterSpecivParameterSpec=newIvParameterSpec(iv);(type,sm4Key,ivParameterSpec);}}(data);}}
四、各类支付系统常见加密方式组合介绍

在支付系统交互中,有多种多样的加密方式组合,这里就简单介绍两钟常用的。

1.传统方式

用可逆,非对称算法(rsa,sm2等)使用对方公钥对报文内的关键信息进行加密,得到的密文进行编码,然后再对密文编码后的串加盐后使用不可逆算法(sha256,md5,sm3等)进行签名,使用这些算法签名后得到的是一个16进制的串,签名放到另一个字段,一般是和加密后的信息并列的。

步骤:

1.使用对方的RSA公钥对明文进行加密,得到的密文进行base64编码,作为data

2.将data的值加上约定好的盐,使用sha256算法进行签名,得到的签名是16进制的串,放到sign

加密后的json:

{"data":"auwPDINowtdseZTfcCR8B1OPsevJE1MqIVOLn56WDvw3gjksSjkpMGp4lpYiqZkJ9G2PTaYC2DZSiyhbjtLvfnJE54mZz649gTWQVIHAn5fzV8Vs3JL3Kf9WB0Br9EbR07qrfGlWCvkkgktmTfDS/4qQGywn7TVQ3EH6HwQI7kUf0GlZ9CYcYHKi4/F61s6H9Hws+CPrhchGfJmHnu+835dSVS4IJOnA+0S5JXWVEN/is5i5cmxFb3RUYZbfpu+7JLDgcXLC8oNKIZxSE1aXhoFMj4CTTYCyRxKNCD015fnBMKh+7TYHEksyyybtVjkPqDeczgT3z+Qvj9vdyUZB1Q==","sign":"d3b36e7a837d6241445e506faf72c8d8e3467ee9c11efae0c67dfb5b15f44b6e"}

接收后,先拿到密文,加入约定好的盐进行验签,验签通过后再用私钥进行解密。返回报文同理,只不过返回报文用的也是对方的公钥加密,对方接收后用自己的私钥解密。

demo:RSASha256Test

packageRSASha256;;;publicclassRSASha256Test{publicstaticvoidmain(String[]args){MapString,StringjsonData=newHashMap();StringpublicKey="MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuazymB25s/ueIfwMM2H74736dQQE4bvRDgNfWltM4PzduNC84ntav41qEgbZtby47O57m/YDVf6vMXJH25ejlsBBhls7FD7xHTkOrskZqLekH0xCs2xa/akdwllbewUNzvWMuQy8X3j2VnrILXzVjvqYxkFY0itMo8fq1xSO6B/S5/RaeKpTtIepFB2cIU9vMrtLoCsnjVoTuPdWcoC79LtS0g1Q5BV4dn+Uca+8/gUbhS7vbth3oLZt6gXTRjJrPxhT4lqWsCZqwkQHPG/8JQgnFqs7+R0KcyemG/411IaZI9WYRGTsQji8sQ2q7HAlZRXvJn+As7jJPvyi67JGKwIDAQAB";StringprivateKey="MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQC5rPKYHbmz+54h/AwzYfvjvfp1BAThu9EOA19aW0zg/N240Lzie1q/jWoSBtm1vLjs7nub9gNV/q8xckfbl6OWwEGGWzsUPvEdOQ6uyRmot6QfTEKzbFr9qR3CWVt7BQ3O9Yy5DLxfePZWesgtfNWO+pjGQVjSK0yjx+rXFI7oH9Ln9Fp4qlO0h6kUHZwhT28yu0ugKyeNWhO491ZygLv0u1LSDVDkFXh2f5Rxr7z+BRuFLu9u2Hegtm3qBdNGMms/GFPiWpawJmrCRAc8b/wlCCcWqzv5HQpzJ6Yb/jXUhpkj1ZhEZOxCOLyxDarscCVlFe8mf4CzuMk+/KLrskYrAgMBAAECggEABjC+8dVj4J1N+2IU4g2tQT2PQSF+LCx/3tC7+B49JO8pUUUcVwy3zNUhKTKzRXziSXv2ARAlslNIcgSWYrreiGMmjB00jgs/LLM/SxKHWXmt7iEzxBmjuvtNc7JY+3QCrti+9Vh4W1KEHAQB8opL8HVobIu3M2KgLoG20a7syM5gPiCUb3EQ6P30u47y7I2wsbMnMmu79rPu3Q7lSNeoB9KdVV6EA6vukL3chY1QxFh6oFZS1yNjFjxy5RxT8U5Juhr5LYRnOP8MEVptbtrh34SSm0uyckkgJ6jOsrDJqo/DJxjPxixj+BWgG5/XbNq3PFEyEAqkrTZY+FMHSufoaQKBgQDpqPxpl05mDUXCnc7I6F8LZqjnjZU1h9zwKuQe94Fs3I3siWS62sJx1pZ66P9eeIOsT0T4Ye9nDx2x04yyfUcENhydFTQ5M5M9e2q1kKdNeBUT6Xy4WcRibKozUq07mLYSn0kDbuimp/Erp2w3hl5nZu/eLKDjt7yM0otv3uPp5wKBgQDLbYC4hcvk+f1kd/xJQ2ljwF+c8kHHFrlLRipf7qTB24dcrauWXbAGbbcKXx2G+3Waswyf09NdALiWab/jUUUHJm0YGxyr0k5lHci0/eC7hD3tWTL/HRyeF3umKZEkBQypzNeymE6t0lSqjL3MXFQLqumu4h677qA9/DNh7DYhHQKBgQCfAm/bj6s7iba6jVfmozPi91bkVRaAWlgBXL7nT/nU0ncGzC0vd6WxgJ3hQORgLtU0krFV8pfP45qKpHNwGA8XD5gDUiW68500zuM8chdYgeqeJVvJvNUHQfnFeXMIRpFJNPqkCnrqxwk5cvMTCi7+YS/FW0uWDDiVAMcBN4aUawKBgCOgvAiVNk6WEfEEqqTSL6UOzjAYpbiOnEk4src2fpiNMDnlGMYvBmM51/LzEaLQa5p6fV2Ipd4GAE4nmznew+4qprSwGudk3+IJw1sfk7qDwKzPEIVpvddaWYeShB8A22TpwWVAE5eR3M459AvUp8ubVW4RoDxd4Ka6gu1Fh31pAoGAYNPKJNCrdOsQH0nkH0Ld44cH6HD+zcZtoad2eQk0T2SPnKBsIS1S9W0adreOXUv1edO/hN3P/BcTuCaax7ijTscS2f0atc/NIa6LjBnK7oUBBzib9v21L72ZVZ5st4c/H7IzbQCXfS81489a7TTHP+e1HzS/XePftO0pAkr1GJ0=";Stringsalt="E4bvRDg";("公钥为:"+publicKey);Stringplaintext="{'a':'1111','b':'2222'}";Stringciphertext=null;Stringsign=null;try{ciphertext=(plaintext,publicKey);("data",ciphertext);("第一步,使用对方的RSA公钥对明文进行加密,得到的密文进行base64编码,作为data:"+("data"));sign=(ciphertext+salt);("sign",sign);("第二步,将data的值加上约定好的盐,使用sha256算法进行签名,得到的签名是16进制的串,放到sign:"+("sign"));}catch(Exceptione){("加密失败");thrownewRuntimeException(e);}("得到的密文和签名为:"+jsonData);("模拟另一方收到密文和签名之后.");("私钥为:"+privateKey);Stringciphertext1=("data");Stringsign1=("sign");Stringdeciphering1=null;if(((ciphertext1+salt))){("签名验证成功");deciphering1=(ciphertext1,privateKey);("数据解密成功,data值为:"+deciphering1);}else{("签名验证失败,解密失败");}}}
2.一次一密+签名身份验证

生成一个对称算法秘钥,使用该秘钥对明文进行加密,然后将该秘钥使用对方的公钥进行加密,加密后编码,然后再对明文使用自己的私钥进行签名,因为私钥只有自己有,所以用自己的私钥签名后,对方使用你提供的公钥进行验签,就可以验证你的身份。

步骤:

1.随机生成一个SM4密钥;

2.使用SM4密钥加密密文,得到的密文进行base64编码,作为textToDecrypt

3.将SM4密钥进行base64编码后,再使用对方的SM2公钥对这个base64串进行加密,得到的密文进行base64编码,作为keyCiphertext;

4.对第二步的明文使用第三方sm2私钥签名,得到的签名进行base64编码后作为signature。

加密后json:

{"textToDecrypt":"cU0ymFMho3HXmVq0hwDHvZg9oLsuZT19GLBKcvHzdZ4=","signature":"MEUCIA8nO1g705B3zzmaYv7yK8jajz9r2fKuvSPZliY8k1xBAiEA0noAEiBos3fU7RwEt81jTjwlrQL+tbQfy77VK/h/ES4=","keyCiphertext":"BJv91ULAd6fNchtKF/+b1JW2o7il0Hjbr6erQrY96S8QrDrkE7Y6EpgzM/eY1OumNsr6VbRuK0wx6yo8fq3QapYHZU5X1LzjgyMC+AiCnhzut5V3xxz4Yd0M1Zx2D4ljaOnJTDED4nS5kU2+C5VFF81DyzVDmWw6ZQ=="}

对方接收后,按照以上步骤再进行验签,解密等操作。

demo:GMSMTest

packageGMSM;;;;publicclassGMSMTest{publicstaticvoidmain(String[]args)throwsException{//你这边拿到的sm2公私钥,对方的公钥和自己的私钥StringpriK="AMz5m/WOgpgYiXnlckC7+zdvZXnQYMBcWXt1n7khfdVO";StringotherPubK="BJkVGU87s7xhLrFCI8MGPzp2X+lizte+2So52CQ1tVEDDqOe+Q4vdQXglV2JtIOZeWc/bE8Rzdo29svmTj8+7mA=";Stringmessge="{'aaa':'111','bbb':'222'}";MapString,StringjsonData=newHashMap();byte[]keyB=(null);Stringkey=().encodeToString(keyB);StringalgorithmName=("SM4/ECB/PKCS5PADDING");("第一步,随机生成一个SM4秘钥:"+key);("选定算法:"+algorithmName);//用随机生成的SM4秘钥加密byte[]encryptMSG=(algorithmName,keyB,null,());("textToDecrypt",().encodeToString(encryptMSG));("第二步,使用SM4密钥加密明文,得到的密文进行base64编码,作为textToDecrypt:"+("textToDecrypt"));//将随机生成的SM4秘钥,使用对方的SM2公钥进行加密StringkeyCiphertext=(key,otherPubK);("keyCiphertext",keyCiphertext);("第三步,将SM4密钥进行base64编码后,再使用对方的SM2公钥对这个base64串进行加密,得到的密文进行base64编码,作为keyCiphertext;"+("keyCiphertext"));//对明文使用自己的sm2私钥进行签名如果有需要,可以加点盐Stringsignature=(priK,messge);("signature",signature);("第四步,对第二步的明文使用对方sm2私钥签名,得到的签名进行base64编码后作为signature:"+("signature"));("完整json串:"+jsonData);//模拟接到json传之后的处理//对方拿到的,你的公钥,和对方自己的私钥StringPubK="BNTFr3oo1xm3biGoQQnk20QJfbFvK4HNFgs1DkZJuUT9pW8I7K0D9L9P4mW+tQhWwfJlD/Nsx3BY+oriF1B25bA=";StringotherPriK="I0sHzcDm+oS2FIAHFLxxkWJi1AbrHRxEYs1AxpZTlNw=";//将sm4秘钥进行解密StringkeyCiphertext1=(("keyCiphertext"),otherPriK);("对方使用sm2私钥解密sm4秘钥:"+keyCiphertext1);//通过sm4秘钥解密数据密文byte[]textToDecrypts=(algorithmName,().decode(keyCiphertext1),null,().decode(("textToDecrypt").getBytes()));StringtextToDecryptsS=newString(textToDecrypts);("对方使用sm4秘钥解密后的数据:"+textToDecryptsS);//验证签名booleanproving=(PubK,textToDecryptsS,("signature"));("验证签名是否通过:"+proving);}}

国密依赖pom

/groupIdartifactIdguava//version//groupIdartifactIdbcprov-jdk15on//version/depency/depencies