将C#struct编组到本机C库

时间:2016-06-08 23:02:53

标签: c# c struct shared-libraries marshalling

我正在为NTRUMLS C#库编写NTRUMLS 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 Struct我正在传递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运行密钥生成测试。

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);
<{1}}和params.h

中的

params.c

我相信当前的问题在于enum _PQ_PARAM_SET_ID { XXX_20140508_401, XXX_20140508_439, XXX_20140508_593, XXX_20140508_743, XXX_20151024_401, XXX_20151024_443, XXX_20151024_563, //XXX_20151024_509, XXX_20151024_743, XXX_20151024_907, }; struct _PQ_PARAM_SET { PQ_PARAM_SET_ID id; /* parameter set id */ const char *name; /* human readable name */ const uint8_t OID[3]; /* OID */ uint8_t N_bits; /* ceil(log2(N)) */ uint8_t q_bits; /* ceil(log2(q)) */ uint16_t N; /* ring degree */ int8_t p; /* message space prime */ int64_t q; /* ring modulus */ int64_t B_s; /* max norm of f*a convolution */ int64_t B_t; /* max norm of g*a convolution */ int64_t norm_bound_s;/* q/2 - B_s */ int64_t norm_bound_t;/* q/2 - B_t */ uint8_t d1; /* Product form +1/-1 counts */ uint8_t d2; uint8_t d3; uint16_t padded_N; /* # Polynomial coefficients for Karatsuba */ }; ,并且正确地将name属性与C struct ParamSet struct指针属性匹配。但是,我并不完全确定是这样的。

我修改了NTRUMLS C const char*name源文件以打印到log.txt并记录我正在传递的变量。这是我在pqntrusign.c函数的最开头添加的片段。

int pq_gen_key

我正在使用Fedora 23 x64,因此在NTRUMLS-Sharp github上传的当前libntrumls.so是在添加了该片段的情况下编译的。

C#Console的输出

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

log.txt的输出

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!

修改
另一个有趣的事情是记录为3是正确的param ID,因为枚举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 是3,而D1正确为11.但是每次运行该函数时,为OID记录的输出都是不同的,当它是a时在我的Xxx20140508743中设置3个字节的数组。这让我相信错误是在编组ParamSet.Xxx20140508_743,这是其余的。

下面是log.txt的另一个输出用于比较(这也是添加到“{0}”到const char *name

Marshal.StringToHGlobalAuto("Xxx20140508743\0")

我不相信Windows dll还在运行。如果有人在我的代码或错误日志中无法立即看到问题,编译和测试所有内容的说明都在NTRUMLS C#README文件中。

感谢您抽出宝贵时间阅读此问题!我知道它很长并且具有描述性,但我不太确定如何在不提供所有信息的情况下缩小范围,因为我花了很多时间搜索论坛并修改我的代码以实现这一目标。

最好的问候

1 个答案:

答案 0 :(得分: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);


}