1. AES加密算法:
高级加密标准(AES,Advanced Encryption Standard)为最常见的对称加密算法(微信小程序加密传输就是用这个加密算法的)。对称加密算法也就是加密和解密用相同的密钥,具体的加密流程如下图:
2. ECDH/ECC秘钥磋商:
ECC:Elliptic Curves Cryptography,椭圆曲线密码编码学
ECDSA:用于数字签名,是ECC与DSA的结合,整个签名过程与DSA类似,所不一样的是签名中采取的算法为ECC,最后签名出来的值也是分为r,s。
ECDH:是基于ECC(Elliptic Curve Cryptosystems,椭圆曲线密码体制,参看ECC)的DH( Diffie-Hellman)密钥交换算法。交
重点说一下,ECDH用途:
由于通过ECDH,双方可以在不共享任何秘密的前提下协商出一个共享秘密,因此,ECDH广泛用于协议之中,通过ECDH得到对称加密密钥。如TLS中的*_ECDH_*密码套件。使用DH算法的协议,都可以升级到ECDH算法。ECDH具有ECC的高强度、短密钥长度、计算速度快等优点。
密钥交换过程:
假设密钥交换双方为Alice、Bob,其有共享曲线参数(椭圆曲线E、阶N、基点G)。
1.Alice生成随机整数a,计算A=a*G。Bob生成随机整数b,计算B=b*G。
2.Alice将A传递给Bob。A的传递可以公开,即攻击者可以获取A。由于椭圆曲线的离散对数问题是难题,
所以攻击者不可以通过A、G计算出a。Bob将B传递给Alice。同理,B的传递可以公开。
3.Bob收到Alice传递的A,计算Q=b*A
4.Alice收到Bob传递的B,计算Q‘=a*B
最终:Alice、Bob双方即得Q=b*A=b*(a*G)=(b*a)*G=(a*b)*G=a*(b*G)=a*B=Q' (交换律和结合律),
即双方得到一致的密钥Q
3.使用ECDH/ECC秘钥磋商,为AES加密提供加密/解密Key:
具体过程:
(1)服务器初始化时,客户端和服务端都会生成各自的一对初始化公私钥,并各自拥有对方的初始化公钥;
(2)客户端请求服务端时,会生成一对临时公私钥,并使用初始化私钥对明文进行加签,然后客户端临时私钥与服务端初始化公钥进行秘钥磋商生成key,使用key对加签后的明文进行AES加密,对可无端请求时,会将签名,客户端临时公钥和密文一起传给服务端;
(3)服务端获取请求参数后,会使用客户端临时公钥和自己服务端初始化私钥进行秘钥磋商获得key,对明文进行AES解密,
然后使用签名,客户端初始化公钥对密文进行解密操作;
另外这里客户端和服务端秘钥磋商生成的key是一模一样的,这就ECDH/ECC秘钥磋商的效果
下面是简单测试类
public class EncryptOrDecryptUtil {
private static MessageDigest md5Digest;
static {
try {
md5Digest = MessageDigest.getInstance("MD5");
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
Map<String, String> initKeys = generatorKey();
Map<String, String> tempKeys = generatorKey();
System.out.println("*******************************************************");
String serPubKey = initKeys.get("serPubKey");
System.out.println("【服务端初始化公钥serPubKey】" + serPubKey);
String serPriKey = initKeys.get("serPriKey");
System.out.println("【服务端初始化私钥serPriKey】" + serPriKey);
String cliPubKey = initKeys.get("cliPubKey");
System.out.println("【客户端初始化公钥cliPubKey】" + cliPubKey);
String cliPriKey = initKeys.get("cliPriKey");
System.out.println("【客户端初始化私钥cliPriKey】" + cliPriKey);
String tempSerPubKey = tempKeys.get("serPubKey");
System.out.println("【服务端临时公钥tempSerPubKey】" + tempSerPubKey);
String tempSerPriKey = tempKeys.get("serPriKey");
System.out.println("【服务端临时私钥tempSerPriKey】" + tempSerPriKey);
String tempCliPubKey = tempKeys.get("cliPubKey");
System.out.println("【客户端临时公钥tempCliPubKey】" + tempCliPubKey);
String tempCliPriKey = tempKeys.get("cliPriKey");
System.out.println("【客户端临时公钥tempCliPriKey】" + tempCliPriKey);
System.out.println("*******************************************************");
String request = "{\"serviceHeader\":{\"serviceId\":\"1010\",\"responseCode\":\"000000\",\"requestMsg\":\"请求成功\"},\"serviceBody\":{\"sessionId\":\"bf2d5af85239439aa56db5a149ddaaac\",\"userId\":null,\"deviceId\":\"990009263463476\",\"lastAccessTime\":\"2018-06-11 14:30:21\"}}";
String response = "{\"serviceId\":\"1010\",\"responseCode\":\"000000\",\"responseMsg\":\"请求成功\"}&