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

Nim语言中使用OpenSSL实现RSA加密的指针问题求助

Nim中使用OpenSSL实现RSA加密解密的指针与内存问题解决

你的代码运行时出现段错误的核心原因有三个:一是res和decRes未分配内存就直接传递nil指针,二是使用RSA_NO_PADDING但输入长度不符合该模式要求,三是未正确释放OpenSSL相关资源。下面是修复后的完整代码,附带关键修改的说明:

import openssl, system, strutils

proc main() =
  var publicRsa: PRSA
  var privateRsa: PRSA
  let publicKeyStr = readAll(open("keys/public.pem", fmRead))
  let privateKeyStr = readAll(open("keys/private.pem", fmRead))

  # 创建内存BIO并加载公钥,用完及时释放BIO
  let pubBio = BIO_new_mem_buf(addr publicKeyStr[0], -1)
  publicRsa = PEM_read_bio_RSA_PUBKEY(pubBio, addr publicRsa, nil, nil)
  BIO_free(pubBio)

  # 创建内存BIO并加载私钥,用完及时释放BIO
  let privBio = BIO_new_mem_buf(addr privateKeyStr[0], -1)
  privateRsa = PEM_read_bio_PrivateKey(privBio, addr privateRsa, nil, nil)
  BIO_free(privBio)

  # 检查密钥加载是否成功
  if publicRsa.isNil():
    echo "ERROR: Could not load PUBLIC KEY!"
    echo $ERR_error_string(ERR_get_error(), nil)
    return
  if privateRsa.isNil():
    echo "ERROR: Could not load PRIVATE KEY!"
    echo $ERR_error_string(ERR_get_error(), nil)
    return

  let msg = "Hello World!"
  let rsaKeySize = RSA_size(publicRsa)

  # 分配加密结果内存,用defer保证函数退出时自动释放
  var encrypted = cast[ptr uint8](alloc(rsaKeySize))
  defer: dealloc(encrypted)

  # 使用PKCS#1标准填充加密,输入长度限制为 密钥长度-11
  let encLen = RSA_public_encrypt(
    cint(msg.len),
    cast[ptr uint8](addr msg[0]),
    encrypted,
    publicRsa,
    RSA_PKCS1_PADDING
  )

  if encLen == -1:
    echo "Encryption failed: ", $ERR_error_string(ERR_get_error(), nil)
    return

  # 分配解密结果内存,同样用defer自动释放
  var decrypted = cast[ptr uint8](alloc(rsaKeySize))
  defer: dealloc(decrypted)

  # 执行解密
  let decLen = RSA_private_decrypt(
    encLen,
    encrypted,
    decrypted,
    privateRsa,
    RSA_PKCS1_PADDING
  )

  if decLen == -1:
    echo "Decryption failed: ", $ERR_error_string(ERR_get_error(), nil)
    return

  # 将解密后的指针转换为Nim字符串
  let decryptedStr = newString(decLen)
  copyMem(addr decryptedStr[0], decrypted, decLen)

  echo "Original message: ", msg
  echo "Decrypted message: ", decryptedStr

  # 释放RSA对象
  RSA_free(publicRsa)
  RSA_free(privateRsa)

when isMainModule:
  main()

关键修改说明

  • 内存分配与释放

    • 用system.alloc为加密/解密结果分配内存,长度通过RSA_size(publicRsa)获取(返回RSA密钥的字节长度,比如2048位密钥对应256字节)
    • 用defer语句绑定内存释放操作,确保函数退出时自动清理,避免内存泄漏
    • 加载密钥时创建的BIO对象必须用BIO_free释放,RSA对象用RSA_free释放
  • 填充模式修正

    • 替换RSA_NO_PADDING为RSA_PKCS1_PADDING:无填充模式要求输入长度必须和密钥长度完全一致,几乎不适用于普通短消息;PKCS#1是标准安全填充,允许输入长度为密钥长度-11,符合大多数场景需求
  • 指针转字符串

    • 先用newString(decLen)创建指定长度的空Nim字符串
    • 用system.copyMem将解密后的指针内容复制到字符串缓冲区,直接得到可正常使用的Nim字符串
  • 错误处理增强

    • 检查RSA_public_encrypt和RSA_private_decrypt的返回值(返回-1表示操作失败),并输出OpenSSL的错误信息

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.26 01:30:25