背景
我们的游戏充值平台马上要到货一批充值码,需要入库。之前充值码发奖相关的需求都是我做的,但在存储充值码的时候没有加密,是明文存储的。
现在的需求是,数据库中的充值码需要密文存储。这就涉及到:
- 提供一个新增充值码记录的接口,请求参数为明文,使用 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 =