乐趣区

关于数据安全:数据的安全交互

一、数据交互

咱们本人的零碎须要和第三方零碎进行对接,实现业务的齐全系统化、自动化操作等,零碎对接其实就是数据的对接,有数据的传输那么就得思考数据的平安交互,个别须要咱们做到两点:数据加密和数据签名。数据加密是为了解决明文裸露的问题,数据签名是为了确保数据完整性和防篡改。

二、非对称加密

非对称加密算法存在两个密钥,一个称之为公钥,一个称之为私钥,这两个密钥齐全不同但又齐全匹配。只有应用匹配的一对公钥和私钥,能力实现对明文的加密和解密过程。常见的非对称加密有 RSA、SM2 等

三、公钥与私钥

由服务端生成公钥与私钥,而后把公钥发送给客户端,客户端通过公钥对数据加密,而后把加密的数据发送给服务端,服务端通过私钥对数据解密。

理论我的项目中,客户端和服务端是相对而言的,客户端也有可能是服务端来接收数据,所以个别两端都会生成一对公钥和私钥,而后把公钥发送给对方,接口交互过程中,通过公钥加密,私钥解密进行数据传输。

公钥和私钥都能够用于加解密操作,用公钥加密的数据只能由对应的私钥解密,反之亦然。虽说两者都可用于加密,然而不同场景应用不同的密钥来加密,规定如下:
1、私钥用于签名、公钥用于验签(私钥加密,公钥解密)
签名和加密作用不同,签名并不是为了窃密,而是为了保障这个签名是由特定的某个人签名的,而不是被其它人伪造的签名,所以私钥的公有性就适宜用在签名用处上。

2、公钥用于加密、私钥用于解密
公钥加密,只能由私钥解密,而私钥是公有不公开的,只能由特定的私钥持有人解密,保证数据的安全性(即便截获数据也不晓得是什么内容)

四、RSA 加解密代码

/**
 * RSA 非对称加密
 */
public class RSAUtils {
    /**
     * 非对称密钥算法
     */
    public static final String KEY_ALGORITHM = "RSA";
    /**
     * 密钥长度,DH 算法的默认密钥长度是 1024
     * 密钥长度必须是 64 的倍数,在 512 到 65536 位之间
     */
    private static final int KEY_SIZE = 1024;
    /**
     * 公钥
     */
    private static final String PUBLIC_KEY = "RSAPublicKey";
    /**
     * 私钥
     */
    private static final String PRIVATE_KEY = "RSAPrivateKey";

    /**
     * 初始化密钥对
     *
     * @return Map 甲方密钥的 Map
     */
    public static Map<String, Object> initKey() throws Exception {
        // 实例化密钥生成器
        KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(KEY_ALGORITHM);
        // 初始化密钥生成器
        keyPairGenerator.initialize(KEY_SIZE);
        // 生成密钥对
        KeyPair keyPair = keyPairGenerator.generateKeyPair();
        // 甲方公钥
        RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
        // 甲方私钥
        RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();
        // 将密钥存储在 map 中
        Map<String, Object> keyMap = new HashMap<String, Object>();
        keyMap.put(PUBLIC_KEY, publicKey);
        keyMap.put(PRIVATE_KEY, privateKey);
        return keyMap;
    }

    /**
     * 私钥加密
     *
     * @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);
    }

    /**
     * 获得私钥
     *
     * @param keyMap 密钥 map
     * @return byte[] 私钥
     */
    public static byte[] getPrivateKey(Map<String, Object> keyMap) {Key key = (Key) keyMap.get(PRIVATE_KEY);
        return key.getEncoded();}

    /**
     * 获得公钥
     *
     * @param keyMap 密钥 map
     * @return byte[] 公钥
     */
    public static byte[] getPublicKey(Map<String, Object> keyMap) throws Exception {Key key = (Key) keyMap.get(PUBLIC_KEY);
        return key.getEncoded();}
}

五、接口设计

申请体类:

public class RequestData {

    /**
     * 序列号,全局惟一,用来标识一个申请
     */
    private String seqNo;

    /**
     * 工夫戳,毫秒
     */
    private String timestamp;

    /**
     * 交易服务码
     */
    private String transCode;

    /**
     * 数据签名
     */
    private String signature;

    /**
     * 申请数据体,数据 JSON 串
     */
    private String plain;

    public String getSeqNo() {return seqNo;}

    public void setSeqNo(String seqNo) {this.seqNo = seqNo;}

    public String getTimestamp() {return timestamp;}

    public void setTimestamp(String timestamp) {this.timestamp = timestamp;}

    public String getTransCode() {return transCode;}

    public void setTransCode(String transCode) {this.transCode = transCode;}

    public String getSignature() {return signature;}

    public void setSignature(String signature) {this.signature = signature;}

    public String getPlain() {return plain;}

    public void setPlain(String plain) {this.plain = plain;}
}

响应体类:

public class ResponseData {

    /**
     * 序列号,全局惟一,用来标识一个申请
     */
    private String seqNo;

    /**
     * 工夫戳,毫秒
     */
    private Long timestamp;

    /**
     * 交易服务码
     */
    private String transCode;

    /**
     * 数据签名
     */
    private String signature;

    /**
     * 申请数据体
     */
    private String plain;

    public String getSeqNo() {return seqNo;}

    public void setSeqNo(String seqNo) {this.seqNo = seqNo;}

    public Long getTimestamp() {return timestamp;}

    public void setTimestamp(Long timestamp) {this.timestamp = timestamp;}

    public String getTransCode() {return transCode;}

    public void setTransCode(String transCode) {this.transCode = transCode;}

    public String getSignature() {return signature;}

    public void setSignature(String signature) {this.signature = signature;}

    public String getPlain() {return plain;}

    public void setPlain(String plain) {this.plain = plain;}
}
退出移动版