Class Ghostryde

java.lang.Object
google.registry.rde.Ghostryde

public final class Ghostryde extends Object
Utility class for reading and writing data in the ghostryde container format.

Whenever we stage sensitive data to cloud storage (like XML RDE deposit data), we GHOST RYDE IT first to keep it safe from the prying eyes of anyone with access to the Google Cloud Console.

The encryption is similar to the "regular" RyDE RDE deposit file encryption. The main difference (and the reason we had to create a custom encryption) is that the RDE deposit has a tar file in the encoding. A tar file needs to know its final size in the header, which means we have to create the entire deposit before we can start encoding it.

Deposits are big, and there's no reason to hold it all in memory. Instead, save a "staging" version encrypted with Ghostryde instead of "RyDE" (the RDE encryption/encoding), using the "rde-staging" keys. We also remember the actual data size during the staging creation.

Then when we want to create the actual deposits, we decrypt the staging version, and using the saved value for the data size we can encrypt with "RyDE" using the receiver key.

Here's how you write a file:


 File in = new File("lol.txt");
 File out = new File("lol.txt.ghostryde");
 File lengthOut = new File("lol.length.ghostryde");
 try (OutputStream output = new FileOutputStream(out);
     OutputStream lengthOutput = new FileOutputStream(lengthOut);
     OutputStream ghostrydeEncoder = Ghostryde.encoder(output, publicKey, lengthOut);
     InputStream input = new FileInputStream(in)) {
       ByteStreams.copy(input, ghostrydeEncoder);
     }
 

Here's how you read a file:


 File in = new File("lol.txt.ghostryde");
 File out = new File("lol.txt");
 Ghostryde ghost = new Ghostryde(1024);
 try (InputStream fileInput = new FileInputStream(in);
     InputStream ghostrydeDecoder = new Ghostryde.decoder(fileInput, privateKey);
     OutputStream fileOutput = new FileOutputStream(out)) {
       ByteStreams.copy(ghostryderDecoder, fileOutput);
     }
 

Simple API

If you're writing test code or are certain your data can fit in memory, you might find these static methods more convenient:


 byte[] data = "hello kitty".getBytes(UTF_8);
 byte[] blob = Ghostryde.encode(data, publicKey);
 byte[] result = Ghostryde.decode(blob, privateKey);

 

GhostRYDE Format

A .ghostryde file is the exact same thing as a .gpg file, except the OpenPGP message layers will always be present and in a specific order. You can analyse the layers on the command-line using the gpg --list-packets blah.ghostryde command.

Ghostryde is different from RyDE in the sense that ghostryde is only used for internal storage; whereas RyDE is meant to protect data being stored by a third-party.

  • Method Details

    • encode

      public static byte[] encode(byte[] data, org.bouncycastle.openpgp.PGPPublicKey key) throws IOException
      Creates a ghostryde file from an in-memory byte array.
      Throws:
      IOException
    • decode

      public static byte[] decode(byte[] data, org.bouncycastle.openpgp.PGPPrivateKey key) throws IOException
      Deciphers a ghostryde file from an in-memory byte array.
      Throws:
      IOException
    • readLength

      public static long readLength(InputStream lengthStream) throws IOException
      Throws:
      IOException
    • encoder

      public static ImprovedOutputStream encoder(OutputStream output, org.bouncycastle.openpgp.PGPPublicKey encryptionKey, @Nullable OutputStream lengthOutput)
      Creates a Ghostryde Encoder.

      Optionally can also save the total length of the data written to an OutputStream.

      This is necessary because the RyDE format uses a tar file which requires the total length in the header. We don't want to have to decrypt the entire ghostryde file to determine the length, so we just save it separately.

      Parameters:
      output - where to write the encrypted data
      encryptionKey - the encryption key to use
      lengthOutput - if not null - will save the total length of the data written to this output. See readLength(java.io.InputStream).
    • encoder

      public static ImprovedOutputStream encoder(OutputStream output, org.bouncycastle.openpgp.PGPPublicKey encryptionKey)
      Creates a Ghostryde Encoder.
      Parameters:
      output - where to write the encrypted data
      encryptionKey - the encryption key to use
    • decoder

      public static ImprovedInputStream decoder(InputStream input, org.bouncycastle.openpgp.PGPPrivateKey decryptionKey)
      Creates a Ghostryde decoder.
      Parameters:
      input - from where to read the encrypted data
      decryptionKey - the decryption key to use