加解密和数字签名的理论基础都是密码学. 甚至, 区块链本质上也是密码协议的一种。

一. 加密算法

加密算法主要分为如下几类:对称算法、公钥算法、散列算法、随机数产生算法等。

1. 对称算法 (传统密码算法)

常用的有: DES(Data Encryption Standard)、3DES(Triple DES)、AES(Advanced Encryption Standard)、RC4(Rivest Cipher 4)、SM1、SM4(国产).在大多数对称算法中,加密和解密的密钥是相同的。

DES(Data Encryption Standard)

出自IBM之手,后被美国军方采纳,但是近些年使用越来越少,因为DES使用56位密钥(一般应用都是64位),以现代计算能力,24小时内即可被破解。

DES算法详解

3DES(Triple DES)

三重数据加密算法(TDEA,Triple Data Encryption Algorithm)它的密钥长度是192位(24个字节), 但加解密运算的时候,也是拆分为8字节为一组进行DES运算的, 相当于是对每个数据块应用三次DES加密算法。

AES(Advanced Encryption Standard)

在密码学中又称Rijndael加密法,是美国联邦政府采用的一种区块加密标准。这个标准用来替代原先的DES, 至今尚未听说有被破解的案例。通常用于移动通信系统加密以及基于SSH协议的软件, 如SSH Client,secureCRT.

AES加解密

SM1( SM1 cryptographic algorithm)

国密 SM1 算法是由国家密码管理局编制的一种商用密码分组标准对称算法。该算法不公开,调用该算法时,需要通过加密芯片的接口进行调用;用于芯片、智能 IC 卡、智能密码钥匙、加密卡、加密机等安全产品.

国密算法概述

SM4

国家密码管理局公布的6项密码行业标准之一. SM4加密/解密算法的结构相同,只是使用的密钥相反,其中解密密钥是加密密钥的逆序。

无线局域网产品使用的 SM4 密码算法

RC4(Rivest Cipher 4)

1987年提出,不同于上面算法, 它是流算法,也叫序列算法。流算法是从密钥作为种子产生密钥流,明文比特流和密钥流异或即加密。
RC4算法由于算法简洁,速度极快,密钥长度可变,而且也没有填充的麻烦,因此在很多场合值得大力推荐。

优点: 效率高,算法简单,系统开销小,适合加密大量数据。

缺点: 安全性依赖于密钥,泄漏密钥就意味着任何人都能对消息进行加密解密; 当用户量大时, 钥匙数量呈几何级数增长,密钥管理成为巨大负担; 无法用来签名

2. 公钥算法 (公开密钥算法, 非对称算法)

其原理是加密密钥与解密密钥不同,形成一个密钥对。常用的有: RSA、ECC(椭圆曲线)、SM2等。

RSA

1977年由麻省理工学院的三个学者提出, RSA就是他们三人姓氏开头字母拼在一起组成的.
RSA是基于大质数因子分解困难性(IFP)的加密方法. 理论上讲,密钥为1024位长的RSA算法,用一台512量子比特位的量子计算机在1秒内即可破解。现在更多的会使用RSA2, 就是密钥为2048位的RSA加强版算法, 来提高安全性.

RSA算法

ECC

Ellipse Curve Cryptography 椭圆曲线加密算法 . 基于椭圆曲线理论的公钥加密技术(1985),通过椭圆曲线方程式的性质产生密钥. 其数学基础是基于椭圆曲线上离散对数计算难题(ECDLP)。

ECC加密算法

椭圆曲线密码学原理分析

SM2

SM2算法由国家密码管理局于2010年12月17日发布,是我国自主设计的公钥密码算法,基于椭圆曲线密码机制,在国际标准的ECC椭圆曲线密码理论基础上进行自主研发设计,具备ECC算法的性能特点并实现优化改进。
SM2推荐了一条256位的曲线作为标准曲线。现在大部分加密硬件, 以及第三方库, 都是基于这个推荐曲线, 作为SM2的计算因子.

与RSA算法相比,SM2算法安全性更高、资源占用更少、加密速度更快。

SM2椭圆曲线公钥密码算法

SM2椭圆曲线公钥密码算法推荐曲线参数

优点: 密钥分配安全;可以用来签名

缺点: 相对对称算法效率低,算法复杂,系统开销大

3. 散列算法 (摘要算法)

输入不定长度的内容,返回固定长度的散列值. 其过程不可逆, 就是说无法从散列值推断出原文内容. 散列算法没有密钥, 主要是用于消息摘要和签名.
常用的有: MD5、SHA-1、SHA-2、SM3.

MD5

Message-Digest泛指字节串(Message)的Hash变换, 将任意长度的“字节数组”变换成一个128bit的大整数.
2004年,MD5被证实无法避免碰撞;
2009年,中国科学院的谢涛和冯登国仅用了2^20.96的碰撞算法复杂度,破解了MD5的碰撞抵抗,该攻击在普通计算机上运行只需要数秒钟.

SHA-1

一种密码散列函数,由美国国家安全局设计。
2017年2月23日,Google宣布了一个成功的SHA-1碰撞攻击,发布了两份内容不同但SHA-1散列值相同的PDF文件作为概念证明。自2010年以来,许多组织建议用SHA-2或SHA-3来替换SHA-1。

SHA-2

由美国国家安全局设计,2001年由美国国家标准与技术研究院(NIST)发布. 其下又可再分为六个不同的算法标准,包括了:SHA-224、SHA-256、SHA-384、SHA-512、SHA-512/224、SHA-512/256. 与SHA-1算法相比,SHA-2的混合程度有大幅提升, 碰撞可能性更小.

SM3

SM3算法也是一种哈希算法,中国国家密码管理局在2010年发布。SM3会生成一个固定长度32字节(256位)的哈希值.

SM3密码杂凑算法

优点: 效率高,算法简单,系统开销小,适合加密大量数据。

缺点: 安全性依赖于密钥,泄漏密钥就意味着任何人都能对消息进行加密解密; 当用户量大时, 钥匙数量呈几何级数增长,密钥管理成为巨大负担

二. 算法的工作模式/运行模式

同样的算法, 在不同的工作模式下, 加密出来的结果不一样, 工作效率也有差别, 不同模式的适用场景也不一样.

ECB(Electronic Code Book 电子编码本模式)

这种模式是最早采用和最简单的模式,它将加密的数据分成若干组,每组的大小跟加密密钥长度相同,然后每组都用相同的密钥进行加密,适用加密小消息。

CBC(Cipher Block Chaining 加密分组链接模式)

CBC 模式的加密首先也是将明文分成固定长度的块,然后将前面一个加密块输出的密文与下一个要加密的明文块进行异或操作,将计算的结果再用密钥进行加密得到密文。

那么, 当加密第一个分组时,由于不存在前一个密文块,因此需要事先准备一个比特序列称为初始化向量(Initialization Vector),通常缩写为IV。一般来说,每次加密时都会随机产生一个不同的比特序列来作为初始化向量。

CFB(Cipher Feedback 加密反馈模式)

面向字符应用程序的加密要使用流加密算法,可以使用加密反馈模式进行加密。在此模式下,数据用更小的单元加密,如可以是8位,这个长度小于定义的块长(通常是 64 位)。

OFB(Output Feedback 输出反馈模式)

输出反馈模式与 CFB 相似,惟一差别是,CFB 中密文填入加密过程下一阶段,而在 OFB 中,初始化向量加密过程的输入填入加密过程下一阶段。

三. 算法的填充方式

当需要按块处理的数据, 如果数据长度不符合块处理需求, 就要按照一定的方法填充满块长的规则。

NoPadding

不填充。

在DES加密算法下, 要求原文长度必须是8byte的整数倍。

在AES加密算法下, 要求原文长度必须是16byte的整数倍。

ZerosPadding

它是使用“0”作为填充数据的填充方式,也就是说在分组时,最后一组明文的长度没有达到分组长度,那么就用“0”来补足。

PKCS1Padding

这个是RSA的PKCS1V1.5中定义的填充模式RSA_PKCS1_PADDING.
在进行RSA运算时, 需要将明文数据M转化成与钥模长(modulus) 一样长的数据块(EB).
EB = 00+ BT+PS +00 + M

EB:为转化后Hex进制表示的数据块,长度为128个字节(密钥1024位的情况下)

00:开头为00, 是一个保留位

BT:用一个字节表示,在目前的版本上,有三个值00,01,02.
如果用公钥操作,BT为02,
如果用私钥操作, BT则可能为00或01。BouncyCastle用的是01.

PS:为填充位PS由k-3-M这么多个字节构成,k表示密钥的字节长度.
如果我们用1024bit的RSA密钥,这个长度就是1024/8=128 ,M表示明文数据M的字节长度
对于BT为00的, 这些字节全部为00,
对于BT为01的, 这些值全部为FF,
对于BT为02的, 这些字节的值随机产生, 但不能是0字节(就是00)。

00:在明文数据M前一个字节用00表示

M:明文数据

PKCS5Padding/PKCS7Padding

以整字节填充,每个填充字节的值等于填充的字节数。也就是说,添加N个字节,每个的值都是N。

PKCS5Padding是PKCS7Padding的子集, 两者的区别在于PKCS5Padding是限制块大小为8个字节的PKCS7Padding。

所以一个算法实现通常包含三个因素: 算法类型/工作模式/填充方式. 我们经常会见到这样的内容:

AES/ECB/NoPadding

AES/ECB/PKCS5Padding

AES/CBC/NoPadding

AES/CBC/PKCS5Padding

RSA/ECB/PKCS1Padding
....

四. 数字签名/数字证书

数字签名

简单来说, 数字签名是对信息的摘要, 进行加密的技术, 它的作用就是防止信息被伪造, 被篡改.
它必须保证三点:
不可否认
只有用户A拥有私钥A,并能使用私钥A产生"加密的摘要",这样用户A就不能否认给用户B发送了经过签名的密文。

报文的完整性
用户B通过比较得出的两份摘要是否相等,可以判断签名或文件内容是否发生改变。

报文鉴别
用户B可以使用收到的公钥对"加密的摘要"进行解密,从而核实用户A对文件的签名。

从技术上来说, 数字签名是用 散列算法 (计算摘要)和 非对称算法 (摘要加密)来实现的. 比如:

SHA256withRSA: SHA-256为散列算法, RSA为公钥算法;

SM3withSM2: SM3为散列算法, SM2为公钥算法;

数字证书

如图上图所示,用户A使用数字签名时给用户B发送了一个数据包,数据包中包含了A的公钥、文件和加密的摘要。那么问题来了:用户B如何确定收到的公钥是用户A发送的,而不是他人冒充用户A发送的呢?如果用户C拦截了用户A发送的内容, 自己创建一对密钥, 篡改文件内容, 然后将文件+加密摘要+公钥, 发送给用户B, 那么用户B就无法确定内容是来自用户A了.

这时候就需要引入第三方机构来做密钥安全的认证工作, 这个机构就是证书颁发机构CA(Certification Authority). 它一般由政府出资建立, 有的大公司也提供认证中心服务。

CA证书颁发和使用过程:

  1. 用户A向第三方认证机构CA提交公钥、组织信息、个人信息(域名)等信息,并申请认证

  2. CA 向用户A颁发认证证书(包含了用户A的身份信息,域名,公钥信息,CA的数字签名等)

  3. 用户B授权第三方机构的CA公钥证书为信任机构证书

  4. 用户B请求用户A接口时,用户A返回CA证书

  5. 用户B利用CA的公钥来验证CA证书的合法性、域名信息、有效时间等

五. 密钥格式

对称算法的密钥一般采用随机串或按约定的非公开算法生成;
非对称算法的密钥则需要根据相应的算法,计算出一对密钥对(公钥和私钥). 然后, 将私钥(保密存储)用于签名和解密; 将公钥发布给对方, 用于验签和加密.

1. 密钥数据结构

在计算机密码学中, 有广泛应用的一种数据结构是ASN.1(Abstract Syntax Notation One) .
ASN.1是一种数据描述语言,它定义了一些数据类型来描述数据结构,包括基础类型(如整数,布尔,字符串)和结构化类型(序列, 列表)

FooProtocol DEFINITIONS ::= BEGIN
    FooQuestion ::= SEQUENCE {
        id INTEGER,
        question IA5String
    }
END

2. 密钥编码规则

ASN.1 只是定义了数据结构,并未规定具体的编码方式, 将ASN.1加上特定的编码规则, 就可以用来描述数据结构。

BER

BER 是基础编码规则,编码结构包括类型标志、长度,值以及结束符(可选),每个字段以 8bit 即字节进行分割。

----------------------------------------------------
| Identifier  | Length | Contents  | End-of-contents |
| ASN.1数据类型 | 数据长度 |  数据内容  | 不定长度的数据类型才有,为00 00 |
----------------------------------------------------

DER

DER 是 BER 的子集, 是典型的 Tag-Length-Value(TLV) 编码方式,是 PKCS 密钥体系常用的编码。
和BER相比, 它多了几个限制:

  1. 如果数据长度在 0-127 之间,则 Length 必须使用第 1 种编码方式。
  2. 如果数据长度 >= 128,则 Length 必须使用第 2 种编码方式,且 Length 必须用最少的字节编码,如果能用 2 字节的则不能用 3 字节。
  3. 数据要用明确长度的编码方式,不支持 Length 的第3种编码即未知数据长度+结束标记的方式。

PEM

PEM(Privacy Enhanced Mail): 因为 DER 编码是二进制数据,不方便直接传输,因此密钥文件通常会在 DER 基础上进行 Base64 编码,这就是经常看到的密钥文件格式 PEM。
openssl 和 ssh-keygen 工具生成的公私钥文件默认都采用 PEM 格式。PEM 本身不是 ASN.1 的编码规则,它只是 Base64-encoded DER。

3. 密钥格式

PKCS (公钥密码学标准 Public Key Cryptography Standards) 和PKIX(公钥基础设施 Public-Key Infrastructure X.509) 使用 ASN.1 定义了密钥的数据结构,并使用 DER 编码规则编码密钥,最终使用 PEM (Base64-encoded DER) 格式将密钥数据存储在密钥文件中。

PKCS#1

PKCS#1(RSA Cryptography Specifications) 是 RSA 密码学规,定义了 RSA 密钥文件的格式和编码方式,以及加解密、签名、填充的基础算法。

 RSAPublicKey ::= SEQUENCE {
        modulus           INTEGER,  -- n
        publicExponent    INTEGER   -- e
 }

 RSAPrivateKey ::= SEQUENCE {
        version           Version,
        modulus           INTEGER,  -- n
        publicExponent    INTEGER,  -- e
        privateExponent   INTEGER,  -- d
        prime1            INTEGER,  -- p
        prime2            INTEGER,  -- q
        exponent1         INTEGER,  -- d mod (p-1)
        exponent2         INTEGER,  -- d mod (q-1)
        coefficient       INTEGER,  -- (inverse of q) mod p
        otherPrimeInfos   OtherPrimeInfos OPTIONAL
}

加密后的PEM格式:

-----BEGIN RSA PRIVATE KEY-----
XXXXXXXXXXXXXXXXX
-----END RSA PRIVATE KEY-----

PKCS#8

PKCS#8(Private-Key Information Syntax Standard)是私钥格式相关的标准,它支持各种类型的私钥。PKCS#8 私钥文件格式中首尾并未说明私钥算法类型,算法类型在数据中标识。
加密后的PEM格式:

-----BEGIN PRIVATE KEY-----
XXXXXXXXXXXXXXXXX
-----END PRIVATE KEY-----

PKCS#1与PKCS#8互转

  1. 在线工具: PKCS#1 转 PKCS#8

  2. OpenSSL指令:

# 1.pkcs8私钥转pkcs1私钥
openssl rsa  -in pkcs8.pem  -out private1.pem
# 2.PKCS1私钥转换为PKCS8私钥
openssl pkcs8 -topk8 -inform PEM -in private1.pem -outform pem -nocrypt -out pkcs8.pem
# 3.从pkcs1私钥中生成pkcs8公钥
openssl rsa -in private1.pem -pubout -out public8.pem
# 4.pkcs8私钥中生成pkcs8公钥
openssl rsa -in pkcs8.pem -pubout -out public8.pem
# 5.pkcs8公钥转pkcs1公钥
openssl rsa -pubin -in public8.pem -RSAPublicKey_out
# 6.pkcs1公钥转换为pkcs8公钥
openssl rsa -RSAPublicKey_in -in public1.pem -pubout

X.509

PKCS#1和PKCS#8 定义了通用的私钥格式支持各类私钥,在 PKIX ([rfc5280]) 中也定义了通用的公钥格式标准X.509。

SubjectPublicKeyInfo  ::=  SEQUENCE  {
        algorithm AlgorithmIdentifier,
        subjectPublicKey BIT STRING 
}

AlgorithmIdentifier  ::=  SEQUENCE  {
        algorithm OBJECT IDENTIFIER,
        parameters ANY DEFINED BY algorithm OPTIONAL  
}

加密后的PEM格式:

-----BEGIN PUBLIC KEY-----
XXXXXXXXXXXXXXXXX
-----END PUBLIC KEY-----

密钥文件格式完全解析

六. Java的JCE

JCE(Java Cryptography Extension)java加解密扩展功能。其核心功能包括:加解密、密钥生成、消息摘要生成、MAC生成、密钥协商,在javax.crypto包和java.security包下。

1. 密钥生成

对称密钥(java.crypto.KeyGenerator)

KeyGenerator gen = KeyGenerator.getInstance("AES");
gen.init(128, new SecureRandom());
Key key= gen.generateKey();

非对称密钥(java.security.KeyPairGenerator)

KeyPairGenerator gen = KeyPairGenerator.getInstance("RSA");
gen.initialize(1024, new SecureRandom());
KeyPair keyPair = gen.generateKeyPair();
PublicKey pubKey = keyPair.getPublic();
PrivateKey privKey = keyPair.getPrivate();

2. 加解密(javax.crypto.Cipher)

Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, secretKey); //解密: DECRYPT_MODE
byte[] pBts = plainText.getBytes("UTF-8");
byte[] result = cipher.doFinal(pBts);
String encoded = Base64.getEncoder().encodeToString(result);
return encoded;

3. 摘要信息生成(java.security.MessageDigest)

MessageDigest md5 = MessageDigest.getInstance("MD5");
byte[] pBts = plainText.getBytes("UTF-8");
byte[] result = md5.digest(pBts);
String encoded = Base64.getEncoder().encodeToString(result);

4. MAC(消息认证码)生成(java.crypto.Mac)

MAC本质也是消息摘要, 不同的是, MAC多了密钥的输入, 使得其具有身份认证的功能.

Mac mac = Mac.getInstance("HmacSHA256");
mac.init(key);
byte[] pBts = plainText.getBytes("UTF-8");
byte[] result = mac.doFinal(pBts);
String encoded = Base64.getEncoder().encodeToString(result);

5. 密钥协商

密钥协商就是在通讯双方间, 不直接交换通讯密钥的情况下, 而选择一个大家达成一致的密钥(session key),这个session key是对称密钥。其实现的两种方式:

  1. 通过javax.crypto.KeyAgreement组件完成,常用算法包括DH(Diffie-Hellman),ECDH(Elliptic Curve Diffie-Hellman),ECMQV(Elliptic Curve Menezes-Qu-Vanstone)等。
  2. 通过数字信封完成,常用算法包括RSA等。

发表评论

您的电子邮箱地址不会被公开。 必填项已用*标注