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
相关产品推荐
相关产品推荐

