英文:
Cryptographic code in CSharp similar to code in Go (AES,CFB,XorKeyStream)
问题
我在Go语言中有一段加密代码,但是我找不到类似的C#代码。我正在考虑自己实现XorKeyStream,但有人告诉我,如果我编写自己的加密代码,可能会涉及到法律问题。我相信在C#中一定有类似的代码。
以下是要翻译的代码:
using System;
using System.Security.Cryptography;
class Program
{
static void Main()
{
byte[] k1 = { 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66 };
byte[] r1 = { 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x30, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66 };
byte[] data = { 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39 };
Console.WriteLine("original {0} {1}", BitConverter.ToString(data).Replace("-", ""), System.Text.Encoding.ASCII.GetString(data));
using (Aes aes = Aes.Create())
{
aes.Key = k1;
aes.IV = r1;
using (ICryptoTransform encryptor = aes.CreateEncryptor())
{
encryptor.TransformBlock(data, 0, data.Length, data, 0);
Console.WriteLine("crypted {0}", BitConverter.ToString(data).Replace("-", ""));
}
using (ICryptoTransform decryptor = aes.CreateDecryptor())
{
decryptor.TransformBlock(data, 0, data.Length, data, 0);
Console.WriteLine("decrypted {0} {1}", BitConverter.ToString(data).Replace("-", ""), System.Text.Encoding.ASCII.GetString(data));
}
}
}
}
你可以在这里运行代码:http://play.golang.org/p/EnJ56dYX_-
输出结果
original 30313233343536373839 0123456789
crypted 762B6DCEA9C2A7460DB7
decrypted 30313233343536373839 0123456789
备注
有些人将这个问题标记为可能是重复问题:“C# AES: Encrypt a file causes “Length of the data to encrypt is invalid.” error”。
我正在寻找与Go中现有代码相同的C#代码。那个问题是关于填充的。这个算法需要进行异或的“密钥流”。
这是不同的问题。
英文:
I have cryptographic code in Go but I can't hard find similar code in CSharp.
I am debating to make my own implementation of XorKeyStream but I am told that there is legal issue if I write my own cryptographic code. I am sure there must be similar code in 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_-
output
original 30313233343536373839 0123456789
crypted 762b6dcea9c2a7460db7
decrypted 30313233343536373839 0123456789
PS
Some people marked that question as possible duplicate of question: "C# AES: Encrypt a file causes “Length of the data to encrypt is invalid.” error"
I look for identical code in CSharp for existing code in Go. That question is about padding. This algorithm needs "Key stream" that will xor text.
It is different questions.
答案1
得分: 4
以下是代码的翻译:
这是你的代码
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("原始数据 " + 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("加密后的数据 " + 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("解密后的数据 " + BitConverter.ToString(data));
}
}
}
}
__输出__
原始数据 30-31-32-33-34-35-36-37-38-39
加密后的数据 76-2B-6D-CE-A9-C2-A7-46-0D-B7
解密后的数据 30-31-32-33-34-35-36-37-38-39
希望对你有帮助!
英文:
Here is your code
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));
}
}
}
}
output
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
答案2
得分: 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};
// 自定义填充字节
int padded;
encryptedBytes = PadBytes(encryptedBytes, aes.BlockSize, out padded);
// 解密字节
byte[] decryptedBytes = DecryptBytesAES(encryptedBytes, key, iv, encryptedBytes.Length);
// 检查解密是否成功
if(decryptedBytes != null){
// 取消填充
decryptedBytes = UnpadBytes(decryptedBytes, padded);
Console.Write("Decrypted: " + Encoding.UTF8.GetString(decryptedBytes));
}
}
// 用字节初始化数组的优雅方式
public static byte[] Initialize(this byte[] array, byte value, int length)
{
for (int i = 0; i < array.Length; i++)
{
array[i] = value;
}
return array;
}
// 自定义填充以解决Go在不使用填充的情况下以不同于C#的方式使用CFB模式的问题
public static byte[] PadBytes(byte[] encryptedBytes, int blockSize, out int numPadded)
{
numPadded = 0;
// 检查块大小的模数
int mod = encryptedBytes.Length % blockSize;
if (mod != 0)
{
// 计算需要填充的数量
numPadded = blockSize - mod;
// 构建数组
return encryptedBytes.Concat(new byte[numPadded].Initialize(0, numPadded)).ToArray();
}
else {
// 不需要填充
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 Fiddle: https://dotnetfiddle.net/NPHKN3
英文:
I had this exact same issue with only the first byte of each decrypted block being correct, but I did not have the luxury of being able to change source on the Go program.
I ended up implementing my own padding. Just pad the encrypted bytes with 0 bytes to make it divisible by the block size of 128, then after running through the decryption routine, chop that number of bytes off the end.
Example code:
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 Fiddle: https://dotnetfiddle.net/NPHKN3
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论