edu.vt.middleware.crypt.util.CryptReader Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of vt-crypt Show documentation
Show all versions of vt-crypt Show documentation
Library for performing common cryptographic operations
/*
$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