【发布时间】:2021-09-11 20:46:25
【问题描述】:
我可能只是犯了一个我看不到的小错误。也许其他人在看这个可以弄清楚我做错了什么。
这是C# 中的函数,我试图在Go 中重写,目标是在调用函数时输出相同的值。
public static string NewEncrypt(string Input)
{
RijndaelManaged rijndaelManaged = new RijndaelManaged();
rijndaelManaged.KeySize = 256;
rijndaelManaged.BlockSize = 256;
rijndaelManaged.Padding = PaddingMode.PKCS7;
rijndaelManaged.Key = Convert.FromBase64String(Convert.ToBase64String(Encoding.UTF8.GetBytes("095fc90fe8b18e8f243e4b07a9c0d170")));
rijndaelManaged.IV = Convert.FromBase64String(Convert.ToBase64String(Encoding.UTF8.GetBytes("8bef55a546d27958ead1fdddba4d36ea")));
ICryptoTransform transform = rijndaelManaged.CreateEncryptor(rijndaelManaged.Key, rijndaelManaged.IV);
byte[] myArray = null;
using (MemoryStream memoryStream = new MemoryStream())
{
using (CryptoStream cryptoStream = new CryptoStream(memoryStream, transform, CryptoStreamMode.Write))
{
byte[] bytes = Encoding.UTF8.GetBytes(Input);
cryptoStream.Write(bytes, 0, bytes.Length);
}
myArray = memoryStream.ToArray();
}
return Convert.ToBase64String(myArray);
}
您可以使用以下方式调用它:
NewEncrypt("{\"randJsonList\":[ \"abc\" ], \"name\":\"baron\", \"support\":\"king\"}")
我们有这个返回输出(myArray):
DdSUyoYRYW/zDNSVaA1JZ39WqJt06qp0FiJUlCW5BbZWEt41GzsmtgVnGZuHigZNs7qKhI+kHAKMXL8EPnK1vg==
现在我的 Go 实现(我试图利用 GitHub 资源:https://gist.github.com/huyinghuan/7bf174017bf54efb91ece04a48589b22):
您可能会注意到的第一件事是,我不知道在哪里可以使用全局 IV 变量,每次运行此代码时,您都会看到不同的输出。我想输出与 C# 相同的结果,除非输入字符串被修改
package main
import (
"bytes"
"crypto/aes"
"crypto/cipher"
"crypto/rand"
"encoding/base64"
"errors"
"fmt"
"io"
)
var KEY = []byte("095fc90fe8b18e8f243e4b07a9c0d170")
var IV = []byte("8bef55a546d27958ead1fdddba4d36ea")
func encrypt(myInput string) []byte {
plaintext := []byte(myInput)
// Create the AES cipher
block, err := aes.NewCipher(KEY)
if err != nil {
panic(err)
}
plaintext, _ = pkcs7Pad(plaintext, block.BlockSize())
// The IV needs to be unique, but not secure. Therefore it's common to
// include it at the beginning of the ciphertext.
ciphertext := make([]byte, aes.BlockSize+len(plaintext))
iv := ciphertext[:aes.BlockSize]
if _, err := io.ReadFull(rand.Reader, iv); err != nil {
panic(err)
}
bm := cipher.NewCBCEncrypter(block, iv)
bm.CryptBlocks(ciphertext[aes.BlockSize:], plaintext)
//stream := cipher.NewCFBEncrypter(block, iv)
//stream.XORKeyStream(ciphertext[aes.BlockSize:], plaintext)
return ciphertext
}
// pkcs7Pad right-pads the given byte slice with 1 to n bytes, where
// n is the block size. The size of the result is x times n, where x
// is at least 1.
func pkcs7Pad(b []byte, blocksize int) ([]byte, error) {
if blocksize <= 0 {
return nil, errors.New("invalid blocksize")
}
if b == nil || len(b) == 0 {
return nil, errors.New("invalid PKCS7 data (empty or not padded)")
}
n := blocksize - (len(b) % blocksize)
pb := make([]byte, len(b)+n)
copy(pb, b)
copy(pb[len(b):], bytes.Repeat([]byte{byte(n)}, n))
return pb, nil
}
func main() {
plainText := "{\"randJsonList\":[ \"abc\" ], \"name\":\"baron\", \"support\":\"king\"}"
x := encrypt(plainText)
outputString := base64.StdEncoding.EncodeToString(x)
fmt.Println(outputString)
}
示例输出(与 C# 不同):
PS D:\Software\Git\repositories\tet> go run .\main.go
N+hm5TItq367eXAz+WbtKXhhhMAy4woEKSngTf6rGUt8GZce7LsUxaqNtheceGDZ2dK8Bx187x87NeRPC1UQ6lUokjy7t1MLU8NcCtjODCM=
PS D:\Software\Git\repositories\tet> go run .\main.go
OT/CngTVs2O4BR4czjvR3MLVPoKFH2dUtW8LsIDUgLXfikJrRKsvKGaf0JFe39Cwf1/00HP7mvmCure7+IO+vupzAtdLX6nTQt1KZGsNp4o=
PS D:\Software\Git\repositories\tet> go run .\main.go
yDRHxWTvjX4HnSW8jbao+0Mhf77zgRj9tKXA3MNtAoF1I3bRou5Sv4Ds+r0HRuiA7NkoBR57m4aCYcU6quYzQA3R0GCGB8TGUfrWS5PvMNU=
【问题讨论】:
-
只是我的 2 个注释:您的 C# 代码使用 Rijndael 算法,选择的块长度为 256 位 = 32 字节。您在链接的 Go 代码中使用的 AES 算法的块长度为 128 位 = 16 字节,因此您需要找到支持 256 位/32 字节块长度的 Go 实现。第二:在您的 C# 代码中,您使用的是 static IV,它使您的完全加密 unsecure,所以我的建议是使用随机生成的 IV 并将其与密文发送给收件人进行解密。
-
C# 代码没有进行十六进制解码。不要那样做。此外,如果您希望它以与 C# 代码相同的方式工作,您应该将
IV传递给cipher.NewCBCEncrypter(block, iv)而不是iv。 -
@Brannon 当您以这种方式指定 IV 时,控制台会出现以下错误:
panic: cipher.NewCBCEncrypter: IV length must equal block size。我相信这就是 Michael 提到的,因为 Go 实现是 128bit/16byte,所以它不会起作用。此外,对于这种情况,我想使用静态 IV。那么,到底..不使用十六进制解码?获得一些示例会很棒,但我会尝试找到另一个 256bit/32byte 的 go 实现。
标签: c# go encryption