/** * Licensed to Apereo under one or more contributor license agreements. See the NOTICE file * distributed with this work for additional information regarding copyright ownership. Apereo * licenses this file to you under the Apache License, Version 2.0 (the "License"); you may not use * this file except in compliance with the License. You may obtain a copy of the License at the * following location: * * <p>http://www.apache.org/licenses/LICENSE-2.0 * * <p>Unless required by applicable law or agreed to in writing, software distributed under the * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either * express or implied. See the License for the specific language governing permissions and * limitations under the License. */ package org.apereo.portal.utils; import java.security.SecureRandom; import java.util.Random; /** * Generate random tokens. The default character set is the numbers 2-9 and lower case letters a-z * except i, l and o. This is intended to create a set that avoids numbers and letters which can * easily be confused with others depending on the font in use. * */ public final class RandomTokenGenerator { private static final char[] DEFAULT_TOKEN_CHARS = new char[] { '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'j', 'k', 'm', 'n', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z' }; /** The recommended generator, uses its own instance of {@link SecureRandom} */ public static final RandomTokenGenerator INSTANCE = new RandomTokenGenerator(new SecureRandom()); private final Random random; private final char[] tokenChars; private final double bitsPerChar; /** @param random User defined random source */ public RandomTokenGenerator(Random random) { this(random, DEFAULT_TOKEN_CHARS); } /** * @param random User defined random source * @param tokenChars User defined character set to generate tokens from */ public RandomTokenGenerator(Random random, char[] tokenChars) { this.random = random; this.tokenChars = tokenChars.clone(); this.bitsPerChar = Math.log(tokenChars.length) / Math.log(2); } /** * @param tokenChars User defined character set to generate tokens from, performance will be * better if the length of the array is a power of 2 */ public RandomTokenGenerator(char[] tokenChars) { this(new SecureRandom(), tokenChars); } /** Generate a random token of the specified length */ public String generateRandomToken(int length) { final char[] token = new char[length]; for (int i = 0; i < length; i++) { final int tokenIndex = random.nextInt(this.tokenChars.length); token[i] = tokenChars[tokenIndex]; } return new String(token); } /** Determine the token length required to assure the specified number of bits of randomness */ public int getLengthRequiredForBits(int bits) { final double length = (double) bits / bitsPerChar; return (int) Math.ceil(length); } /** * Determine the number of bits of randomness a token of the specified length would be generated * from */ public double getNumberOfRandomBits(int length) { final double bitsPerToken = bitsPerChar * (double) length; return bitsPerToken; } }