Skip to content

Commit c96a93d

Browse files
sachin071287Sachin kumar
andauthored
bael7821- pgp crypto using bc (#17008)
* bael7821- pgp crypto using bc * bael-7821 * bael-7821 * bael-7821 * bael-7821 junit update * bael-7821 review fix * bael-7821 review comment fix * bael-7821 review comment fix --------- Co-authored-by: Sachin kumar <[email protected]>
1 parent 05f5f10 commit c96a93d

File tree

8 files changed

+427
-1
lines changed

8 files changed

+427
-1
lines changed

libraries-security/pom.xml

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,11 @@
4747
<artifactId>bcpkix-jdk15on</artifactId>
4848
<version>${bouncycastle.version}</version>
4949
</dependency>
50+
<dependency>
51+
<groupId>org.bouncycastle</groupId>
52+
<artifactId>bcpg-jdk15on</artifactId>
53+
<version>${bouncycastle.version}</version>
54+
</dependency>
5055
<dependency>
5156
<groupId>org.passay</groupId>
5257
<artifactId>passay</artifactId>
@@ -169,4 +174,4 @@
169174
<sshj.version>0.38.0</sshj.version>
170175
</properties>
171176

172-
</project>
177+
</project>
Lines changed: 156 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,156 @@
1+
package com.baeldung.bouncycastle.pgp;
2+
3+
import java.io.BufferedInputStream;
4+
import java.io.BufferedOutputStream;
5+
import java.io.FileInputStream;
6+
import java.io.FileOutputStream;
7+
import java.io.IOException;
8+
import java.io.InputStream;
9+
import java.io.OutputStream;
10+
import java.nio.file.Path;
11+
import java.nio.file.Paths;
12+
import java.security.NoSuchProviderException;
13+
import java.security.SecureRandom;
14+
import java.security.Security;
15+
import java.util.Iterator;
16+
17+
import org.bouncycastle.bcpg.ArmoredOutputStream;
18+
import org.bouncycastle.bcpg.CompressionAlgorithmTags;
19+
import org.bouncycastle.jce.provider.BouncyCastleProvider;
20+
import org.bouncycastle.openpgp.PGPCompressedData;
21+
import org.bouncycastle.openpgp.PGPEncryptedData;
22+
import org.bouncycastle.openpgp.PGPEncryptedDataGenerator;
23+
import org.bouncycastle.openpgp.PGPEncryptedDataList;
24+
import org.bouncycastle.openpgp.PGPException;
25+
import org.bouncycastle.openpgp.PGPLiteralData;
26+
import org.bouncycastle.openpgp.PGPOnePassSignatureList;
27+
import org.bouncycastle.openpgp.PGPPrivateKey;
28+
import org.bouncycastle.openpgp.PGPPublicKey;
29+
import org.bouncycastle.openpgp.PGPPublicKeyEncryptedData;
30+
import org.bouncycastle.openpgp.PGPSecretKeyRingCollection;
31+
import org.bouncycastle.openpgp.PGPUtil;
32+
import org.bouncycastle.openpgp.jcajce.JcaPGPObjectFactory;
33+
import org.bouncycastle.openpgp.operator.PGPDataEncryptorBuilder;
34+
import org.bouncycastle.openpgp.operator.jcajce.JcaKeyFingerprintCalculator;
35+
import org.bouncycastle.openpgp.operator.jcajce.JcePGPDataEncryptorBuilder;
36+
import org.bouncycastle.openpgp.operator.jcajce.JcePublicKeyDataDecryptorFactoryBuilder;
37+
import org.bouncycastle.openpgp.operator.jcajce.JcePublicKeyKeyEncryptionMethodGenerator;
38+
import org.bouncycastle.util.io.Streams;
39+
import org.slf4j.Logger;
40+
import org.slf4j.LoggerFactory;
41+
42+
public class BouncyCastlePGPDemoApplication {
43+
44+
private static final Logger logger = LoggerFactory.getLogger(BouncyCastlePGPDemoApplication.class);
45+
46+
static {
47+
Security.addProvider(new BouncyCastleProvider());
48+
}
49+
50+
public static void main(String[] args) {
51+
52+
Path resourcesPath = Paths.get("src", "main", "resources");
53+
String pgpresource = resourcesPath.resolve("pgp")
54+
.toAbsolutePath()
55+
.toString();
56+
String pubKeyFileName = pgpresource + "/public_key.asc";
57+
String encryptedFileName = pgpresource + "/EncryptedOutputFile.pgp";
58+
String plainTextInputFileName = pgpresource + "/PlainTextInputFile.txt";
59+
String privKeyFileName = pgpresource + "/private_key.asc";
60+
61+
try {
62+
encryptFile(encryptedFileName, plainTextInputFileName, pubKeyFileName, true);
63+
decryptFile(encryptedFileName, privKeyFileName, "baeldung".toCharArray(), "decryptedFile", true);
64+
} catch (NoSuchProviderException e) {
65+
logger.error(e.getMessage());
66+
} catch (IOException e) {
67+
logger.error(e.getMessage());
68+
} catch (PGPException e) {
69+
logger.error(e.getMessage());
70+
}
71+
72+
}
73+
74+
public static void encryptFile(String outputFileName, String inputFileName, String pubKeyFileName, boolean armor) throws IOException, NoSuchProviderException, PGPException {
75+
76+
OutputStream out = new BufferedOutputStream(new FileOutputStream(outputFileName));
77+
PGPPublicKey encKey = PGPExampleUtil.readPublicKey(pubKeyFileName);
78+
if (armor) {
79+
out = new ArmoredOutputStream(out);
80+
}
81+
try {
82+
byte[] bytes = PGPExampleUtil.compressFile(inputFileName, CompressionAlgorithmTags.ZIP);
83+
PGPDataEncryptorBuilder encryptorBuilder = new JcePGPDataEncryptorBuilder(PGPEncryptedData.CAST5).setProvider("BC")
84+
.setSecureRandom(new SecureRandom())
85+
.setWithIntegrityPacket(true);
86+
PGPEncryptedDataGenerator encGen = new PGPEncryptedDataGenerator(encryptorBuilder);
87+
encGen.addMethod(new JcePublicKeyKeyEncryptionMethodGenerator(encKey).setProvider("BC"));
88+
OutputStream cOut = encGen.open(out, bytes.length);
89+
cOut.write(bytes);
90+
cOut.close();
91+
out.close();
92+
} catch (PGPException e) {
93+
logger.error(e.getMessage());
94+
}
95+
}
96+
97+
public static void decryptFile(String encryptedInputFileName, String privatekeyFileName, char[] passPhrase, String defaultFileName, boolean withIntegrityCheck) throws IOException, NoSuchProviderException {
98+
InputStream instream = new BufferedInputStream(new FileInputStream(encryptedInputFileName));
99+
InputStream privateKeyInStream = new BufferedInputStream(new FileInputStream(privatekeyFileName));
100+
instream = PGPUtil.getDecoderStream(instream);
101+
102+
try {
103+
JcaPGPObjectFactory pgpF = new JcaPGPObjectFactory(instream);
104+
PGPEncryptedDataList enc;
105+
Object o = pgpF.nextObject();
106+
// the first object might be a PGP marker packet.
107+
if (o instanceof PGPEncryptedDataList) {
108+
enc = (PGPEncryptedDataList) o;
109+
} else {
110+
enc = (PGPEncryptedDataList) pgpF.nextObject();
111+
}
112+
Iterator it = enc.getEncryptedDataObjects();
113+
PGPPrivateKey sKey = null;
114+
PGPPublicKeyEncryptedData pbe = null;
115+
PGPSecretKeyRingCollection pgpSec = new PGPSecretKeyRingCollection(PGPUtil.getDecoderStream(privateKeyInStream), new JcaKeyFingerprintCalculator());
116+
while (sKey == null && it.hasNext()) {
117+
pbe = (PGPPublicKeyEncryptedData) it.next();
118+
sKey = PGPExampleUtil.findSecretKey(pgpSec, pbe.getKeyID(), passPhrase);
119+
}
120+
if (sKey == null) {
121+
throw new IllegalArgumentException("secret key for message not found.");
122+
}
123+
InputStream clear = pbe.getDataStream(new JcePublicKeyDataDecryptorFactoryBuilder().setProvider("BC")
124+
.build(sKey));
125+
JcaPGPObjectFactory plainFact = new JcaPGPObjectFactory(clear);
126+
Object message = plainFact.nextObject();
127+
if (message instanceof PGPCompressedData) {
128+
PGPCompressedData cData = (PGPCompressedData) message;
129+
JcaPGPObjectFactory pgpFact = new JcaPGPObjectFactory(cData.getDataStream());
130+
message = pgpFact.nextObject();
131+
}
132+
if (message instanceof PGPLiteralData) {
133+
PGPLiteralData ld = (PGPLiteralData) message;
134+
String outFileName = ld.getFileName();
135+
outFileName = defaultFileName;
136+
InputStream unc = ld.getInputStream();
137+
OutputStream fOut = new FileOutputStream(outFileName);
138+
Streams.pipeAll(unc, fOut);
139+
fOut.close();
140+
} else if (message instanceof PGPOnePassSignatureList) {
141+
throw new PGPException("encrypted message contains a signed message - not literal data.");
142+
} else {
143+
throw new PGPException("message is not a simple encrypted file - type unknown.");
144+
}
145+
if (pbe.isIntegrityProtected() && pbe.verify()) {
146+
logger.error("message integrity check passed");
147+
} else {
148+
logger.error("message integrity check failed");
149+
}
150+
} catch (PGPException e) {
151+
logger.error(e.getMessage());
152+
}
153+
privateKeyInStream.close();
154+
instream.close();
155+
}
156+
}
Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
package com.baeldung.bouncycastle.pgp;
2+
3+
import java.io.BufferedInputStream;
4+
import java.io.ByteArrayOutputStream;
5+
import java.io.File;
6+
import java.io.FileInputStream;
7+
import java.io.IOException;
8+
import java.io.InputStream;
9+
import java.security.NoSuchProviderException;
10+
import java.util.Iterator;
11+
12+
import org.bouncycastle.openpgp.PGPCompressedDataGenerator;
13+
import org.bouncycastle.openpgp.PGPException;
14+
import org.bouncycastle.openpgp.PGPLiteralData;
15+
import org.bouncycastle.openpgp.PGPPrivateKey;
16+
import org.bouncycastle.openpgp.PGPPublicKey;
17+
import org.bouncycastle.openpgp.PGPPublicKeyRing;
18+
import org.bouncycastle.openpgp.PGPPublicKeyRingCollection;
19+
import org.bouncycastle.openpgp.PGPSecretKey;
20+
import org.bouncycastle.openpgp.PGPSecretKeyRing;
21+
import org.bouncycastle.openpgp.PGPSecretKeyRingCollection;
22+
import org.bouncycastle.openpgp.PGPUtil;
23+
import org.bouncycastle.openpgp.operator.jcajce.JcaKeyFingerprintCalculator;
24+
import org.bouncycastle.openpgp.operator.jcajce.JcePBESecretKeyDecryptorBuilder;
25+
26+
class PGPExampleUtil {
27+
static byte[] compressFile(String fileName, int algorithm) throws IOException {
28+
ByteArrayOutputStream bOut = new ByteArrayOutputStream();
29+
PGPCompressedDataGenerator comData = new PGPCompressedDataGenerator(algorithm);
30+
PGPUtil.writeFileToLiteralData(comData.open(bOut), PGPLiteralData.BINARY, new File(fileName));
31+
comData.close();
32+
return bOut.toByteArray();
33+
}
34+
35+
/**
36+
* Search a secret key ring collection for a secret key corresponding to keyID if it
37+
* exists.
38+
*
39+
* @param pgpSec a secret key ring collection.
40+
* @param keyID keyID we want.
41+
* @param pass passphrase to decrypt secret key with.
42+
* @return the private key.
43+
* @throws PGPException
44+
* @throws NoSuchProviderException
45+
*/
46+
static PGPPrivateKey findSecretKey(PGPSecretKeyRingCollection pgpSec, long keyID, char[] pass) throws PGPException, NoSuchProviderException {
47+
PGPSecretKey pgpSecKey = pgpSec.getSecretKey(keyID);
48+
if (pgpSecKey == null) {
49+
return null;
50+
}
51+
return pgpSecKey.extractPrivateKey(new JcePBESecretKeyDecryptorBuilder().setProvider("BC")
52+
.build(pass));
53+
}
54+
55+
static PGPPublicKey readPublicKey(String fileName) throws IOException, PGPException {
56+
InputStream keyIn = new BufferedInputStream(new FileInputStream(fileName));
57+
PGPPublicKey pubKey = readPublicKey(keyIn);
58+
keyIn.close();
59+
return pubKey;
60+
}
61+
62+
/**
63+
* A simple method that opens a key ring file and loads the first available key
64+
* suitable for encryption.
65+
*
66+
* @param input data stream containing the public key data
67+
* @return the first public key found.
68+
* @throws IOException
69+
* @throws PGPException
70+
*/
71+
static PGPPublicKey readPublicKey(InputStream input) throws IOException, PGPException {
72+
PGPPublicKeyRingCollection pgpPub = new PGPPublicKeyRingCollection(PGPUtil.getDecoderStream(input), new JcaKeyFingerprintCalculator());
73+
Iterator keyRingIter = pgpPub.getKeyRings();
74+
while (keyRingIter.hasNext()) {
75+
PGPPublicKeyRing keyRing = (PGPPublicKeyRing) keyRingIter.next();
76+
77+
Iterator keyIter = keyRing.getPublicKeys();
78+
while (keyIter.hasNext()) {
79+
PGPPublicKey key = (PGPPublicKey) keyIter.next();
80+
81+
if (key.isEncryptionKey()) {
82+
return key;
83+
}
84+
}
85+
}
86+
throw new IllegalArgumentException("Can't find encryption key in key ring.");
87+
}
88+
89+
static PGPSecretKey readSecretKey(String fileName) throws IOException, PGPException {
90+
InputStream keyIn = new BufferedInputStream(new FileInputStream(fileName));
91+
PGPSecretKey secKey = readSecretKey(keyIn);
92+
keyIn.close();
93+
return secKey;
94+
}
95+
96+
/**
97+
* A simple method that opens a key ring file and loads the first available key
98+
* suitable for signature generation.
99+
*
100+
* @param input stream to read the secret key ring collection from.
101+
* @return a secret key.
102+
* @throws IOException on a problem with using the input stream.
103+
* @throws PGPException if there is an issue parsing the input stream.
104+
*/
105+
static PGPSecretKey readSecretKey(InputStream input) throws IOException, PGPException {
106+
PGPSecretKeyRingCollection pgpSec = new PGPSecretKeyRingCollection(PGPUtil.getDecoderStream(input), new JcaKeyFingerprintCalculator());
107+
Iterator keyRingIter = pgpSec.getKeyRings();
108+
while (keyRingIter.hasNext()) {
109+
PGPSecretKeyRing keyRing = (PGPSecretKeyRing) keyRingIter.next();
110+
Iterator keyIter = keyRing.getSecretKeys();
111+
while (keyIter.hasNext()) {
112+
PGPSecretKey key = (PGPSecretKey) keyIter.next();
113+
if (key.isSigningKey()) {
114+
return key;
115+
}
116+
}
117+
}
118+
throw new IllegalArgumentException("Can't find signing key in key ring.");
119+
}
120+
}

libraries-security/src/main/resources/pgp/EncryptedOutputFile.pgp

Whitespace-only changes.
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
This is my message.
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
-----BEGIN PGP PRIVATE KEY BLOCK-----
2+
3+
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
58+
jMN0HPfH
59+
=2+ew
60+
-----END PGP PRIVATE KEY BLOCK-----
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
-----BEGIN PGP PUBLIC KEY BLOCK-----
2+
3+
mQENBGaHwXsBCADMA2LCSl8Hwm/Ok182JRO3Gf3IOs9OHlzQZZSQmzcCxSy04+Gi
4+
FEHbQly3lcZheQK0nd8NDCJfrZI6lq8/Nj4TwQFk4YXQE6BR85X+6u27rOLKy0nS
5+
DyxoPzxrJnY1dbVAS4y45F9JhbfRwsRIhQtGPiGiPcb+2enAotxoDaECXnZBl3Sx
6+
ghSd0hn8+b1u+r7o0gnNI372eWx64jQvSbaBh/weSnS2v/T4ae1gRXh/U7nYCvjR
7+
gz1zpdVDGNRIvZXBG7WGQKMg+dmNQEsb/3aQ62gbfJju3T/SDoYyGdmm53OKLUmO
8+
SOV+jMZ99dwbB6Gk7RyCQ7pqlkD0Zx3ubEsnABEBAAG0KWJhZWxkdW5nICh0ZXN0
9+
IGtleXMpIDxkdW1teUBiYWxlZHVuZy5jb20+iQFXBBMBCABBFiEEhp8oMsn/H4Ay
10+
dGwysGDL9y3HY7YFAmaHwXsCGwMFCQPCZwAFCwkIBwICIgIGFQoJCAsCBBYCAwEC
11+
HgcCF4AACgkQsGDL9y3HY7ZKHwf/SEc4af+FZ0jM/nzNDedXnihEeQIkelh4zBEH
12+
jCUFQV9firYh9aCF0Njzz/aPzLZVIuhigu8eyPsZzA+TonExJezPIuCM9mjIHXOA
13+
wPzffqQATsQQCdexDqyL3VtnZ2QQNXUZHmQtjWf15Rf0QuQ5QzzRLUrcDsc94UYb
14+
u2j1vp60XdkWaJ4zHj1VkJdN3RawGH0AIDdN7hS+a3gHIWizPFwoZVYA7BhxNFqc
15+
xLWMlIUewB2ZNvHlBFd4tJSgT6kVmY6uxtpZvy2+USVbONCDd7HQJHVmlD+fJU8Z
16+
h0CvS5Znrh2ICZEQdF9yBpHQBkJQ3RzfiV1urzhlbQ8GMs3RsbkBDQRmh8F7AQgA
17+
xz+TX9WKU1hxbrTbifLvmN7G9gdrBcETAr0k2cq7BKeWKhhDS/C2QkgZl1A/8SD/
18+
3bdOYfPIEEzWUcFZRMinQ1L1Df/PyJQIDv1oji66Plzu0CKY4+bHCCwLskbJChwx
19+
HcXDeaw5gsJlKHZQyaCxRTzpzkvdAjb1oOQRb7r2UbZdq+leIgqmgo2Y41WCvfTp
20+
5rfnAZ1AUYneDfPaPa5TmVT9zBufC/ZISYvHGxiBGYu4SOrNxZ5LNiL74nj+2FlK
21+
aszLcySSUK5WiFItxhh7bJAcTyJDrkpubueYXf2qPBbsYExWw43JvLthCIioLZwH
22+
PR0epSRTQEUBKRNAbvfd6wARAQABiQE8BBgBCAAmFiEEhp8oMsn/H4AydGwysGDL
23+
9y3HY7YFAmaHwXsCGwwFCQPCZwAACgkQsGDL9y3HY7agAQf/bxAZJiq6kxFWP1lj
24+
//h4+qtWSM9zaOuhBeN2MNCheIC7ffVSBsV/31ptbNtQAAoY391MKdU8sUZC8BtM
25+
JVDslmo1jvlciztN8D+vZkO7c8TW6etfXA9pZUlmnGhd1KMlQIrld3xNgwjtTSD9
26+
DvkVC8KTgsDmUSWInq8UUgQz6fr0Wl5rVlJ7QulGgknt+WjaBzSaCpq9EauM7GjD
27+
kZ3xKdUr6qY5+2NDrSMXXBUlwn6N5ha0PlZRTjPGsOGHDwlYTMkNY/nVswLPJRln
28+
mpix8RJeKDKZcqdpKTlOq1RQ923/ozpBwiSHcY3WBvVki6coPWTn2nE6O30zwIzD
29+
dBz3xw==
30+
=1T8p
31+
-----END PGP PUBLIC KEY BLOCK-----

0 commit comments

Comments
 (0)