它的主要作用是将二进制数据转换为文本格式,从而便于在文本传输通道中传递。
因为传输二进制数据时候比如在http中要以可见字符传输,所以需要将二进制数据编码为可见字符。
ans := make([]byte, base64.StdEncoding.EncodedLen(len("abcd")))
base64.StdEncoding.Encode(ans,[]byte("abcs"))//编码
fmt.Println(string(ans))
ans2 := make([]byte, base64.StdEncoding.DecodedLen(len(ans)))
base64.StdEncoding.Decode(ans2,ans)//解码
fmt.Println(string(ans2))
将字节数组转换为十六进制字符串
将其每个字节转换为两个十六进制字符,并将结果组合成一个字符串返回。但是比base64长
对比base64是十六进制编码可以直接参与运算,且方便查看二进制数据
哈希算法(Hash Function) 是一种将任意长度的数据转换为固定长度的输出,该输出基于输入数据,且唯一对应于输入数据。哈希函数是单向函数,它将输入转换为固定长度的输出,而且不可逆。
返回定长16字节的128位bit哈希值
数据完整性校验:MD5算法常用于验证数据的完整性。在数据传输过程中,发送方可以计算数据的MD5哈希值并将其发送给接收方。接收方收到数据后,再次计算哈希值并与发送方提供的哈希值进行比较。如果两者匹配,则说明数据在传输过程中没有被篡改。
密码存储:MD5算法也常用于密码存储。将用户密码通过MD5哈希后存储在数据库中,即使数据库被泄露,攻击者也无法直接获取用户的明文密码。然而,由于MD5算法存在已知的安全漏洞(如彩虹表攻击和碰撞攻击),现在已不推荐使用MD5来存储密码。更安全的做法是使用加盐哈希
func Test_MD5(t *testing.T) {
salt := "123456"//盐值
s := "hello"//需要哈希的字符串
h := md5.New()//创建一个md5对象
h.Write([]byte(s)+[]byte(salt))//写入需要哈希的字符串
fmt.Println(h.Sum(nil))//Sum把哈希值追加到参数*[]byte中,并返回
}
即使加盐,MD5 仍然可以被破解。加盐只是增加了破解的难度,但并没有解决 MD5 本身的安全缺陷。以下是详细的解释:
加盐的作用和局限性
增加破解难度:加盐主要是为了防止彩虹表攻击(即预计算哈希值的查找表)。通过加入随机盐值,每个输入的哈希结果都会有所不同,即使输入相同也会生成不同的哈希值,这使得预计算哈希表变得无效。
防止简单暴力破解:如果每个输入都带有唯一的盐值,攻击者不能一次破解多个哈希值,他们必须针对每个盐值单独进行暴力破解。
盐值和输入:盐值并不需要保密,通常与哈希值一起存储。然而,盐值的存在不会消除哈希算法的固有弱点。如果哈希算法易于碰撞(如 MD5),攻击者仍然可以利用这些弱点进行攻击。
返回定长32字节的256bit哈希值
SHA-256 是一种哈希算法,属于安全哈希算法(Secure Hash Algorithm)家族的一员,用于将任意长度的输入数据转换为固定长度(256 比特,即 32 字节)的哈希值。SHA-256 具有以下特点:
func Test_SHA256(t *testing.T) {
s := "hello"//需要哈希的字符串
h := sha256.New()//创建一个sha256对象
h.Write([]byte(s))//写入需要哈希的字符串
fmt.Println(hex.EncodeToString(h.Sum(nil)))//Sum把哈希值追加到参数*[]byte中,并返回
}
HMAC 是一种基于哈希函数和密钥的消息认证码。它结合了哈希算法(如 SHA-256、SHA-1、MD5 等)和密钥,用于生成一种认证码,用于验证消息的完整性和真实性。HMAC 的特点包括:
func Test_HMAC(t *testing.T) {
key := []byte("secret")// 密钥
a := hmac.New(sha256.New, key)// 创建一个新的hmac对象
a.Write([]byte("hello"))// 写入需要签名的数据
b := a.Sum(nil)// 计算签名并返回结果
fmt.Println(base64.StdEncoding.EncodeToString(b))// 对结果进行Base64编码
//iKqz7ejTrflNJquQ07r9SiCDBww7zOnAFO4EpEOEfAs=
}
加密算法(Encryption Algorithm) 是将明文(plaintext)转换为密文(ciphertext),或者将密文转换为明文的算法。
加密都是把一个block快加密成等长的密文,由于只能一个个块加密,要配合不同的加密模式例如下面的CBC模式和ECB模式,才能达到加密的目的。
对称加密比非对称加密快
DES 加密算法的密钥长度应该是 8 个字节(64 位),不过实际上只有 56 位被用于加密计算,而 8 位用于奇偶校验,所以通常是使用 8 个字节的密钥
对于 DES 加密算法而言,数据长度必须是加密块大小的整数倍,即 8 字节。
但是近些年使用越来越少,因为 DES 使用56位密钥(密钥长度越长越安全),以现代计算能力24小时内即可被破解。虽然如此,在某些简单应用中,我们还是可以使用 DES 加密算法。
var key = []byte("12345678") // 56位密钥
//编码一个blocksize长度的块(8位)
func encoded(s []byte) []byte {
block, _ := des.NewCipher(key) //Cipher是密码的意思
ans := make([]byte, len(s))
block.Encrypt(ans, s) //encrypt加密一个block块
return ans
}
//解码一个blocksize长度的块(8位)
func decoded(s []byte) []byte {
block, _ := des.NewCipher(key) //Cipher是密码的意思
ans := make([]byte, len(s))
block.Decrypt(ans, s) //decrypt解密一个block块
return ans
}
func Test_AES(t *testing.T) {
key := []byte("1234567890123456") // 16字节密钥
plaintext := []byte("helloworldaaaaaa")// 16字节明文
ans:=encoded_aes(key,plaintext)
fmt.Println(ans)
fmt.Println(deccode_aes(key,ans))
}
// 编码一个blocksize长度的块(16位)
func encoded_aes(keys,s []byte) []byte {
block, _ := aes.NewCipher(keys) //Cipher是密码的意思
ans := make([]byte, len(s))
block.Encrypt(ans, s) //encrypt加密一个block块
return ans
}
func deccode_aes(keys,s []byte) []byte {
block, _ := aes.NewCipher(keys) //Cipher是密码的意思
ans := make([]byte, len(s))
block.Decrypt(ans, s) //encrypt加密一个block块
return ans
}
AES(Advanced Encryption Standard)和DES(Data Encryption Standard)是两种常见的对称加密算法,它们在多个方面有显著的区别:
func Test_RSA(t *testing.T) {
// 生成私钥和公钥
privateKey, _ := rsa.GenerateKey(rand.Reader, 2048)
publicKey := &privateKey.PublicKey
// 保存私钥和公钥
// res1 := pem.EncodeToMemory(&pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(privateKey)})
// res2 := pem.EncodeToMemory(&pem.Block{Type: "PUBLIC KEY", Bytes: x509.MarshalPKCS1PublicKey(publicKey)})
// ioutil.WriteFile("private.pem", res1, 0600)
// ioutil.WriteFile("public.pem", res2, 0600)
//读取私钥和公钥
data, _ := ioutil.ReadFile("private.pem")
block, _ := pem.Decode(data)
privateKey, _ = x509.ParsePKCS1PrivateKey(block.Bytes)
data, _ = ioutil.ReadFile("public.pem")
block, _ = pem.Decode(data)
publicKey, _ = x509.ParsePKCS1PublicKey(block.Bytes)
// 加密
src := []byte("hello world")
encrypted, _ := rsa.EncryptOAEP(sha256.New(), rand.Reader, publicKey, src, nil)
fmt.Println("加密后的数据:",base64.StdEncoding.EncodeToString(encrypted))
// 解密
decrypted, _ := rsa.DecryptOAEP(sha256.New(), rand.Reader, privateKey, encrypted, nil)
fmt.Println(string(decrypted))
}
ECC 密钥
在椭圆曲线加密(ECC)中:
pem.EncodeToMemory 是 Go 语言标准库中的一个函数,位于 encoding/pem 包内,用于将 PEM 编码的块(pem.Block)编码为字节切片并返回。
什么是 PEM 编码
PEM(Privacy-Enhanced Mail)编码是一种用于表示加密对象(如证书、私钥、公钥等)的标准。PEM 格式的文件通常以 -----BEGIN
例如:public.pem 文件的内容可能如下所示:
-----BEGIN PUBLIC KEY-----
MIIBCgKCAQEAvHxBCN85ydD+qwZvnIC1jt2X6PCivCgmgF0whfRfZE2CSukKJfWs
BZaPDdV8Zus/LPuH7PJs1rOazwQxyoewSy0hO2h66eAoyfCkGAwi30+lshop/oiK
BrHQW0g3S7Uywcfx+WQpFxP+YtWqXqhSGmb/Y83gYpvVtWUm5zzWleg1Iv1M2ihs
KBR+SxAoLRQmnycEmHlOorw138VR0wnH8Gmh9xNZ/+RV6wIOQVmf1VHu+dJnmf21
wAMdua9nOoibxrVz69IzjixiXi5M1El2jncAMGjRBJsMbwtfWPbABVju6f6PK13y
nYcf1rwlRcchxTeAwVnMCppMStrdhl2fTQIDAQAB
-----END PUBLIC KEY-----
pem.EncodeToMemory 的作用
pem.EncodeToMemory 的主要作用是将一个 pem.Block 对象编码为 PEM 格式的字节切片,方便存储或传输。
示例代码
下面是一个使用 pem.EncodeToMemory 的示例,它生成一个 RSA 私钥,并将其编码为 PEM 格式的字节切片,然后打印出来:
package main
import (
"crypto/rand"
"crypto/rsa"
"crypto/x509"
"encoding/pem"
"fmt"
)
func main() {
// 生成 RSA 私钥
privateKey, err := rsa.GenerateKey(rand.Reader, 2048)
if err != nil {
fmt.Println("Error generating RSA key:", err)
return
}
// 将私钥转换为 PKCS#1 格式的 ASN.1 DER 编码
privateKeyDER := x509.MarshalPKCS1PrivateKey(privateKey)
// 创建一个 PEM Block
privateKeyBlock := &pem.Block{
Type: "RSA PRIVATE KEY",
Bytes: privateKeyDER,
}
// 将 PEM Block 编码为字节切片
privateKeyPEM := pem.EncodeToMemory(privateKeyBlock)
// 打印 PEM 编码的私钥
fmt.Println(string(privateKeyPEM))
}
DER(Distinguished Encoding Rules)格式是一种二进制编码格式,用于存储 ASN.1 编码的结构。
DER 格式的文件通常以 0x30 开始,以 0x00 结束。
https://blog.csdn.net/fengshenyun/article/details/124596279
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])
fmt.Println("unpadding:", origData[length-1])
return origData[:(length - unpadding)]
}
func Test_DES_CBC(t *testing.T) {
key := []byte("12345678") // 8位密钥
plaintext := []byte("hello woqrld for study des cbc") // 8字节明文
iv := []byte("12345678") // 8字节iv
block, _ := des.NewCipher(key)
mode := cipher.NewCBCEncrypter(block, iv) // 创建一个新的CBC加密器
fmt.Println("补位前明文:", plaintext, len(plaintext))
plaintext = PKCS7Padding(plaintext, block.BlockSize()) // 填充
fmt.Println("加密前明文:", plaintext, len(plaintext))
ciphertext := make([]byte, len(plaintext)) // 16字节密文
for i := 0; i < len(plaintext); i += des.BlockSize {
blocks := plaintext[i : i+des.BlockSize] // 取出一个block块
mode.CryptBlocks(ciphertext[i:], blocks) // 加密一个block块
}
fmt.Println("加密后密文:", ciphertext)
fmt.Println("解密前密文:", ciphertext)
block1, _ := des.NewCipher(key)
mode1 := cipher.NewCBCDecrypter(block1, iv) // 创建一个新的CBC解密器
plaintext1 := make([]byte, len(ciphertext))
for i := 0; i < len(ciphertext); i += des.BlockSize {
block2 := ciphertext[i : i+des.BlockSize] // 取出一个block块
mode1.CryptBlocks(plaintext1[i:], block2) // 解密一个block块
}
fmt.Println("解密后明文:", plaintext1)
plaintext1 = PKCS7UnPadding(plaintext1) // 去除填充
fmt.Println("去除填充后明文:", string(plaintext1))
}
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])
fmt.Println("unpadding:", origData[length-1])
return origData[:(length - unpadding)]
}
func encrypt_DES_ECB(plaintext, key []byte) ([]byte, error) {
block, err := des.NewCipher(key)
if err != nil {
return nil, err
}
//对明文进行填充
plaintext = PKCS7Padding(plaintext, block.BlockSize())
ciphertext := make([]byte, len(plaintext))
//就是逐块EDS加密后拼接
for bs, be := 0, block.BlockSize(); bs < len(plaintext); bs, be = bs+block.BlockSize(), be+block.BlockSize() {
block.Encrypt(ciphertext[bs:be], plaintext[bs:be])
}
return ciphertext, nil
}
func decrypt_DES_ECB(ciphertext, key []byte) ([]byte, error) {
block, _ := des.NewCipher(key)
lens := len(ciphertext)
ans := make([]byte, lens)
//就是逐块EDS解密后拼接
for bs, be := 0, block.BlockSize(); bs < len(ciphertext); bs, be = bs+block.BlockSize(), be+block.BlockSize() {
block.Decrypt(ans[bs:be], ciphertext[bs:be])
}
//对密文进行去填充
ans = PKCS7UnPadding(ans)
return ans, nil
}
func Test_DES_ECB(t *testing.T) {
// 加密
key := []byte("12345678")
src := []byte("hello world")
ans, _ := encrypt_DES_ECB(src, key)
fmt.Println(ans)
// 解密
ans1, _ := decrypt_DES_ECB(ans, key)
fmt.Println(string(ans1))
}