数据传输加密-数字信封

 1、什么是数字信封

  数字信封是公钥密码体制在实际中的一个应用,是用加密技术来保证只有规定的特定收信人才能阅读通讯的内容。算法

  在数字信封中,信息发送方采用对称密钥来加密信息内容,而后将此对称密钥用接收方的公开密钥来加密(这部分称数字信封)以后,将它和加密后的信息一块儿发送给接收方,接收方先用相应的私有密钥打开数字信封,获得对称密钥,而后使用对称密钥解开加密信息。这种技术的安全性至关高。数字信封主要包括数字信封打包和数字信封拆解,数字信封打包是使用对方的公钥将加密密钥进行加密的过程,只有对方的私钥才能将加密后的数据(通讯密钥)还原;数字信封拆解是使用私钥将加密过的数据解密的过程。安全

image.png

  对称加密和非对称加密各有千秋。对称加密实现简单,加解密速度快,非对称加密算法牢固,容易实现数字签名,可是加解密速度稍慢,因此通常状况下,将对称加密和非对称加密结合起来应用,就能够达到良好的加密效果。典型的应用之一就是电子信封。markdown

2、数字信封优势

  数字信封是一种综合利用了对称加密技术和非对称加密技术二者的优势进行信息安全传输的一种技术。数字信封既发挥了对称加密算法速度快、安全性好的优势,又发挥了非对称加密算法密钥管理方便的优势。dom

3、代码实现

1.对称加密实现,这里采用的是3des加密oop

3DES(或称为Triple DES)是三重数据加密算法(TDEA,Triple Data Encryption Algorithm)块密码的通称。它至关因而对每一个数据块应用三次DES加密算法。因为计算机运算能力的加强,原版DES密码的密钥长度变得容易被暴力破解;3DES便是设计用来提供一种相对简单的方法,即经过增长DES的密钥长度来避免相似的攻击,而不是设计一种全新的块密码算法。测试

/**
 * 对称加密
 */
public class DES3Utils {

    // 向量
    private final static String iv = "01234567";
    // 加解密统一使用的编码方式
    private final static String encoding = "utf-8";

    /**
     * 3DES加密
     *
     * @param plainText 普通文本
     * @return
     * @throws Exception
     */
    public static String encode(String plainText,String secretKey) throws Exception {
        Key deskey = null;
        DESedeKeySpec spec = new DESedeKeySpec(secretKey.getBytes());
        SecretKeyFactory keyfactory = SecretKeyFactory.getInstance("desede");
        deskey = keyfactory.generateSecret(spec);
        Cipher cipher = Cipher.getInstance("desede/CBC/PKCS5Padding");
        IvParameterSpec ips = new IvParameterSpec(iv.getBytes());
        cipher.init(Cipher.ENCRYPT_MODE, deskey, ips);
        byte[] encryptData = cipher.doFinal(plainText.getBytes(encoding));
        return Base64.encode(encryptData);
    }


    /**
     * 3DES解密
     *
     * @param encryptText 加密文本
     * @return
     * @throws Exception
     */
    public static String decode(String encryptText,String secretKey)  {
        try {
            Key deskey = null;
            DESedeKeySpec spec = new DESedeKeySpec(secretKey.getBytes());
            SecretKeyFactory keyfactory = SecretKeyFactory.getInstance("desede");
            deskey = keyfactory.generateSecret(spec);
            Cipher cipher = Cipher.getInstance("desede/CBC/PKCS5Padding");
            IvParameterSpec ips = new IvParameterSpec(iv.getBytes());
            cipher.init(Cipher.DECRYPT_MODE, deskey, ips);
            byte[] decryptData = cipher.doFinal(Base64.decode(encryptText));
            return new String(decryptData, encoding);
        }catch (Exception e){
            return "";
        }
    }

}
复制代码

2.非对称加密实现,这里采用的是RSA加密编码

RSA是目前使用最普遍的公钥密码体制之一。它是1977年由罗纳德·李维斯特(Ron Rivest)、阿迪·萨莫尔(Adi Shamir)和伦纳德·阿德曼(Leonard Adleman)一块儿提出的。当时他们三人都在麻省理工学院工做。RSA就是他们三人姓氏开头字母拼在一块儿组成的。
RSA算法的安全性基于RSA问题的困难性,也就是基于大整数因子分解的困难性上。可是RSA问题不会比因子分解问题更加困难,也就是说,在没有解决因子分解问题的状况下可能解决RSA问题,所以RSA算法并非彻底基于大整数因子分解的困难性上的。
加密

/**
 * 非对称加密
 */
public class RSA {

    private static final String ALGO = "RSA";
    private static final String CHARSET = "UTF-8";

    /*
     * 用于存储随机产生的公钥与私钥
     */
    public static Map<Integer, String> KEY_CACHE = new HashMap<>();

    /**
     * 随机生成密钥对
     *
     * @throws NoSuchAlgorithmException
     */
    public static void generateKeyPair() throws NoSuchAlgorithmException {
        // KeyPairGenerator 类用于生成公钥和私钥对,基于RSA算法生成对象
        KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance(ALGO);
        // 初始化密钥对生成器,密钥大小为 96-1024 位
        keyPairGen.initialize(1024, new SecureRandom());
        // 生成一个密钥对,保存在 keyPair 中
        KeyPair keyPair = keyPairGen.generateKeyPair();
        // 获得私钥
        RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();
        // 获得公钥
        RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
        String publicKeyString = new String(Base64.getEncoder().encode(publicKey.getEncoded()));
        // 获得私钥字符串
        String privateKeyString = new String(Base64.getEncoder().encode((privateKey.getEncoded())));
        // 将公钥和私钥保存到 Map
        KEY_CACHE.put(0, publicKeyString);
        KEY_CACHE.put(1, privateKeyString);
    }

    /**
     * RSA公钥加密
     *
     * @param data       加密字符串
     * @param publicKey 公钥
     * @return 密文
     * @throws Exception 加密过程当中的异常信息
     */
    public static String encrypt(String data, String publicKey) throws Exception {
        // base64 编码的公钥
        byte[] decoded = Base64.getDecoder().decode(publicKey);
        RSAPublicKey pubKey = (RSAPublicKey) KeyFactory.getInstance(ALGO).generatePublic(new X509EncodedKeySpec(decoded));
        // RSA加密
        Cipher cipher = Cipher.getInstance(ALGO);
        // 公钥加密
        cipher.init(Cipher.ENCRYPT_MODE, pubKey);
        return Base64.getEncoder().encodeToString(cipher.doFinal(data.getBytes(CHARSET)));
    }

    /**
     * RSA私钥解密
     *
     * @param data        加密字符串
     * @param privateKey 私钥
     * @return 铭文
     * @throws Exception 解密过程当中的异常信息
     */
    public static String decrypt(String data, String privateKey) throws Exception {
        byte[] inputByte = Base64.getDecoder().decode(data.getBytes(CHARSET));
        // base64 编码的私钥
        byte[] decoded = Base64.getDecoder().decode(privateKey);
        RSAPrivateKey priKey = (RSAPrivateKey) KeyFactory.getInstance(ALGO).generatePrivate(new PKCS8EncodedKeySpec(decoded));
        // RSA 解密
        Cipher cipher = Cipher.getInstance(ALGO);
        // 私钥解密
        cipher.init(Cipher.DECRYPT_MODE, priKey);
        return new String(cipher.doFinal(inputByte));
    }
}
复制代码

3.测试spa

//=================数据传输加密======================
//第一步:获取要加密的数据
String data = "{dano:1256,eugo:6521}";
//第二步:生成对称加密密钥(随机生成了一串字符串)
String miyao = generateString(28);
//第三步:经过对称密钥 加密传输数据
String csData=DES3Utils.encode(data, miyao);
//第四步:经过RSA公钥加密 对称密钥
generateKeyPair();
String csKey=RSA.encrypt(miyao, KEY_CACHE.get(0));
//第五步:返回数据
Map<String,String> toMap=new HashMap<>(16);
toMap.put("data",csData);
toMap.put("key",csKey);
//=================数据接收解密======================
//第一步:获取加密后的数据
String Data=toMap.get("data");
//第二步:获取加密后的对称密钥
String key=toMap.get("key");
//第三步:经过RSA公钥解密 对称密钥
String jmKey=RSA.decrypt(key, KEY_CACHE.get(1));
//第四步:经过对称密钥 解密加密数据
String jmData=DES3Utils.decode(Data, jmKey);
System.out.println(jmData);
复制代码

END结束