基于Libgcrypt实现ECDH Curve25519密钥对生成的段错误求助
libgcrypt Curve25519密钥对生成段错误修复
在libgcrypt中实现ECDH时,共享密钥计算和对称加密逻辑正常,但密钥对生成过程中,gcry_mpi_ec_mul(mpi_public_key, mpi_private_key, NULL, ctx);行始终触发段错误,目标是将密钥存储为unsigned char*类型,原代码如下:
void generate_curve25519_keypair(unsigned char *public_key, unsigned char *private_key) { gcry_error_t error; gcry_mpi_t mpi_private_key; gcry_mpi_point_t mpi_public_key; gcry_ctx_t ctx; // Generate a random private key gcry_randomize(private_key, CURVE25519_KEY_SIZE, GCRY_STRONG_RANDOM); // Clamp the private key for Curve25519 private_key[0] &= 248; private_key[31] &= 127; private_key[31] |= 64; // Initialize the context for Curve25519 error = gcry_mpi_ec_new(&ctx, NULL, "Curve25519"); if (error) { fprintf(stderr, "Failed to create context: %s\n", gpg_strerror(error)); return; } // Convert the private key to an MPI error = gcry_mpi_scan(&mpi_private_key, GCRYMPI_FMT_USG, private_key, CURVE25519_KEY_SIZE, NULL); if (error) { fprintf(stderr, "Failed to convert private key to MPI: %s\n", gpg_strerror(error)); gcry_ctx_release(ctx); return; } // Allocate memory for the resulting public key point mpi_public_key = gcry_mpi_point_new(0); // Multiply the base point with the private key MPI to get the public key point gcry_mpi_ec_mul(mpi_public_key, mpi_private_key, NULL, ctx); // Use NULL for the default base point G if (error) { fprintf(stderr, "Failed to multiply with base point: %s\n", gpg_strerror(error)); gcry_mpi_release(mpi_private_key); gcry_mpi_point_release(mpi_public_key); gcry_ctx_release(ctx); return; } // Extract the x-coordinate of the public key point and convert it to a byte array gcry_mpi_t mpi_x = gcry_mpi_new(0); gcry_mpi_point_get(mpi_x, NULL, NULL, mpi_public_key); error = gcry_mpi_print(GCRYMPI_FMT_USG, public_key, CURVE25519_KEY_SIZE, NULL, mpi_x); if (error) { fprintf(stderr, "Failed to export public key: %s\n", gpg_strerror(error)); gcry_mpi_release(mpi_x); gcry_mpi_release(mpi_private_key); gcry_mpi_point_release(mpi_public_key); gcry_ctx_release(ctx); return; } // Release resources gcry_mpi_release(mpi_x); gcry_mpi_release(mpi_private_key); gcry_mpi_point_release(mpi_public_key); gcry_ctx_release(ctx); }
错误分析
- 未捕获
gcry_mpi_ec_mul返回错误:原代码调用该函数后未将返回值赋值给error,后续错误检查完全无效,无法定位函数调用本身的问题。 gcry_mpi_point_new参数错误:创建公钥点时传入0,导致点对象未关联Curve25519的上下文域参数,执行乘法操作时访问未初始化内存,直接引发段错误。正确做法是传入已创建的曲线上下文ctx。- 内存分配无空指针检查:
gcry_mpi_point_new、gcry_mpi_new等内存分配操作未检查返回值,存在潜在崩溃风险。 gcry_mpi_point_get未捕获错误:提取公钥坐标时未处理函数返回错误,无法定位提取失败的原因。
修正后代码
#include <gcrypt.h> #include <stdio.h> #include <string.h> #define CURVE25519_KEY_SIZE 32 void generate_curve25519_keypair(unsigned char *public_key, unsigned char *private_key) { gcry_error_t error; gcry_mpi_t mpi_private_key; gcry_mpi_point_t mpi_public_key; gcry_ctx_t ctx; // 生成随机私钥 gcry_randomize(private_key, CURVE25519_KEY_SIZE, GCRY_STRONG_RANDOM); // Curve25519私钥钳位处理 private_key[0] &= 248; private_key[31] &= 127; private_key[31] |= 64; // 初始化Curve25519上下文 error = gcry_mpi_ec_new(&ctx, NULL, "Curve25519"); if (error) { fprintf(stderr, "创建上下文失败: %s\n", gpg_strerror(error)); return; } // 将私钥转换为MPI error = gcry_mpi_scan(&mpi_private_key, GCRYMPI_FMT_USG, private_key, CURVE25519_KEY_SIZE, NULL); if (error) { fprintf(stderr, "私钥转MPI失败: %s\n", gpg_strerror(error)); gcry_ctx_release(ctx); return; } // 关联上下文创建公钥点对象(核心修复:传入ctx而非0) mpi_public_key = gcry_mpi_point_new(ctx); if (!mpi_public_key) { fprintf(stderr, "公钥点内存分配失败\n"); gcry_mpi_release(mpi_private_key); gcry_ctx_release(ctx); return; } // 私钥乘基点生成公钥,捕获返回错误 error = gcry_mpi_ec_mul(mpi_public_key, mpi_private_key, NULL, ctx); if (error) { fprintf(stderr, "基点乘法失败: %s\n", gpg_strerror(error)); gcry_mpi_release(mpi_private_key); gcry_mpi_point_release(mpi_public_key); gcry_ctx_release(ctx); return; } // 提取公钥点的x坐标 gcry_mpi_t mpi_x = gcry_mpi_new(0); if (!mpi_x) { fprintf(stderr, "MPI内存分配失败\n"); gcry_mpi_release(mpi_private_key); gcry_mpi_point_release(mpi_public_key); gcry_ctx_release(ctx); return; } error = gcry_mpi_point_get(mpi_x, NULL, NULL, mpi_public_key); if (error) { fprintf(stderr, "提取公钥x坐标失败: %s\n", gpg_strerror(error)); gcry_mpi_release(mpi_x); gcry_mpi_release(mpi_private_key); gcry_mpi_point_release(mpi_public_key); gcry_ctx_release(ctx); return; } // 将x坐标转换为字节数组 error = gcry_mpi_print(GCRYMPI_FMT_USG, public_key, CURVE25519_KEY_SIZE, NULL, mpi_x); if (error) { fprintf(stderr, "导出公钥失败: %s\n", gpg_strerror(error)); gcry_mpi_release(mpi_x); gcry_mpi_release(mpi_private_key); gcry_mpi_point_release(mpi_public_key); gcry_ctx_release(ctx); return; } // 释放资源 gcry_mpi_release(mpi_x); gcry_mpi_release(mpi_private_key); gcry_mpi_point_release(mpi_public_key); gcry_ctx_release(ctx); }
关键修复说明
gcry_mpi_point_new(ctx):确保公钥点对象关联Curve25519的域参数,避免操作未初始化内存引发段错误。- 完善错误捕获:新增
gcry_mpi_ec_mul、gcry_mpi_point_get等关键函数的错误检查,便于定位问题。 - 内存分配检查:对所有内存分配操作添加空指针检查,避免潜在崩溃。
内容的提问来源于stack exchange,提问作者CWorkMakesTheDreamWork
相关产品推荐
相关产品推荐

