title: Type could not be marshaled error when interfacing function from globalplatform in C#
body: <p>I have been working to create an interface of globalplatform library in C#, and currently stuck with this error:</p>
  <pre><code>System.ArgumentException: Type could not be marshaled because the length of an embedded array instance does not match the declared length in the layout.
     at System.StubHelpers.StubHelpers.FmtClassUpdateNativeInternal(Object obj, Byte* pNative, CleanupWorkList&amp; pCleanupWorkList)
   at LibGlobalPlatform.GlobalPlatform.GP211_mutual_authentication_wrapper(OPGP_CARD_CONTEXT cardContext, OPGP_CARD_INFO cardInfo, Byte[] baseKey, Byte[] S_ENC, Byte[] S_MAC, Byte[] DEK, Int32 keyLength, Byte keySetVersion, Byte keyIndex, Byte secureChannelProcotol, Byte secureChannelProtocolImpl, Byte securityLevel, Byte derivationMethod, GP211_SECURITY_INFO&amp; secInfo, OPGP_ERROR_STATUS&amp; cardStatus)
  </code></pre>
  <p>When calling the following (C) function:</p>
  <pre><code>void GP211_mutual_authentication_wrapper(OPGP_CARD_CONTEXT cardContext, OPGP_CARD_INFO cardInfo,
                             BYTE baseKey[32], BYTE S_ENC[32], BYTE S_MAC[32],
                             BYTE DEK[32], DWORD keyLength, BYTE keySetVersion,
                             BYTE keyIndex, BYTE secureChannelProtocol,
                             BYTE secureChannelProtocolImpl,
                             BYTE securityLevel, BYTE derivationMethod, GP211_SECURITY_INFO *secInfo,
                             OPGP_ERROR_STATUS *cardErrorStatus);
  </code></pre>
  <p>Its function signature is the following:</p>
  <pre><code>[DllImport(&quot;globalPlatform.dll&quot;, CallingConvention = CallingConvention.Cdecl)]
  public static extern void GP211_mutual_authentication_wrapper(OPGP_CARD_CONTEXT cardContext, OPGP_CARD_INFO cardInfo, byte[] baseKey, byte[] S_ENC, 
                                      byte[] S_MAC, byte[] DEK, int keyLength, byte keySetVersion, byte keyIndex, byte secureChannelProcotol, 
                                      byte secureChannelProtocolImpl, byte securityLevel, byte derivationMethod, ref GP211_SECURITY_INFO secInfo, 
                                      ref OPGP_ERROR_STATUS cardStatus);
  </code></pre>
  <p>I call the function like this:</p>
  <pre><code>GlobalPlatform.OPGP_ERROR_STATUS cardStatus = new GlobalPlatform.OPGP_ERROR_STATUS();
  GlobalPlatform.OPGP_CARD_CONTEXT cardContext = new GlobalPlatform.OPGP_CARD_CONTEXT();
  GlobalPlatform.OPGP_CARD_INFO cardInfo = new GlobalPlatform.OPGP_CARD_INFO();
  GlobalPlatform.GP211_SECURITY_INFO secInfo = new GlobalPlatform.GP211_SECURITY_INFO();
  byte[] baseKey = new byte[32];
  byte[] S_ENC = new byte[32];
  byte[] S_MAC = new byte[32];
  byte[] DEK = new byte[32];
  GlobalPlatform.GP211_mutual_authentication_wrapper(cardContext, cardInfo, baseKey, S_ENC, S_MAC, DEK, keyLength, keySetVersion, keyIndex, scp, scpImpl, securityLevel, derivationMethod, ref secInfo, ref cardStatus);
  </code></pre>
  <p>The struct paramaters tested to be working in other functions, except the <code>GP211_SECURITY_INFO</code> struct is untested. The source code of the struct is defined as follow:</p>
  <pre><code>typedef struct {
      BYTE securityLevel; //!&lt; The security level.
      BYTE secureChannelProtocol; //!&lt; The Secure Channel Protocol.
      BYTE secureChannelProtocolImpl; //!&lt; The Secure Channel Protocol implementation.
      BYTE C_MACSessionKey[32]; //!&lt; The Secure Channel C-MAC session key.
      BYTE R_MACSessionKey[32]; //!&lt; The Secure Channel R-MAC session key.
      BYTE encryptionSessionKey[32]; //!&lt; The Secure Channel encryption session key.
      BYTE dataEncryptionSessionKey[32]; //!&lt; Secure Channel data encryption key.
      /*
       * Philip Wendland: lastC_MAC must be 16 Bytes for SCP03 because the MAC chaining value
       * for MAC code generation is 16 Bytes (according to GP 2.2 Amendment D), not 8.
       */
      BYTE lastC_MAC[16]; //!&lt; The last computed C-MAC. Only 8 byte used for SCP01 and SCP02. Used as MAC Chaining Value for SCP03.
      BYTE lastR_MAC[8]; //!&lt; The last computed R-MAC.
      /* Augusto: added two more attributes for key information */
      BYTE keySetVersion; //!&lt; The keyset version used in secure channel
      BYTE keyIndex; //!&lt; The key index used in secured channel
      BYTE invokingAid[16]; //!&lt; The invoking AID used for the mutual authentication.
      DWORD invokingAidLength; //!&lt; The length of the invoking AID buffer.
      LONG sessionEncryptionCounter; //!&lt; Session counter for SCP03 ICV encryption.
      DWORD keyLength; //!&lt; The key length. 16,24 or 32 bytes.
  } GP211_SECURITY_INFO;
  </code></pre>
  <p>And in C# I marshalled the struct like this:</p>
  <pre><code>[StructLayout(LayoutKind.Sequential)]
  public class GP211_SECURITY_INFO
  {
  public byte securityLevel;
  public byte secureChannelProtocol;
  public byte secureChanngelProtocolImpl;
  [MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)]
  public byte[] C_MACSessionKey;
  [MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)]
  public byte[] R_MACSessionKey;
  [MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)]
  public byte[] encryptionSessionKey;
  [MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)]
  public byte[] dataEncryptionSessionKey;           
  [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)]
  public byte[] lastC_MAC;
  [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]
  public byte[] lastR_MAC;
  public byte keySetVersion;
  public byte keyIndex;
  [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)]
  public byte[] invokingAid;
  public int invokingAidLength;
  public long sessionEncryptionCounter;        // long
  public int keyLength;
  }
  </code></pre>
  <p>Any suggestion to fix the error? Or is there any things that I missing on?</p>
  <p>Update:
  I initialized the array in the struct as follow and managed to get pass the error above:</p>
  <pre><code>GlobalPlatform.GP211_SECURITY_INFO secInfo = new GlobalPlatform.GP211_SECURITY_INFO();
  secInfo.C_MACSessionKey = new byte[32];
  secInfo.R_MACSessionKey = new byte[32];
  secInfo.dataEncryptionSessionKey = new byte[32];
  secInfo.lastC_MAC = new byte[16];
  secInfo.lastR_MAC = new byte[8];
  secInfo.invokingAid = new byte[16];
  </code></pre>
  <p>But other problems appeared:</p>
  <ol>
  <li>When printing the array of the struct in the C, the value is different with the value it has been initialized with. For example when initialized with zeros, it printed some random value.</li>
  <li>The function <code>GP211_mutual_authentication_wrapper</code> seems to be ran and exited just fine in the dll side, but in the C# side it caused <code>Exception thrown at 0x76B1C3A2 in ConsoleGP.exe: Microsoft C++ exception: unsigned long at memory location 0x010FDF70.</code> error when the function finished.</li>
  </ol>