views:

780

answers:

4

Hello,

This is my 3rd thread concerning a blowfish problem in C#.Despite the fact I cannot have blowfish implemented in my application, I decided to use it as an external C++ dll. Please note I've tried Blowfish.NET and any other, the problem is that I'm translating code from C++ to C# and the C# code must do exactly the same as the C++ code does.

So far:

--->C++ DLL source<---

Note the exported functions are in the end of the code

C# code(definition)

    [DllImport("TestDLL.dll", EntryPoint = "Initkey" ,ExactSpelling = true , CallingConvention = CallingConvention.Cdecl)]
    public static unsafe extern void Initkey(byte[] key);

    [DllImport("TestDLL.dll", EntryPoint = "encode", ExactSpelling = true, CallingConvention = CallingConvention.Cdecl)]
    public static unsafe extern void encode(UInt32 *stream);

C# code(function calling)

-Initialize blowfish key

UInt32[] keyarray = new UInt32[2];
//some code
Extern.Initkey(Misc.ConvertFromUInt32Array(keyarray));
//
//
//Helper function used to convert a UInt32 array into Byte array.
public static byte[] ConvertFromUInt32Array(UInt32[] array)
{
    List<byte> results = new List<byte>();
    foreach (UInt32 value in array)
    {
        byte[] converted = BitConverter.GetBytes(value);
        results.AddRange(converted);
    }
    return results.ToArray();
}

-Encode the data.

            UInt32[] keyarray2 = new UInt32[2];
            //some code
            unsafe
            {
                fixed (UInt32* LPBYTE = keyarray2)
                {
                    Extern.encode(LPBYTE);
                }
            }

After keyarray2 is overwritten by the Encode function, I check the values in the C++ code by decrypting them to make sure everything is alright.

Well, It's not alright.That's my problem, That's why I am asking you for your help.

The values are different when I decrypt them,but If I encrypt them and decrypt them in the C++ source, they are equal.The C++ code is absolutely the same,except that there's no DLL since the code is in C++.

Could that be, because of the Initialize function.I had read a couple of months ago that arrays in C++ are passed as Pointers.I don't believe it,but even so - could that be the problem?

I can't find a clue.I wasted my wife with that blowfish in C#.At least that solution should work,but it doesn't - Why?

Thanks in advance!

A: 

Arrays in C and C++ are passed as pointers. Semantics for arrays in C# include an additional layer of indirection. Your C# program is (probably) passing the address of a variable that holds the address of the data.

I recently wrestled with passing an array of bytes from C# to a C function and had to marshal the data in both directions. It's not obvious to me that your code is doing that.

Better than an explanation, I'll provide a concrete example:

//extern "C" LIBEXIFWRAPPER_API void findEXIFtagValue( void * load, unsigned int tagID, char* buf, int bufLen );
[DllImport("libexif-wrapper.dll")]
unsafe public static extern IntPtr findEXIFtagValue([MarshalAs(UnmanagedType.SysUInt)]IntPtr load, int tagID, [MarshalAs(UnmanagedType.SysUInt)]IntPtr buf, int bufLen);

This function accepts a pointer to opaque data, an int and a byte array in which it stores a text string.

The following snippet shows how the byte array is declared, passed to the C function and the results extracted:

const int tagBuffer = 1024;
IntPtr buf = Marshal.AllocHGlobal(tagBuffer);

findEXIFtagValue(loader, (int)ExifTag.EXIF_TAG_DATE_TIME, buf, tagBuffer);
string s = Marshal.PtrToStringAnsi(buf);

Note that the argument is marshaled in the prototype and marshaled again to retrieve the result.

None of this was particularly obvious to me. It seems that IntPtr is the C# equivalent of void* except I had to use a SysUInt to manage a (C) void*. The pointer to the byte array is marshaled in as SysUInt.

(from a C# noob)

HTH

HankB
A: 

May be you should try using ref for pointers, and out for functions that return data through an argument. Let me know if that works. Thanks.

+1  A: 

Are you aware of the fact that you are initializing a temporary instance that is destroyed by the time the Initkey function returns? You should combine the whole thing in one function, or create the cBlowfish on the heap and return the pointer to the C# code (it can treat it as an opaque IntPtr).

Moreover, you don't need to use unsafe here. Just pass the UInt32[] directly.

jachymko
+1  A: 

To add to what jachymko has said, also check the documentation for BitConverter - you need to be sure you are passing the key and data in the byte order you intended. Note - from your previous thread, I successfully encrypted data using the modified Blowfish.NET encryptor and got it to match the result of your C++ code.

Dave Cluderay
@Dave,Thank you for your help! Could you upload the source of the modified Blowfish.NET somewhere,please.
John
Yes, I will upload the source somewhere. It was a C# 2008 project and a C++ 2008 project - they both produce the same output for me.
Dave Cluderay
@Dave,thanks! Please paste the link here,not in my old thread.Did you use my C++ blowfish encryption,not some other?
John
http://www.stiperstuff.com/BF.zip
Dave Cluderay
Works! God bless you Dave! I misunderstood your last statement,you said our last "modification" caused some effects and I thought I have to bring back the original,so only the EncryptBlock was changed your way.I've got it working,thanks!
John
Ace! I will remove the zip file now.
Dave Cluderay
Hello Dave! I'm meeting another problem with blowfish.I can't encrypt a byte array of less than 8 bytes.I made some research and found why it works in C++ Blowfish,but not in C#.Please check my other thread. http://stackoverflow.com/questions/705596/c-blowfish-encipher-a-single-dwordThank you!
John