可能只是我犯了一个我看不见的小错误。也许其他人看过这件事,就会发现我做错了什么。
这是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=发布于 2021-09-12 08:05:25
C#代码使用块大小为256位的Rijndael (参见注释)、静态的IV (参见注释),并且只返回密文(即不带前缀IV)。
根据定义,Go代码应用AES,其块大小为128位,随机生成的IV (忽略代码中的静态IV )并返回IV和密文的级联。
AES是Rijndael的子集。Rijndael在32位步骤中定义了128到256位之间的不同块大小和密钥大小,参见这里。对于AES,只定义块大小128位,密钥大小128、192和256位。请注意,标准是AES而不是Rijndael,所以应该首选AES而不是Rijndael (许多库甚至不实现Rijndael,而是AES )。
静态IV是不安全的。由于安全原因,不能重复密钥/IV对。因此,通常使用固定密钥,为每个加密生成一个随机IV。IV不是秘密的,并与密文一起传递到解密端,通常以IV#密文顺序连接。
因此,当前的Go代码是一个安全的实现(更安全的是通过GCM进行身份验证的加密),而C#代码则不是。因此,将C#代码修改为功能等效于Go代码就更有意义了。
但是,由于C#代码似乎是引用,因此需要对Go代码进行以下更改,使其在功能上与C#代码相同:
"github.com/azihsoyn/rijndael256"并将aes正式替换为rijndael256。当然,您可以应用另一个实现。bm := cipher.NewCBCEncrypter(block, IV)。iv及其填充将与相关导入一起删除。enecrypt()-method:return ciphertext[rijndael256.BlockSize:]中只返回密文。下面的Go代码给出了C#代码的结果:
package main
import (
"bytes"
"github.com/azihsoyn/rijndael256"
"crypto/cipher"
"encoding/base64"
"errors"
"fmt"
)
var KEY = []byte("095fc90fe8b18e8f243e4b07a9c0d170")
var IV = []byte("8bef55a546d27958ead1fdddba4d36ea")
func encrypt(myInput string) []byte {
plaintext := []byte(myInput)
// Create the AES cipher
block, err := rijndael256.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, rijndael256.BlockSize+len(plaintext))
bm := cipher.NewCBCEncrypter(block, IV)
bm.CryptBlocks(ciphertext[rijndael256.BlockSize:], plaintext)
return ciphertext[rijndael256.BlockSize:]
}
// 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)
}产出:
DdSUyoYRYW/zDNSVaA1JZ39WqJt06qp0FiJUlCW5BbZWEt41GzsmtgVnGZuHigZNs7qKhI+kHAKMXL8EPnK1vg==等于C#代码的值。
https://stackoverflow.com/questions/69146596
复制相似问题