2013-01-31 34 views
6

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

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

+1

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. –

+1

Đ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#. –

Trả lời

1

Trong trường hợp bạn vẫn đang tìm câu trả lời, ví dụ này cho biết điểm bắt đầu.Về cơ bản, bắt đầu từ cấp phát khối bộ nhớ trong cuộc gọi hàm gốc, hơn gọi gọi lại để quản lý nơi bạn vượt qua (theo ref) mảng và kích thước của nó được lưu từ danh sách gốc của các tham số đầu vào.

Bằng cách này bạn phân bổ khối bộ nhớ cho mã được quản lý trong mã được quản lý và chỉnh sửa nó bằng nội dung gốc.

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

Một phương pháp thay thế sẽ được tốt đẹp để tìm, hiệu suất so sánh sẽ là một tiền thưởng :)

1

Thành thật mà nói, tôi đã tìm thấy cách dễ nhất để thực hiện việc này là bao bọc cuộc gọi C++ không được quản lý bằng cuộc gọi C++ được quản lý. Trong C++ được quản lý, bạn có thể sao chép dữ liệu theo cách C++ thẳng (bằng cách ghim cấu trúc dữ liệu) và chuyển nó về C#

Các vấn đề liên quan