go语言之字符串加密

项目中常用的加解密的方式三种:

  • 对称加密, 加解密都使用的是同一个密钥, 其中的代表就是AES
  • 非对加解密, 加解密使用不同的密钥, 其中的代表就是RSA
  • 签名算法, 如MD5SHA1HMAC等, 主要用于验证,防止信息被修改, 如:文件校验、数字签名、鉴权协议

一、AES:

AES:高级加密标准(Advanced Encryption Standard),又称Rijndael加密法,这个标准用来替代原先的DES,AES加密数据块分组长度必须为128bit(byte[16]),密钥长度可以是128bit(byte[16])、192bit(byte[24])、256bit(byte[32])中的任意一个

块:对明文进行加密的时候,先要将明文按照128bit进行划分

填充方式:因为明文的长度不一定总是128的整数倍,所以要进行补位,我们这里采用的是PKCS7填充方式

AES实现的方式多样, 其中包括ECBCBC、CTR、CFBOFB

  • 电码本模式(Electronic Codebook Book (ECB)):将明文分组加密之后的结果直接称为密文分组
  • 密码分组链接模式(Cipher Block Chaining (CBC)):将明文分组与前一个密文分组进行XOR运算,然后再进行加密。每个分组的加解密都依赖于前一个分组。而第一个分组没有前一个分组,因此需要一个初始化向量
  • 计算器模式(Counter (CTR))
  • 密码反馈模式(Cipher FeedBack (CFB)):前一个密文分组会被送回到密码算法的输入端
  • 输出反馈模式(Output FeedBack (OFB))
加密模式对应加解密方法
CBCNewCBCDecrypter, NewCBCEncrypter
CTRNewCTR
CFBNewCFBDecrypter, NewCFBEncrypter
OFBNewOFB

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

标签