密码学知识
密钥
密钥secret key:是一种参数,它是在明文转换为密文或将密文转换为明文的算法中输入的参数。
根据密码算法所使用的加密密钥和解密密钥是否相同,密钥分为对称密钥与非对称密钥。
常用加密算法
总结:
1. 加密算法是可逆的,用来对敏感数据进行保护。散列算法(签名算法、哈希算法)是不可逆的,主要用于身份验证。
2. 对称加密算法使用同一个密钥加密和解密,速度快,适合给大量数据加密。对称加密客户端和服务端使用同一个密匙,存在被抓包破解的风险。
3. 非对称加密算法使用公钥加密,私钥解密,私钥签名,公钥验签。安全性比对称加密高,但速度较慢。非对称加密使用两个密匙,服务端和客户端密匙不一样,私钥放在服务端,黑客一般是拿不到的,安全性高。
4. Base64不是安全领域下的加解密算法,只是一个编码算法,通常用于把二进制数据编码为可写的字符形式的数据,特别适合在http,mime协议下的网络快速传输数据。UTF-8和GBK中文的Base64编码结果是不同的。采用Base64编码不仅比较简短,同时也具有不可读性,即所编码的数据不会被人用肉眼所直接看到,但这种方式很初级,很简单。Base64可以对图片文件进行编码传输。
5. https协议广泛用于万维网上安全敏感的通讯,例如交易支付方面。它的主要作用可以分为两种:一种是建立一个信息安全通道,来保证数据传输的安全;另一种就是确认网站的真实性。
6. 大量数据加密建议采用对称加密算法,提高加解密速度;小量的机密数据,可以采用非对称加密算法。
在实际的操作过程中,我们通常采用的方式是:采用非对称加密算法管理对称算法的密钥,然后用对称加密算法加密数据,这样我们就集成了两类加密算法的优点,既实现了加密速度快的优点,又实现了安全方便管理密钥的优点。
7. MD5标准密钥长度128位(128位是指二进制位。二进制太长,所以一般都改写成16进制,每一位16进制数可以代替4位二进制数,所以128位二进制数写成16进制就变成了128/4=32位。16位加密就是从32位MD5散列中把中间16位提取出来);sha1标准密钥长度160位(比MD5摘要长32位),Base64转换后的字符串理论上将要比原来的长1/3。
对称加密
加密一般分为对称加密(Symmetric Key Encryption)和非对称加密(Asymmetric Key Encryption)。
对称加密又分为分组加密和序列密码。
(1)分组加密,也叫块加密(block cyphers),一次加密明文中的一个块。是将明文按一定的位长分组,明文组经过加密运算得到密文组,密文组经过解密运算(加密运算的逆运算),还原成明文组。具有代表性的块加密算法有DES,AES,3DES等。
(2)序列加密,也叫流加密(stream cyphers),一次加密明文中的一个位。是指利用少量的密钥(制乱元素)通过某种复杂的运算(密码算法)产生大量的伪随机位流,用于对明文位流的加密。解密是指用同样的密钥和密码算法及与加密相同的伪随机位流,用以还原明文位流。
分组加密算法中,有ECB、CBC、PCBC、CFB、OFB、CTR这几种算法模式:
我在实际项目中用到的是CBC模式(密码分组链接(CBC,Cipher-block chaining)模式)
对称加密算法之分组加密的六种工作模式(ECB、CBC、PCBC、CFB、OFB、CTR)
分组密码模式的填充
在密码学中,分组加密(Block cipher),又称分块加密或块密码,是一种对称密钥算法。 它将明文分成多个等长的模块(block),使用确定的算法和对称密钥对每组分别加密解密。(对过长的数据 进行循环调用加解密)
常见的分组加密算法有: DES、3DES、AES、IDEA。
填充 padding
一般的填充方式有以下几种:
1、ANSI X9.23
ANSIX923 填充字符串由一个字节序列组成,此字节序列的最后一个字节填充字节序列的长度,其余字节均填充数字零。
假定块长度为8,数据长度为 9,数据: FF FF FF FF FF FF FF FF FF,填充: FF FF FF FF FF FF FF FF FF 00 00 00 00 00 00 07
2、ISO10126
ISO10126 填充字符串由一个字节序列组成,此字节序列的最后一个字节填充字节序列的长度,其余字节填充随机数据。
假定块长度为 8,数据长度为 9,数据: FF FF FF FF FF FF FF FF FF,填充: FF FF FF FF FF FF FF FF FF 7D 2A 75 EF F8 EF 07
3、PKCS7 (RFC5652)
PKCS7 填充字符串由一个字节序列组成,每个字节填充该字节序列的长度。
假定块长度为 8,数据长度为 9,数据: FF FF FF FF FF FF FF FF FF,填充: FF FF FF FF FF FF FF FF FF 07 07 07 07 07 07 07,如果恰好8个字节时还要补8个字节的0x08,可以让解密的数据很确定无误的移除多余的字节。 PKCS5 Padding 和 PKCS7 Padding 在这方面是类似的。不同点在于,选择算法的时候如果选用 PKCS5 Padding 填充模式,就是明确指定块大小是 8 个字节。选用 PKCS7 Padding 则是没有明确指定块大小。如果选择算法的时候选用 PKCS7 Padding 填充模式,同时设置块大小为 8 字节,和选用 PKCS5 Padding 填充模式,没有设置块大小(实际已经设置了 8 字节),这两种情况下,两种填充模式没有区别。另外有个值得注意的是,AES 中块大小是固定 16 字节。
补零
填充字符串由设置为零的字节组成
非对称加密
什么是不对称加密,以及公钥和私钥
每个用户都有两把钥匙,一把公钥一把私钥。公钥是对外发布的,所有人都看的到所有人的公钥,私钥是自己保存,每个人都只知道自己的私钥而不知道别人的。当用公钥加密的时候,就用私钥解密,用私钥加密的时候,就用公钥解密。常用于https协议加密。
常见的不对称加密方式
- 一种是服务端用私钥加密,然后客户端用公钥解密,这种常用于分发数字签名,当数字签名被工信单位认证之后就成了数字证书。
- 一种是客户端用公钥加密,然后服务端用私钥解密,因为客户端一旦用公钥加密之后,只有拥有私钥的服务端才能打开,所以是安全的。这种方式常用于加密客户端发送的信息。
数字签名:是用于解密的公钥,可以比喻成合同中的签字,能够认证信息发送方身份的真实性。数字签名的本质是公钥。
数字证书:经过工信部门认证过的数字签名叫做数字证书。
不对称加密的发展及流程
基础版
所有人持有一份我的公钥,私钥只有我一个人持有,也就是说所有人都可以用公钥加密包裹,但是只有我一个人能用私钥拆开包裹。
这个时候出现了另一个问题
只通过前面的方法 你没有办法确认这个包裹到底是不是我发的。
这个时候如果有一个人装作快递员,把我的包裹拦了下来,然后假装我给你发包裹,当你把你的公钥放进这个包裹并发回的时候,这个快递员再把包裹拦截下来,然后用另外一个包裹把快递员自己的公钥放进去,这个时候他就有了我们两个人的公钥,他就可以扮演一个中间者,随意的更改我们两个发的包裹中的数据,而我们两个人并不知道我们实际上是在和这个快递员互发包裹。
升级版--加入数字签名
我们采用数字签名的方式,先用hash函数生成包裹的摘要 digest,然后我用私钥对这个digest加密生成数字签名,这个时候这个数字签名可以被所有人解密看到,但是大家都没有办法对他进行修改,因为能加密他的只有我的私钥。这个时候你就能知道这个包裹是不是我发的了(你对信件的内容进行hash,如果得到的结果和数字签名解密后的结果一样,说明包裹没有被人修改过)
但是这里还有一个问题:因为我们前面的前提是你知道你手里的公钥是我的,但是万一你手里的公钥是假的呢,是上一个快递员伪造的呢,这个时候上一个快递员就可以假装是我给你发包裹了。
终极版--数字签名升级成数字证书。
这个时候就有了一个认证中心,在认证中心CA,我的公钥进行了登记,认证中心用他的私钥加密我的公钥和一些其他信息发给我,这个时候我就有了数字证书,相当于我的身份证,之后我再给你发消息的时候在发送数字签名的同时也发送一份我的证书给你,通过对比你就知道这个包裹有没有被伪造了。认证中心发给你的加密过的文件就叫做数字证书,证书必须是工信机构颁发的,必须人工进行登记,所以很难伪造。这也是https信息安全的原因,但是https证书需要注册认证,所以不需要保证网站数据安全的时候一般都使用http。
RSA
1、RSA简介
这种算法1978年就出现了,它是第一个既能用于数据加密也能用于数字签名的算法。它易于理解和操作,也很流行。算法的名字以发明者的名字命名:Ron Rivest, AdiShamir 和Leonard Adleman。
2、数字签名技术
数字签名技术是将摘要信息用发送者的私钥加密,与原文一起传送给接收者。接收者只有用发送者的公钥才能解密被加密的摘要信息,然后用HASH函数对收到的原文产生一个摘要信息,与解密的摘要信息对比。如果相同,则说明收到的信息是完整的,在传输过程中没有被修改,否则说明信息被修改过,因此数字签名能够验证信息的完整性。数字签名是个加密的过程,数字签名验证是个解密的过程。
3、RSA加解密
RSA非对称加密内容长度有限制,1024位key的最多只能加密127位数据,否则就会报错。
解决办法是用对称加密(AES/DES etc)加密数据,然后用RSA公钥加密对称加密的密钥,用RSA的私钥解密得到对称加密的密钥,然后完成反向操作得到明文。
由于RSA算法相对于对称加密算来说效率较低,通常RSA算法用来加密小数据,如对称加密使用的key等。实际上应用更为广泛的是RSA算法用在签名操作上。通常使用私钥对一段消息的hash值进行签名操作,达到消息的防篡改和伪造。
RSA加解密算法还有两种不同的方式:
一种是使用对称密钥(比如DES等加解密方法)加密数据,然后使用非对称密钥(RSA加解密密钥)加密对称密钥;另一种是直接使用非对称密钥加密数据。
第一种方式安全性高,复杂度也高,不存在加密数据长度限制问题,第二种方式安全性差一些,复杂度低,但是存在加密数据限制问题(即使用非对称密钥加密数据时,一次加密的数据长度是(密钥长度/8-11))。
4、RSA密钥结构
在利用Org.BouncyCastle.Crypto.Parameters产生CSR,公钥私钥的时候,因为【modulus 为一个大整数,最高位为符号位,其为1时,就是负数,所以要在最高位填充0x00以保证不为负。】所以了解一下其结构。
RSA私钥文件(PEM)解析 (TLV格式见下面)
5、TLV格式:
(每一个字段都是TLV)
Tag |
Length |
Value |
||
Tag |
Length |
Value |
TLV的注意事项
1)上述TLV结构中:
V值长度<0x80,L表示数据的长度;
V值长度>=0x80的时候,L为0x8X,X表示的L长度要占用的字节数,X个字节用来表示V的长度。
2)RSA公钥N的第一个字节如果大于0x80,则需要在公钥值前面补00,这是因为modulus 为一个大整数,最高位为符号位,其为1时,就是负数,所以要在最高位填充0x00以保证不为负。所以公钥TLV应该是:02 81 81 00 [128字节个公钥值]。
3)RSA私钥的N,d,p,q,Dp,Dq,Mp也需要考虑(2)中的第一个字节如果大于0x80的情况。
4)TLV格式中是可以嵌套原,就是说V里面可以包括另一个TLV,嵌套的层数没有阴制
【IoT】加密与安全:非对称加密算法 RSA 公私钥 DER 编码示例解析
非对称加密填充方式
与对称加密算法DES,AES一样,RSA算法也是一个块加密算法( block cipher algorithm),总是在一个固定长度的块上进行操作。但跟AES等不同的是,block length是跟key length有关的。
Der 、Cer、 Pfx、 Pem它们都是扩展名(文件名的后缀,代表格式)
- .DER:用二进制DER编码的证书;
- .PEM:用ASCLL(BASE64)编码的证书;
- .CER:存放公钥,没有私钥;
- .PFX:存放公钥和私钥
(pem 后缀的证书都是base64编码;der 后缀的证书都是二进制格式;crt .cer 后缀的文件都是证书文件(编码方式不一定,有可能是.pem,也有可能是.der);.pfx 主要用于windows平台,浏览器可以使用,也是包含证书和私钥,获取私钥需要密码才可以)
X509文件扩展名(x509 这种证书只有公钥,不包含私钥。)
附:ASN.1解析器
这是JavaScript通用ASN.1解析器,该解析器可以解码任何有效的ASN.1 DER或BER结构,无论是使用Base64编码(可识别原始base64,PEM装甲和begin-base64)还是十六进制编码。
数字签名与证书
前面提到了数字签名,数字签名的作用就是防止篡改和伪装,并且能够防止否认。但是要正确运用数字签名技术还有一个非常大的前提,那就是用来验证签名的公钥必须真正的属于发送者。
如果你获取到的公钥是伪造的,那么不管你的签名算法多完美,也是会得到错误的结果。
那么我们怎么才能安全的获得发送者的公钥呢?这里就需要使用到证书了。所谓证书就是通过第三方的可信机构 对发送者的公钥进行签名而得到的。
这里有两个概念:公钥证书(Public-Key Certificate, PKC)和认证机构(Certification Authority, CA)。
证书的例子
我们看一个实际中可能会遇到的例子:
假如A要向B发送一条消息,这条消息希望使用B的公钥来加密,但是A事先无法知道B的公钥到底是什么,那么可以使用下面的证书架构:
- 在第一步,B需要生成自己的密钥对,然后将公钥注册到CA中。这里CA就是一个第三方的可信赖的机构。
- CA获得到了B的公钥之后,使用自己的私钥对B的公钥进行签名,得到证书。
- A从CA获得到证书和CA的公钥(CA是个可信赖机构,可以从公共站点中获取),并使用CA的公钥来验证证书签名的合法性。
- A获得了B的公钥,使用B的公钥加密消息。
- B用自己的私钥解密消息,得到明文。
好了,这就是一个最简单的证书使用的例子。
证书的标准和生成
因为证书是由认证机构颁发的,使用者需要对其进行验证,那么就需要一个标准的证书格式来方便使用者使用。最广泛的一个证书标准格式是由ITU和ISO制定的X.509规范。
x.509有很多扩展格式包括:DER、CRT、CER、PEM等。他们在不同的环境中有不同的用处。
那么怎么生成证书呢?可以借助第三方工具,也可以使用命令行命令比如:openssl来生成。
PKI
有了证书的格式,是不是就可以实际使用证书了呢?
其实这还是不够的,我们还需要定义证书该由谁来颁发,如何颁发,如果作废证书等。而PKI(Public-Key Infrastructure)公钥基础设施就是为了有效的使用证书而制定的一系列规范和协议。
PKI的组成主要有三部分:
- 用户
用户是使用PKI的人,也就是需要借助CA来发布自己的公钥和获取别人公钥的人。
- 认证机构
认证机构就是CA了,它是对证书进行管理的人。CA除了生成证书之外,还有一个非常重要的工作就是作废证书。
因为用户有可能会丢失密钥,或者出于特殊的原因,废弃掉某些证书。那么就可以向CA发起一个作废请求。而作废的证书会被保存在CRL中。CRL就是对外的证书废弃列表。用户在使用证书的时候必须首先查看该证书是否在CRL列表中。如果在则该证书不能够被使用。
- 仓库
仓库是一个保存证书的数据库,用户注册之后生成的证书都存在仓库中,以供其他的用户获取使用。
参考:一文读懂密码学中的证书
哈希函数
Hash函数又称哈希函数、散列函数、杂凑函数。它是一种单向密码体制,即从一个从明文到密文的不可逆映射,只有加密过程,没有解密过程。
Hash函数H将可变长度的数据块M(长度任意)作为输入,产生固定长度的Hash值h=H(M)。
在安全应用中使用的Hash函数称为密码学Hash函数。
特性
1. (逆天特性)应用于任意长的消息,产生固定长的输出(散列值,消息摘要,数字指纹随便你叫什么了);
2. (单向性)对于给定消息x,H(x)很容易得出。但是对于给定z,寻找H(x)=z是不可行的;
3. (安全特性)抗弱碰撞性:有x,找一个y,使得H(x)=H(y)计算不可行;抗强碰撞性:寻找(x,y),使得使得H(x)=H(y)计算不可行。
4. (雪崩性)雪崩效应,散列值的每一位都与消息的每一位有关,相近的消息,输出很大差别。
哈希函数的运用
1、消息认证(由于雪崩性,稍有改动一对比就发现了)
消息认证是用来验证消息完整性的一种机制或服务。消息认证确保收到的数据确实和发送时的一样(即没有修改、插入、删除或重放)。
当Hash函数用于提供消息认证功能时,Hash函数值通常称为消息摘要。
发送者将明文通过单向加密算法加密生成定长的密文串,然后传递给接收方。接收方在收到加密的报文后进行解密,将解密获取到的明文使用相同的单向加密算法进行加密,得出加密后的密文串。随后将之与发送者发送过来的密文串进行对比,若发送前和发送后的密文串相一致,则说明传输过程中数据没有损坏;若不一致,说明传输过程中数据丢失了。单向加密算法只能用于对数据的加密,无法被解密,其特点为定长输出、雪崩效应。
参考:https://www.jiamisoft.com/blog/24470-sansan.html
2、数字签名(计算H(m),然后私钥加密)
在进行数字签名过程中使用用户的私钥加密 消息的Hash值,其他任何知道该用户公钥的人都能够通过数字签名来验证消息的完整性。
可以验证很长的消息。
数字签名和验证的文件传输过程如下:
3、其他应用
单向口令文件。
入侵检测。
病毒检测。
构建随机函数(PRF)或用做伪随机数发生器(PRNG)
安全Hash算法(SHA)
安全散列算法SHA(Secure Hash Algorithm)是美国国家安全局 (NSA) 设计,美国国家标准与技术研究院(NIST) 发布的一系列密码散列函数,包括 SHA-1、SHA-224、SHA-256、SHA-384 和 SHA-512 等变体。主要适用于数字签名标准(DigitalSignature Standard DSS)里面定义的数字签名算法(Digital Signature Algorithm DSA)。
- SHA-1
SHA-1产生160位的Hash值。(20字节)
SHA1始终把消息当成一个位(bit)字符串来处理。
- SHA-2
Hash值长度依次为256位、384位和512位,分别称为SHA-256、SHA-384和SHA-512,这些算法统称为SHA-2。
SHA-256算法:SHA-256算法的输入是最大长度小于264 位的消息,输出是256位的消息摘要,输入消息以512位的分组为单位进行处理。
MAC与HMAC
MAC
在密码学中,(消息认证码)Message Authentication Code是用来认证消息比较短的信息。换言之,MAC用来保证消息的数据完整性和消息的数据源认证。
MAC由消息本身和一个密钥经过一系列计算产生,用于生成MAC的算法,称为MAC算法。MAC算法应能满足如下几个条件:
- 在仅有消息本身没有密钥的情况下,无法得到该消息的MAC;
- 同一个消息在使用不同密钥的情况下,生成的MAC应当无关联;
- 在已有一系列消息以及其MAC时,给定一个新的消息,无法得到该消息的MAC。
下图摘自维基百科,可以很好的描述MAC的使用原理:
过程:
(1)明文+key,通过mac算法得到MAC值;
(2)将明文和MAC值 传给对方,再 对明文+key进行mac运算,计算得到的MAC和 接收到的MAC值进行比较。
MAC就是消息验证码(Message Authentication Code)的简称,是一种与密钥相关的单向散列函数,它能够做到验证消息是来自发送者发送的,正确的没有被篡改过的。具体做法是:
- 发送方和接收方事先共享同一个密钥。
- 发送方将发送消息和密钥进行MAC运算,得到MAC值,并把MAC值与消息一同发送给接收方。
- 接收方接收到消息后,将消息部分与事先共享的密钥进行MAC运算,得到MAC值,将MAC值与发送方发送的MAC值进行比较,如果一致,证明消息是来自发送方。
HMAC
由H.Krawezyk,M.Bellare,R.Canetti于1996年提出的一种基于Hash函数和密钥进行消息认证的方法,它可以与任何迭代散列函数捆绑使用。
HMAC是MAC算法中的一种,其基于加密HASH算法实现。任何加密HASH, 比如MD5、SHA256等,都可以用来实现HMAC算法,其相应的算法称为HMAC-MD5、HMAC-SHA256等。
HMAC运算利用hash算法,以一个消息M和一个密钥K作为输入,生成一个定长的消息摘要作为输出。HMAC算法利用已有的Hash函数,关键问题是如何使用密钥。
HMAC的密钥长度可以是任意大小,如果小于n(hash输出值的大小),那么将会消弱算法安全的强度。建议使用长度大于n的密钥,但是采用长度大的密钥并不意味着增强了函数的安全性。密钥应该是随机选取的,可以采用一种强伪随机发生器,并且密钥需要周期性更新,这样可以减少散列函数弱密钥的危险性以及已经暴露密钥所带来的破坏。
HTTPS
HTTPS全过程 = 对称加密 + 非对称加密 + 数字证书
客户端浏览器 vs 服务端
1、客户端浏览器 内置 各大权威机构(CA)的数字证书【含CA的公钥,权威的,不会被篡改的】
CA例如 Digicert、GeoTrust、Globalsign等等,
2、访问https网站,获取到服务器的数字证书,进行验证
- 校验证书声明的CA在操作系统的根证书里面
- 校验证书在有效期内
- 校验证书的签名,这一步能够证明此证书确实是由CA机构颁发的。
其中校验证书签名是关键,证书签名是网站申请证书时,CA机构对一个hash值使用CA私钥对称加密后的字符串。 证书的签名 可以用表达式表达为:
sign = encrypt(hash("证书机构" + "证书有效期" + "证书所有者" + "公钥"))
校验签名的步骤:
- 客户端从系统根证书中取出对应CA的公钥,然后对签名解密 获取到hash值。
- 客户端使用相同的方式拼接证书信息,使用相同算法 得到hash值。
- 比较解密出来的hash值和客户端拼接并运算得到的hash值是否相同,相同则通过。
这个过程其实完成了这么一件事情,客户端看了一眼证书提供的信息,然后通过CA公钥解密,证明了证书提供的信息是被拥有CA私钥的机构确认过的(证书的签名),便相信了证书提供的信息。
就像现实生活中的票据,相信票据中的信息,因为有一个独一无二的机构签章(虽然可以伪造,但是非对称机密的签章是不可伪造的)
3、客户端 用服务器证书的公钥 加密自己的对称密钥 发给服务器
服务端用 自己的证书的私钥 解密,得到客户端的对称密钥。。之后用此对称密钥 加密传输文本。
(涉及到 非对称加密 和对称加密)
Https流程图:
解决的问题:
-
非对称加密只用来传输密码本,实际数据传输用的对称加密,解决了非对称加密解密速度慢的问题
-
CA机构数字证书验证公钥,解决公钥传输的信任问题
参考:https://blog.csdn.net/weixin_40898368/article/details/103691882
编程参考
.Net Framework参考:C#编程总结(八)数字签名
.NetCore参考:https://www.cnblogs.com/stulzq/category/1611398.html
RSA加解密 签名验签
在.NET下的RSA类所生成的密钥为Xml格式,而其他语言比如java一般使用pkcs8格式的密钥,JavaScript一般使用pkcs1格式。我们在开发过程中很可能遇到需要与其他语言开发的api进行对接,如果遇到RSA加密解密,我们肯定需要保证key是相同的,才能保证数据的正确处理,我们肯定需要对密钥进行转换。
https://www.cnblogs.com/stulzq/category/1611398.html
仅私钥有PKCS1和PKCS8之分,公钥无格式区别。
不管是对称算法还是非对称算法,其输入与输出均是字节数组,通常我们要结合编码算法对加密之后或解密之前的数据,进行编码操作。
BouncyCastle提供的Base64编码算法:
namespace Org.BouncyCastle.Utilities.Encoders { public sealed class Base64 { // public static byte[] Decode(byte[] data); // public static byte[] Decode(string data); // public static int Decode(string data, Stream outStream); // public static byte[] Encode(byte[] data); // public static byte[] Encode(byte[] data, int off, int length); // public static int Encode(byte[] data, Stream outStream); // public static int Encode(byte[] data, int off, int length, Stream outStream); public static string ToBase64String(byte[] data); public static string ToBase64String(byte[] data, int off, int length); } }
参考:.NET Core加解密实战系列之——RSA非对称加密算法