From 7489cf6effece4e08ddc2bb2dc274278766472e5 Mon Sep 17 00:00:00 2001
From: nabyla <31042612+nabyla@users.noreply.github.com>
Date: Fri, 27 Oct 2017 10:46:29 +0100
Subject: [PATCH] PR Bouncycastle article (#2882)
* Add bouncycastle depedencies
* Add certificate and private key to resources folder
* add bouncycastle code sample
* Add bouncycastle test
---
libraries/pom.xml | 15 +++
.../bouncycastle/BouncyCastleCrypto.java | 111 ++++++++++++++++++
libraries/src/main/resources/Baeldung.cer | 20 ++++
libraries/src/main/resources/Baeldung.p12 | Bin 0 -> 2502 bytes
.../bouncycastle/BouncyCastleLiveTest.java | 53 +++++++++
5 files changed, 199 insertions(+)
create mode 100644 libraries/src/main/java/com/baeldung/bouncycastle/BouncyCastleCrypto.java
create mode 100644 libraries/src/main/resources/Baeldung.cer
create mode 100644 libraries/src/main/resources/Baeldung.p12
create mode 100644 libraries/src/test/java/com/baeldung/bouncycastle/BouncyCastleLiveTest.java
diff --git a/libraries/pom.xml b/libraries/pom.xml
index b519b9cd53..409b4df08d 100644
--- a/libraries/pom.xml
+++ b/libraries/pom.xml
@@ -600,6 +600,21 @@
caffeine
${caffeine.version}
+
+ org.bouncycastle
+ bcprov-jdk15on
+ 1.58
+
+
+ org.bouncycastle
+ bcprov-jdk15on
+ 1.58
+
+
+ org.bouncycastle
+ bcpkix-jdk15on
+ 1.58
+
diff --git a/libraries/src/main/java/com/baeldung/bouncycastle/BouncyCastleCrypto.java b/libraries/src/main/java/com/baeldung/bouncycastle/BouncyCastleCrypto.java
new file mode 100644
index 0000000000..5d8a7a6643
--- /dev/null
+++ b/libraries/src/main/java/com/baeldung/bouncycastle/BouncyCastleCrypto.java
@@ -0,0 +1,111 @@
+package com.baeldung.bouncycastle;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.security.PrivateKey;
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.CertificateException;
+import java.security.cert.X509Certificate;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+
+import org.bouncycastle.asn1.ASN1InputStream;
+import org.bouncycastle.asn1.cms.ContentInfo;
+import org.bouncycastle.cert.X509CertificateHolder;
+import org.bouncycastle.cert.jcajce.JcaCertStore;
+import org.bouncycastle.cms.CMSAlgorithm;
+import org.bouncycastle.cms.CMSEnvelopedData;
+import org.bouncycastle.cms.CMSEnvelopedDataGenerator;
+import org.bouncycastle.cms.CMSException;
+import org.bouncycastle.cms.CMSProcessableByteArray;
+import org.bouncycastle.cms.CMSSignedData;
+import org.bouncycastle.cms.CMSSignedDataGenerator;
+import org.bouncycastle.cms.CMSTypedData;
+import org.bouncycastle.cms.KeyTransRecipientInformation;
+import org.bouncycastle.cms.RecipientInformation;
+import org.bouncycastle.cms.SignerInformation;
+import org.bouncycastle.cms.SignerInformationStore;
+import org.bouncycastle.cms.jcajce.JcaSignerInfoGeneratorBuilder;
+import org.bouncycastle.cms.jcajce.JcaSimpleSignerInfoVerifierBuilder;
+import org.bouncycastle.cms.jcajce.JceCMSContentEncryptorBuilder;
+import org.bouncycastle.cms.jcajce.JceKeyTransEnvelopedRecipient;
+import org.bouncycastle.cms.jcajce.JceKeyTransRecipient;
+import org.bouncycastle.cms.jcajce.JceKeyTransRecipientInfoGenerator;
+import org.bouncycastle.operator.ContentSigner;
+import org.bouncycastle.operator.OperatorCreationException;
+import org.bouncycastle.operator.OutputEncryptor;
+import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;
+import org.bouncycastle.operator.jcajce.JcaDigestCalculatorProviderBuilder;
+import org.bouncycastle.util.Store;
+
+public class BouncyCastleCrypto {
+
+ public static byte[] signData(byte[] data, final X509Certificate signingCertificate, final PrivateKey signingKey)
+ throws CertificateEncodingException, OperatorCreationException, CMSException, IOException {
+ byte[] signedMessage = null;
+ List certList = new ArrayList();
+ CMSTypedData cmsData = new CMSProcessableByteArray(data);
+ certList.add(signingCertificate);
+ Store certs = new JcaCertStore(certList);
+ CMSSignedDataGenerator cmsGenerator = new CMSSignedDataGenerator();
+ ContentSigner contentSigner = new JcaContentSignerBuilder("SHA256withRSA").build(signingKey);
+ cmsGenerator.addSignerInfoGenerator(
+ new JcaSignerInfoGeneratorBuilder(new JcaDigestCalculatorProviderBuilder().setProvider("BC").build())
+ .build(contentSigner, signingCertificate));
+ cmsGenerator.addCertificates(certs);
+ CMSSignedData cms = cmsGenerator.generate(cmsData, true);
+ signedMessage = cms.getEncoded();
+ return signedMessage;
+ }
+
+ public static boolean verifSignData(final byte[] signedData)
+ throws CMSException, IOException, OperatorCreationException, CertificateException {
+ ByteArrayInputStream bIn = new ByteArrayInputStream(signedData);
+ ASN1InputStream aIn = new ASN1InputStream(bIn);
+ CMSSignedData s = new CMSSignedData(ContentInfo.getInstance(aIn.readObject()));
+ aIn.close();
+ bIn.close();
+ Store certs = s.getCertificates();
+ SignerInformationStore signers = s.getSignerInfos();
+ Collection c = signers.getSigners();
+ SignerInformation signer = c.iterator().next();
+ Collection certCollection = certs.getMatches(signer.getSID());
+ Iterator certIt = certCollection.iterator();
+ X509CertificateHolder certHolder = certIt.next();
+ boolean verifResult = signer.verify(new JcaSimpleSignerInfoVerifierBuilder().build(certHolder));
+ if (!verifResult) {
+ return false;
+ }
+ return true;
+ }
+
+ public static byte[] encryptData(final byte[] data, X509Certificate encryptionCertificate)
+ throws CertificateEncodingException, CMSException, IOException {
+ byte[] encryptedData = null;
+ if (null != data && null != encryptionCertificate) {
+ CMSEnvelopedDataGenerator cmsEnvelopedDataGenerator = new CMSEnvelopedDataGenerator();
+ JceKeyTransRecipientInfoGenerator jceKey = new JceKeyTransRecipientInfoGenerator(encryptionCertificate);
+ cmsEnvelopedDataGenerator.addRecipientInfoGenerator(jceKey);
+ CMSTypedData msg = new CMSProcessableByteArray(data);
+ OutputEncryptor encryptor = new JceCMSContentEncryptorBuilder(CMSAlgorithm.AES128_CBC).setProvider("BC")
+ .build();
+ CMSEnvelopedData cmsEnvelopedData = cmsEnvelopedDataGenerator.generate(msg, encryptor);
+ encryptedData = cmsEnvelopedData.getEncoded();
+ }
+ return encryptedData;
+ }
+
+ public static byte[] decryptData(final byte[] encryptedData, final PrivateKey decryptionKey) throws CMSException {
+ byte[] decryptedData = null;
+ if (null != encryptedData && null != decryptionKey) {
+ CMSEnvelopedData envelopedData = new CMSEnvelopedData(encryptedData);
+ Collection recip = envelopedData.getRecipientInfos().getRecipients();
+ KeyTransRecipientInformation recipientInfo = (KeyTransRecipientInformation) recip.iterator().next();
+ JceKeyTransRecipient recipient = new JceKeyTransEnvelopedRecipient(decryptionKey);
+ decryptedData = recipientInfo.getContent(recipient);
+ }
+ return decryptedData;
+ }
+}
diff --git a/libraries/src/main/resources/Baeldung.cer b/libraries/src/main/resources/Baeldung.cer
new file mode 100644
index 0000000000..72d0918424
--- /dev/null
+++ b/libraries/src/main/resources/Baeldung.cer
@@ -0,0 +1,20 @@
+-----BEGIN CERTIFICATE-----
+MIIDPjCCAiagAwIBAgIJAPvd1gx14C3CMA0GCSqGSIb3DQEBBQUAMEcxCzAJBgNV
+BAYTAk1BMRAwDgYDVQQIEwdNb3JvY2NvMRMwEQYDVQQHEwpDYXNhYmxhbmNhMREw
+DwYDVQQDEwhCYWVsZHVuZzAeFw0xNzEwMTIxMDQzMTRaFw0yNzEwMTMxMDQzMTRa
+MEcxCzAJBgNVBAYTAk1BMRAwDgYDVQQIEwdNb3JvY2NvMRMwEQYDVQQHEwpDYXNh
+YmxhbmNhMREwDwYDVQQDEwhCYWVsZHVuZzCCASIwDQYJKoZIhvcNAQEBBQADggEP
+ADCCAQoCggEBAMyi5GmOeN4QaH/CP5gSOyHX8znb5TDHWV8wc+ZT7kNU8zt5tGMh
+jozK6hax155/6tOsBDR0rSYBhL+Dm/+uCVS7qOlRHhf6cNGtzGF1gnNJB2WjI8oM
+AYm24xpLj1WphKUwKrn3nTMPnQup5OoNAMYl99flANrRYVjjxrLQvDZDUio6Iujr
+CZ2TtXGM0g/gP++28KT7g1KlUui3xtB0u33wx7UN8Fix3JmjOaPHGwxGpwP3VGSj
+fs8cuhqVwRQaZpCOoHU/P8wpXKw80sSdhz+SRueMPtVYqK0CiLL5/O0h0Y3le4IV
+whgg3KG1iTGOWn60UMFn1EYmQ18k5Nsma6UCAwEAAaMtMCswCQYDVR0TBAIwADAR
+BglghkgBhvhCAQEEBAMCBPAwCwYDVR0PBAQDAgUgMA0GCSqGSIb3DQEBBQUAA4IB
+AQC8DDBmJ3p4xytxBiE0s4p1715WT6Dm/QJHp0XC0hkSoyZKDh+XVmrzm+J3SiW1
+vpswb5hLgPo040YX9jnDmgOD+TpleTuKHxZRYj92UYWmdjkWLVtFMcvOh+gxBiAP
+pHIqZsqo8lfcyAuh8Jx834IXbknfCUtERDLG/rU9P/3XJhrM2GC5qPQznrW4EYhU
+CGPyIJXmvATMVvXMWCtfogAL+n42vjYXQXZoAWomHhLHoNbSJUErnNdWDOh4WoJt
+XJCxA6U5LSBplqb3wB2hUTqw+0admKltvmy+KA1PD7OxoGiY7V544zeGqJam1qxU
+ia7y5BL6uOa/4ShSV8pcJDYz
+-----END CERTIFICATE-----
diff --git a/libraries/src/main/resources/Baeldung.p12 b/libraries/src/main/resources/Baeldung.p12
new file mode 100644
index 0000000000000000000000000000000000000000..65ec8bc8fec33120b2c11276883dde5dad7a3ea6
GIT binary patch
literal 2502
zcmY+Ec{CJ^8pg-W7-KiSAxm~&AvE}qeFbou@HKRX#MCzW*R!0LL7Y%
z7)Sr`m+g30_7yeFjs-&~fCI+{-yx;|%9MeT2(tgQ10!G4XA2
zkG>wSErwX=^nQsIu&jb*uF4fhJf{o`c{-h8IOQJ-3P1FiZj0wRF6K9
z8mc&Zv?tvBj9P!Y^4uoj2G=6#18%wBeI!8jBRU|{P+P>0Aj=k375X=>QV+%oS!bk}+lJ+=1;z2pF||>sP$r3Brd~;
zK)4%I2x>Ka+<;kKSK~)>L|uxGz&8_NxTGL2SC%Ui58tY=@-RCRhmrcaiO=Kg3VLao
zL4POxN4d@n*d5|D3|P>OiNs!L2y3}V91S9g=+MPm2z2B)8SfIlps2SxADFc?et7bp
zX$NVVRh<~4WzxjUvYD%W)wYw9O8Brp^L0RcbZ~X#P4;$
zj@d^cTmNv5A?VBUvx?k4kPIs2@lgJ*dzk-y`e;r~_tMcguyihj(WZx;W7st6eU1^p
zA%3;BP+|V=UsgnMaP2xR9K?kLwyMXM~nWS!589aEx|ZivtPE+FCig}|Cv7n
z4X_Xg-u#7*)&HXc=rv2DY6l{514xv{C2smp+M*
z0HVF+G4qecX9^nOQ_20k2BM02$9dQ593Rq`jJUz%jTp%B$M|BdRc91;W`+2m}mmXL+cwS
z-&0lg5an|f6il`kXk#vPZhK2Z{$$;;@;0;b_10a*B5Rf5vKBR^@uJW`WS*}TZ=JLU
zrj7F9)-nOh*HW4C!Otz_FqYnEa!4nC@x0Wy?`_DN=c%fjkhTs@U^UB&)l0w$4n{K*
zxd;D}W@$I_F{l@h(sB)s*Iz+sw{FOEa8&
z#EfydGU+EgJ3m#S4b&`TTCBfC)eJ1M>U(%yKc+7F3lI-0X##xff#=dtmj;cWs@*(1
zZXS(tbGXP@?braN#P>=GxwN^xFqQBRSvZbJniMWr*lo`MXc=JWLQ&?yr)-$(Q$h^t
zmmrKH?`t%wDk~pX1aJ^CbU%HXCAh@rR6?f`m^|7yVOF)+`(Y=4B-tto(B<>E=#QYq
z&@RDn^M$lUwdx-1I4h;lvzUX6)HqThjqi4SlgM#nYG;nAtd-nO%TPn)KA9c{jep;9
zv79sQ{V`P{aJuEBb+8(|yi8}R
z6hXIAFE*35l(toZR?k^d;kDRbp0Bi3D0P+;?`sW)yZdU2IS(8r-PlbgD6J2GLhODl
zx^Ea$kiSoZQ1qd#$
zrw<*y{e#y|n++B0#ujM&wp!KoH<8hT7JB{RiW`47kpL%2BP;hRkV5E^;HN+5b
za*HI=nMx7`*nucDb(iCuuCi`KplQ=xzr^Ya{l%oz=!5s?{M_rv@Zq3;FGnmok06!C
z!iZ>7b}M(R4R=#t|6J8