对称加密
DES加密
工作模式
- ECB
- CBC
- PCBC
- CTR
AES加密
des对称加密,是一种比较传统的加密方式,其加密运算、解密运算使用的是同样的密钥,信息的发送者和信息的接收者在进行信息的传输与处理时,必须共同持有该密码(称为对称密码),是一种对称加密算法
创建密码对象,需要传入算法/工作模式/填充模式
工作模式
-
ECB
import java.security.*; import java.util.Base64; import javax.crypto.*; import javax.crypto.spec.*; public class Main { public static void main(String[] args) throws Exception { // 原文: String message = "Hello, world!"; System.out.println("Message(原始信息): " + message); // 128位密钥 = 16 bytes Key: byte[] key = "1234567890abcdef".getBytes(); // 加密: byte[] data = message.getBytes(); byte[] encrypted = encrypt(key, data); System.out.println("Encrypted(加密内容): " + Base64.getEncoder().encodeToString(encrypted)); // 解密: byte[] decrypted = decrypt(key, encrypted); System.out.println("Decrypted(解密内容): " + new String(decrypted)); } // 加密: public static byte[] encrypt(byte[] key, byte[] input) throws GeneralSecurityException { // 创建密码对象,需要传入算法/工作模式/填充模式 Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding"); // 根据key的字节内容,"恢复"秘钥对象 SecretKey keySpec = new SecretKeySpec(key, "AES"); // 初始化秘钥:设置加密模式ENCRYPT_MODE cipher.init(Cipher.ENCRYPT_MODE, keySpec); // 根据原始内容(字节),进行加密 return cipher.doFinal(input); } // 解密: public static byte[] decrypt(byte[] key, byte[] input) throws GeneralSecurityException { // 创建密码对象,需要传入算法/工作模式/填充模式 Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding"); // 根据key的字节内容,"恢复"秘钥对象 SecretKey keySpec = new SecretKeySpec(key, "AES"); // 初始化秘钥:设置解密模式DECRYPT_MODE cipher.init(Cipher.DECRYPT_MODE, keySpec); // 根据原始内容(字节),进行解密 return cipher.doFinal(input); } } -
CBC
package com.apesource.demo04; import java.security.*; import java.util.Base64; import javax.crypto.*; import javax.crypto.spec.*; public class Main { public static void main(String[] args) throws Exception { // 原文: String message = "Hello, world!"; System.out.println("Message(原始信息): " + message); // 256位密钥 = 32 bytes Key: byte[] key = "1234567890abcdef1234567890abcdef".getBytes(); // 加密: byte[] data = message.getBytes(); byte[] encrypted = encrypt(key, data); System.out.println("Encrypted(加密内容): " + Base64.getEncoder().encodeToString(encrypted)); // 解密: byte[] decrypted = decrypt(key, encrypted); System.out.println("Decrypted(解密内容): " + new String(decrypted)); } // 加密: public static byte[] encrypt(byte[] key, byte[] input) throws GeneralSecurityException { // 设置算法/工作模式CBC/填充 Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); // 恢复秘钥对象 SecretKeySpec keySpec = new SecretKeySpec(key, "AES"); // CBC模式需要生成一个16 bytes的initialization vector: SecureRandom sr = SecureRandom.getInstanceStrong(); byte[] iv = sr.generateSeed(16); // 生成16个字节的随机数 System.out.println(Arrays.toString(iv)); IvParameterSpec ivps = new IvParameterSpec(iv); // 随机数封装成IvParameterSpec参数对象 // 初始化秘钥:操作模式、秘钥、IV参数 cipher.init(Cipher.ENCRYPT_MODE, keySpec, ivps); // 加密 byte[] data = cipher.doFinal(input); // IV不需要保密,把IV和密文一起返回: return join(iv, data); } // 解密: public static byte[] decrypt(byte[] key, byte[] input) throws GeneralSecurityException { // 把input分割成IV和密文: byte[] iv = new byte[16]; byte[] data = new byte[input.length - 16]; System.arraycopy(input, 0, iv, 0, 16); // IV System.arraycopy(input, 16, data, 0, data.length); //密文 System.out.println(Arrays.toString(iv)); // 解密: Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); // 密码对象 SecretKeySpec keySpec = new SecretKeySpec(key, "AES"); // 恢复秘钥 IvParameterSpec ivps = new IvParameterSpec(iv); // 恢复IV // 初始化秘钥:操作模式、秘钥、IV参数 cipher.init(Cipher.DECRYPT_MODE, keySpec, ivps); // 解密操作 return cipher.doFinal(data); } // 合并数组 public static byte[] join(byte[] bs1, byte[] bs2) { byte[] r = new byte[bs1.length + bs2.length]; System.arraycopy(bs1, 0, r, 0, bs1.length); System.arraycopy(bs2, 0, r, bs1.length, bs2.length); return r; } } -
PCBC
-
CTR
IDEA
工作模式
- ECB
非对称加密
RSA
RSA是非对称的,RSA其实一般用来传输AES的秘钥或者加密一些数据量比较小的场景,AES的速度更快一些。
java实现
import java.math.BigInteger;
import java.security.GeneralSecurityException;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.PrivateKey;
import java.security.PublicKey;
import javax.crypto.Cipher;
// RSA
public class Main {
public static void main(String[] args) throws Exception {
// 明文:
byte[] plain = "Hello, encrypt use RSA".getBytes("UTF-8");
// 创建公钥/私钥对:
Human alice = new Human("Alice");
// 用Alice的公钥加密:
// 获取Alice的公钥,并输出
byte[] pk = alice.getPublicKey();
System.out.println(String.format("public key(公钥): %x", new BigInteger(1, pk)));
// 使用公钥加密
byte[] encrypted = alice.encrypt(plain);
System.out.println(String.format("encrypted(加密): %x", new BigInteger(1, encrypted)));
// 用Alice的私钥解密:
// 获取Alice的私钥,并输出
byte[] sk = alice.getPrivateKey();
System.out.println(String.format("private key(私钥): %x", new BigInteger(1, sk)));
// 使用私钥解密
byte[] decrypted = alice.decrypt(encrypted);
System.out.println("decrypted(解密): " + new String(decrypted, "UTF-8"));
}
}
// 用户类
class Human {
// 姓名
String name;
// 私钥:
PrivateKey sk;
// 公钥:
PublicKey pk;
// 构造方法
public Human(String name) throws GeneralSecurityException {
// 初始化姓名
this.name = name;
// 生成公钥/私钥对:
KeyPairGenerator kpGen = KeyPairGenerator.getInstance("RSA");
kpGen.initialize(1024);
KeyPair kp = kpGen.generateKeyPair();
this.sk = kp.getPrivate();
this.pk = kp.getPublic();
}
// 把私钥导出为字节
public byte[] getPrivateKey() {
return this.sk.getEncoded();
}
// 把公钥导出为字节
public byte[] getPublicKey() {
return this.pk.getEncoded();
}
// 用公钥加密:
public byte[] encrypt(byte[] message) throws GeneralSecurityException {
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.ENCRYPT_MODE, this.pk); // 使用公钥进行初始化
return cipher.doFinal(message);
}
// 用私钥解密:
public byte[] decrypt(byte[] input) throws GeneralSecurityException {
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.DECRYPT_MODE, this.sk); // 使用私钥进行初始化
return cipher.doFinal(input);
}
}
摘要算法
MD5
SHA256
其他
SHA1WITHRSA
SHA1withRSA:浅显的理解,用SHA算法进行签名,用RSA算法进行加密。
SHA1安全哈希算法(Secure Hash Algorithm)主要适用于数字签名标准 (Digital Signature Standard DSS)里面定义的数字签名算法(Digital Signature Algorithm DSA)
生成密钥公钥证书
openssl genrsa -out rsa_private_key.pem 1024
pkcs8 -topk8 -inform PEM -in rsa_private_key.pem -outform PEM -nocrypt(java需使用pkcs8 )
openssl rsa -in rsa_private_key.pem -pubout -out rsa_public_key.pem
java实现加密解密签名摘要
简单实现
- 加密
/**
* content: 加密内容
* slatKey: 加密的盐,16位字符串
* vectorKey: 加密的向量,16位字符串
*/
public String encrypt(String content, String slatKey, String vectorKey) throws Exception {
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
SecretKey secretKey = new SecretKeySpec(slatKey.getBytes(), "AES");
IvParameterSpec iv = new IvParameterSpec(vectorKey.getBytes());
cipher.init(Cipher.ENCRYPT_MODE, secretKey, iv);
byte[] encrypted = cipher.doFinal(content.getBytes());
return Base64.encodeBase64String(encrypted);
}
- 解密
/**
* content: 解密内容(base64编码格式)
* slatKey: 加密时使用的盐,16位字符串
* vectorKey: 加密时使用的向量,16位字符串
*/
public String decrypt(String base64Content, String slatKey, String vectorKey) throws Exception {
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
SecretKey secretKey = new SecretKeySpec(slatKey.getBytes(), "AES");
IvParameterSpec iv = new IvParameterSpec(vectorKey.getBytes());
cipher.init(Cipher.DECRYPT_MODE, secretKey, iv);
byte[] content = Base64.decodeBase64(base64Content);
byte[] encrypted = cipher.doFinal(content);
return new String(encrypted);
}
Cipher类
实现加密,包括DES,DES3,AES和RSA加密
Cipher cipher = Cipher.getInstance(“DES/CBC/PKCS5Padding”); 参数按"算法/模式/填充模式",有以下的参数
- AES/CBC/NoPadding (128)
- AES/CBC/PKCS5Padding (128)
- AES/ECB/NoPadding (128)
- AES/ECB/PKCS5Padding (128)
- DES/CBC/NoPadding (56)
- DES/CBC/PKCS5Padding (56)
- DES/ECB/NoPadding (56)
- DES/ECB/PKCS5Padding (56)
- DESede/CBC/NoPadding (168)
- DESede/CBC/PKCS5Padding (168)
- DESede/ECB/NoPadding (168)
- DESede/ECB/PKCS5Padding (168)
- RSA/ECB/PKCS1Padding (1024, 2048)
- RSA/ECB/OAEPWithSHA-1AndMGF1Padding (1024, 2048)
- RSA/ECB/OAEPWithSHA-256AndMGF1Padding (1024, 2048)
介绍
- 加密算法
AES,DES,DESede(DES3)和RSA 四种
-
模式
CBC(有向量模式)和ECB(无向量模式),向量模式可以简单理解为偏移量,使用CBC模式需要定义一个IvParameterSpec对象
-
填充模式
- NoPadding: 加密内容不足8位用0补足8位, Cipher类不提供补位功能,需自己实现代码给加密内容添加0, 如{65,65,65,0,0,0,0,0}
- PKCS5Padding: 加密内容不足8位用余位数补足8位, 如{65,65,65,5,5,5,5,5}或{97,97,97,97,97,97,2,2}; 刚好8位补8位8
Cipher初始化
init(int opmode, Key key, AlgorithmParameterSpec params)
-
opmode :
- Cipher.ENCRYPT_MODE(加密模式)
- Cipher.DECRYPT_MODE(解密模式)
-
key :密匙,使用传入的盐构造出一个密匙,可以使用SecretKeySpec、KeyGenerator和KeyPairGenerator创建密匙,其中
-
SecretKeySpec和KeyGenerator支持AES,DES,DESede三种加密算法创建密匙
-
KeyPairGenerator支持RSA加密算法创建密匙
-
-
params :使用CBC模式时必须传入该参数,该项目使用IvParameterSpec创建iv 对象
加密或解密
byte[] b = cipher.doFinal(content);
返回结果为byte数组,如果直接使用 new String(b) 封装成字符串,则会出现乱码
创建密匙
创建密匙主要使用SecretKeySpec、KeyGenerator和KeyPairGenerator三个类来创建密匙。
SecretKeySpec类
SecretKeySpec类支持创建密匙的加密算法(ASE,DES,DES3)
SecretKey secretKey = new SecretKeySpec(slatKey.getBytes(), "AES");
需要注意的是不同的加密算法的byte数组的长度是不同的,创建密匙前最好先检测下byte数组的长度
KeyGenerator类
KeyGenerator类支持创建密匙的加密算法(ASE,DES,DES3,HmacSHA1,HmacSHA256)
/**
* 获取加密的密匙,传入的slatKey可以是任意长度的,作为SecureRandom的随机种子,
* 而在KeyGenerator初始化时设置密匙的长度128bit(16位byte)
*/
private static Key getSlatKey(String slatKey) throws Exception {
KeyGenerator kgen = KeyGenerator.getInstance("AES");
SecureRandom random = SecureRandom.getInstance("SHA1PRNG");
random.setSeed(slatKey.getBytes());
kgen.init(128, random);
Key key = kgen.generateKey();
return key;
}
KeyGenerator对象在初始化需要传入一个随机源。一般使用的都是SecureRandom类来创建随机源,此时传入的盐只作为SecureRandom类的随机种子,种子相同,产生的随机数也相同;
盐的长度不再受限制了,但KeyGenerator对象则必须指定长度。
KeyPairGenerator 类
RSA加密算法使用的密匙是包含公匙和私匙两种,一般情况下,有使用公匙加密,则用私匙解密;使用私匙加密,则使用公匙解密。可以使用KeyPairGenerator类来创建RSA加密算法的密匙
DSA/RSA/EC
/**
* 根据slatKey获取公匙,传入的slatKey作为SecureRandom的随机种子
* 若使用new SecureRandom()创建公匙,则需要记录下私匙,解密时使用
*/
private static byte[] getPublicKey(String slatKey) throws Exception {
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
SecureRandom random = SecureRandom.getInstance("SHA1PRNG");
random.setSeed(slatKey.getBytes());
keyPairGenerator.initialize(1024, random);//or 2048
KeyPair keyPair = keyPairGenerator.generateKeyPair();
return keyPair.getPublic().getEncoded();
}
/**
* 根据slatKey获取私匙,传入的slatKey作为SecureRandom的随机种子
*/
private static byte[] getPrivateKey(String slatKey) throws Exception {
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
SecureRandom random = SecureRandom.getInstance("SHA1PRNG");
random.setSeed(slatKey.getBytes());
keyPairGenerator.initialize(1024, random);// or 2048
KeyPair keyPair = keyPairGenerator.generateKeyPair();
return keyPair.getPrivate().getEncoded();
}
Mac类
基于密钥的哈希消息认证
HMAC(Hash-based Message Authentication Code,散列消息认证码)是一种使用密码散列函数,同时结合一个加密密钥,通过特别计算方式之后产生的消息认证码(MAC)。它可以用来保证数据的完整性,同时可以用来作某个消息的身份验证。
HMAC算法 是一种基于密钥的报文完整性的验证方法。HMAC算法利用哈希运算,以一个密钥和一个消息为输入,生成一个消息摘要作为输出。其安全性是建立在Hash加密算法基础上的。它要求通信双方共享密钥、约定算法、对报文进行Hash运算,形成固定长度的认证码。通信双方通过认证码的校验来确定报文的合法性。HMAC算法可以用来作加密、数字签名、报文验证等。
原文链接:https://blog.csdn.net/qq_32907491/article/details/131524420
该类主要用作Hmac运算,初始化方法Mac.getInstance(String algorithm)的可用参数有
HmacMD5
HmacSHA1
HmacSHA224
HmacSHA256
HmacSHA384
HmacSHA512
public void testHmac() throws Exception {
Mac mac = Mac.getInstance("HmacMD5");
//第一个参数可以是任意字符串,第二个参数与获取Mac对象的algorithm相同
SecretKeySpec secretKeySpec = new SecretKeySpec("123456".getBytes(), "HmacMD5");
mac.init(secretKeySpec);
byte[] bytes = mac.doFinal("helloworld".getBytes());
System.out.println("HmacMD5结果:" + HexUtil.toHexString(bytes));
mac = Mac.getInstance("HmacSHA1");
mac.init(new SecretKeySpec("123456".getBytes(), "HmacSHA1"));
bytes = mac.doFinal("helloworld".getBytes());
System.out.println("HmacSHA1结果:" + HexUtil.toHexString(bytes));
}
Signature类
signature类用于提供数字签名,用于保证数据的完整性
示例代码,Signature.getInstance(String algorithm)的可用参数有
- NONEwithRSA
- MD2withRSA
- MD5withRSA
- SHA1withRSA
- SHA224withRSA
- SHA256withRSA
- SHA384withRSA
- SHA512withRSA
- NONEwithDSA
- SHA1withDSA
- SHA224withDSA
- SHA256withDSA
- NONEwithECDSA
- SHA1withECDSA
- SHA224withECDSA
- SHA256withECDSA
- SHA384withECDSA
- SHA512withECDSA
public void testSignature() throws Exception {
Signature signature = Signature.getInstance("NONEwithRSA");
//KeyPairGenerator生成公钥和私钥
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
keyPairGenerator.initialize(1024);
KeyPair keyPair = keyPairGenerator.generateKeyPair();
PublicKey publicKey = keyPair.getPublic();
PrivateKey privateKey = keyPair.getPrivate();
//用私钥初始化signature
signature.initSign(privateKey);
//更新原始字符串
signature.update(TEXT.getBytes());
byte[] bytes = signature.sign();
String sign = Base64.getEncoder().encodeToString(bytes);
System.out.println("数字签名: " + sign);
//用公钥初始化signature
signature.initVerify(publicKey);
//更新原始字符串
signature.update(TEXT.getBytes());
//校验签名是否正确
boolean result = signature.verify(Base64.getDecoder().decode(sign));
System.out.println("签名校验结果: " + result);
}
常用三种RSA、DSA、ECDSA
- RSA
public static void jdkRSA() {
try {
//1.初始化密钥
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
keyPairGenerator.initialize(512);
KeyPair keyPair = keyPairGenerator.generateKeyPair();
RSAPublicKey rsaPublicKey = (RSAPublicKey)keyPair.getPublic();
RSAPrivateKey rsaPrivateKey = (RSAPrivateKey)keyPair.getPrivate();
//2.执行签名
PKCS8EncodedKeySpec pkcs8EncodedKeySpec =
new PKCS8EncodedKeySpec(rsaPrivateKey.getEncoded());
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
PrivateKey privateKey = keyFactory.generatePrivate(pkcs8EncodedKeySpec);
Signature signature = Signature.getInstance("MD5withRSA");
signature.initSign(privateKey);
signature.update(src.getBytes());
byte[] result = signature.sign();
//3.验证签名
X509EncodedKeySpec x509EncodedKeySpec =
new X509EncodedKeySpec(rsaPublicKey.getEncoded());
keyFactory = KeyFactory.getInstance("RSA");
PublicKey publicKey = keyFactory.generatePublic(x509EncodedKeySpec);
signature = Signature.getInstance("MD5withRSA");
signature.initVerify(publicKey);
signature.update(src.getBytes());
boolean bool = signature.verify(result);
System.out.println("jdk rsa verify : " + bool);
} catch (Exception e) {
e.printStackTrace();
}
}
- DSA
public static void jdkDSA() {
try {
//1.初始化密钥
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("DSA");
keyPairGenerator.initialize(512);
KeyPair keyPair = keyPairGenerator.generateKeyPair();
DSAPublicKey dsaPublicKey = (DSAPublicKey) keyPair.getPublic();
DSAPrivateKey dsaPrivateKey = (DSAPrivateKey)keyPair.getPrivate();
//2.执行签名
PKCS8EncodedKeySpec pkcs8EncodedKeySpec =
new PKCS8EncodedKeySpec(dsaPrivateKey.getEncoded());
KeyFactory keyFactory = KeyFactory.getInstance("DSA");
PrivateKey privateKey = keyFactory.generatePrivate(pkcs8EncodedKeySpec);
Signature signature = Signature.getInstance("SHA1withDSA");
signature.initSign(privateKey);
signature.update(src.getBytes());
byte[] result = signature.sign();
System.out.println("jdk dsa sign : " + Hex.encodeHexString(result));
//3.验证签名
X509EncodedKeySpec x509EncodedKeySpec =
new X509EncodedKeySpec(dsaPublicKey.getEncoded());
keyFactory = KeyFactory.getInstance("DSA");
PublicKey publicKey = keyFactory.generatePublic(x509EncodedKeySpec);
signature = Signature.getInstance("SHA1withDSA");
signature.initVerify(publicKey);
signature.update(src.getBytes());
boolean bool = signature.verify(result);
System.out.println("jdk dsa verify : " + bool);
} catch (Exception e) {
e.printStackTrace();
}
}
- ECDSA
public static void jdkECDSA() {
try {
//1.初始化密钥
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("EC");
keyPairGenerator.initialize(256);
KeyPair keyPair = keyPairGenerator.generateKeyPair();
ECPublicKey ecPublicKey = (ECPublicKey)keyPair.getPublic();
ECPrivateKey ecPrivateKey = (ECPrivateKey)keyPair.getPrivate();
//2.执行签名
PKCS8EncodedKeySpec pkcs8EncodedKeySpec =
new PKCS8EncodedKeySpec(ecPrivateKey.getEncoded());
KeyFactory keyFactory = KeyFactory.getInstance("EC");
PrivateKey privateKey = keyFactory.generatePrivate(pkcs8EncodedKeySpec);
Signature signature = Signature.getInstance("SHA1withECDSA");
signature.initSign(privateKey);
signature.update(src.getBytes());
byte[] result = signature.sign();
System.out.println("jdk ecdsa sign : " + Hex.encodeHexString(result));
//3.验证签名
X509EncodedKeySpec x509EncodedKeySpec =
new X509EncodedKeySpec(ecPublicKey.getEncoded());
keyFactory = KeyFactory.getInstance("EC");
PublicKey publicKey = keyFactory.generatePublic(x509EncodedKeySpec);
signature = Signature.getInstance("SHA1withECDSA");
signature.initVerify(publicKey);
signature.update(src.getBytes());
boolean bool = signature.verify(result);
System.out.println("jdk ecdsa verify : " + bool);
} catch (Exception e) {
e.printStackTrace();
}
}
MessageDiges类
MessageDigest主要是做hash变换(也称消息摘要或者散列值)
@org.junit.Test
public void testMessageDigest() throws Exception {
//参数可以是 MD5,MD2,MD5,SHA-1,SHA-224,SHA-256,SHA-384,SHA-512
MessageDigest messageDigest = MessageDigest.getInstance("MD5");
byte[] bytes = messageDigest.digest("helloworld".getBytes());
//将二进制数组转成16进制字符串输出
System.out.println("MD5哈希变换:" + HexUtil.toHexString(bytes));
messageDigest = MessageDigest.getInstance("SHA-1");
bytes = messageDigest.digest("helloworld".getBytes());
System.out.println("SHA1哈希变换:" + HexUtil.toHexString(bytes));
}
//HexUtil
public static String toHexString(byte[] data) {
StringBuilder builder = new StringBuilder();
int len = data.length;
String hex;
for (int i = 0; i < len; i++) {
hex = Integer.toHexString(data[i] & 0xFF);
if (hex.length() == 1) {
builder.append("0");
}
builder.append(hex);
}
return builder.toString();
}
//MD5哈希变换:fc5e038d38a57032085441e7fe7010b0
//SHA1哈希变换:6adfb183a4a2c94a2f92dab5ade762a47889a5a1

2418

被折叠的 条评论
为什么被折叠?



