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 * Creates {@link CryptoRandom} instances 030 */ 031public class CryptoRandomFactory { 032 033 /** 034 * Defines the internal CryptoRandom implementations. 035 * <p> 036 * Usage: 037 * <blockquote><pre> 038 * props.setProperty(CryptoRandomFactory.CLASSES_KEY, RandomProvider.OPENSSL.getClassName()); 039 * props.setProperty(...); // if required by the implementation 040 * random = CryptoRandomFactory.getCryptoRandom(transformation, props); 041 * </pre></blockquote> 042 */ 043 public enum RandomProvider { 044 045 /** 046 * The OpenSSL Random implementation (using JNI) 047 * <p> 048 * No properties are used for configuration, but they 049 * are passed to the {@link RandomProvider#JAVA} backup implementation 050 */ 051 // Please ensure the property description agrees with the implementation 052 OPENSSL(OpenSslCryptoRandom.class), 053 054 /** 055 * The SecureRandom implementation from the JVM 056 * <p> 057 * Uses the property with key 058 * {@link #JAVA_ALGORITHM_KEY} 059 * with the default of 060 * {@link #JAVA_ALGORITHM_DEFAULT} 061 */ 062 // Please ensure the property description agrees with the implementation 063 JAVA(JavaCryptoRandom.class), 064 065 /** 066 * The OS random device implementation. May not be available on some OSes. 067 * <p> 068 * Uses {@link #DEVICE_FILE_PATH_KEY} to determine the 069 * path to the random device, default is 070 * {@link #DEVICE_FILE_PATH_DEFAULT} 071 */ 072 // Please ensure the property description agrees with the implementation 073 OS(OsCryptoRandom.class); 074 075 private final Class<? extends CryptoRandom> klass; 076 077 private final String className; 078 079 /** 080 * The private constructor. 081 * @param klass the Class of CryptoRandom 082 */ 083 RandomProvider(final Class<? extends CryptoRandom> klass) { 084 this.klass = klass; 085 this.className = klass.getName(); 086 } 087 088 /** 089 * Gets the class name of the provider. 090 * 091 * @return the name of the provider class 092 */ 093 public String getClassName() { 094 return className; 095 } 096 097 /** 098 * Gets the implementation class of the provider. 099 * 100 * @return the implementation class of the provider 101 */ 102 public Class<? extends CryptoRandom> getImplClass() { 103 return klass; 104 } 105 } 106 107 // security random related configuration keys 108 /** 109 * The configuration key of the file path for secure random device. 110 */ 111 public static final String DEVICE_FILE_PATH_KEY = Crypto.CONF_PREFIX + "secure.random.device.file.path"; 112 113 /** 114 * The default value ({@value}) of the file path for secure random device. 115 */ 116 // Note: this is public mainly for use by the Javadoc 117 public static final String DEVICE_FILE_PATH_DEFAULT = "/dev/urandom"; 118 119 /** 120 * The configuration key of the algorithm of secure random. 121 */ 122 public static final String JAVA_ALGORITHM_KEY = Crypto.CONF_PREFIX + "secure.random.java.algorithm"; 123 124 /** 125 * The default value ({@value}) of the algorithm of secure random. 126 */ 127 // Note: this is public mainly for use by the Javadoc 128 public static final String JAVA_ALGORITHM_DEFAULT = "SHA1PRNG"; 129 130 /** 131 * The configuration key of the CryptoRandom implementation class. 132 * <p> 133 * The value of the CLASSES_KEY needs to be the full name of a 134 * class that implements the 135 * {@link org.apache.commons.crypto.random.CryptoRandom CryptoRandom} interface 136 * The internal classes are listed in the enum 137 * {@link RandomProvider RandomProvider} 138 * which can be used to obtain the full class name. 139 * <p> 140 * The value can also be a comma-separated list of class names in 141 * order of descending priority. 142 */ 143 public static final String CLASSES_KEY = Crypto.CONF_PREFIX + "secure.random.classes"; 144 145 /** 146 * The default value (OPENSSL,JAVA) used when creating a {@link org.apache.commons.crypto.cipher.CryptoCipher}. 147 */ 148 private static final String CLASSES_DEFAULT = 149 RandomProvider.OPENSSL.getClassName() 150 .concat(",") 151 .concat(RandomProvider.JAVA.getClassName()); 152 153 /** 154 * Gets a CryptoRandom instance using the default implementation 155 * as defined by {@link #CLASSES_DEFAULT} 156 * 157 * @return CryptoRandom the cryptoRandom object. 158 * @throws GeneralSecurityException if cannot create the {@link CryptoRandom} class 159 */ 160 public static CryptoRandom getCryptoRandom() throws GeneralSecurityException { 161 final Properties properties = new Properties(); 162 return getCryptoRandom(properties); 163 } 164 165 /** 166 * Gets a CryptoRandom instance for specified props. 167 * Uses the SECURE_RANDOM_CLASSES_KEY from the provided 168 * properties. 169 * If it is not set, then it checks the System properties. 170 * Failing that, it defaults to OpenSslCryptoRandom,JavaCryptoRandom 171 * The properties are passed to the generated class. 172 * 173 * @param props the configuration properties. 174 * @return CryptoRandom the cryptoRandom object. 175 * @throws GeneralSecurityException if cannot create the {@link CryptoRandom} class 176 * @throws IllegalArgumentException if no classname(s) are provided 177 */ 178 public static CryptoRandom getCryptoRandom(final Properties props) 179 throws GeneralSecurityException { 180 final List<String> names = Utils.splitClassNames(getRandomClassString(props), ","); 181 if (names.isEmpty()) { 182 throw new IllegalArgumentException("No class name(s) provided"); 183 } 184 final StringBuilder errorMessage = new StringBuilder(); 185 CryptoRandom random = null; 186 Exception lastException = null; 187 for (final String klassName : names) { 188 try { 189 final Class<?> klass = ReflectionUtils.getClassByName(klassName); 190 random = (CryptoRandom) ReflectionUtils.newInstance(klass, props); 191 break; 192 } catch (final ClassCastException e) { 193 lastException = e; 194 errorMessage.append("Class: [" + klassName + "] is not a CryptoRandom."); 195 } catch (final ClassNotFoundException e) { 196 lastException = e; 197 errorMessage.append("CryptoRandom: [" + klassName + "] not found."); 198 } catch (final Exception e) { 199 lastException = e; 200 errorMessage.append("CryptoRandom: [" + klassName + "] failed with " + e.getMessage()); 201 } 202 } 203 204 if (random != null) { 205 return random; 206 } 207 throw new GeneralSecurityException(errorMessage.toString(), lastException); 208 } 209 210 /** 211 * Gets the CryptoRandom class. 212 * 213 * @param props The {@code Properties} class represents a set of 214 * properties. 215 * @return the CryptoRandom class based on the props. 216 */ 217 private static String getRandomClassString(final Properties props) { 218 String randomClassString = props.getProperty(CryptoRandomFactory.CLASSES_KEY, CLASSES_DEFAULT); 219 if (randomClassString.isEmpty()) { // TODO does it make sense to treat the empty string as the default? 220 randomClassString = CLASSES_DEFAULT; 221 } 222 return randomClassString; 223 } 224 225 /** 226 * The private constructor of {@link CryptoRandomFactory}. 227 */ 228 private CryptoRandomFactory() { 229 } 230}