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

时间:2011-06-21 20:50:48

标签: java delphi translation capicom

我有一个使用证书签名字符串的java应用程序。它使用SHA1加密字符串。我正在尝试将代码转换为Delphi 2010,但我不知道如何让它以与java应用程序相同的方式运行(使用sha1)。到目前为止,我发现了这个:

Delphi 7 access Windows X509 Certificate Store

它确实有效,但它不使用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;

德尔福代码

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常量以及一个哈希类,也许我应该使用这些类,但我不知道如何。

2 个答案:

答案 0 :(得分:3)

我们在一些与我们的Java Tomcat App接口的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;

答案 1 :(得分:0)

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

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

第三,你必须知道有关CAPICOM的内容:“content”属性是一个广泛的字符串。这具有各种含义,包括将所有内容填充到16位的事实。如果您的输入数据大小不同,您将得到不同的结果。

  

基于java代码,我应该以二进制格式获取证书信息,在它上面应用sha1并将它们转换为十六进制?

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

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

  

这是正确的顺序和java代码的相同吗?

是和否。 Java代码在显式细节中执行所有必要的步骤,这是您没有(实际上不能)使用CAPICOM的。但它应该会产生兼容的结果。

它还有一个与签名本身无关的附加步骤:我不确定它的作用,因为它似乎创建了一个虚拟证书信息数据并存储了已签名CMS消息的SHA-1哈希值并返回结果实例。我想这是Java dev发现将哈希值传递回调用者的方式。

  

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

HashedData类用于(惊讶)哈希数据。它与Signeddata具有相同的限制,即它只适用于宽带,因此与其他框架的兼容性充其量是狡猾的。

最后注意事项:Windows通过CAPI功能组提供对更全面的加密功能的访问。 CAPICOM只是该库的接口,主要用于脚本语言(网页上的JavaScript,VB等)。你应该帮个忙,尝试使用它而不是CAPICOM,因为很有可能你会遇到使用CAPICOM无法正常使用的东西。在那个阶段,您将不得不使用CAPI(或其他库)为您的所有应用程序重写部分。因此,如果您没有要求使用它,请立即节省时间并跳过CAPICOM。