首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何将rijndaelManaged函数从C#重写而去?

如何将rijndaelManaged函数从C#重写而去?
EN

Stack Overflow用户
提问于 2021-09-11 20:46:25
回答 1查看 297关注 0票数 0

可能只是我犯了一个我看不见的小错误。也许其他人看过这件事,就会发现我做错了什么。

这是C#中的函数,我试图用Go重写它,目的是在调用函数时输出相同的值。

代码语言:javascript
复制
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);
}

您可以使用以下方法将其称为:

代码语言:javascript
复制
NewEncrypt("{\"randJsonList\":[ \"abc\" ], \"name\":\"baron\", \"support\":\"king\"}")

我们有这个返回输出(myArray):

代码语言:javascript
复制
DdSUyoYRYW/zDNSVaA1JZ39WqJt06qp0FiJUlCW5BbZWEt41GzsmtgVnGZuHigZNs7qKhI+kHAKMXL8EPnK1vg==

现在,对于Go实现(我试图使用GitHub资源:https://gist.github.com/huyinghuan/7bf174017bf54efb91ece04a48589b22):

您可能注意到的第一件事是,我不知道在哪里可以使用全局IV变量,每次运行这段代码时,都会显示不同的输出。我希望输出与C#中相同的结果,除非修改了输入字符串

代码语言:javascript
复制
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#不同):

代码语言:javascript
复制
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=
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 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#代码相同:

  • 必须应用Rijndael而不是AES。在下面的示例中,将使用pkg.go.dev/github.com/azihsoyn/rijndael256 256。为此,导入"github.com/azihsoyn/rijndael256"并将aes正式替换为rijndael256。当然,您可以应用另一个实现。
  • 静态IV将被应用:bm := cipher.NewCBCEncrypter(block, IV)iv及其填充将与相关导入一起删除。
  • enecrypt()-method:return ciphertext[rijndael256.BlockSize:]中只返回密文。

下面的Go代码给出了C#代码的结果:

代码语言:javascript
复制
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)
}

产出:

代码语言:javascript
复制
DdSUyoYRYW/zDNSVaA1JZ39WqJt06qp0FiJUlCW5BbZWEt41GzsmtgVnGZuHigZNs7qKhI+kHAKMXL8EPnK1vg==

等于C#代码的值。

票数 4
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/69146596

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档