001: /*
002: * JBoss, Home of Professional Open Source.
003: * Copyright 2006, Red Hat Middleware LLC, and individual contributors
004: * as indicated by the @author tags. See the copyright.txt file in the
005: * distribution for a full listing of individual contributors.
006: *
007: * This is free software; you can redistribute it and/or modify it
008: * under the terms of the GNU Lesser General Public License as
009: * published by the Free Software Foundation; either version 2.1 of
010: * the License, or (at your option) any later version.
011: *
012: * This software is distributed in the hope that it will be useful,
013: * but WITHOUT ANY WARRANTY; without even the implied warranty of
014: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
015: * Lesser General Public License for more details.
016: *
017: * You should have received a copy of the GNU Lesser General Public
018: * License along with this software; if not, write to the Free
019: * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
020: * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
021: */
022: package org.jboss.security.plugins;
023:
024: import java.io.File;
025: import java.io.IOException;
026: import java.io.RandomAccessFile;
027: import java.io.ByteArrayOutputStream;
028:
029: import javax.crypto.spec.PBEParameterSpec;
030: import javax.crypto.spec.PBEKeySpec;
031: import javax.crypto.Cipher;
032: import javax.crypto.SecretKeyFactory;
033: import javax.crypto.SecretKey;
034:
035: import org.jboss.logging.Logger;
036:
037: /** Read a password in opaque form to a file for use with the FilePassword
038: accessor in conjunction with the JaasSecurityDomain
039: {CLASS}org.jboss.security.plugins.FilePassword:password-file
040: format of the KeyStorePass attribute. The original opaque password file
041: can be created by running:
042: java org.jboss.security.plugins.FilePassword salt count password password-file
043: Running
044: java org.jboss.security.plugins.FilePassword
045: will generate a usage message.
046:
047: Note that this is security by obscurity in that the password is not store
048: in plaintext, but it can be recovered by simply using the code from this
049: class.
050:
051: @see #main(String[])
052:
053: @author Scott.Stark@jboss.org
054: @version $Revison:$
055: */
056: public class FilePassword {
057: private File passwordFile;
058:
059: public FilePassword(String file) {
060: passwordFile = new File(file);
061: }
062:
063: public char[] toCharArray() throws IOException {
064: RandomAccessFile raf = new RandomAccessFile(passwordFile, "rws");
065: try {
066: char[] password = decode(raf);
067: return password;
068: } catch (Exception e) {
069: Logger log = Logger.getLogger(FilePassword.class);
070: log.error(
071: "Failed to decode password file: " + passwordFile,
072: e);
073: throw new IOException(e.getMessage());
074: }
075: }
076:
077: static char[] decode(RandomAccessFile passwordFile)
078: throws Exception {
079: byte[] salt = new byte[8];
080: passwordFile.readFully(salt);
081: int count = passwordFile.readInt();
082: ByteArrayOutputStream baos = new ByteArrayOutputStream();
083: int b;
084: while ((b = passwordFile.read()) >= 0)
085: baos.write(b);
086: passwordFile.close();
087: byte[] secret = baos.toByteArray();
088:
089: PBEParameterSpec cipherSpec = new PBEParameterSpec(salt, count);
090: PBEKeySpec keySpec = new PBEKeySpec(
091: "78aac249a60a13d5e882927928043ebb".toCharArray());
092: SecretKeyFactory factory = SecretKeyFactory
093: .getInstance("PBEwithMD5andDES");
094: SecretKey cipherKey = factory.generateSecret(keySpec);
095: Cipher cipher = Cipher.getInstance("PBEwithMD5andDES");
096: cipher.init(Cipher.DECRYPT_MODE, cipherKey, cipherSpec);
097: byte[] decode = cipher.doFinal(secret);
098: return new String(decode, "UTF-8").toCharArray();
099: }
100:
101: static void encode(RandomAccessFile passwordFile, byte[] salt,
102: int count, byte[] secret) throws Exception {
103: PBEParameterSpec cipherSpec = new PBEParameterSpec(salt, count);
104: PBEKeySpec keySpec = new PBEKeySpec(
105: "78aac249a60a13d5e882927928043ebb".toCharArray());
106: SecretKeyFactory factory = SecretKeyFactory
107: .getInstance("PBEwithMD5andDES");
108: SecretKey cipherKey = factory.generateSecret(keySpec);
109: Cipher cipher = Cipher.getInstance("PBEwithMD5andDES");
110: cipher.init(Cipher.ENCRYPT_MODE, cipherKey, cipherSpec);
111: byte[] encode = cipher.doFinal(secret);
112: passwordFile.write(salt);
113: passwordFile.writeInt(count);
114: passwordFile.write(encode);
115: passwordFile.close();
116:
117: }
118:
119: /** Write a password in opaque form to a file for use with the FilePassword
120: * accessor in conjunction with the JaasSecurityDomain
121: * {CLASS}org.jboss.security.plugins.FilePassword:password-file
122: * format of the KeyStorePass attribute.
123: *
124: * @param args
125: */
126: public static void main(String[] args) throws Exception {
127: if (args.length != 4) {
128: System.err
129: .println("Write a password in opaque form to a file for use with the FilePassword accessor"
130: + "Usage: FilePassword salt count password password-file"
131: + " salt : an 8 char sequence for PBEKeySpec"
132: + " count : iteration count for PBEKeySpec"
133: + " password : the clear text password to write"
134: + " password-file : the path to the file to write the password to");
135: }
136: byte[] salt = args[0].substring(0, 8).getBytes();
137: int count = Integer.parseInt(args[1]);
138: byte[] passwordBytes = args[2].getBytes("UTF-8");
139: RandomAccessFile passwordFile = new RandomAccessFile(args[3],
140: "rws");
141: encode(passwordFile, salt, count, passwordBytes);
142: }
143: }
|