2016-06-08 24 views
3

Ich schreibe derzeit eine NTRUMLS C# Wrapper für die NTRUMLS C-Bibliothek. Ich stoße auf ein Problem, bei dem ich nicht glaube, dass ich die Parameterdaten korrekt über die Fremdfunktionsschnittstelle matrahle, die den C-Bibliothekseinstiegspunkten zugeordnet ist.Marshalling C# -Struktur in native C-Bibliothek

Hier ist die spezifische Fremdfunktionsschnittstelle, die ich in ffi.cs verwende.

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

Der spezifische ParamSet Struct i in param.cs vorbei bin, die ich glauben könnte, speziell sein das Problem verursacht.

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

Und hier ist der Wrapper selbst 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; 
    } 

    } 

} 

Und die Program.cs den Schlüssel gen Test auszuführen.

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 

    } 
} 
} 

Hier ist der Header-Funktion der C-Funktion in

I Marshalling bin

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

in params.h und params.c

ich das aktuelle Problem glauben mit der ParamSet struct und das Attribut name korrekt mit dem C-Struct const char*name Zeigerattribut übereinstimmen. Ich bin mir aber nicht ganz sicher, ob das der Fall ist.

Ich änderte die NTRUMLS C pqntrusign.c Quelldatei, um in eine log.txt auszudrucken und protokolliert die Variablen, die ich übergebe. Hier ist das Snippet, das ich am Anfang der int pq_gen_key Funktion hinzugefügt habe.

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

Ich bin mit Fedora 23 x 64, so dass die aktuelle libntrumls.so auf dem NTRUMLS-Sharp Github hochgeladen zusammengestellt wurde mit dem Snippet hinzugefügt.

Ausgabe von C# Console

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! 

Ausgabe von 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 

EDIT:
Eine weitere interessante Sache als 3 zu beachten ist, protokolliert param ID korrekt ist, da die Enum Xxx20140508743 ist 3, und D1 ist korrekt wie 11. Aber jedes Mal, wenn ich die Funktion ausführen, ist die Ausgabe, die für OID protokolliert wird, anders, wenn es ein gesetztes 3-Byte-Array in meinemist. Das führt mich zu der Annahme, dass der Fehler im Marshalling const char *name ist, das den Rest auswirft.

Unten ist eine weitere Ausgabe von Protokoll.txt zum Vergleich (dies ist auch mit dem zusätzlichen „\ 0“ zu 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 

Ich glaube nicht, das Windows-DLL noch funktioniert. Wenn jemand das Problem nicht sofort in meinem Code sehen kann, oder Fehler log, die Anweisungen zum kompilieren und testen alles in der NTRUMLS C# README-Datei

Vielen Dank, dass Sie sich die Zeit nehmen, diese Frage zu lesen! Ich weiß, dass es lang und beschreibend ist, aber ich war mir nicht sicher, wie man es eingrenzen kann Da ich viel Zeit damit verbracht habe, die Foren zu durchsuchen und meinen Code zu modifizieren, um so weit zu kommen.

Mit freundlichen Grüßen

+1

eine ENUM können unterschiedliche Größen 1,2,4,8 Bytes, so dass Sie für Standardgröße c Sprache Compiler überprüfen. Die Größe kann in C# eingestellt werden, um der Sprache c zu entsprechen. Stellen Sie sicher, dass "name" mit einem "\ 0" endet. Versuchen Sie: Marshal.StringToHGlobalAuto ("Xxx20140508743 \ 0"), – jdweng

+0

Leider wurde das Hinzufügen von "\ 0" nicht behoben. Eine weitere interessante Bemerkung ist, dass die Parameter-ID enum korrekt zu marshallen scheint, da Xxx2014050874 die dritte enum in der Liste ist und die log-Ausgabe zeigt, dass param ID 3 ist, sowie D1 11 ist, was korrekt ist. Interessant ist aber, dass sich Oid jedes Mal ändert, wenn die Funktion ausgeführt wird. Es sollte ein set const 3 Byte Array sein. Ich werde meinen Beitrag bearbeiten, um die verschiedenen Protokollausgaben anzuzeigen – KickTheDragon

+2

Variablen werden ordnungsgemäß von C# an c übergeben, aber die Rückgabe schlägt fehl, weil Sie den Ausführungsstapel beschädigt haben. In .h pq_gen_key Parameterliste enthält 5 Zeiger, so dass in C# der DllImport 5 IntPtr enthalten muss. Dann nimm ParamSet p und benutze Marshal.StructureToPtr, um IntPtr zu erhalten. – jdweng

Antwort

0

Alles funktioniert jetzt!

sieht die params struct Marshalling wie folgt

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

     Marshal.StructureToPtr(param, parameter, false); 

unter die letzte Funktion aktiviert ist.

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

    } 

Und mein 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); 


}