Package com.google.k2crypto.keyversions

Source Code of com.google.k2crypto.keyversions.AESKeyVersion$Builder

/*
* Copyright 2014 Google Inc. 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. 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.k2crypto.keyversions;

import com.google.k2crypto.exceptions.BuilderException;
import com.google.k2crypto.keyversions.KeyVersionProto.KeyVersionCore;
import com.google.k2crypto.keyversions.KeyVersionProto.KeyVersionData;
import com.google.k2crypto.keyversions.AesKeyVersionProto.AesKeyVersionCore;
import com.google.k2crypto.keyversions.AesKeyVersionProto.AesKeyVersionData;
import com.google.protobuf.ByteString;
import com.google.protobuf.ExtensionRegistry;
import com.google.protobuf.InvalidProtocolBufferException;

import java.security.SecureRandom;

import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;

/**
* This class represents an AES key version in K2. It allows you to encrypt and
* decrypt messaged using AES symmetric key encryption
*
* @author John Maheswaran (maheswaran@google.com)
*/
@KeyVersionInfo(
    type = KeyVersionProto.Type.AES,
    proto = AesKeyVersionProto.class)
public class AESKeyVersion extends SymmetricKeyVersion {
 
  private static final int BLOCK_SIZE = 16; // bytes;
 
  /**
   * The key length in bytes (128 bits / 8 = 16 bytes) Can be 16, 24 or 32
   * (NO OTHER VALUES)
   */
  private int keyVersionLengthInBytes = 16;

  /**
   * SecretKey object representing the key matter in the AES key
   */
  private SecretKey secretKey;

  /**
   * initialization vector used for encryption and decryption
   */
  private byte[] initVector;

  /**
   * Enum representing all supported modes Supported modes:
   *    CBC, ECB, OFB, CFB, CTR Unsupported
   * modes: XTS, OCB
   */
  public enum Mode {
    CBC, ECB, OFB, CFB, CTR
  }

  /**
   * The encryption mode
   */
  private Mode mode;

  /**
   * Enum representing all supported padding modes.
   */
  public enum Padding {
    PKCS5
  }

  /**
   * Supported padding: PKCS5PADDING Unsupported padding: PKCS7Padding,
   * ISO10126d2Padding, X932Padding, ISO7816d4Padding, ZeroBytePadding
   */
  private Padding padding;

  /**
   * Method to give length of key in BITS. Used to prevent mixing up bytes
   * and bits
   *
   * @return Key length in BITS
   */
  private int keyLengthInBits() {
    return this.keyVersionLengthInBytes * 8;
  }

  /**
   *
   * Method to give length of key in BYTES. Used to prevent mixing up bytes
   * and bits
   *
   * @return Key length in BYTES
   */
  private int keyLengthInBytes() {
    return this.keyVersionLengthInBytes;
  }
 
  /**
   * represents the algorithm, mode, and padding to use and paddings
   * (NOT algorithm - AES ONLY)
   *
   */
  private String algModePadding;

  /**
   * Cipher for encrypting data using this AES key version
   */
  private Cipher encryptingCipher;

  /**
   * Cipher for decrypting data using this AES key version
   */
  private Cipher decryptingCipher;

  /**
   * Constructor to make an AESKeyVersion using the AESKeyVersionBuilder.
   * Private to prevent use unless through the AESKeyVersionBuilder
   *
   * @param builder An AESKeyVersionBuilder with all the variables set according
   *                to how you want the AESKeyVersion to be setup.
   * @throws BuilderException
   */
  private AESKeyVersion(Builder builder) throws BuilderException {
    super(builder);
    // set key version length, mode and padding based on the key version builder
    this.keyVersionLengthInBytes = builder.keyVersionLengthInBytes;
    this.mode = builder.mode;
    this.padding = builder.padding;

    // IMPORTANT! this line of code updates the algorithm/mode/padding string
    // to reflect the new mode and padding. The class will not work if you move
    // or remove this line of code
    this.algModePadding = "AES/" + this.mode + "/" + padding + "padding";

    // use try catch block to abstract from individual exceptions using
    // BuilderException
    try {
      // set the key matter and initialization vector from input if is
      // was provided
      if (builder.keyVersionMatterInitVectorProvided) {
        // load the initialization vector
        initVector = (builder.initVector == null ?
            null : builder.initVector.clone());

        // initialize secret key using key matter byte array
        secretKey = new SecretKeySpec(
            builder.keyVersionMatter, 0, this.keyLengthInBytes(), "AES");
       
      } else {
        // Generate the key using JCE crypto libraries
        KeyGenerator keyGen = KeyGenerator.getInstance("AES");
        keyGen.init(this.keyLengthInBits());
        secretKey = keyGen.generateKey();
      }
     
      if (initVector == null) {
        // use this secure random number generator to initialize
        // the vector with random bytes
        SecureRandom prng = new SecureRandom();
        initVector = new byte[BLOCK_SIZE];
        prng.nextBytes(initVector);       
      }

      // make an AES cipher that we can use for encryption
      this.encryptingCipher = Cipher.getInstance(this.algModePadding);

      // initialize the encrypting cipher
      switch (this.mode) {
        case ECB:
          // Initialize the cipher using the secret key -
          // ECB does NOT use an initialization vector
          encryptingCipher.init(Cipher.ENCRYPT_MODE, this.secretKey);
          break;
        case CBC:
        case OFB:
        case CFB:
        case CTR:
          // Initialize the cipher using the secret key of this class
          // and the initialization vector
          encryptingCipher.init(Cipher.ENCRYPT_MODE, this.secretKey,
              new IvParameterSpec(this.initVector));
          break;
        default:
          throw new BuilderException("Unrecognized mode");
      }

      // make an AES cipher that we can use for decryption
      this.decryptingCipher = Cipher.getInstance(this.algModePadding);

      // initialize the decrypting cipher
      switch (this.mode) {
        case ECB:
          // Initialize the cipher using the secret key -
          // ECB does NOT use an initialization vector
          decryptingCipher.init(Cipher.DECRYPT_MODE, secretKey);
          break;
        case CBC:
        case OFB:
        case CFB:
        case CTR:
          // Initialize the cipher using the secret key of this class
          // and the initialization vector
          decryptingCipher.init(
              Cipher.DECRYPT_MODE, secretKey, new IvParameterSpec(initVector));
          break;
        default:
          throw new BuilderException("Unrecognized mode");
      }

      // Catch all exceptions
    } catch (Exception e) {
      // Propagate the exception up using BuilderException
      throw new BuilderException("Building AESKeyVersion failed", e);
    }
  }
 
  /**
   * Public method to get the byte array of the AES key version matter
   *
   * @return The byte array representation of the AES key version matter
   */
  public byte[] getKeyVersionMatter() {
    return this.secretKey.getEncoded();
  }
 
  /**
   * Returns a copy of the IV.
   */
  public byte[] getInitVector() {
    return initVector.clone();
  }
 
  /**
   * Returns the algorithm, mode, and padding string passed to JCE.
   */
  public String getAlgModePadding() {
    return algModePadding;
  }
 
  /**
   * Method to get the encrypting cipher of this key version
   *
   * @return The Cipher object representing the encrypting cipher
   *         of this key version
   */
  @Override
  public Cipher getEncryptingCipher() {
    return this.encryptingCipher;
  }

  /**
   * Method to get the decrypting cipher of this key version
   *
   * @return The Cipher object representing the decrypting cipher
   *         of this key version
   */
  @Override
  public Cipher getDecryptingCipher() {
    return this.decryptingCipher;
  }

  /**
   * @see KeyVersion#buildCore()
   */
  @Override
  protected KeyVersionCore.Builder buildCore() {
    AesKeyVersionCore.Builder coreBuilder = AesKeyVersionCore.newBuilder();
   
    // Populate the core builder
    coreBuilder.setMatter(ByteString.copyFrom(secretKey.getEncoded()));
   
    // We can just use valueOf here because the enum constants have the same
    // names. This may not be the case for all key versions...
    coreBuilder.setBlockMode(KeyVersionProto.BlockMode.valueOf(mode.name()));
    coreBuilder.setPadding(KeyVersionProto.Padding.valueOf(padding.name()));
   
    KeyVersionCore.Builder builder = super.buildCore();
    builder.setExtension(AesKeyVersionCore.extension, coreBuilder.build());
    return builder;
  }
 
  /**
   * @see KeyVersion#buildData()
   */
  @Override
  public KeyVersionData.Builder buildData() {
    AesKeyVersionData.Builder dataBuilder = AesKeyVersionData.newBuilder();
    // TODO(darylseah): Populate the data builder
   
    KeyVersionData.Builder builder = super.buildData();
    builder.setExtension(AesKeyVersionData.extension, dataBuilder.build());
    return builder;
  }

  /**
   * This class represents a key version builder for AES key versions.
   *
   * @author John Maheswaran (maheswaran@google.com)
   */
  public static class Builder extends KeyVersion.Builder {
    /**
     * key size can be 16, 24 or 32
     */
    private int keyVersionLengthInBytes = 16;
   
    /**
     * Supported modes: CBC, ECB, OFB, CFB, CTR Unsupported modes: XTS, OCB
     */
    private Mode mode = Mode.CTR;

    /**
     * Supported paddings depends on Java implementation. Upgrade java
     * implementation to support more paddings. Supported padding: PKCS5PADDING
     * Unsupported padding: PKCS7Padding, ISO10126d2Padding, X932Padding,
     * ISO7816d4Padding, ZeroBytePadding
     */
    private Padding padding = Padding.PKCS5;

    /**
     * Byte array that will represent the key matter
     */
    private byte[] keyVersionMatter;
   
    /**
     * Byte array that will represent the initialization vector
     */
    private byte[] initVector;

    /**
     * Flag to indicate to the parent class (AESKeyVersion) whether the key
     * matter and initialization vector have been manually set (true if and
     * only if they have been manually set)
     */
    private boolean keyVersionMatterInitVectorProvided = false;

    /**
     * Set the key version length
     *
     * @param keyVersionLength Integer representing key version length in BYTES,
     *                         can be 16, 24, 32
     * @return This object with keyVersionLength updated
     */
    public Builder keyVersionLengthInBytes(int keyVersionLength) {
      this.keyVersionLengthInBytes = keyVersionLength;
      return this;
    }

    /**
     * Set the encryption mode
     *
     * @param mode representing the encryption mode.
     *             Supported modes: CBC, ECB, OFB, CFB, CTR
     * @return This object with mode updated
     */
    public Builder mode(Mode mode) {
      if (mode == null) {
        throw new NullPointerException("mode");
      }
      this.mode = mode;
      return this;
    }

    /**
     * Set the padding
     *
     * @param padding String representing the padding. Supported padding: PKCS5
     * @return This object with padding updated
     */
    public Builder padding(Padding padding) {
      if (padding == null) {
        throw new NullPointerException("padding");
      }
      this.padding = padding;
      return this;
    }

    /**
     *
     * @param keyVersionMatter Byte array representing the key matter
     * @param initVector Byte array representing the initialization vector
     * @return This object with key matter, initialization vector set
     */
    public Builder matterVector(byte[] keyVersionMatter, byte[] initVector) {
      if (keyVersionMatter == null) {
        throw new NullPointerException("keyVersionMatter");
      }
     
      // This flag indicates to the parent class (AESKeyVersion) that the
      // key matter and initialization vector have been manually set
      keyVersionMatterInitVectorProvided = true;
      // set the key matter
      this.keyVersionMatter = keyVersionMatter;
      // set the initialization vector
      this.initVector = initVector;
      // set derived key size
      keyVersionLengthInBytes = keyVersionMatter.length;
           
      return this;
    }

    /**
     * @see KeyVersion.Builder#withData(KeyVersionData, ExtensionRegistry)
     */
    @Override
    public Builder withData(KeyVersionData kvData, ExtensionRegistry registry)
        throws InvalidProtocolBufferException {
      super.withData(kvData, registry);
     
      @SuppressWarnings("unused")
      AesKeyVersionData data = kvData.getExtension(AesKeyVersionData.extension);
      // TODO(darylseah): Extract info from data (currently not used)
     
      return this;
    }

    /**
     * @see KeyVersion.Builder#withCore(KeyVersionCore)
     */
    @Override
    protected Builder withCore(KeyVersionCore kvCore)
        throws InvalidProtocolBufferException {
      super.withCore(kvCore);
     
      // Extract info from core
      AesKeyVersionCore core = kvCore.getExtension(AesKeyVersionCore.extension);
      this.matterVector(core.getMatter().toByteArray(), null);
     
      // valueOf()s below can fail if the mode/padding stored is unsupported
      this.mode(Mode.valueOf(core.getBlockMode().name()));
      this.padding(Padding.valueOf(core.getPadding().name()));
     
      return this;
    }

    /**
     * Method to build a new AESKeyVersion
     *
     * @return An AESKeyVersion with the parameters set from the builder
     * @throws BuilderException
     */
    @Override
    public AESKeyVersion build() throws BuilderException {
      try {
        return new AESKeyVersion(this);
      } catch (Exception e) {
        throw new BuilderException("Building AESKeyVersion failed", e);
      }
    }
  }
}
TOP

Related Classes of com.google.k2crypto.keyversions.AESKeyVersion$Builder

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.