Capicom和SHA1-帮助将java代码翻译成Delphi



我有一个java应用程序,它使用证书对字符串进行签名。它使用SHA1对字符串进行加密。我正试图将代码翻译成Delphi2010,但我不知道如何让它像java应用程序一样工作(使用sha1)。到目前为止,我发现了这个:

Delphi 7访问Windows X509证书存储

它确实有效,但它不使用sha1,当我运行java应用程序时,我会得到不同的结果。

Java代码

 char[] pass = (char[]) null;
 PrivateKey key = (PrivateKey) getKeyStore().getKey(alias, pass);
 Certificate[] chain = getKeyStore().getCertificateChain(alias);
 CertStore certsAndCRLs = CertStore.getInstance("Collection", new CollectionCertStoreParameters(Arrays.asList(chain)), "BC");
 X509Certificate cert = (X509Certificate) chain[0];
 CMSSignedDataGenerator gen = new CMSSignedDataGenerator();
 gen.addSigner(key, cert, CMSSignedDataGenerator.DIGEST_SHA1);
 gen.addCertificatesAndCRLs(certsAndCRLs);
 CMSProcessable data = new CMSProcessableByteArray(conteudoParaAssinar);
 CMSSignedData signed = gen.generate(data, true, "SunMSCAPI");
 byte[] envHex = signed.getEncoded();
 CertInfo certInfo = new CertInfo();
 certInfo.Hash = new BigInteger(envHex).toString(16);
 return certInfo;

Delphi代码

var
  lSigner: TSigner;
  lSignedData: TSignedData;
  fs: TFileStream;
  qt: integer;
  ch: PChar;
  msg : WideString;
  content : string;
  cert: TCertificate;
begin
  cert := Self.GetCert;
  content := 'test';
  lSigner := TSigner.Create(self);
  lSigner.Certificate := cert.DefaultInterface;
  lSignedData := TSignedData.Create(self);
  lSignedData.content := content;
  msg := lSignedData.Sign(lSigner.DefaultInterface, false, CAPICOM_ENCODE_BASE64);
  lSignedData.Free;
  lSigner.Free;

编辑

基于java代码,我应该获得二进制格式的证书信息,在上面应用sha1,然后他们将其转换为十六进制吗?这是正确的顺序,也是java代码所做的事情吗?我可以在capicom tlb中看到一些SHA1常量以及一个哈希类,也许我应该使用这些类,但我不知道如何使用。

我们在一些与Java Tomcat应用程序接口的delphi应用程序中使用DCPCrypt,并能够获得与SHA-256兼容的哈希。我怀疑SHA1也很容易。

这里有一个的例子

function Sha256FileStreamHash(fs : TFileStream): String;
var
    Hash: TDCP_sha256;
    Digest: array[0..31] of byte;  // RipeMD-160 produces a 160bit digest (20bytes)
    i: integer;
    s: string;
begin
  if fs <> nil then
  begin
    fs.Seek(0, soFromBeginning);
    Hash:= TDCP_sha256.Create(nil);          // create the hash
    try
      Hash.Init;                                   // initialize it
      Hash.UpdateStream(fs,fs.Size);       // hash the stream contents
      Hash.Final(Digest);                          // produce the digest
      s:= '';
      for i:= 0 to 31 do
        s:= s + IntToHex(Digest[i],2);
      Result:= s;                              // display the digest
    finally
      Hash.Free;
    end;
  end;
end;

首先,是什么让你认为你没有使用SHA-1?我这么问是因为CAPICOM的签名功能只适用于SHA-1签名。

第二,你怎么知道你得到了不同的结果?你试过验证答案了吗?如果是,使用什么?

第三,关于CAPICOM,您必须了解一些内容:"content"属性是一个宽字符串。这有各种含义,包括所有内容都将被填充到16位。如果你的输入数据大小不同,你会得到不同的结果。

基于java代码,我应该获得二进制格式的证书信息,在上面应用sha1,然后他们将其转换为十六进制吗?

没有。您可以获得一个到ICertificate对象实例(或者更可能是ICertificate2)的接口,然后直接使用它。如果您有B64编码版本的证书,您可以创建一个新的ICertificate实例,然后调用ICertificte。导入方法。证书本身的哈希仅由签名机构用于对特定证书进行签名。

哈希算法实际上在数据签名过程中使用:库读取数据,创建该数据的哈希(在CAPICOM的情况下使用SHA-1),然后对该哈希值进行数字签名。这种减少是必要的,因为对整个数据块进行签名太慢了,而且这样,如果你使用硬件加密系统,你只需要携带哈希。

这是正确的顺序,也是java代码所做的事情吗?

是和否。Java代码以明确的细节完成了所有必要的步骤,这是CAPICOM所没有的(实际上也不能)。不过,它应该会产生兼容的结果。

它还有一个与签名本身无关的附加步骤:我不确定它做了什么,因为它似乎创建了一个伪证书信息数据,存储了签名CMS消息的SHA-1哈希值,并返回结果实例。我想这是Java开发人员找到的将散列值传递回调用方的一种方式。

我可以在capicom tlb中看到一些SHA1常量以及一个哈希类,也许我应该使用这些类,但我不知道如何使用。

HashedData类用于(意外)散列数据。它与Signeddata有着相同的局限性,即它只适用于宽字符串,因此与其他框架的兼容性充其量是不可靠的。

最后一点:Windows通过CAPI函数组提供了对更全面的加密函数的访问。CAPICOM只是该库的一个接口,主要用于脚本语言(网页上的JavaScript、VB等)。你应该帮自己一个忙,试着用它代替CAPICOM,因为你很有可能会遇到一些你根本无法正确使用CAPICOM的事情。在那个阶段,您将不得不使用CAPI(或另一个库)重写所有应用程序的一部分。因此,现在节省时间,如果您没有使用CAPICOM的要求,请跳过它。

最新更新