想当初, 某次将服务器容器jetty升级之后, 公司的小霸王服务器直接就跪了, 当时还不知道
DHE
,
ECDHE
是什么鬼. 只是通过分析jvm stack发现, 大量线程卡在这两个相关算法中. 于是果断地配置jetty, 这两个算法剔除掉了.
不过.
ECDHE
是趋势, 苹果公司指定要用这种算法, 等迫不得已的时候再开吧.
今天测试了一下
RSA
,
DHE
,
ECDHE
这三种方式的性能.
先上总结
TLSv1.2密钥交换算法 | 安全性 | 本次测试耗时(秒) |
---|---|---|
RSA | 低, 如果RSA私钥泄露或被破解, 全完蛋 | 0.1 |
DHE | 较高, 即使RSA私钥泄露, 也没事. 即使某个人的连接被破解, 其他人也不受影响 算法难度等同于 解方程: 2e % p = q, 已知p和q , 求e等于多少? |
23 |
ECDHE | 很高. 同上. 算法难度等同于: 已知有限域椭圆曲线方程E, 曲线上两点g和Q, k * g = Q, 求k为多少? |
28 |
测试DHE
分析:
- DH每次需要随机生成一个
大素数
p, 大指数e, 基数为固定值g=2 - 执行一次大数
模幂
运算 , 算出公钥 - 使用对方的公钥q, 再次执行大数
模幂
运算, 计算出密钥key =
测试代码如下.
public static KeyPair genDHKeyPair() throws Exception {
//KeyPairGenerator keyPairGeneator = KeyPairGenerator.getInstance("DH");
//keyPairGeneator.initialize(1024);
DHKeyPairGenerator keyPairGeneator = new DHKeyPairGenerator();
keyPairGeneator.initialize(1024, RANDOM);
KeyPair pair = keyPairGeneator.generateKeyPair();
return pair;
}
public static void DHPerformance() throws Throwable {
KeyPair clientKeyPair = genDHKeyPair();
long time = System.currentTimeMillis();
for (int i = 0; i < 1 * 10000; i++) {
KeyPair serverKeyPair = genDHKeyPair();
KeyAgreement keyAgreement = KeyAgreement.getInstance("DH");
keyAgreement.init(serverKeyPair.getPrivate());
keyAgreement.doPhase(clientKeyPair.getPublic(), true);
keyAgreement.generateSecret();
}
logger.info("time: {}", System.currentTimeMillis() - time);
}
耗时23秒
测试ECDHE
分析:
- 每次需要生成一个私钥(大数), 并计算椭圆方程的乘法, 得到公钥
- 拿到对方公钥之后, 本端私钥与对方公钥执行椭圆方程的乘法,
测试代码如下.
public static KeyPair genECCKeyPair() throws Throwable {
//KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("EC");
ECKeyPairGenerator keyPairGenerator = new ECKeyPairGenerator();
ECGenParameterSpec spec = new ECGenParameterSpec("secp256r1");
keyPairGenerator.initialize(spec, new SecureRandom());
KeyPair pair = keyPairGenerator.generateKeyPair();
return pair;
}
public static void ECDHEPerformance() throws Throwable {
KeyPair clientPair = genECCKeyPair();
long time = System.currentTimeMillis();
for (int i = 0; i < 1 * 10000; i++) {
KeyPair serverPair = genECCKeyPair();
KeyAgreement keyAgreement = KeyAgreement.getInstance("ECDH");
keyAgreement.init(serverPair.getPrivate());
keyAgreement.doPhase(clientPair.getPublic(), true);
keyAgreement.generateSecret();
}
logger.info("time: {}", System.currentTimeMillis() - time);
}
耗时28秒
测试RSA
分析:
服务器已经有私钥和公钥, 只需要执行一次解密操作, 即一次大数模幂
操作
测试代码
public static KeyPair genRSAKeyPair() throws Exception {
//KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
RSAKeyPairGenerator keyPairGenerator = new RSAKeyPairGenerator();
keyPairGenerator.initialize(2048, RANDOM);
KeyPair keyPair = keyPairGenerator.generateKeyPair();
return keyPair;
}
public static void RSAPerformance() throws Throwable {
KeyPair serverKeyPair = genRSAKeyPair();
Random r = new Random();
byte[] preMaster = new byte[48];
r.nextBytes(preMaster);
Cipher encoder = Cipher.getInstance("RSA/ECB/PKCS1Padding");
encoder.init(Cipher.ENCRYPT_MODE, serverKeyPair.getPublic());
encoder.update(preMaster);
byte[] encryptedPreMaster = encoder.doFinal();
long time = System.currentTimeMillis();
for (int i = 0; i < 1 * 10000; i++) {
Cipher decryptor = Cipher.getInstance("RSA/ECB/PKCS1Padding");
decryptor.init(Cipher.DECRYPT_MODE, serverKeyPair.getPublic());
decryptor.update(encryptedPreMaster);
}
logger.info("time: {}", System.currentTimeMillis() - time);
}
耗时 0.1秒