2013-01-31 181 views
6

所以我一直在爲這一點努力。我正在嘗試將我自己的AES 128庫用於我的一個程序。圖書館測試出來,在C工作++(良好的加密功能。我還沒有實現的其他人)的「加密」功能是這樣的:如何從C++返回一個字節數組到C#

新規範

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

的想法如果plainText不是16字節塊增量,那麼我強制它。所以這使得可變大小的字節數組。它在我的C++測試中起作用,但是當我在C#中調用它時,我收到了一些不同的錯誤......這需要一分鐘來描述。

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

當我打電話給我時,我得到了有效的指針array和outlength。它現在的樣子現在會導致訪問衝突,但如果我將[Out]int OutLength更改爲ref IntPtr,則可以使用該結構。有趣的是,如果我做ref intref uint它仍然「有效」。所以如果我這樣做,我嘗試閱讀intptr,然後我得到一個訪問衝突。我正在編譯x86 project.NET 4.0(因爲我讀了3.5的地方有一些錯誤的訪問...)

這是我在C#試過。這是一個有點亂碼,因爲我一直在玩好幾個小時了(對不起):

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

這個工作唯一的一次,當我剛剛作出了一個靜態大小的數組並沒有採用refmarshal複製或什麼..我想我的簽名是這樣的

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

,幾乎工作,但問題是,當我這樣做對array一個foreach循環它一直是我把大小..沮喪地說,最小。

那麼我做錯了什麼?我怎樣才能使這個工作?我很沮喪。謝謝

哦和FYI,這是我不能依賴於cryptlib了。我試圖重新編譯一個不同的項目,它使用cryptlib作爲一個靜態庫並且不共享,這會導致我的編譯選項出現一些問題,並且太麻煩了。

編輯以顯示更多的代碼

這是我使用的測試。我發現了一個顯示一堆測試的網頁,所以這是我實現這個。

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

看看這個【答案】(http://stackoverflow.com/a/13123962/175157) 。簡而言之,C#無法知道您在C++代碼中分配了多少內存。 – Alex

+1

我不確定你的最終目標是什麼,但我只想指出C#在[System.Security.Cryptography Namespace]中包含了一些很棒的加密類(http://msdn.microsoft.com/en-us /library/system.security.cryptography.aspx)很好。 –

+1

與C++代碼互操作的一個必要的出發點是,您可以從其他C++代碼安全地調用C++代碼啓動*。你還沒到,你的內存泄漏嚴重,C++調用者也不會猜測所需的緩衝區大小。這些問題在您從C#撥打電話時不會變得更好。 –

回答

1

如果您仍在尋找答案,此示例給出了一個起點。

基本上,從原生函數調用開始分配內存塊,比調用回調到託管的地方你通過(參考)數組及其大小從輸入參數的原始列表保存。

通過這種方式,您可以爲託管代碼中的託管代碼分配內存塊,並使用本地內容對其進行編輯。

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

的另一種方法將是很好找,性能比較將是一個獎金:)

1

坦率地說,我發現最簡單的方法是使用託管C++調用來封裝非託管C++調用。在受管理的C++中,您可以以直接C++方式(通過固定數據結構)複製數據並將其傳回給C#