本文主要是前面《java实现双向RSA + AES加密》的补充,只补充新增的代码,
JDK中自带了椭圆曲线的签名,但是没有实现椭圆曲线的加密解密。不过bouncycastle库实现了,下面的代码需要bouncycastle库。
需要做的准备工作:
1. 去JDK的下载页面,下载
这个东西。这个是为了解除默认JDK中的加密强度的限制。不使用这个可能会报错。
下载下来以后,需要将local_policy.jar 和 US_export_policy.jar替换掉D:\Program Files\Java\jdk1.8.0_91\jre\lib\security下面的相同的两个jar包。
2. 下载bouncycastle的jar文件,加入classpath中。
http://mvnrepository.com/artifact/org.bouncycastle/bcprov-jdk15on
下面上代码
ECCUtil:
package com.zhuyun.encrypt;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.SecureRandom;
import java.security.Security;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import javax.crypto.Cipher;
import org.bouncycastle.jce.interfaces.ECPrivateKey;
import org.bouncycastle.jce.interfaces.ECPublicKey;
public class ECCUtil {
static {
Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
}
//生成秘钥对
public static KeyPair getKeyPair() throws Exception {
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("EC", "BC");
keyPairGenerator.initialize(256, new SecureRandom());
KeyPair keyPair = keyPairGenerator.generateKeyPair();
return keyPair;
}
//获取公钥(Base64编码)
public static String getPublicKey(KeyPair keyPair){
ECPublicKey publicKey = (ECPublicKey) keyPair.getPublic();
byte[] bytes = publicKey.getEncoded();
return AESUtil.byte2Base64(bytes);
}
//获取私钥(Base64编码)
public static String getPrivateKey(KeyPair keyPair){
ECPrivateKey privateKey = (ECPrivateKey) keyPair.getPrivate();
byte[] bytes = privateKey.getEncoded();
return AESUtil.byte2Base64(bytes);
}
//将Base64编码后的公钥转换成PublicKey对象
public static ECPublicKey string2PublicKey(String pubStr) throws Exception{
byte[] keyBytes = AESUtil.base642Byte(pubStr);
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);
KeyFactory keyFactory = KeyFactory.getInstance("EC", "BC");
ECPublicKey publicKey = (ECPublicKey) keyFactory.generatePublic(keySpec);
return publicKey;
}
//将Base64编码后的私钥转换成PrivateKey对象
public static ECPrivateKey string2PrivateKey(String priStr) throws Exception{
byte[] keyBytes = AESUtil.base642Byte(priStr);
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(keyBytes);
KeyFactory keyFactory = KeyFactory.getInstance("EC", "BC");
ECPrivateKey privateKey = (ECPrivateKey) keyFactory.generatePrivate(keySpec);
return privateKey;
}
//公钥加密
public static byte[] publicEncrypt(byte[] content, PublicKey publicKey) throws Exception{
Cipher cipher = Cipher.getInstance("ECIES", "BC");
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
byte[] bytes = cipher.doFinal(content);
return bytes;
}
//私钥解密
public static byte[] privateDecrypt(byte[] content, PrivateKey privateKey) throws Exception{
Cipher cipher = Cipher.getInstance("ECIES", "BC");
cipher.init(Cipher.DECRYPT_MODE, privateKey);
byte[] bytes = cipher.doFinal(content);
return bytes;
}
public static void main(String[] args) throws Exception {
KeyPair keyPair = ECCUtil.getKeyPair();
String publicKeyStr = ECCUtil.getPublicKey(keyPair);
String privateKeyStr = ECCUtil.getPrivateKey(keyPair);
System.out.println("ECC公钥Base64编码:" + publicKeyStr);
System.out.println("ECC私钥Base64编码:" + privateKeyStr);
ECPublicKey publicKey = string2PublicKey(publicKeyStr);
ECPrivateKey privateKey = string2PrivateKey(privateKeyStr);
byte[] publicEncrypt = publicEncrypt("hello world".getBytes(), publicKey);
byte[] privateDecrypt = privateDecrypt(publicEncrypt, privateKey);
System.out.println(new String(privateDecrypt));
}
}
封装好的类 HttpEncryptUtil:
package com.zhuyun.encrypt;
import java.security.PrivateKey;
import java.security.PublicKey;
import javax.crypto.SecretKey;
import org.bouncycastle.jce.interfaces.ECPrivateKey;
import org.bouncycastle.jce.interfaces.ECPublicKey;
import net.sf.json.JSONObject;
public class HttpEncryptUtil {
// //################################双向RSA + AES ##########################
// //APP加密请求内容
// public static String appEncrypt(String appPublicKeyStr, String content) throws Exception{
// //将Base64编码后的Server公钥转换成PublicKey对象
// PublicKey serverPublicKey = RSAUtil.string2PublicKey(KeyUtil.SERVER_PUBLIC_KEY);
// //每次都随机生成AES秘钥
// String aesKeyStr = AESUtil.genKeyAES();
// SecretKey aesKey = AESUtil.loadKeyAES(aesKeyStr);
// //用Server公钥加密AES秘钥
// byte[] encryptAesKey = RSAUtil.publicEncrypt(aesKeyStr.getBytes(), serverPublicKey);
// //用AES秘钥加密APP公钥
// byte[] encryptAppPublicKey = AESUtil.encryptAES(appPublicKeyStr.getBytes(), aesKey);
// //用AES秘钥加密请求内容
// byte[] encryptRequest = AESUtil.encryptAES(content.getBytes(), aesKey);
//
// JSONObject result = new JSONObject();
// result.put("ak", RSAUtil.byte2Base64(encryptAesKey).replaceAll("\r\n", ""));
// result.put("apk", RSAUtil.byte2Base64(encryptAppPublicKey).replaceAll("\r\n", ""));
// result.put("ct", RSAUtil.byte2Base64(encryptRequest).replaceAll("\r\n", ""));
// return result.toString();
// }
//
// //APP解密服务器的响应内容
// public static String appDecrypt(String appPrivateKeyStr, String content) throws Exception{
// JSONObject result = JSONObject.fromObject(content);
// String encryptAesKeyStr = (String) result.get("ak");
// String encryptContent = (String) result.get("ct");
//
// //将Base64编码后的APP私钥转换成PrivateKey对象
// PrivateKey appPrivateKey = RSAUtil.string2PrivateKey(appPrivateKeyStr);
// //用APP私钥解密AES秘钥
// byte[] aesKeyBytes = RSAUtil.privateDecrypt(RSAUtil.base642Byte(encryptAesKeyStr), appPrivateKey);
// //用AES秘钥解密请求内容
// SecretKey aesKey = AESUtil.loadKeyAES(new String(aesKeyBytes));
// byte[] response = AESUtil.decryptAES(RSAUtil.base642Byte(encryptContent), aesKey);
//
// return new String(response);
// }
//
// //服务器加密响应给APP的内容
// public static String serverEncrypt(String appPublicKeyStr, String aesKeyStr, String content) throws Exception{
// //将Base64编码后的APP公钥转换成PublicKey对象
// PublicKey appPublicKey = RSAUtil.string2PublicKey(appPublicKeyStr);
// //将Base64编码后的AES秘钥转换成SecretKey对象
// SecretKey aesKey = AESUtil.loadKeyAES(aesKeyStr);
// //用APP公钥加密AES秘钥
// byte[] encryptAesKey = RSAUtil.publicEncrypt(aesKeyStr.getBytes(), appPublicKey);
// //用AES秘钥加密响应内容
// byte[] encryptContent = AESUtil.encryptAES(content.getBytes(), aesKey);
//
// JSONObject result = new JSONObject();
// result.put("ak", RSAUtil.byte2Base64(encryptAesKey).replaceAll("\r\n", ""));
// result.put("ct", RSAUtil.byte2Base64(encryptContent).replaceAll("\r\n", ""));
// return result.toString();
// }
//
// //服务器解密APP的请求内容
// public static String serverDecrypt(String content) throws Exception{
// JSONObject result = JSONObject.fromObject(content);
// String encryptAesKeyStr = (String) result.get("ak");
// String encryptAppPublicKeyStr = (String) result.get("apk");
// String encryptContent = (String) result.get("ct");
//
// //将Base64编码后的Server私钥转换成PrivateKey对象
// PrivateKey serverPrivateKey = RSAUtil.string2PrivateKey(KeyUtil.SERVER_PRIVATE_KEY);
// //用Server私钥解密AES秘钥
// byte[] aesKeyBytes = RSAUtil.privateDecrypt(RSAUtil.base642Byte(encryptAesKeyStr), serverPrivateKey);
// //用Server私钥解密APP公钥
// SecretKey aesKey = AESUtil.loadKeyAES(new String(aesKeyBytes));
// byte[] appPublicKeyBytes = AESUtil.decryptAES(RSAUtil.base642Byte(encryptAppPublicKeyStr), aesKey);
// //用AES秘钥解密请求内容
// byte[] request = AESUtil.decryptAES(RSAUtil.base642Byte(encryptContent), aesKey);
//
// JSONObject result2 = new JSONObject();
// result2.put("ak", new String(aesKeyBytes));
// result2.put("apk", new String(appPublicKeyBytes));
// result2.put("ct", new String(request));
// return result2.toString();
// }
//################################双向ECC + AES ##########################
//APP加密请求内容
public static String appEncrypt(String appPublicKeyStr, String content) throws Exception{
//将Base64编码后的Server公钥转换成PublicKey对象
ECPublicKey serverPublicKey = ECCUtil.string2PublicKey(KeyUtil.SERVER_PUBLIC_KEY);
//每次都随机生成AES秘钥
String aesKeyStr = AESUtil.genKeyAES();
SecretKey aesKey = AESUtil.loadKeyAES(aesKeyStr);
//用Server公钥加密AES秘钥
byte[] encryptAesKey = ECCUtil.publicEncrypt(aesKeyStr.getBytes(), serverPublicKey);
//用AES秘钥加密APP公钥
byte[] encryptAppPublicKey = AESUtil.encryptAES(appPublicKeyStr.getBytes(), aesKey);
//用AES秘钥加密请求内容
byte[] encryptRequest = AESUtil.encryptAES(content.getBytes(), aesKey);
JSONObject result = new JSONObject();
result.put("ak", AESUtil.byte2Base64(encryptAesKey).replaceAll("\r\n", ""));
result.put("apk", AESUtil.byte2Base64(encryptAppPublicKey).replaceAll("\r\n", ""));
result.put("ct", AESUtil.byte2Base64(encryptRequest).replaceAll("\r\n", ""));
return result.toString();
}
//APP解密服务器的响应内容
public static String appDecrypt(String appPrivateKeyStr, String content) throws Exception{
JSONObject result = JSONObject.fromObject(content);
String encryptAesKeyStr = (String) result.get("ak");
String encryptContent = (String) result.get("ct");
//将Base64编码后的APP私钥转换成PrivateKey对象
ECPrivateKey appPrivateKey = ECCUtil.string2PrivateKey(appPrivateKeyStr);
//用APP私钥解密AES秘钥
byte[] aesKeyBytes = ECCUtil.privateDecrypt(AESUtil.base642Byte(encryptAesKeyStr), appPrivateKey);
//用AES秘钥解密请求内容
SecretKey aesKey = AESUtil.loadKeyAES(new String(aesKeyBytes));
byte[] response = AESUtil.decryptAES(AESUtil.base642Byte(encryptContent), aesKey);
return new String(response);
}
//服务器加密响应给APP的内容
public static String serverEncrypt(String appPublicKeyStr, String aesKeyStr, String content) throws Exception{
//将Base64编码后的APP公钥转换成PublicKey对象
ECPublicKey appPublicKey = ECCUtil.string2PublicKey(appPublicKeyStr);
//将Base64编码后的AES秘钥转换成SecretKey对象
SecretKey aesKey = AESUtil.loadKeyAES(aesKeyStr);
//用APP公钥加密AES秘钥
byte[] encryptAesKey = ECCUtil.publicEncrypt(aesKeyStr.getBytes(), appPublicKey);
//用AES秘钥加密响应内容
byte[] encryptContent = AESUtil.encryptAES(content.getBytes(), aesKey);
JSONObject result = new JSONObject();
result.put("ak", AESUtil.byte2Base64(encryptAesKey).replaceAll("\r\n", ""));
result.put("ct", AESUtil.byte2Base64(encryptContent).replaceAll("\r\n", ""));
return result.toString();
}
//服务器解密APP的请求内容
public static String serverDecrypt(String content) throws Exception{
JSONObject result = JSONObject.fromObject(content);
String encryptAesKeyStr = (String) result.get("ak");
String encryptAppPublicKeyStr = (String) result.get("apk");
String encryptContent = (String) result.get("ct");
//将Base64编码后的Server私钥转换成PrivateKey对象
ECPrivateKey serverPrivateKey = ECCUtil.string2PrivateKey(KeyUtil.SERVER_PRIVATE_KEY);
//用Server私钥解密AES秘钥
byte[] aesKeyBytes = ECCUtil.privateDecrypt(AESUtil.base642Byte(encryptAesKeyStr), serverPrivateKey);
//用AES秘钥解密APP公钥
SecretKey aesKey = AESUtil.loadKeyAES(new String(aesKeyBytes));
byte[] appPublicKeyBytes = AESUtil.decryptAES(AESUtil.base642Byte(encryptAppPublicKeyStr), aesKey);
//用AES秘钥解密请求内容
byte[] request = AESUtil.decryptAES(AESUtil.base642Byte(encryptContent), aesKey);
JSONObject result2 = new JSONObject();
result2.put("ak", new String(aesKeyBytes));
result2.put("apk", new String(appPublicKeyBytes));
result2.put("ct", new String(request));
return result2.toString();
}
}
测试类 TestHttpEncrypt:
package com.zhuyun.encrypt;
import java.io.InputStream;
import java.security.KeyPair;
import java.util.Properties;
import org.junit.Test;
public class TestHttpEncrypt {
@Test
public void testGenerateKeyPair() throws Exception{
//生成RSA公钥和私钥,并Base64编码
// KeyPair keyPair = RSAUtil.getKeyPair();
// String publicKeyStr = RSAUtil.getPublicKey(keyPair);
// String privateKeyStr = RSAUtil.getPrivateKey(keyPair);
// System.out.println("RSA公钥Base64编码:" + publicKeyStr);
// System.out.println("RSA私钥Base64编码:" + privateKeyStr);
//生成ECC公钥和私钥,并Base64编码
KeyPair keyPair = ECCUtil.getKeyPair();
String publicKeyStr = ECCUtil.getPublicKey(keyPair);
String privateKeyStr = ECCUtil.getPrivateKey(keyPair);
System.out.println("ECC公钥Base64编码:" + publicKeyStr);
System.out.println("ECC私钥Base64编码:" + privateKeyStr);
}
@Test
public void testGenerateAesKey() throws Exception{
//生成AES秘钥,并Base64编码
String base64Str = AESUtil.genKeyAES();
System.out.println("AES秘钥Base64编码:" + base64Str);
}
//测试 APP加密请求内容
@Test
public void testAppEncrypt() throws Exception{
//APP端公钥和私钥从配置文件读取,不能写死在代码里
Properties prop = new Properties();
InputStream in = TestHttpEncrypt.class.getClassLoader().getResourceAsStream("client.properties");
prop.load(in);
String appPublicKey = prop.getProperty("app.public.key");
//请求的实际内容
// String content = "{\"name\":\"infi\", \"weight\":\"60\"}";
String content = "{\"tenantid\":\"1\", \"account\":\"13015929018\", \"pwd\":\"123456\"}";
String result = HttpEncryptUtil.appEncrypt(appPublicKey, content);
System.out.println(result);
}
//测试 服务器解密APP的请求内容
@Test
public void testServerDecrypt() throws Exception{
String result = "{\"ak\":\"BPXJhKTtBu6YrFXdxnzzl32tIKMER6X/XfaXbBKKqg6VP0m8Wk2AV+Se+D1MWgqaSC+ahzHh1s8m1hjdbSkFf4eBjdzwSbb0YXDofCgrD0fxvbQQsQdVhSRiL/nPlLzrgtQ9yGAcCF4qjDa4dA==\",\"apk\":\"Dtz7R4XbboA/SwsrUDXXEgt6q3fmMTqh4kvxZA1UyMvhi4isEgKoDL6KuLixXGXI709PBBW22kK6hz1jgMWUAr7QBUA8EqdLsi5GFPukEKBS1b+Xh71KKnwY21+uppds8gsJ9cPbxPmduJoCq44fwn15entZQ9EaWN+2xisF4ac=\",\"ct\":\"CAqCFSHCMKFKpEECVBngMX8sGD2teaeyLiQ13X4b2+gkOrm/mYnzvWpPK/tpQNWThw2146VcXrQX+NZNEOH5Vw==\"}";
System.out.println(HttpEncryptUtil.serverDecrypt(result));
}
//测试 服务器加密响应给APP的内容
@Test
public void testserverEncrypt() throws Exception{
String aesKeyStr = "zQMfufsgoWP+FWCKteGjdg==";
String appPublicKeyStr = "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEFXblKT9aq5X86K+d5RzXpspH4GVwqbSkUc80EbkJn7+ZIejEWba/Io9c5DftUy0AiGXlz9/HgFPdhYBuz5p5rg==";
String content = "{\"retcode\":\"200\"}";
System.out.println(HttpEncryptUtil.serverEncrypt(appPublicKeyStr, aesKeyStr, content));
}
//测试 APP解密服务器的响应内容
@Test
public void testAppDecrypt() throws Exception{
//APP端公钥和私钥从配置文件读取,不能写死在代码里
Properties prop = new Properties();
InputStream in = TestHttpEncrypt.class.getClassLoader().getResourceAsStream("client.properties");
prop.load(in);
String appPrivateKey = prop.getProperty("app.private.key");
String content = "{\"ak\":\"BArM6HfwUYj78sSXrhzYDjVjjpl6Gp3UiFYvNXCJMKfk6aQnC9vto6ZniCEyWAEhmaw9xOw5GmyUy17tV8tiYwKGFfDhS1c4oGOsPEG9KiOxIOuo2saTwrTCGvCwDNju3AGJGfGg8SbnXBndkA==\",\"ct\":\"xE/BBpt30aS/fE5OMJGsyKOcqwlN9MT1swcqbiuMuLnZw98wwGCSZ0aeCdJkDkaZ/JfcJc3exf0tA+/UNdPZ8a7khq5RYyZNA1VfHdhKq6n6n7f7xDqHVZ7uW7ljeLRm\"}";
System.out.println(HttpEncryptUtil.appDecrypt(appPrivateKey, content));
}
}