Невозможно проверить подпись с помощью двух разных механизмов - PullRequest
0 голосов
/ 06 августа 2020

У меня два клиента,

  1. первый клиент ожидает от CMS / PKCS проверки подписи
  2. второй клиент ожидает только подпись (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.

параметры:

  1. signedData -> Signature
  2. fileBytes -> Исходное содержимое файла
  3. cert -> X509Certificate для расшифровки подписи

метод процесс:

  1. сгенерировать messageHa sh из исходного содержимого файла
  2. расшифровать подпись с помощью сертификата и получить decryptedMessageHa sh
  3. сравнить 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);
        
    }

Может ли кто-нибудь объяснить, какую ошибку я сделал?

...