加密算法

所谓对称加密算法,通过密钥将明文加密成密文,并且再通过同一个密钥将密文解密成明文,相对于非对称加密算法速度快效率高,对于明文文本越长效率优势越大。

常见的对称加密算法有AES、DES、3DES等,其中DES由于密钥长度低容易被暴力破解,因此安全性相对较低已经不推荐使用。而3DES则是DES的升级版,安全性有所提升,但依然不如AES,因此推荐安全性更高的AES加密算法。

算法 算法类型 密钥长度 分组长度 安全性
AES 块密码算法 128/192/256比特 128比特 安全
DES 块密码算法 56比特 64比特 不安全
3DES 块密码算法 128/168比特 64比特 安全

分组模式

AES、DES、3DES都是块密码算法,即运算加密解密时不是一次性将整个明文/密文文本进行运算,而是拆成固定长度的数据块后对每个数据块进行运算。

由于文本被拆分成若干个数据块,对于超过一个数据块的场景需要定义数据块之间的拆分和组装方式,即分组模式,场景的分组模式如下表:

分组 是否需要填充 安全性
ECB 不安全
CBC 安全
CTR 安全

ECB

ECB是最简单的一种分组模式,简单地将明文拆成数据块后,每个数据块单独加密解密。如果两个数据块内容相同,那么这两个数据块加密后的密文段也是完全一样,容易受到重放攻击以及密文篡改,因此安全度不高。

CBC

CBC引入了一个新的变量初始向量IV,一般是一个随机数,用于在第一块明文数据块加密前对数据块做XOR运算,之后每一块明文数据块加密前都与前一块的密文数据块做XOR运算。

由于每一块数据块的计算结果都与上一块数据块有关联,因此即使有两个相同的数据块,计算出的密文段也不同,解决了ECB的安全问题。但因此,CBC计算只能串行处理,效率不如ECB。

CTR

CTR同样引入了一个新的变量初始随机数,每一个数据块计算时先对随机数+1,然后再参与加密解密运算,因此即使有两个相同的数据块,计算出的密文段也不同,解决了ECB的安全问题。并且每个数据块仅与随机数有联系,因此可以并行处理。

填充算法

对于块加密算法来说,不是对一次性对整个明文进行加密计算,而是拆分成若干个固定长度(加密算法的分组长度)的数据块,然后对各个数据块进行加密计算,因此明文的字节长度必须是分组长度的整数倍数。如果明文的字节长度不是分组长度的整数倍数,则需要一种填充的机制,在加密前将明文字节长度填充成分组长度的整数倍数,并且在解密后正确移除填充的字节。

常见的填充算法有PKCS#7和PKCS#5,而实际上两者的处理逻辑是相同的,只是PKCS#5只能处理分组长度为8字节的数据,而PKCS#7可以处理分组长度是1-255任意长度字节的数据。从这个角度看,PKCS#5是PKCS#7的子集。

PKCS#7很简单,实现代码如下:

/*** PKCS#7填充实现* @param src 明文* @param cipherBlockSize 加密算法分组长度*/
public static byte[] padding7(byte[] src, int cipherBlockSize) {// PKCS#7的分组最大为255字节int blockSize = Math.min(255, cipherBlockSize);int padNum = blockSize - src.length % blockSize;byte[] dst = new byte[src.length + padNum];System.arraycopy(src, 0, dst, 0, src.length);for (int i = 0; i < padNum; i++) {dst[src.length + i] = (byte) padNum;}return dst;
}/*** PKCS#5填充实现* @param src 明文* @param cipherBlockSize 加密算法分组长度*/
public static byte[] padding5(byte[] src, int cipherBlockSize) {// PKCS#5的分组固定为8字节final int blockSize = 8;if (cipherBlockSize != blockSize) {throw new RuntimeException("block length not support");}int padNum = blockSize - src.length % blockSize;byte[] dst = new byte[src.length + padNum];System.arraycopy(src, 0, dst, 0, src.length);for (int i = 0; i < padNum; i++) {dst[src.length + i] = (byte) padNum;}return dst;
}

如果数据需要填充n个字节,则在数据后添加n个字节长度的字节,并且填充的每个字节的值为n。另外,如果数据长度刚好是分组长度的整数倍时,依然还需要填充,填充长度为分组长度。

0x01
0x02 0x02
0x03 0x03 0x03
0x04 0x04 0x04 0x04
  • 分组长度8字节时数据5字节,需要填充3个字节:
Hello
0x48 0x65 0x6c 0x6c 0x6f
0x48 0x65 0x6c 0x6c 0x6f 0x03 0x03 0x03
  • 分组长度8字节时数据8字节,本应不需要填充,但实际上再额外填充8字节:
EchoEcho
0x45 0x63 0x68 0x6f 0x45 0x63 0x68 0x6f
0x45 0x63 0x68 0x6f 0x45 0x63 0x68 0x6f 0x08 0x08 0x08 0x08 0x08 0x08 0x08 0x08

AES算法的分组长度超过8字节,因此不能使用PKCS#5,但有些程序使用AES算法时若指定PKCS#5时并未报错,实际内部依然使用了PCKS#7。

代码实现

常见的填充算法有PCKS#5和PKCS#7,但JDK的语法中存在PKCS5Padding却不存在PKCS7Padding。查阅官方文档Cipher以及Cipher Algorithm Padding后确认语法中确实不存在PKCS7Padding

JDK中PKCS#7命名问题无从考证,但可以确定的是,JDK中语法上的PKCS5Padding实际上就是PKCS#7的实现,而官方文档Cipher也显示了这一点:

Every implementation of the Java platform is required to support the following standard Cipher transformations with the keysizes in parentheses:

  • 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)

DES-ECB

import org.apache.commons.codec.binary.Base64;
import org.apache.commons.codec.binary.Hex;import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;public class DESECBUtils {public static String encrypt(String key, String data) throws Exception {Cipher cipher = initCipher(key, Cipher.ENCRYPT_MODE);byte[] encryptedByte = cipher.doFinal(data.getBytes());return Base64.encodeBase64String(encryptedByte);}public static String decrypt(String key, String data) throws Exception {Cipher cipher = initCipher(key, Cipher.DECRYPT_MODE);byte[] decryptedByte = cipher.doFinal(Base64.decodeBase64(data));return new String(decryptedByte);}private static Cipher initCipher(String key, int encryptMode) throws Exception {Cipher cipher = Cipher.getInstance("DES/ECB/PKCS5Padding");cipher.init(encryptMode, new SecretKeySpec(key.getBytes(), "DES"));return cipher;}public static void main(String[] args) throws Exception {String key = "12345678";String value = "HelloWorld";// 16进制的加密参数keySystem.out.println("key hex: " + Hex.encodeHexString(key.getBytes()));// 加密String encrypt = encrypt(key, value);System.out.println("encrypt: " + encrypt);// 解密String decrypt = decrypt(key, encrypt);System.out.println("decrypt: " + decrypt);}}
key hex: 3132333435363738
encrypt: 8SBfruuCs9qh0WiTqhkSbg==
decrypt: HelloWorld

OpenSSL命令行调用:

[root@VM_0_10_centos ~]# echo -n HelloWorld > in.txt
[root@VM_0_10_centos ~]# openssl enc -des-ecb -in in.txt -out encrypt.txt -K 3132333435363738 -a
[root@VM_0_10_centos ~]# cat encrypt.txt
8SBfruuCs9qh0WiTqhkSbg==
[root@VM_0_10_centos ~]# openssl enc -des-ecb -in encrypt.txt -out decrypt.txt -K 3132333435363738 -a -d
[root@VM_0_10_centos ~]# cat decrypt.txt
HelloWorld

DES-CBC

import org.apache.commons.codec.binary.Base64;
import org.apache.commons.codec.binary.Hex;import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;public class DESCBCUtils {public static String encrypt(String key, String iv, String data) throws Exception {Cipher cipher = initCipher(key, iv, Cipher.ENCRYPT_MODE);byte[] encryptedByte = cipher.doFinal(data.getBytes());return Base64.encodeBase64String(encryptedByte);}public static String decrypt(String key, String iv, String data) throws Exception {Cipher cipher = initCipher(key, iv, Cipher.DECRYPT_MODE);byte[] decryptedByte = cipher.doFinal(Base64.decodeBase64(data));return new String(decryptedByte);}private static Cipher initCipher(String key, String iv, int encryptMode) throws Exception {Cipher cipher = Cipher.getInstance("DES/CBC/PKCS5Padding");SecretKeySpec keySpec = new SecretKeySpec(key.getBytes(), "DES");IvParameterSpec ivSpec = new IvParameterSpec(iv.getBytes());cipher.init(encryptMode, keySpec, ivSpec);return cipher;}public static void main(String[] args) throws Exception {String key = "12345678";String iv = "87654321";String value = "HelloWorld";// 16进制的加密参数key,ivSystem.out.println("key hex: " + Hex.encodeHexString(key.getBytes()));System.out.println("iv hex: " + Hex.encodeHexString(iv.getBytes()));// 加密String encrypt = encrypt(key, iv, value);System.out.println("encrypt: " + encrypt);// 解密String decrypt = decrypt(key, iv, encrypt);System.out.println("decrypt: " + decrypt);}}
key hex: 3132333435363738
iv hex: 3837363534333231
encrypt: 9r2UI+JnSrVP+WqsrFUqsg==
decrypt: HelloWorld

OpenSSL命令行调用:

[root@VM_0_10_centos ~]# echo -n HelloWorld > in.txt
[root@VM_0_10_centos ~]# openssl enc -des-cbc -in in.txt -out encrypt.txt -K 3132333435363738 -iv 3837363534333231 -a
[root@VM_0_10_centos ~]# cat encrypt.txt
9r2UI+JnSrVP+WqsrFUqsg==
[root@VM_0_10_centos ~]# openssl enc -des-cbc -in encrypt.txt -out decrypt.txt -K 3132333435363738 -iv 3837363534333231 -a -d
[root@VM_0_10_centos ~]# cat decrypt.txt
HelloWorld

AES-ECB

import org.apache.commons.codec.binary.Base64;
import org.apache.commons.codec.binary.Hex;import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;public class AESECBUtils {public static String encrypt(String key, String data) throws Exception {Cipher cipher = initCipher(key, Cipher.ENCRYPT_MODE);byte[] encryptedByte = cipher.doFinal(data.getBytes());return Base64.encodeBase64String(encryptedByte);}public static String decrypt(String key, String data) throws Exception {Cipher cipher = initCipher(key, Cipher.DECRYPT_MODE);byte[] decryptedByte = cipher.doFinal(Base64.decodeBase64(data));return new String(decryptedByte);}private static Cipher initCipher(String key, int encryptMode) throws Exception {Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");cipher.init(encryptMode, new SecretKeySpec(key.getBytes(), "AES"));return cipher;}public static void main(String[] args) throws Exception {// 16字节秘钥即128比特String key = "1234567890123456";String value = "HelloWorld";// 16进制的加密参数keySystem.out.println("key hex: " + Hex.encodeHexString(key.getBytes()));// 加密String encrypt = encrypt(key, value);System.out.println("encrypt: " + encrypt);// 解密String decrypt = decrypt(key, encrypt);System.out.println("decrypt: " + decrypt);}}
key hex: 31323334353637383930313233343536
encrypt: VfqXvdGjzea0rgvXO56j5g==
decrypt: HelloWorld

OpenSSL命令行调用:

[root@VM_0_10_centos ~]# echo -n HelloWorld > in.txt
[root@VM_0_10_centos ~]# openssl enc -aes-128-ecb -in in.txt -out encrypt.txt -K 31323334353637383930313233343536 -a
[root@VM_0_10_centos ~]# cat encrypt.txt
VfqXvdGjzea0rgvXO56j5g==
[root@VM_0_10_centos ~]# openssl enc -aes-128-ecb -in encrypt.txt -out decrypt.txt -K 31323334353637383930313233343536 -a -d
[root@VM_0_10_centos ~]# cat decrypt.txt
HelloWorld

AES-CBC

import org.apache.commons.codec.binary.Base64;
import org.apache.commons.codec.binary.Hex;import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;public class AESCBCUtils {public static String encrypt(String key, String iv, String data) throws Exception {Cipher cipher = initCipher(key, iv, Cipher.ENCRYPT_MODE);byte[] encryptedByte = cipher.doFinal(data.getBytes());return Base64.encodeBase64String(encryptedByte);}public static String decrypt(String key, String iv, String data) throws Exception {Cipher cipher = initCipher(key, iv, Cipher.DECRYPT_MODE);byte[] decryptedByte = cipher.doFinal(Base64.decodeBase64(data));return new String(decryptedByte);}private static Cipher initCipher(String key, String iv, int encryptMode) throws Exception {Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");SecretKeySpec keySpec = new SecretKeySpec(key.getBytes(), "AES");IvParameterSpec ivSpec = new IvParameterSpec(iv.getBytes());cipher.init(encryptMode, keySpec, ivSpec);return cipher;}public static void main(String[] args) throws Exception {// 16字节秘钥即128比特String key = "1234567890123456";String iv = "9876543210987654";String value = "HelloWorld";// 16进制的加密参数key,ivSystem.out.println("key hex: " + Hex.encodeHexString(key.getBytes()));System.out.println("iv hex: " + Hex.encodeHexString(iv.getBytes()));// 加密String encrypt = encrypt(key, iv, value);System.out.println("encrypt: " + encrypt);// 解密String decrypt = decrypt(key, iv, encrypt);System.out.println("decrypt: " + decrypt);}}
key hex: 31323334353637383930313233343536
iv hex: 39383736353433323130393837363534
encrypt: 5febt2VH5eaKXn/nrQj/aQ==
decrypt: HelloWorld

OpenSSL命令行调用:

[root@VM_0_10_centos ~]# echo -n HelloWorld > in.txt
[root@VM_0_10_centos ~]# openssl enc -aes-128-cbc -in in.txt -out encrypt.txt -K 31323334353637383930313233343536 -iv 39383736353433323130393837363534 -a
[root@VM_0_10_centos ~]# cat encrypt.txt
5febt2VH5eaKXn/nrQj/aQ==
[root@VM_0_10_centos ~]# openssl enc -aes-128-cbc -in encrypt.txt -out decrypt.txt -K 31323334353637383930313233343536 -iv 39383736353433323130393837363534 -a -d
[root@VM_0_10_centos ~]# cat decrypt.txt
HelloWorld

AES-CTR

import org.apache.commons.codec.binary.Base64;
import org.apache.commons.codec.binary.Hex;import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;public class AESCTRUtils {public static String encrypt(String key, String iv, String data) throws Exception {Cipher cipher = initCipher(key, iv, Cipher.ENCRYPT_MODE);byte[] encryptedByte = cipher.doFinal(data.getBytes());return Base64.encodeBase64String(encryptedByte);}public static String decrypt(String key, String iv, String data) throws Exception {Cipher cipher = initCipher(key, iv, Cipher.DECRYPT_MODE);byte[] decryptedByte = cipher.doFinal(Base64.decodeBase64(data));return new String(decryptedByte);}private static Cipher initCipher(String key, String iv, int encryptMode) throws Exception {Cipher cipher = Cipher.getInstance("AES/CTR/NoPadding");SecretKeySpec keySpec = new SecretKeySpec(key.getBytes(), "AES");IvParameterSpec ivSpec = new IvParameterSpec(iv.getBytes());cipher.init(encryptMode, keySpec, ivSpec);return cipher;}public static void main(String[] args) throws Exception {// 16字节秘钥即128比特String key = "1234567890123456";String iv = "9876543210987654";String value = "HelloWorld";// 16进制的加密参数key,ivSystem.out.println("key hex: " + Hex.encodeHexString(key.getBytes()));System.out.println("iv hex: " + Hex.encodeHexString(iv.getBytes()));// 加密String encrypt = encrypt(key, iv, value);System.out.println("encrypt: " + encrypt);// 解密String decrypt = decrypt(key, iv, encrypt);System.out.println("decrypt: " + decrypt);}}
key hex: 31323334353637383930313233343536
iv hex: 39383736353433323130393837363534
encrypt: Zjh8leeiqcWH0w==
decrypt: HelloWorld

OpenSSL命令行调用:

[root@VM_0_10_centos ~]# echo -n HelloWorld > in.txt
[root@VM_0_10_centos ~]# openssl enc -aes-128-ctr -in in.txt -out encrypt.txt -K 31323334353637383930313233343536 -iv 39383736353433323130393837363534 -a
[root@VM_0_10_centos ~]# cat encrypt.txt
Zjh8leeiqcWH0w==
[root@VM_0_10_centos ~]# openssl enc -aes-128-ctr -in encrypt.txt -out decrypt.txt -K 31323334353637383930313233343536 -iv 39383736353433323130393837363534 -a -d
[root@VM_0_10_centos ~]# cat decrypt.txt
HelloWorld

随机密钥

阅读一些java的加解密代码实现时可能会看到如下代码,这实际上是一个密码学的随机数生成,通过指定一个随机种子后生成一个随机数,最后以随机数作为对称加密算法的密钥。

因此随后参与对称加密运算的密钥并不是最开始的程序输入值,而是随机数生成器生成的随机数secretKey.getEncoded()

KeyGenerator generator = KeyGenerator.getInstance("AES");
SecureRandom secureRandom = SecureRandom.getInstance("SHA1PRNG");
secureRandom.setSeed("1234567890123456".getBytes());
generator.init(secureRandom);
SecretKey secretKey = generator.generateKey();
System.out.println(Hex.encodeHexString(secretKey.getEncoded()));

常见对称加密原理以及应用相关推荐

  1. 【C 语言】文件操作 ( 文件加密解密 | 加密解密原理 | 对称加密原理 | 非密钥整数倍长度的数据加密处理 )

    文章目录 一.对称加密原理 二.非密钥整数倍长度的数据加密处理 一.对称加密原理 给定一个 密钥 , 密钥的 长度不确定 , 可能是 323232 字节 , 也可能是 646464 字节 ; 将 被加 ...

  2. TLS 协议-对称加密原理

    文章目录 TLS 协议-对称加密原理 1.TLS 设计的目的 2.TLS/SSL 发展历史及通用模型 3.TLS 协议 4.TLS 安全密码套件解读 5.对称加密示意图 6.基于 XOR 的对称加密原 ...

  3. 对称加密和不对称加密原理

    本文转载至 http://my.oschina.net/freelife/blog/109048 java加密解密 java对称不对称 md5 des 私钥加密(对称加密 symmetric cryp ...

  4. 对称加密和非对称加密原理

    对称加密和非对称加密原理 私钥加密(对称加密 symmetric cryptography):私钥加密算法使用单个私钥来加密和解密数据.由于具有密钥的任意一方都可以使用该密钥解密数据,因此必须保护密钥 ...

  5. 【安全加密技术】 对称加密

    转载请注明出处:http://blog.csdn.net/sk719887916/article/details/46822663 上篇了解了<非对称加密>后 今天我来继续了解下加密技术中 ...

  6. 网络协议从入门到底层原理(7)网络安全 - 常见攻击、单向散列函数、对称加密、非对称加密、混合密码系统、数字签名、证书

    网络安全 网络层 - ARP欺骗 DoS.DDoS 介绍与防御 传输层 - SYN洪水攻击(SYN flooding attack) 传输层 - LAND攻击 应用层 - DNS劫持.HTTP劫持 H ...

  7. 对称加密与非对称加密的区别_https原理及对称加密、非对称加密、数字证书、数字签名的含义...

    一.为什么要使用https 使用https的原因其实很简单,就是因为http的不安全. 当我们往服务器发送比较隐私的数据(比如说你的银行卡,身份证)时,如果使用http进行通信.那么安全性将得不到保障 ...

  8. 对称加密与非对称加密,以及RSA的原理

    一 , 概述 在现代密码学诞生以前,就已经有很多的加密方法了.例如,最古老的斯巴达加密棒,广泛应用于公元前7世纪的古希腊.16世纪意大利数学家卡尔达诺发明的栅格密码,基于单表代换的凯撒密码.猪圈密码, ...

  9. (二)Java网络编程之爆肝HTTP、HTTPS、TLS协议及对称与非对称加密原理!

    引言 在上篇文章中,已经讲明了当下计算机网络的基础知识,其中对网络体系结构.分层模型.TCP/IP协议簇.....等多方面内容进行了阐述,而在本章会分析到网络知识中另外两个大名鼎鼎的协议:HTTP/H ...

最新文章

  1. Linux性能研究(总)
  2. Keepalived实现LVS-DR双机热备_2015101601
  3. 前端之JQuery(一)
  4. ORACLE RAC+DG 硬件配置
  5. 为什么苹果有2500亿美刀不用,偏偏要借钱?
  6. C# partial 关键字的使用
  7. endnote文献顺序编号不对_把Endnote装进大脑:行走的文献管理者
  8. 构建自己的简单微服务架构(开源)
  9. 2.1)深度学习笔记:深度学习的实践层面
  10. 信息学奥赛一本通(1206:放苹果)
  11. 最新cuDNN 7[Linux]百度云下载[免费] 适用于CUDA 10.0
  12. html调用mysql数据库表里值,如何从MYSQL数据库正确调用行到HTML表中
  13. Xshell和secureCRT
  14. 博客显示ip签名图片html代码,如何制作显示IP的签名图片
  15. python flask web_Python Web开发之Flask
  16. Similarity Reasoning and Filtration for Image-Text Matching
  17. 【MongoDB-MongoVUE图像管理工具】
  18. ffmpeg js转换音频_实践!实现纯前端下的音频剪辑处理
  19. 解决iOS 证书不受信任的问题
  20. 程序员面试,面试官更注重代码量、项目经验还是操作系统、数据结构这种基础课程?

热门文章

  1. 低代码里程碑版—JeecgBoot 3.4.3 版本发布,低代码功能专项升级
  2. 大学英语四级考试必读必备
  3. Linux的ssh客户端
  4. 《重构:改善既有代码的设计》读书笔记(上)
  5. 全国计算机软考中级哪个科目最简单,软考中级哪个科目比较容易考?
  6. Docker实战-部署GPE微服务的监控体系
  7. 华为m2青春版android7,时尚新体验:华为M2青春版
  8. (附源码)计算机毕业设计SSM旅游出行系统
  9. hdf5-java_Java HDF5LibraryException類代碼示例
  10. Java开发技术总结!小米java校招面试题