generated from codeforamerica/form-flow-starter-app
-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* Updated deploy configs for staging
- Loading branch information
Showing
9 changed files
with
220 additions
and
159 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
23 changes: 23 additions & 0 deletions
23
src/main/java/org/ladocuploader/app/cli/MockPGPEncryptorImpl.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
package org.ladocuploader.app.cli; | ||
|
||
import lombok.extern.slf4j.Slf4j; | ||
import org.springframework.context.annotation.Profile; | ||
import org.springframework.stereotype.Component; | ||
|
||
import java.io.FileInputStream; | ||
import java.io.IOException; | ||
import java.io.InputStream; | ||
|
||
@Slf4j | ||
@Component | ||
@Profile({"dev", "test", "demo"}) | ||
public class MockPGPEncryptorImpl implements PGPEncryptor { | ||
|
||
@Override | ||
public byte[] signAndEncryptPayload(String filename) throws IOException { | ||
log.info("Mock encrypting payload " + filename); | ||
try (InputStream inputStream = new FileInputStream(filename)) { | ||
return inputStream.readAllBytes(); | ||
} | ||
} | ||
} |
152 changes: 3 additions & 149 deletions
152
src/main/java/org/ladocuploader/app/cli/PGPEncryptor.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,154 +1,8 @@ | ||
package org.ladocuploader.app.cli; | ||
|
||
import lombok.extern.slf4j.Slf4j; | ||
import org.bouncycastle.bcpg.CompressionAlgorithmTags; | ||
import org.bouncycastle.bcpg.SymmetricKeyAlgorithmTags; | ||
import org.bouncycastle.openpgp.*; | ||
import org.bouncycastle.openpgp.jcajce.JcaPGPPublicKeyRingCollection; | ||
import org.bouncycastle.openpgp.operator.KeyFingerPrintCalculator; | ||
import org.bouncycastle.openpgp.operator.jcajce.*; | ||
import org.springframework.beans.factory.annotation.Value; | ||
import org.springframework.stereotype.Component; | ||
import java.io.IOException; | ||
|
||
import java.io.*; | ||
import java.security.SecureRandom; | ||
import java.util.Date; | ||
import java.util.Iterator; | ||
|
||
@Slf4j | ||
@Component | ||
public class PGPEncryptor { | ||
|
||
private final String pubkeyFilename; | ||
private final String sigkeyFilename; | ||
private final String sigkeyPassword; | ||
|
||
public PGPEncryptor(@Value("${pgp.pubkey_filename:}") String pubkeyFilename, @Value("${pgp.sigkey_filename:}") String sigkeyFilename, @Value("${pgp.sigkey_password:}") String sigkeyPassword) { | ||
this.pubkeyFilename = pubkeyFilename; | ||
this.sigkeyFilename = sigkeyFilename; | ||
this.sigkeyPassword = sigkeyPassword; | ||
} | ||
|
||
public byte[] signAndEncryptPayload(String filename) throws IOException { | ||
FileInputStream instream = new FileInputStream(filename); | ||
|
||
log.info("Retrieving keys for signing and encryption"); | ||
PGPSecretKey signingKey = getSecretKey(); | ||
PGPPublicKey pubKey = getPublicKey(); | ||
|
||
ByteArrayOutputStream outstream = new ByteArrayOutputStream(); | ||
try { | ||
log.info("Signing and encrypting payload"); | ||
return signAndEncryptPayload(instream, signingKey, pubKey, outstream); | ||
} catch (PGPException e) { | ||
throw new IllegalStateException("There was an issue signing and encrypting the file", e); | ||
} finally { | ||
instream.close(); | ||
outstream.close(); | ||
log.info("Completed signing and encrypting payload"); | ||
} | ||
} | ||
|
||
private PGPPublicKey getPublicKey() throws IOException { | ||
PGPPublicKey pubKey = null; | ||
InputStream inputStream = new FileInputStream(pubkeyFilename); | ||
inputStream = PGPUtil.getDecoderStream(inputStream); | ||
try { | ||
JcaPGPPublicKeyRingCollection ringCollection = new JcaPGPPublicKeyRingCollection(inputStream); | ||
Iterator<PGPPublicKeyRing> keyRingsIterator = ringCollection.getKeyRings(); | ||
while (keyRingsIterator.hasNext()) { | ||
PGPPublicKeyRing pgpPublicKeyRing = keyRingsIterator.next(); | ||
Iterator<PGPPublicKey> pubKeysIterator = pgpPublicKeyRing.getPublicKeys(); | ||
while (pubKeysIterator.hasNext()) { | ||
pubKey = pubKeysIterator.next(); | ||
} | ||
} | ||
} catch (PGPException e) { | ||
throw new IllegalArgumentException("Invalid public key"); | ||
} finally { | ||
inputStream.close(); | ||
} | ||
return pubKey; | ||
} | ||
|
||
private PGPSecretKey getSecretKey() throws IOException { | ||
try (InputStream fileInputStream = new FileInputStream(sigkeyFilename);) { | ||
InputStream inputStream = PGPUtil.getDecoderStream(fileInputStream); | ||
KeyFingerPrintCalculator fpCalculator = new JcaKeyFingerprintCalculator(); | ||
PGPSecretKeyRingCollection pgpSec = new PGPSecretKeyRingCollection(inputStream, fpCalculator); | ||
|
||
Iterator<PGPSecretKeyRing> keyRingIter = pgpSec.getKeyRings(); | ||
while (keyRingIter.hasNext()) { | ||
PGPSecretKeyRing keyRing = keyRingIter.next(); | ||
|
||
Iterator<PGPSecretKey> keyIter = keyRing.getSecretKeys(); | ||
while (keyIter.hasNext()) { | ||
PGPSecretKey key = keyIter.next(); | ||
|
||
if (key.isSigningKey()) { | ||
return key; | ||
} | ||
} | ||
} | ||
} catch (PGPException e) { | ||
throw new IllegalArgumentException("Invalid signing key", e); | ||
} | ||
|
||
throw new IllegalArgumentException("Invalid signing key"); | ||
} | ||
|
||
private PGPPrivateKey getPrivateKey(PGPSecretKey secretKey) throws PGPException { | ||
return secretKey.extractPrivateKey( | ||
new JcePBESecretKeyDecryptorBuilder().build(sigkeyPassword.toCharArray())); | ||
} | ||
|
||
private byte[] signAndEncryptPayload(InputStream inputStream, PGPSecretKey secKey, PGPPublicKey pubKey, | ||
ByteArrayOutputStream outputStream) throws PGPException, IOException { | ||
int BUFFER_SIZE = 1 << 16; | ||
|
||
// Encryption | ||
PGPEncryptedDataGenerator encGen = new PGPEncryptedDataGenerator( | ||
new JcePGPDataEncryptorBuilder(SymmetricKeyAlgorithmTags.AES_256) | ||
.setWithIntegrityPacket(true) | ||
.setSecureRandom(new SecureRandom())); | ||
encGen.addMethod(new JcePublicKeyKeyEncryptionMethodGenerator(pubKey)); | ||
OutputStream encOut = encGen.open(outputStream, new byte[BUFFER_SIZE]); | ||
|
||
// Compression | ||
PGPCompressedDataGenerator cGen = new PGPCompressedDataGenerator(CompressionAlgorithmTags.ZIP); | ||
OutputStream cOut = cGen.open(encOut); | ||
|
||
// Signing | ||
PGPSignatureGenerator sGen = new PGPSignatureGenerator(new JcaPGPContentSignerBuilder(secKey.getPublicKey().getAlgorithm(), PGPUtil.SHA1)); | ||
sGen.init(PGPSignature.BINARY_DOCUMENT, getPrivateKey(secKey)); | ||
|
||
Iterator<String> it = secKey.getPublicKey().getUserIDs(); | ||
if (it.hasNext()) { | ||
PGPSignatureSubpacketGenerator spGen = new PGPSignatureSubpacketGenerator(); | ||
spGen.addSignerUserID(false, it.next()); | ||
sGen.setHashedSubpackets(spGen.generate()); | ||
} | ||
|
||
sGen.generateOnePassVersion(false).encode(cOut); | ||
|
||
// Literal Data generator and output stream | ||
byte[] data = inputStream.readAllBytes(); | ||
PGPLiteralDataGenerator lGen = new PGPLiteralDataGenerator(); | ||
OutputStream lOut = lGen.open(cOut, PGPLiteralData.BINARY, PGPLiteralData.CONSOLE, data.length, new Date()); | ||
|
||
lOut.write(data); | ||
sGen.update(data); | ||
|
||
lOut.close(); | ||
lGen.close(); | ||
|
||
sGen.generate().encode(cOut); | ||
cOut.close(); | ||
cGen.close(); | ||
encGen.close(); | ||
|
||
return outputStream.toByteArray(); | ||
} | ||
public interface PGPEncryptor { | ||
|
||
byte[] signAndEncryptPayload(String filename) throws IOException; | ||
} | ||
|
179 changes: 179 additions & 0 deletions
179
src/main/java/org/ladocuploader/app/cli/PGPEncryptorImpl.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,179 @@ | ||
package org.ladocuploader.app.cli; | ||
|
||
import formflow.library.file.CloudFile; | ||
import formflow.library.file.S3CloudFileRepository; | ||
import jakarta.annotation.PostConstruct; | ||
import lombok.extern.slf4j.Slf4j; | ||
import org.bouncycastle.bcpg.CompressionAlgorithmTags; | ||
import org.bouncycastle.bcpg.SymmetricKeyAlgorithmTags; | ||
import org.bouncycastle.openpgp.*; | ||
import org.bouncycastle.openpgp.jcajce.JcaPGPPublicKeyRingCollection; | ||
import org.bouncycastle.openpgp.operator.KeyFingerPrintCalculator; | ||
import org.bouncycastle.openpgp.operator.jcajce.*; | ||
import org.springframework.beans.factory.annotation.Value; | ||
import org.springframework.context.annotation.Profile; | ||
import org.springframework.stereotype.Component; | ||
|
||
import java.io.*; | ||
import java.security.SecureRandom; | ||
import java.util.Date; | ||
import java.util.Iterator; | ||
|
||
@Slf4j | ||
@Component | ||
@Profile({"production", "staging"}) | ||
public class PGPEncryptorImpl implements PGPEncryptor { | ||
|
||
@Value("${pgp.sigkey-password}") | ||
private String sigkeyPassword; | ||
@Value("${pgp.seckey-file-path}") | ||
private String seckeyFilePath; | ||
@Value("${pgp.pubkey-file-path}") | ||
private String pubkeyFilePath; | ||
@Value("${pgp.bucket-name}") | ||
private String bucketName; | ||
|
||
@Value("${form-flow.aws.access_key}") | ||
private String accessKey; | ||
@Value("${form-flow.aws.secret_key}") | ||
private String secretKey; | ||
@Value("${form-flow.aws.region}") | ||
private String region; | ||
|
||
private PGPSecretKey signingKey; | ||
private PGPPublicKey pubKey; | ||
|
||
@PostConstruct | ||
public void init() { | ||
log.info("Retrieving keys for signing and encryption"); | ||
S3CloudFileRepository repository = new S3CloudFileRepository(accessKey, secretKey, bucketName, region); | ||
CloudFile pubKey = repository.get(pubkeyFilePath); | ||
CloudFile sigKey = repository.get(seckeyFilePath); | ||
try { | ||
initPubKey(pubKey.getFileBytes()); | ||
initSigKey(sigKey.getFileBytes()); | ||
} catch (IOException e) { | ||
throw new IllegalStateException("Issue initializing encryption keys", e); | ||
} | ||
} | ||
|
||
@Override | ||
public byte[] signAndEncryptPayload(String filename) throws IOException { | ||
FileInputStream instream = new FileInputStream(filename); | ||
ByteArrayOutputStream outstream = new ByteArrayOutputStream(); | ||
try { | ||
log.info("Signing and encrypting payload"); | ||
return signAndEncryptPayload(instream, signingKey, pubKey, outstream); | ||
} catch (PGPException e) { | ||
throw new IllegalStateException("There was an issue signing and encrypting the file", e); | ||
} finally { | ||
instream.close(); | ||
outstream.close(); | ||
log.info("Completed signing and encrypting payload"); | ||
} | ||
} | ||
|
||
private void initPubKey(byte[] fileBytes) throws IOException { | ||
PGPPublicKey pubKey = null; | ||
InputStream inputStream = new ByteArrayInputStream(fileBytes); | ||
inputStream = PGPUtil.getDecoderStream(inputStream); | ||
try { | ||
JcaPGPPublicKeyRingCollection ringCollection = new JcaPGPPublicKeyRingCollection(inputStream); | ||
Iterator<PGPPublicKeyRing> keyRingsIterator = ringCollection.getKeyRings(); | ||
while (keyRingsIterator.hasNext()) { | ||
PGPPublicKeyRing pgpPublicKeyRing = keyRingsIterator.next(); | ||
Iterator<PGPPublicKey> pubKeysIterator = pgpPublicKeyRing.getPublicKeys(); | ||
while (pubKeysIterator.hasNext()) { | ||
pubKey = pubKeysIterator.next(); | ||
} | ||
} | ||
} catch (PGPException e) { | ||
throw new IllegalArgumentException("Invalid public key"); | ||
} finally { | ||
inputStream.close(); | ||
} | ||
this.pubKey = pubKey; | ||
} | ||
|
||
private void initSigKey(byte[] sigkeyFileBytes) throws IOException { | ||
try (InputStream fileInputStream = new ByteArrayInputStream(sigkeyFileBytes);) { | ||
InputStream inputStream = PGPUtil.getDecoderStream(fileInputStream); | ||
KeyFingerPrintCalculator fpCalculator = new JcaKeyFingerprintCalculator(); | ||
PGPSecretKeyRingCollection pgpSec = new PGPSecretKeyRingCollection(inputStream, fpCalculator); | ||
|
||
Iterator<PGPSecretKeyRing> keyRingIter = pgpSec.getKeyRings(); | ||
while (keyRingIter.hasNext()) { | ||
PGPSecretKeyRing keyRing = keyRingIter.next(); | ||
|
||
Iterator<PGPSecretKey> keyIter = keyRing.getSecretKeys(); | ||
while (keyIter.hasNext()) { | ||
PGPSecretKey key = keyIter.next(); | ||
|
||
if (key.isSigningKey()) { | ||
signingKey = key; | ||
return; | ||
} | ||
} | ||
} | ||
} catch (PGPException e) { | ||
throw new IllegalArgumentException("Invalid signing key", e); | ||
} | ||
|
||
throw new IllegalArgumentException("Invalid signing key"); | ||
} | ||
|
||
private PGPPrivateKey getPrivateKey(PGPSecretKey secretKey) throws PGPException { | ||
return secretKey.extractPrivateKey( | ||
new JcePBESecretKeyDecryptorBuilder().build(sigkeyPassword.toCharArray())); | ||
} | ||
|
||
private byte[] signAndEncryptPayload(InputStream inputStream, PGPSecretKey secKey, PGPPublicKey pubKey, | ||
ByteArrayOutputStream outputStream) throws PGPException, IOException { | ||
int BUFFER_SIZE = 1 << 16; | ||
|
||
// Encryption | ||
PGPEncryptedDataGenerator encGen = new PGPEncryptedDataGenerator( | ||
new JcePGPDataEncryptorBuilder(SymmetricKeyAlgorithmTags.AES_256) | ||
.setWithIntegrityPacket(true) | ||
.setSecureRandom(new SecureRandom())); | ||
encGen.addMethod(new JcePublicKeyKeyEncryptionMethodGenerator(pubKey)); | ||
OutputStream encOut = encGen.open(outputStream, new byte[BUFFER_SIZE]); | ||
|
||
// Compression | ||
PGPCompressedDataGenerator cGen = new PGPCompressedDataGenerator(CompressionAlgorithmTags.ZIP); | ||
OutputStream cOut = cGen.open(encOut); | ||
|
||
// Signing | ||
PGPSignatureGenerator sGen = new PGPSignatureGenerator(new JcaPGPContentSignerBuilder(secKey.getPublicKey().getAlgorithm(), PGPUtil.SHA1)); | ||
sGen.init(PGPSignature.BINARY_DOCUMENT, getPrivateKey(secKey)); | ||
|
||
Iterator<String> it = secKey.getPublicKey().getUserIDs(); | ||
if (it.hasNext()) { | ||
PGPSignatureSubpacketGenerator spGen = new PGPSignatureSubpacketGenerator(); | ||
spGen.addSignerUserID(false, it.next()); | ||
sGen.setHashedSubpackets(spGen.generate()); | ||
} | ||
|
||
sGen.generateOnePassVersion(false).encode(cOut); | ||
|
||
// Literal Data generator and output stream | ||
byte[] data = inputStream.readAllBytes(); | ||
PGPLiteralDataGenerator lGen = new PGPLiteralDataGenerator(); | ||
OutputStream lOut = lGen.open(cOut, PGPLiteralData.BINARY, PGPLiteralData.CONSOLE, data.length, new Date()); | ||
|
||
lOut.write(data); | ||
sGen.update(data); | ||
|
||
lOut.close(); | ||
lGen.close(); | ||
|
||
sGen.generate().encode(cOut); | ||
cOut.close(); | ||
cGen.close(); | ||
encGen.close(); | ||
|
||
return outputStream.toByteArray(); | ||
} | ||
|
||
} | ||
|
Oops, something went wrong.