问题
I have two clients,
- first client expect CMS/PKCS to verify signature
- second client expect only signature (EncryptedDigestMessage). Original file and certificate separately to verify signature
So, I want to create one method that should return the appropriate output based on format (PKCS or SignOnly)
public static byte[] digitalSign(byte[] fileContent , PrivateKey privkey , X509Certificate x509Certificate , String format) throws Exception{
Security.addProvider(new BouncyCastleProvider());
List<X509Certificate> certList = new ArrayList<X509Certificate>();
CMSTypedData data = new CMSProcessableByteArray(fileContent);
certList.add(x509Certificate);
Store certs = new JcaCertStore(certList);
CMSSignedDataGenerator gen = new CMSSignedDataGenerator();
ContentSigner sha1Signer = new JcaContentSignerBuilder("MD5WithRSA").setProvider("BC").build(privkey);
gen.addSignerInfoGenerator(new JcaSignerInfoGeneratorBuilder(new JcaDigestCalculatorProviderBuilder().setProvider("BC").build()).build(sha1Signer,x509Certificate));
gen.addCertificates(certs);
CMSSignedData signedData = gen.generate(data, true);
//based on the format this method should return expected byte[]
if(format.equals("PKCS")){//should return CMS/PKCS package
return signedData.getEncoded();
}else{//should return only Signature (Encrypted Digest of fileContent)
SignerInformation signer = signedData.getSignerInfos().getSigners().iterator().next();
return signer.getSignature();// returns the Signature
}
}
I verified PKCS using below method. signature is verified it returns true.
//CMS/PKCS signature verification
public static boolean verfySignaturePKCS(byte[] cmsSignedBytes ) throws Exception{
boolean result = false;
Security.addProvider(new BouncyCastleProvider());
CMSSignedData cms =new CMSSignedData(cmsSignedBytes );
Store<X509CertificateHolder> certificates = cms.getCertificates();
SignerInformationStore signerInfos = cms.getSignerInfos();
Collection<SignerInformation> signers = signerInfos.getSigners();
Iterator<SignerInformation> iterator = signers.iterator();
while (iterator.hasNext()) {
SignerInformation signer = iterator.next();
Collection<X509CertificateHolder> certCollection = certificates.getMatches(signer.getSID());
Iterator<X509CertificateHolder> certIt = certCollection.iterator();
X509CertificateHolder certHolder = certIt.next();
X509Certificate cert = new JcaX509CertificateConverter().setProvider("BC").getCertificate(certHolder);
if (signer.verify(new JcaSimpleSignerInfoVerifierBuilder().setProvider("BC").build(cert))) {
result = true;
}
}
return result;
}
To verify that SignOnly data, I'm using normal Java security MessageDigest
and Cipher
classes.
parameters:
- signedData--> Signature
- fileBytes--> Original File content
- cert--> X509Certificate to decrypt the signature
method process:
- generate messageHash from original file content
- decrypt Signature with cert and get the decryptedMessageHash
- compare messageHash and decryptedMessageHash
In this way decrypt signature is going well without error. So I understand this is correct signature which is signed by my privatekey related to the given certificate. but, both messageHash and decryptedMessageHash having different data.
public static boolean verifySignOnly(byte[] signedData,byte[] fileBytes ,X509Certificate cert) throws Exception{
Security.addProvider(new BouncyCastleProvider());
MessageDigest md = MessageDigest.getInstance("MD5" , "BC");
byte[] messageHash = md.digest(fileBytes);
Cipher cipher = Cipher.getInstance("RSA" , "BC");
cipher.init(Cipher.DECRYPT_MODE, cert);
byte[] decryptedMessageHash = cipher.doFinal(signedData);
return Arrays.equals(decryptedMessageHash, messageHash);
}
Can anyone explain what mistake I made?
来源:https://stackoverflow.com/questions/63287608/unable-to-verify-the-signature-with-two-different-mechanism