文章目录
一、常用的加密算法及简略介绍
1、常用加密算法
Base64编码
严格来说只是一种编码方式,并不算是加密算法
Base64 编码是从二进制到字符的过程,用 64 个字符来表示任意的二进制数据,常用于在 HTTP 加密,图片编码传输等
MD5信息摘要算法
Message Digest algorithm 5
一般用于确保信息的传输完整一致性,校验传输的数据是否被修改,一旦原始信息被修改,生成的 MD5 值将会变得很不同
SHA密码散列函数家族
FIPS 所认证的安全散列算法,和 MD5 类似,都是对文本进行散列,产生一定长度的散列值
HMAC散列消息鉴别码
Hash Message Authentication Code
是一种通过特别计算方式之后产生的消息认证码(MAC),使用密码散列函数,同时结合一个加密密钥。它可以用来保证数据的完整性,同时可以用来作某个消息的身份验证。
2、对称加密
对称加密的意思就是信息收发都有相同的一把钥匙,消息的加密解密都用这把钥匙进行。
1、DES
Data Encryption Standard,数据加密标准,速度较快,适用于加密大量数据的场合。
2、3DES
DES的升级版,原理和DES一样,需要处理三个密钥
3、AES
Advanced Encryption Standard,高级加密标准,是下一代的加密算法标准,速度快,安全级别高;
3、非对称加密
非对称加密算法是一种密钥的保密方法。
非对称加密算法需要两个密钥:
公开密钥(publickey)和私有密钥(privatekey)。
公开密钥与私有密钥是一对,如果用公开密钥对数据进行加密,只有用对应的私有密钥才能解密;如果用私有密钥对数据进行加密,那么只有用对应的公开密钥才能解密。
1、RSA
名称来源于发明这个算法的三个人的姓氏组成,算法大致内容就是对极大整数进行因式分解
这种算法非常可靠,密钥越长,它就越难破解。根据已经披露的文献,目前被破解的最长 RSA密钥是768个二进制位。也就是说,长度超过768位的密钥,还无法破解(至少没人公开宣布)。因此可以认为,1024位的RSA密钥基本安全,2048位的密钥极其安全。
2、DSA
Digital Signature Algorithm,数字签名算法,是一种标准的 DSS(数字签名标准);
3、ECC
Elliptic Curves Cryptography,椭圆曲线密码编码学。
一种建立公开密钥加密的算法,基于椭圆曲线数学。
ECC的主要优势是在某些情况下它比其他的方法使用更小的密钥——比如RSA加密算法——提供相当的或更高等级的安全。ECC的另一个优势是可以定义群之间的双线性映射,基于Weil对或是Tate对;双线性映射已经在密码学中发现了大量的应用,例如基于身份的加密。不过一个缺点是加密和解密操作的实现比其他机制花费的时间长。
总结
现在的加密算法大部分情况下是为了验证数据的一致性,例如传递一些参数组的时候,简单的会使用 BASE64 或 MD5 进行加密生成一个签名。复杂点就是 BASE64 编码之后再用 对称密钥再加密一次,达到比较不容易被人篡改的目的
对于一些支付场景,一般使用非对称加密算法 实现,这样的场景需要的安全性更高。
二、简单介绍算法示例
1、Base64
public static void main(String[] args) throws Exception {
String data = "即将加密的数据";
//base64加密(方式1)
String encData1 = Base64.encodeBase64String(data.getBytes());
//base64加密(方式2)
String encData2 = (new BASE64Encoder()).encodeBuffer(data.getBytes());
System.out.println("encData1 = "+ encData1);
System.out.println("encData2 = "+ encData2);
//base64解密(方式1)
byte[] decData1 = Base64.decodeBase64(encData1);
byte[] decData2 = Base64.decodeBase64(encData2);
//base64解密(方式2)
byte[] decData3 = (new BASE64Decoder()).decodeBuffer(encData1);
byte[] decData4 = (new BASE64Decoder()).decodeBuffer(encData2);
System.out.println("decData1 = "+ new String(decData1) );
System.out.println("decData2 = "+ new String(decData2) );
System.out.println("decData3 = "+ new String(decData3) );
System.out.println("decData4 = "+ new String(decData4) );
}
2、MD5
public static void main(String[] args) throws Exception {
String data = "即将加密的数据";
// 拿到一个MD5转换器
MessageDigest md5 = MessageDigest.getInstance("MD5");
md5.update(data.getBytes());
BigInteger encData = new BigInteger(md5.digest());
//加密之后转换为16进制字符串
System.out.println("encData = "+ encData.toString(16));
}
3、SHA
public static void main(String[] args) throws Exception {
String data = "即将加密的数据";
// 拿到一个SHA转换器
MessageDigest sha = MessageDigest.getInstance("SHA");
sha.update(data.getBytes());
BigInteger encData = new BigInteger(sha.digest());
//加密之后转换为32进制字符串
System.out.println("encData = "+ encData.toString(32));
}
4、HMAC
/**
* MAC算法可选以下多种算法
* <pre>
* HmacMD5
* HmacSHA1
* HmacSHA256
* HmacSHA384
* HmacSHA512
* </pre>
*/
public static final String KEY_MAC = "HmacMD5";
public static void main(String[] args) throws Exception {
String data = "即将加密的数据";
String key = "给定密钥";
//根据给定的字节数组构造一个密钥,第二参数指定一个密钥算法的名称
SecretKey secretKey = new SecretKeySpec(key.getBytes(), KEY_MAC);
//getInstance得到实例
Mac mac = Mac.getInstance(secretKey.getAlgorithm());
//用给定密钥初始化 Mac 对象
mac.init(secretKey);
// 加密处理
BigInteger macMd5 = new BigInteger(mac.doFinal(data.getBytes()))
System.out.println("HMAC:" + macMd5.toString(16));
}
5、对称加密
在对称加密算法中,加密与解密的密钥是相同的。
128 192 256 分别表示密钥的长度。
填充方式:
1、NoPadding
不进行填充,但是这里要求明文必须要是16个字节的整数倍,如果一定要用 NoPadding 的话,那么必须保证原文字节是 8 的倍数,否则的话需要使用其他的填充模式。
2、PKCS5Padding(默认)
在明文的末尾进行填充,填充的数据是当前和16个字节相差的数量,例如:
- 未填充明文
1,2,3,4,5,6,7,8,9,10,11- 填充明文(缺少五个满足16个字节)
1,2,3,4,5,6,7,8,9,10,11,5,5,5,5,5注:使用PKCS7Padding/PKCS5Padding填充时,最后一个字节肯定为填充数据的长度,所以在解密后可以准确删除填充的数据
3、 ISO10126Padding
在明文的末尾进行填充,当前和16个字节相差的数量填写在最后,其余字节填充随机数,例如:
- 未填充明文
1,2,3,4,5,6,7,8,9,10,11- 填充明文(缺少五个满足16个字节)
1,2,3,4,5,6,7,8,9,10,11,c,b,4,1,5
模式
模式是需要制定AES对明文进行加密时使用的模式,一共有五种模式,模式的基本原理是相似的,但是细节上会有一些变化。
- ECB模式(默认):电码本模式
- CBC模式:密码分组链接模式
- CFB模式:密码反馈模式
- OFB模式:输出反馈模式
- CTR模式:计算器模式
如果想详细了解内部原理可以参考:
https://www.cnblogs.com/better-farther-world2099/p/13293291.html
https://blog.csdn.net/qq_28205153/article/details/55798628
1、AES-128-ECB
public static void main(String[] args) throws Exception {
/*
* 此处使用AES-128-ECB加密模式。
*/
String key = "很随便的密钥";
// 需要加密的字串
String data = "即将加密的数据";
// 加密
String encData = encrypt(data, key);
System.out.println("加密后的字串是:" + encData);
// 解密
String decData = decrypt(encData, key);
System.out.println("解密后的字串是:" + decData);
}
// 加密
public static String encrypt(String data, String key) throws Exception {
//创建AES的Key生产者
KeyGenerator kgen = KeyGenerator.getInstance("AES");
// 利用"很随便的密钥"作为随机数初始化生成一个128字节16位的密钥
kgen.init(128, new SecureRandom(key.getBytes()));
//SecureRandom是生成安全随机数序列
SecretKey secretKey = kgen.generateKey();
byte[] rKey = secretKey.getEncoded();
// 转换为AES专用密钥
SecretKeySpec skeySpec = new SecretKeySpec(rKey, "AES");
// 创建密码器
//"算法/模式/补码方式"
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
// 初始化为加密模式的密码器
cipher.init(Cipher.ENCRYPT_MODE, skeySpec);
byte[] encrypted = cipher.doFinal(data.getBytes(StandardCharsets.UTF_8));
//此处使用BASE64做转码功能,同时能起到2次加密的作用。
return new BASE64Encoder().encode(encrypted);
}
// 解密
public static String decrypt(String encData, String key) throws Exception {
//创建AES的Key生产者
KeyGenerator kgen = KeyGenerator.getInstance("AES");
// 利用"很随便的密钥"作为随机数初始化生成一个128字节16位的密钥
kgen.init(128, new SecureRandom(key.getBytes()));
//SecureRandom是生成安全随机数序列
SecretKey secretKey = kgen.generateKey();
byte[] rKey = secretKey.getEncoded();
SecretKeySpec skeySpec = new SecretKeySpec(rKey, "AES");
// 创建密码器
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
// 初始化为解密模式的密码器
cipher.init(Cipher.DECRYPT_MODE, skeySpec);
//先用base64解密
byte[] encDataByte = cipher.doFinal(new BASE64Decoder().decodeBuffer(encData));
String decData = new String(encDataByte,StandardCharsets.UTF_8);
return decData;
}
2、AES-128-CBC
使用CBC模式,需要填充一个向量,这里我直接用key来代替。
public static void main(String[] args) throws Exception {
/*
* 此处使用AES-128-CBC加密模式。
*/
String key = "很随便的密钥";
// 需要加密的字串
String data = "即将加密的数据";
// 加密
String encData = encrypt(data, key);
System.out.println("加密后的字串是:" + encData);
// 解密
String decData = decrypt(encData, key);
System.out.println("解密后的字串是:" + decData);
}
// 加密
public static String encrypt(String data, String key) throws Exception {
//创建AES的Key生产者
KeyGenerator kgen = KeyGenerator.getInstance("AES");
// 利用"很随便的密钥"作为随机数初始化生成一个128字节16位的密钥
kgen.init(128, new SecureRandom(key.getBytes()));
//SecureRandom是生成安全随机数序列
SecretKey secretKey = kgen.generateKey();
byte[] rKey = secretKey.getEncoded();
// 转换为AES专用密钥
SecretKeySpec skeySpec = new SecretKeySpec(rKey, "AES");
// 创建密码器
//"算法/模式/补码方式"
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
//使用CBC模式,需要一个向量iv,可增加加密算法的强度
IvParameterSpec ips = new IvParameterSpec(rKey);
// 初始化为加密模式的密码器
cipher.init(Cipher.ENCRYPT_MODE, skeySpec,ips);
byte[] encrypted = cipher.doFinal(data.getBytes(StandardCharsets.UTF_8));
//此处使用BASE64做转码功能,同时能起到2次加密的作用。
return new BASE64Encoder().encode(encrypted);
}
// 解密
public static String decrypt(String encData, String key) throws Exception {
//创建AES的Key生产者
KeyGenerator kgen = KeyGenerator.getInstance("AES");
// 利用"很随便的密钥"作为随机数初始化生成一个128字节16位的密钥
kgen.init(128, new SecureRandom(key.getBytes()));
//SecureRandom是生成安全随机数序列
SecretKey secretKey = kgen.generateKey();
byte[] rKey = secretKey.getEncoded();
SecretKeySpec skeySpec = new SecretKeySpec(rKey, "AES");
// 创建密码器
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");//使用CBC模式,需要一个向量iv,可增加加密算法的强度
IvParameterSpec ips = new IvParameterSpec(rKey);
// 初始化为解密模式的密码器
cipher.init(Cipher.DECRYPT_MODE, skeySpec,ips);
//先用base64解密
byte[] encDataByte = cipher.doFinal(new BASE64Decoder().decodeBuffer(encData));
String decData = new String(encDataByte,StandardCharsets.UTF_8);
return decData;
}
6、非对称加密
RSA:
1、私钥加密,公钥解密
private static final String DATA = "要加密的数据";
private static String rsaPublicKey = null;
private static String rsaPrivateKey = null;
public static void main(String[] args) throws Exception {
//构建密钥对
createEnck();
//私钥加密
String result = encByPrivateKey(rsaPrivateKey);
//公钥解密
decByPublicKey(rsaPublicKey,result);
}
//构建密钥对,保存公私钥
private static void createEnck() throws Exception {
KeyPairGenerator senderKeyPairGenerator = KeyPairGenerator.getInstance("RSA");
senderKeyPairGenerator.initialize(512);
KeyPair keyPair = senderKeyPairGenerator.generateKeyPair();
//生成公钥
RSAPublicKey rsaPublicKey1 = (RSAPublicKey) keyPair.getPublic();
//生成私钥
RSAPrivateKey rsaPrivateKey1 = (RSAPrivateKey) keyPair.getPrivate();
//这里也可以不用base64加密,看自己的需求
rsaPublicKey = Base64.encodeBase64String(rsaPublicKey1.getEncoded());
rsaPrivateKey = Base64.encodeBase64String(rsaPrivateKey1.getEncoded());
System.out.println("rsaPublicKey = "+rsaPublicKey);
System.out.println("rsaPrivateKey = "+rsaPrivateKey);
}
/**
* 私钥加密
*/
private static String encByPrivateKey(String rsaPrivateKey) throws Exception {
// 在构建密钥对时,对密钥做了base64编码,这里需要先解码
PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec((new BASE64Decoder()).decodeBuffer(rsaPrivateKey));
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
PrivateKey privateKey = keyFactory.generatePrivate(pkcs8EncodedKeySpec);
//创建Cipher对象。
Cipher cipher = Cipher.getInstance("RSA");
//初始化为加密模式的密码器
//用密钥初始化 Cipher
cipher.init(Cipher.ENCRYPT_MODE, privateKey);
//加密
byte[] bytes = cipher.doFinal(DATA.getBytes());
String result = Base64.encodeBase64String(bytes);
System.out.println("私钥加密: " + result);
return result;
}
/**
* 公钥解密
*/
private static void decByPublicKey(String rsaPublicKey,String result) throws Exception {
// 这里也需要对公钥进行解码
X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec((new BASE64Decoder()).decodeBuffer(rsaPublicKey));
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
PublicKey publicKey = keyFactory.generatePublic(x509EncodedKeySpec);
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.DECRYPT_MODE, publicKey);
byte[] bytes = cipher.doFinal(Base64.decodeBase64(result));
System.out.println("公钥解密: " + new String(bytes));
}
2、公钥加密,私钥解密
private static final String DATA = "要加密的数据";
private static String rsaPublicKey = null;
private static String rsaPrivateKey = null;
public static void main(String[] args) throws Exception {
//构建密钥对
createEnck();
//加密
String result = encByPublicKey(rsaPublicKey);
//解密
decByPrivateKey(rsaPrivateKey,result);
}
//构建密钥对,保存公私钥
private static void createEnck() throws Exception {
KeyPairGenerator senderKeyPairGenerator = KeyPairGenerator.getInstance("RSA");
senderKeyPairGenerator.initialize(512);
KeyPair keyPair = senderKeyPairGenerator.generateKeyPair();
//生成公钥
RSAPublicKey rsaPublicKey1 = (RSAPublicKey) keyPair.getPublic();
//生成私钥
RSAPrivateKey rsaPrivateKey1 = (RSAPrivateKey) keyPair.getPrivate();
rsaPublicKey = Base64.encodeBase64String(rsaPublicKey1.getEncoded());
rsaPrivateKey = Base64.encodeBase64String(rsaPrivateKey1.getEncoded());
System.out.println("rsaPublicKey = "+rsaPublicKey);
System.out.println("rsaPrivateKey = "+rsaPrivateKey);
}
/**
* 公钥加密
*/
private static String encByPublicKey(String rsaPublicKey) throws Exception {
X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec((new BASE64Decoder()).decodeBuffer(rsaPublicKey));
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
PublicKey publicKey = keyFactory.generatePublic(x509EncodedKeySpec);
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
byte[] bytes = cipher.doFinal(DATA.getBytes());
String result = Base64.encodeBase64String(bytes);
System.out.println("公钥加密: " + result);
return result;
}
/**
* 私钥解密
*/
private static void decByPrivateKey(String rsaPrivateKey,String result) throws Exception {
PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec((new BASE64Decoder()).decodeBuffer(rsaPrivateKey));
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
PrivateKey privateKey = keyFactory.generatePrivate(pkcs8EncodedKeySpec);
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.DECRYPT_MODE, privateKey);
byte[] bytes = cipher.doFinal(Base64.decodeBase64(result));
System.out.println("私钥解密解密:" + new String(bytes));
}