У меня два клиента,
- первый клиент ожидает от CMS / PKCS проверки подписи
- второй клиент ожидает только подпись (EncryptedDigestMessage). Исходный файл и сертификат отдельно для проверки подписи
Итак, я хочу создать один метод, который должен возвращать соответствующий вывод в зависимости от формата (PKCS или 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
}
}
Я проверил PKCS с использованием метода ниже. подпись проверена, она возвращает истину.
//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;
}
Чтобы проверить данные SignOnly, я использую обычные классы Java security MessageDigest
и Cipher
.
параметры:
- signedData -> Signature
- fileBytes -> Исходное содержимое файла
- cert -> X509Certificate для расшифровки подписи
метод процесс:
- сгенерировать messageHa sh из исходного содержимого файла
- расшифровать подпись с помощью сертификата и получить decryptedMessageHa sh
- сравнить messageHa sh и decryptedMessageHa sh
Таким образом, расшифровка подписи проходит без ошибок. Итак, я понимаю, что это правильная подпись, которая подписана моим личным ключом, связанным с данным сертификатом. но оба messageHa sh и decryptedMessageHa sh имеют разные данные.
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);
}
Может ли кто-нибудь объяснить, какую ошибку я сделал?