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

时间:2016-02-26 17:35:49

标签: c# go cryptography aes

我在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

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

2 个答案:

答案 0 :(得分:3)

这是您的代码

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

答案 1 :(得分:3)

我有完全相同的问题,只有每个解密块的第一个字节是正确的,但我没有能够在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