我如何返回从C ++字节数组C# [英] How do I return a byte array from C++ to C#

查看:206
本文介绍了我如何返回从C ++字节数组C#的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

所以,我一直在挣扎了这一点。我试图使自己的AES 128库,我的项目之一使用。图书馆测试出来,用C ++工作(以及对加密功能的..我还没有实现别人)加密功能是这样的:



新代码

 无效Aes128Class :: EncryptBlock(BYTE * outBlock,常量BYTE * inBlock,常量BYTE *密文分组)
{
字节的临时[16] = {0×00};
伽罗瓦:: XorBlock(温度,inBlock);
伽罗瓦:: XorBlock(温度,密文分组);

字节expandedKey [176] = {0×00};
的memcpy(expandedKey,钥匙,16);
伽罗瓦:: expand_key(expandedKey);

伽罗瓦:: XorBlock(温度,expandedKey);
的for(int i = 16; I< 160; I + = 16)
{
伽罗瓦:: DoRound(温度,和放大器; expandedKey [I]);
}
伽罗瓦:: SubBytes(TEMP);
伽罗:: ShiftRows(临时);
伽罗瓦:: XorBlock(温度,和放大器; expandedKey [160]);

的memcpy(outBlock,温度,16);
}
无效Aes128Class :: EncryptData(BYTE * outBlock,为size_t和放大器; outlen,常量BYTE * inBlock,为size_t长度)
{
浮动块大小=(浮点)(长/ 16 );
块大小= ceilf(块大小);
INT满足newLength =(INT)(块大小* 16);
BYTE * TEMP =(BYTE *)malloc的(满足newLength);
BYTE * PADD =(BYTE *)malloc的(满足newLength);
memset的(温度,0,满足newLength);
的memcpy(PADD,inBlock,长度);
EncryptBlock(温度,PADD,IV);
的for(int i = 1; I<块大小,我++)
{
EncryptBlock(安培;临时[I * 16],&安培; PADD [I * 16],&安培;温度[ (ⅰ-1)* 16]);
}
outlen =满足newLength;
的memcpy(outBlock,温度,满足newLength);
}



的想法是,如果在明文不是一个16字节的块增量然后我强迫它是。因此,这使得一个可变大小的字节数组。它工作在我的 C ++ 测试,但是当我把它在 C#我得到一些不同的错误......这将采取一分钟来形容。

 函数[DllImport(CppAes128.dll,CallingConvention = CallingConvention.ThisCall,
入口点=)]
静态外部无效EncryptData(IntPtr的pClass,楼盘的IntPtr outblock,[OUT] INT OutLength,字节[] inBlock,INT长度)EncryptData @ Aes128Class @@ QAEXPAEAAIPBEI @ Z?

当我把这个我得到有效的指针均阵列和outlength。它看起来现在的方式会导致访问冲突,但我可以得到结构工作,如果我改变 [OUT] INT OutLength REF的IntPtr 。有趣的是,如果我做 REF INT REF UINT 它仍然工程。所以,如果我这样做,我尝试阅读的IntPtr ,然后我得到一个访问冲突。我编写本作中 86项目 .NET 4.0 (因为我读的地方,有3.5一些错误的访问...)



下面是我在 C#已经试过。这是一个有点乱码,因为我一直在玩好几个小时了(对不起):

 公共字节[] EncryptData(字节[ ]明文,INT长度)
{
的byte [] ENC = NULL;
INT LEN = 0;
IntPtr的粒子阵列= IntPtr.Zero;
EncryptData(theClass描述,参考粒子阵列,LEN,明文长度);

Console.WriteLine(LEN);
// ENC =新的字节[长度]
//Marshal.Copy(pArray,ENC,0,LEN);
//Marshal.Release(pArray);
//尝试
// {
// INT elementSize = Marshal.SizeOf(typeof运算(IntPtr的));
// // IntPtr的unmanagedArray = Marshal.AllocHGlobal(10 * elementSize);
// Console.WriteLine(读非托管内存:);
// //打印C风格的unmanagedArray
的10个元素//的for(int i = 0;我小于10;我++)
// {
/ / Console.WriteLine({0:X2}:Marshal.ReadByte(粒子阵列,I));
//}

// Marshal.FreeHGlobal(粒子阵列);

//}
//赶上(异常前)
// {
// Console.WriteLine({0} \\\
{1} ,ex.Source,ex.Message);
// Console.WriteLine(Win32的({0}),Marshal.GetLastWin32Error());
//}
//Marshal.Release(pArray);
返回ENC;
}



只有这个工作的时间是,当我刚刚作出了一个静态大小的数组和没有使用 REF 名帅复制或任何东西。我觉得我的签名是这样的

 静态外部无效EncryptData(IntPtr的pClass,字节[] outBlock,字节[] inBlock,INT长度); 

这几乎工作,但问题是,当我做了一个的foreach 阵列上环它总是说我把至少可以说大小..沮丧。



那么,我做错了什么?我怎么能得到这个工作?我与它很沮丧。谢谢



呵呵,仅供参考,这是所以我不能依赖于 cryptlib 了。我试图重新编译一个不同的项目,它采用 cryptlib ,作为静态库和不共享,这会导致一些问题,我的编译选项是太大的麻烦改回来。



编辑以显示更多的代码



这是测试我使用。我发现了一个网页即显示一系列测试,所以这是我实现这一点。

 无效VerifyEncrypt16(常量BYTE *预期,常量BYTE *键,常量BYTE *四,常量BYTE *明文)
{
字节实际[16] = {0×00};
Aes128Class AES;
aes.SetKey(键,16);
aes.SetIV(四,16);
为size_t的len = 0;
aes.EncryptData(实际,LEN,明文,16);
_assert(CompareTwoArrays(预计实际));
}
无效VerifyEncrypt16String(为const char *预期,为const char *键,为const char *四,为const char *明文)
{
字节E [16];
K字节[16];
字节I [16];
字节P [16];

ByteUtil :: StringToHex(预期,E);
ByteUtil :: StringToHex(密钥K);
ByteUtil :: StringToHex(四,我);
ByteUtil :: StringToHex(明文,p)的;

VerifyEncrypt16(E,K,I,P);
}
无效CheckEncrypt16(无效)
{
_RPT0(_CRT_WARN,一个16字节数IV组到0\\\
的检查加密);
//为CBC
VerifyEncrypt16String AESVS GFSbox测试数据(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);

//为CBC
VerifyEncrypt16String AESVS KeySbox测试数据(6d251e6944b051e04eaa6fb4dbf78465,10a58869d74be5a374cf867cfb473859,00000000000000000000000000000000,00000000000000000000000000000000);
//更多的测试,一吨!等等等等VerifyEncrypt16String(5c005e72c1418c44f569f2ea33ba54f3,00000000000000000000000000000000,00000000000000000000000000000000,fffffffffffffffffffffffffffffffe);
VerifyEncrypt16String(3f5b8cc9ea855a0afa7347d23e8d664e,00000000000000000000000000000000,00000000000000000000000000000000,ffffffffffffffffffffffffffffffff);
}


解决方案

如果你还在寻找对于答案,这个例子给出了一个起点。



基本上,开始从分配的内存块的本地函数调用,不是调用呼叫 - 回你通过,其中管理(由参)阵列,其大小由输入参数的原始列表保存。



您分配给托管代码托管代码的内存块,并从本地与内容编辑这样说。



的http:// MSDN .microsoft.com / EN-US /库/ ektebyzx.aspx



这是另一种方法将是很好找,性能比较将是一个奖金:)


So I've been struggling with this for a little bit. I'm trying to make my own AES 128 library to use with one of my programs. The library tests out and works in C++ (well for the encrypt function.. I haven't implemented the others) The 'Encrypt' function is like this:

NEW CODE

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);
}

The idea is that if the plainText is not in a 16-byte block increment then I force it to be. So this makes for a variable size byte array. It works in my C++ tests, but when I call it in C# I get a few different errors... This will take a minute to describe.

    [DllImport("CppAes128.dll", CallingConvention = CallingConvention.ThisCall,
        EntryPoint = "?EncryptData@Aes128Class@@QAEXPAEAAIPBEI@Z")]
    static extern void EncryptData(IntPtr pClass, ref IntPtr outblock, [Out]int OutLength, byte[] inBlock, int length);

When I call this I get valid pointers to both the array, and the outlength. The way it looks right now causes an access violation, but I can get that structure to work if I change [Out]int OutLength to ref IntPtr. Interestingly, if I do ref int or ref uint it still "works". So if I do that I try to read the intptr and then I get an access violation. I am compiling this as a x86 project in .NET 4.0 (since I read somewhere that 3.5 had some bugs with access...)

Here is what I've tried in C#. It's a little garbled as I've been playing with it for hours (sorry):

    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;
    }

The only time this worked is when I just made a static-size array and didn't use ref or marshal copy or anything.. I think my signature was something like this

static extern void EncryptData(IntPtr pClass, byte[] outBlock, byte[] inBlock, int length);

That almost worked, but the problem was that when I did a foreach loop on that array it was always the size that i put.. frustrating to say the least.

So what am I doing wrong? how can I get this to work? I am so frustrated with it. Thank you

Oh and FYI, this is so I cannot be dependent on the cryptlib anymore. I'm trying to recompile a different project, which uses cryptlib, as a static library and not shared, which causes some problems with my compiled options and is too big of a hassle to change back.

EDITED to show more code

This is the tests that I use. I found a webpage that showed a bunch of tests, so this is me implementing this.

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");
}

解决方案

In case you are still looking for answer, this example gives a starting point.

Basically, start from allocate memory block in native function call, than invoke call - back to managed where you pass ( by ref ) array and its size saved from the original list of input parameters.

This way you allocate memory block for managed code in managed code and edit it with content from native.

http://msdn.microsoft.com/en-us/library/ektebyzx.aspx

An alternate method would be nice to find, performance compare would be a bonus :)

这篇关于我如何返回从C ++字节数组C#的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆