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

Delphi实现OpenSSL签名转Base64并跨应用公钥解密求助

解决Delphi Chilkat与OpenSSL签名结果不兼容的问题

咱们先梳理清楚你要模拟的OpenSSL命令的核心行为:

  • openssl dgst -sha1 -sign:读取输入文本的原始字节计算SHA-1哈希,然后用RSA私钥以PKCS#1 v1.5填充生成二进制签名(这是OpenSSL的默认填充规则)
  • openssl enc -base64 -A:把二进制签名编码为Base64,并且强制输出为单行(无换行)

你的Chilkat代码有几个关键细节没和OpenSSL对齐,导致其他应用用公钥无法解密/验证,下面逐一修正:

1. 字节序设置错误

OpenSSL的RSA签名默认使用大端字节序,但你代码里设置了CkRsa_putLittleEndian(rsa,True);,这直接导致签名的字节顺序和OpenSSL完全相反,必须改成:

CkRsa_putLittleEndian(rsa, False);

2. 字符串编码不匹配

OpenSSL处理Imput.txt时是读取文件的原始字节(比如如果是UTF-8文本就用UTF-8字节,Windows系统默认编码就用对应字节),但你直接传递Addr(s[1])——Delphi默认的string是UTF-16编码的Unicode字符串,这样Chilkat处理的是UTF-16字节,和OpenSSL处理的原始文本字节完全不同,哈希结果自然不一致。

你需要把字符串转换成和输入文件一致的字节编码,比如用UTF-8的话:

var
  utf8Bytes: TBytes;
begin
  // ... 其他代码 ...
  utf8Bytes := TEncoding.UTF8.GetBytes(s);
  b64Sig := CkRsa__signBytesENC(rsa, @utf8Bytes[0], Length(utf8Bytes), 'sha1');
  // ... 其他代码 ...

如果你的Imput.txt是系统默认编码,就换成TEncoding.Default.GetBytes(s)。

3. Base64输出格式不对

OpenSSL的-A参数会生成无换行的单行Base64,但Chilkat默认会每76个字符换行,需要关闭这个设置:

CkRsa_putBd64LineLength(rsa, 0); // 0表示不添加换行符

4. 显式指定填充方式(避免默认值变更)

虽然Chilkat默认用的是PKCS#1 v1.5填充(和OpenSSL一致),但显式设置更稳妥,防止后续组件版本变更:

CkRsa_putPssPadding(rsa, False); // 关闭PSS填充,使用PKCS#1 v1.5
CkRsa_putSignatureHashAlgorithm(rsa, 'sha1');

修正后的完整代码

function Tf_invsign.EncSHAB64(s: string): String;
var
  pkey: HCkPrivateKey;
  success: Boolean;
  rsa: HCkRsa;
  b64Sig: PWideChar;
  utf8Bytes: TBytes;
begin
  addlog(s);
  pkey := CkPrivateKey_Create();
  try
    success := CkPrivateKey_LoadEncryptedPemFile(pkey, 'private.PEM', '');
    if not success then
    begin
      addlog(CkPrivateKey__lastErrorText(pkey));
      Exit;
    end;

    rsa := CkRsa_Create();
    try
      success := CkRsa_ImportPrivateKeyObj(rsa, pkey);
      if not success then
      begin
        addlog(CkRsa__lastErrorText(rsa));
        Exit;
      end;

      // 对齐OpenSSL的RSA配置
      CkRsa_putLittleEndian(rsa, False); // 大端字节序,匹配OpenSSL
      CkRsa_putEncodingMode(rsa, 'base64');
      CkRsa_putBd64LineLength(rsa, 0); // 单行Base64输出
      CkRsa_putPssPadding(rsa, False); // 使用PKCS#1 v1.5填充
      CkRsa_putSignatureHashAlgorithm(rsa, 'sha1');

      // 将字符串转换为UTF-8字节(和OpenSSL处理文本的方式一致)
      utf8Bytes := TEncoding.UTF8.GetBytes(s);
      b64Sig := CkRsa__signBytesENC(rsa, @utf8Bytes[0], Length(utf8Bytes), 'sha1');
      if b64Sig = nil then
      begin
        addlog(CkRsa__lastErrorText(rsa));
        Exit;
      end;

      Result := b64Sig;
    finally
      CkRsa_Dispose(rsa);
    end;
  finally
    CkPrivateKey_Dispose(pkey);
  end;
end;

验证方法

  1. 对比你的代码生成的Base64字符串和OpenSSL命令生成的OutB64.b64内容,应该完全一致
  2. 用OpenSSL验证你的签名:把代码生成的Base64解码成二进制文件,执行openssl dgst -sha1 -verify PublicKey.pem -signature your_signature.bin input.txt,应该返回Verified OK
  3. 也可以用Chilkat的VerifyStringENC方法验证,确保公钥能正常验证签名

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.08 18:12:45