All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.google.crypto.tink.StreamingAead Maven / Gradle / Ivy

// Copyright 2017 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
////////////////////////////////////////////////////////////////////////////////

package com.google.crypto.tink;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.channels.ReadableByteChannel;
import java.nio.channels.SeekableByteChannel;
import java.nio.channels.WritableByteChannel;
import java.security.GeneralSecurityException;

/**
 * An interface for streaming authenticated encryption with associated data.
 *
 * 

Streaming encryption is typically used for encrypting large plaintexts such as large files. * Tink may eventually contain multiple interfaces for streaming encryption depending on the * supported properties. This interface supports a streaming interface for symmetric encryption with * authentication. The underlying encryption modes are selected so that partial plaintext can be * obtained fast by decrypting and authenticating just a part of the ciphertext. * *

Security guarantees

* *

Instances of StreamingAead must follow the OAE2 definition as proposed in the paper "Online * Authenticated-Encryption and its Nonce-Reuse Misuse-Resistance" by Hoang, Reyhanitabar, Rogaway * and Vizár https://eprint.iacr.org/2015/189.pdf * *

Restrictions

* *

Encryption must be done in one session. There is no possibility to modify an existing * ciphertext or append to it (other than reencrypt the whole file again). One reason for this * restriction is the use of AES-GCM as one cipher to implement this interface. If single segments * are modified then this is equivalent to reusing the same IV twice, but reusing an IV twice leaks * an AES-GCM key. Another reason is that implementations of this interface have no protection * against roll-back attacks: an attacker can always try to restore a previous version of the file * without detection. * *

Blocking vs non-blocking I/O

* *

A channel can be in a blocking mode (i.e. always waits until the requested number of bytes * have been processed) or non-blocking mode (i.e. I/O operation will never block and may transfer * fewer bytes than were requested or possibly no bytes at all). * *

If the channel provided to the streaming encryption is in blocking mode then encryption and * decryption have the same property. That is, encryption always processes all the plaintext passed * in, and waits until complete segments have been written to the ciphertext channel (incomplete * segment, if any, is buffered). Similarly, decryption blocks until sufficiently many bytes have * been read from the ciphertext channel so that all the requested plaintext can be decrypted and * authenticated, or until the end of the plaintext has been reached, or an IOException occurred. * *

If the channel provided to the streaming encryption is in non-blocking mode, then encryption * and decryption are also non-blocking. Since encryption and decryption is done in segments it is * possible that for example a call attempting to read() returns no plaintext at all even if partial * ciphertext was read from the underlying channel. * *

Sample encryption

* *
{@code
 * StreamingAead s = ...
 * java.nio.channels.FileChannel ciphertextDestination =
 *     new FileOutputStream(ciphertextFile).getChannel();
 * byte[] aad = ...
 * WritableByteChannel encryptingChannel = s.newEncryptingChannel(ciphertextDestination, aad);
 * while ( ... ) {
 *   int r = encryptingChannel.write(buffer);
 *   ...
 * }
 * encryptingChannel.close();
 * }
* *

Sample full decryption

* *
{@code
 * StreamingAead s = ...
 * java.nio.channels.FileChannel ciphertextSource =
 *     new FileInputStream(ciphertextFile).getChannel();
 * byte[] aad = ...
 * ReadableByteChannel decryptingChannel = s.newDecryptingChannel(ciphertextSource, aad);
 * int chunkSize = ...
 * ByteBuffer buffer = ByteBuffer.allocate(chunkSize);
 * do {
 *   buffer.clear();
 *   int cnt = decryptingChannel.read(buffer);
 *   if (cnt > 0) {
 *     // Process cnt bytes of plaintext.
 *   } else if (read == -1) {
 *     // End of plaintext detected.
 *     break;
 *   } else if (read == 0) {
 *     // No ciphertext is available at the moment.
 *   }
 * }
 * }
* * @since 1.1.0 */ public 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 * {@code ciphertextDestination} * * @param ciphertextDestination the channel to which the ciphertext is written. * @param associatedData data associated with the plaintext. This data is authenticated * but not encrypted. It must be passed into the decryption. */ WritableByteChannel newEncryptingChannel( WritableByteChannel ciphertextDestination, byte[] associatedData) throws GeneralSecurityException, IOException; /** * 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. * * @param ciphertextSource the ciphertext * @param associatedData the data associated with the ciphertext. * @return {@link SeekableByteChannel} that allows random read access to the plaintext. The * following methods of SeekableByteChannel are implemented: *

    *
  • {@code long position()} Returns the channel's position in the plaintext. *
  • {@code 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. *
  • {@code 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 {@link IOException} if a MAC verification failed. TODO: Should we extend * the interface with read(ByteBuffer dst, long position) to avoid race conditions? *

  • {@code long size()} Returns the size of the plaintext. TODO: Decide whether the * result should be authenticated) *
  • {@code SeekableByteChannel truncate(long size)} throws {@link * java.nio.channels.NonWritableChannelException } because the channel is read-only. *
  • {@code int write(ByteBuffer src)} throws {@link * java.nio.channels.NonWritableChannelException } because the channel is read-only. *
  • {@code close()} closes the channel *
  • {@code isOpen()} *
* * @throws GeneralSecurityException if the header of the ciphertext is corrupt or if * associatedData is not correct. * @throws IOException if an IOException occurred while reading from ciphertextDestination. */ SeekableByteChannel newSeekableDecryptingChannel( SeekableByteChannel ciphertextSource, byte[] associatedData) throws GeneralSecurityException, IOException; ReadableByteChannel newDecryptingChannel( ReadableByteChannel ciphertextSource, byte[] associatedData) throws GeneralSecurityException, IOException; /** * Returns a wrapper around {@code ciphertextDestination}, such that any write-operation via * the wrapper results in AEAD-encryption of the written data, using {@code associatedData} * as associated authenticated data. The associated data is not included in the ciphertext * and has to be passed in as parameter for decryption. */ OutputStream newEncryptingStream(OutputStream ciphertextDestination, byte[] associatedData) throws GeneralSecurityException, IOException; /** * Returns a wrapper around {@code ciphertextSource}, such that any read-operation * via the wrapper results in AEAD-decryption of the underlying ciphertext, * using {@code associatedData} as associated authenticated data. * *

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

The returned InputStream supports {@code skip()}, yet possibly in an inefficient way, * i.e. by reading a sequence of blocks until the desired position. If a more efficient * {@code skip()}-functionality is needed, the Channel-based API can be used. */ InputStream newDecryptingStream(InputStream ciphertextSource, byte[] associatedData) throws GeneralSecurityException, IOException; }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy