001/** 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, software 013 * distributed under the License is distributed on an "AS IS" BASIS, 014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 015 * See the License for the specific language governing permissions and 016 * limitations under the License. 017 */ 018package org.apache.commons.crypto.random; 019 020import java.security.GeneralSecurityException; 021import java.util.List; 022import java.util.Properties; 023 024import org.apache.commons.crypto.Crypto; 025import org.apache.commons.crypto.utils.ReflectionUtils; 026import org.apache.commons.crypto.utils.Utils; 027 028/** 029 * This is the factory class used for creating {@link CryptoRandom} instances 030 */ 031public class CryptoRandomFactory { 032 033 // security random related configuration keys 034 /** 035 * The configuration key of the file path for secure random device. 036 */ 037 public static final String DEVICE_FILE_PATH_KEY = Crypto.CONF_PREFIX 038 + "secure.random.device.file.path"; 039 040 /** 041 * The default value ({@value}) of the file path for secure random device. 042 */ 043 // Note: this is public mainly for use by the Javadoc 044 public static final String DEVICE_FILE_PATH_DEFAULT = "/dev/urandom"; 045 046 /** 047 * The configuration key of the algorithm of secure random. 048 */ 049 public static final String JAVA_ALGORITHM_KEY = Crypto.CONF_PREFIX 050 + "secure.random.java.algorithm"; 051 052 /** 053 * The default value ({@value}) of the algorithm of secure random. 054 */ 055 // Note: this is public mainly for use by the Javadoc 056 public static final String JAVA_ALGORITHM_DEFAULT = "SHA1PRNG"; 057 058 /** 059 * The configuration key of the CryptoRandom implementation class. 060 * <p> 061 * The value of the CLASSES_KEY needs to be the full name of a 062 * class that implements the 063 * {@link org.apache.commons.crypto.random.CryptoRandom CryptoRandom} interface 064 * The internal classes are listed in the enum 065 * {@link RandomProvider RandomProvider} 066 * which can be used to obtain the full class name. 067 * <p> 068 * The value can also be a comma-separated list of class names in 069 * order of descending priority. 070 */ 071 public static final String CLASSES_KEY = Crypto.CONF_PREFIX 072 + "secure.random.classes"; 073 /** 074 * Defines the internal CryptoRandom implementations. 075 * <p> 076 * Usage: 077 * <blockquote><pre> 078 * props.setProperty(CryptoRandomFactory.CLASSES_KEY, RandomProvider.OPENSSL.getClassName()); 079 * props.setProperty(...); // if required by the implementation 080 * random = CryptoRandomFactory.getCryptoRandom(transformation, props); 081 * </pre></blockquote> 082 */ 083 public enum RandomProvider { 084 085 /** 086 * The OpenSSL Random implementation (using JNI) 087 * <p> 088 * No properties are used for configuration, but they 089 * are passed to the {@link RandomProvider#JAVA} backup implementation 090 */ 091 // Please ensure the property description agrees with the implementation 092 OPENSSL(OpenSslCryptoRandom.class), 093 094 /** 095 * The SecureRandom implementation from the JVM 096 * <p> 097 * Uses the property with key 098 * {@link #JAVA_ALGORITHM_KEY} 099 * with the default of 100 * {@link #JAVA_ALGORITHM_DEFAULT} 101 */ 102 // Please ensure the property description agrees with the implementation 103 JAVA(JavaCryptoRandom.class), 104 105 /** 106 * The OS random device implementation. May not be available on some OSes. 107 * <p> 108 * Uses {@link #DEVICE_FILE_PATH_KEY} to determine the 109 * path to the random device, default is 110 * {@link #DEVICE_FILE_PATH_DEFAULT} 111 */ 112 // Please ensure the property description agrees with the implementation 113 OS(OsCryptoRandom.class); 114 115 private final Class<? extends CryptoRandom> klass; 116 117 private final String className; 118 119 /** 120 * The private constructor. 121 * @param klass the Class of CryptoRandom 122 */ 123 private RandomProvider(final Class<? extends CryptoRandom> klass) { 124 this.klass = klass; 125 this.className = klass.getName(); 126 } 127 128 /** 129 * Gets the class name of the provider. 130 * 131 * @return the name of the provider class 132 */ 133 public String getClassName() { 134 return className; 135 } 136 137 /** 138 * Gets the implementation class of the provider. 139 * 140 * @return the implementation class of the provider 141 */ 142 public Class<? extends CryptoRandom> getImplClass() { 143 return klass; 144 } 145 } 146 147 /** 148 * The default value (OPENSSL,JAVA) used when creating a {@link org.apache.commons.crypto.cipher.CryptoCipher}. 149 */ 150 private static final String CLASSES_DEFAULT = 151 RandomProvider.OPENSSL.getClassName() 152 .concat(",") 153 .concat(RandomProvider.JAVA.getClassName()); 154 155 /** 156 * The private constructor of {@link CryptoRandomFactory}. 157 */ 158 private CryptoRandomFactory() { 159 } 160 161 /** 162 * Gets a CryptoRandom instance using the default implementation 163 * as defined by {@link #CLASSES_DEFAULT} 164 * 165 * @return CryptoRandom the cryptoRandom object. 166 * @throws GeneralSecurityException if cannot create the {@link CryptoRandom} class 167 */ 168 public static CryptoRandom getCryptoRandom() throws GeneralSecurityException { 169 final Properties properties = new Properties(); 170 return getCryptoRandom(properties); 171 } 172 173 /** 174 * Gets a CryptoRandom instance for specified props. 175 * Uses the SECURE_RANDOM_CLASSES_KEY from the provided 176 * properties. 177 * If it is not set, then it checks the System properties. 178 * Failing that, it defaults to OpenSslCryptoRandom,JavaCryptoRandom 179 * The properties are passed to the generated class. 180 * 181 * @param props the configuration properties. 182 * @return CryptoRandom the cryptoRandom object. 183 * @throws GeneralSecurityException if cannot create the {@link CryptoRandom} class 184 * @throws IllegalArgumentException if no classname(s) are provided 185 */ 186 public static CryptoRandom getCryptoRandom(final Properties props) 187 throws GeneralSecurityException { 188 final List<String> names = Utils.splitClassNames(getRandomClassString(props), ","); 189 if (names.size() == 0) { 190 throw new IllegalArgumentException("No class name(s) provided"); 191 } 192 final StringBuilder errorMessage = new StringBuilder(); 193 CryptoRandom random = null; 194 Exception lastException = null; 195 for (final String klassName : names) { 196 try { 197 final Class<?> klass = ReflectionUtils.getClassByName(klassName); 198 random = (CryptoRandom) ReflectionUtils.newInstance(klass, props); 199 if (random != null) { 200 break; 201 } 202 } catch (final ClassCastException e) { 203 lastException = e; 204 errorMessage.append("Class: [" + klassName + "] is not a CryptoRandom."); 205 } catch (final ClassNotFoundException e) { 206 lastException = e; 207 errorMessage.append("CryptoRandom: [" + klassName + "] not found."); 208 } catch (final Exception e) { 209 lastException = e; 210 errorMessage.append("CryptoRandom: [" + klassName + "] failed with " + e.getMessage()); 211 } 212 } 213 214 if (random != null) { 215 return random; 216 } 217 throw new GeneralSecurityException(errorMessage.toString(), lastException); 218 } 219 220 /** 221 * Gets the CryptoRandom class. 222 * 223 * @param props The {@code Properties} class represents a set of 224 * properties. 225 * @return the CryptoRandom class based on the props. 226 */ 227 private static String getRandomClassString(final Properties props) { 228 String randomClassString = props.getProperty(CryptoRandomFactory.CLASSES_KEY, CLASSES_DEFAULT); 229 if (randomClassString.isEmpty()) { // TODO does it make sense to treat the empty string as the default? 230 randomClassString = CLASSES_DEFAULT; 231 } 232 return randomClassString; 233 } 234}