GO 对称加密算法

加密算法,使用AES对称加密算法和CFB加密模式加密用户输入的密码:

package main

import (
	"crypto/aes"
	"crypto/cipher"
	"crypto/rand"
	"encoding/base64"
	"fmt"
	"log"
)

// 将明文进行加密
func encrypt(plainText string, key string) (string, error) {
	// 将 key 转换成字节数组
	keyBytes := []byte(key)
	// 创建一个新的密码快
	block, err := aes.NewCipher(keyBytes)
	if err != nil {
		return "", err
	}

	// 对明文进行补全
	plainBytes := []byte(plainText)
	padding := aes.BlockSize - len(plainBytes)%aes.BlockSize
	padBytes := make([]byte, padding)
	for i := 0; i < padding; i++ {
		padBytes[i] = byte(padding)
	}
	plainBytes = append(plainBytes, padBytes...)

	// 创建一个密文快
	cipherBytes := make([]byte, aes.BlockSize+len(plainBytes))
	iv := cipherBytes[:aes.BlockSize]
	if _, err := rand.Read(iv); err != nil {
		return "", err
	}
	stream := cipher.NewCFBEncrypter(block, iv)
	stream.XORKeyStream(cipherBytes[aes.BlockSize:], plainBytes)

	// 将密文转换为 base64 编码的字符串
	cipherText := base64.StdEncoding.EncodeToString(cipherBytes)
	return cipherText, nil
}

func main() {

	//随机填充key,使其长度为16,这里的key要保存起来,因为在下面解密的时候要使用(例如key="qwertyuiop123456")
	key := make([]byte, 16)
	if _, err := rand.Read(key); err != nil {
		panic(err)
	}

	fmt.Println("key:", key)

	//从控制台输入密码
	var password string
	log.Println("请输入密码:")
	_, err := fmt.Scanln(&password)
	if err != nil {
		log.Fatalf("scan password failed: %v", err)
	}

	// 加密
	cipherText, err := encrypt(password, string(key))
	if err != nil {
		panic(err)
	}
	fmt.Printf("加密成功!密文: %v\n", cipherText)
}

该加密算法使用AES对称加密算法加密了用户输入的密码。

首先,使用key作为密钥创建一个新的AES密码块。AES加密算法要求key的长度为128位(16字节)、192位(24字节)或256位(32字节),因此这里的key需要16个字符或24、32个字符。在代码中,将key转换为字节数组后,再通过aes.NewCipher()创建一个新的密码块,所以key的长度必须满足AES算法的要求。如果长度不足,则会报错。然后,将明文字符串转换为字节数组,对其进行补全以填充到AES块大小的倍数。随机生成一个长度为AES块大小的初始向量,并创建一个新的密文块。使用AES的CFB加密模式创建一个新的加密器,使用密钥和初始向量初始化加密器。使用加密器加密填充后的明文,将加密后的结果附加到密文块中。最后,将密文块转换为Base64编码的字符串,将其保存到配置文件中。

该算法中使用了AES对称加密算法和CFB加密模式。AES是一种常用的对称加密算法,它采用固定大小的块进行加密和解密。CFB模式是一种流密码模式,它可以将块密码转换为流密码。在CFB模式下,加密器会将前一个密文块作为输入,并输出一个伪随机的密钥流来加密下一个明文块。

解密算法,使用 CFB 模式的解密器解密:

package main

import (
	"crypto/aes"
	"crypto/cipher"
	"crypto/rand"
	"encoding/base64"
	"fmt"
	"log"
)

// 将密文进行解密
func decrypt(cipherText string, key string) (string, error) {
	// 将 key 转换成字节数组
	keyBytes := []byte(key)
	// 创建一个新的密码快
	block, err := aes.NewCipher(keyBytes)
	if err != nil {
		return "", err
	}

	// 将 base64 编码的字符串转换为密文字节数组
	cipherBytes, err := base64.StdEncoding.DecodeString(cipherText)
	if err != nil {
		return "", err
	}

	// 创建一个新的解密器
	if len(cipherBytes) < aes.BlockSize {
		return "", fmt.Errorf("ciphertext too short")
	}
	iv := cipherBytes[:aes.BlockSize]
	cipherBytes = cipherBytes[aes.BlockSize:]
	stream := cipher.NewCFBDecrypter(block, iv)
	stream.XORKeyStream(cipherBytes, cipherBytes)

	// 对解密后的明文进行去除补全
	length := len(cipherBytes)
	unpadding := int(cipherBytes[length-1])
	return string(cipherBytes[:(length - unpadding)]), nil
}
func main() {

	key="qwertyuiop123456"(加密时随机生成的16字节密钥)

	// 解密
	decryptedText, err := decrypt(cipherText, string(key))
	if err != nil {
		panic(err)
	}
	fmt.Printf("Decrypted text: %v\n", decryptedText)
}

这段代码实现了将密文进行解密的功能。它的实现原理是:

将 key 转换成字节数组,创建一个新的密码快。
将 base64 编码的字符串转换为密文字节数组。
从密文字节数组中取出初始化向量 iv 和实际的密文,创建一个新的解密器。
使用解密器对密文进行解密,得到明文。
对解密后的明文进行去除补全,得到原始明文。
具体来说,步骤3中,如果密文字节数组长度小于一个密码块大小(16个字节),则返回错误信息“ciphertext too short”。否则,取出密文中的前16个字节作为初始化向量 iv,将剩余的字节作为实际的密文。
在步骤4中,使用解密器对密文进行解密,得到明文。这里使用的是 CFB 模式的解密器,解密时采用密文反馈模式,将上一个密码块的密文作为下一个密码块的初始化向量 iv,解密时用当前密码块的密文 XOR 上一个密码块的密文,得到当前密码块的明文。
在步骤5中,首先获取解密后的明文的长度,然后取出最后一个字节的值,这个值表示填充的字节数。从明文中去掉填充的字节,得到原始明文。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值