首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >go AES加密CBC

go AES加密CBC
EN

Stack Overflow用户
提问于 2021-03-11 13:00:39
回答 1查看 2K关注 0票数 2

问题

我必须将一个函数从C#移植到使用AES加密的GO。显然,我必须在GO中得到与C#相同的结果。

C

代码小提琴

我用C#做了一个小C#

代码语言:javascript
复制
using System;
using System.Linq;
using System.Security.Cryptography;
using System.Text;

public class Program
{
    public static void Main()
    {
        var query = "csharp -> golang";
        var key = Encoding.UTF8.GetBytes("12345678901234567890123456789012");
        var iv = Encoding.UTF8.GetBytes("1234567890123456");
        using (var aes = (RijndaelManaged)RijndaelManaged.Create())
        {
            aes.KeySize = 256;
            aes.Mode = CipherMode.CBC;
            aes.Key = key;
            aes.IV = iv;
            using (var transform = aes.CreateEncryptor())
            {
                Console.WriteLine("query => " + query);
                var toEncodeByte = Encoding.UTF8.GetBytes(query);
                Console.WriteLine("toEncodeByte = " + ToString(toEncodeByte));
                var encrypted = transform.TransformFinalBlock(toEncodeByte, 0, toEncodeByte.Length);
                Console.WriteLine("encrypted = " + ToString(encrypted));
            }
        }
    }

    public static string ToString(byte[] b)
    {
        return "[" + String.Join(" ", b.Select(h => h.ToString())) + "]";
    }
}

控制台输出

代码语言:javascript
复制
query => csharp -> golang
toEncodeByte = [99 115 104 97 114 112 32 45 62 32 103 111 108 97 110 103]
encrypted = [110 150 8 224 44 118 15 182 248 172 105 14 61 212 219 205 216 31 76 112 179 76 214 154 227 112 159 176 24 61 108 100]

代码小提琴

我准备了一个小小提琴 GO

代码语言:javascript
复制
package main

import (
    "bytes"
    "crypto/aes"
    "crypto/cipher"
    "encoding/hex"
    "fmt"
)

func main() {
    query := "csharp -> golang"
    key := []byte("12345678901234567890123456789012")
    iv := []byte("1234567890123456")

    if len(key) != 32 {
        fmt.Printf("key len must be 16. its: %v\n", len(key))
    }
    if len(iv) != 16 {
        fmt.Printf("IV len must be 16. its: %v\n", len(iv))
    }
    var encrypted string
    toEncodeByte := []byte(query)
    fmt.Println("query =>", query)
    fmt.Println("toEncodeByte = ", toEncodeByte)
    toEncodeBytePadded := PKCS5Padding(toEncodeByte, len(key))

    // aes
    block, err := aes.NewCipher(key)
    if err != nil {
        fmt.Println("CBC Enctryping failed.")
    }
    ciphertext := make([]byte, len(toEncodeBytePadded))
    mode := cipher.NewCBCEncrypter(block, iv)
    mode.CryptBlocks(ciphertext, toEncodeBytePadded)
    encrypted = hex.EncodeToString(ciphertext)
    // end of aes
    fmt.Println("encrypted", []byte(encrypted))
}

func PKCS5Padding(ciphertext []byte, blockSize int) []byte {
    padding := (blockSize - len(ciphertext)%blockSize)
    padtext := bytes.Repeat([]byte{byte(padding)}, padding)
    return append(ciphertext, padtext...)
}

控制台输出

代码语言:javascript
复制
query => csharp -> golang
toEncodeByte =  [99 115 104 97 114 112 32 45 62 32 103 111 108 97 110 103]
encrypted [54 101 57 54 48 56 101 48 50 99 55 54 48 102 98 54 102 56 97 99 54 57 48 101 51 100 100 52 100 98 99 100 100 56 49 102 52 99 55 48 98 51 52 99 100 54 57 97 101 51 55 48 57 102 98 48 49 56 51 100 54 99 54 52]

摘要

我注意到,在C#中,输入不必与block大小相同。

GO中,这似乎没有填充(因此我在GO代码中添加了填充),但结果是不同的。

获得equal结果的解决方案将是很棒的

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2021-03-11 17:14:52

首先,这两种密码的密文是相同的。但是,Golang码中的密文被错误地转换。

在C#代码中,byte[]的内容以十进制格式打印。要在Golang代码中获得等效的输出,还必须以十进制格式打印[]byte的内容,这很容易通过以下方法实现:

代码语言:javascript
复制
fmt.Println("ciphertext ", ciphertext)

并产生以下输出:

代码语言:javascript
复制
ciphertext  [110 150 8 224 44 118 15 182 248 172 105 14 61 212 219 205 216 31 76 112 179 76 214 154 227 112 159 176 24 61 108 100]

并与C#代码的输出相同。

在当前代码中,密文首先用以下代码编码:

代码语言:javascript
复制
encrypted = hex.EncodeToString(ciphertext)

转换为十六进制字符串,该字符串很容易用以下方法验证:

代码语言:javascript
复制
fmt.Println("encrypted (hex)", encrypted)

产生下列产出:

代码语言:javascript
复制
encrypted (hex) 6e9608e02c760fb6f8ac690e3dd4dbcdd81f4c70b34cd69ae3709fb0183d6c64

当使用[]byte(encrypted)将十六进制字符串转换为[]byte(encrypted)时,会发生Utf8编码,这会使数据的大小翻倍,因为输出的内容如下:

代码语言:javascript
复制
fmt.Println("encrypted", []byte(encrypted))

在当前代码中显示:

代码语言:javascript
复制
encrypted [54 101 57 54 48 56 101 48 50 99 55 54 48 102 98 54 102 56 97 99 54 57 48 101 51 100 100 52 100 98 99 100 100 56 49 102 52 99 55 48 98 51 52 99 100 54 57 97 101 51 55 48 57 102 98 48 49 56 51 100 54 99 54 52]

CBC是一种分组密码模式,即明文长度必须是块大小的整数倍(AES为16字节)。如果不是这样,则必须应用填充。C#代码隐式使用PKCS7填充。这就是为什么不符合长度条件的明文也被处理的原因。

相反,在Golang代码中,填充必须显式执行,这是通过PKCS5Padding()方法完成的,该方法实现了PKCS7填充。PKCS5Padding()方法的第二个参数是块大小,对于AES来说是16个字节。对于这个参数,实际上应该传递aes.BlockSize。目前,len(key)被传递到这里,它的大小为AES-256的32字节.尽管这与当前明文长度的C#代码兼容,但它不兼容任意明文长度(例如32个字节)。

以下代码包含上述更改和输出:

代码语言:javascript
复制
package main

import (
    "bytes"
    "crypto/aes"
    "crypto/cipher"
    "encoding/hex"
    "fmt"
)

func main() {
    query := "csharp -> golang"
    key := []byte("12345678901234567890123456789012")
    iv := []byte("1234567890123456")

    if len(key) != 32 {
        fmt.Printf("key len must be 16. its: %v\n", len(key))
    }
    if len(iv) != 16 {
        fmt.Printf("IV len must be 16. its: %v\n", len(iv))
    }
    var encrypted string
    toEncodeByte := []byte(query)
    fmt.Println("query =>", query)
    fmt.Println("toEncodeByte = ", toEncodeByte)
    toEncodeBytePadded := PKCS5Padding(toEncodeByte, aes.BlockSize)

    // aes
    block, err := aes.NewCipher(key)
    if err != nil {
        fmt.Println("CBC Enctryping failed.")
    }
    ciphertext := make([]byte, len(toEncodeBytePadded))
    mode := cipher.NewCBCEncrypter(block, iv)
    mode.CryptBlocks(ciphertext, toEncodeBytePadded)
    encrypted = hex.EncodeToString(ciphertext)
    // end of aes
    fmt.Println("encrypted", []byte(encrypted))
    fmt.Println("encrypted (hex)", encrypted)
    fmt.Println("ciphertext", ciphertext)
    fmt.Println("aes.BlockSize", aes.BlockSize)
}

func PKCS5Padding(ciphertext []byte, blockSize int) []byte {
    padding := (blockSize - len(ciphertext)%blockSize)
    padtext := bytes.Repeat([]byte{byte(padding)}, padding)
    return append(ciphertext, padtext...)
}
票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/66583084

复制
相关文章

相似问题

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