Package org.keyczar

Source Code of org.keyczar.Crypter

/*
* Copyright 2008 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 org.keyczar;

import org.apache.log4j.Logger;
import org.keyczar.enums.KeyPurpose;
import org.keyczar.exceptions.BadVersionException;
import org.keyczar.exceptions.InvalidSignatureException;
import org.keyczar.exceptions.KeyNotFoundException;
import org.keyczar.exceptions.KeyczarException;
import org.keyczar.exceptions.ShortCiphertextException;
import org.keyczar.i18n.Messages;
import org.keyczar.interfaces.DecryptingStream;
import org.keyczar.interfaces.KeyczarReader;
import org.keyczar.interfaces.VerifyingStream;
import org.keyczar.util.Base64Coder;

import java.nio.ByteBuffer;

/**
* Crypters may both encrypt and decrypt data using sets of symmetric or private
* keys. Sets of public keys may only be used with {@link Encrypter} objects.
*
* @author steveweis@gmail.com (Steve Weis)
*
*/
public class Crypter extends Encrypter {
  private static final int DECRYPT_CHUNK_SIZE = 1024;
  private static final Logger LOG = Logger.getLogger(Crypter.class);
  private static final StreamCache<DecryptingStream> CRYPT_CACHE
    = new StreamCache<DecryptingStream>();

  /**
   * Initialize a new Crypter with a KeyczarReader. The corresponding key set
   * must have a purpose {@link org.keyczar.enums.KeyPurpose#DECRYPT_AND_ENCRYPT}.
   *
   * @param reader A reader to read keys from
   * @throws KeyczarException In the event of an IO error reading keys or if the
   * key set does not have the appropriate purpose.
   */
  public Crypter(KeyczarReader reader) throws KeyczarException {
    super(reader);
  }

  /**
   * Initialize a new Crypter with a key set location. This will attempt to
   * read the keys using a KeyczarFileReader. The corresponding key set
   * must have a purpose of
   * {@link org.keyczar.enums.KeyPurpose#DECRYPT_AND_ENCRYPT}.
   *
   * @param fileLocation Directory containing a key set
   * @throws KeyczarException In the event of an IO error reading keys or if the
   * key set does not have the appropriate purpose.
   */
  public Crypter(String fileLocation) throws KeyczarException {
    super(fileLocation);
  }

  /**
   * Decrypt the given byte array of ciphertext
   *
   * @param input The input ciphertext
   * @return The decrypted plaintext
   * @throws KeyczarException If the input is malformed, the ciphertext
   * signature does not verify, the decryption key is not found, or a JCE
   * error occurs.
   */
  public byte[] decrypt(byte[] input) throws KeyczarException {
    ByteBuffer output = ByteBuffer.allocate(input.length);
    decrypt(ByteBuffer.wrap(input), output);
    output.reset();
    byte[] outputBytes = new byte[output.remaining()];
    output.get(outputBytes);
    return outputBytes;
  }

  /**
   * Decrypt the given ciphertext input ByteBuffer and write the decrypted
   * plaintext to the output ByteBuffer
   *
   * @param input The input ciphertext. Will not be modified.
   * @param output The output buffer to write the decrypted plaintext
   * @throws KeyczarException If the input is malformed, the ciphertext
   * signature does not verify, the decryption key is not found, or a JCE
   * error occurs.
   */
  public void decrypt(ByteBuffer input, ByteBuffer output)
      throws KeyczarException {
    ByteBuffer inputCopy = input.asReadOnlyBuffer();
    LOG.debug(Messages.getString("Crypter.Decrypting", inputCopy.remaining()));
    if (inputCopy.remaining() < HEADER_SIZE) {
      throw new ShortCiphertextException(inputCopy.remaining());
    }
    byte version = inputCopy.get();
    if (version != FORMAT_VERSION) {
      throw new BadVersionException(version);
    }

    byte[] hash = new byte[KEY_HASH_SIZE];
    inputCopy.get(hash);
    KeyczarKey key = getKey(hash);
    if (key == null) {
      throw new KeyNotFoundException(hash);
    }

    // The input to decrypt is now positioned at the start of the ciphertext
    inputCopy.mark();

    DecryptingStream cryptStream = CRYPT_CACHE.get(key);
    if (cryptStream == null) {
      cryptStream = (DecryptingStream) key.getStream();
    }

    VerifyingStream verifyStream = cryptStream.getVerifyingStream();
    if (inputCopy.remaining() < verifyStream.digestSize()) {
      throw new ShortCiphertextException(inputCopy.remaining());
    }

    // Slice off the signature into another buffer
    inputCopy.position(inputCopy.limit() - verifyStream.digestSize());
    ByteBuffer signature = inputCopy.slice();

    // Reset the position of the input to start of the ciphertext
    inputCopy.reset();
    inputCopy.limit(inputCopy.limit() - verifyStream.digestSize());

    // Initialize the crypt stream. This may read an IV if any.
    cryptStream.initDecrypt(inputCopy);

    // Verify the header and IV if any
    ByteBuffer headerAndIvToVerify = input.asReadOnlyBuffer();
    headerAndIvToVerify.limit(inputCopy.position());
    verifyStream.initVerify();
    verifyStream.updateVerify(headerAndIvToVerify);

    output.mark();
    // This will process large input in chunks, rather than all at once. This
    // avoids making two passes through memory.
    while (inputCopy.remaining() > DECRYPT_CHUNK_SIZE) {
      ByteBuffer ciphertextChunk = inputCopy.slice();
      ciphertextChunk.limit(DECRYPT_CHUNK_SIZE);
      cryptStream.updateDecrypt(ciphertextChunk, output);
      ciphertextChunk.rewind();
      verifyStream.updateVerify(ciphertextChunk);
      inputCopy.position(inputCopy.position() + DECRYPT_CHUNK_SIZE);
    }
    inputCopy.mark();
    verifyStream.updateVerify(inputCopy);
    if (!verifyStream.verify(signature)) {
      throw new InvalidSignatureException();
    }
    inputCopy.reset();
    cryptStream.doFinalDecrypt(inputCopy, output);
    output.limit(output.position());
    CRYPT_CACHE.put(key, cryptStream);
  }

  /**
   * Decrypt the given web-safe Base64 encoded ciphertext and return the
   * decrypted plaintext as a String.
   *
   * @param ciphertext The encrypted ciphertext in web-safe Base64 format
   * @return The decrypted plaintext as a string
   * @throws KeyczarException If the input is malformed, the ciphertext
   * signature does not verify, the decryption key is not found, the input is
   * not web-safe Base64 encoded, or a JCE error occurs.
   */
  public String decrypt(String ciphertext) throws KeyczarException {
    return new String(decrypt(Base64Coder.decode(ciphertext)));
  }

  @Override
  boolean isAcceptablePurpose(KeyPurpose purpose) {
    return purpose == KeyPurpose.DECRYPT_AND_ENCRYPT;
  }
}
TOP

Related Classes of org.keyczar.Crypter

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.