app与server通信加密
2018-09-23 本文已影响293人
王小杰at2019
[toc]
使用的加密算法及作用
- RSA 非对称加密,做密钥分发
- AES/CBC/PKCS5Padding 对称加密接口传输
交互流程
image 实现流程java实现
server
- 生成RSA密钥对
在线生成
公钥
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsvYa1zk0RB+IrH7P5D9+
DwKEZi4ai96wFUs7Iyef5PYC+SabuIBdHp2eVS44hnC6J92g3yBoxBlPp6neRcNY
gcRvUbJ6xcpR25FuxiJ7SPe3PrbFow2hBe81kfU/GMdQvI3Eq0UUYSgY7M1W+ppI
6jeAaoC8k379R7mhR619UFYxgRl2Gukj0+ihAgNDCshSqqNLqgqrk8jh0AyXjxtn
IzfZg0E34FAidEl7txvrlP2PfUqYnxTksEqVGlk3orJ6ALZZx9CyaojEEPMsXXAU
ftY09duJFt6jXI/qbXT/pTFsOxhJToYzq7NwDFhbtqlgrFQqp9/1/IQtOExD3IRd
0QIDAQAB
-----END PUBLIC KEY-----
私钥
-----BEGIN PRIVATE KEY-----
MIIEwAIBADANBgkqhkiG9w0BAQEFAASCBKowggSmAgEAAoIBAQCy9hrXOTREH4is
fs/kP34PAoRmLhqL3rAVSzsjJ5/k9gL5Jpu4gF0enZ5VLjiGcLon3aDfIGjEGU+n
qd5Fw1iBxG9RsnrFylHbkW7GIntI97c+tsWjDaEF7zWR9T8Yx1C8jcSrRRRhKBjs
zVb6mkjqN4BqgLyTfv1HuaFHrX1QVjGBGXYa6SPT6KECA0MKyFKqo0uqCquTyOHQ
DJePG2cjN9mDQTfgUCJ0SXu3G+uU/Y99SpifFOSwSpUaWTeisnoAtlnH0LJqiMQQ
8yxdcBR+1jT124kW3qNcj+ptdP+lMWw7GElOhjOrs3AMWFu2qWCsVCqn3/X8hC04
TEPchF3RAgMBAAECggEBALIIbOlBSkKfEEtyGITbuR9bhLVWFiihT5DPd7RgXgvb
xVdxVib05C5p5TKeObNc/4RbUgfG6RJ0j66fKbVDQZBPB+NBaCvOOyLwij/n27fa
X1yvXOv5yf/qWeOrE6sl1abObiFoJn8E8c7Z9DZ4OCNxNXo+OduN0JCDFfQFno3E
ljto9vDSbpKlOdC1Mputn2ISaVB6zzEUica1HGtsPa2XrBLnTKuVvqeviiRzoFn6
DCJ9wteddfQpbhYrfaWvYQBgp9eI+YuY9c4b9q9tFKqdlQ+eBZJu8Qzu01U5CfeP
JBLq/D299j0sy9+h3dTNrUlViFCbA4aC5P3B+onEpiUCgYEA6L7X/VxSBOZLDQR0
9fE1V8t+GRu2OMDLyRLrRtPTnue27VmM2SmLbL7uWjpLiMNa3eAoXhl62WSYUbOj
WkLMZIKy3AKEdLiKFNHwvH9FXShEOib4kBIEJ13KfgtSIRPinOck8lVTSDXMdIOy
bdvfpYtIfFTkPXz3/m/iXI5l8tsCgYEAxNeSgLJVhKlBQUYWVexh59M6n4rCmQOr
1UWLEaU05B2X9wJ+EjyciEO/fpATH2O9xVu9vR4pxAu5KkrcaJkVyPjtmY/oudXP
m4DLyLNpVSneiYKn8amoNO7LZAUDLmpyPZzu7PgZQoAGWgZYpAtgkMbzjrsCJN+I
3uT4wCuMc8MCgYEAlTBn0P8RkBRyfTijJFdmYw2Mmdmal4x11EDtUWxM1Sogpsnl
L/qiZaWJsYp2iob2wwyBs7fPeHQz8wMcLapty+u/bKmscAkucaQVFS7brpg2C7SZ
VfhGc1l6iAsHrS5K71p242NwS/Q4R2N3x1XOaRX7876SwxtM9+qOBdg9X0sCgYEA
tFf9dcPt7hlUHAWmuRpVqRwx/bIYEDD44fFRNN1z0/v5GupBr1uw3neTntVJb9zm
JUekUvyrr14+S61CuuJmvzayGZtr0bc++m3KRxt5SfmOVdZLIHIcFkMiPYUKISCN
gj2h+aJlIjRBnYFq/QEffAWLaB2WHUpgEDcgYJCFohkCgYEAlslPd+4crwS7phQ+
dUYkpTyZuf9Y58ltVHbCopqNWjB0CJMN3T0OMfNoqEIeN14pd+30BrclccvGT7B7
I3uImbaMaOZnmL5miOcOzP0KTyPCLJOSTa4zBHbSA+23Xso1Iz7UXtJcS572VPs9
dlUNmFd5BO9NKlSLq9E2LCDTx7M=
-----END PRIVATE KEY-----
- 提供公钥访问地址
@RestController
public class PublicController {
private static String publicKey;
static {
try (InputStream resourceAsStream =
ClassLoader.getSystemClassLoader().getResourceAsStream("public.key")) {
publicKey = new String(FileCopyUtils.copyToByteArray(resourceAsStream));
} catch (Exception e) {
e.printStackTrace();
}
}
@RequestMapping("/publicKey")
public String getPublicKey() throws IOException {
return publicKey;
}
}
- 解密并存储客户端AES密钥
@RestController
public class AESKeyController {
private static String privateKey;
@Autowired
RedisTemplate<String, String> redisTemplate;
static {
try (InputStream resourceAsStream =
ClassLoader.getSystemClassLoader().getResourceAsStream("private.key")) {
privateKey = new String(FileCopyUtils.copyToByteArray(resourceAsStream));
} catch (Exception e) {
e.printStackTrace();
}
}
@RequestMapping("/register")
public String test(@RequestBody String body) throws Exception {
byte[] bytes = RSAUtil.decryptByPrivateKey(
new BASE64Decoder().decodeBuffer(body), new BASE64Decoder().decodeBuffer(privateKey));
String txt = new String(bytes, "utf-8");
String deviceId = JSON.parseObject(txt).getString("deviceId");
redisTemplate.opsForValue().set(deviceId, txt);
byte[] resp = RSAUtil.encryptByPrivateKey("ok".getBytes(), new BASE64Decoder().decodeBuffer(privateKey));
return new BASE64Encoder().encode(resp);
}
}
- 解密客户端数据
@RestController
@RequestMapping("/user")
public class UserInfoController {
@Autowired
RedisTemplate<String, String> redisTemplate;
@RequestMapping("/login")
public String login(@RequestBody String body) throws IOException {
JSONObject jsonObject = JSON.parseObject(body);
String deviceId = jsonObject.getString("deviceId");
//取出密钥
JSONObject info = JSON.parseObject(redisTemplate.opsForValue().get(deviceId));
String key = info.getString("key");
String vi = info.getString("vi");
String data = AESUtil.decrypt(jsonObject.getString("data"), key, vi);
System.out.println(data);
data = AESUtil.encrypt("ok 我收到了", key, vi);
return data;
}
}
app
- 获取公钥
String url = "http://localhost:8080/publicKey";
OkHttpClient okHttpClient = new OkHttpClient();
Request request = new Request.Builder()
.url(url)
.build();
Call call = okHttpClient.newCall(request);
String publicKey = call.execute().body().string();
System.out.println(publicKey);
- 生成随机AES密钥
//16 位key
String key = UUID.randomUUID().toString().replace("-", "").substring(0, 16);
// 16 为 vi
String vi = UUID.randomUUID().toString().replace("-", "").substring(0, 16);
System.out.println(key);
System.out.println(vi);
- 使用公钥加密AES密钥发送到服务端
@Test
public void registKey() throws Exception {
OkHttpClient okHttpClient = new OkHttpClient();
Request request = new Request.Builder()
.url("http://localhost:8080/publicKey")
.build();
Call call = okHttpClient.newCall(request);
String publicKey = call.execute().body().string();
System.out.println(publicKey);
Map<String, String> map = new HashMap<>();
map.put("key", key);
map.put("vi", vi);
map.put("deviceId", DEVICE_ID);
byte[] keyByte = new BASE64Decoder().decodeBuffer(publicKey);
byte[] reqData = RSAUtil.encryptByPublicKey(
JSON.toJSONString(map).getBytes(), keyByte);
request = new Request.Builder()
.url("http://localhost:8080/register")
.post(RequestBody.create(null, new BASE64Encoder().encode(reqData)))
.build();
call = okHttpClient.newCall(request);
String respBase64 = call.execute().body().string();
byte[] respData = RSAUtil.decryptByPublicKey(new BASE64Decoder().decodeBuffer(respBase64), keyByte);
System.out.println(new String(respData, "utf-8"));
}
- 使用AES密钥通信
@Test
public void test() throws IOException {
OkHttpClient okHttpClient = new OkHttpClient();
Map<String, Object> map = new HashMap<>();
map.put("deviceId", DEVICE_ID);
String encrypt = AESUtil.encrypt("wyj,test", key, vi);
map.put("data", encrypt);
Request request = new Request.Builder()
.url("http://localhost:8080/user/login")
.post(RequestBody.create(null, JSON.toJSONString(map)))
.build();
Call call = okHttpClient.newCall(request);
String response = call.execute().body().string();
String txt = AESUtil.decrypt(response, key, vi);
System.out.println(txt);
}
工具类
- AES
package cn.wyj.appcrypto.util;
import org.apache.commons.crypto.stream.CryptoInputStream;
import org.apache.commons.crypto.stream.CryptoOutputStream;
import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.util.Properties;
public class AESUtil {
private final static String transform = "AES/CBC/PKCS5Padding";
static Properties properties = new Properties();
public static String decrypt(String content, String key, String iv) throws IOException {
final SecretKeySpec keySpec = new SecretKeySpec(getUTF8Bytes(key), "AES");
final IvParameterSpec ivParameterSpec = new IvParameterSpec(getUTF8Bytes(iv));
InputStream inputStream = new ByteArrayInputStream(new BASE64Decoder().decodeBuffer(content));
try (CryptoInputStream cis = new CryptoInputStream(transform, properties, inputStream, keySpec, ivParameterSpec)) {
byte[] decryptedData = new byte[1024];
int decryptedLen = 0;
int i;
while ((i = cis.read(decryptedData, decryptedLen, decryptedData.length - decryptedLen)) > -1) {
decryptedLen += i;
}
return new String(decryptedData, 0, decryptedLen, StandardCharsets.UTF_8);
}
}
public static String encrypt(String content, String key, String iv) {
final SecretKeySpec keySpec = new SecretKeySpec(getUTF8Bytes(key), "AES");
final IvParameterSpec ivParameterSpec = new IvParameterSpec(getUTF8Bytes(iv));
Properties properties = new Properties();
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
try (CryptoOutputStream cos = new CryptoOutputStream(transform, properties, outputStream, keySpec, ivParameterSpec)) {
cos.write(getUTF8Bytes(content));
cos.flush();
} catch (IOException e) {
e.printStackTrace();
}
return new BASE64Encoder().encode(outputStream.toByteArray());
}
/**
* Converts String to UTF8 bytes
*
* @param input the input string
* @return UTF8 bytes
*/
private static byte[] getUTF8Bytes(String input) {
return input.getBytes(StandardCharsets.UTF_8);
}
}
- RSA
package cn.wyj.appcrypto.util;
import javax.crypto.Cipher;
import java.security.KeyFactory;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
public class RSAUtil {
//非对称密钥算法
private static final String KEY_ALGORITHM = "RSA";
/**
* 私钥加密
*
* @param data 待加密数据
* @param key 密钥
* @return byte[] 加密数据
*/
public static byte[] encryptByPrivateKey(byte[] data, byte[] key) throws Exception {
//取得私钥
PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(key);
KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
//生成私钥
PrivateKey privateKey = keyFactory.generatePrivate(pkcs8KeySpec);
//数据加密
Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
cipher.init(Cipher.ENCRYPT_MODE, privateKey);
return cipher.doFinal(data);
}
/**
* 公钥加密
*
* @param data 待加密数据
* @param key 密钥
* @return byte[] 加密数据
*/
public static byte[] encryptByPublicKey(byte[] data, byte[] key) throws Exception {
//实例化密钥工厂
KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
//初始化公钥
//密钥材料转换
X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(key);
//产生公钥
PublicKey pubKey = keyFactory.generatePublic(x509KeySpec);
//数据加密
Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
cipher.init(Cipher.ENCRYPT_MODE, pubKey);
return cipher.doFinal(data);
}
/**
* 私钥解密
*
* @param data 待解密数据
* @param key 密钥
* @return byte[] 解密数据
*/
public static byte[] decryptByPrivateKey(byte[] data, byte[] key) throws Exception {
//取得私钥
PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(key);
KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
//生成私钥
PrivateKey privateKey = keyFactory.generatePrivate(pkcs8KeySpec);
//数据解密
Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
cipher.init(Cipher.DECRYPT_MODE, privateKey);
return cipher.doFinal(data);
}
/**
* 公钥解密
*
* @param data 待解密数据
* @param key 密钥
* @return byte[] 解密数据
*/
public static byte[] decryptByPublicKey(byte[] data, byte[] key) throws Exception {
//实例化密钥工厂
KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
//初始化公钥
//密钥材料转换
X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(key);
//产生公钥
PublicKey pubKey = keyFactory.generatePublic(x509KeySpec);
//数据解密
Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
cipher.init(Cipher.DECRYPT_MODE, pubKey);
return cipher.doFinal(data);
}
}