数据加密是计算机系统对信息进行保护的一种最可靠的办法。它利用密码技术对信息进行加密,实现信息隐蔽,从而起到保护信息的安全的作用。本文主要介绍了几种常见的数据加密算法(对称密码算法/非对称密码算法)的 Java 实现和常见编码方式的使用。
对称加密指加密和解密使用相同密钥的加密算法。常见的对称加密算法包括:
算法 | 说明 | 密钥长度 | 默认密钥长度 | 工作模式 | 填充方式 | 默认填充方式 | 实现方式 |
---|---|---|---|---|---|---|---|
DES | 数据加密标准 | 56bit | 56bit | ECB、CBC、PCBC、CTR、CTS、CFB、CFB8-CFB128、OFB、OFB8-OFB128 | NoPadding、PKCS5Padding、ISO10126Padding | PKCS5Padding | JDK |
3DES | 进行了三重DES加密的算法 | 112bit、168bit | 168bit | ECB、CBC、PCBC、CTR、CTS、CFB、CFB8-CFB128、OFB、OFB8-OFB128 | NoPadding、PKCS5Padding、ISO10126Padding | PKCS5Padding | JDK |
AES(推荐使用) | 高级数据加密标准,AES算法可以有效抵制针对DES的攻击算法 | 128bit、192bit、256bit | 128bit | ECB、CBC、PCBC、CTR、CTS、CFB、CFB8-CFB128、OFB、OFB8-OFB128 | NoPadding、PKCS5Padding、ISO10126Padding | PKCS5Padding | JDK |
Java实现,密钥建立时间短、灵敏性好、内存需求低、安全性高。AES 算法我们选择 CBC 模式,可以增强安全性。
1、生成密钥
KeyGenerator keyGen = KeyGenerator.getInstance("AES"); // 密钥生成器
keygen.init(128); // 默认128, 获得无政策权限后可为192或256
SecretKey secretKey = keyGen.generateKey(); // 生成密钥
byte[] enCodeFormat = secretKey.getEncoded(); // 密钥字节数组
2、定义16 byte IV
private static final byte[] IV_BYTES = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01};
3、AES-CBC 加密
IvParameterSpec iv = new IvParameterSpec(IV_BYTES);
SecretKeySpec sKeySpec = new SecretKeySpec(key, "AES"); // key: 密钥
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); // 密码器
cipher.init(Cipher.ENCRYPT_MODE, sKeySpec, iv); // 对Cipher初始化, 加密模式
byte[] result = cipher.doFinal(value.getBytes("UTF-8")); // value: 需要加密的字符串, result: 加密后的结果
4、AES-CBC 解密
IvParameterSpec iv = new IvParameterSpec(IV_BYTES);
SecretKeySpec sKeySpec = new SecretKeySpec(key, "AES"); // key: 密钥
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); // 密码器
cipher.init(Cipher.DECRYPT_MODE, sKeySpec, iv); // 对Cipher初始化, 解密模式
String result = new String(cipher.doFinal(value), "UTF-8"); // value: 需要解密的二进制字节数组, result: 解密后的结果
非对称加密算法是一种基于密钥的保密方法,需要公开密钥和私有密钥,在文件加密、尤其是网银中应用广泛。非对称密码算法比对称密码算法更安全。常见的非对称加密算法包括:
算法 | 说明 | 密钥长度 | 默认密钥长度 | 工作模式 | 填充方式 | 实现方式 |
---|---|---|---|---|---|---|
DH | 密钥交换算法 | 512-1024 (64的整数倍) | 1024 | 无 | 无 | JDK |
RSA(推荐使用) | 基于因子分解,用于数据加密和数字签名 | 512-65536 (64的整数倍) | 1024 | ECB | NoPadding、PKCS1Padding、OAEPWITHMD5AndMGF1Padding、OAEPWITHSHA1AndMGF1Padding、OAEPWITHSHA256AndMGF1Padding、OAEPWITHSHA384AndMGF1Padding、OAEPWITHSHA512AndMGF1Padding | JDK |
2048 | NONE | NoPadding、PKCS1Padding、OAEPWITHMD5AndMGF1Padding、OAEPWITHSHA1AndMGF1Padding、OAEPWITHSHA224AndMGF1Padding、OAEPWITHSHA256AndMGF1Padding、OAEPWITHSHA384AndMGF1Padding、OAEPWITHSHA512AndMGF1Padding、ISO9796-1Padding | BC | |||
ElGamal | 基于离散对数,只提供了公钥加密算法,私钥不能加密 | 160-16384 (8的整数倍) | 1024 | ECB、NONE | “和如上RSA的BC实现相同” | BC |
ECC | 椭圆曲线加密 |
初始化密钥:
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA"); // 密钥生成器
keyPairGenerator.initialize(1024); // 默认1024
KeyPair keyPair = keyPairGenerator.generateKeyPair(); // 生成密钥
RSAPublicKey rsaPublicKey = (RSAPublicKey) keyPair.getPublic(); // 获取公钥
RSAPrivateKey rsaPrivateKey = (RSAPrivateKey) keyPair.getPrivate(); // 获取私钥
公钥需要发送给客户端,私钥存储在服务端中。
1、私钥加密,公钥解密
服务端私钥加密:
PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(rsaPrivateKey.getEncoded()); // rsaPrivateKey:私钥
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
PrivateKey privateKey = keyFactory.generatePrivate(pkcs8EncodedKeySpec);
Cipher cipher = Cipher.getInstance("RSA"); // 密码器
cipher.init(Cipher.ENCRYPT_MODE, privateKey); // 对Cipher初始化, 加密模式
byte[] result = cipher.doFinal(inStr.getBytes("UTF-8")); // inStr: 需要加密的字符串, result: 加密后的结果
客户端公钥解密:
X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(rsaPublicKey.getEncoded()); // rsaPublicKey:公钥
keyFactory = KeyFactory.getInstance("RSA");
PublicKey publicKey = keyFactory.generatePublic(x509EncodedKeySpec);
Cipher cipher = Cipher.getInstance("RSA"); // 密码器
cipher.init(Cipher.DECRYPT_MODE, publicKey); // 对Cipher初始化, 解密模式
String result = new String(cipher.doFinal(inByte), "UTF-8"); // inByte: 需要解密的二进制字节数组, result:解密后的结果
2、公钥加密,私钥解密
客户端公钥加密:
X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(rsaPublicKey.getEncoded()); //rsaPublicKey:公钥
keyFactory = KeyFactory.getInstance("RSA");
PublicKey publicKey = keyFactory.generatePublic(x509EncodedKeySpec);
Cipher cipher = Cipher.getInstance("RSA"); // 密码器
cipher.init(Cipher.ENCRYPT_MODE, publicKey); // 对Cipher初始化, 加密模式
byte[] result = cipher.doFinal(inStr.getBytes("UTF-8")); // inStr: 需要加密的字符串, result: 加密后的结果
服务端私钥解密:
PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(rsaPrivateKey.getEncoded()); // rsaPrivateKey: 私钥
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
PrivateKey privateKey = keyFactory.generatePrivate(pkcs8EncodedKeySpec);
Cipher cipher = Cipher.getInstance("RSA"); // 密码器
cipher.init(Cipher.DECRYPT_MODE, privateKey); // 对Cipher初始化, 解密模式
String result = new String(cipher.doFinal(inByte), "UTF-8"); // inByte: 需要解密的二进制字节数组, result: 解密后的结果
Base64 是网络上最常见的用于传输 8 位字节码的编码方式之一。Base64 不是加密算法,而是一种编码方式,由于加密后都是 byte[],为了可读性,一般将 byte[] 转为 base64 编码。最简单的使用方法是添加如下 Maven 依赖:
<dependency>
<groupId>commons-codecgroupId>
<artifactId>commons-codecartifactId>
<version>1.11version>
dependency>
commons-codec 是 Apache 开源组织提供的用于摘要运算、编码的包 (简化 JDK)。Base64 编码和解码的方法如下:
// 编码,inStr:需要编码的字符串
String result = new String(Base64.encodeBase64(inStr.getBytes()), "UTF-8");
// 解码,inStr:需要解码的字符串
String result = new String(Base64.decodeBase64(inStr.getBytes()), "UTF-8");
自定义 Base64 编码:
URL编码 (URL encoding),也称作百分号编码 (Percent-encoding), 是特定上下文的统一资源定位符 (URL) 的编码机制。适用于统一资源标识符 (URI) 的编码,也用于为 “application/x-www-form-urlencoded” MIME 准备数据, 因为它用于通过 HTTP 的请求操作 (request) 提交 HTML 表单数据。
URL 编码和解码的方法如下:
// 编码, inStr: 需要编码的字符串
String result = URLEncoder.encode(inStr, "UTF-8");
// 解码, inStr: 需要解码的字符串
String result = URLDecoder.decode(inStr, "UTF-8");
消息摘要算法是为了验证数据的完整性而出现的,它是数字签名的核心算法。常见的消息摘要算法包括:
算法 | 说明 | 摘要长度 | 包含算法 | 实现方式 | 适用场景 |
---|---|---|---|---|---|
MD | 消息摘要,不可逆加密 | 128 | MD2、MD4、MD5 | JDK(MD2、MD5)、BC(MD4) | 用户注册的时候对密码进行加密 |
SHA | 安全散列算法,固定长度摘要信息,不可逆加密 | SHA-1(160)、SHA-224(224)、SHA-256(256)、SHA-384(384)、SHA-512(512) | SHA-1、SHA-2(SHA-224、SHA-256、SHA-384、SHA-512) | JDK(SHA-1、SHA-256、SHA-384、SHA-512)、BC(SHA-224) | |
MAC | 消息认证码,不可逆加密 | JDK |
消息摘要算法加密最简单的方法是使用 commons-codec:
// MD5
String md5Str = DigestUtils.md5Hex(inStr); //inStr: 需要加密的字符串, md5Str: 加密后的结果
// SHA1
String sha1Str = DigestUtils.sha1Hex(inStr)); //inStr: 需要加密的字符串, sha1Str: 加密后的结果