All Downloads are FREE. Search and download functionalities are using the official Maven repository.

edu.vt.middleware.crypt.util.CryptReader Maven / Gradle / Ivy

There is a newer version: 2.2
Show newest version
/*
  $Id$

  Copyright (C) 2007-2010 Virginia Tech.
  All rights reserved.

  SEE LICENSE FOR MORE INFORMATION

  Author:  Middleware Services
  Email:   [email protected]
  Version: $Revision$
  Updated: $Date$
*/
package edu.vt.middleware.crypt.util;

import java.io.BufferedInputStream;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.security.KeyFactory;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.ArrayList;
import java.util.List;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import edu.vt.middleware.crypt.CryptException;
import edu.vt.middleware.crypt.CryptProvider;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.bouncycastle.asn1.ASN1InputStream;
import org.bouncycastle.asn1.DERObject;

/**
 * Helper class for performing I/O read operations on cryptographic data.
 *
 * @author  Middleware Services
 * @version  $Revision: 578 $
 */
public class CryptReader
{

  /** X.509 certificate type. */
  public static final String DEFAULT_CERTIFICATE_TYPE = "X.509";

  /** Buffer size for read operations. */
  private static final int BUFFER_SIZE = 4096;


  /** Protected constructor of utility class. */
  protected CryptReader() {}


  /**
   * Reads the raw bytes of a symmetric encryption key from a file.
   *
   * @param  keyFile  File containing key data.
   * @param  algorithm  Symmetric cipher algorithm for which key is used.
   *
   * @return  Secret key.
   *
   * @throws  IOException  On IO errors.
   */
  public static SecretKey readSecretKey(
    final File keyFile,
    final String algorithm)
    throws IOException
  {
    return
      readSecretKey(
        new BufferedInputStream(new FileInputStream(keyFile)),
        algorithm);
  }


  /**
   * Reads the raw bytes of a symmetric encryption key from an input stream.
   *
   * @param  keyStream  Stream containing key data.
   * @param  algorithm  Symmetric cipher algorithm for which key is used.
   *
   * @return  Secret key.
   *
   * @throws  IOException  On IO errors.
   */
  public static SecretKey readSecretKey(
    final InputStream keyStream,
    final String algorithm)
    throws IOException
  {
    return new SecretKeySpec(readData(keyStream), algorithm);
  }


  /**
   * Reads a DER-encoded private key in PKCS#8 format from a file into a {@link
   * PrivateKey} object. SSLeay-format keys may also work in some cases; testing
   * revealed SSLeay-format RSA keys generated by the OpenSSL rsa command are
   * supported.
   *
   * @param  keyFile  Private key file.
   * @param  algorithm  Name of encryption algorithm used by key.
   *
   * @return  Private key containing data read from file.
   *
   * @throws  CryptException  On key format errors.
   * @throws  IOException  On key read errors.
   */
  public static PrivateKey readPrivateKey(
    final File keyFile,
    final String algorithm)
    throws CryptException, IOException
  {
    return
      readPrivateKey(
        new BufferedInputStream(new FileInputStream(keyFile)),
        algorithm);
  }


  /**
   * Reads a DER-encoded private key in PKCS#8 format from an input stream into
   * a {@link PrivateKey} object. SSLeay-format keys may also work in some
   * cases; testing revealed SSLeay-format RSA keys generated by the OpenSSL rsa
   * command are supported.
   *
   * @param  keyStream  Input stream containing private key data.
   * @param  algorithm  Name of encryption algorithm used by key.
   *
   * @return  Private key containing data read from stream.
   *
   * @throws  CryptException  On key format errors.
   * @throws  IOException  On key read errors.
   */
  public static PrivateKey readPrivateKey(
    final InputStream keyStream,
    final String algorithm)
    throws CryptException, IOException
  {
    final KeyFactory kf = CryptProvider.getKeyFactory(algorithm);
    try {
      final PKCS8EncodedKeySpec keysp = new PKCS8EncodedKeySpec(
        readData(keyStream));
      return kf.generatePrivate(keysp);
    } catch (InvalidKeySpecException e) {
      throw new CryptException("Invalid private key format.", e);
    }
  }


  /**
   * Reads a PEM-encoded private key from a file into a {@link PrivateKey}
   * object. The header of the PEM-encoded file must meet the requirements
   * described in {@link #readPemPrivateKey(InputStream, char[])}.
   *
   * @param  keyFile  File containing private key data in PEM format.
   * @param  password  Password used to encrypt private key; may be null to
   * indicate no encryption.
   *
   * @return  Private key containing data read from file.
   *
   * @throws  CryptException  On key format errors.
   * @throws  IOException  On key read errors.
   */
  public static PrivateKey readPemPrivateKey(
    final File keyFile,
    final char[] password)
    throws CryptException, IOException
  {
    return
      readPemPrivateKey(
        new BufferedInputStream(new FileInputStream(keyFile)),
        password);
  }


  /**
   * Reads a PEM-encoded private key from an input stream into a {@link
   * PrivateKey} object. The header of the encoded key MUST
   * contain the cipher algorithm of the key, e.g.:
   *
   * 
-----BEGIN RSA PRIVATE KEY-----
* *

This is the case for PEM-encoded SSLeay format private keys created by * the OpenSSL rsa command, but not for the OpenSSL pkcs8 command. *

* * @param keyStream Input stream containing private key data in PEM format. * @param password Password used to encrypt private key; may be null to * indicate no encryption. * * @return Private key containing data read from stream. * * @throws CryptException On key format errors. * @throws IOException On key read errors. */ public static PrivateKey readPemPrivateKey( final InputStream keyStream, final char[] password) throws CryptException, IOException { return PemHelper.decodeKey(readPem(keyStream), password); } /** * Reads a DER-encoded X.509 public key from an input stream into a {@link * PublicKey} object. * * @param keyFile File containing DER-encoded X.509 public key. * @param algorithm Name of encryption algorithm used by key. * * @return Public key containing data read from file. * * @throws CryptException On key format errors. * @throws IOException On key read errors. */ public static PublicKey readPublicKey( final File keyFile, final String algorithm) throws CryptException, IOException { return readPublicKey( new BufferedInputStream(new FileInputStream(keyFile)), algorithm); } /** * Reads a DER-encoded X.509 public key from an input stream into a {@link * PublicKey} object. * * @param keyStream Input stream containing DER-encoded X.509 public key. * @param algorithm Name of encryption algorithm used by key. * * @return Public key containing data read from stream. * * @throws CryptException On key format errors. * @throws IOException On key read errors. */ public static PublicKey readPublicKey( final InputStream keyStream, final String algorithm) throws CryptException, IOException { final KeyFactory kf = CryptProvider.getKeyFactory(algorithm); try { final X509EncodedKeySpec keySpec = new X509EncodedKeySpec( readData(keyStream)); return kf.generatePublic(keySpec); } catch (InvalidKeySpecException e) { throw new CryptException("Invalid public key format.", e); } } /** * Reads a PEM-encoded public key from a file into a {@link PublicKey} object. * * @param keyFile File containing public key data in PEM format. * * @return Public key containing data read from file. * * @throws CryptException On key format errors. * @throws IOException On key read errors. */ public static PublicKey readPemPublicKey(final File keyFile) throws CryptException, IOException { return readPemPublicKey(new BufferedInputStream(new FileInputStream(keyFile))); } /** * Reads a PEM-encoded public key from an input stream into a {@link * PublicKey} object. * * @param keyStream Input stream containing public key data in PEM format. * * @return Public key containing data read from stream. * * @throws CryptException On key format errors. * @throws IOException On key read errors. */ public static PublicKey readPemPublicKey(final InputStream keyStream) throws CryptException, IOException { return PemHelper.decodeKey(readPem(keyStream)); } /** * Reads a PEM or DER-encoded certificate of the default type from a file into * a {@link Certificate} object. * * @param certFile Path to certificate file. * * @return Certificate containing data read from file. * * @throws CryptException On certificate format errors. * @throws IOException On read errors. */ public static Certificate readCertificate(final File certFile) throws CryptException, IOException { return readCertificate(certFile, DEFAULT_CERTIFICATE_TYPE); } /** * Reads a PEM or DER-encoded certificate of the given type from a file into a * {@link Certificate} object. * * @param certFile Path to certificate file. * @param type Type of certificate to read, e.g. X.509. * * @return Certificate containing data read from file. * * @throws CryptException On certificate format errors. * @throws IOException On read errors. */ public static Certificate readCertificate( final File certFile, final String type) throws CryptException, IOException { return readCertificate(new BufferedInputStream(new FileInputStream(certFile))); } /** * Reads a PEM or DER-encoded certificate of the default type from an input * stream into a {@link Certificate} object. * * @param certStream Input stream with certificate data. * * @return Certificate created from data read from stream. * * @throws CryptException On certificate read or format errors. */ public static Certificate readCertificate(final InputStream certStream) throws CryptException { return readCertificate(certStream, DEFAULT_CERTIFICATE_TYPE); } /** * Reads a PEM or DER-encoded certificate of the default type from an input * stream into a {@link Certificate} object. * * @param certStream Input stream with certificate data. * @param type Type of certificate to read, e.g. X.509. * * @return Certificate created from data read from stream. * * @throws CryptException On certificate read or format errors. */ public static Certificate readCertificate( final InputStream certStream, final String type) throws CryptException { final CertificateFactory cf = CryptProvider.getCertificateFactory(type); try { return cf.generateCertificate(certStream); } catch (CertificateException e) { throw new CryptException("Certificate read/format error.", e); } } /** * Reads a certificate chain of the default certificate type from a file * containing data in any of the formats supported by {@link * #readCertificateChain(InputStream, String)}. * * @param chainFile Path to certificate chain file. * * @return Array of certificates in the order in which they appear in the * given file. * * @throws CryptException On certificate format errors. * @throws IOException On read errors. */ public static Certificate[] readCertificateChain(final File chainFile) throws CryptException, IOException { return readCertificateChain(chainFile, DEFAULT_CERTIFICATE_TYPE); } /** * Reads a certificate chain of the given type from a file containing data in * any of the formats supported by {@link #readCertificateChain(InputStream, * String)}. * * @param chainFile Path to certificate chain file. * @param type Type of certificate to read, e.g. X.509. * * @return Array of certificates in the order in which they appear in the * given file. * * @throws CryptException On certificate format errors. * @throws IOException On read errors. */ public static Certificate[] readCertificateChain( final File chainFile, final String type) throws CryptException, IOException { return readCertificateChain( new BufferedInputStream(new FileInputStream(chainFile))); } /** * Reads a certificate chain of the default certificate type from an input * stream containing data in any of the formats supported by {@link * #readCertificateChain(InputStream, String)}. * * @param chainStream Stream containing certificate chain data. * * @return Array of certificates in the order in which they appear in the * given input stream. * * @throws CryptException On certificate read or format errors. */ public static Certificate[] readCertificateChain( final InputStream chainStream) throws CryptException { return readCertificateChain(chainStream, DEFAULT_CERTIFICATE_TYPE); } /** * Reads a certificate chain of the default certificate type from an input * stream containing data in any of the following formats: * *
    *
  • Sequence of DER-encoded certificates
  • *
  • Concatenation of PEM-encoded certificates
  • *
  • PKCS#7 certificate chain
  • *
* * @param chainStream Stream containing certificate chain data. * @param type Type of certificate to read, e.g. X.509. * * @return Array of certificates in the order in which they appear in the * stream. * * @throws CryptException On certificate read or format errors. */ public static Certificate[] readCertificateChain( final InputStream chainStream, final String type) throws CryptException { final CertificateFactory cf = CryptProvider.getCertificateFactory(type); InputStream in = chainStream; if (!chainStream.markSupported()) { in = new BufferedInputStream(chainStream); } final List certList = new ArrayList(); try { while (in.available() > 0) { final Certificate cert = cf.generateCertificate(in); if (cert != null) { certList.add(cert); } } } catch (CertificateException e) { throw new CryptException("Certificate read/format error.", e); } catch (IOException e) { throw new CryptException("Stream I/O error."); } return certList.toArray(new Certificate[certList.size()]); } /** * Attempts to create a Bouncy Castle DERObject from a byte array * representing ASN.1 encoded data. * * @param data ASN.1 encoded data as byte array. * @param discardWrapper In some cases the value of the encoded data may * itself be encoded data, where the latter encoded data is desired. Recall * ASN.1 data is of the form {TAG, SIZE, DATA}. Set this flag to true to skip * the first two bytes, e.g. TAG and SIZE, and treat the remaining bytes as * the encoded data. * * @return DER object. * * @throws IOException On I/O errors. */ public static DERObject readEncodedBytes( final byte[] data, final boolean discardWrapper) throws IOException { final ByteArrayInputStream inBytes = new ByteArrayInputStream(data); int size = data.length; if (discardWrapper) { inBytes.skip(2); size = data.length - 2; } final ASN1InputStream in = new ASN1InputStream(inBytes, size); try { return in.readObject(); } finally { try { in.close(); } catch (IOException e) { final Log logger = LogFactory.getLog(CryptReader.class); if (logger.isWarnEnabled()) { logger.warn("Error closing ASN.1 input stream.", e); } } } } /** * Reads a PEM object from an input stream into a string. * * @param in Input stream containing PEM-encoded data. * * @return Entire contents of stream as a string. * * @throws IOException On I/O read errors. */ private static String readPem(final InputStream in) throws IOException { return new String(readData(in), Convert.ASCII_CHARSET.name()); } /** * Reads all the data in the given stream and returns the contents as a byte * array. * * @param in Input stream to read. * * @return Entire contents of stream. * * @throws IOException On read errors. */ private static byte[] readData(final InputStream in) throws IOException { final byte[] buffer = new byte[BUFFER_SIZE]; final ByteArrayOutputStream bos = new ByteArrayOutputStream(BUFFER_SIZE); int count = 0; try { while ((count = in.read(buffer, 0, BUFFER_SIZE)) > 0) { bos.write(buffer, 0, count); } } finally { try { in.close(); } catch (IOException e) { final Log logger = LogFactory.getLog(CryptProvider.class); if (logger.isWarnEnabled()) { logger.warn("Error closing input stream.", e); } } } return bos.toByteArray(); } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy