通过DES实现JavaScript加密和Java解密

96
SevenLin1993
0.1 2018.07.27 00:11 字数 527

场景

前后端使用HTTP协议进行交互的时候,由于HTTP报文为明文,所以通常情况下对于比较敏感的信息可以通过对称加密在前端加密,然后在后端解密实现"混淆"的效果,避免在传输过程中敏感信息的泄露(如,密码,证件信息等)。

前端加密的意义

为什么说"混淆"呢?因为我们知道只要不是服务端加密,那么在Web前端加密的都不能保证真正的加密:

  • 攻击者可以通过前端源码知道加密算法进行破解
  • 攻击者只要拿到加密后的密文请求服务端,服务端是无感知的

这里需要明确一个共识,服务端绝对不能相信前端传递过来的密文直接保存入库,只能通过服务端自己加密进行加密保存。

那么前端加密真的就没有意义么?对于安全级别来说其实意义不大,但是有以下好处:

  • 前端加密增加攻击者的成本
  • 传输过程中不是原始密码,避免在传输通道中密码泄露的风险

前端加密的争论其实一直都有,这里我也不做过多的讨论,如果前后端交互需要安全的通道可以使用HTTPS协议进行通信。

通过DES实现前后端加解密

使用Crypto-JS通过DES算法在前端加密

安装
$ npm install crypto-js
加解密

使用DES算法,工作方式为ECB,填充方式为PKcs7

var CryptoJS = require("crypto-js");

const secretKey = 'com.sevenlin.foo.key';

var afterEncrypt = CryptoJS.DES.encrypt('passwordtoecrypt', CryptoJS.enc.Utf8.parse(secretKey), {
        mode: CryptoJS.mode.ECB,
        padding: CryptoJS.pad.Pkcs7
}).toString()

console.log(afterEncrypt);//7D7RsPHmNSlBAaEVgEyE4aL0j1SJtFi9

var afterDecrypt = CryptoJS.DES.decrypt(afterEncrypt, CryptoJS.enc.Utf8.parse(secretKey), {
        mode: CryptoJS.mode.ECB,
        padding: CryptoJS.pad.Pkcs7
}).toString(CryptoJS.enc.Utf8);

console.log(afterDecrypt);//passwordtoecrypt

使用BC通过DES算法在后端解密

安装
<dependency>
    <groupId>org.bouncycastle</groupId>
    <artifactId>bcprov-jdk16</artifactId>
    <version>1.46</version>
</dependency>
加解密工具
public class DesCipherUtil {

    private DesCipherUtil() {
        throw new AssertionError("No DesCipherUtil instances for you!");
    }

    static {
        // add BC provider
        Security.addProvider(new BouncyCastleProvider());
    }

    /**
     * 加密
     * 
     * @param encryptText 需要加密的信息
     * @param key 加密密钥
     * @return 加密后Base64编码的字符串
     */
    public static String encrypt(String encryptText, String key) {

        if (encryptText == null || key == null) {
            throw new IllegalArgumentException("encryptText or key must not be null");
        }

        try {
            DESKeySpec desKeySpec = new DESKeySpec(key.getBytes());
            SecretKeyFactory secretKeyFactory = SecretKeyFactory.getInstance("DES");
            SecretKey secretKey = secretKeyFactory.generateSecret(desKeySpec);

            Cipher cipher = Cipher.getInstance("DES/ECB/PKCS7Padding", "BC");
            cipher.init(Cipher.ENCRYPT_MODE, secretKey);
            byte[] bytes = cipher.doFinal(encryptText.getBytes(Charset.forName("UTF-8")));
            return Base64.getEncoder().encodeToString(bytes);

        } catch (NoSuchAlgorithmException | InvalidKeyException | InvalidKeySpecException | NoSuchPaddingException
            | BadPaddingException | NoSuchProviderException | IllegalBlockSizeException e) {
            throw new RuntimeException("encrypt failed", e);
        }

    }

    /**
     * 解密
     * 
     * @param decryptText 需要解密的信息
     * @param key 解密密钥,经过Base64编码
     * @return 解密后的字符串
     */
    public static  String decrypt(String decryptText, String key) {

        if (decryptText == null || key == null) {
            throw new IllegalArgumentException("decryptText or key must not be null");
        }

        try {
            DESKeySpec desKeySpec = new DESKeySpec(key.getBytes());
            SecretKeyFactory secretKeyFactory = SecretKeyFactory.getInstance("DES");
            SecretKey secretKey = secretKeyFactory.generateSecret(desKeySpec);

            Cipher cipher = Cipher.getInstance("DES/ECB/PKCS7Padding", "BC");
            cipher.init(Cipher.DECRYPT_MODE, secretKey);
            byte[] bytes = cipher.doFinal(Base64.getDecoder().decode(decryptText));
            return new String(bytes, Charset.forName("UTF-8"));

        } catch (NoSuchAlgorithmException | InvalidKeyException | InvalidKeySpecException | NoSuchPaddingException
            | BadPaddingException | NoSuchProviderException | IllegalBlockSizeException e) {
            throw new RuntimeException("decrypt failed", e);
        }
    }
}

解密前端的加密信息
String fromWeb = "7D7RsPHmNSlBAaEVgEyE4aL0j1SJtFi9";
String key = "com.sevenlin.foo.key";
String afterDecrypt = DesCipherUtil.decrypt(fromWeb, key);
System.out.println(afterDecrypt);//passwordtoecrypt

总结

这里只是简单介绍下前端加密和后端解密的大概思路,使用DES算法实现的一个例子,虽然实际应用可能不是这么简单,但可以作为一个简单的DEMO来学习。

编程
Gupao