跳到主要内容

Go与加密算法

一 密码学概述

1.0 加密算法分类

常用的加密算法有三类:

  • 哈希算法:不可逆
  • 加密解密算法:通过秘钥实现加密解密,是可逆的
  • 编码解码算法:无需秘钥,是可逆的,如Base64,但是严格意义上来说该类算法只是一种数据编码格式

1.1 哈希算法

哈希算法其实是一种消息摘要实现技术,hash是剁碎的意思,所以也称呼hash为散列。

哈希算法能让任意长度的二进制值映射为较短的固定长度的二进制值,并且不同明文基本上不会映射为相同的Hash值。

哈希算法加密不可逆,常见的算法有:md4、md5、hash1、SHA256、SHA3等。

例如一段字符串hello world,经过md5加密后转换成了:5eb63bbbe01eeed093cb22bb8f5acdc3,该密文是无法返回到原始的明文的。

不过哈希算法必须解决冲突问题,即不同的数据通过哈希算法产生了相同的输出,MD5,SHA-1算法都已经被证明不具备”强抗碰撞性“,不足以应对要求很高的商业场景。

为了提升哈希算法的安全性,推荐使用SHA-2,该算法是SHA-256,SHA-512等算法的并称。

不过MD5仍然被大量用于网站的登录中,如下所示:

![] (04-01.png)

利用彩虹表攻击,哈希算法变得很脆弱,可以通过加盐的方式提升安全性:

![] (04-02.png)

1.2 加密解密算法-对称加密

对称加密(datar encryption algorithm,DEA)也称为私钥加密算法、单秘钥算法,常见的对称加密算法有:DES,3DES,AES等。

对称加密的特点:

  • 加密和解密的秘钥相同
  • 运算效率加高

对称加密由于加密方和解密方需要共享秘钥,所以容易泄露,如下所示:

![] (04-03.png)

DES目前是非常安全的加密方式,只有穷举法才可以破解。

1.3 加密解密算法-非对称加密

非对称加密也称呼为公钥加密,最著名的非对称加密算法是RSA、椭圆曲线算法ECC。

非对称加密的特点:加密和解密分别使用两个不同的秘钥。使用其中一个秘钥对明文加密得到的密文,只有另外一个秘钥才能解密得到明文!而且这2个秘钥只在数学上有关,即使知道了其中一个,也无法计算出另外一个,所以一个可以公开,任意发布,一个不公开,由用户保管,绝对不同通过任何途径传输。

这两个秘钥分别是:

  • 公钥:公开秘钥,公钥可以向外任意发布。
  • 私钥:私有秘钥,私钥由用户存储,私钥不能通过任何渠道传输

总结如下:

  • 公开密钥和私有密钥是一对
  • 如果用公开密钥对数据进行加密,只有用对应的私有密钥才能解密。
  • 如果用私有密钥对数据进行加密,只有用对应的公开密钥才能解密。
  • 因为加密和解密使用的是两个不同的密钥,所以这种算法叫作非对称加密算法。

步骤如下: ![] (04-04.png)

非对称加密中用于解密的私钥是不公开、不进行传输的,所以安全性较高,但是相对的,也增加了运算时间。

1.4 加解密算法

加密解密算法包括三种:

  • 对称加密:包括DES、3DES、AES等
  • 非对称加密:包括RSA算法、椭圆曲线加密算法
  • 数字签名算法DSA

编码解码算法常见的有Base64编码解码,Base58编码解码。

二 数字签名与验证

非对称加密中双方进行通信的加密解密过程:

  • 1.A要向B发送信息,A和B都要产生一对用于加密和解密的公钥和私钥
  • 2.A的私钥保密,A的公钥告诉B;B的私钥保密,B的公钥告诉A。
  • 3.A要给B发送信息时,A用B的公钥加密信息,因为A知道B的公钥。
  • 4.A将这个消息发给B(已经用B的公钥加密消息)。
  • 5.B收到这个消息后,B用自己的私钥解密A的消息。其他所有收到这个报文的人都无法解密,因为只有B才有B的私钥。

通过公钥加密、私钥解密的过程,称为数字签名、验证签名。数字签名有两部分组成:

  • 使用私钥从消息中创建签名
  • 允许任何人验证签名

数字签名主要用于验证双方的数据是否被串改,数字签名与加密解密不是一个概念!

非对称加密找那个双方进行通信时,不但要对消息进行加密解密,也要执行数字签名与验证:

![] (04-05.png)

三 Go实现加密算法

3.1 AES

import (
"bytes"
"crypto/aes"
"fmt"
"crypto/cipher"
"encoding/base64"
)

func main() {
orig := "hello world"
key := "123456781234567812345678"
fmt.Println("原文:", orig)

encryptCode := AesEncrypt(orig, key)
fmt.Println("密文:" , encryptCode)

decryptCode := AesDecrypt(encryptCode, key)
fmt.Println("解密结果:", decryptCode)
}

func AesEncrypt(orig string, key string) string {
// 转成字节数组
origData := []byte(orig)
k := []byte(key)

// 分组秘钥
block, _ := aes.NewCipher(k)
// 获取秘钥块的长度
blockSize := block.BlockSize()
// 补全码
origData = PKCS7Padding(origData, blockSize)
// 加密模式
blockMode := cipher.NewCBCEncrypter(block, k[:blockSize])
// 创建数组
cryted := make([]byte, len(origData))
// 加密
blockMode.CryptBlocks(cryted, origData)

return base64.StdEncoding.EncodeToString(cryted)

}

func AesDecrypt(cryted string, key string) string {
// 转成字节数组
crytedByte, _ := base64.StdEncoding.DecodeString(cryted)
k := []byte(key)

// 分组秘钥
block, _ := aes.NewCipher(k)
// 获取秘钥块的长度
blockSize := block.BlockSize()
// 加密模式
blockMode := cipher.NewCBCDecrypter(block, k[:blockSize])
// 创建数组
orig := make([]byte, len(crytedByte))
// 解密
blockMode.CryptBlocks(orig, crytedByte)
// 去补全码
orig = PKCS7UnPadding(orig)
return string(orig)
}

//补码
func PKCS7Padding(ciphertext []byte, blocksize int) []byte {
padding := blocksize - len(ciphertext)%blocksize
padtext := bytes.Repeat([]byte{byte(padding)}, padding)
return append(ciphertext, padtext...)
}

//去码
func PKCS7UnPadding(origData []byte) []byte {
length := len(origData)
unpadding := int(origData[length-1])
return origData[:(length - unpadding)]
}

3.2 DES

填充和去填充函数:

func ZeroPadding(ciphertext []byte, blockSize int) []byte {
padding := blockSize - len(ciphertext)%blockSize
padtext := bytes.Repeat([]byte{0}, padding)
return append(ciphertext, padtext...)
}

func ZeroUnPadding(origData []byte) []byte {
return bytes.TrimFunc(origData,
func(r rune) bool {
return r == rune(0)
})
}

加密:

func Encrypt(text string, key []byte) (string, error) {
src := []byte(text)
block, err := des.NewCipher(key)
if err != nil {
return "", err
}
bs := block.BlockSize()
src = ZeroPadding(src, bs)
if len(src)%bs != 0 {
return "", errors.New("Need a multiple of the blocksize")
}
out := make([]byte, len(src))
dst := out
for len(src) > 0 {
block.Encrypt(dst, src[:bs])
src = src[bs:]
dst = dst[bs:]
}
return hex.EncodeToString(out), nil
}

解密:

func Decrypt(decrypted string , key []byte) (string, error) {
src, err := hex.DecodeString(decrypted)
if err != nil {
return "", err
}
block, err := des.NewCipher(key)
if err != nil {
return "", err
}
out := make([]byte, len(src))
dst := out
bs := block.BlockSize()
if len(src)%bs != 0 {
return "", errors.New("crypto/cipher: input not full blocks")
}
for len(src) > 0 {
block.Decrypt(dst, src[:bs])
src = src[bs:]
dst = dst[bs:]
}
out = ZeroUnPadding(out)
return string(out), nil
}

测试:

func main() {
key := []byte("2fa6c1e9")
str :="I love this beautiful world!"
strEncrypted, err := Encrypt(str, key)
if err != nil {
log.Fatal(err)
}
fmt.Println("Encrypted:", strEncrypted)
strDecrypted, err := Decrypt(strEncrypted, key)
if err != nil {
log.Fatal(err)
}
fmt.Println("Decrypted:", strDecrypted)
}
//Output:
//Encrypted: 5d2333b9fbbe5892379e6bcc25ffd1f3a51b6ffe4dc7af62beb28e1270d5daa1
//Decrypted: I love this beautiful world!

3.3 RSA

首先使用openssl生成公私钥,使用RSA的时候需要提供公钥和私钥 , 可以通过openss来生成对应的pem格式的公钥和私钥匙:

import (
"crypto/rand"
"crypto/rsa"
"crypto/x509"
"encoding/base64"
"encoding/pem"
"errors"
"fmt"
)

// 私钥生成
//openssl genrsa -out rsa_private_key.pem 1024
var privateKey = []byte(`
-----BEGIN RSA PRIVATE KEY-----
MIICWwIBAAKBgQDcGsUIIAINHfRTdMmgGwLrjzfMNSrtgIf4EGsNaYwmC1GjF/bM
h0Mcm10oLhNrKNYCTTQVGGIxuc5heKd1gOzb7bdTnCDPPZ7oV7p1B9Pud+6zPaco
qDz2M24vHFWYY2FbIIJh8fHhKcfXNXOLovdVBE7Zy682X1+R1lRK8D+vmQIDAQAB
AoGAeWAZvz1HZExca5k/hpbeqV+0+VtobMgwMs96+U53BpO/VRzl8Cu3CpNyb7HY
64L9YQ+J5QgpPhqkgIO0dMu/0RIXsmhvr2gcxmKObcqT3JQ6S4rjHTln49I2sYTz
7JEH4TcplKjSjHyq5MhHfA+CV2/AB2BO6G8limu7SheXuvECQQDwOpZrZDeTOOBk
z1vercawd+J9ll/FZYttnrWYTI1sSF1sNfZ7dUXPyYPQFZ0LQ1bhZGmWBZ6a6wd9
R+PKlmJvAkEA6o32c/WEXxW2zeh18sOO4wqUiBYq3L3hFObhcsUAY8jfykQefW8q
yPuuL02jLIajFWd0itjvIrzWnVmoUuXydwJAXGLrvllIVkIlah+lATprkypH3Gyc
YFnxCTNkOzIVoXMjGp6WMFylgIfLPZdSUiaPnxby1FNM7987fh7Lp/m12QJAK9iL
2JNtwkSR3p305oOuAz0oFORn8MnB+KFMRaMT9pNHWk0vke0lB1sc7ZTKyvkEJW0o
eQgic9DvIYzwDUcU8wJAIkKROzuzLi9AvLnLUrSdI6998lmeYO9x7pwZPukz3era
zncjRK3pbVkv0KrKfczuJiRlZ7dUzVO0b6QJr8TRAA==
-----END RSA PRIVATE KEY-----
`)

// 公钥: 根据私钥生成
//openssl rsa -in rsa_private_key.pem -pubout -out rsa_public_key.pem
var publicKey = []byte(`
-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDcGsUIIAINHfRTdMmgGwLrjzfM
NSrtgIf4EGsNaYwmC1GjF/bMh0Mcm10oLhNrKNYCTTQVGGIxuc5heKd1gOzb7bdT
nCDPPZ7oV7p1B9Pud+6zPacoqDz2M24vHFWYY2FbIIJh8fHhKcfXNXOLovdVBE7Z
y682X1+R1lRK8D+vmQIDAQAB
-----END PUBLIC KEY-----
`)

// 加密
func RsaEncrypt(origData []byte) ([]byte, error) {
//解密pem格式的公钥
block, _ := pem.Decode(publicKey)
if block == nil {
return nil, errors.New("public key error")
}
// 解析公钥
pubInterface, err := x509.ParsePKIXPublicKey(block.Bytes)
if err != nil {
return nil, err
}
// 类型断言
pub := pubInterface.(*rsa.PublicKey)
//加密
return rsa.EncryptPKCS1v15(rand.Reader, pub, origData)
}

// 解密
func RsaDecrypt(ciphertext []byte) ([]byte, error) {
//解密
block, _ := pem.Decode(privateKey)
if block == nil {
return nil, errors.New("private key error!")
}
//解析PKCS1格式的私钥
priv, err := x509.ParsePKCS1PrivateKey(block.Bytes)
if err != nil {
return nil, err
}
// 解密
return rsa.DecryptPKCS1v15(rand.Reader, priv, ciphertext)
}
func main() {
data, _ := RsaEncrypt([]byte("hello world"))
fmt.Println(base64.StdEncoding.EncodeToString(data))
origData, _ := RsaDecrypt(data)
fmt.Println(string(origData))
}