加密算法,使用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中,首先获取解密后的明文的长度,然后取出最后一个字节的值,这个值表示填充的字节数。从明文中去掉填充的字节,得到原始明文。