delphi 如何通过CryptoAPI将证书从Windows证书存储导出为Base64字符串

j13ufse2  于 2022-12-23  发布在  Windows
关注(0)|答案(2)|浏览(230)

我已经得到了下面的C#代码来做我在主题中要求的事情:

public static void ExportCertificatesToFile(string FileName)
{
    stringBuilder builder = new StringBuilder();

    X509Store storeMy = new X509Store(StoreName.My);
    storeMy.Open(OpenFlags.ReadOnly);

    foreach (X509Certificate2 cert in storeMy.Certificates)
    {
        builder.AppendLine("-----BEGIN CERTIFICATE-----");   
              builder.AppendLine(Convert.ToBase64String(cert.Export(X509ContentType.Cert),  Base64FormattingOptions.InsertLineBreaks));
        builder.AppendLine("-----END CERTIFICATE-----");
    }

    storeMy.Close();

    File.WriteAllText(FileName, builder.ToString());
}

正是我想用 Delphi 使用CryptoAPI(JwaWinCrypt.pas)归档,我尝试了以下代码:

procedure TForm1.Button1Click(Sender: TObject);
var
  hStore: HCERTSTORE;
  CertContext: PCertContext;
  pszString: PAnsiChar;
  pchString: Cardinal;
begin
  hStore := CertOpenSystemStore(0, PChar('MY'));

  try
    CertContext := CertEnumCertificatesInStore(hStore, nil);
    while CertContext <> nil do
    begin
      pszString := '';
      pchString := 0;
      CryptBinaryToString(CertContext.pbCertEncoded, CertContext.cbCertEncoded,  CRYPT_STRING_BASE64, pszString, pchString);

      ShowMessage(StrPas(pszString));

      CertContext := CertEnumCertificatesInStore(hStore, CertContext);
    end;
  finally
    CertCloseStore(hStore, 0);
  end;
end;

问题是ShowMessage什么都不显示,字符串是空的。有人知道我做错了什么吗?

tf7tbtn2

tf7tbtn21#

CryptBinaryToString的文档是这样描述pszString参数的。
指向接收转换后字符串的缓冲区的指针。要计算必须分配以保存返回字符串的字符数,请将此参数设置为NULL。此函数将在pcchString指向的值中放置所需数量的字符,包括终止NULL字符。
您必须分配缓冲区,以便API函数可以填充它。您未能执行此操作。为了继续,您必须仔细阅读文档并遵守API的要求。
所以你需要像这样调用这个函数:

szString: AnsiString;
....
chString := 0;
CryptBinaryToString(CertContext.pbCertEncoded, CertContext.cbCertEncoded,  
    CRYPT_STRING_BASE64, nil, chString);
SetLength(szString, chString-1);
CryptBinaryToString(CertContext.pbCertEncoded, CertContext.cbCertEncoded,  
    CRYPT_STRING_BASE64, PAnsiChar(szString), chString);

您还应该检查CryptBinaryToString的返回值以检测故障,为了简洁起见,我省略了这一点。
我还假设你的是ANSI Delphi 。我假设是因为你使用了PAnsiChar

ybzsozfc

ybzsozfc2#

不应该是这样的吗:

String: AnsiString;
....
chString := 0;
CryptBinaryToString(CertContext.pbCertEncoded, CertContext.cbCertEncoded,  
    CRYPT_STRING_BASE64, nil, chString);
SetLength(szString, chString);
CryptBinaryToString(CertContext.pbCertEncoded, CertContext.cbCertEncoded,  
    CRYPT_STRING_BASE64, PAnsiChar(szString), chString);
SetLength(szString, chString);

对CryptBinaryToString的第一次调用返回包括NULL终止符的长度,因此调整字符串的大小以允许字符串数据和NULL终止符。
对CryptBinaryToString的第二次调用使用包括NULL终止符的字符串数据填充szString,但它返回的长度值不包括NULL终止符,因此只需再次调用SetLength来调整大小以删除NULL终止符。

相关问题