签名验签以及RSA与AES的区别

做项目时,会经常要与第三方进行交互,比如与支付宝、微信等做交互。

为了保证交互时数据的安全,一般情况下我们会进行签名、验签。

我们假设商户AAA与某第三方XXX进行支付对接,以商户为主语:

商户AAA有自己的私钥,并把AAA的公钥提供给XXX;

支付XXX有自己的私钥,并把XXX公钥提供给AAA;

签名:用AAA的私钥做签名,并把AAA的公钥提供给XXX,XXX使用AAA给的公钥验证签名,确认是AAA发送过来的数据,且没有被篡改过。

验签:XXX收到AAA发送过来的数据后,会回复一串数据,并用XXX自己的私钥进行签名;同上,AAA用XXX给的XXX的公钥进行签名验签。


我们举个例子:

1、商户发送数据:

商户发给支付方的数据要求是xml格式的,比如是如下格式的:

"1.0" encoding="GBK"?>

  1. 100001
  2. 02
  3. 2
  4. 0
  5. test
  6. test
  7. 2009041611084101
  8. 00600
  9. 0010530001
  10. 20090416120000
  11. 2
  12. 2
我们需要给以上的数据做签名,签名放在中进行传输。

要求是:做签名的原始数据不能包括标签,所以我们需要在做签名时将标签删除,签名完成后再添加标签到数据中。

做签名的代码如下:

        /**

  1. * 报文签名
  2. * @param msg:原始XML数据
  3. */
  4. public String signMsg(String xml) throws Exception{
  5. xml=XmlTools.signMsg(xml, tranxContants.pfxPath,tranxContants.pfxPassword);
  6. return xml;
  7. }
其中pfxPath是商户的私钥证书,加密时会读取该文件,pfxPassword是一个字符串常量,加密使用。XmlTools.signMsg定义如下:
  1. public static String signMsg(String strData, String pathPfx, String pass) throws Exception{
  2. return signMsg(strData, pathPfx, pass, prvd);
  3. }
其中prvd是java.security.Provider,关于这个对象的作用,可自行搜索,它是jdk引入的密码服务提供者概念,实现了Java安全性的一部分或者全部。Provider 可能实现的服务包括: 算法(如DES、RSA、MD5);密钥的生成、转换和管理。上面的signMsg方法如下:
  1. private static String signMsg(String strData, String pathPfx, String pass,Provider prv) throws Exception{
  2. final String IDD_STR= "";
  3. String strMsg = strData.replaceAll(IDD_STR, "");
  4. String signedMsg = signPlain(strMsg, pathPfx, pass,prv);
  5. String strRnt = strData.replaceAll(IDD_STR, "" + signedMsg + "");
  6. return strRnt;
  7. }
这一步分三个要点:

1、去除xml格式数据中的

2、使用1中的数据做签名;

3、将2中做的签名放入中,并放回原xml数据中,至此,要发送的数据已经做好的签名。

String signedMsg = signPlain(strMsg, pathPfx, pass,prv);
此处是得到签名字符串的逻辑,由商户和第三方协商好如何处理,在此不做论述。

上述的只是做签名,总体并没有对发送的数据进行加密,这意味着,此种方式只能确保数据在发送的过程中,如果被篡改,接收方能发现数据被篡改。因此,如果发送的数据涉及到密码等,还需要对整体发送的数据再进行一次加密。

2、商户接收返回的数据:

 我们现在讨论商户接收到第三方的返回数据后,如何处理:返回的数据是resp

  1. String resp=XmlTools.send(url,xml);
  2. boolean flag= this.verifyMsg(resp, tranxContants.tltcerPath,isFront);
我们需要对返回的数据进行校验,确保数据是第三方返回的且没有被篡改,处理逻辑在verifyMsg()方法中,tranxContants.tltcerPath是第三方给商户的公钥证书。

verifyMsg方法逻辑如下:

  1. int iStart = strXML.indexOf( "");
  2. if(iStart==- 1) throw new Exception( "XML报文中不存在");
  3. int end = strXML.indexOf( "");
  4. if(end==- 1) throw new Exception( "XML报文中不存在");
  5. String signedMsg = strXML.substring(iStart + 12, end);
  6. String strMsg = strXML.substring( 0, iStart) + strXML.substring(end + 13);
  7. System.out.println(strMsg);
  8. System.out.println(strMsg.length());
  9. System.out.println(signedMsg.toLowerCase());
  10. return crypt.VerifyMsg(signedMsg.toLowerCase(), strMsg,cerFile);

其中:

   signMsg是第三方返回的数据中的签名数据,这个数据功能类似于商户发送数据给第三方时做的signMsg;

   strMsg是去除了返回的数据中的签名信息后的数据;

我们用第三方给的公钥(cerFile)+strMsg做签名,并将签名的结果和signMsg做对比,若一致,说明返回的数据是正确的、未被篡改的。

return crypt.VerifyMsg(signedMsg.toLowerCase(), strMsg,cerFile);就是商户做签名验签的逻辑,在此不做论述。

RSA

非对称加密,公钥加密,私钥解密,反之亦然。由于需要大数的乘幂求模等算法,运行速度慢,不易于硬件实现。

通常私钥长度有512bit,1024bit,2048bit,4096bit,长度越长,越安全,但是生成密钥越慢,加解密也越耗时。

既然是加密,那肯定是不希望别人知道我的消息,所以只有我才能解密,所以可得出公钥负责加密,私钥负责解密;

同理,既然是签名,那肯定是不希望有人冒充我发消息,只有我才能发布这个签名,所以可得出私钥负责签名,公钥负责验证。

AES

对称加密,密钥最长只有256个bit,执行速度快,易于硬件实现。由于是对称加密,密钥需要在传输前通讯双方获知。

基于以上特点,通常使用RSA来首先传输AES的密钥给对方,然后再使用AES来进行加密通讯。

 

签名验签以及RSA与AES的区别_第1张图片

 

AES加密数据块分组长度必须为128比特,密钥长度可以是128比特、192比特、256比特中的任意一个(如果数据块及密钥

长度不足时,会补齐)。AES加密有很多轮的重复和变换。大致步骤如下:

1、密钥扩展(KeyExpansion),

2、初始轮(Initial Round),

3、重复轮(Rounds),每一轮又包括:SubBytes、ShiftRows、MixColumns、AddRoundKey,

4、最终轮(Final Round),最终轮没有MixColumns

 

AES加密过程是在一个4×4的字节矩阵上运作,这个矩阵又称为“状态(state)”,其初值就是一个明文区块(矩阵中一个元

素大小就是明文区块中的一个Byte)。加密时,各轮AES加密循环(除最后一轮外)均包含4个步骤:

AddRoundKey (加轮秘钥)— 矩阵中的每一个字节都与该次轮秘钥(round key)做XOR运算。

SubBytes (字节代换)— 通过非线性的替换函数,用查找表的方式把每个字节替换成对应的字节。

ShiftRows (行移位)— 将矩阵中的每个横列进行循环式移位。

MixColumns (列混淆)— 使用线性转换来混合每列的四个字节。

 

字节代换

代换表(S盒)被设计成能够抵挡所有已知的攻击
例如,十六进制{95}对应的的行值是9,列值是5,S盒中此处的值是{2A}。因此{95}被映射为{2A}

签名验签以及RSA与AES的区别_第2张图片


你可能感兴趣的:(传输)