Class AesGcmHkdfStreaming

  • All Implemented Interfaces:
    StreamingAead

    public final class AesGcmHkdfStreaming
    extends java.lang.Object
    Streaming encryption using AES-GCM with HKDF as key derivation function.

    Each ciphertext uses a new AES-GCM key that is derived from the key derivation key, a randomly chosen salt of the same size as the key and a nonce prefix.

    The format of a ciphertext is header || segment_0 || segment_1 || ... || segment_k. The header has size this.getHeaderLength(). Its format is headerLength || salt || prefix. where headerLength is 1 byte determining the size of the header, salt is a salt used in the key derivation and prefix is the prefix of the nonce. In principle headerLength is redundant information, since the length of the header can be determined from the key size.

    segment_i is the i-th segment of the ciphertext. The size of segment_1 .. segment_{k-1} is ciphertextSegmentSize. segment_0 is shorter, so that segment_0, the header and other information of size firstSegmentOffset align with ciphertextSegmentSize.

    This class does not work on Android KitKat (API level 19) or older.

    Since:
    1.1.0
    • Constructor Summary

      Constructors 
      Constructor Description
      AesGcmHkdfStreaming​(byte[] ikm, java.lang.String hkdfAlg, int keySizeInBytes, int ciphertextSegmentSize, int firstSegmentOffset)
      Initializes a streaming primitive with a key derivation key and encryption parameters.
    • Method Summary

      All Methods Static Methods Instance Methods Concrete Methods 
      Modifier and Type Method Description
      static StreamingAead create​(AesGcmHkdfStreamingKey key)  
      long expectedCiphertextSize​(long plaintextSize)
      Returns the expected size of the ciphertext for a given plaintext.
      int getCiphertextOffset()  
      int getCiphertextOverhead()  
      int getCiphertextSegmentSize()  
      int getFirstSegmentOffset()  
      int getHeaderLength()  
      int getPlaintextSegmentSize()  
      java.nio.channels.ReadableByteChannel newDecryptingChannel​(java.nio.channels.ReadableByteChannel ciphertextChannel, byte[] associatedData)  
      java.io.InputStream newDecryptingStream​(java.io.InputStream ciphertextStream, byte[] associatedData)
      Returns a wrapper around ciphertextSource, such that any read-operation via the wrapper results in AEAD-decryption of the underlying ciphertext, using associatedData as associated authenticated data.
      java.nio.channels.WritableByteChannel newEncryptingChannel​(java.nio.channels.WritableByteChannel ciphertextChannel, byte[] associatedData)
      Returns a WritableByteChannel for plaintext.
      java.io.OutputStream newEncryptingStream​(java.io.OutputStream ciphertext, byte[] associatedData)
      Returns a wrapper around ciphertextDestination, such that any write-operation via the wrapper results in AEAD-encryption of the written data, using associatedData as associated authenticated data.
      java.nio.channels.SeekableByteChannel newSeekableDecryptingChannel​(java.nio.channels.SeekableByteChannel ciphertextSource, byte[] associatedData)
      Returns a SeekableByteChannel that allows to access the plaintext.
      com.google.crypto.tink.subtle.AesGcmHkdfStreaming.AesGcmHkdfStreamDecrypter newStreamSegmentDecrypter()  
      com.google.crypto.tink.subtle.AesGcmHkdfStreaming.AesGcmHkdfStreamEncrypter newStreamSegmentEncrypter​(byte[] aad)  
      • Methods inherited from class java.lang.Object

        clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
    • Constructor Detail

      • AesGcmHkdfStreaming

        public AesGcmHkdfStreaming​(byte[] ikm,
                                   java.lang.String hkdfAlg,
                                   int keySizeInBytes,
                                   int ciphertextSegmentSize,
                                   int firstSegmentOffset)
                            throws java.security.InvalidAlgorithmParameterException
        Initializes a streaming primitive with a key derivation key and encryption parameters.
        Parameters:
        ikm - input keying material used to derive sub keys.
        hkdfAlg - the JCE MAC algorithm name, e.g., HmacSha256, used for the HKDF key derivation.
        keySizeInBytes - the key size of the sub keys
        ciphertextSegmentSize - the size of ciphertext segments.
        firstSegmentOffset - the offset of the first ciphertext segment. That means the first segment has size ciphertextSegmentSize - getHeaderLength() - firstSegmentOffset
        Throws:
        java.security.InvalidAlgorithmParameterException - if ikm is too short, the key size not supported or ciphertextSegmentSize is to short.
    • Method Detail

      • newStreamSegmentEncrypter

        public com.google.crypto.tink.subtle.AesGcmHkdfStreaming.AesGcmHkdfStreamEncrypter newStreamSegmentEncrypter​(byte[] aad)
                                                                                                              throws java.security.GeneralSecurityException
        Throws:
        java.security.GeneralSecurityException
      • newStreamSegmentDecrypter

        public com.google.crypto.tink.subtle.AesGcmHkdfStreaming.AesGcmHkdfStreamDecrypter newStreamSegmentDecrypter()
                                                                                                              throws java.security.GeneralSecurityException
        Throws:
        java.security.GeneralSecurityException
      • getPlaintextSegmentSize

        public int getPlaintextSegmentSize()
      • getCiphertextSegmentSize

        public int getCiphertextSegmentSize()
      • getHeaderLength

        public int getHeaderLength()
      • getCiphertextOffset

        public int getCiphertextOffset()
      • getCiphertextOverhead

        public int getCiphertextOverhead()
      • getFirstSegmentOffset

        public int getFirstSegmentOffset()
      • expectedCiphertextSize

        public long expectedCiphertextSize​(long plaintextSize)
        Returns the expected size of the ciphertext for a given plaintext. The returned value includes the header and offset.
      • newEncryptingChannel

        public java.nio.channels.WritableByteChannel newEncryptingChannel​(java.nio.channels.WritableByteChannel ciphertextChannel,
                                                                          byte[] associatedData)
                                                                   throws java.security.GeneralSecurityException,
                                                                          java.io.IOException
        Description copied from interface: StreamingAead
        Returns a WritableByteChannel for plaintext. Any data written to the returned channel will be encrypted and the resulting ciphertext written to the provided ciphertextDestination
        Specified by:
        newEncryptingChannel in interface StreamingAead
        Parameters:
        ciphertextChannel - the channel to which the ciphertext is written.
        associatedData - data associated with the plaintext. This data is authenticated but not encrypted. It must be passed into the decryption.
        Throws:
        java.security.GeneralSecurityException
        java.io.IOException
      • newDecryptingChannel

        public java.nio.channels.ReadableByteChannel newDecryptingChannel​(java.nio.channels.ReadableByteChannel ciphertextChannel,
                                                                          byte[] associatedData)
                                                                   throws java.security.GeneralSecurityException,
                                                                          java.io.IOException
        Specified by:
        newDecryptingChannel in interface StreamingAead
        Throws:
        java.security.GeneralSecurityException
        java.io.IOException
      • newSeekableDecryptingChannel

        public java.nio.channels.SeekableByteChannel newSeekableDecryptingChannel​(java.nio.channels.SeekableByteChannel ciphertextSource,
                                                                                  byte[] associatedData)
                                                                           throws java.security.GeneralSecurityException,
                                                                                  java.io.IOException
        Description copied from interface: StreamingAead
        Returns a SeekableByteChannel that allows to access the plaintext.

        This method does not work on Android Marshmallow (API level 23) or older because these Android versions don't have the java.nio.channels.SeekableByteChannel interface.

        Specified by:
        newSeekableDecryptingChannel in interface StreamingAead
        Parameters:
        ciphertextSource - the ciphertext
        associatedData - the data associated with the ciphertext.
        Returns:
        SeekableByteChannel that allows random read access to the plaintext. The following methods of SeekableByteChannel are implemented:
        • long position() Returns the channel's position in the plaintext.
        • SeekableByteChannel position(long newPosition) Sets the channel's position. Setting the position to a value greater than the plaintext size is legal. A later attempt to read byte will immediately return an end-of-file indication.
        • int read(ByteBuffer dst) Bytes are read starting at the channel's position, and then the position is updated with the number of bytes actually read. All bytes returned have been authenticated. If the end of the stream has been reached -1 is returned. A result of -1 is authenticated (e.g. by checking the MAC of the last ciphertext chunk.) A call to this function attempts to fill dst, but it may return fewer bytes than requested, e.g. if the underlying ciphertextSource does not provide the requested number of bytes or if the plaintext ended.

          Throws IOException if a MAC verification failed. TODO: Should we extend the interface with read(ByteBuffer dst, long position) to avoid race conditions?

        • long size() Returns the size of the plaintext. TODO: Decide whether the result should be authenticated)
        • SeekableByteChannel truncate(long size) throws NonWritableChannelException because the channel is read-only.
        • int write(ByteBuffer src) throws NonWritableChannelException because the channel is read-only.
        • close() closes the channel
        • isOpen()
        Throws:
        java.security.GeneralSecurityException - if the header of the ciphertext is corrupt or if associatedData is not correct.
        java.io.IOException - if an IOException occurred while reading from ciphertextDestination.
      • newEncryptingStream

        public java.io.OutputStream newEncryptingStream​(java.io.OutputStream ciphertext,
                                                        byte[] associatedData)
                                                 throws java.security.GeneralSecurityException,
                                                        java.io.IOException
        Description copied from interface: StreamingAead
        Returns a wrapper around ciphertextDestination, such that any write-operation via the wrapper results in AEAD-encryption of the written data, using associatedData as associated authenticated data. The associated data is not included in the ciphertext and has to be passed in as parameter for decryption.
        Specified by:
        newEncryptingStream in interface StreamingAead
        Throws:
        java.security.GeneralSecurityException
        java.io.IOException
      • newDecryptingStream

        public java.io.InputStream newDecryptingStream​(java.io.InputStream ciphertextStream,
                                                       byte[] associatedData)
                                                throws java.security.GeneralSecurityException,
                                                       java.io.IOException
        Description copied from interface: StreamingAead
        Returns a wrapper around ciphertextSource, such that any read-operation via the wrapper results in AEAD-decryption of the underlying ciphertext, using associatedData as associated authenticated data.

        The returned InputStream may support mark()/reset(), but does not have to do it -- markSupported() provides the corresponding info.

        The returned InputStream supports skip(), yet possibly in an inefficient way, i.e. by reading a sequence of blocks until the desired position. If a more efficient skip()-functionality is needed, the Channel-based API can be used.

        Specified by:
        newDecryptingStream in interface StreamingAead
        Throws:
        java.security.GeneralSecurityException
        java.io.IOException