我正在开发一个Java类,以PKCS7格式签名文本文件。我发现可以使用Sun库而不是BouncyCastle进行此操作,因此我开发了以下方法:
For i = 0 to 20
Graph1Bar(i).Height = 200
Next
当我尝试在在线验证器https://www.receita.fazenda.gov.br/Aplicacoes/SSL/ATBHE/assinadoc/ValidadorAssinaturas.app/valida.aspx中验证结果文件时,收到以下错误消息:
ASN1损坏的数据
我检查了签名,她很好。我相信错误在于在生成PKCS7结果时进行som数据转换。
有人遇到过这个问题吗?以及如何在Java代码中验证PCKS7结果?
答案 0 :(得分:0)
我不知道您如何检查签名,除了您的代码中无意义的检查会重复错误之外,但它是错误的数据,并且由于您没有向我们展示AlgoritmoAssinatura
也许是错误的方法。您还有其他一些错误。而不是详细说明所有示例,下面是一个产生有效结果并带有注释注释的示例:
// use test data for example
KeyStore ks = KeyStore.getInstance("JKS"); ks.load(new FileInputStream (args[0]), args[1].toCharArray());
PrivateKey PrivKey = (PrivateKey) ks.getKey (args[2], args[1].toCharArray());
X509Certificate Certif = (X509Certificate) ks.getCertificate(args[2]);
String Message = "test";
String ArquivoAssinar = args[3];
String Charset = "ASCII"; // no idea, see below
String SrtResultPKCS7 = "";
byte[] Conteudo = Message.getBytes(Charset);
byte[] Hash;
//String DadosArq = "";
//String Linha = "";
//boolean AssinValid = false;
try {
// the name in SignerInfo is the _Issuer_ name NOT the Subject
X500Name xName = X500Name.asX500Name(Certif.getIssuerX500Principal());
BigInteger serial = Certif.getSerialNumber();
AlgorithmId digestAlgorithmId = new AlgorithmId(AlgorithmId.SHA_oid);
AlgorithmId signAlgorithmId = new AlgorithmId(AlgorithmId.RSAEncryption_oid);
MessageDigest MessDig = MessageDigest.getInstance("SHA1");
Hash = MessDig.digest(Conteudo);
PKCS9Attribute Atributo1 = new PKCS9Attribute(PKCS9Attribute.CONTENT_TYPE_OID, ContentInfo.DATA_OID);
PKCS9Attribute Atributo2 = new PKCS9Attribute(PKCS9Attribute.MESSAGE_DIGEST_OID, Hash);
PKCS9Attributes ConjuntoAtrib = new PKCS9Attributes(new PKCS9Attribute[] {Atributo1, Atributo2});
// when using signedattrs, signature is of the encoded attrs
// (without the context-implicit tag used when embedded in SignerInfo)
Signature Sign = Signature.getInstance("SHA1withRSA");
Sign.initSign(PrivKey);
Sign.update(ConjuntoAtrib.getDerEncoding());
byte[] ResultadoAssinatura = Sign.sign();
SignerInfo sInfo = new SignerInfo(xName, serial, digestAlgorithmId, ConjuntoAtrib, signAlgorithmId, ResultadoAssinatura, null);
// contenttype inside signed-data is data not digested-data
ContentInfo cInfo = new ContentInfo(ContentInfo.DATA_OID, new DerValue(DerValue.tag_OctetString, Conteudo));
PKCS7 p7 = new PKCS7(new AlgorithmId[] { digestAlgorithmId }, cInfo, new java.security.cert.X509Certificate[] { Certif }, new SignerInfo[] { sInfo });
ByteArrayOutputStream bOut = new DerOutputStream();
p7.encodeSignedData(bOut);
byte[] encoded = bOut.toByteArray();
// Java doesn't define a class 'Encoder' so I assume this is base64
SrtResultPKCS7 = DatatypeConverter.printBase64Binary(encoded); // gone in 11!
FileOutputStream Saida = new FileOutputStream(ArquivoAssinar);
OutputStreamWriter Escritor = new OutputStreamWriter(Saida, Charset);
BufferedWriter BuffWriter = new BufferedWriter(Escritor);
// this was correct for base64 (although the buffering is wasted)
BuffWriter.write(SrtResultPKCS7);
// this was nonsense -- it decodes the DER bytes as if they were characters,
// which they aren't, and then OSW re-encodes them to probably wrong bytes
//BuffWriter.write(bOut.toString());
BuffWriter.close();
// alternatively could write DER/binary with a Stream (NOT a Writer)
}
catch (Exception E) {
E.printStackTrace();
}
我不清楚您(或链接的网站)需要哪种输出格式。 使用二进制/ DER非常普遍,但是不能被剪切和粘贴,并且更难使用。 DER的Base64很少见,但并非未知。如果您或他们想要由许多软件使用的标准PEM格式,那不只是DER的base64;它是DER PLUS换行符的base64,每64个字符换行,并添加了破折号-BEGIN和破折号-END行。
此外,SHA-1因碰撞而被打破了一年多;请参阅https://shattered.io以及有关密码学,安全性和安全性的大量问答。甚至在此之前,自2014年或2015年以来,包括NIST(美国政府)和CABforum(公共网络证书)在内的许多机构都禁止签名。我对您正在签名的数据一无所知,但是如果它在任何方面都很重要或有价值,并且您可以选择在签名中使用更好的哈希,则应该这样做。
添加:另外,我想您也意识到sun.*
类没有记录,不能保证,并且可能会在Oracle感到满意时停止工作。