700字范文,内容丰富有趣,生活中的好帮手!
700字范文 > 【AES 算法】实现服务端 Java 加密 前端 JS 解密

【AES 算法】实现服务端 Java 加密 前端 JS 解密

时间:2023-06-19 23:17:34

相关推荐

【AES 算法】实现服务端 Java 加密 前端 JS 解密

目录

背景AES CBC 加解密算法代码实现Java 生成 key 和 ivJava 加密 & 解密JavaScript 解密小结

背景

我们的游戏充值平台马上要到货一批充值码,需要入库。之前充值码发奖相关的需求都是我做的,但在存储充值码的时候没有加密,是明文存储的。

现在的需求是,数据库中的充值码需要密文存储。这就涉及到:

提供一个新增充值码记录的接口,请求参数为明文,使用 Java 加密后把充值码密文存入数据库;发送充值码邮件时,需要使用 Java 解密充值码,给用户发送明文;前端展示充值码时,服务端传送密文,前端使用 JavaScript 解密,给用户展示明文;(纯属多此一举,因为 HTTPS 通信本来就是加密的。但业务方坚持要这样做。)

AES CBC 加解密算法

这是我第一次做加密相关的需求。一开始(几周前吧)图省事,想着在 StackOverflow 上搜一下,一两行代码就搞定了,不就是个加密嘛。后来发现,怎么都这么复杂啊,一直搜到我身心俱疲,也没找到简单的方法。

这回我静下心来,好好读了一篇介绍 AES 的文章,终于大体上搞明白了。

参考链接:Java AES Encryption and Decryption

简单来说就是,AES 分为很多模式,但大家基本上都用 CBC。

在 CBC 模式下,除了秘钥key之外,为了增强安全性,还需要一个iv。(最基础的 ECB 模式不需要iv,只需要key,但该模式不提倡使用)。

key有 128、192、256 位三种选择,iv固定是 128 位,因为加密块固定是 128 位,需要加密的信息需要先分成 128 位大小的块,如果最后一块不足 128 位需要填充到 128 位(padding)。实际上并不需要用户自己填充,指定参数就行。

代码实现

Java 生成 key 和 iv

生成一个新的key(默认 128 位):

public static SecretKey generateKey(int n) throws NoSuchAlgorithmException {KeyGenerator keyGenerator = KeyGenerator.getInstance("AES");keyGenerator.init(n);SecretKey key = keyGenerator.generateKey();return key;}

生成一个新的iv

public static IvParameterSpec generateIv() {byte[] iv = new byte[16];new SecureRandom().nextBytes(iv);return new IvParameterSpec(iv);}

当然,生成之后最终是要用字符串的格式保存和传送keyiv的。下面使用base64格式保存:

// 使用上面的方法生成 key 并转换为 base64 格式SecretKey key = EncryptUtils.generateKey(128);String keyBase64 = Base64.getEncoder().encodeToString(key.getEncoded());// 使用上面的方法生成 iv 并转换为 base64 格式IvParameterSpec ivParameterSpec = EncryptUtils.generateIv();String ivBase64 = Base64.getEncoder().encodeToString(ivParameterSpec.getIV());

Java 加密 & 解密

首先,可以把base64格式的keyiv转换回 Java 中的类型(参考链接:Converting Secret Key into a String and Vice Versa)

代码如下:

// 导入 keybyte[] keyBytes = Base64.getDecoder().decode(keyBase64);SecretKey key = new SecretKeySpec(keyBytes, 0, keyBytes.length, "AES");// 导入 ivbyte[] ivBytes = Base64.getDecoder().decode(ivBase64);IvParameterSpec iv = new IvParameterSpec(ivBytes);

之后就是用keyiv来进行加密和解密了:

String algorithm = "AES/CBC/PKCS5Padding";// 加密,input 是要加密的明文,返回的是一个 base64 格式的密文:public static String encrypt(String algorithm, String input, SecretKey key,IvParameterSpec iv) throws NoSuchPaddingException, NoSuchAlgorithmException,InvalidAlgorithmParameterException, InvalidKeyException,BadPaddingException, IllegalBlockSizeException {Cipher cipher = Cipher.getInstance(algorithm);cipher.init(Cipher.ENCRYPT_MODE, key, iv);byte[] cipherText = cipher.doFinal(input.getBytes());return Base64.getEncoder().encodeToString(cipherText);}// 解密,cipherText 是 base64格式的密文public static String decrypt(String algorithm, String cipherText, SecretKey key,IvParameterSpec iv) throws NoSuchPaddingException, NoSuchAlgorithmException,InvalidAlgorithmParameterException, InvalidKeyException,BadPaddingException, IllegalBlockSizeException {Cipher cipher = Cipher.getInstance(algorithm);cipher.init(Cipher.DECRYPT_MODE, key, iv);byte[] plainText = cipher.doFinal(Base64.getDecoder().decode(cipherText));return new String(plainText);}

当然,实际使用时还是会做一些封装什么的,比如我把 cipher 单独存起来了。但大体就是这样了。

JavaScript 解密

JS 这边使用CryptoJS这个库来解密。

我没找到介绍 JS AES 加解密的特别好的文章,CryptoJS的文档我感觉写的也不是很好。后来一路磕磕绊绊,看了好多个 StackOverflow 和 JSFiddle 之类的,花了得有俩小时,终于找到了解密方法:

参考链接:AES encryption using Java and decryption using Javascript

// 从 base64 格式导入 key 和 ivvar key = CryptoJS.enc.Base64.parse('nlCdv7/wqRIsf1iWzqz96Q==');var iv = CryptoJS.enc.Base64.parse('n9CvQB/1quXtItsdhnel2g==');function decrypt(encrypted) {var cipherParams = CryptoJS.lib.CipherParams.create({// 从 base64 格式导入密文ciphertext: CryptoJS.enc.Base64.parse(encrypted)});// 解密return CryptoJS.AES.decrypt(cipherParams, key, {iv: iv,padding: CryptoJS.pad.Pkcs7,mode: CryptoJS.mode.CBC}).toString(CryptoJS.enc.Utf8);}

小结

用 Java 进行 AES CBC 加密/解密还是比较简单的,之前只因我太急躁,错误地留下了“这件事很难”的印象。

先把加密的基本原理和流程搞清楚,再做就好多了。

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。