GpgService.java (5315B)
1 package com.wimdupont.service; 2 3 import org.bouncycastle.crypto.DataLengthException; 4 import org.bouncycastle.jce.provider.BouncyCastleProvider; 5 import org.bouncycastle.openpgp.PGPCompressedData; 6 import org.bouncycastle.openpgp.PGPEncryptedData; 7 import org.bouncycastle.openpgp.PGPEncryptedDataList; 8 import org.bouncycastle.openpgp.PGPException; 9 import org.bouncycastle.openpgp.PGPLiteralData; 10 import org.bouncycastle.openpgp.PGPObjectFactory; 11 import org.bouncycastle.openpgp.PGPPrivateKey; 12 import org.bouncycastle.openpgp.PGPPublicKeyEncryptedData; 13 import org.bouncycastle.openpgp.PGPSecretKey; 14 import org.bouncycastle.openpgp.PGPSecretKeyRingCollection; 15 import org.bouncycastle.openpgp.PGPUtil; 16 import org.bouncycastle.openpgp.jcajce.JcaPGPObjectFactory; 17 import org.bouncycastle.openpgp.operator.bc.BcKeyFingerprintCalculator; 18 import org.bouncycastle.openpgp.operator.bc.BcPBESecretKeyDecryptorBuilder; 19 import org.bouncycastle.openpgp.operator.bc.BcPGPDigestCalculatorProvider; 20 import org.bouncycastle.openpgp.operator.bc.BcPublicKeyDataDecryptorFactory; 21 22 import java.io.ByteArrayOutputStream; 23 import java.io.FileInputStream; 24 import java.io.IOException; 25 import java.io.InputStream; 26 import java.security.Security; 27 import java.util.Iterator; 28 29 public class GpgService { 30 31 private final ApplicationProperties applicationProperties; 32 33 public GpgService(ApplicationProperties applicationProperties){ 34 this.applicationProperties = applicationProperties; 35 } 36 37 public byte[] decrypt(String fileName) throws IOException, PGPException { 38 Security.addProvider(new BouncyCastleProvider()); 39 40 var encryptedDataObjects = getPgpEncryptedDataIterator(fileName); 41 42 if (encryptedDataObjects.hasNext()) { 43 var pgpPublicKeyEncryptedData = (PGPPublicKeyEncryptedData) encryptedDataObjects.next(); 44 var pgpPrivateKey = retrievePgpPrivateKey(pgpPublicKeyEncryptedData); 45 46 return getByteArrayOutputStream(pgpPublicKeyEncryptedData, pgpPrivateKey); 47 } else { 48 throw new DataLengthException(String.format("No encrypted dataObjects found in file: %s", fileName)); 49 } 50 } 51 52 private Iterator<PGPEncryptedData> getPgpEncryptedDataIterator(String fileName) throws IOException { 53 var secretDecoderStream = PGPUtil.getDecoderStream(KeyRetriever 54 .getSecretKeyInputStream(fileName, applicationProperties.getDirPath())); 55 var pgpObjectFactory = new PGPObjectFactory(secretDecoderStream, new BcKeyFingerprintCalculator()); 56 var nextObject = pgpObjectFactory.nextObject(); 57 58 return (nextObject instanceof PGPEncryptedDataList) 59 ? ((PGPEncryptedDataList) nextObject).getEncryptedDataObjects() 60 : ((PGPEncryptedDataList) pgpObjectFactory.nextObject()).getEncryptedDataObjects(); 61 } 62 63 private PGPPrivateKey retrievePgpPrivateKey(PGPPublicKeyEncryptedData pgpPublicKeyEncryptedData) throws IOException, PGPException { 64 var pgpPrivateKey = readSecretKey(new FileInputStream(applicationProperties.getSecretFile()), pgpPublicKeyEncryptedData.getKeyID()) 65 .extractPrivateKey(new BcPBESecretKeyDecryptorBuilder(new BcPGPDigestCalculatorProvider()) 66 .build(PasswordReader.getPassword())); 67 68 if (pgpPrivateKey == null) { 69 throw new IllegalArgumentException("Secret key for message not found."); 70 } 71 72 return pgpPrivateKey; 73 } 74 75 private PGPSecretKey readSecretKey(InputStream inputStream, 76 long keyId) throws IOException, PGPException { 77 inputStream = PGPUtil.getDecoderStream(inputStream); 78 var pgpSecretKeyRings = new PGPSecretKeyRingCollection(inputStream, new BcKeyFingerprintCalculator()); 79 var secretKey = pgpSecretKeyRings.getSecretKey(keyId); 80 81 if (secretKey == null) { 82 throw new IllegalArgumentException("Can't find encryption key in key ring."); 83 } 84 85 return secretKey; 86 } 87 88 private byte[] getByteArrayOutputStream(PGPPublicKeyEncryptedData pgpPublicKeyEncryptedData, 89 PGPPrivateKey pgpPrivateKey) throws IOException, PGPException { 90 ByteArrayOutputStream byteArrayOutputStream; 91 92 try (var dataStream = toDataStream(pgpPublicKeyEncryptedData, pgpPrivateKey)) { 93 byteArrayOutputStream = new ByteArrayOutputStream(); 94 int dataRead; 95 96 while ((dataRead = dataStream.read()) >= 0) { 97 byteArrayOutputStream.write(dataRead); 98 } 99 } 100 101 return byteArrayOutputStream.toByteArray(); 102 } 103 104 private InputStream toDataStream(PGPPublicKeyEncryptedData pgpPublicKeyEncryptedData, 105 PGPPrivateKey pgpPrivateKey) throws PGPException, IOException { 106 var pgpDataStream = pgpPublicKeyEncryptedData.getDataStream( 107 new BcPublicKeyDataDecryptorFactory(pgpPrivateKey)); 108 var jcaPGPObjectFactory = new JcaPGPObjectFactory(pgpDataStream); 109 var pgpCompressedDataStream = ((PGPCompressedData) jcaPGPObjectFactory.nextObject()).getDataStream(); 110 jcaPGPObjectFactory = new JcaPGPObjectFactory(pgpCompressedDataStream); 111 112 return ((PGPLiteralData) jcaPGPObjectFactory.nextObject()).getDataStream(); 113 } 114 115 }