I want to create a OutputStream
from another OutputStream
in which the new OutputStream
will automatically encrypt the content I write to that OutputStream
. I want to use Bouncy Castle since I am already using that dependency for other functionality.
I see various questions over the internet how to encrypt data with Bouncy Castle, but the answers either encrypt a given File
(I don't use files, I use OutputStream
s) or have a huge amount of code I need to copy paste. I can not believe it must be that difficult.
This is my setup:
- I am using this Bouncy Castle dependency (V1.68)
- I am using Java 8
- I have a public and private key generated by https://pgpkeygen.com/. The algorithm is RSA and the keysize is 1024.
- I saved the public key and private key as a file on my machine
- I want to make sure the test below passes
I have some code commented out, the init function on Cipher (the code compiles, but the test fails). I don't know what I should put in as second argument in the init function. The read functions are from: https://github.com/jordanbaucke/PGP-Sign-and-Encrypt/blob/472d8932df303d6861ec494a3e942ea268eaf25f/src/SignAndEncrypt.java#L272. Only the testEncryptDecryptWithoutSigning is writting by me.
Code:
@Test
void testEncryptDecryptWithoutSigning() throws Exception {
// The data will be written to this property
ByteArrayOutputStream baos = new ByteArrayOutputStream();
Security.addProvider(new BouncyCastleProvider());
PGPSecretKey privateKey = readSecretKey(pathToFile("privatekey0"));
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
//cipher.init(Cipher.ENCRYPT_MODE, privateKey);
CipherOutputStream os = new CipherOutputStream(baos, cipher);
// I also need to use a PrintWriter
PrintWriter printWriter =
new PrintWriter(new BufferedWriter(new OutputStreamWriter(
os,
StandardCharsets.UTF_8.name())));
// This is an example of super secret data to write
String data = "Some very sensitive data";
printWriter.print(data);
printWriter.close();
// At this point, the data is 'inside' the byte array property
// Assert the text is encrypted
if (baos.toString(StandardCharsets.UTF_8.name()).equals(data)) {
throw new RuntimeException("baos not encrypted");
}
PGPSecretKey publicKey = readSecretKey(pathToFile("publickey0"));
//cipher.init(Cipher.DECRYPT_MODE, publicKey);
ByteArrayInputStream inputStream = new ByteArrayInputStream(baos.toByteArray());
ByteArrayOutputStream decrypted = new ByteArrayOutputStream();
// Decrypt the stream, but how?
if (!decrypted.toString(StandardCharsets.UTF_8.name()).equals(data)) {
throw new RuntimeException("Not successfully decrypted");
}
}
static PGPSecretKey readSecretKey(InputStream input) throws IOException, PGPException
{
PGPSecretKeyRingCollection pgpSec = new PGPSecretKeyRingCollection(
PGPUtil.getDecoderStream(input), new JcaKeyFingerprintCalculator());
//
// we just loop through the collection till we find a key suitable for encryption, in the real
// world you would probably want to be a bit smarter about this.
//
Iterator keyRingIter = pgpSec.getKeyRings();
while (keyRingIter.hasNext())
{
PGPSecretKeyRing keyRing = (PGPSecretKeyRing)keyRingIter.next();
Iterator keyIter = keyRing.getSecretKeys();
while (keyIter.hasNext())
{
PGPSecretKey key = (PGPSecretKey)keyIter.next();
if (key.isSigningKey())
{
return key;
}
}
}
throw new IllegalArgumentException("Can't find signing key in key ring.");
}
static PGPSecretKey readSecretKey(String fileName) throws IOException, PGPException
{
InputStream keyIn = new BufferedInputStream(new FileInputStream(fileName));
PGPSecretKey secKey = readSecretKey(keyIn);
keyIn.close();
return secKey;
}
static PGPPublicKey readPublicKey(String fileName) throws IOException, PGPException
{
InputStream keyIn = new BufferedInputStream(new FileInputStream(fileName));
PGPPublicKey pubKey = readPublicKey(keyIn);
keyIn.close();
return pubKey;
}
/**
* A simple routine that opens a key ring file and loads the first available key
* suitable for encryption.
*
* @param input data stream containing the public key data
* @return the first public key found.
* @throws IOException
* @throws PGPException
*/
static PGPPublicKey readPublicKey(InputStream input) throws IOException, PGPException
{
PGPPublicKeyRingCollection pgpPub = new PGPPublicKeyRingCollection(
PGPUtil.getDecoderStream(input), new JcaKeyFingerprintCalculator());
//
// we just loop through the collection till we find a key suitable for encryption, in the real
// world you would probably want to be a bit smarter about this.
//
Iterator keyRingIter = pgpPub.getKeyRings();
while (keyRingIter.hasNext())
{
PGPPublicKeyRing keyRing = (PGPPublicKeyRing)keyRingIter.next();
Iterator keyIter = keyRing.getPublicKeys();
while (keyIter.hasNext())
{
PGPPublicKey key = (PGPPublicKey)keyIter.next();
if (key.isEncryptionKey())
{
return key;
}
}
}
throw new IllegalArgumentException("Can't find encryption key in key ring.");
}