You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于OpenSSL-1_0_2o的ECDH代码及ctypes Pointer与CFUNCTYPE使用问询

Handling ECDH Code with ctypes 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_t in C maps to c_size_t in ctypes (not c_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 to c_void_p if a function expects a generic void* parameter.

内容的提问来源于stack exchange,提问作者yensan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.25 07:02:26