Vì vậy, tôi đã đấu tranh với điều này một chút. Tôi đang cố gắng tạo thư viện AES 128 của riêng mình để sử dụng với một trong các chương trình của tôi. Các thư viện kiểm tra ra và các công trình trong C++ (tốt cho chức năng mã hóa .. Tôi đã không được thực hiện với những người khác) chức năng các 'Encrypt' là như thế này:Làm thế nào để trả về một mảng byte từ C++ thành C#
MỚI MÃ
void Aes128Class::EncryptBlock(BYTE* outBlock, const BYTE* inBlock, const BYTE* cipherBlock)
{
BYTE temp[16] = {0x00};
Galois::XorBlock(temp, inBlock);
Galois::XorBlock(temp, cipherBlock);
BYTE expandedKey[176] = {0x00};
memcpy(expandedKey, Key, 16);
Galois::expand_key(expandedKey);
Galois::XorBlock(temp, expandedKey);
for(int i=16; i<160; i+=16)
{
Galois::DoRound(temp, &expandedKey[i]);
}
Galois::SubBytes(temp);
Galois::ShiftRows(temp);
Galois::XorBlock(temp, &expandedKey[160]);
memcpy(outBlock, temp, 16);
}
void Aes128Class::EncryptData(BYTE* outBlock, size_t& outlen, const BYTE* inBlock, size_t length)
{
float blockSize = (float)(length/16);
blockSize = ceilf(blockSize);
int newLength = (int)(blockSize*16);
BYTE* temp = (BYTE*)malloc(newLength);
BYTE* padd = (BYTE*)malloc(newLength);
memset(temp, 0, newLength);
memcpy(padd, inBlock, length);
EncryptBlock(temp, padd, IV);
for (int i=1; i<blockSize; i++)
{
EncryptBlock(&temp[i*16], &padd[i*16], &temp[(i-1)*16]);
}
outlen = newLength;
memcpy(outBlock, temp, newLength);
}
Ý tưởng là nếu plainText
không nằm trong khối tăng 16 byte thì tôi buộc nó phải là. Vì vậy, điều này làm cho một mảng byte có kích thước biến. Nó hoạt động trong các thử nghiệm C++
của tôi, nhưng khi tôi gọi nó là C#
tôi nhận được một vài lỗi khác nhau ... Việc này sẽ mất một phút để mô tả.
[DllImport("CppAes128.dll", CallingConvention = CallingConvention.ThisCall,
EntryPoint = "[email protected]@@[email protected]")]
static extern void EncryptData(IntPtr pClass, ref IntPtr outblock, [Out]int OutLength, byte[] inBlock, int length);
Khi tôi gọi điều này, tôi sẽ nhận được con trỏ hợp lệ cho cả array
và độ dài. Cách nó trông ngay bây giờ gây ra một sự vi phạm truy cập, nhưng tôi có thể làm cho cấu trúc đó hoạt động nếu tôi thay đổi [Out]int OutLength
thành ref IntPtr
. Thật thú vị, nếu tôi làm ref int
hoặc ref uint
nó vẫn "hoạt động". Vì vậy, nếu tôi làm điều đó tôi cố gắng đọc intptr
và sau đó tôi nhận được một sự vi phạm truy cập. Tôi đang biên soạn điều này dưới dạng x86 project
trong .NET 4.0
(vì tôi đã đọc ở đâu đó có 3.5 lỗi có quyền truy cập ...)
Đây là những gì tôi đã thử trong C#
. Đó là một chút bị cắt xén như tôi đã chơi với nó trong nhiều giờ (xin lỗi):
public byte[] EncryptData(byte[] plainText, int length)
{
byte[] enc = null;
int len = 0;
IntPtr pArray = IntPtr.Zero;
EncryptData(theClass, ref pArray, len, plainText, length);
Console.WriteLine(len);
//enc = new byte[len];
//Marshal.Copy(pArray, enc, 0, len);
//Marshal.Release(pArray);
//try
//{
// int elementSize = Marshal.SizeOf(typeof(IntPtr));
// //IntPtr unmanagedArray = Marshal.AllocHGlobal(10 * elementSize);
// Console.WriteLine("Reading unmanaged memory:");
// // Print the 10 elements of the C-style unmanagedArray
// for (int i = 0; i < 10; i++)
// {
// Console.WriteLine("{0:X2}:", Marshal.ReadByte(pArray, i));
// }
// Marshal.FreeHGlobal(pArray);
//}
//catch (Exception ex)
//{
// Console.WriteLine("{0}\n{1}", ex.Source, ex.Message);
// Console.WriteLine("Win32({0})", Marshal.GetLastWin32Error());
//}
//Marshal.Release(pArray);
return enc;
}
Thời gian duy nhất làm việc này là khi tôi chỉ cần thực hiện một mảng tĩnh có kích thước và không sử dụng ref
hoặc marshal
bản sao hoặc bất cứ điều gì .. tôi nghĩ rằng chữ ký của tôi là một cái gì đó như thế này
static extern void EncryptData(IntPtr pClass, byte[] outBlock, byte[] inBlock, int length);
đó gần như làm việc, nhưng vấn đề là khi tôi đã làm một vòng lặp foreach
trên array
rằng đó là luôn kích thước mà tôi đặt .. bực bội để nói rằng ít nhất.
Vì vậy, tôi đang làm gì sai? làm thế nào tôi có thể có được điều này để làm việc? Tôi rất thất vọng với nó. Cảm ơn bạn
Oh và FYI, điều này là vì vậy tôi không thể phụ thuộc vào số cryptlib
nữa. Tôi đang cố gắng biên dịch lại một dự án khác, sử dụng cryptlib
, như một thư viện tĩnh và không được chia sẻ, điều này gây ra một số vấn đề với các tùy chọn đã biên soạn của tôi và quá phức tạp để thay đổi lại.
chỉnh sửa để hiển thị mã hơn
Đây là các bài kiểm tra mà tôi sử dụng. Tôi tìm thấy một trang web cho thấy một loạt các bài kiểm tra, vì vậy đây là tôi thực hiện điều này.
void VerifyEncrypt16(const BYTE* expected, const BYTE* key, const BYTE* iv, const BYTE* plainText)
{
BYTE actual[16] = {0x00};
Aes128Class aes;
aes.SetKey(key, 16);
aes.SetIV(iv, 16);
size_t len = 0;
aes.EncryptData(actual, len, plainText, 16);
_ASSERT(CompareTwoArrays(expected, actual));
}
void VerifyEncrypt16String(const char* expected, const char* key, const char* iv, const char* plainText)
{
BYTE e[16];
BYTE k[16];
BYTE i[16];
BYTE p[16];
ByteUtil::StringToHex(expected, e);
ByteUtil::StringToHex(key, k);
ByteUtil::StringToHex(iv, i);
ByteUtil::StringToHex(plainText, p);
VerifyEncrypt16(e, k, i, p);
}
void CheckEncrypt16(void)
{
_RPT0(_CRT_WARN, "Checking Encryption of a 16 byte number IV set to 0\n");
//AESVS GFSbox test data for CBC
VerifyEncrypt16String("0336763e966d92595a567cc9ce537f5e","00000000000000000000000000000000","00000000000000000000000000000000","f34481ec3cc627bacd5dc3fb08f273e6");
VerifyEncrypt16String("a9a1631bf4996954ebc093957b234589","00000000000000000000000000000000","00000000000000000000000000000000","9798c4640bad75c7c3227db910174e72");
VerifyEncrypt16String("ff4f8391a6a40ca5b25d23bedd44a597","00000000000000000000000000000000","00000000000000000000000000000000","96ab5c2ff612d9dfaae8c31f30c42168");
VerifyEncrypt16String("dc43be40be0e53712f7e2bf5ca707209","00000000000000000000000000000000","00000000000000000000000000000000","6a118a874519e64e9963798a503f1d35");
VerifyEncrypt16String("92beedab1895a94faa69b632e5cc47ce","00000000000000000000000000000000","00000000000000000000000000000000","cb9fceec81286ca3e989bd979b0cb284");
VerifyEncrypt16String("459264f4798f6a78bacb89c15ed3d601","00000000000000000000000000000000","00000000000000000000000000000000","b26aeb1874e47ca8358ff22378f09144");
VerifyEncrypt16String("08a4e2efec8a8e3312ca7460b9040bbf","00000000000000000000000000000000","00000000000000000000000000000000","58c8e00b2631686d54eab84b91f0aca1");
//AESVS KeySbox test data for CBC
VerifyEncrypt16String("6d251e6944b051e04eaa6fb4dbf78465","10a58869d74be5a374cf867cfb473859","00000000000000000000000000000000","00000000000000000000000000000000");
//A TON OF MORE TESTS! etc etc etc VerifyEncrypt16String("5c005e72c1418c44f569f2ea33ba54f3","00000000000000000000000000000000","00000000000000000000000000000000","fffffffffffffffffffffffffffffffe");
VerifyEncrypt16String("3f5b8cc9ea855a0afa7347d23e8d664e","00000000000000000000000000000000","00000000000000000000000000000000","ffffffffffffffffffffffffffffffff");
}
Check-out này [trả lời] (http://stackoverflow.com/a/13123962/175157) . Tóm lại, C# không thể biết bạn đã cấp phát bao nhiêu bộ nhớ trong mã C++. – Alex
Tôi không chắc mục tiêu cuối cùng của bạn là gì nhưng tôi chỉ muốn chỉ ra rằng C# bao gồm một số lớp mã hóa tuyệt vời trong [System.Security.Cryptography Namespace] (http://msdn.microsoft.com/en-us /library/system.security.cryptography.aspx) hoạt động tốt. –
Điểm bắt đầu cần thiết cho interop với mã C++ là bạn * bắt đầu * với mã C++ có thể được gọi một cách an toàn từ mã C++ khác. Bạn chưa có, bạn đang bị rò rỉ bộ nhớ nặng và một người gọi C++ sẽ không có bất kỳ đoán ở kích thước bộ đệm cần thiết hoặc. Những vấn đề này không tốt hơn khi bạn thực hiện cuộc gọi từ C#. –