app与server通信加密

2018-09-23  本文已影响293人  王小杰at2019

[toc]

使用的加密算法及作用

  1. RSA 非对称加密,做密钥分发
  2. AES/CBC/PKCS5Padding 对称加密接口传输

交互流程

image 实现流程

java实现

server

  1. 生成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-----

  1. 提供公钥访问地址

@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;
    }
}
  1. 解密并存储客户端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);
    }
}

  1. 解密客户端数据

@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

  1. 获取公钥
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);

  1. 生成随机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);
  1. 使用公钥加密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"));


    }
  1. 使用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);

    }

工具类

  1. 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);
    }

}

  1. 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);
    }

}
上一篇下一篇

猜你喜欢

热点阅读