本文档讲述内容与代码示例可参见 Shoulder-Demo1 |
-
设计初衷
提供可配可扩展的常用加解密实现以及通用场景的加密方案。
能力激活方式:
<dependency>
<groupId>cn.itlym</groupId>
<artifactId>shoulder-starter-crypto</artifactId>
<version>0.8.1<version>
</dependency>
compile 'cn.itlym:shoulder-starter-crypto:0.8.1'
能力总览
Shoulder
根据 安全加密规范 做算法选型,并提供了以下算法实现:
-
对称加密
-
AES
-
SM4 (
国密
安全级别同AES128
) -
自定义(几十种算法供选择,一行配置切换)
-
-
非对称加密
-
RSA
-
ECC (高性能对称加密算法,
ECC256
安全级别同RSA2048
) -
SM2(
国密
ECC 版本)
-
-
Hash / 摘要
-
MD5 (注意:尽管有
彩虹表
的存在,MD5
算法安全性有限,不适合在密码上使用,但由于其高性能,在信息摘要/大数据对比方面仍然是优秀算法) -
SHA256
-
SHA256Ex (加随机盐版本的
SHA256
) -
SM3(
国密
安全级别同SHA256
)
-
-
签名 / 防伪 / 防篡改
-
HmacSha256
-
RSA 基于上文
RSA
-
ECDSA 基于上文
ECC
-
-
特殊领域
-
本地绝密
(高性能多级密钥加密算法,适用于数据库/参数中心/配置中心内数据加解密) -
安全通信
:ECDH (基于ECC
+DH
的密钥协商算法实现的安全通信算法,类似应用层HTTPS
,适用于非信任网络环境下的安全通信,如接口传输身份证
、银行卡号
等敏感信息)
-
对称加密
大部分应用层场景是对 文本内容(String)
的加解密,请直接使用 SymmetricTextCipher
即可,而无需关心内部密钥细节。
byte[] key = ... 您的密钥
byte[] iv = ... 您的初始化向量iv
// 加密
String cipher = textCipher.encrypt(key, iv, text);
// 解密
String decryptText = textCipher.decrypt(key, iv, cipher);
如果您需要对字节类对象进行加解密,可使用 SymmetricCipher 类,其提供了 byte[] 类型的加解密方法,您可以直接使用 byte[] 类型的加解密方法,无需转换成 String 类型。
|
若您需要对 数据库 、配置中 中字段加解密,请使用 本地加解密 ,更 安全 也更 便携 。
|
本地安全加解密
对于高频本地加解密场景:数据库内容
、缓存内容
、本地文件内容
,Shoulder
提供了更安全成熟的解决方案,直接使用 LocalTextCipher
:
// 加密
String cipher = localTextCipher.encrypt(text);
// 解密
String decryptText = localTextCipher.decrypt(cipher);
内部实现
LocalTextCipher
默认实现为 LocalTextCipherManager
,其内部包含多个 JudgeAbleLocalTextCipher
用于判断密文版本,支持多种加密算法以便于可能的加密算法升级。
LocalTextCipher
需要一个持久化存储存放 密钥
、初始化向量 IV
、算法版本与优先级
等信息,默认会按照以下顺序尝试自动加载。
-
数据库:若类路径中存在
JdbcTemplate.class
则会使用数据库存储,需要数据库中存在表crypto_info
(表结构详见:JdbcLocalCryptoInfoRepository#CREATE_STATEMENT
) -
Redis:若类路径中存在
RedisTemplate.class
则会使用Redis
存储。 -
文件:若不满足以上两种条件,会自动使用本地文件存储,方便支持重启后仍能对数据加解密。
-
内存:在内存中存储,重启后之前加密的数据无法再解密!仅演示模式使用,不要在生产中使用!
密钥部件持久化
本地安全加解密 需要外部存储保存密钥部件,以确保重启后仍可解密上次运行加密的数据。
|
Shoulder
默认在用户 home
目录保存密钥部件,若您想调整保存方式,可在 application.properties
中显示指定 shoulder.crypto.local.repository=file/jdbc
来主动明确要使用怎样的存储方式。
当指定为 jdbc
时,请确保您引入了数据库相关依赖、链接配置正确性 以及表结构已创建。
CREATE TABLE IF NOT EXISTS crypto_info
(
app_id varchar(32) not null comment '应用标识',
header varchar(32) default '' not null comment '密文前缀/算法标识/版本标志',
data_key varchar(64) not null comment '数据密钥(密文)',
root_key_part varchar(512) null comment '根密钥部件',
vector varchar(64) null comment '初始偏移向量',
create_time datetime default CURRENT_TIMESTAMP null comment '创建时间',
primary key (app_id, header)
)
comment '加密元信息';
非对称加密 AsymmetricTextCipher
大部分应用层场景是对 文本内容(String)
的加解密,请直接使用 AsymmetricTextCipher
即可,而无需关心内部密钥细节。
// 加密
String cipher = asymmetricTextCipher.encrypt(text);
// 解密
String decryptText = asymmetricTextCipher.decrypt(cipher);
// 生成签名摘要
String sign = asymmetricTextCipher.sign(text);
// 验签
boolean signByServer = asymmetricTextCipher.verify(sign);
// 获取公钥
String publicKey = asymmetricTextCipher.getPublicKey();
若您希望使用多个密钥达成更高程度的安全(如不同用户角色非对称密钥不同),也别担心,Shoulder
替您完成了多密钥管理,您只需在所有方法前添加 密钥对代号
即可。
// 确认密钥对
String keyPairId = ... 密钥对标识
// 加密
String cipher = asymmetricTextCipher.encrypt(keyPairId, text);
// 解密
String decryptText = asymmetricTextCipher.decrypt(keyPairId, cipher);
// 生成签名摘要
String sign = asymmetricTextCipher.sign(keyPairId, text);
// 验签
boolean signByServer = asymmetricTextCipher.verify(keyPairId, sign);
// 获取公钥
String publicKey = asymmetricTextCipher.getPublicKey(keyPairId);
如果您需要对字节类对象进行加解密,可使用 AsymmetricCipher 类,其提供了 byte[] 类型的加解密方法,您可以直接使用 byte[] 类型的加解密方法,无需转换成 String 类型。
|
流式加密
对于大数据量的内容需要更高的性能,AES-GCM
结合了 CTR
的并行计算和 GMAC
消息认证能力,具有 高性能
+ 可验证
的特点,无疑是大数据量下“最合适的选择”,在 Shoulder
中对流式内容加密,只需要使用 CryptoableOutputStream
包装即可。
// 加解密文件
String originFilePath = ... 源文件路径,如视频/图片/配置文件...
String cipherFilePath = ... 加密后的文件路径
String resultFilePath = ... 加密后再解密的文件路径
// 加密文件
CryptoableOutputStream.encryptFile(originFilePath, cipherFilePath);
// 解密文件
CryptoableOutputStream.decryptFile(cipherFilePath, resultFilePath);
// 原生用法
public OutputStream os = ... 如文件、网络流
// 加密
os = new CryptoableOutputStream(os, Cipher.ENCRYPT_MODE);
// 解密
os = new CryptoableOutputStream(os, Cipher.DECRYPT_MODE);
摘要 Digest (Hash)
可直接使用 Sha256Utils
轻松将 Sha256
算法带到您的应用中
String text = "yourText";
// 生成摘要
String digest = Sha256Utils.digest(text);
// 校验摘要是否正确
boolean match = Sha256Utils.verify(digest);
Shoulder 也提供了可加盐版本的工具类: Sha256UExtils 。
|
签名 Sign (防伪 / 防篡改)
可直接使用 SignUtil
轻松将 HmacSha256
算法带到您的应用中
String key = ... 签名使用的key
int validSeconds = ... 有效秒数...
String text = "yourText";
// 生成签名
String sign = SignUtil.sign(text);
// 校验签名是否正确
boolean success = SignUtil.verify(sign, key, validSeconds);
签名公式:Base64(AK.时间戳.SHA256(Base64(AK).Base64(时间戳), SK))
签名依赖非对称算法,不适合大数据量内容,若需要加密大数据量内容请参考流式加密,若仅需要大数据校验是否正确,请参考摘要 Digest (Hash) |