go语言之字符串加密
项目中常用的加解密的方式三种:
- 对称加密, 加解密都使用的是同一个密钥, 其中的代表就是
AES - 非对加解密, 加解密使用不同的密钥, 其中的代表就是
RSA - 签名算法, 如
MD5、SHA1、HMAC等, 主要用于验证,防止信息被修改, 如:文件校验、数字签名、鉴权协议
一、AES:
AES:高级加密标准(Advanced Encryption Standard),又称Rijndael加密法,这个标准用来替代原先的DES,AES加密数据块分组长度必须为128bit(byte[16]),密钥长度可以是128bit(byte[16])、192bit(byte[24])、256bit(byte[32])中的任意一个
块:对明文进行加密的时候,先要将明文按照128bit进行划分
填充方式:因为明文的长度不一定总是128的整数倍,所以要进行补位,我们这里采用的是PKCS7填充方式
AES实现的方式多样, 其中包括ECB、CBC、CTR、CFB、OFB等
- 电码本模式(Electronic Codebook Book (ECB)):将明文分组加密之后的结果直接称为密文分组
- 密码分组链接模式(Cipher Block Chaining (CBC)):将明文分组与前一个密文分组进行XOR运算,然后再进行加密。每个分组的加解密都依赖于前一个分组。而第一个分组没有前一个分组,因此需要一个初始化向量
- 计算器模式(Counter (CTR))
- 密码反馈模式(Cipher FeedBack (CFB)):前一个密文分组会被送回到密码算法的输入端
- 输出反馈模式(Output FeedBack (OFB))
| 加密模式 | 对应加解密方法 |
| CBC | NewCBCDecrypter, NewCBCEncrypter |
| CTR | NewCTR |
| CFB | NewCFBDecrypter, NewCFBEncrypter |
| OFB | NewOFB |
1、CBC模式,最常见的使用方式:
package main
import (
"bytes"
"crypto/aes"
"crypto/cipher"
"encoding/base64"
"fmt"
)
func main() {
str := "hello world"
//key的长度可是16位、24位、32位中的一个
key := "1235456789012f4D8888888823122234"
fmt.Println("原字符串内容:", str)
encryptCode := AesEncrypt(str, key)
fmt.Println("加密后的密文:", encryptCode)
decryptCode := AesDecrypt(encryptCode, key)
fmt.Println("解密结果:", decryptCode)
}
func AesEncrypt(str string, key string) string {
// 转成字节数组
strData := []byte(str)
k := []byte(key)
// 分组秘钥
// NewCipher该函数限制了输入k的长度必须为16, 24或者32
block, _ := aes.NewCipher(k)
// 获取秘钥块的长度
blockSize := block.BlockSize()
// 补全码
strData = PKCS7Padding(strData, blockSize)
// 加密模式
blockMode := cipher.NewCBCEncrypter(block, k[:blockSize])
// 创建数组
cryted := make([]byte, len(strData))
// 加密
blockMode.CryptBlocks(cryted, strData)
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])
// 创建数组
str := make([]byte, len(crytedByte))
// 解密
blockMode.CryptBlocks(str, crytedByte)
// 去补全码
str = PKCS7UnPadding(str)
return string(str)
}
//补码
//AES加密数据块分组长度必须为128bit(byte[16]),密钥长度可以是128bit(byte[16])、192bit(byte[24])、256bit(byte[32])中的任意一个。
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(strData []byte) []byte {
length := len(strData)
unpadding := int(strData[length-1])
return strData[:(length - unpadding)]
}
运行结果如下:

二、签名算法方式加密字符串
1、sha256加密字符串

运行结果如下:

2、通过sha256加密文件,如图:

运行结果如下:

3、通过md5方式加密,有三种方式,如图:

运行结果如下:

注:md5加密方式不可逆,也就说可加密不可解密,通常用于文件对比,sha256加密方式也不可逆,只能加密无法解密
三、RSA方式加密
1、执行命令生成私钥:
openssl genrsa -out rsa_private_key.pem 1024
2、根据私钥生成公钥:
openssl rsa -in rsa_private_key.pem -pubout -out rsa_public_key.pem
3、完整的加密方式如下:
package main
import (
"crypto/rand"
"crypto/rsa"
"crypto/x509"
"encoding/base64"
"encoding/pem"
"errors"
"fmt"
)
// 私钥生成,文件名 rsa_private_key.pem
//openssl genrsa -out rsa_private_key.pem 1024
//将私钥转换为字节切片
var privateKey = []byte(`
-----BEGIN RSA PRIVATE KEY-----
MIICWwIBAAKBgQC2cn5r0HpZ+Q2GFegNCHjbwJGkeE/h8aKgIXCndAeqRHy/RdR6
nkJfZB321EDsAFcCa3kRKPMKndAVbpyASLZpcl9DwEuyKcFlK1GXVn6ADidYThYv
ewasayxP10iLjHtebhPdgxqW63ElYpjKuFiiL54o526ADjzF8Jp5+8AR7wIDAQAB
AoGADJmPnYaCTKBkjLQKmIvTPOnppQAiFCqJ3qEwlH/w35NnQhZifC1dzBSv9RHn
geTsHWCqtcKsN6LThHe8RfetjMpdGPQqIpUrJJ
1JvZHcyL+Ppn+YrLztOLB3UhU2ECQQDwt/2yvXvH/bKP
Qf3Mgz6Ll8ZFcBb2hLUE2DdMt9llIpUjPOyFDSY+kc6lbWpx4DI/NYK9xHCtHt+a
7x3aYBenAkEAwgny101dzYMli63Y7vbzTPQjSSvoC07
XWR+qjt0ppTDMf6WLE3d5obmfAbSHCB8eQJAPYT4PG76rIDk2oHmCBdeq7RNQr/D
zprZ3HQZpeyyjYtKDChs1hAnPwRqiJKvCo1eqhLV6APFPClQwjrsKTw3rwJAa9EC
ulJURlgpNyDXKXL9+nrzufScXhbhnZ5t93SPKhKtw5BsKwSXZUkPfYa2Rk6JvMEs
L4hBUvUJJEgh/tEqeQJALros9McGUINUChqGKTk9qaDpFcBqS0Yx8JbHx53dS7S1
8m5TZ3yCQvRVEtuIhfgTK6HBZ/FwUCxUtdd0zm3Mow==
-----END RSA PRIVATE KEY-----
`)
// 公钥: 根据私钥生成,文件名:rsa_public_key.pem
//openssl rsa -in rsa_private_key.pem -pubout -out rsa_public_key.pem
var publicKey = []byte(`
-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSUAA4GNADCBiQKBgQC2cn5r0HpZ+Q2GFegNCHjbwJGk
eE/h8aKgIXCndAeqRHy/sAFcCa3kRKPMKndAVbpyASLZpcl9D
wEuyKcFlK1GXVn6ADidYThYvewasayxP10iLjHtebhPdgxqW63ElYpjKuFiiL54o
526ADjzF8Jp5+8AR7wIDAQAB
-----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))
}
运行结果如下:
[root@VM-16-6-centos Goproject]# go run jiami.go
加密后的内容: RGw0d86Kr3VO/8tHNnGKoSa6M38GXj/r3rTo9Ca+6+vRRaam7JGRozrJ2nnfrtEm/hQnY5HSJKv7Iy+nXac//YcHfvIXh3DQJ9Kb+4LPbMthL2YxM4iVEsfyhRMlmk8BaoiZlfOkh9I0PTqDbWdqo07zzAKQ5JW+pLWDA+oXLrs=
解密后: hello world


