基于OpenSSL-1_0_2o的ECDH代码及ctypes Pointer与CFUNCTYPE使用问询
Pointer and CFUNCTYPE Hey there! Let’s walk through how to work with your OpenSSL-based ECDH implementation using ctypes’ Pointer and CFUNCTYPE—I’ll break this down with practical examples tied directly to your code.
First, Let’s Recap Your C Code
Here’s your provided ECDH and KDF implementation, formatted for clarity:
void *KDF_MD5(const void *in, size_t inlen, void *out, size_t *outlen) { MD5_CTX ctx; MD5_Init(&ctx); MD5_Update(&ctx, in, inlen); MD5_Final((unsigned char*)out, &ctx); *outlen = MD5_DIGEST_LENGTH; return out; } bool DoEcdh(int nid, unsigned char * szServerPubKey, int nLenServerPub, unsigned char * szLocalPriKey, int nLenLocalPri, unsigned char * szShareKey, ...) { // Your ECDH key exchange logic here }
Working with CFUNCTYPE to Wrap C Functions
CFUNCTYPE lets you define the exact signature of your C functions so ctypes knows how to safely call them from Python. Here’s how to apply it to your two functions:
Wrapping KDF_MD5
This function returns a void* and takes four parameters. We’ll declare its type first, then bind it to your loaded shared library:
from ctypes import CFUNCTYPE, c_void_p, c_size_t, POINTER, c_ubyte, c_bool, c_int # Declare the function signature for KDF_MD5 KDF_MD5_SIG = CFUNCTYPE( c_void_p, # Return type: void* c_void_p, # const void* in c_size_t, # size_t inlen c_void_p, # void* out POINTER(c_size_t) # size_t* outlen ) # Assume you've loaded your compiled shared library (e.g., libecdh.so / ecdh.dll) as 'lib' kdf_md5 = KDF_MD5_SIG(("KDF_MD5", lib))
Wrapping DoEcdh
Since DoEcdh uses variable arguments (...), we’ll declare the fixed parameters first—ctypes handles varargs by letting you pass extra arguments directly when calling the function:
# Declare the fixed signature for DoEcdh DO_ECDH_SIG = CFUNCTYPE( c_bool, # Return type: bool c_int, # int nid POINTER(c_ubyte), # unsigned char* szServerPubKey c_int, # int nLenServerPub POINTER(c_ubyte), # unsigned char* szLocalPriKey c_int, # int nLenLocalPri POINTER(c_ubyte), # unsigned char* szShareKey # Varargs are omitted here; pass them as extra args when calling ) do_ecdh = DO_ECDH_SIG(("DoEcdh", lib))
Using Pointer (POINTER) for Buffer Parameters
Your C functions rely heavily on pointers for input/output buffers—here’s how to handle these in Python:
Input Buffers (e.g., szServerPubKey, szLocalPriKey)
Convert your Python bytes objects into ctypes arrays, then retrieve their pointers:
# Example: Server public key as bytes server_pub_key = b"\x04\x1a\x2b..." # Replace with your actual public key bytes # Create a ctypes array and get its pointer server_pub_ptr = (c_ubyte * len(server_pub_key)).from_buffer_copy(server_pub_key) # Same logic applies to local private key local_pri_key = b"\x01\x02\x03..." local_pri_ptr = (c_ubyte * len(local_pri_key)).from_buffer_copy(local_pri_key)
Output Buffers (e.g., szShareKey)
Allocate a buffer of sufficient size, then pass its pointer to the function:
# For MD5-derived keys, we know the length is MD5_DIGEST_LENGTH (16 bytes) SHARE_KEY_LEN = 16 share_key_buf = (c_ubyte * SHARE_KEY_LEN)() # Allocate empty buffer share_key_ptr = POINTER(c_ubyte)(share_key_buf)
Pointer-to-Size Parameters (e.g., *outlen in KDF_MD5)
Use c_size_t to hold the length value, then pass its pointer to capture the output length:
out_len = c_size_t(0) out_len_ptr = POINTER(c_size_t)(out_len) # Call KDF_MD5 with your shared secret data input_data = b"your_shared_ecdh_secret" kdf_md5(input_data, len(input_data), share_key_buf, out_len_ptr) # Now out_len.value holds the actual digest length (16 for MD5) print(f"Generated key length: {out_len.value}")
Quick Tips to Avoid Headaches
- Match types exactly:
size_tin C maps toc_size_tin ctypes (notc_int—this is critical for avoiding bugs on 64-bit systems). - Buffer safety: Always ensure output buffers are large enough. If a function returns the required size first, call it twice: once to get the size, then again with an appropriately allocated buffer.
void*flexibility: You can cast any ctypes pointer toc_void_pif a function expects a genericvoid*parameter.
内容的提问来源于stack exchange,提问作者yensan

