private void tryRsaPkcs15Sig( String algorithm, byte[] data, PrivateKey signingKey, PublicKey verifyKey, ASN1ObjectIdentifier sigOid, ASN1ObjectIdentifier hashOid) throws Exception { Signature sig; byte[] sigBytes; sig = Signature.getInstance(algorithm, "BC"); sig.initSign(signingKey); sig.update(data); sigBytes = sig.sign(); sig.initVerify(verifyKey); sig.update(data); if (!sig.verify(sigBytes)) { fail(algorithm + " verification failed"); } Cipher c = Cipher.getInstance("RSA/NONE/PKCS1Padding", "BC"); c.init(Cipher.DECRYPT_MODE, verifyKey); DigestInfo digInfo = DigestInfo.getInstance(c.doFinal(sigBytes)); isTrue("digest alg not match", digInfo.getAlgorithmId().getAlgorithm().equals(hashOid)); sig = Signature.getInstance(sigOid.getId(), "BC"); sig.initSign(signingKey); sig.update(data); isTrue("sig not matched", Arrays.areEqual(sigBytes, sig.sign())); sig.initVerify(verifyKey); sig.update(data); if (!sig.verify(sigBytes)) { fail(algorithm + " oid verification failed"); } }
public static LogotypeReference getInstance(ASN1Sequence seq) { ASN1Sequence refStructHashSeq = null; ASN1Sequence refStructURISeq = null; if (seq.size() != 2) { throw new IllegalArgumentException("size of sequence must be 2 not " + seq.size()); } refStructHashSeq = ASN1Sequence.getInstance(seq.getObjectAt(0)); refStructURISeq = ASN1Sequence.getInstance(seq.getObjectAt(1)); DigestInfo[] refStructHash = null; DERIA5String[] refStructURI = null; { Vector<DigestInfo> v = new Vector<DigestInfo>(); for (int i = 0; i < refStructHashSeq.size(); i++) { DigestInfo di = DigestInfo.getInstance(refStructHashSeq.getObjectAt(i)); v.add(di); } refStructHash = v.toArray(new DigestInfo[refStructHashSeq.size()]); } { Vector<DERIA5String> v = new Vector<DERIA5String>(); for (int i = 0; i < refStructURISeq.size(); i++) { DERIA5String di = DERIA5String.getInstance(refStructURISeq.getObjectAt(i)); v.add(di); } refStructHash = v.toArray(new DigestInfo[refStructURISeq.size()]); } return new LogotypeReference(refStructHash, refStructURI); }
private DigestInfo derDecode(byte[] encoding) throws IOException, CMSException { if (encoding[0] != (DERTags.CONSTRUCTED | DERTags.SEQUENCE)) { throw new IOException("not a digest info object"); } ASN1InputStream aIn = new ASN1InputStream(encoding); DigestInfo digInfo = new DigestInfo((ASN1Sequence) aIn.readObject()); // length check to avoid Bleichenbacher vulnerability if (digInfo.getEncoded().length != encoding.length) { throw new CMSException("malformed RSA signature"); } return digInfo; }
public synchronized String generateSignature(byte[] message) throws Exception { // Log.trace("Signed message length is " + message.length); try { digest.reset(); cipher.init(true, privateRsaKey); digest.update(message, 0, message.length); byte[] hash = new byte[digest.getDigestSize()]; digest.doFinal(hash, 0); DigestInfo info = new DigestInfo(new AlgorithmIdentifier(md5, null), hash); byte[] bytes = info.getEncoded(ASN1Encoding.DER); byte[] signature = cipher.processBlock(bytes, 0, bytes.length); return new String(org.bouncycastle.util.encoders.Base64.encode(signature)); } catch (Exception e) { throw new Exception("Ошибка создания подписи:\n" + e.getMessage()); } }
/** @deprecated */ private boolean verifyDigest(byte[] digest, PublicKey key, byte[] signature, Provider sigProvider) throws NoSuchAlgorithmException, CMSException { String encName = CMSSignedHelper.INSTANCE.getEncryptionAlgName(this.getEncryptionAlgOID()); try { if (encName.equals("RSA")) { Cipher c = CMSEnvelopedHelper.INSTANCE.createAsymmetricCipher("RSA/ECB/PKCS1Padding", sigProvider); c.init(Cipher.DECRYPT_MODE, key); DigestInfo digInfo = derDecode(c.doFinal(signature)); if (!digInfo.getAlgorithmId().getObjectId().equals(digestAlgorithm.getObjectId())) { return false; } if (!isNull(digInfo.getAlgorithmId().getParameters())) { return false; } byte[] sigHash = digInfo.getDigest(); return Arrays.constantTimeAreEqual(digest, sigHash); } else if (encName.equals("DSA")) { Signature sig = CMSSignedHelper.INSTANCE.getSignatureInstance("NONEwithDSA", sigProvider); sig.initVerify(key); sig.update(digest); return sig.verify(signature); } else { throw new CMSException("algorithm: " + encName + " not supported in base signatures."); } } catch (GeneralSecurityException e) { throw new CMSException("Exception processing signature: " + e, e); } catch (IOException e) { throw new CMSException("Exception decoding signature: " + e, e); } }
public synchronized void verifySignature(byte[] message, byte[] signature) throws Exception { try { digest.reset(); cipher.init(false, publicRsaKey); digest.update(message, 0, message.length); byte[] hash = new byte[digest.getDigestSize()]; digest.doFinal(hash, 0); DigestInfo info = new DigestInfo(new AlgorithmIdentifier(md5, null), hash); byte[] bytes = info.getEncoded(ASN1Encoding.DER); byte[] signatureData = org.bouncycastle.util.encoders.Base64.decode(signature); byte[] result = cipher.processBlock(signatureData, 0, signatureData.length); if ((result == null) || (result.length < hash.length)) { throw new Exception("Invalid signature (1)!"); } if (!compareFromTheEnd(hash, result)) { throw new Exception("Invalid signature (2)!"); } } catch (Exception e) { throw new Exception("Error checking signature:\n" + e.getMessage()); } }
@Override protected void onDocumentSigned(byte[] byteArray) { try { InputStream inputStream = new ByteArrayInputStream(byteArray); PDDocument document = PDDocument.load(inputStream); List<PDSignature> signatures = document.getSignatureDictionaries(); assertEquals(1, signatures.size()); for (PDSignature pdSignature : signatures) { byte[] contents = pdSignature.getContents(byteArray); byte[] signedContent = pdSignature.getSignedContent(byteArray); logger.info("Byte range : " + Arrays.toString(pdSignature.getByteRange())); // IOUtils.write(contents, new FileOutputStream("sig.p7s")); ASN1InputStream asn1sInput = new ASN1InputStream(contents); ASN1Sequence asn1Seq = (ASN1Sequence) asn1sInput.readObject(); logger.info("SEQ : " + asn1Seq.toString()); ASN1ObjectIdentifier oid = ASN1ObjectIdentifier.getInstance(asn1Seq.getObjectAt(0)); assertEquals(PKCSObjectIdentifiers.signedData, oid); SignedData signedData = SignedData.getInstance(DERTaggedObject.getInstance(asn1Seq.getObjectAt(1)).getObject()); ASN1Set digestAlgorithmSet = signedData.getDigestAlgorithms(); ASN1ObjectIdentifier oidDigestAlgo = ASN1ObjectIdentifier.getInstance( ASN1Sequence.getInstance(digestAlgorithmSet.getObjectAt(0)).getObjectAt(0)); DigestAlgorithm digestAlgorithm = DigestAlgorithm.forOID(oidDigestAlgo.getId()); logger.info("DIGEST ALGO : " + digestAlgorithm); ContentInfo encapContentInfo = signedData.getEncapContentInfo(); ASN1ObjectIdentifier contentTypeOID = encapContentInfo.getContentType(); logger.info("ENCAPSULATED CONTENT INFO TYPE : " + contentTypeOID); assertEquals(PKCSObjectIdentifiers.data, contentTypeOID); ASN1Encodable content = encapContentInfo.getContent(); logger.info("ENCAPSULATED CONTENT INFO CONTENT : " + content); assertNull(content); List<X509Certificate> certificates = extractCertificates(signedData); ASN1Set signerInfosAsn1 = signedData.getSignerInfos(); logger.info("SIGNER INFO ASN1 : " + signerInfosAsn1.toString()); SignerInfo signedInfo = SignerInfo.getInstance(ASN1Sequence.getInstance(signerInfosAsn1.getObjectAt(0))); ASN1Set authenticatedAttributeSet = signedInfo.getAuthenticatedAttributes(); logger.info("AUTHENTICATED ATTR : " + authenticatedAttributeSet); List<ASN1ObjectIdentifier> attributeOids = new ArrayList<ASN1ObjectIdentifier>(); for (int i = 0; i < authenticatedAttributeSet.size(); i++) { Attribute attribute = Attribute.getInstance(authenticatedAttributeSet.getObjectAt(i)); attributeOids.add(attribute.getAttrType()); } logger.info("List of OID for Auth Attrb : " + attributeOids); Attribute attributeDigest = Attribute.getInstance(authenticatedAttributeSet.getObjectAt(1)); assertEquals(PKCSObjectIdentifiers.pkcs_9_at_messageDigest, attributeDigest.getAttrType()); ASN1OctetString asn1ObjString = ASN1OctetString.getInstance(attributeDigest.getAttrValues().getObjectAt(0)); String embeddedDigest = Base64.encode(asn1ObjString.getOctets()); logger.info("MESSAGE DIGEST : " + embeddedDigest); byte[] digestSignedContent = DSSUtils.digest(digestAlgorithm, signedContent); String computedDigestSignedContentEncodeBase64 = Base64.encode(digestSignedContent); logger.info( "COMPUTED DIGEST SIGNED CONTENT BASE64 : " + computedDigestSignedContentEncodeBase64); assertEquals(embeddedDigest, computedDigestSignedContentEncodeBase64); SignerIdentifier sid = signedInfo.getSID(); logger.info("SIGNER IDENTIFIER : " + sid.getId()); IssuerAndSerialNumber issuerAndSerialNumber = IssuerAndSerialNumber.getInstance(signedInfo.getSID()); ASN1Integer signerSerialNumber = issuerAndSerialNumber.getSerialNumber(); logger.info( "ISSUER AND SN : " + issuerAndSerialNumber.getName() + " " + signerSerialNumber); BigInteger serial = issuerAndSerialNumber.getSerialNumber().getValue(); X509Certificate signerCertificate = null; for (X509Certificate x509Certificate : certificates) { if (serial.equals(x509Certificate.getSerialNumber())) { signerCertificate = x509Certificate; } } assertNotNull(signerCertificate); String algorithm = signerCertificate.getPublicKey().getAlgorithm(); EncryptionAlgorithm encryptionAlgorithm = EncryptionAlgorithm.forName(algorithm); ASN1OctetString encryptedInfoOctedString = signedInfo.getEncryptedDigest(); String signatureValue = Hex.toHexString(encryptedInfoOctedString.getOctets()); logger.info("SIGNATURE VALUE : " + signatureValue); Cipher cipher = Cipher.getInstance(encryptionAlgorithm.getName()); cipher.init(Cipher.DECRYPT_MODE, signerCertificate); byte[] decrypted = cipher.doFinal(encryptedInfoOctedString.getOctets()); ASN1InputStream inputDecrypted = new ASN1InputStream(decrypted); ASN1Sequence seqDecrypt = (ASN1Sequence) inputDecrypted.readObject(); logger.info("DECRYPTED : " + seqDecrypt); DigestInfo digestInfo = new DigestInfo(seqDecrypt); assertEquals(oidDigestAlgo, digestInfo.getAlgorithmId().getAlgorithm()); String decryptedDigestEncodeBase64 = Base64.encode(digestInfo.getDigest()); logger.info("DECRYPTED BASE64 : " + decryptedDigestEncodeBase64); byte[] encoded = authenticatedAttributeSet.getEncoded(); byte[] digest = DSSUtils.digest(digestAlgorithm, encoded); String computedDigestFromSignatureEncodeBase64 = Base64.encode(digest); logger.info( "COMPUTED DIGEST FROM SIGNATURE BASE64 : " + computedDigestFromSignatureEncodeBase64); assertEquals(decryptedDigestEncodeBase64, computedDigestFromSignatureEncodeBase64); IOUtils.closeQuietly(inputDecrypted); IOUtils.closeQuietly(asn1sInput); } IOUtils.closeQuietly(inputStream); document.close(); } catch (Exception e) { logger.error(e.getMessage(), e); fail(e.getMessage()); } }
private boolean doVerify(SignerInformationVerifier verifier) throws CMSException { String digestName = CMSSignedHelper.INSTANCE.getDigestAlgName(this.getDigestAlgOID()); String encName = CMSSignedHelper.INSTANCE.getEncryptionAlgName(this.getEncryptionAlgOID()); String signatureName = digestName + "with" + encName; try { if (digestCalculator != null) { resultDigest = digestCalculator.getDigest(); } else { DigestCalculator calc = verifier.getDigestCalculator(this.getDigestAlgorithmID()); if (content != null) { OutputStream digOut = calc.getOutputStream(); content.write(digOut); digOut.close(); } else if (signedAttributeSet == null) { // TODO Get rid of this exception and just treat content==null as empty not missing? throw new CMSException("data not encapsulated in signature - use detached constructor."); } resultDigest = calc.getDigest(); } } catch (IOException e) { throw new CMSException("can't process mime object to create signature.", e); } catch (NoSuchAlgorithmException e) { throw new CMSException("can't find algorithm: " + e.getMessage(), e); } catch (OperatorCreationException e) { throw new CMSException("can't create digest calculator: " + e.getMessage(), e); } // RFC 3852 11.1 Check the content-type attribute is correct { DERObject validContentType = getSingleValuedSignedAttribute(CMSAttributes.contentType, "content-type"); if (validContentType == null) { if (!isCounterSignature && signedAttributeSet != null) { throw new CMSException( "The content-type attribute type MUST be present whenever signed attributes are present in signed-data"); } } else { if (isCounterSignature) { throw new CMSException( "[For counter signatures,] the signedAttributes field MUST NOT contain a content-type attribute"); } if (!(validContentType instanceof DERObjectIdentifier)) { throw new CMSException( "content-type attribute value not of ASN.1 type 'OBJECT IDENTIFIER'"); } DERObjectIdentifier signedContentType = (DERObjectIdentifier) validContentType; if (!signedContentType.equals(contentType)) { throw new CMSException("content-type attribute value does not match eContentType"); } } } // RFC 3852 11.2 Check the message-digest attribute is correct { DERObject validMessageDigest = getSingleValuedSignedAttribute(CMSAttributes.messageDigest, "message-digest"); if (validMessageDigest == null) { if (signedAttributeSet != null) { throw new CMSException( "the message-digest signed attribute type MUST be present when there are any signed attributes present"); } } else { if (!(validMessageDigest instanceof ASN1OctetString)) { throw new CMSException("message-digest attribute value not of ASN.1 type 'OCTET STRING'"); } ASN1OctetString signedMessageDigest = (ASN1OctetString) validMessageDigest; if (!Arrays.constantTimeAreEqual(resultDigest, signedMessageDigest.getOctets())) { throw new CMSSignerDigestMismatchException( "message-digest attribute value does not match calculated value"); } } } // RFC 3852 11.4 Validate countersignature attribute(s) { AttributeTable signedAttrTable = this.getSignedAttributes(); if (signedAttrTable != null && signedAttrTable.getAll(CMSAttributes.counterSignature).size() > 0) { throw new CMSException("A countersignature attribute MUST NOT be a signed attribute"); } AttributeTable unsignedAttrTable = this.getUnsignedAttributes(); if (unsignedAttrTable != null) { ASN1EncodableVector csAttrs = unsignedAttrTable.getAll(CMSAttributes.counterSignature); for (int i = 0; i < csAttrs.size(); ++i) { Attribute csAttr = (Attribute) csAttrs.get(i); if (csAttr.getAttrValues().size() < 1) { throw new CMSException( "A countersignature attribute MUST contain at least one AttributeValue"); } // Note: We don't recursively validate the countersignature value } } } try { ContentVerifier contentVerifier = verifier.getContentVerifier(sigAlgFinder.find(signatureName)); OutputStream sigOut = contentVerifier.getOutputStream(); if (signedAttributeSet == null) { if (digestCalculator != null) { if (contentVerifier instanceof RawContentVerifier) { RawContentVerifier rawVerifier = (RawContentVerifier) contentVerifier; if (encName.equals("RSA")) { DigestInfo digInfo = new DigestInfo(digestAlgorithm, resultDigest); return rawVerifier.verify(digInfo.getDEREncoded(), this.getSignature()); } return rawVerifier.verify(resultDigest, this.getSignature()); } throw new CMSException("verifier unable to process raw signature"); } else if (content != null) { // TODO Use raw signature of the hash value instead content.write(sigOut); } } else { sigOut.write(this.getEncodedSignedAttributes()); } sigOut.close(); return contentVerifier.verify(this.getSignature()); } catch (IOException e) { throw new CMSException("can't process mime object to create signature.", e); } catch (OperatorCreationException e) { throw new CMSException("can't create content verifier: " + e.getMessage(), e); } }