2016-06-08 67 views
3

我正在爲NTRUMLS C庫編寫NTRUMLS C#包裝。我遇到了一個問題,我不相信我通過映射到C庫入口點的外部函數接口正確編組參數數據。將C#結構編譯爲本地C庫

下面是我在ffi.cs中使用的特定外部函數接口。

using System; 
using System.Runtime.InteropServices; 
using NTRUMLS.Params; 

namespace NTRUMLS.ffi { 
public static class ffi { 

    [DllImport("ntrumls")] 
    public static extern int pq_gen_key(ParamSet p, out IntPtr privkey_blob_len, out byte[] privkey_blob, out IntPtr pubkey_blob_len, out byte[] pubkey_blob); 
    } 
} 

具體ParamSet結構我傳遞在param.cs,我認爲可能是專門導致了問題。

using System; 
using System.Text; 
using System.Runtime.InteropServices; 
namespace NTRUMLS.Params { 

[SerializableAttribute] 
[ComVisibleAttribute(true)] 
public enum ParamSetId { 
    Xxx20140508401, 
    Xxx20140508439, 
    Xxx20140508593, 
    Xxx20140508743, 

    Xxx20151024401, 
    Xxx20151024443, 
    Xxx20151024563, 
    // Xxx20151024509, 
    Xxx20151024743, 
    Xxx20151024907, 
} 

[StructLayout(LayoutKind.Sequential)] 
public struct ParamSet { 


    ParamSetId id; 

    IntPtr name; 
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] 
    byte[] oid; 
    [MarshalAs(UnmanagedType.U1)] 
    byte n_bits; 
    [MarshalAs(UnmanagedType.U1)] 
    byte q_bits; 
    [MarshalAs(UnmanagedType.U2)] 
    ushort n; 
    [MarshalAs(UnmanagedType.I1)] 
    sbyte p; 
    [MarshalAs(UnmanagedType.I8)] 
    long q; 
    [MarshalAs(UnmanagedType.I8)] 
    long b_s; 
    [MarshalAs(UnmanagedType.I8)] 
    long b_t; 
    [MarshalAs(UnmanagedType.I8)] 
    long norm_bound_s; 
    [MarshalAs(UnmanagedType.I8)] 
    long norm_bound_t; 
    [MarshalAs(UnmanagedType.U1)] 
    byte d1; 
    [MarshalAs(UnmanagedType.U1)] 
    byte d2; 
    [MarshalAs(UnmanagedType.U1)] 
    byte d3; 
    [MarshalAs(UnmanagedType.U2)] 
    ushort padded_n; 

    public ushort get_n() { 
     return n; 
    } 

    public sbyte get_p() { 
     return p; 
    } 

    public byte get_d1() { 
     return d1; 
    } 

    public byte get_d2() { 
     return d2; 
    } 

    public byte get_d3() { 
     return d3; 
    } 

    public uint product_form_bytes() { 
     return (uint)(4 * (d1 + d2 + d3)); 
    } 

    public uint polynomial_bytes() { 
     return (uint)(padded_n * 8); 
    } 

    public uint privkey_packed_bytes() { 
     return (uint)(5 + 2 * ((2 * (d1 + d2 + d3) * n_bits + 7)/8) + ((n +4)/5)); 
    } 

    public uint pubkey_packed_bytes() { 
     return (uint)(5 + (n * q_bits + 7)/8 + 64); 
    } 

    public ParamSet (ParamSetId ID, IntPtr NAME, byte[] OID, byte N_BITS, byte Q_BITS, ushort N, sbyte P, long Q, long B_S, long B_T, long NORM_BOUND_S, long NORM_BOUND_T, byte D1, byte D2, byte D3, ushort PADDED_N) { 
     id = ID; 
     name = NAME; 
     oid = OID; 
     n_bits = N_BITS; 
     q_bits = Q_BITS; 
     n = N; 
     p = P; 
     q = Q;; 
     b_s = B_S; 
     b_t = B_T; 
     norm_bound_s = NORM_BOUND_S; 
     norm_bound_t = NORM_BOUND_T; 
     d1 = D1; 
     d2 = D2; 
     d3 = D3; 
     padded_n = PADDED_N; 
    } 


} 

public static class ParamSets { 

    /// <summary> 
    /// 256 bit security parameter 
    /// </summary> 
    public static readonly ParamSet Xxx20140508_743 = new ParamSet(
     ParamSetId.Xxx20140508743, 
     Marshal.StringToHGlobalAuto("Xxx20140508743"), 
     new byte[] {0xff, 0xff, 0xfc}, 
     10, 
     20, 
     743, 
     3, 
     1 << 20, 
     336, 
     112, 
     (1 << 19) - 336, 
     (1 << 19) - 112, 
     11, 
     11, 
     15, 
     768); 
    } 
} 

而這裏是包裝本身NTRUMLSWrapper.cs

using NTRUMLS.ffi; 
using NTRUMLS.Params; 
using System; 
using System.Runtime.InteropServices; 

namespace NTRUMLS.Library { 

public static class NTRUMLSWrapper { 

    public static KeyPair generate_keys(ParamSet param) { 
     int pub_len = 0; 
     int priv_len = 0; 

     Console.WriteLine("Param N: " + param.get_n()); 
     Console.WriteLine("Param P: " + param.get_p()); 
     Console.WriteLine("Param D1: " + param.get_d1()); 
     Console.WriteLine("Param D2: " + param.get_d2()); 
     Console.WriteLine("Param D3: " + param.get_d3()); 

     GCHandle pub_len_handle = GCHandle.Alloc(pub_len); 
     GCHandle priv_len_handle = GCHandle.Alloc(priv_len); 

     IntPtr privkey_blob_len = (IntPtr)pub_len_handle; 
     IntPtr pubkey_blob_len = (IntPtr)priv_len_handle; 

     GCHandle handle = GCHandle.Alloc(param); 

     IntPtr paramater = (IntPtr)handle; 

     byte[] pv = new byte[priv_len]; 
     byte[] pb = new byte[pub_len]; 

    // GCHandle pv_handle = GCHandle.Alloc(pv); 
    // GCHandle pb_handle = GCHandle.Alloc(pb); 

     var result = ffi.ffi.pq_gen_key(param, out privkey_blob_len, out pv, out pubkey_blob_len, out pb); 

     Console.WriteLine("Result: " + result + " Private Key BLob Length: " + priv_len + " Public Key Blob Lengh: " + pub_len); 



     if (result != 0) 
      Console.WriteLine("We got problems"); 

     byte[] privatekey_blob = new byte[privkey_blob_len.ToInt64()]; 
     byte[] pubkey_blob = new byte[pubkey_blob_len.ToInt64()]; 

     result = ffi.ffi.pq_gen_key(param, out privkey_blob_len, out privatekey_blob, out pubkey_blob_len, out pubkey_blob); 

     if (result != 0) 
      Console.WriteLine("We got problems"); 

     Console.WriteLine("Result: " + result.ToString() + " Private Key BLob Length: " + privkey_blob_len + " Public Key Blob Lengh: " + pubkey_blob_len); 

     // byte[] privkeyBytes = new byte[priv_len.ToInt32()]; 
     // byte[] pubkeyBytes = new byte[pub_len.ToInt32()]; 



     return new KeyPair(new PrivateKey(pubkey_blob), new PublicKey(privatekey_blob));; 

    } 

} 


public struct PrivateKey { 
    byte[] ffi_key; 

    public PrivateKey (byte[] bytes) { 
     ffi_key = bytes; 
    } 

    public byte[] get_bytes() { 
     return ffi_key; 
    } 
} 

public struct PublicKey { 
    byte[] ffi_key; 

    public PublicKey (byte[] bytes) { 
     ffi_key = bytes; 
    } 

    public byte[] get_bytes() { 
     return ffi_key; 
    } 
} 

public struct KeyPair { 

    PublicKey publicKey; 
    PrivateKey privateKey; 

    public KeyPair(PrivateKey privKey, PublicKey pubkey) 
    { 
     publicKey = pubkey; 
     privateKey = privKey; 
    } 

    public PublicKey getPublic() 
    { 
     return publicKey; 
    } 

    public PrivateKey getPrivate() 
    { 
     return privateKey; 
    } 

    } 

} 

Program.cs運行鍵gen測試。

using System; 
using NTRUMLS.Library; 
using NTRUMLS.Params; 

namespace NTRUMLS 
{ 
public class Program 
{ 
    public static void Main(string[] args) 
    { 
     KeyPair keypair = NTRUMLSWrapper.generate_keys(ParamSets.Xxx20140508_743); 

     Console.WriteLine("Generated Keys!"); 

     // TODO Sign, than Verify to confirm test 

    } 
} 
} 

這裏的C函數,我編組到

pqntrusign.h

int 
pq_gen_key(
PQ_PARAM_SET *params, 
size_t  *privkey_blob_len, 
unsigned char *privkey_blob, 
size_t  *pubkey_blob_len, 
unsigned char *pubkey_blob); 

params.h和頭功能params.c

我認爲,當前的問題是與ParamSet struct,並正確地將名稱屬性與C結構的const char*name指針屬性進行匹配。但是,我不完全確定是這種情況。

我修改了NTRUMLS C pqntrusign.c源文件以打印出log.txt文件並記錄下我傳遞的變量。這是我在int pq_gen_key函數的開頭添加的代碼片段。

FILE * fp; 

fp = fopen ("log.txt", "a+"); 
fprintf(fp, "Logging made it here variables priv_blob_len_pointer %i pub_blob_len_pointer %i priv_blob_len %i pub_blob_len %i privkey %x pubkey %x \n", privkey_blob_len, pubkey_blob_len, *privkey_blob_len, *pubkey_blob_len, privkey_blob, pubkey_blob); 

fprintf(fp, "Logging param ID: %i Oid %x : N: %i Q: %i P %i Padded N: %i D1: %i D2: %i D3: %i \n", P->id, P->OID, P->N, P->q, P->p, P->padded_N, P->d1, P->d2, P->d3); 



if(!P || !privkey_blob_len || !pubkey_blob_len) 
{ 
    return PQNTRU_ERROR; 
} 

N = P->N; 
padN = P->padded_N; 
q = P->q; 
p = P->p; 
d1 = P->d1; 
d2 = P->d2; 
d3 = P->d3; 

fprintf(fp, "Logging Local N: %i Q: %i P %i Padded N: %i D1: %i D2: %i D3: %i \n", N, q, p, padN, d1, d2, d3); 

fclose(fp); 

我使用的Fedora 23的x64所以上載於NTRUMLS夏普GitHub上的電流libntrumls.so編譯與片段添加。

從C#控制檯

Param N: 743 
Param P: 3 
Param D1: 11 
Param D2: 11 
Param D3: 15 
Result: -1 Private Key BLob Length: 0 Public Key Blob Lengh: 0 
We got problems 
We got problems 
Result: -1 Private Key BLob Length: 3 Public Key Blob Lengh: 11 
Generated Keys! 

輸出輸出從log.txt的

Logging made it here variables priv_blob_len_pointer -923442424 pub_blob_len_pointer -923442432 priv_blob_len -994004096 pub_blob_len -994004064 privkey c8f56510 pubkey f0b0b 
Logging param ID: 3 Oid c8f56528 : N: 0 Q: 42678032 P 19 Padded N: 0 D1: 11 D2: 0 D3: 0 
Logging Local N: 0 Q: 42678032 P 19 Padded N: 0 D1: 11 D2: 0 D3: 0 
Logging made it here variables priv_blob_len_pointer -923442424 pub_blob_len_pointer -923442432 priv_blob_len -994003392 pub_blob_len -994003352 privkey c8f56510 pubkey f0b0b 
Logging param ID: 3 Oid c8f56528 : N: 0 Q: 42678032 P 19 Padded N: 0 D1: 11 D2: 0 D3: 0 
Logging Local N: 0 Q: 42678032 P 19 Padded N: 0 D1: 11 D2: 0 D3: 0 

編輯:
另一個有趣的事情需要注意的是PARAM ID記錄爲3是正確的,因爲枚舉Xxx20140508743是3,而D1是正確的11.但是,每次我運行該函數輸出記錄的OID是不同的,當它是一組3字節數組在我的ParamSet.Xxx20140508_743。這導致我相信錯誤發生在編組const char *name,這是拋出休息。

下面是日誌的另一個輸出。TXT進行比較(這也與加「\ 0」 Marshal.StringToHGlobalAuto("Xxx20140508743\0")

Logging made it here variables priv_blob_len_pointer 982750168 pub_blob_len_pointer 982750160 priv_blob_len -960449664 pub_blob_len -960449632 privkey 3a9395e0 pubkey f0b0b 
Logging param ID: 3 Oid 3a9395f8 : N: 0 Q: 38160144 P 19 Padded N: 0 D1: 11 D2: 0 D3: 0 
Logging Local N: 0 Q: 38160144 P 19 Padded N: 0 D1: 11 D2: 0 D3: 0 
Logging made it here variables priv_blob_len_pointer 982750168 pub_blob_len_pointer 982750160 priv_blob_len -960448960 pub_blob_len -960448920 privkey 3a9395e0 pubkey f0b0b 
Logging param ID: 3 Oid 3a9395f8 : N: 0 Q: 38160144 P 19 Padded N: 0 D1: 11 D2: 0 D3: 0 
Logging Local N: 0 Q: 38160144 P 19 Padded N: 0 D1: 11 D2: 0 D3: 0 

我不相信在Windows DLL工作呢。如果有人不能立即看到在我的代碼的問題或錯誤日誌,編譯和測試所有東西的方向都在NTRUMLS C#README文件中。

謝謝你花時間閱讀這個問題!我知道它很長並且描述性很強,但我不太確定如何縮小它沒有提供所有的信息,因爲我花了很多時間搜索論壇並修改我的代碼以實現這一目標。最好的問候

+1

枚舉可以有不同的尺寸1,2,4,8字節,因此檢查你的C語言編譯器的默認大小。大小可以在c#中設置以匹配c語言。確保'名稱'以'\ 0'結尾。嘗試:Marshal.StringToHGlobalAuto(「Xxx20140508743 \ 0」), – jdweng

+0

不幸的是,添加「\ 0」沒有解決它。然而,另一個有趣的注意事項是參數ID枚舉似乎是編組正確,因爲Xxx2014050874是列表中的第三枚枚舉,並且日誌輸出顯示參數ID爲3,以及D1爲11,這是正確的。但有趣的是每次函數運行時Oid都會改變,並且應該是一個const 3字節數組。我將編輯我的帖子以顯示不同的日誌輸出 – KickTheDragon

+2

變量正在從c#正確傳遞到c,但返回失敗,因爲您破壞了執行堆棧。在.h中,pq_gen_key參數列表包含5個指針,因此在C#中,DllImport必須包含5個IntPtr。然後採取ParamSet p並使用Marshal.StructureToPtr來獲取IntPtr。 – jdweng

回答

0

現在所有的作品!

封送PARAMS結構看起來低於這個

 IntPtr parameter = Marshal.AllocHGlobal(Marshal.SizeOf(param)); 

     Marshal.StructureToPtr(param, parameter, false); 

是最後的功能工作。

public static KeyPair generate_keys(ParamSet param) { 
     uint pub_len = 0; 
     uint priv_len = 0; 

     IntPtr privkey_blob_len = new IntPtr(priv_len); 
     IntPtr pubkey_blob_len = new IntPtr(pub_len); 

     IntPtr parameter = Marshal.AllocHGlobal(Marshal.SizeOf(param)); 

     Marshal.StructureToPtr(param, parameter, false); 

     IntPtr pv_ptr = IntPtr.Zero; 
     IntPtr pb_ptr = IntPtr.Zero; 

     var result = ffi.ffi.pq_gen_key(parameter, out privkey_blob_len, pv_ptr, out pubkey_blob_len, pb_ptr); 

     Console.WriteLine("Result: " + result + " Private Key BLob Length: " + privkey_blob_len.ToInt32() + " Public Key Blob Lengh: " + pubkey_blob_len); 


     if (result != 0) 
      Console.WriteLine("We got problems"); 


     pv_ptr = Marshal.AllocHGlobal(privkey_blob_len.ToInt32()); 
     pb_ptr = Marshal.AllocHGlobal(pubkey_blob_len.ToInt32()); 


     result = ffi.ffi.pq_gen_key(parameter, out privkey_blob_len, pv_ptr, out pubkey_blob_len, pb_ptr); 

     if (result != 0) 
      Console.WriteLine("We got problems"); 

     Console.WriteLine("Result: " + result.ToString() + " Private Key BLob Length: " + privkey_blob_len + " Public Key Blob Lengh: " + pubkey_blob_len); 

     byte[] privkeyBytes = new byte[privkey_blob_len.ToInt32()]; 
     byte[] pubkeyBytes = new byte[pubkey_blob_len.ToInt32()]; 

     Marshal.Copy(pv_ptr, privkeyBytes, 0, privkey_blob_len.ToInt32()); 
     Marshal.Copy(pb_ptr, pubkeyBytes, 0, pubkey_blob_len.ToInt32()); 


     Marshal.FreeHGlobal(pv_ptr); 
     Marshal.FreeHGlobal(pb_ptr); 
     Marshal.FreeHGlobal(parameter); 


     return new KeyPair(new PrivateKey(privkeyBytes), new PublicKey(pubkeyBytes)); 

    } 

我的FFI

public static class ffi { 

    [DllImport("ntrumls")] 
    public static extern int pq_gen_key(IntPtr p, out IntPtr privkey_blob_len, IntPtr privkey_blob, out IntPtr pubkey_blob_len, IntPtr pubkey_blob); 


}