Start line:  
End line:  

Snippet Preview

Snippet HTML Code

Stack Overflow Questions
  /*
   * Copyright 2013-2015 Amazon.com, Inc. or its affiliates. All Rights Reserved.
   *
   * Licensed under the Apache License, Version 2.0 (the "License").
   * You may not use this file except in compliance with the License.
   * A copy of the License is located at
   *
   *  http://aws.amazon.com/apache2.0
   *
  * or in the "license" file accompanying this file. This file 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.amazonaws.services.s3.internal.crypto;
 
 
A AES/GCM specific CipherLite that support re-processing of input data via mark() and reset().

Author(s):
Hanson Char
See also:
CipherLite
 
 final class GCMCipherLite extends CipherLite {
     private static final int TAG_LENGTH = .
             .getTagLengthInBits() / 8;
    
Applicable only for encryption; set to zero otherwise.
 
     private final int tagLen;
    
The total number of bytes (excluding the final tag) that has been output by this cipher since the beginning of the input that have been processed by the AES/GCM cipher.
 
     private long outputByteCount;
    
The last part of the plaintext has been processed by the GCM cipher but not reflected in the outputByteCount.
 
     private boolean invisiblyProcessed;
    
The current number of bytes since the beginning of the plaintext that have been re-encrypted and output so far. If currentCount < outputByteCount, it means re-processing using AES/CTR is in progress. If currentCount == outputByteCount, it means it is not re-processing and therefore the AES/GCM cipher should be used.
 
     private long currentCount;
    
Used to mark the location where a reset can be made for re-processing purposes.
 
     private long markedCount;
    
An auxiliary cipher that is used for re-processing purposes, or null if no re-processing is in progress.
 
     private CipherLite aux;
    
The final bytes that has been computed, or null if it has not yet been computed.
 
     private byte[] finalBytes;
    
True if doFinal has been called; false otherwise.
 
     private boolean doneFinal;
    
True if a security exception has been thrown, which means this cipher lite must no longer be used.
 
     private boolean securityViolated;
 
     GCMCipherLite(Cipher cipherSecretKey secreteKeyint cipherMode) {
         super(cipher.secreteKeycipherMode);
          = cipherMode == . ?  : 0;
         if (cipherMode != .
                 && cipherMode != .) {
             throw new IllegalArgumentException();
         }
     }
 
     byte[] doFinal() throws IllegalBlockSizeException,
             BadPaddingException {
         if () {
             if ()
                 throw new SecurityException();
             // final bytes can only be null for decryption
             return  == null ? null : .clone();
         }
          = true;
          = super.doFinal();
        if ( == null)
            return null;    // only possible for decryption
        return .clone();
    }
    final byte[] doFinal(byte[] inputthrows IllegalBlockSizeException,
            BadPaddingException {
        return doFinal0(input, 0, input.length);
    }
    final byte[] doFinal(byte[] inputint inputOffsetint inputLen)
            throws IllegalBlockSizeExceptionBadPaddingException {
        return doFinal0(inputinputOffsetinputLen);
    }
    private final byte[] doFinal0(byte[] inputint inputOffsetint inputLen)
            throws IllegalBlockSizeExceptionBadPaddingException {
        if () {
            if ()
                throw new SecurityException();
            if (. == getCipherMode())
                return  == null ? null : .clone();
            // final bytes must have been previously computed via encryption
            int finalDataLen = . - ;
            if (inputLen == finalDataLen)
                return .clone();
            if (inputLen < finalDataLen) {
                if (inputLen +  == ) {
                    int from = . -  - inputLen;
                    return Arrays.copyOfRange(from.);
                }
            }
            throw new IllegalStateException("Inconsistent re-rencryption");
        }
         = true;
        // compute final bytes for the first time
         = super.doFinal(inputinputOffsetinputLen);
        if ( == null)
            return null;    // only possible for decryption
        return .clone();
    }

    

Parameters:
inputLen for mark() and reset() to work correctly, inputLen should always be in multiple of 16 bytes except for the very last part of the plaintext.
    byte[] update(byte[] inputint inputOffsetint inputLen) {
        byte[] out;
        if ( == null) {
            out = super.update(inputinputOffsetinputLen);
            if (out == null) {
                 = input.length > 0;
                return null;
            }
             += checkMax(out.length);
            // There is no need to update "currentCount" here given "aux" is
            // null, as currentCount is irrelevant when reencryption is NOT in
            // progress.
             = out.length == 0 && inputLen > 0;
        } else {
            out = .update(inputinputOffsetinputLen);
            if (out == null)
                return null;    // possible even for encryption
             += out.length;
            if ( == ) {
                 = null// flip back to the original GCM cipher
            } else if ( > ) {
                if (. == getCipherMode()) {
                    throw new IllegalStateException("currentCount=" + 
                        + " > outputByteCount=" + );
                }
                // For decryption, this is possible since AES/CTR doesn't know
                // about the tag at the end
                int finalBytesLen = ( == null ? 0 : .);
                long diff =  - ( - out.length) - finalBytesLen;
                 =  - finalBytesLen;
                 = null// flip back to the original GCM cipher
                return Arrays.copyOf(out, (int)diff);
            }
        }
        return out;
    }

    
Returns the input delta but only if it will not result in exceeding the limit of the maximum number of bytes that can be processed by AES/GCM.

Throws:
java.lang.SecurityException if the number of bytes processed has exceeded the maximum allowed by AES/GCM.
    private int checkMax(int delta) {
        if ( + delta > .) {
             = true;
            throw new SecurityException(
                    "Number of bytes processed has exceeded the maximum allowed by AES/GCM; [outputByteCount="
                            +  + ", delta=" + delta + "]");
        }
        return delta;
    }
    @Override long mark() {
        return this. =  == null ?  : ;
    }
    @Override boolean markSupported() { return true; }
    @Override void reset() {
        if ( <  || ) {
            try {
                 = createAuxiliary();
                // assign to currentCount after calling createAuillary, not
                // before, just in case createAuillary failed
                 = ;
            } catch (Exception e) {
                throw ((e instanceof RuntimeException)
                    ? (RuntimeException)e
                    : new IllegalStateException(e))
                    ;
            }
        }
    }

    
For testing purposes only.
    byte[] getFinalBytes() {
        return  == null ? null : .clone();
    }

    
For testing purposes. Applicable only during encryption: returns the tag that has been produced; or null otherwise.
    byte[] getTag() {
        return getCipherMode() != . ||  == null
             ? null
             : Arrays.copyOfRange(,
                 . - .)
             ;
    }

    
For testing purposes.
    long getOutputByteCount() {
        return ;
    }

    
For testing purposes.
    long getCurrentCount() {
        return ;
    }

    
For testing purposes.
    long getMarkedCount() {
        return ;
    }
New to GrepCode? Check out our FAQ X