Class StreamingArtifactCipher

java.lang.Object
com.kingsrook.qqq.backend.core.crypto.StreamingArtifactCipher

public class StreamingArtifactCipher extends Object
Streaming authenticated encryption of large artifacts (e.g., backup files), built on Google Tink's StreamingAead (AES256_GCM_HKDF_1MB), which authenticates every segment and detects truncation. Each artifact gets a FRESH data key. That data key is wrapped (AES-256-GCM) by the key-encryption key (KEK) from a QKeyProviderInterface, and the wrapped data key, the KEK's id and its version are written in a header at the start of the stream:
   "QSC1" | UTF keyId | UTF keyVersion | int wrappedLength | wrappedDataKey | tink stream...
 
The whole header is also bound into the stream as associated data, so any change to it makes decryption fail. Decrypting reads the key id and version from the header and asks the provider for exactly that version, so data written under an old key version stays readable after rotation. Key material is never logged and never put in an exception message.
  • Constructor Details

    • StreamingArtifactCipher

      public StreamingArtifactCipher(QKeyProviderInterface keyProvider)
      Constructor
  • Method Details

    • newEncryptingStream

      public OutputStream newEncryptingStream(String keyRef, OutputStream destination) throws QException
      Wrap an output stream so that what is written to it is encrypted (under a new data key, wrapped by the CURRENT version of keyRef) into the destination. The header is written immediately. The returned stream MUST be closed to finish the encryption (an unclosed stream is a truncated one, and will fail to decrypt); closing it also closes the destination.
      Throws:
      QException
    • newDecryptingStream

      public InputStream newDecryptingStream(InputStream source) throws QException
      Wrap an input stream of encrypted data (as written by newEncryptingStream) so that reading from it yields the plaintext. Reads the header now, and gets the named key version from the provider. Throws QException if the header is malformed, the key is unavailable, or the data key cannot be unwrapped (wrong key). Reading the returned stream throws IOException if the content has been altered or truncated.
      Throws:
      QException
    • readKeyIdAndVersion

      public static String[] readKeyIdAndVersion(InputStream source) throws QException
      Read just the key id and version named in the header of an encrypted stream (consumes the header from the stream). Useful for finding which runs still need an old key version.
      Throws:
      QException