Package org.keyczar

Source Code of org.keyczar.Signer

/*
* 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.KeyczarException;
import org.keyczar.exceptions.NoPrimaryKeyException;
import org.keyczar.exceptions.ShortBufferException;
import org.keyczar.i18n.Messages;
import org.keyczar.interfaces.KeyczarReader;
import org.keyczar.interfaces.SigningStream;
import org.keyczar.util.Base64Coder;
import org.keyczar.util.Util;

import java.io.UnsupportedEncodingException;
import java.nio.ByteBuffer;

/**
* Signers may both sign and verify data using sets of symmetric or private
* keys. Sets of public keys may only be used with {@link Verifier} objects.
*
* {@link Signer} objects should be used with symmetric or private key sets to
* generate signatures.
*
* @author steveweis@gmail.com (Steve Weis)
*
*/
public class Signer extends Verifier {
  static final int TIMESTAMP_SIZE = 8;
  private static final Logger LOG = Logger.getLogger(Signer.class);
  private final StreamQueue<SigningStream> SIGN_QUEUE = new StreamQueue<SigningStream>();

  /**
   * Initialize a new Signer with a KeyczarReader. The corresponding key set
   * must have a purpose {@link org.keyczar.enums.KeyPurpose#SIGN_AND_VERIFY}.
   *
   * @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 Signer(KeyczarReader reader) throws KeyczarException {
    super(reader);
  }

  /**
   * Initialize a new Signer 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#SIGN_AND_VERIFY}.
   *
   * @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 Signer(String fileLocation) throws KeyczarException {
    super(fileLocation);
  }

  /**
   * Returns the size of signatures produced by this Signer.
   *
   * @return The size of signatures produced by this Signer.
   * @throws KeyczarException If this Signer does not have a primary or a
   * JCE exception occurs.
   */
  public int digestSize() throws KeyczarException {
    KeyczarKey signingKey = getPrimaryKey();
    if (signingKey == null) {
      throw new NoPrimaryKeyException();
    }
    return HEADER_SIZE + ((SigningStream) signingKey.getStream()).digestSize();
  }

  /**
   * Sign the given input and return a signature.
   *
   * @param input The input to sign.
   * @return A byte array representation of a signature.
   * @throws KeyczarException If this Signer does not have a primary or a
   * JCE exception occurs.
   */
  public byte[] sign(byte[] input) throws KeyczarException {
    ByteBuffer output = ByteBuffer.allocate(digestSize());
    sign(ByteBuffer.wrap(input), output);
    output.reset();
    byte[] outputBytes = new byte[output.remaining()];
    output.get(outputBytes);
    return outputBytes;
  }

  /**
   * Sign the given input and write the signature to the given ByteBuffer
   *
   * @param input The input to sign.
   * @param output The ByteBuffer to write the signature in.
   * @throws KeyczarException If this Signer does not have a primary or a
   * JCE exception occurs.
   */
  public void sign(ByteBuffer input, ByteBuffer output) throws KeyczarException {
    sign(input, null, 0, output);
  }

  /**
   * This allows other classes in the package to pass in hidden data and/or
   * expiration data to be signed.
   *
   * @param input The input to be signed
   * @param hidden Hidden data to be signed
   * @param expirationTime The expiration time of this signature
   * @param output The destination of this signature
   *
   * @throws KeyczarException
   */
  void sign(ByteBuffer input, ByteBuffer hidden, long expirationTime, ByteBuffer output)
      throws KeyczarException {
    if (LOG.isDebugEnabled()) {
      LOG.debug(Messages.getString("Signer.Signing", input.remaining()));
    }
    KeyczarKey signingKey = getPrimaryKey();
    if (signingKey == null) {
      throw new NoPrimaryKeyException();
    }
    SigningStream stream = SIGN_QUEUE.poll();
    if (stream == null) {
      stream = (SigningStream) signingKey.getStream();
    }

    int spaceNeeded = digestSize();
    if (expirationTime > 0) {
      spaceNeeded += TIMESTAMP_SIZE;
    }
    if (output.capacity() < spaceNeeded) {
      throw new ShortBufferException(output.capacity(), spaceNeeded);
    }

    ByteBuffer header = ByteBuffer.allocate(HEADER_SIZE);
    signingKey.copyHeader(header);
    header.rewind();
    stream.initSign();

    // Sign the header and write it to the output buffer
    output.mark();
    output.put(header);

    if (expirationTime > 0) {
      // Write an expiration time following the header and sign it.
      ByteBuffer expiration = ByteBuffer.wrap(Util.fromLong(expirationTime));
      output.put(expiration);
      expiration.rewind();
      stream.updateSign(expiration);
    }

    if (hidden != null && hidden.remaining() > 0) {
      // Sign any hidden data
      stream.updateSign(hidden);
    }

    // Sign the input data
    stream.updateSign(input);
    // Sign the version byte
    stream.updateSign(ByteBuffer.wrap(FORMAT_BYTES));

    // Write the signature to the output
    stream.sign(output);
    output.limit(output.position());
    SIGN_QUEUE.add(stream);
  }

  /**
   * Signs the given input String and return the output as a web-safe Base64
   * encoded String.
   *
   * @param input The input String to sign.
   * @return A web-safe Base64-encoded representation of a signature on the
   * input.
   * @throws KeyczarException
   */
  public String sign(String input) throws KeyczarException {
    try {
      return Base64Coder.encodeWebSafe(sign(input.getBytes(DEFAULT_ENCODING)));
    } catch (UnsupportedEncodingException e) {
      throw new KeyczarException(e);
    }
  }

  /**
   * Signs an input blob and returns the data with attached signature
   *
   * @param blob Data to sign
   * @param hidden Hidden data or nonce to include in signature
   * @return The input data with an attached signature
   */
  public byte[] attachedSign(final byte[] blob, final byte[] hidden) throws KeyczarException {
    KeyczarKey signingKey = getPrimaryKey();
    if (signingKey == null) {
      throw new NoPrimaryKeyException();
    }

    SigningStream stream = SIGN_QUEUE.poll();

    if (stream == null) {
      // If not, allocate a new stream object.
      stream = (SigningStream) signingKey.getStream();
    }

    stream.initSign();
    // Attached signature signs:
    // [blob | hidden.length | hidden | format] or [blob | 0 | format]
    byte[] hiddenPlusLength = Util.fromInt(0);
    if (hidden.length > 0) {
      hiddenPlusLength = Util.lenPrefix(hidden);
    }

    stream.updateSign(ByteBuffer.wrap(blob));
    stream.updateSign(ByteBuffer.wrap(hiddenPlusLength));
    stream.updateSign(ByteBuffer.wrap(FORMAT_BYTES));

    // now get signature output
    ByteBuffer output = ByteBuffer.allocate(stream.digestSize());
    output.mark();

    stream.sign(output);
    output.limit(output.position());

    // Attached signature format is:
    // [Format number | 4 bytes of key hash | blob size | blob | raw signature]
    byte[] signature =
        Util.cat(FORMAT_BYTES, signingKey.hash(), Util.lenPrefix(blob), output.array());

    SIGN_QUEUE.add(stream);

    return signature;
  }

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

Related Classes of org.keyczar.Signer

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.