Android Open Source - conceal Native G C M Cipher Input Stream






From Project

Back to project page conceal.

License

The source code is released under:

BSD License For Conceal software Copyright (c) 2014, Facebook, Inc. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that...

If you think the Android project conceal listed in this page is inappropriate, such as containing malicious code/tools or violating the copyright, please email info at java2s dot com, thanks.

Java Source Code

/*
 *  Copyright (c) 2014, Facebook, Inc.//  w w  w  .j av  a  2s .  c o  m
 *  All rights reserved.
 *
 *  This source code is licensed under the BSD-style license found in the
 *  LICENSE file in the root directory of this source tree. An additional grant
 *  of patent rights can be found in the PATENTS file in the same directory.
 *
 */

package com.facebook.crypto.streams;

import java.io.IOException;
import java.io.InputStream;

import com.facebook.crypto.cipher.NativeGCMCipher;

/**
 * This class is used to encapsulate decryption using GCM. On reads, bytes are first read from the
 * delegate input stream and decrypted before being store in the read buffer.
 */
public class NativeGCMCipherInputStream extends InputStream {

  private static final int UPDATE_BUFFER_SIZE = 256;

  private final TailInputStream mCipherDelegate;
  private final NativeGCMCipher mCipher;

  private final byte[] mUpdateBuffer;

  private boolean mTagChecked = false;

  /**
   * Creates a new input stream to read from.
   *
   * @param cipherDelegate The stream to read encrypted bytes from.
   * @param cipher The cipher used to decrypt the bytes.
   */
  public NativeGCMCipherInputStream(InputStream cipherDelegate, NativeGCMCipher cipher) {
    mCipherDelegate = new TailInputStream(cipherDelegate, NativeGCMCipher.TAG_LENGTH);
    mCipher = cipher;
    mUpdateBuffer = new byte[UPDATE_BUFFER_SIZE + mCipher.getCipherBlockSize()];
  }

  @Override
  public int available() throws IOException {
    return mCipherDelegate.available();
  }

  @Override
  public void close() throws IOException {
    try {
      ensureTagValid();
    } finally {
      mCipherDelegate.close();
    }
  }

  @Override
  public void mark(int readlimit) {
    throw new UnsupportedOperationException();
  }

  @Override
  public boolean markSupported() {
    return false;
  }

  @Override
  public int read() throws IOException {
    throw new UnsupportedOperationException();
  }

  @Override
  public int read(byte[] buffer) throws IOException {
    return read(buffer, 0, buffer.length);
  }

  @Override
  public int read(byte[] buffer, int offset, int length)
      throws IOException {
    if (buffer.length < offset + length) {
      throw new ArrayIndexOutOfBoundsException(offset + length);
    }

    int read = mCipherDelegate.read(buffer, offset, length);

    if (read == -1) {
      // since we have reached the end of the input stream we should
      // verify whether the tag of the data we've read in is valid.
      ensureTagValid();
      return -1;
    }

    int times = read / UPDATE_BUFFER_SIZE;
    int remainder = read % UPDATE_BUFFER_SIZE;

    int originalOffset = offset;
    int currentReadOffset = offset;

    for (int i = 0; i < times; ++i) {
      int bytesDecrypted = mCipher.update(buffer, offset, UPDATE_BUFFER_SIZE, mUpdateBuffer);
      System.arraycopy(mUpdateBuffer, 0, buffer, currentReadOffset, bytesDecrypted);
      currentReadOffset += bytesDecrypted;
      offset += UPDATE_BUFFER_SIZE;
    }

    if (remainder > 0) {
      int bytesDecrypted = mCipher.update(buffer, offset, remainder, mUpdateBuffer);
      System.arraycopy(mUpdateBuffer, 0, buffer, currentReadOffset, bytesDecrypted);
      currentReadOffset += bytesDecrypted;
    }

    return currentReadOffset - originalOffset;
  }

  private void ensureTagValid() throws IOException {
    if (mTagChecked) {
      return;
    }

    // sets it to true before executing it, since we put the cipher into a finalized
    // state and destroy it, so we should not execute this again.
    mTagChecked = true;
    try {
      mCipher.decryptFinal(mCipherDelegate.getTail(), NativeGCMCipher.TAG_LENGTH);
    } finally {
      mCipher.destroy();
    }
  }

  @Override
  public synchronized void reset() throws IOException {
    throw new UnsupportedOperationException();
  }

  @Override
  public long skip(long byteCount) throws IOException {
    throw new UnsupportedOperationException();
  }
}




Java Source Code List

com.facebook.android.crypto.keychain.SecureRandomFix.java
com.facebook.android.crypto.keychain.SharedPrefsBackedKeyChainTest.java
com.facebook.android.crypto.keychain.SharedPrefsBackedKeyChain.java
com.facebook.crypto.BouncyCastleHelper.java
com.facebook.crypto.CipherHelper.java
com.facebook.crypto.CryptoSerializerHelper.java
com.facebook.crypto.CryptoTestUtils.java
com.facebook.crypto.Crypto.java
com.facebook.crypto.Entity.java
com.facebook.crypto.FakeKeyChain.java
com.facebook.crypto.FbInstrumentationTestRunner.java
com.facebook.crypto.NativeGCMCipherInputStreamTest.java
com.facebook.crypto.NativeGCMCipherOutputStreamTest.java
com.facebook.crypto.NativeMacLayeredInputStreamTest.java
com.facebook.crypto.NativeMacLayeredOutputStreamTest.java
com.facebook.crypto.SimpleDecryptTest.java
com.facebook.crypto.SimpleEncryptTest.java
com.facebook.crypto.VersionCodes.java
com.facebook.crypto.benchmarks.BenchmarkNativeCryptoLibrary.java
com.facebook.crypto.benchmarks.CipherReadBenchmark.java
com.facebook.crypto.benchmarks.CipherWriteBenchmark.java
com.facebook.crypto.benchmarks.MacBenchmark.java
com.facebook.crypto.benchmarks.cipher.AESCipher.java
com.facebook.crypto.benchmarks.cipher.BaseCipher.java
com.facebook.crypto.benchmarks.cipher.BouncyCastleCCMCipher.java
com.facebook.crypto.benchmarks.cipher.BouncyCastleGCMCipher.java
com.facebook.crypto.benchmarks.cipher.NativeGCMCipherHelper.java
com.facebook.crypto.benchmarks.mac.BaseMac.java
com.facebook.crypto.benchmarks.mac.HMAC.java
com.facebook.crypto.benchmarks.mac.NativeMacHelper.java
com.facebook.crypto.benchmarks.mac.streams.MacLayeredInputStream.java
com.facebook.crypto.benchmarks.mac.streams.MacLayeredOutputStream.java
com.facebook.crypto.cipher.NativeGCMCipherException.java
com.facebook.crypto.cipher.NativeGCMCipher.java
com.facebook.crypto.exception.CryptoInitializationException.java
com.facebook.crypto.exception.KeyChainException.java
com.facebook.crypto.keychain.KeyChain.java
com.facebook.crypto.mac.NativeMac.java
com.facebook.crypto.streams.BetterCipherInputStreamTest.java
com.facebook.crypto.streams.BetterCipherInputStream.java
com.facebook.crypto.streams.FixedSizeByteArrayOutputStream.java
com.facebook.crypto.streams.NativeGCMCipherInputStream.java
com.facebook.crypto.streams.NativeGCMCipherOutputStream.java
com.facebook.crypto.streams.NativeMacLayeredInputStream.java
com.facebook.crypto.streams.NativeMacLayeredOutputStream.java
com.facebook.crypto.streams.TailBufferHelper.java
com.facebook.crypto.streams.TailInputStreamTest.java
com.facebook.crypto.streams.TailInputStream.java
com.facebook.crypto.util.Assertions.java
com.facebook.crypto.util.NativeCryptoLibrary.java
com.facebook.crypto.util.SystemNativeCryptoLibrary.java
com.facebook.proguard.annotations.DoNotStrip.java
com.facebook.proguard.annotations.InternalBuildOnly.java
com.facebook.proguard.annotations.KeepGettersAndSetters.java