JS 与 JAVA 跨语言实现 RSA 和 AES加密算法

简介:       

        开发中为了数据的安全性使用加密算法对数据进行加密是一种很常见的情况,但就一种语言来说,直接使用提供的相应的库进行少许封装是一件很容易的事。但是在一些情况下我们可能需要跨语言来实现,比如前后端分离的 web 开发中,我们需要前端使用 JS 进行加密与解密,后端则使用 Java、PHP等。这个时候由于不再是使用相同的库,相应的库中提供的默认参数设置也就存在不一样的情况,这个时候要做到前端与后端数据的加密解密交换,就不太容易了。本人也是折腾了两天啃了书,查了许多资料才搞定的。

       这里不对原理进行详细赘述,如果还不了解加密算法细节和原理的可以自行查找,本人博客也提供 AES 与 RSA 简单原理介绍,你可以查看。如需详细全面了解,推荐读《Java 加密与解密艺术》这本书。

相关参考:

RSA 加密算法原理简述:https://blog.csdn.net/gulang03/article/details/81176133

AES 加密算法的原理详解:https://blog.csdn.net/gulang03/article/details/81175854

 

       下面的例子是经过测试的,确保了前端与后端都能对相同的数据进行加解密,使用时请尽量与我的环境保持一致。

       JDK:1.8.0_201

       JS 的相关库及版本,参考源码的注释,由于前端使用了 webpack 打包工具,所以代码中会存在 ES6 语法,如果您使用的是原生 JS,只需参考其中的方法即可。

AES

    前端 JS 实现:

/**
 * AES 加密算法封装,
 * 密钥长度定位 256 位,
 * 对外提供密钥的生成、加密、解密
 * 本模块测试时使用的是:crypto-js@3.1.9-1,uuid@3.3.2
 */

let CryptJS = require("crypto-js");
let UUID = require("uuid")


export var AESUtil = {
    /**
     * AES 加密
     * @param _content 待加密内容
     * @param _key aesKey, 
     * @param _iv 初始化向量
     * @return 返回经 BASE64 处理之后的密文
     */
    encrypt: function (_content, _key, _iv) {
        // 先以 UTF-8 编码解码参数 返回 any 类型
        let content = CryptJS.enc.Utf8.parse(_content);
        let aesKey = CryptJS.enc.Utf8.parse(_key);
        let iv = CryptJS.enc.Utf8.parse(_iv);

        // 加密
        let encrypted = CryptJS.AES.encrypt(content, aesKey, {
            iv: iv,
            mode: CryptJS.mode.CBC,
            padding: CryptJS.pad.Pkcs7
        })
        // console.log(encrypted)
        return CryptJS.enc.Base64.stringify(encrypted.ciphertext);
    },

    /**
     * AES 解密
     * @param:_content 待解密的内容[Base64处理过的]
     * @param:解密用的 AES key
     * @param: 初始化向量
     * @return 返回以 UTF-8 处理之后的明文
     */
    decrypt: function (_content, _key, _iv) {    
        // let content = CryptJS.enc.Base64.parse(_content);
        // content = CryptJS.enc.Base64.stringify(content);
        let aesKey = CryptJS.enc.Utf8.parse(_key);
        let iv = CryptJS.enc.Utf8.parse(_iv);

        // 解密
        let decrypted = CryptJS.AES.decrypt(_content, aesKey, {
            iv: iv,
            mode: CryptJS.mode.CBC,
            padding: CryptJS.pad.Pkcs7
        })
        // console.log(decrypted)
        return decrypted.toString(CryptJS.enc.Utf8);
    },

    /**
     * 获得 AES 密钥
     * @returns 32 字节的AES密钥
     */
    getAesKey: function () {
        let uuid = UUID.v1();
        // console.log(uuid)
        let aeskey = CryptJS.enc.Utf8.parse(uuid)
        aeskey = CryptJS.enc.Base64.stringify(aeskey).substring(2, 34)
        // console.log(aeskey + "\n" + "长度:" + aeskey.length);
        return aeskey;
    },

    /**
     * 获得初始化向量
     * @returns 16 字节的初始化向量
     */
    getIv: function () {
        let uuid = UUID.v1();
        let iv = CryptJS.enc.Utf8.parse(uuid);
        iv = CryptJS.enc.Base64.stringify(iv).substring(2, 18);
        // console.log(iv + "\n" + "长度:" + iv.length);
        return iv;
    },

    /**
     * 获得 AES key 及 初始化向量 iv
     * 其实 iv 和 aesKey 两者的生成并没有什么关系,两者只是对各自的长度有限制,
     * 这里只是为了方便使用,进行了一个组合返回。
     * @return 返回 iv 和 aesKey 的组合
     */
    getAESKeyAndIv: function () {
        let aesKeyAndIv = {
            "iv": this.getIv(),
            "aesKey": this.getAesKey(),
        }

        return aesKeyAndIv;
    }
}

      后端 Java 实现: 

import javax.crypto.*;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.io.UnsupportedEncodingException;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.Base64;
import java.util.UUID;

/**
 * AES 加密方法,是对称的密码算法(加密与解密的密钥一致),这里使用最大的 256 位的密钥,
 * 对外提供密钥生成、加密、解密方法
 */
public class AESUtil {
    /**
     * 获得一个 密钥长度为 8*32 = 256 位的 AES 密钥,
     * @return 返回经 BASE64 处理之后的密钥字符串(并截取 32 字节长度)
     */
    public static String getAESStrKey() throws NoSuchAlgorithmException, UnsupportedEncodingException {
        UUID uuid = UUID.randomUUID();
        String aesKey= Base64.getEncoder().encodeToString(uuid.toString().getBytes()).substring(2,34);
        return aesKey;
    }

    /**
     * 获得一个初始化向量,初始化向量长度为 4*4 = 16 个字节
     * @return 返回经 BASE64 处理之后的密钥字符串(并截取 16 字节长度)
     */
    public static String getIv(){
        UUID uuid = UUID.randomUUID();
        String iv = Base64.getEncoder().encodeToString(uuid.toString().getBytes()).substring(2,18);
        return iv;
    }

    /**
     * 获得 AES key 及 初始化向量 iv
     * 其实 
  • 6
    点赞
  • 44
    收藏
    觉得还不错? 一键收藏
  • 9
    评论
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值