http://git-wip-us.apache.org/repos/asf/commons-crypto/blob/95a8d486/src/main/java/org/apache/commons/crypto/conf/ConfigurationKeys.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/apache/commons/crypto/conf/ConfigurationKeys.java b/src/main/java/org/apache/commons/crypto/conf/ConfigurationKeys.java index 7bab928..c6005a5 100644 --- a/src/main/java/org/apache/commons/crypto/conf/ConfigurationKeys.java +++ b/src/main/java/org/apache/commons/crypto/conf/ConfigurationKeys.java @@ -25,112 +25,112 @@ import org.apache.commons.crypto.random.CryptoRandom; */ public class ConfigurationKeys { - /** - * The prefix of crypto configuration. - */ - public static final String CONF_PREFIX = "commons.crypto."; - - /** - * The filename of configuration file. - */ - public static final String COMMONS_CRYPTO_SYSTEM_PROPERTIES_FILE = - CONF_PREFIX + "properties"; - - /** - * The configuration key of implementation class for crypto cipher. - * The values of COMMONS_CRYPTO_CIPHER_CLASSES_KEY can be - * "org.apache.commons.crypto.cipher.JceCipher" and "org.apache.commons.crypto.cipher.OpensslCipher". - * And it takes a common separated list. - * The "org.apache.commons.crypto.cipher.JceCipher" use jce provider to - * implement CryptoCipher and - * the "org.apache.commons.crypto.cipher.OpensslCipher" use jni into openssl to implement. - * Note that for each value,the first value which can be created without exception - * will be used (priority by order). - */ - public static final String COMMONS_CRYPTO_CIPHER_CLASSES_KEY = - CONF_PREFIX + "cipher.classes"; - - /** - * The default value for crypto cipher. - */ - public static final String COMMONS_CRYPTO_CIPHER_CLASSES_DEFAULT = - OpensslCipher.class.getName(); - - /** - * The configuration key of the provider class for JCE cipher. - */ - public static final String COMMONS_CRYPTO_CIPHER_JCE_PROVIDER_KEY = - CONF_PREFIX + "cipher.jce.provider"; - - // security random related configuration keys - /** - * The configuration key of the file path for secure random device. - */ - public static final String COMMONS_CRYPTO_SECURE_RANDOM_DEVICE_FILE_PATH_KEY = - CONF_PREFIX + "secure.random.device.file.path"; - - /** - * The default value of the file path for secure random device. - */ - public static final String COMMONS_CRYPTO_SECURE_RANDOM_DEVICE_FILE_PATH_DEFAULT = - "/dev/urandom"; - - /** - * The configuration key of the algorithm of secure random. - */ - public static final String COMMONS_CRYPTO_SECURE_RANDOM_JAVA_ALGORITHM_KEY = - CONF_PREFIX + "secure.random.java.algorithm"; - - /** - * The default value of the algorithm of secure random. - */ - public static final String - COMMONS_CRYPTO_SECURE_RANDOM_JAVA_ALGORITHM_DEFAULT = "SHA1PRNG"; - - /** - * The configuration key of the implementation class for secure random. - * The values of COMMONS_CRYPTO_SECURE_RANDOM_CLASSES_KEY can be - * "org.apache.commons.crypto.random.JavaCryptoRandom" and "org.apache.commons.crypto.random.OpensslCryptoRandom". - * And it takes a common separated list. - * The "org.apache.commons.crypto.random.JavaCryptoRandom" use java to - * implement {@link CryptoRandom} and - * the "org.apache.commons.crypto.random.OpensslCryptoRandom" use jni into openssl to implement. - * Note that for each value,the first value which can be created without exception - * will be used (priority by order). - */ - public static final String COMMONS_CRYPTO_SECURE_RANDOM_CLASSES_KEY = - CONF_PREFIX + "secure.random.classes"; - - /** - * The configuration key of the buffer size for stream. - */ - public static final String COMMONS_CRYPTO_STREAM_BUFFER_SIZE_KEY = - CONF_PREFIX + "stream.buffer.size"; - - // stream related configuration keys - /** - * The default value of the buffer size for stream. - */ - public static final int COMMONS_CRYPTO_STREAM_BUFFER_SIZE_DEFAULT = 8192; - - // native lib related configuration keys - /** - * The configuration key of the path for loading crypto library. - */ - public static final String COMMONS_CRYPTO_LIB_PATH_KEY = - CONF_PREFIX + "lib.path"; - - /** - * The configuration key of the file name for loading crypto library. - */ - public static final String COMMONS_CRYPTO_LIB_NAME_KEY = - CONF_PREFIX + "lib.name"; - - /** - * The configuration key of temp directory for extracting crypto library. - */ - public static final String COMMONS_CRYPTO_LIB_TEMPDIR_KEY = - CONF_PREFIX + "lib.tempdir"; - - private ConfigurationKeys() {} + /** + * The prefix of crypto configuration. + */ + public static final String CONF_PREFIX = "commons.crypto."; + + /** + * The filename of configuration file. + */ + public static final String COMMONS_CRYPTO_SYSTEM_PROPERTIES_FILE = CONF_PREFIX + + "properties"; + + /** + * The configuration key of implementation class for crypto cipher. The + * values of COMMONS_CRYPTO_CIPHER_CLASSES_KEY can be + * "org.apache.commons.crypto.cipher.JceCipher" and + * "org.apache.commons.crypto.cipher.OpensslCipher". And it takes a common + * separated list. The "org.apache.commons.crypto.cipher.JceCipher" use jce + * provider to implement CryptoCipher and the + * "org.apache.commons.crypto.cipher.OpensslCipher" use jni into openssl to + * implement. Note that for each value,the first value which can be created + * without exception will be used (priority by order). + */ + public static final String COMMONS_CRYPTO_CIPHER_CLASSES_KEY = CONF_PREFIX + + "cipher.classes"; + + /** + * The default value for crypto cipher. + */ + public static final String COMMONS_CRYPTO_CIPHER_CLASSES_DEFAULT = OpensslCipher.class + .getName(); + + /** + * The configuration key of the provider class for JCE cipher. + */ + public static final String COMMONS_CRYPTO_CIPHER_JCE_PROVIDER_KEY = CONF_PREFIX + + "cipher.jce.provider"; + + // security random related configuration keys + /** + * The configuration key of the file path for secure random device. + */ + public static final String COMMONS_CRYPTO_SECURE_RANDOM_DEVICE_FILE_PATH_KEY = CONF_PREFIX + + "secure.random.device.file.path"; + + /** + * The default value of the file path for secure random device. + */ + public static final String COMMONS_CRYPTO_SECURE_RANDOM_DEVICE_FILE_PATH_DEFAULT = "/dev/urandom"; + + /** + * The configuration key of the algorithm of secure random. + */ + public static final String COMMONS_CRYPTO_SECURE_RANDOM_JAVA_ALGORITHM_KEY = CONF_PREFIX + + "secure.random.java.algorithm"; + + /** + * The default value of the algorithm of secure random. + */ + public static final String COMMONS_CRYPTO_SECURE_RANDOM_JAVA_ALGORITHM_DEFAULT = "SHA1PRNG"; + + /** + * The configuration key of the implementation class for secure random. The + * values of COMMONS_CRYPTO_SECURE_RANDOM_CLASSES_KEY can be + * "org.apache.commons.crypto.random.JavaCryptoRandom" and + * "org.apache.commons.crypto.random.OpensslCryptoRandom". And it takes a + * common separated list. The + * "org.apache.commons.crypto.random.JavaCryptoRandom" use java to implement + * {@link CryptoRandom} and the + * "org.apache.commons.crypto.random.OpensslCryptoRandom" use jni into + * openssl to implement. Note that for each value,the first value which can + * be created without exception will be used (priority by order). + */ + public static final String COMMONS_CRYPTO_SECURE_RANDOM_CLASSES_KEY = CONF_PREFIX + + "secure.random.classes"; + + /** + * The configuration key of the buffer size for stream. + */ + public static final String COMMONS_CRYPTO_STREAM_BUFFER_SIZE_KEY = CONF_PREFIX + + "stream.buffer.size"; + + // stream related configuration keys + /** + * The default value of the buffer size for stream. + */ + public static final int COMMONS_CRYPTO_STREAM_BUFFER_SIZE_DEFAULT = 8192; + + // native lib related configuration keys + /** + * The configuration key of the path for loading crypto library. + */ + public static final String COMMONS_CRYPTO_LIB_PATH_KEY = CONF_PREFIX + + "lib.path"; + + /** + * The configuration key of the file name for loading crypto library. + */ + public static final String COMMONS_CRYPTO_LIB_NAME_KEY = CONF_PREFIX + + "lib.name"; + + /** + * The configuration key of temp directory for extracting crypto library. + */ + public static final String COMMONS_CRYPTO_LIB_TEMPDIR_KEY = CONF_PREFIX + + "lib.tempdir"; + + private ConfigurationKeys() { + } }
http://git-wip-us.apache.org/repos/asf/commons-crypto/blob/95a8d486/src/main/java/org/apache/commons/crypto/conf/package-info.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/apache/commons/crypto/conf/package-info.java b/src/main/java/org/apache/commons/crypto/conf/package-info.java index 837b195..6e340a9 100644 --- a/src/main/java/org/apache/commons/crypto/conf/package-info.java +++ b/src/main/java/org/apache/commons/crypto/conf/package-info.java @@ -19,3 +19,4 @@ * Configuration classes */ package org.apache.commons.crypto.conf; + http://git-wip-us.apache.org/repos/asf/commons-crypto/blob/95a8d486/src/main/java/org/apache/commons/crypto/random/CryptoRandom.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/apache/commons/crypto/random/CryptoRandom.java b/src/main/java/org/apache/commons/crypto/random/CryptoRandom.java index 8194a9b..6c8c983 100644 --- a/src/main/java/org/apache/commons/crypto/random/CryptoRandom.java +++ b/src/main/java/org/apache/commons/crypto/random/CryptoRandom.java @@ -24,13 +24,13 @@ import java.io.Closeable; */ public interface CryptoRandom extends Closeable { - /** - * Generates random bytes and places them into a user-supplied - * byte array. The number of random bytes produced is equal to - * the length of the byte array. - * - * @param bytes the byte array to fill with random bytes - */ - void nextBytes(byte[] bytes); + /** + * Generates random bytes and places them into a user-supplied byte array. + * The number of random bytes produced is equal to the length of the byte + * array. + * + * @param bytes the byte array to fill with random bytes + */ + void nextBytes(byte[] bytes); } http://git-wip-us.apache.org/repos/asf/commons-crypto/blob/95a8d486/src/main/java/org/apache/commons/crypto/random/CryptoRandomFactory.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/apache/commons/crypto/random/CryptoRandomFactory.java b/src/main/java/org/apache/commons/crypto/random/CryptoRandomFactory.java index 8c9fd35..df57cd8 100644 --- a/src/main/java/org/apache/commons/crypto/random/CryptoRandomFactory.java +++ b/src/main/java/org/apache/commons/crypto/random/CryptoRandomFactory.java @@ -26,51 +26,56 @@ import org.slf4j.LoggerFactory; import org.apache.commons.crypto.utils.Utils; import org.apache.commons.crypto.utils.ReflectionUtils; -import static org.apache.commons.crypto.conf.ConfigurationKeys - .COMMONS_CRYPTO_SECURE_RANDOM_CLASSES_KEY; +import static org.apache.commons.crypto.conf.ConfigurationKeys.COMMONS_CRYPTO_SECURE_RANDOM_CLASSES_KEY; /** * This is the factory class used for {@link CryptoRandom}. */ public class CryptoRandomFactory { - public final static Logger LOG = LoggerFactory - .getLogger(CryptoRandomFactory.class); + public final static Logger LOG = LoggerFactory + .getLogger(CryptoRandomFactory.class); - private CryptoRandomFactory() {} - - /** - * Gets a CryptoRandom instance for specified props. - * - * @param props the configuration properties. - * @return CryptoRandom the cryptoRandom object.Null value will be returned if no CryptoRandom - * classes with props. - * @throws GeneralSecurityException if fail to create the {@link CryptoRandom}. - */ - public static CryptoRandom getCryptoRandom(Properties props) throws GeneralSecurityException { - String cryptoRandomClasses = props.getProperty( - COMMONS_CRYPTO_SECURE_RANDOM_CLASSES_KEY); - if (cryptoRandomClasses == null) { - cryptoRandomClasses = System.getProperty( - COMMONS_CRYPTO_SECURE_RANDOM_CLASSES_KEY); + private CryptoRandomFactory() { } - CryptoRandom random = null; - if (cryptoRandomClasses != null) { - for (String klassName : Utils.splitClassNames(cryptoRandomClasses, ",")) { - try { - final Class<?> klass = ReflectionUtils.getClassByName(klassName); - random = (CryptoRandom) ReflectionUtils.newInstance(klass, props); - if (random != null) { - break; - } - } catch (ClassCastException e) { - LOG.error("Class {} is not a CryptoCipher.", klassName); - } catch (ClassNotFoundException e) { - LOG.error("CryptoCipher {} not found.", klassName); + /** + * Gets a CryptoRandom instance for specified props. + * + * @param props the configuration properties. + * @return CryptoRandom the cryptoRandom object.Null value will be returned + * if no CryptoRandom classes with props. + * @throws GeneralSecurityException if fail to create the + * {@link CryptoRandom}. + */ + public static CryptoRandom getCryptoRandom(Properties props) + throws GeneralSecurityException { + String cryptoRandomClasses = props + .getProperty(COMMONS_CRYPTO_SECURE_RANDOM_CLASSES_KEY); + if (cryptoRandomClasses == null) { + cryptoRandomClasses = System + .getProperty(COMMONS_CRYPTO_SECURE_RANDOM_CLASSES_KEY); } - } - } - return (random == null) ? new JavaCryptoRandom(props) : random; - } + CryptoRandom random = null; + if (cryptoRandomClasses != null) { + for (String klassName : Utils.splitClassNames(cryptoRandomClasses, + ",")) { + try { + final Class<?> klass = ReflectionUtils + .getClassByName(klassName); + random = (CryptoRandom) ReflectionUtils.newInstance(klass, + props); + if (random != null) { + break; + } + } catch (ClassCastException e) { + LOG.error("Class {} is not a CryptoCipher.", klassName); + } catch (ClassNotFoundException e) { + LOG.error("CryptoCipher {} not found.", klassName); + } + } + } + + return (random == null) ? new JavaCryptoRandom(props) : random; + } } http://git-wip-us.apache.org/repos/asf/commons-crypto/blob/95a8d486/src/main/java/org/apache/commons/crypto/random/JavaCryptoRandom.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/apache/commons/crypto/random/JavaCryptoRandom.java b/src/main/java/org/apache/commons/crypto/random/JavaCryptoRandom.java index ac0ab3e..69fbf98 100644 --- a/src/main/java/org/apache/commons/crypto/random/JavaCryptoRandom.java +++ b/src/main/java/org/apache/commons/crypto/random/JavaCryptoRandom.java @@ -30,42 +30,45 @@ import org.apache.commons.crypto.conf.ConfigurationKeys; * A CryptoRandom of Java implementation. */ public class JavaCryptoRandom implements CryptoRandom { - private static final Log LOG = - LogFactory.getLog(JavaCryptoRandom.class.getName()); + private static final Log LOG = LogFactory.getLog(JavaCryptoRandom.class + .getName()); - private final SecureRandom instance; + private final SecureRandom instance; - /** - * Constructs a {@link JavaCryptoRandom}. - * - * @param properties the configuration properties. - * @throws NoSuchAlgorithmException if no Provider supports a SecureRandomSpi implementation for - * the specified algorithm. - */ - public JavaCryptoRandom(Properties properties) throws NoSuchAlgorithmException { - instance = SecureRandom.getInstance(properties - .getProperty(ConfigurationKeys.COMMONS_CRYPTO_SECURE_RANDOM_JAVA_ALGORITHM_KEY, - ConfigurationKeys.COMMONS_CRYPTO_SECURE_RANDOM_JAVA_ALGORITHM_DEFAULT)); - } + /** + * Constructs a {@link JavaCryptoRandom}. + * + * @param properties the configuration properties. + * @throws NoSuchAlgorithmException if no Provider supports a + * SecureRandomSpi implementation for the specified algorithm. + */ + public JavaCryptoRandom(Properties properties) + throws NoSuchAlgorithmException { + instance = SecureRandom + .getInstance(properties + .getProperty( + ConfigurationKeys.COMMONS_CRYPTO_SECURE_RANDOM_JAVA_ALGORITHM_KEY, + ConfigurationKeys.COMMONS_CRYPTO_SECURE_RANDOM_JAVA_ALGORITHM_DEFAULT)); + } - /** - * Overrides {@link java.lang.AutoCloseable#close()}. - * For{@link JavaCryptoRandom}, we don't need to recycle resource. - */ - @Override - public void close() { - // do nothing - } + /** + * Overrides {@link java.lang.AutoCloseable#close()}. For + * {@link JavaCryptoRandom}, we don't need to recycle resource. + */ + @Override + public void close() { + // do nothing + } - /** - * Overrides {@link CryptoRandom#nextBytes(byte[])}. - * Generates random bytes and places them into a user-supplied byte array. - * The number of random bytes produced is equal to the length of the byte array. - * - * @param bytes the array to be filled in with random bytes. - */ - @Override - public void nextBytes(byte[] bytes) { - instance.nextBytes(bytes); - } + /** + * Overrides {@link CryptoRandom#nextBytes(byte[])}. Generates random bytes + * and places them into a user-supplied byte array. The number of random + * bytes produced is equal to the length of the byte array. + * + * @param bytes the array to be filled in with random bytes. + */ + @Override + public void nextBytes(byte[] bytes) { + instance.nextBytes(bytes); + } } http://git-wip-us.apache.org/repos/asf/commons-crypto/blob/95a8d486/src/main/java/org/apache/commons/crypto/random/OpensslCryptoRandom.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/apache/commons/crypto/random/OpensslCryptoRandom.java b/src/main/java/org/apache/commons/crypto/random/OpensslCryptoRandom.java index 315e259..3adb9b6 100644 --- a/src/main/java/org/apache/commons/crypto/random/OpensslCryptoRandom.java +++ b/src/main/java/org/apache/commons/crypto/random/OpensslCryptoRandom.java @@ -33,118 +33,120 @@ import org.apache.commons.crypto.utils.Utils; * </p> * * <p> - * If using an Intel chipset with RDRAND, the high-performance hardware - * random number generator will be used and it's much faster than - * SecureRandom. If RDRAND is unavailable, default OpenSSL secure random - * generator will be used. It's still faster and can generate strong random bytes. + * If using an Intel chipset with RDRAND, the high-performance hardware random + * number generator will be used and it's much faster than SecureRandom. If + * RDRAND is unavailable, default OpenSSL secure random generator will be used. + * It's still faster and can generate strong random bytes. * </p> + * * @see <a href="https://wiki.openssl.org/index.php/Random_Numbers"> * https://wiki.openssl.org/index.php/Random_Numbers</a> * @see <a href="http://en.wikipedia.org/wiki/RdRand"> * http://en.wikipedia.org/wiki/RdRand</a> */ public class OpensslCryptoRandom extends Random implements CryptoRandom { - private static final long serialVersionUID = -7828193502768789584L; - private static final Log LOG = - LogFactory.getLog(OpensslCryptoRandom.class.getName()); + private static final long serialVersionUID = -7828193502768789584L; + private static final Log LOG = LogFactory.getLog(OpensslCryptoRandom.class + .getName()); - /** If native SecureRandom unavailable, use java SecureRandom */ - private final JavaCryptoRandom fallback; - private static final boolean nativeEnabled; + /** If native SecureRandom unavailable, use java SecureRandom */ + private final JavaCryptoRandom fallback; + private static final boolean nativeEnabled; - static { - boolean opensslLoaded = false; - if (NativeCodeLoader.isNativeCodeLoaded()) { - try { - OpensslCryptoRandomNative.initSR(); - opensslLoaded = true; - } catch (Throwable t) { - LOG.error("Failed to load Openssl CryptoRandom", t); - } + static { + boolean opensslLoaded = false; + if (NativeCodeLoader.isNativeCodeLoaded()) { + try { + OpensslCryptoRandomNative.initSR(); + opensslLoaded = true; + } catch (Throwable t) { + LOG.error("Failed to load Openssl CryptoRandom", t); + } + } + nativeEnabled = opensslLoaded; } - nativeEnabled = opensslLoaded; - } - /** - * Judges whether loading native library successfully. - * - * @return true if loading library successfully. - */ - public static boolean isNativeCodeLoaded() { - return nativeEnabled; - } + /** + * Judges whether loading native library successfully. + * + * @return true if loading library successfully. + */ + public static boolean isNativeCodeLoaded() { + return nativeEnabled; + } - /** - * Constructs a {@link OpensslCryptoRandom}. - * - * @param props the configuration properties. - * @throws NoSuchAlgorithmException if no Provider supports a SecureRandomSpi implementation for - * the specified algorithm. - */ - public OpensslCryptoRandom(Properties props) throws NoSuchAlgorithmException { - if (!nativeEnabled) { - fallback = new JavaCryptoRandom(props); - } else { - fallback = null; + /** + * Constructs a {@link OpensslCryptoRandom}. + * + * @param props the configuration properties. + * @throws NoSuchAlgorithmException if no Provider supports a + * SecureRandomSpi implementation for the specified algorithm. + */ + public OpensslCryptoRandom(Properties props) + throws NoSuchAlgorithmException { + if (!nativeEnabled) { + fallback = new JavaCryptoRandom(props); + } else { + fallback = null; + } } - } - /** - * Generates a user-specified number of random bytes. - * It's thread-safe. - * - * @param bytes the array to be filled in with random bytes. - */ - @Override - public void nextBytes(byte[] bytes) { - if (!nativeEnabled || !OpensslCryptoRandomNative.nextRandBytes(bytes)) { - fallback.nextBytes(bytes); + /** + * Generates a user-specified number of random bytes. It's thread-safe. + * + * @param bytes the array to be filled in with random bytes. + */ + @Override + public void nextBytes(byte[] bytes) { + if (!nativeEnabled || !OpensslCryptoRandomNative.nextRandBytes(bytes)) { + fallback.nextBytes(bytes); + } } - } - /** - * Overrides {@link OpensslCryptoRandom}. - * For {@link OpensslCryptoRandom}, we don't need to set seed. - * - * @param seed the initial seed. - */ - @Override - public void setSeed(long seed) { - // Self-seeding. - } + /** + * Overrides {@link OpensslCryptoRandom}. For {@link OpensslCryptoRandom}, + * we don't need to set seed. + * + * @param seed the initial seed. + */ + @Override + public void setSeed(long seed) { + // Self-seeding. + } - /** - * Overrides Random#next(). Generates an integer containing the - * user-specified number of random bits(right justified, with leading - * zeros). - * - * @param numBits number of random bits to be generated, where 0 - * {@literal <=} <code>numBits</code> {@literal <=} 32. - * @return int an <code>int</code> containing the user-specified number of - * random bits (right justified, with leading zeros). - */ - @Override - final protected int next(int numBits) { - Utils.checkArgument(numBits >= 0 && numBits <= 32); - int numBytes = (numBits + 7) / 8; - byte b[] = new byte[numBytes]; - int next = 0; + /** + * Overrides Random#next(). Generates an integer containing the + * user-specified number of random bits(right justified, with leading + * zeros). + * + * @param numBits number of random bits to be generated, where 0 + * {@literal <=} <code>numBits</code> {@literal <=} 32. + * @return int an <code>int</code> containing the user-specified number of + * random bits (right justified, with leading zeros). + */ + @Override + final protected int next(int numBits) { + Utils.checkArgument(numBits >= 0 && numBits <= 32); + int numBytes = (numBits + 7) / 8; + byte b[] = new byte[numBytes]; + int next = 0; - nextBytes(b); - for (int i = 0; i < numBytes; i++) { - next = (next << 8) + (b[i] & 0xFF); - } + nextBytes(b); + for (int i = 0; i < numBytes; i++) { + next = (next << 8) + (b[i] & 0xFF); + } - return next >>> (numBytes * 8 - numBits); - } + return next >>> (numBytes * 8 - numBits); + } - /** - * Overrides {@link java.lang.AutoCloseable#close()}. Closes openssl context if native enabled. - */ - @Override - public void close() { - if (!nativeEnabled && fallback !=null) { - fallback.close(); + /** + * Overrides {@link java.lang.AutoCloseable#close()}. Closes openssl context + * if native enabled. + */ + @Override + public void close() { + if (!nativeEnabled && fallback != null) { + fallback.close(); + } } - } } http://git-wip-us.apache.org/repos/asf/commons-crypto/blob/95a8d486/src/main/java/org/apache/commons/crypto/random/OpensslCryptoRandomNative.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/apache/commons/crypto/random/OpensslCryptoRandomNative.java b/src/main/java/org/apache/commons/crypto/random/OpensslCryptoRandomNative.java index 8b4a0a1..65078c3 100644 --- a/src/main/java/org/apache/commons/crypto/random/OpensslCryptoRandomNative.java +++ b/src/main/java/org/apache/commons/crypto/random/OpensslCryptoRandomNative.java @@ -18,26 +18,26 @@ package org.apache.commons.crypto.random; /** - * JNI interface of {@link CryptoRandom} implementation. - * The native method in this class is defined in - * OpensslCryptoRandomNative.h(genereted by javah). + * JNI interface of {@link CryptoRandom} implementation. The native method in + * this class is defined in OpensslCryptoRandomNative.h(genereted by javah). */ public class OpensslCryptoRandomNative { - private OpensslCryptoRandomNative() {} + private OpensslCryptoRandomNative() { + } - /** - * Declares a native method to initialize SR. - */ - public native static void initSR(); + /** + * Declares a native method to initialize SR. + */ + public native static void initSR(); - /** - * Judges whether use {@link OpensslCryptoRandomNative} to - * generate the user-specified number of random bits. - * - * @param bytes the array to be filled in with random bytes. - * @return true if use {@link OpensslCryptoRandomNative} to - * generate the user-specified number of random bits. - */ - public native static boolean nextRandBytes(byte[] bytes); + /** + * Judges whether use {@link OpensslCryptoRandomNative} to generate the + * user-specified number of random bits. + * + * @param bytes the array to be filled in with random bytes. + * @return true if use {@link OpensslCryptoRandomNative} to generate the + * user-specified number of random bits. + */ + public native static boolean nextRandBytes(byte[] bytes); } http://git-wip-us.apache.org/repos/asf/commons-crypto/blob/95a8d486/src/main/java/org/apache/commons/crypto/random/OsCryptoRandom.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/apache/commons/crypto/random/OsCryptoRandom.java b/src/main/java/org/apache/commons/crypto/random/OsCryptoRandom.java index 7c8bc07..eca62d2 100644 --- a/src/main/java/org/apache/commons/crypto/random/OsCryptoRandom.java +++ b/src/main/java/org/apache/commons/crypto/random/OsCryptoRandom.java @@ -29,105 +29,105 @@ import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; /** - * A Random implementation that uses random bytes sourced from the - * operating system. + * A Random implementation that uses random bytes sourced from the operating + * system. */ public class OsCryptoRandom extends Random implements CryptoRandom { - public static final Log LOG = LogFactory.getLog(OsCryptoRandom.class); + public static final Log LOG = LogFactory.getLog(OsCryptoRandom.class); - private static final long serialVersionUID = 6391500337172057900L; + private static final long serialVersionUID = 6391500337172057900L; - private final int RESERVOIR_LENGTH = 8192; + private final int RESERVOIR_LENGTH = 8192; - private String randomDevPath; + private String randomDevPath; - private transient FileInputStream stream; + private transient FileInputStream stream; - private final byte[] reservoir = new byte[RESERVOIR_LENGTH]; + private final byte[] reservoir = new byte[RESERVOIR_LENGTH]; - private int pos = reservoir.length; + private int pos = reservoir.length; - private void fillReservoir(int min) { - if (pos >= reservoir.length - min) { - try { - IOUtils.readFully(stream, reservoir, 0, reservoir.length); - } catch (IOException e) { - throw new RuntimeException("failed to fill reservoir", e); - } - pos = 0; - } - } - - /** - * Constructs a {@link OsCryptoRandom}. - * - * @param props the configuration properties. - */ - public OsCryptoRandom(Properties props) { - randomDevPath = Utils.getRandomDevPath(props); - File randomDevFile = new File(randomDevPath); - - try { - close(); - this.stream = new FileInputStream(randomDevFile); - } catch (IOException e) { - throw new RuntimeException(e); + private void fillReservoir(int min) { + if (pos >= reservoir.length - min) { + try { + IOUtils.readFully(stream, reservoir, 0, reservoir.length); + } catch (IOException e) { + throw new RuntimeException("failed to fill reservoir", e); + } + pos = 0; + } } - try { - fillReservoir(0); - } catch (RuntimeException e) { - close(); - throw e; + /** + * Constructs a {@link OsCryptoRandom}. + * + * @param props the configuration properties. + */ + public OsCryptoRandom(Properties props) { + randomDevPath = Utils.getRandomDevPath(props); + File randomDevFile = new File(randomDevPath); + + try { + close(); + this.stream = new FileInputStream(randomDevFile); + } catch (IOException e) { + throw new RuntimeException(e); + } + + try { + fillReservoir(0); + } catch (RuntimeException e) { + close(); + throw e; + } } - } - - /** - * Overrides {@link CryptoRandom#nextBytes(byte[])}. - * Generates random bytes and places them into a user-supplied byte array. - * The number of random bytes produced is equal to the length of the byte array. - * - * @param bytes the array to be filled in with random bytes. - */ - @Override - synchronized public void nextBytes(byte[] bytes) { - int off = 0; - int n = 0; - while (off < bytes.length) { - fillReservoir(0); - n = Math.min(bytes.length - off, reservoir.length - pos); - System.arraycopy(reservoir, pos, bytes, off, n); - off += n; - pos += n; + + /** + * Overrides {@link CryptoRandom#nextBytes(byte[])}. Generates random bytes + * and places them into a user-supplied byte array. The number of random + * bytes produced is equal to the length of the byte array. + * + * @param bytes the array to be filled in with random bytes. + */ + @Override + synchronized public void nextBytes(byte[] bytes) { + int off = 0; + int n = 0; + while (off < bytes.length) { + fillReservoir(0); + n = Math.min(bytes.length - off, reservoir.length - pos); + System.arraycopy(reservoir, pos, bytes, off, n); + off += n; + pos += n; + } } - } - - /** - * Overrides Random#next(). Generates the next pseudorandom number. - * Subclasses should override this, as this is used by all other methods. - * - * @param nbits random bits. - * @return the next pseudorandom value from this random number - * generator's sequence. - */ - @Override - synchronized protected int next(int nbits) { - fillReservoir(4); - int n = 0; - for (int i = 0; i < 4; i++) { - n = ((n << 8) | (reservoir[pos++] & 0xff)); + + /** + * Overrides Random#next(). Generates the next pseudorandom number. + * Subclasses should override this, as this is used by all other methods. + * + * @param nbits random bits. + * @return the next pseudorandom value from this random number generator's + * sequence. + */ + @Override + synchronized protected int next(int nbits) { + fillReservoir(4); + int n = 0; + for (int i = 0; i < 4; i++) { + n = ((n << 8) | (reservoir[pos++] & 0xff)); + } + return n & (0xffffffff >> (32 - nbits)); } - return n & (0xffffffff >> (32 - nbits)); - } - - /** - * Overrides {@link java.lang.AutoCloseable#close()}. Closes the OS stream. - */ - @Override - synchronized public void close() { - if (stream != null) { - IOUtils.cleanup(LOG, stream); - stream = null; + + /** + * Overrides {@link java.lang.AutoCloseable#close()}. Closes the OS stream. + */ + @Override + synchronized public void close() { + if (stream != null) { + IOUtils.cleanup(LOG, stream); + stream = null; + } } - } } http://git-wip-us.apache.org/repos/asf/commons-crypto/blob/95a8d486/src/main/java/org/apache/commons/crypto/random/package-info.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/apache/commons/crypto/random/package-info.java b/src/main/java/org/apache/commons/crypto/random/package-info.java index f8fd4de..9e392a7 100644 --- a/src/main/java/org/apache/commons/crypto/random/package-info.java +++ b/src/main/java/org/apache/commons/crypto/random/package-info.java @@ -19,3 +19,4 @@ * Random classes */ package org.apache.commons.crypto.random; + http://git-wip-us.apache.org/repos/asf/commons-crypto/blob/95a8d486/src/main/java/org/apache/commons/crypto/stream/CTRCryptoInputStream.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/apache/commons/crypto/stream/CTRCryptoInputStream.java b/src/main/java/org/apache/commons/crypto/stream/CTRCryptoInputStream.java index 481b0d6..b357000 100644 --- a/src/main/java/org/apache/commons/crypto/stream/CTRCryptoInputStream.java +++ b/src/main/java/org/apache/commons/crypto/stream/CTRCryptoInputStream.java @@ -41,588 +41,581 @@ import org.apache.commons.crypto.utils.Utils; * <p> * CTRCryptoInputStream decrypts data. AES CTR mode is required in order to * ensure that the plain text and cipher text have a 1:1 mapping. CTR crypto - * stream has stream characteristic which is useful for implement features - * like random seek. The decryption is buffer based. The key points of the - * decryption are (1) calculating the counter and (2) padding through stream - * position: + * stream has stream characteristic which is useful for implement features like + * random seek. The decryption is buffer based. The key points of the decryption + * are (1) calculating the counter and (2) padding through stream position: * </p> * <p> - * counter = base + pos/(algorithm blocksize); - * padding = pos%(algorithm blocksize); + * counter = base + pos/(algorithm blocksize); padding = pos%(algorithm + * blocksize); * </p> * The underlying stream offset is maintained as state. It is not thread-safe. */ public class CTRCryptoInputStream extends CryptoInputStream { - /** - * Underlying stream offset - */ - long streamOffset = 0; - - /** - * The initial IV. - */ - protected final byte[] initIV; - - /** - * Initialization vector for the cipher. - */ - protected byte[] iv; - - /** - * Padding = pos%(algorithm blocksize); Padding is put into {@link #inBuffer} - * before any other data goes in. The purpose of padding is to put the input - * data at proper position. - */ - private byte padding; - - /** - * Flag to mark whether the cipher has been reset - */ - private boolean cipherReset = false; - - /** - * Constructs a {@link CTRCryptoInputStream}. - * - * @param props The <code>Properties</code> class represents a set of - * properties. - * @param in the input stream. - * @param key crypto key for the cipher. - * @param iv Initialization vector for the cipher. - * @throws IOException if an I/O error occurs. - */ - public CTRCryptoInputStream(Properties props, InputStream in, - byte[] key, byte[] iv) - throws IOException { - this(props, in, key, iv, 0); - } - - /** - * Constructs a {@link CTRCryptoInputStream}. - * - * @param props The <code>Properties</code> class represents a set of - * properties. - * @param in the ReadableByteChannel instance. - * @param key crypto key for the cipher. - * @param iv Initialization vector for the cipher. - * @throws IOException if an I/O error occurs. - */ - public CTRCryptoInputStream(Properties props, ReadableByteChannel in, - byte[] key, byte[] iv) - throws IOException { - this(props, in, key, iv, 0); - } - - /** - * Constructs a {@link CTRCryptoInputStream}. - * - * @param in the input stream. - * @param cipher the CryptoCipher instance. - * @param bufferSize the bufferSize. - * @param key crypto key for the cipher. - * @param iv Initialization vector for the cipher. - * @throws IOException if an I/O error occurs. - */ - public CTRCryptoInputStream(InputStream in, CryptoCipher cipher, int bufferSize, - byte[] key, byte[] iv) throws IOException { - this(in, cipher, bufferSize, key, iv, 0); - } - - /** - * Constructs a {@link CTRCryptoInputStream}. - * - * @param in the ReadableByteChannel instance. - * @param cipher the cipher instance. - * @param bufferSize the bufferSize. - * @param key crypto key for the cipher. - * @param iv Initialization vector for the cipher. - * @throws IOException if an I/O error occurs. - */ - public CTRCryptoInputStream(ReadableByteChannel in, CryptoCipher cipher, - int bufferSize, byte[] key, byte[] iv) throws IOException { - this(in, cipher, bufferSize, key, iv, 0); - } - - /** - * Constructs a {@link CTRCryptoInputStream}. - * - * @param input the input data. - * @param cipher the CryptoCipher instance. - * @param bufferSize the bufferSize. - * @param key crypto key for the cipher. - * @param iv Initialization vector for the cipher. - * @throws IOException if an I/O error occurs. - */ - public CTRCryptoInputStream( - Input input, - CryptoCipher cipher, - int bufferSize, - byte[] key, - byte[] iv) throws IOException { - this(input, cipher, bufferSize, key, iv, 0); - } - - /** - * Constructs a {@link CTRCryptoInputStream}. - * - * @param props The <code>Properties</code> class represents a set of - * properties. - * @param in the InputStream instance. - * @param key crypto key for the cipher. - * @param iv Initialization vector for the cipher. - * @param streamOffset the start offset in the stream. - * @throws IOException if an I/O error occurs. - */ - public CTRCryptoInputStream(Properties props, InputStream in, - byte[] key, byte[] iv, long streamOffset) - throws IOException { - this(in, Utils.getCipherInstance(CipherTransformation.AES_CTR_NOPADDING, props), - Utils.getBufferSize(props), key, iv, streamOffset); - } - - /** - *Constructs a {@link CTRCryptoInputStream}. - * - * @param props The <code>Properties</code> class represents a set of - * properties. - * @param in the ReadableByteChannel instance. - * @param key crypto key for the cipher. - * @param iv Initialization vector for the cipher. - * @param streamOffset the start offset in the stream. - * @throws IOException if an I/O error occurs. - */ - public CTRCryptoInputStream(Properties props, ReadableByteChannel in, - byte[] key, byte[] iv, long streamOffset) - throws IOException { - this(in, Utils.getCipherInstance(CipherTransformation.AES_CTR_NOPADDING, props), - Utils.getBufferSize(props), key, iv, streamOffset); - } - - /** - * Constructs a {@link CTRCryptoInputStream}. - * - * @param in the InputStream instance. - * @param cipher the CryptoCipher instance. - * @param bufferSize the bufferSize. - * @param key crypto key for the cipher. - * @param iv Initialization vector for the cipher. - * @param streamOffset the start offset in the stream. - * @throws IOException if an I/O error occurs. - */ - public CTRCryptoInputStream(InputStream in, CryptoCipher cipher, int bufferSize, - byte[] key, byte[] iv, long streamOffset) throws IOException { - this(new StreamInput(in, bufferSize), cipher, bufferSize, key, iv, streamOffset); - } - - /** - * Constructs a {@link CTRCryptoInputStream}. - * - * @param in the ReadableByteChannel instance. - * @param cipher the CryptoCipher instance. - * @param bufferSize the bufferSize. - * @param key crypto key for the cipher. - * @param iv Initialization vector for the cipher. - * @param streamOffset the start offset in the stream. - * @throws IOException if an I/O error occurs. - */ - public CTRCryptoInputStream(ReadableByteChannel in, CryptoCipher cipher, - int bufferSize, byte[] key, byte[] iv, long streamOffset) throws IOException { - this(new ChannelInput(in), cipher, bufferSize, key, iv, streamOffset); - } - - /** - * Constructs a {@link CTRCryptoInputStream}. - * - * @param input the input data. - * @param cipher the CryptoCipher instance. - * @param bufferSize the bufferSize. - * @param key crypto key for the cipher. - * @param iv Initialization vector for the cipher. - * @param streamOffset the start offset in the stream. - * @throws IOException if an I/O error occurs. - */ - public CTRCryptoInputStream( - Input input, - CryptoCipher cipher, - int bufferSize, - byte[] key, - byte[] iv, - long streamOffset) throws IOException { - super(input, cipher, bufferSize, new SecretKeySpec(key, "AES"), new IvParameterSpec(iv)); - - this.initIV = iv.clone(); - this.iv = iv.clone(); - - Utils.checkStreamCipher(cipher); - - resetStreamOffset(streamOffset); - } - - /** - * Overrides the {@link CryptoInputStream#skip(long)}. - * Skips over and discards <code>n</code> bytes of data from this input - * stream. - * - * @param n the number of bytes to be skipped. - * @return the actual number of bytes skipped. - * @throws IOException if an I/O error occurs. - */ - @Override - public long skip(long n) throws IOException { - Utils.checkArgument(n >= 0, "Negative skip length."); - checkStream(); - - if (n == 0) { - return 0; - } else if (n <= outBuffer.remaining()) { - int pos = outBuffer.position() + (int) n; - outBuffer.position(pos); - return n; - } else { - /* - * Subtract outBuffer.remaining() to see how many bytes we need to - * skip in the underlying stream. Add outBuffer.remaining() to the - * actual number of skipped bytes in the underlying stream to get the - * number of skipped bytes from the user's point of view. - */ - n -= outBuffer.remaining(); - long skipped = input.skip(n); - if (skipped < 0) { - skipped = 0; - } - long pos = streamOffset + skipped; - skipped += outBuffer.remaining(); - resetStreamOffset(pos); - return skipped; + /** + * Underlying stream offset + */ + long streamOffset = 0; + + /** + * The initial IV. + */ + protected final byte[] initIV; + + /** + * Initialization vector for the cipher. + */ + protected byte[] iv; + + /** + * Padding = pos%(algorithm blocksize); Padding is put into + * {@link #inBuffer} before any other data goes in. The purpose of padding + * is to put the input data at proper position. + */ + private byte padding; + + /** + * Flag to mark whether the cipher has been reset + */ + private boolean cipherReset = false; + + /** + * Constructs a {@link CTRCryptoInputStream}. + * + * @param props The <code>Properties</code> class represents a set of + * properties. + * @param in the input stream. + * @param key crypto key for the cipher. + * @param iv Initialization vector for the cipher. + * @throws IOException if an I/O error occurs. + */ + public CTRCryptoInputStream(Properties props, InputStream in, byte[] key, + byte[] iv) throws IOException { + this(props, in, key, iv, 0); } - } - - /** - * Overrides the {@link CTRCryptoInputStream#read(ByteBuffer)}. - * Reads a sequence of bytes from this channel into the given buffer. - * - * @param buf The buffer into which bytes are to be transferred. - * @return The number of bytes read, possibly zero, or <tt>-1</tt> if the - * channel has reached end-of-stream. - * @throws IOException if an I/O error occurs. - */ - @Override - public int read(ByteBuffer buf) throws IOException { - checkStream(); - int unread = outBuffer.remaining(); - if (unread <= 0) { // Fill the unread decrypted data buffer firstly - final int n = input.read(inBuffer); - if (n <= 0) { - return n; - } - - streamOffset += n; // Read n bytes - if (buf.isDirect() && buf.remaining() >= inBuffer.position() && padding == 0) { - // Use buf as the output buffer directly - decryptInPlace(buf); - padding = postDecryption(streamOffset); - return n; - } else { - // Use outBuffer as the output buffer + + /** + * Constructs a {@link CTRCryptoInputStream}. + * + * @param props The <code>Properties</code> class represents a set of + * properties. + * @param in the ReadableByteChannel instance. + * @param key crypto key for the cipher. + * @param iv Initialization vector for the cipher. + * @throws IOException if an I/O error occurs. + */ + public CTRCryptoInputStream(Properties props, ReadableByteChannel in, + byte[] key, byte[] iv) throws IOException { + this(props, in, key, iv, 0); + } + + /** + * Constructs a {@link CTRCryptoInputStream}. + * + * @param in the input stream. + * @param cipher the CryptoCipher instance. + * @param bufferSize the bufferSize. + * @param key crypto key for the cipher. + * @param iv Initialization vector for the cipher. + * @throws IOException if an I/O error occurs. + */ + public CTRCryptoInputStream(InputStream in, CryptoCipher cipher, + int bufferSize, byte[] key, byte[] iv) throws IOException { + this(in, cipher, bufferSize, key, iv, 0); + } + + /** + * Constructs a {@link CTRCryptoInputStream}. + * + * @param in the ReadableByteChannel instance. + * @param cipher the cipher instance. + * @param bufferSize the bufferSize. + * @param key crypto key for the cipher. + * @param iv Initialization vector for the cipher. + * @throws IOException if an I/O error occurs. + */ + public CTRCryptoInputStream(ReadableByteChannel in, CryptoCipher cipher, + int bufferSize, byte[] key, byte[] iv) throws IOException { + this(in, cipher, bufferSize, key, iv, 0); + } + + /** + * Constructs a {@link CTRCryptoInputStream}. + * + * @param input the input data. + * @param cipher the CryptoCipher instance. + * @param bufferSize the bufferSize. + * @param key crypto key for the cipher. + * @param iv Initialization vector for the cipher. + * @throws IOException if an I/O error occurs. + */ + public CTRCryptoInputStream(Input input, CryptoCipher cipher, + int bufferSize, byte[] key, byte[] iv) throws IOException { + this(input, cipher, bufferSize, key, iv, 0); + } + + /** + * Constructs a {@link CTRCryptoInputStream}. + * + * @param props The <code>Properties</code> class represents a set of + * properties. + * @param in the InputStream instance. + * @param key crypto key for the cipher. + * @param iv Initialization vector for the cipher. + * @param streamOffset the start offset in the stream. + * @throws IOException if an I/O error occurs. + */ + public CTRCryptoInputStream(Properties props, InputStream in, byte[] key, + byte[] iv, long streamOffset) throws IOException { + this(in, Utils.getCipherInstance( + CipherTransformation.AES_CTR_NOPADDING, props), Utils + .getBufferSize(props), key, iv, streamOffset); + } + + /** + * Constructs a {@link CTRCryptoInputStream}. + * + * @param props The <code>Properties</code> class represents a set of + * properties. + * @param in the ReadableByteChannel instance. + * @param key crypto key for the cipher. + * @param iv Initialization vector for the cipher. + * @param streamOffset the start offset in the stream. + * @throws IOException if an I/O error occurs. + */ + public CTRCryptoInputStream(Properties props, ReadableByteChannel in, + byte[] key, byte[] iv, long streamOffset) throws IOException { + this(in, Utils.getCipherInstance( + CipherTransformation.AES_CTR_NOPADDING, props), Utils + .getBufferSize(props), key, iv, streamOffset); + } + + /** + * Constructs a {@link CTRCryptoInputStream}. + * + * @param in the InputStream instance. + * @param cipher the CryptoCipher instance. + * @param bufferSize the bufferSize. + * @param key crypto key for the cipher. + * @param iv Initialization vector for the cipher. + * @param streamOffset the start offset in the stream. + * @throws IOException if an I/O error occurs. + */ + public CTRCryptoInputStream(InputStream in, CryptoCipher cipher, + int bufferSize, byte[] key, byte[] iv, long streamOffset) + throws IOException { + this(new StreamInput(in, bufferSize), cipher, bufferSize, key, iv, + streamOffset); + } + + /** + * Constructs a {@link CTRCryptoInputStream}. + * + * @param in the ReadableByteChannel instance. + * @param cipher the CryptoCipher instance. + * @param bufferSize the bufferSize. + * @param key crypto key for the cipher. + * @param iv Initialization vector for the cipher. + * @param streamOffset the start offset in the stream. + * @throws IOException if an I/O error occurs. + */ + public CTRCryptoInputStream(ReadableByteChannel in, CryptoCipher cipher, + int bufferSize, byte[] key, byte[] iv, long streamOffset) + throws IOException { + this(new ChannelInput(in), cipher, bufferSize, key, iv, streamOffset); + } + + /** + * Constructs a {@link CTRCryptoInputStream}. + * + * @param input the input data. + * @param cipher the CryptoCipher instance. + * @param bufferSize the bufferSize. + * @param key crypto key for the cipher. + * @param iv Initialization vector for the cipher. + * @param streamOffset the start offset in the stream. + * @throws IOException if an I/O error occurs. + */ + public CTRCryptoInputStream(Input input, CryptoCipher cipher, + int bufferSize, byte[] key, byte[] iv, long streamOffset) + throws IOException { + super(input, cipher, bufferSize, new SecretKeySpec(key, "AES"), + new IvParameterSpec(iv)); + + this.initIV = iv.clone(); + this.iv = iv.clone(); + + Utils.checkStreamCipher(cipher); + + resetStreamOffset(streamOffset); + } + + /** + * Overrides the {@link CryptoInputStream#skip(long)}. Skips over and + * discards <code>n</code> bytes of data from this input stream. + * + * @param n the number of bytes to be skipped. + * @return the actual number of bytes skipped. + * @throws IOException if an I/O error occurs. + */ + @Override + public long skip(long n) throws IOException { + Utils.checkArgument(n >= 0, "Negative skip length."); + checkStream(); + + if (n == 0) { + return 0; + } else if (n <= outBuffer.remaining()) { + int pos = outBuffer.position() + (int) n; + outBuffer.position(pos); + return n; + } else { + /* + * Subtract outBuffer.remaining() to see how many bytes we need to + * skip in the underlying stream. Add outBuffer.remaining() to the + * actual number of skipped bytes in the underlying stream to get + * the number of skipped bytes from the user's point of view. + */ + n -= outBuffer.remaining(); + long skipped = input.skip(n); + if (skipped < 0) { + skipped = 0; + } + long pos = streamOffset + skipped; + skipped += outBuffer.remaining(); + resetStreamOffset(pos); + return skipped; + } + } + + /** + * Overrides the {@link CTRCryptoInputStream#read(ByteBuffer)}. Reads a + * sequence of bytes from this channel into the given buffer. + * + * @param buf The buffer into which bytes are to be transferred. + * @return The number of bytes read, possibly zero, or <tt>-1</tt> if the + * channel has reached end-of-stream. + * @throws IOException if an I/O error occurs. + */ + @Override + public int read(ByteBuffer buf) throws IOException { + checkStream(); + int unread = outBuffer.remaining(); + if (unread <= 0) { // Fill the unread decrypted data buffer firstly + final int n = input.read(inBuffer); + if (n <= 0) { + return n; + } + + streamOffset += n; // Read n bytes + if (buf.isDirect() && buf.remaining() >= inBuffer.position() + && padding == 0) { + // Use buf as the output buffer directly + decryptInPlace(buf); + padding = postDecryption(streamOffset); + return n; + } else { + // Use outBuffer as the output buffer + decrypt(); + padding = postDecryption(streamOffset); + } + } + + // Copy decrypted data from outBuffer to buf + unread = outBuffer.remaining(); + final int toRead = buf.remaining(); + if (toRead <= unread) { + final int limit = outBuffer.limit(); + outBuffer.limit(outBuffer.position() + toRead); + buf.put(outBuffer); + outBuffer.limit(limit); + return toRead; + } else { + buf.put(outBuffer); + return unread; + } + } + + /** + * Seeks the stream to a specific position relative to start of the under + * layer stream. + * + * @param position the given position in the data. + * @throws IOException if an I/O error occurs. + */ + public void seek(long position) throws IOException { + Utils.checkArgument(position >= 0, "Cannot seek to negative offset."); + checkStream(); + /* + * If data of target pos in the underlying stream has already been read + * and decrypted in outBuffer, we just need to re-position outBuffer. + */ + if (position >= getStreamPosition() && position <= getStreamOffset()) { + int forward = (int) (position - getStreamPosition()); + if (forward > 0) { + outBuffer.position(outBuffer.position() + forward); + } + } else { + input.seek(position); + resetStreamOffset(position); + } + } + + /** + * Gets the offset of the stream. + * + * @return the stream offset. + */ + protected long getStreamOffset() { + return streamOffset; + } + + protected void setStreamOffset(long streamOffset) { + this.streamOffset = streamOffset; + } + + /** + * Gets the position of the stream. + * + * @return the position of the stream. + */ + protected long getStreamPosition() { + return streamOffset - outBuffer.remaining(); + } + + /** + * Decrypts more data by reading the under layer stream. The decrypted data + * will be put in the output buffer. + * + * @return The number of decrypted data. -1 if end of the decrypted stream. + * @throws IOException if an I/O error occurs. + */ + @Override + protected int decryptMore() throws IOException { + int n = input.read(inBuffer); + if (n <= 0) { + return n; + } + + streamOffset += n; // Read n bytes decrypt(); padding = postDecryption(streamOffset); - } + return outBuffer.remaining(); } - // Copy decrypted data from outBuffer to buf - unread = outBuffer.remaining(); - final int toRead = buf.remaining(); - if (toRead <= unread) { - final int limit = outBuffer.limit(); - outBuffer.limit(outBuffer.position() + toRead); - buf.put(outBuffer); - outBuffer.limit(limit); - return toRead; - } else { - buf.put(outBuffer); - return unread; + /** + * Does the decryption using inBuffer as input and outBuffer as output. Upon + * return, inBuffer is cleared; the decrypted data starts at + * outBuffer.position() and ends at outBuffer.limit(). + * + * @throws IOException if an I/O error occurs. + */ + @Override + protected void decrypt() throws IOException { + Utils.checkState(inBuffer.position() >= padding); + if (inBuffer.position() == padding) { + // There is no real data in inBuffer. + return; + } + + inBuffer.flip(); + outBuffer.clear(); + decryptBuffer(outBuffer); + inBuffer.clear(); + outBuffer.flip(); + + if (padding > 0) { + /* + * The plain text and cipher text have a 1:1 mapping, they start at + * the same position. + */ + outBuffer.position(padding); + } } - } - - /** - * Seeks the stream to a specific position relative to start of the under layer stream. - * - * @param position the given position in the data. - * @throws IOException if an I/O error occurs. - */ - public void seek(long position) throws IOException { - Utils.checkArgument(position >= 0, "Cannot seek to negative offset."); - checkStream(); - /* - * If data of target pos in the underlying stream has already been read - * and decrypted in outBuffer, we just need to re-position outBuffer. - */ - if (position >= getStreamPosition() && position <= getStreamOffset()) { - int forward = (int) (position - getStreamPosition()); - if (forward > 0) { - outBuffer.position(outBuffer.position() + forward); - } - } else { - input.seek(position); - resetStreamOffset(position); + + /** + * Does the decryption using inBuffer as input and buf as output. Upon + * return, inBuffer is cleared; the buf's position will be equal to + * <i>p</i> <tt>+</tt> <i>n</i> where <i>p</i> is the position + * before decryption, <i>n</i> is the number of bytes decrypted. The buf's + * limit will not have changed. + * + * @param buf The buffer into which bytes are to be transferred. + * @throws IOException if an I/O error occurs. + */ + protected void decryptInPlace(ByteBuffer buf) throws IOException { + Utils.checkState(inBuffer.position() >= padding); + Utils.checkState(buf.isDirect()); + Utils.checkState(buf.remaining() >= inBuffer.position()); + Utils.checkState(padding == 0); + + if (inBuffer.position() == padding) { + // There is no real data in inBuffer. + return; + } + inBuffer.flip(); + decryptBuffer(buf); + inBuffer.clear(); } - } - - /** - * Gets the offset of the stream. - * - * @return the stream offset. - */ - protected long getStreamOffset() { - return streamOffset; - } - - protected void setStreamOffset(long streamOffset) { - this.streamOffset = streamOffset; - } - - /** - * Gets the position of the stream. - * - * @return the position of the stream. - */ - protected long getStreamPosition() { - return streamOffset - outBuffer.remaining(); - } - - /** - * Decrypts more data by reading the under layer stream. The decrypted data will - * be put in the output buffer. - * - * @return The number of decrypted data. -1 if end of the decrypted stream. - * @throws IOException if an I/O error occurs. - */ - @Override - protected int decryptMore() throws IOException { - int n = input.read(inBuffer); - if (n <= 0) { - return n; + + /** + * Decrypts all data in buf: total n bytes from given start position. Output + * is also buf and same start position. buf.position() and buf.limit() + * should be unchanged after decryption. + * + * @param buf The buffer into which bytes are to be transferred. + * @param offset the start offset in the data. + * @param len the the maximum number of decrypted data bytes to read. + * @throws IOException if an I/O error occurs. + */ + protected void decrypt(ByteBuffer buf, int offset, int len) + throws IOException { + final int pos = buf.position(); + final int limit = buf.limit(); + int n = 0; + while (n < len) { + buf.position(offset + n); + buf.limit(offset + n + Math.min(len - n, inBuffer.remaining())); + inBuffer.put(buf); + // Do decryption + try { + decrypt(); + buf.position(offset + n); + buf.limit(limit); + n += outBuffer.remaining(); + buf.put(outBuffer); + } finally { + padding = postDecryption(streamOffset - (len - n)); + } + } + buf.position(pos); } - streamOffset += n; // Read n bytes - decrypt(); - padding = postDecryption(streamOffset); - return outBuffer.remaining(); - } - - /** - * Does the decryption using inBuffer as input and outBuffer as output. - * Upon return, inBuffer is cleared; the decrypted data starts at - * outBuffer.position() and ends at outBuffer.limit(). - * - * @throws IOException if an I/O error occurs. - */ - @Override - protected void decrypt() throws IOException { - Utils.checkState(inBuffer.position() >= padding); - if(inBuffer.position() == padding) { - // There is no real data in inBuffer. - return; + /** + * This method is executed immediately after decryption. Checks whether + * cipher should be updated and recalculate padding if needed. + * + * @param position the given position in the data.. + * @return the byte. + * @throws IOException if an I/O error occurs. + */ + protected byte postDecryption(long position) throws IOException { + byte padding = 0; + if (cipherReset) { + /* + * This code is generally not executed since the cipher usually + * maintains cipher context (e.g. the counter) internally. However, + * some implementations can't maintain context so a re-init is + * necessary after each decryption call. + */ + resetCipher(position); + padding = getPadding(position); + inBuffer.position(padding); + } + return padding; } - inBuffer.flip(); - outBuffer.clear(); - decryptBuffer(outBuffer); - inBuffer.clear(); - outBuffer.flip(); - - if (padding > 0) { - /* - * The plain text and cipher text have a 1:1 mapping, they start at the - * same position. - */ - outBuffer.position(padding); + /** + * Gets the initialization vector. + * + * @return the initIV. + */ + protected byte[] getInitIV() { + return initIV; } - } - - /** - * Does the decryption using inBuffer as input and buf as output. - * Upon return, inBuffer is cleared; the buf's position will be equal to - * <i>p</i> <tt>+</tt> <i>n</i> where <i>p</i> is the position before - * decryption, <i>n</i> is the number of bytes decrypted. - * The buf's limit will not have changed. - * - * @param buf The buffer into which bytes are to be transferred. - * @throws IOException if an I/O error occurs. - */ - protected void decryptInPlace(ByteBuffer buf) throws IOException { - Utils.checkState(inBuffer.position() >= padding); - Utils.checkState(buf.isDirect()); - Utils.checkState(buf.remaining() >= inBuffer.position()); - Utils.checkState(padding == 0); - - if(inBuffer.position() == padding) { - // There is no real data in inBuffer. - return; + + /** + * Gets the counter for input stream position. + * + * @param position the given position in the data. + * @return the counter for input stream position. + */ + protected long getCounter(long position) { + return position / cipher.getTransformation().getAlgorithmBlockSize(); } - inBuffer.flip(); - decryptBuffer(buf); - inBuffer.clear(); - } - - /** - * Decrypts all data in buf: total n bytes from given start position. - * Output is also buf and same start position. - * buf.position() and buf.limit() should be unchanged after decryption. - * - * @param buf The buffer into which bytes are to be transferred. - * @param offset the start offset in the data. - * @param len the the maximum number of decrypted data bytes to read. - * @throws IOException if an I/O error occurs. - */ - protected void decrypt(ByteBuffer buf, int offset, int len) - throws IOException { - final int pos = buf.position(); - final int limit = buf.limit(); - int n = 0; - while (n < len) { - buf.position(offset + n); - buf.limit(offset + n + Math.min(len - n, inBuffer.remaining())); - inBuffer.put(buf); - // Do decryption - try { - decrypt(); - buf.position(offset + n); - buf.limit(limit); - n += outBuffer.remaining(); - buf.put(outBuffer); - } finally { - padding = postDecryption(streamOffset - (len - n)); - } + + /** + * Gets the padding for input stream position. + * + * @param position the given position in the data. + * @return the padding for input stream position. + */ + protected byte getPadding(long position) { + return (byte) (position % cipher.getTransformation() + .getAlgorithmBlockSize()); } - buf.position(pos); - } - - /** - * This method is executed immediately after decryption. Checks whether - * cipher should be updated and recalculate padding if needed. - * - * @param position the given position in the data.. - * @return the byte. - * @throws IOException if an I/O error occurs. - */ - protected byte postDecryption(long position) throws IOException { - byte padding = 0; - if (cipherReset) { - /* - * This code is generally not executed since the cipher usually - * maintains cipher context (e.g. the counter) internally. However, - * some implementations can't maintain context so a re-init is necessary - * after each decryption call. - */ - resetCipher(position); - padding = getPadding(position); - inBuffer.position(padding); + + /** + * Overrides the {@link CTRCryptoInputStream#initCipher()}. Initializes the + * cipher. + */ + @Override + protected void initCipher() { + // Do nothing for initCipher + // Will reset the cipher when reset the stream offset } - return padding; - } - - /** - * Gets the initialization vector. - * - * @return the initIV. - */ - protected byte[] getInitIV() { - return initIV; - } - - /** - * Gets the counter for input stream position. - * - * @param position the given position in the data. - * @return the counter for input stream position. - */ - protected long getCounter(long position) { - return position / cipher.getTransformation().getAlgorithmBlockSize(); - } - - /** - * Gets the padding for input stream position. - * - * @param position the given position in the data. - * @return the padding for input stream position. - */ - protected byte getPadding(long position) { - return (byte)(position % cipher.getTransformation().getAlgorithmBlockSize()); - } - - /** - * Overrides the {@link CTRCryptoInputStream#initCipher()}. - * Initializes the cipher. - */ - @Override - protected void initCipher() { - // Do nothing for initCipher - // Will reset the cipher when reset the stream offset - } - - /** - * Calculates the counter and iv, resets the cipher. - * - * @param position the given position in the data. - * @throws IOException if an I/O error occurs. - */ - protected void resetCipher(long position) - throws IOException { - final long counter = getCounter(position); - Utils.calculateIV(initIV, counter, iv); - try { - cipher.init(CryptoCipher.DECRYPT_MODE, key, new IvParameterSpec(iv)); - } catch (InvalidKeyException e) { - throw new IOException(e); - } catch (InvalidAlgorithmParameterException e) { - throw new IOException(e); + + /** + * Calculates the counter and iv, resets the cipher. + * + * @param position the given position in the data. + * @throws IOException if an I/O error occurs. + */ + protected void resetCipher(long position) throws IOException { + final long counter = getCounter(position); + Utils.calculateIV(initIV, counter, iv); + try { + cipher.init(CryptoCipher.DECRYPT_MODE, key, new IvParameterSpec(iv)); + } catch (InvalidKeyException e) { + throw new IOException(e); + } catch (InvalidAlgorithmParameterException e) { + throw new IOException(e); + } + cipherReset = false; } - cipherReset = false; - } - - /** - * Resets the underlying stream offset; clear {@link #inBuffer} and - * {@link #outBuffer}. This Typically happens during {@link #skip(long)}. - * - * @param offset the offset of the stream. - * @throws IOException if an I/O error occurs. - */ - protected void resetStreamOffset(long offset) throws IOException { - streamOffset = offset; - inBuffer.clear(); - outBuffer.clear(); - outBuffer.limit(0); - resetCipher(offset); - padding = getPadding(offset); - inBuffer.position(padding); // Set proper position for input data. - } - - /** - * Does the decryption using out as output. - * - * @param out the output ByteBuffer. - * @throws IOException if an I/O error occurs. - */ - protected void decryptBuffer(ByteBuffer out) - throws IOException { - int inputSize = inBuffer.remaining(); - try { - int n = cipher.update(inBuffer, out); - if (n < inputSize) { - /** - * Typically code will not get here. CryptoCipher#update will consume all - * input data and put result in outBuffer. - * CryptoCipher#doFinal will reset the cipher context. - */ - cipher.doFinal(inBuffer, out); - cipherReset = true; - } - } catch (ShortBufferException e) { - throw new IOException(e); - } catch (IllegalBlockSizeException e) { - throw new IOException(e); - } catch (BadPaddingException e) { - throw new IOException(e); + + /** + * Resets the underlying stream offset; clear {@link #inBuffer} and + * {@link #outBuffer}. This Typically happens during {@link #skip(long)}. + * + * @param offset the offset of the stream. + * @throws IOException if an I/O error occurs. + */ + protected void resetStreamOffset(long offset) throws IOException { + streamOffset = offset; + inBuffer.clear(); + outBuffer.clear(); + outBuffer.limit(0); + resetCipher(offset); + padding = getPadding(offset); + inBuffer.position(padding); // Set proper position for input data. + } + + /** + * Does the decryption using out as output. + * + * @param out the output ByteBuffer. + * @throws IOException if an I/O error occurs. + */ + protected void decryptBuffer(ByteBuffer out) throws IOException { + int inputSize = inBuffer.remaining(); + try { + int n = cipher.update(inBuffer, out); + if (n < inputSize) { + /** + * Typically code will not get here. CryptoCipher#update will + * consume all input data and put result in outBuffer. + * CryptoCipher#doFinal will reset the cipher context. + */ + cipher.doFinal(inBuffer, out); + cipherReset = true; + } + } catch (ShortBufferException e) { + throw new IOException(e); + } catch (IllegalBlockSizeException e) { + throw new IOException(e); + } catch (BadPaddingException e) { + throw new IOException(e); + } } - } }