CSharp 中的加密代码类似于 Go 中的代码(AES、CFB、XorKeyStream)

本文关键字:代码 CFB AES XorKeyStream Go 加密 类似于 CSharp | 更新日期: 2023-09-27 18:36:35

我在 Go 中有加密代码,但我在 CSharp 中很难找到类似的代码。我正在讨论如何实现自己的XorKeyStream,但我被告知,如果我编写自己的加密代码,就会有法律问题。我相信CSharp中一定有类似的代码。

package main
import (
    "crypto/aes"
    "crypto/cipher"
    "fmt"
)
func main() {
    k1 := []byte("0123456789abcdef")
    r1 := []byte("1234567890abcdef")
    data := []byte("0123456789")
    fmt.Printf("original %x %s'n", data, string(data))
    {
        block, _ := aes.NewCipher(k1)
        stream := cipher.NewCFBEncrypter(block, r1)
        stream.XORKeyStream(data, data)
        fmt.Printf("crypted %x'n", data)
    }
    {
        block, _ := aes.NewCipher(k1)
        stream := cipher.NewCFBDecrypter(block, r1)
        stream.XORKeyStream(data, data)
        fmt.Printf("decrypted %x %s'n", data, string(data))
    }
}

http://play.golang.org/p/EnJ56dYX_-

输出

original 30313233343536373839 0123456789
crypted 762b6dcea9c2a7460db7
decrypted 30313233343536373839 0123456789

附言有些人将该问题标记为问题的可能重复:"C# AES:加密文件导致"要加密的数据长度无效"错误"我在 CSharp 中为现有的 Go 代码寻找相同的代码。这个问题是关于填充的。此算法需要"密钥流"来异或文本。这是不同的问题。

CSharp 中的加密代码类似于 Go 中的代码(AES、CFB、XorKeyStream)

这是你的代码

using System;
using System.Text;
using System.Security.Cryptography;
using System.IO;
class AES_CFB_XorKeyStream
{
    static void Main(string[] args)
    {
        byte[] data = Encoding.UTF8.GetBytes("0123456789");
        byte [] k1 = Encoding.UTF8.GetBytes("0123456789abcdef");
        byte [] r1 = Encoding.UTF8.GetBytes("1234567890abcdef");
        Console.WriteLine("original " + BitConverter.ToString(data));
        using (RijndaelManaged Aes128 = new RijndaelManaged())
        {
            Aes128.BlockSize = 128;
            Aes128.KeySize = 128;
            Aes128.Mode = CipherMode.CFB;
            Aes128.FeedbackSize = 128;
            Aes128.Padding = PaddingMode.None;
            Aes128.Key = k1;
            Aes128.IV = r1;
            using (var encryptor = Aes128.CreateEncryptor())
            using (var msEncrypt = new MemoryStream())
            using (var csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write))
            using (var bw = new BinaryWriter(csEncrypt, Encoding.UTF8))
            {
                bw.Write(data);
                bw.Close();
                data = msEncrypt.ToArray();
                Console.WriteLine("crypted " + BitConverter.ToString(data));
            }
        }
        using (RijndaelManaged Aes128 = new RijndaelManaged())
        {
            Aes128.BlockSize = 128;
            Aes128.KeySize = 128;
            Aes128.Mode = CipherMode.CFB;
            Aes128.FeedbackSize = 128;
            Aes128.Padding = PaddingMode.None;
            Aes128.Key = k1;
            Aes128.IV = r1;
            using (var decryptor = Aes128.CreateDecryptor())
            using (var msEncrypt = new MemoryStream())
            using (var csEncrypt = new CryptoStream(msEncrypt, decryptor, CryptoStreamMode.Write))
            using (var bw = new BinaryWriter(csEncrypt, Encoding.UTF8))
            {
                bw.Write(data);
                bw.Close();
                data = msEncrypt.ToArray();
                Console.WriteLine("decrypted " + BitConverter.ToString(data));
            }
        }
    }
}

输出

original 30-31-32-33-34-35-36-37-38-39
crypted 76-2B-6D-CE-A9-C2-A7-46-0D-B7
decrypted 30-31-32-33-34-35-36-37-38-39

我遇到了完全相同的问题,每个解密块的第一个字节是正确的,但我无法在 Go 程序上更改源代码。

我最终实现了自己的填充。只需用 0 字节填充加密字节,使其可被块大小 128 整除,然后在运行解密例程后,将该字节数从末尾砍掉。

示例代码:

using System;
using System.Text;
using System.Security.Cryptography;
using System.Linq;
public static class Program
{
    static RijndaelManaged aes = new RijndaelManaged(){
        Mode = CipherMode.CFB,
        BlockSize = 128,
        KeySize = 128,
        FeedbackSize = 128,
        Padding = PaddingMode.None
    };
    public static void Main(){
        byte[] key = Encoding.UTF8.GetBytes("0123456789abcdef");
        byte[] iv = Encoding.UTF8.GetBytes("1234567890abcdef");
        byte[] encryptedBytes = new byte[]{0x76, 0x2b, 0x6d, 0xce, 0xa9, 0xc2, 0xa7, 0x46, 0x0d, 0xb7};
        // Custom pad the bytes
        int padded;
        encryptedBytes = PadBytes(encryptedBytes, aes.BlockSize, out padded);
        // Decrypt bytes
        byte[] decryptedBytes = DecryptBytesAES(encryptedBytes, key, iv, encryptedBytes.Length);
        // Check for successful decrypt
        if(decryptedBytes != null){
            // Unpad
            decryptedBytes = UnpadBytes(decryptedBytes, padded);
            Console.Write("Decrypted: " + Encoding.UTF8.GetString(decryptedBytes));
        }
    }
    // Just an elegant way of initializing an array with bytes
    public static byte[] Initialize(this byte[] array, byte value, int length)
    {
        for (int i = 0; i < array.Length; i++)
        {
            array[i] = value;
        }
        return array;
    }
    // Custom padding to get around the issue of how Go uses CFB mode without padding differently than C#
    public static byte[] PadBytes(byte[] encryptedBytes, int blockSize, out int numPadded)
    {
        numPadded = 0;
        // Check modulus of block size
        int mod = encryptedBytes.Length % blockSize;
        if (mod != 0)
        {
            // Calculate number to pad
            numPadded = blockSize - mod;
            // Build array
            return encryptedBytes.Concat(new byte[numPadded].Initialize(0, numPadded)).ToArray();
        }
        else {
            // No padding needed
            return encryptedBytes;
        }
    }
    public static byte[] UnpadBytes(byte[] decryptedBytes, int numPadded)
    {
        if(numPadded != 0)
        {
            byte[] unpaddedBytes = new byte[decryptedBytes.Length - numPadded];
            Array.Copy(decryptedBytes, unpaddedBytes, unpaddedBytes.Length);
            return unpaddedBytes;
        }
        else
        {
            return decryptedBytes;
        }
    }
    public static byte[] DecryptBytesAES(byte[] cipherText, byte[] Key, byte[] IV, int size)
    {
        byte[] array = new byte[size];
        try{
            aes.Key = Key;
            aes.IV = IV;
            ICryptoTransform transform = aes.CreateDecryptor(aes.Key, aes.IV);
            using (System.IO.MemoryStream memoryStream = new System.IO.MemoryStream(cipherText))
            {
                using (CryptoStream cryptoStream = new CryptoStream(memoryStream, transform, CryptoStreamMode.Read))
                {
                    cryptoStream.Read(array, 0, size);
                }
            }
        }
        catch(Exception e){
            return null;
        }
        return array;
    }
}

.NET 小提琴:https://dotnetfiddle.net/NPHKN3