====== 5.1 P/Invoke - Vključitev DLL-jev ======
Ta stran prikazuje, kako uporabljate OpenSSL preko P/Invoke v .NET.
----
===== Kaj je P/Invoke? =====
**P/Invoke** (Platform Invoke) omogoča klic funkcij nativnih DLL-jev iz .NET:
.NET koda → P/Invoke → libcrypto-3-x64.dll → OpenSSL
----
===== Priprava DLL-jev =====
==== 1. Kopiranje DLL-jev v projekt ====
cd MojProjekt
copy "D:\Projects\openssl-3.6.0\bin\bin\libcrypto-3-x64.dll" .\
copy "D:\Projects\openssl-3.6.0\bin\bin\libssl-3-x64.dll" .\
==== 2. Prilagoditev .csproj ====
net8.0
PreserveNewest
PreserveNewest
----
===== Preprost primer P/Invoke =====
using System;
using System.Runtime.InteropServices;
namespace MojProjekt;
///
/// OpenSSL P/Invoke Bindings
///
public static class OpenSslInterop
{
private const string LIBCRYPTO = "libcrypto-3-x64.dll";
// Inicializacija
[DllImport(LIBCRYPTO, CallingConvention = CallingConvention.Cdecl)]
public static extern int OPENSSL_init_crypto(ulong opts, IntPtr settings);
// Pridobitev različice
[DllImport(LIBCRYPTO, CallingConvention = CallingConvention.Cdecl)]
public static extern IntPtr OpenSSL_version(int type);
// Konstante
public const int OPENSSL_VERSION_STRING = 6;
public const ulong OPENSSL_INIT_LOAD_CRYPTO_STRINGS = 0x00000002;
public const ulong OPENSSL_INIT_ADD_ALL_CIPHERS = 0x00000004;
public const ulong OPENSSL_INIT_ADD_ALL_DIGESTS = 0x00000008;
///
/// Inicializira OpenSSL
///
public static void Initialize()
{
OPENSSL_init_crypto(
OPENSSL_INIT_LOAD_CRYPTO_STRINGS |
OPENSSL_INIT_ADD_ALL_CIPHERS |
OPENSSL_INIT_ADD_ALL_DIGESTS,
IntPtr.Zero);
}
///
/// Vrne različico OpenSSL
///
public static string GetVersion()
{
var ptr = OpenSSL_version(OPENSSL_VERSION_STRING);
return Marshal.PtrToStringAnsi(ptr) ?? "Unknown";
}
}
// Uporaba:
class Program
{
static void Main()
{
OpenSslInterop.Initialize();
Console.WriteLine($"OpenSSL Version: {OpenSslInterop.GetVersion()}");
}
}
----
===== Generiranje ML-DSA ključev =====
public static class MlDsaInterop
{
private const string LIBCRYPTO = "libcrypto-3-x64.dll";
[DllImport(LIBCRYPTO)] private static extern IntPtr EVP_PKEY_CTX_new_from_name(IntPtr libctx, string name, IntPtr propq);
[DllImport(LIBCRYPTO)] private static extern int EVP_PKEY_keygen_init(IntPtr ctx);
[DllImport(LIBCRYPTO)] private static extern int EVP_PKEY_keygen(IntPtr ctx, out IntPtr pkey);
[DllImport(LIBCRYPTO)] private static extern void EVP_PKEY_CTX_free(IntPtr ctx);
[DllImport(LIBCRYPTO)] private static extern void EVP_PKEY_free(IntPtr pkey);
[DllImport(LIBCRYPTO)] private static extern int i2d_PrivateKey(IntPtr pkey, ref IntPtr pp);
[DllImport(LIBCRYPTO)] private static extern int i2d_PUBKEY(IntPtr pkey, ref IntPtr pp);
[DllImport(LIBCRYPTO)] private static extern void OPENSSL_free(IntPtr ptr);
///
/// Generira par ključev ML-DSA-65
///
public static (byte[] privateKey, byte[] publicKey) GenerateMlDsa65KeyPair()
{
IntPtr ctx = EVP_PKEY_CTX_new_from_name(IntPtr.Zero, "mldsa65", IntPtr.Zero);
if (ctx == IntPtr.Zero)
throw new Exception("Failed to create context");
try
{
if (EVP_PKEY_keygen_init(ctx) <= 0)
throw new Exception("Failed to init keygen");
IntPtr pkey;
if (EVP_PKEY_keygen(ctx, out pkey) <= 0)
throw new Exception("Failed to generate key");
try
{
// Izvoz zasebnega ključa
IntPtr privPtr = IntPtr.Zero;
int privLen = i2d_PrivateKey(pkey, ref privPtr);
byte[] privateKey = new byte[privLen];
Marshal.Copy(privPtr, privateKey, 0, privLen);
OPENSSL_free(privPtr);
// Izvoz javnega ključa
IntPtr pubPtr = IntPtr.Zero;
int pubLen = i2d_PUBKEY(pkey, ref pubPtr);
byte[] publicKey = new byte[pubLen];
Marshal.Copy(pubPtr, publicKey, 0, pubLen);
OPENSSL_free(pubPtr);
return (privateKey, publicKey);
}
finally
{
EVP_PKEY_free(pkey);
}
}
finally
{
EVP_PKEY_CTX_free(ctx);
}
}
}
----
===== Popoln razred Interop =====
Za popolno implementacijo P/Invoke glejte:
→ [[wvds:sl:pq_crypto:api:start|WvdS.System.Security.Cryptography API]]
Ta knjižnica vsebuje:
* ML-DSA podpisovanje/preverjanje
* ML-KEM enkapsulacija/dekapsulacija
* X.509 certifikati s PQ algoritmi
* Hibridni podpisi
----
===== Pogoste napake =====
==== "DLL not found" ====
System.DllNotFoundException: Unable to load DLL 'libcrypto-3-x64.dll'
**Rešitev:**
- DLL-ji v izhodnem imeniku (bin/Debug/) prisotni?
- .csproj ''CopyToOutputDirectory'' pravilno?
- Platforma se ujema? (x64 vs x86)
==== "Entry point not found" ====
System.EntryPointNotFoundException: Unable to find entry point 'XYZ'
**Rešitev:**
- Ime funkcije pravilno napisano?
- ''CallingConvention.Cdecl'' nastavljeno?
- Različica OpenSSL podpira funkcijo?
==== Puščanje pomnilnika ====
**Vedno sprostite vire!**
* ''EVP_PKEY_free(pkey)''
* ''EVP_PKEY_CTX_free(ctx)''
* ''OPENSSL_free(ptr)''
----
===== Nasveti =====
**LibraryImport namesto DllImport (od .NET 7)**
// Sodoben pristop
[LibraryImport("libcrypto-3-x64.dll")]
public static partial int OPENSSL_init_crypto(ulong opts, IntPtr settings);
----
===== Naprej na =====
* [[.:nuget-grundlagen|Ustvarjanje NuGet paketa]]
* [[.:blazor-wasm|Blazor WASM integracija]]
* [[wvds:sl:openssl:verteilung:start|6. Distribucija]]
----
//Wolfgang van der Stille @ EMSR DATA d.o.o. - Post-Quantum Cryptography Professional//