java实现双向ECC + AES加密

本文主要是前面《java实现双向RSA + AES加密》的补充,只补充新增的代码,

JDK中自带了椭圆曲线的签名,但是没有实现椭圆曲线的加密解密。不过bouncycastle库实现了,下面的代码需要bouncycastle库。

需要做的准备工作:

1. 去JDK的下载页面,下载

http://www.oracle.com/technetwork/java/javase/downloads/jce8-download-2133166.html 

这个东西。这个是为了解除默认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:

[java] view plain copy

```

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:

[java] view plain copy

```

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));  

    }  

}  

```

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,529评论 5 475
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,015评论 2 379
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,409评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,385评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,387评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,466评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,880评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,528评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,727评论 1 295
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,528评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,602评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,302评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,873评论 3 306
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,890评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,132评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,777评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,310评论 2 342

推荐阅读更多精彩内容