C# and C++...

Joined
Apr 7, 2009
Messages
647
Reaction score
26
Apparently, I keep getting P/Invoke problems with this code...I'm gonna guess that it's cuz my imported parameter type is incorrect.
Could anyone help me?

C++
Code:
#ifdef __cplusplus
extern "C"
{
#endif
    byte tDESKey[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };

	const int blockSize = 8;

	__declspec(dllexport) void getNextIV(byte * iv)
	{
		byte newIV[blockSize];

		if(iv == NULL)
		{
			printf("Hello, World!");//Testing
		}
	}

#ifdef __cplusplus
}
#endif

C#
Code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime;
using System.Runtime.InteropServices;

namespace CPPCryptoTest
{
    class Program
    {
        [DllImport("Stuff.dll")]
        static extern void getNextIV(ref byte[] b);

        static void Main(string[] args)
        {
            byte[] b = new byte[8];

            //The line below causes a P/Invoke exception
            getNextIV(ref b);//This should output "Hello, World!"

            Console.ReadLine();
        }
    }
}
 
Last edited:
Try removing ; from
byte tDESKey[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
 
hey guy
long time no talk

you're passing a ref, which isn't the same as a pointer

You can change the getNextIV(byte * iv) to getNextIV(array<byte> ^ivarray)

...Then when you call it, leave out the "ref" in C#

in C++, you need to pin the memory with a pin_ptr

pin_ptr<byte> p = &ivarray[0]; ...or something similar :P
then "p" is your byte* now... and you can treat it exactly like you tried to treat "iv" before.

your C++ function doesn't look all that complicated - consider writing it in C# for simplicity ... and if you *NEED* access to pointers, you can still do it in C# with unsafe code
 
hey guy
long time no talk

you're passing a ref, which isn't the same as a pointer

You can change the getNextIV(byte * iv) to getNextIV(array<byte> ^ivarray)

...Then when you call it, leave out the "ref" in C#

in C++, you need to pin the memory with a pin_ptr

pin_ptr<byte> p = &ivarray[0]; ...or something similar :P
then "p" is your byte* now... and you can treat it exactly like you tried to treat "iv" before.

your C++ function doesn't look all that complicated - consider writing it in C# for simplicity ... and if you *NEED* access to pointers, you can still do it in C# with unsafe code

Yeah, but doing it in C# would make it pathetically easy to decompile and steal the key.

...Then when you call it, leave out the "ref" in C#

Then I won't be able to get the generated IV.
I used ref, since I wanted to fill a byte array with the returned IV, and since you can't really return an array in a C++ function, I decided to use ref variables.

your C++ function doesn't look all that complicated - consider

You're right, it isn't.
This is the code functionality I was trying to achieve
Code:
private static Random random = new Random();

        // This is the magic
        private static byte[] tDESKey = new byte[8];

        // Block size
        private const int blockSize = 8;

        // getNextIV. Generates an IV from an exisiting one. Supply null to get a new IV.
        public static byte[] getNextIV(byte[] prevIV)
        {           
            byte[] newIV = new byte[blockSize];
            if (prevIV == null)
            {
                // generate new IV
                random.NextBytes(newIV);
            }
            else
            {
                if (prevIV.Length != blockSize) throw new Exception("Invalid IV length specified. The IV must be 16 bytes long.");
                for (int i = 0; i < newIV.Length; i++)
                {
                    newIV[i] = (byte)(prevIV[i] >> 4);
                    newIV[i] ^= prevIV[i];
                    newIV[i] = (byte)(newIV[i] << 1);
                }
            }
            return newIV;
        }

        // Encrypt a byte[] with an iv
        public static byte[] encryptBytes(byte[] plaintext, byte[] iv)
        {
            // key is statically defined.

            TripleDESCryptoServiceProvider tDES = new TripleDESCryptoServiceProvider();
            tDES.Key = tDESKey;
            tDES.IV = iv;
            tDES.Padding = PaddingMode.PKCS7;

            ICryptoTransform crypto = tDES.CreateEncryptor();
            byte[] output = crypto.TransformFinalBlock(plaintext, 0, plaintext.Count());

            crypto.Dispose();
            tDES.Clear();

            return output;
        }

        public static byte[] decryptBytes(byte[] cipherText, byte[] iv)
        {
            TripleDESCryptoServiceProvider tDES = new TripleDESCryptoServiceProvider();
            tDES.Key = tDESKey;
            tDES.IV = iv;
            tDES.Padding = PaddingMode.PKCS7;

            ICryptoTransform crypto = tDES.CreateDecryptor();
            byte[] output = crypto.TransformFinalBlock(cipherText, 0, cipherText.Length);

            crypto.Dispose();
            tDES.Clear();

            return output;
        }

Also, do you know any 3DES libs for C/C++?

---------- Post added at 07:37 PM ---------- Previous post was at 06:28 PM ----------

I changed getNextIV() to return a byte pointer, and now I'm getting this exception in C#, when calling it:
Code:
System.Runtime.InteropServices.MarshalDirectiveException was unhandled
  Message=Cannot marshal 'return value': Invalid managed/unmanaged type combination.
  Source=CPPCryptoTest
  StackTrace:
       at CPPCryptoTest.Program.getNextIV(Byte[] b)
       at CPPCryptoTest.Program.Main(String[] args) in J:\Users\TonyDEV\Desktop\FableSolace\CPPCryptoTest\Program.cs:line 19
       at System.AppDomain._nExecuteAssembly(RuntimeAssembly assembly, String[] args)
       at System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args)
       at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
       at System.Threading.ThreadHelper.ThreadStart_Context(Object state)
       at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean ignoreSyncCtx)
       at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
       at System.Threading.ThreadHelper.ThreadStart()
  InnerException:
 
Last edited:
do it in C#. Use Dotfuscator to obfuscate your code and make it non-decompilable ... or at least as difficult as native code.

By the way, your C++ interop is still .NET, making it just as easy to decompile as C#.

When you use ref byte[] p ... you're telling the function it can overwrite "p", which is the handle to the byte[]... You do NOT want "ref"... because you want the function you're calling to modify the contents of the array that you supply... not to supply you with a new array.

Seriously - just make it C# and use an obfuscator
 
Back