常用加密算法-Go语言实践

这里先简单介绍单向散列函数、消息摘要和哈希碰撞的的概念

单向散列函数:

将任意长度的信息转换为较短的固定长度的值,通常其长度要比信息小得多,且算法不可逆。

一个从明文到密文的不可逆函数,也就是说,是无法解密的安全性在于其产生散列值的操作过程具有较强的单向性。数据完整性确认和数据来源的真伪鉴定都是很重要的安全服务。实现这些安全服务的最好方法就是使用加密函数中的单项散列(Hash)函数。通常应用在只需要加密、不需要解密的特殊应用场合。单项散列(Hash)函数H(M)作用于一任意长度的消息M,它返回一固定长度的散列值h:h=H(M)作为初始消息的独一无二的“数字指纹”,从而能保证数据的完整性和惟一性。

消息摘要也称为数字摘要:它是一个唯一对应一个消息或者文本的固定长度的值,它是由一个单向散列hash函数对消息进行计算产生的,这个摘要又称为指纹

哈希碰撞:如果待摘要的关键字k1和k2,而f(k1)=(k2),这种现象称为hash碰撞

比特币挖矿(Hash 碰撞)

挖矿就是找出一个nonce(幸运值),小于一个目标值target

给定一个元数据,填充一段数据,结果是满足一定规则

比如给定数据hellobitcoin,再后面追加一个任意数据,满足Hash256最前面的5个0(这就是挖矿)

比如前面0越多,难度就越大

哈希摘要的特点:

a.长度固定;无论输入的消息多长,计算出来的消息摘要的长度是固定的,例如MD5算法计算的消息摘要有128个比特位,而SHA-1算法计算出来的消息摘要有160个比特位

b.不同输输出不同,输入相同输出相同;一般输入的消息不同,对其进行摘要以后产生的消息摘要也不同,但相同的输入,出来的消息摘要一定相同

c.无法逆向破解恢复原文;由于消息摘要并不包含原文的完整信息,因此只能进行正向的信息摘要,而无法从摘要中恢复出原来的消息。可以暴力穷举破解,但目前计算水平来看,几乎不可能

好了,下面正式介绍常用的几种加密算法:摘要算法、编码和解码、对称加密算法、非对称加密算法

摘要算法:MD5、SHA-1、HMAC

编码解码算法:base64编码解码、hex十六进制编码解码

对称加密算法:DES、AES

非对称加密算法:RSA

MD5加密(Message Digest Algorithm-消息摘要算法/哈希算法)

是数字摘要算法的一种实现,是一种散列函数,用于确保信息传输完整性和一致性,摘要长度为128位。MD5由MD4 MD3 MD2改进而来,主要增强了算法复杂度和不可逆性,这算法普遍、稳定、快速;将数据运算为另一固定长度值

代码实例

    package main

    import (

        "crypto/md5"

        "encoding/hex"

        "encoding/base64"

        "fmt"

    )

    func main() {

        s := "zhaffdskkdjasfldjsafljdsflkdlasjfkdlasjfkdss"

        md := md5.New()

        md.Write([]byte(s))

        mdSum := md.Sum(nil)

        hexString := hex.EncodeToString(mdSum)

        base64String := base64.StdEncoding.EncodeToString(mdSum)

        fmt.Println("      mdSum:", string(mdSum))

        fmt.Println("  hexString:", hexString)

        fmt.Println("base64String:", base64String)

        fmt.Println(" ")

        md1 := md5.New()

        md1.Write([]byte(s))

        mdSum1 := md.Sum(nil)

        hexString1 := hex.EncodeToString(mdSum1)

        base64String1 := base64.StdEncoding.EncodeToString(mdSum1)

        fmt.Println("      mdSum1:", string(mdSum1))

        fmt.Println("  hexString1:", hexString1)

        fmt.Println("base64String1:", base64String1)

    }

运行结果

mdSum: ��T���b���V��=

  hexString: fc8c1354fb189b8c62dcf6f756faf83d

base64String: /IwTVPsYm4xi3Pb3Vvr4PQ==

      mdSum1: ��T���b���V��=

  hexString1: fc8c1354fb189b8c62dcf6f756faf83d

base64String1: /IwTVPsYm4xi3Pb3Vvr4PQ==

SHA(英语:Secure Hash Algorithm-安全散列算法)

生成的摘要信息长度为160位,由于生成的摘要信息更长,运算的过程更加复杂,在相同的硬件上,SHA-1的运行速度比MD5要更慢,但也更安全

代码实例

    package main

    import (

          "crypto/sha1"

           "encoding/hex"

           "encoding/base64"

           "fmt"

           "io"

    )

    func main() {

          s := "zhaffdskkdjasfldjsafljdsflkdlasjfkdlasjfkdss"

           h := sha1.New()

           io.WriteString(h, s)

           hSum := h.Sum(nil)

           fmt.Println("hSum:% x", hSum)

           fmt.Println("hSumStr:", string(hSum))

           hexString := hex.EncodeToString(hSum)

           base64String := base64.StdEncoding.EncodeToString(hSum)

           fmt.Println("hexString:", hexString)

           fmt.Println("base64String:", base64String)

           fmt.Println("")

           h1 := sha1.New()

           io.WriteString(h1, s)

           hSum1 := h1.Sum(nil)

           fmt.Println("hSum:% x", hSum1)

           fmt.Println("hSumStr1:", string(hSum1))

           hexString1 := hex.EncodeToString(hSum1)

           base64String1 := base64.StdEncoding.EncodeToString(hSum1)

           fmt.Println("hexString1:", hexString1)

           fmt.Println("base64String1:", base64String1)

    }

摘要算法应用场景

* 密码加密

比如我有一个网站,用户注册的时候会输入用户名密码,大家都知道如果密码是明文的方式存储在数据库里的话,如果这个数据泄漏或者内部人员作恶的话,会造成信息安全问题。所以通用的做法是把用户输入的密码做MD5或SHA-1的运算,把返回的固定长度的哈希值存储在数据库中。比如用户的密码是”bigcat”,实际存储在数据库中的值是它的SHA-1的值a748bf7fee2289b22d448ed8efde10a68f7d1cf9。因为这两个函数的“不可逆”性,所以任何人拿到这个hash值是无法知道用户的明文密码的。

* 文件校验

在网上下载大尺寸文件的时候常见到网站同时会提供这个文件的MD5的值,它的作用是用户下载后可以在下载文件基础上计算MD5的值,如果和网站提供的MD5是相同的说明文件在下载过程中没有损坏或者说文件没有被恶意网站修改。

* 工作量证明(Proof ofWork)

彩虹表破解Hash算法

彩虹表是破解Hash算法的技术,从原理上来说可以破解任何一种Hash算法进行攻击

HMAC

HMAC( a keyed-hash message authentication code)运算利用哈希算法,以一个密钥和一个消息为输入,生成一个消息摘要作为输出。

主要应用在身份验证中,它的使用方法是这样的:

 (1) 客户端发出登录请求(假设是浏览器的GET请求)

 (2) 服务器返回一个随机值,并在会话中记录这个随机值

 (3) 客户端将该随机值作为密钥,用户密码进行hmac运算,然后提交给服务器

 (4) 服务器读取用户数据库中的用户密码和步骤2中发送的随机值做与客户端一样的hmac运算,然后与用户发送的结果比较,如果结果一致则验证用户合法在这个过程中,可能遭到安全攻击的是服务器发送的随机值和用户发送的hmac结果,而对于截获了这两个值的黑客而言这两个值是没有意义的,绝无获取用户密码的可能性,随机值的引入使hmac只在当前会话中有效,大大增强了安全性和实用性 

 算法种类                      摘要长度

    HmacMD5                  128

    HmacSHA1                160

    HmacSHA256            256

    HmacSHA384            384

    HmacSHA512            512

代码实例

 package main 

 import ( 

     "crypto/hmac"

     "crypto/sha1" 

     "encoding/base64" 

     "fmt" 

 ) 

 func main() { 

     secret := "testkey" 

     username := "zhaffdskkdjasfldjsafljdsflkdlasjfkdlasjfkdss" 

     key := []byte(secret) 

     h := hmac.New(sha1.New, key) 

     h.Write([]byte(username)) 

     hSum := h.Sum(nil) 

     base64String := base64.StdEncoding.EncodeToString(hSum) 

     fmt.Println("after hmac:",base64String) 

     h2 := hmac.New(sha1.New, key) 

     h2.Write([]byte(username)) 

     hSum2 := h2.Sum(nil) 

     base64String2 := base64.StdEncoding.EncodeToString(hSum2) 

     fmt.Println("after hmac 2:", base64String2) 

     fmt.Println("check equal:",hmac.Equal(hSum, hSum2)) 

 } 

运行结果: 

     after hmac: xapKpnazVfH3FCYqq+jTO39SAD8= 

     after hmac 2: xapKpnazVfH3FCYqq+jTO39SAD8= 

     check equal: true

Base64编码/解码

是一种基于64个可打印字符来表示二进制数据的方法,由于2的6次方等于64,所以每6位为一个单元,对应某个可打印字符,三个字节有24位,对应于4个Base64单元,即三个字节需要用4个可打印字符来表示。在Base64中的可打印字符包括字母A~Z a~z 0~9这样共有62个字符,此外两个可打印符号在不同的系统中而不同

代码实例

    参考代码实例1和代码实例2

十六进制编码/解码

16进制编码  计算机系统使用2进制, 为了编写存储方便一般将2进制转换为16进制字符串 其中base64也是其中类似转换一种16进制编码

代码实例

    参考代码实例1和代码实例2

对称加密算法

例如:AES,RC4,3DES 、DES、AES-GCM、ChaCha20-Poly1305等

特点:算法公开、计算量小、加解密速度快效率髙

优势:加解密的高速度和使用长密钥时的难破解性

缺点:秘钥丢失,就有泄密风险;不同的客户端、服务器数量庞大,所以双方都需要维护大量的密钥,维护成本很高

 DES算法(Data Encryption Standard)/ 3DES算法

属于对称加密算法,明文按照64位进行分组,秘钥长64位,但事实上只有56位参与DES运算,里边有校验位

AES算法(Advanced Encryption Standard)

高级加密标准

代码实例

非对称加密算法

又称为公开秘钥加密算法,它需要两个秘钥,一个称为公开秘钥,另一个称为私有秘钥。公钥和私钥需要配对使用,如果公钥对数据进行加密,只有用对应的私钥才能解密,而如果使用私钥对数据进行加密,那么只有对应的公钥才能进行解密。因为加密和解密使用的是两个不同的秘钥,所以这种算法称为非对称加密算法

非对称加密算法实现机密信息交换的基本过程是:甲方生成一对密钥并将其中的一把作为公钥向其他人公开,得到该公钥的乙方使用该密钥对机密信息进行加密后再发送给甲方,甲方再使用自己保存的另一把专用密钥(即私钥)对加密后的信息进行解密

例如:RSA,DSA/DSS、ECDSA、 DH、ECDHE

弊端:公钥是公开的(也就是黑客也会有公钥),私钥加密的信息,如果被黑客截获,其可以使用公钥进行解密,获取其中的内容


非对称加密算法的特点

对称加密算法中只有一把密钥,并且是非公开的,如果要解密就得让对方知道密钥,所以保证其安全性就是保证密钥的安全,而一旦密钥在传输过程中泄露,加密信息就不再安全;而非对称个加密算法中包含两种密钥,其中一把是公开的,这样就不用像对称加密算法那样,需要传输密钥给对方进行数据加密了,大大提髙了加密算法的安全性。非对称加密算法能够保证,即使是在获知公钥、加密算法和加密算法源代码的情况下,也无法获取公钥对应的私钥,因此无法对公钥加密的密文进行解密。

但是由于非对称个加密算法的复杂性,使得其加密解密速度远没有对称加密解密的速度快,为了解决加解密速度问题,人们广泛使用对称与非对称加密算法结合使用的办法,优缺点互补,达到时间和安全的平衡:对称加密算法加密速度快,人们使用它来加密较长的文件,然后用非对称加密算法来给文件密钥加密,解决了对称加密算法的密钥分发问题

RSA算法

非对称加密算法

签名认证

是对非对称加密技术与数字摘要技术的综合运用,指的是将通信内容的摘要信息使用发送者的私钥进行加密,然后将密文和原文一起传输给信息的接收者,接收者通过发送者的公钥解密被加密的摘要信息,然后使用与发送者相同的摘要算法,对接收到的内容采用相同的方式产生摘要串,与解密的摘要进行对比,如果相同,则说明接收到的内容是完整的,在传输过程中没有受到第三方篡改,否则说明通信内容已被第三方修改

数字签名有两种功效

一是能确定消息确实是由发送方签名并发出来的,因为别人假冒不了发送方的签名。私钥可以代表私钥持有者的身份,可以通过私钥对应的公钥来对私钥拥有者身份进行校验。通过数字签名,能够确认消息是由发送方签名并发送出来的,因为其他人根本假冒不了消息发送方的签名,他们没有消息发送者的私钥

二是数字签名能确定消息的完整性。因为数字签名的特点是它代表了文件的特征,文件如果发生改变,数字摘要的值也将发生变化。不同的文件将得到不同的数字摘要。 一次数字签名涉及到一个哈希函数、发送者的公钥、发送者的私钥。”

MD5withRSA

表示采用MD5算法生成需要发送正文的数字摘要,并使用RSA算法对正文进行加密和解密

SHA1withRSA

表示采用SHA1算法生成需要发送正文的数字摘要,并使用RSA算法对正文进行加密和解密

数字证书

也称为电子证书,集合了多种密码学的加密算法,证书自带公钥信息,可以完成相应的加密、解密操作,同时,还拥有自身信息的数字签名,可以鉴别证书的颁发机构,以及证书内容的完整性。由于证书本身含有用户的认证信息,因此可以作为用户身识别的依据。

通用数字证书会包含如下内容:

* 对象的名称(人、服务器、组织),即证书所代表的用户

* 证书的过期时间

* 证书的颁发机构

* 证书颁发机构对证书信息的数字签名(用于鉴别证书的颁发机构,以及证书内容的完整性,颁发机构用私钥对证书进行签名,而校验方使用颁发机构的公钥来解密签名,与其摘要算法生成的摘要进行比较)

* 签名算法

* 对象的公钥(对象的公钥用来对信息进行加密,信息传输到接收方,接收方将使用公钥对应的私钥进行解密)

证书格式标准 X.509

证书签发CA(Certificate Authority)

它的作用就是提供证书(也就是服务端证书,公钥+申请者与颁发者信息+签名 )来加强客户端与服务器端访问信息的安全性,同时提供证书的发放等相关工作。国内的大部分互联网公司都在国际CA机构申请了CA证书,并且在用户进行访问的时候,对用户的信息加密,保障了用户的信息安全。  客户端解析证书,首先会验证公钥是否有效,比如颁发机构,过期时间等等,如果发现异常,则会弹出一个警告框,提示证书存在问题。如果证书没有问题,那么就生成一个随机值。然后用证书对该随机值进行加密。就好像上面说的,把随机值用锁头锁起来,这样除非有钥匙,不然看不到被锁住的内容

1.服务器向CA机构获取证书,当浏览器首次请求服务器的时候,服务器返回证书给浏览器。

2.浏览器得到证书后,开始验证证书的所有者、有效期等信息;浏览器开始查找操作系统中已内置的受信任的证书发布机构CA,与服务器发来的证书中的颁发者CA比对,用于校验证书是否为合法机构颁发;如果找不到,浏览器就会报错,说明服务器发来的证书是不可信任的。

3.验证完证书后,如果证书有效,或者是用户接受了不受信的证书,浏览器会生成一串随机数的密码,并用证书中提供的公钥加密。发送给服务器,服务器用私钥进行解密,得到随机数。之后双方便开始用该随机数作为钥匙,对要传递的数据进行加密、解密。 

证书校验

摘要认证的实现

1.客户端参数摘要生成:请求的参数需要先排好序,服务端和客户端需要事先约定好排序的方式,否则生成的摘要可能差很远,排好序后,将参数名称与参数值串起来,加上约定好的secret,生成待摘要的字符串,最后使用MD5之类的摘要算法生成摘要串,当然摘要算法也需要事先约定好

2. 服务端参数摘要校验:服务端接收到请求的参数后,按照与客户端相同的方式将参数排序,然后将参数的名称与参数的值串起来,生成待摘要字符串,并且与客户端相同的摘要算法生成摘要串,最后将服务端生成的摘要串与客户端通过header或者其他形式传过来的摘要串进行比较

3. 服务端响应摘要生成:服务端生成响应内容以后,在响应内容后面加上secret,便是待摘要串,然后使用MD5等摘要算法生成响应摘要串

4. 客户端响应摘要校验:客户端接收到服务端的响应内容以后,在响应内容后面加上secret,便成为待摘要串,然后通过MD5等摘要算法的计算来生成对应的响应摘要,与服务端通过header等方式传递过来的摘要串进行比较

签名认证

相对于摘要认证,签名认证的优势在于加密时使用的是私钥,而解密时使用的是对外公开的公钥

摘要认证的方式能够一定程度上防止通信的内容被篡改,但是,算法的安全性取决于secret的安全性,由于通信的客户端与服务端采用的都是相同的secret,一旦secret泄露,恶意攻击者便可以根据相应的摘要算法,伪造出合法的请求或者响应的摘要,达成攻击目的

与摘要认证的方式类似,由于发送端和接收端都认为HTTP协议的请求参数都是无序的,因此对于签名认证来说,客户端和服务端需要约定好参数的排序方式,请求参数经过排序后,再将参数名称和值经过一定的策略组织起来,这时不再是加上secret,而是直接通过约定的摘要算法来生成数字摘要,并且使用客户端私钥对数字摘要进行加密,将加密的密文传递给服务端

1.客户端参数签名生成:请求参数排序以后,将参数的名称和值拼接起来,形成待摘要字符串,然后使用与服务端约定好的摘要算法生成摘要串,生成的摘要串再使用客户端的私钥进行加密,形成数字签名

2.服务端参数签名校验:服务端接收到请求参数后,采用与客户端相同的方式将参数排序,然后将参数拼接成待摘要字符串,使用MD5等摘要算法将待摘要字符串生成摘要,然后使用客户端的公钥对接收到的签名进行解密,将服务端生成的摘要串与解密后的摘要字符串进行比较

3.服务端响应签名生成:针对于响应,服务端直接将其作为待摘要字符串,使用MD5等摘要算法生成摘要串后,使用服务端的私钥对摘要串进行加密,生成数字签名

4.客户端响应签名校验:客户端收到服务端响应内容后,使用MD5等摘要算法生成摘要,然后使用服务器公钥解密服务端返回的数字签名,比较解密后的摘要串是否与客户端生成的摘要串一致

 HTTPS

摘要认证和签名认证虽然能够解决数据完整性和通信两端的合法性问题,但对于一些较为敏感的信息,如个人隐私数据、用户名密码等,这些信息如以明文方式传递,一旦用户的通信被拦截,相关信息会有较大的泄露风险,因此有必要采用更加严密手段来保障信息的安全。

HTTPS的全称是Hypertext Transfer Protocal over Secure Socket Layer,基于SSL的HTTP协议,简单说就是安全版本的HTTP

依托SSL协议,hTTPS能确保整个通信过程都是经过加密的,密钥随机产生,并且通过数字证书验证通信双方的身份,以此来保证信息安全。通信的内容通过对称加密方式进行加密,通信两端约好通信密码后,通过公钥对密码进行加密传输,只有公钥对应私钥,也就是通信的另一端能够解密获得通信密码,这样既保障了通信的安全,也是加密性能和时间成本可控。

SSL的全称是Secure Sockets Layer即安全套接层。是一种网络安全协议,目的是为了保障网络通信的安全,校验通信双方的身份,加密传输的数据。SSL在传输层和应用层之间进行数据通信加密

TLS全称Transport Layer Security ,即传输层安全协议,SSL的继任者

你可能感兴趣的:(常用加密算法-Go语言实践)