/* * RHQ Management Platform * Copyright (C) 2005-2012 Red Hat, Inc. * All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation version 2 of the License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ package org.rhq.core.util.obfuscation; import java.math.BigInteger; import java.security.InvalidKeyException; import java.security.NoSuchAlgorithmException; import java.util.Random; import javax.crypto.BadPaddingException; import javax.crypto.Cipher; import javax.crypto.IllegalBlockSizeException; import javax.crypto.NoSuchPaddingException; import javax.crypto.spec.SecretKeySpec; /** * This class makes available methods for obfuscating a string in the very same way * as the <code>org.jboss.resource.security.SecureIdentityLoginModule</code> in JBossAS 4.2.3. * <p> * This is to ensure backwards compatibility in case we switch containers that would start * obfuscating the password in a different way and also to make those methods available to * other code. The original methods in the SecureIdentityLoginModule are marked private. * * @author Lukas Krejci */ public final class Obfuscator { private static final byte[] KEY = "jaas is the way".getBytes(); public static final String ALGORITHM = "Blowfish"; //no instances, please private Obfuscator() { } /** * Encodes the secret string so that the value is not immediately readable by * a "casual viewer". * * @param secret the string to encode * @return encoded string * @throws NoSuchPaddingException * @throws NoSuchAlgorithmException * @throws InvalidKeyException * @throws BadPaddingException * @throws IllegalBlockSizeException */ public static String encode(String secret) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException { if (secret == null) { return null; } SecretKeySpec key = new SecretKeySpec(KEY, ALGORITHM); Cipher cipher = Cipher.getInstance(ALGORITHM); cipher.init(Cipher.ENCRYPT_MODE, key); byte[] encoding = cipher.doFinal(secret.getBytes()); BigInteger n = new BigInteger(encoding); return n.toString(16); } /** * Decodes the string obfuscated using the {@link #encode(String)} method back to the * original value. * <p> * This method differs from its original <code>org.jboss.resource.security.SecureIdentityLoginModule#decode</code> * private method in that it returns a String whereas the original method returns a char[]. * * @param secret the encoded (obfuscated) string * @return the decoded string * @throws NoSuchPaddingException * @throws NoSuchAlgorithmException * @throws InvalidKeyException * @throws BadPaddingException * @throws IllegalBlockSizeException */ public static String decode(String secret) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException { if (secret == null) { return null; } SecretKeySpec key = new SecretKeySpec(KEY, ALGORITHM); BigInteger n = new BigInteger(secret, 16); byte[] encoding = n.toByteArray(); //SECURITY-344: fix leading zeros if (encoding.length % 8 != 0) { int length = encoding.length; int newLength = ((length / 8) + 1) * 8; int pad = newLength - length; //number of leading zeros byte[] old = encoding; encoding = new byte[newLength]; for (int i = old.length - 1; i >= 0; i--) { encoding[i + pad] = old[i]; } //SECURITY-563: handle negative numbers if (n.signum() == -1) { for (int i = 0; i < newLength - length; i++) { encoding[i] = (byte) -1; } } } Cipher cipher = Cipher.getInstance(ALGORITHM); cipher.init(Cipher.DECRYPT_MODE, key); byte[] decode = cipher.doFinal(encoding); return new String(decode); } /** * Adapted from http://stackoverflow.com/questions/2863852/how-to-generate-a-random-string-in-java. * <p/> * The default set of validCharacters: 1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ * * @param random * @param validCharacters * @param length * @return */ public static String generateString(Random random, String validCharacters, int length) { validCharacters = (null == validCharacters || validCharacters.isEmpty()) ? "1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" : validCharacters; length = (length < 1) ? 10 : length; char[] text = new char[length]; for (int i = 0; i < length; i++) { text[i] = validCharacters.charAt(random.nextInt(validCharacters.length())); } return new String(text); } }