Frames | No Frames |
1: /* PBKDF2.java -- 2: Copyright (C) 2003, 2006 Free Software Foundation, Inc. 3: 4: This file is a part of GNU Classpath. 5: 6: GNU Classpath is free software; you can redistribute it and/or modify 7: it under the terms of the GNU General Public License as published by 8: the Free Software Foundation; either version 2 of the License, or (at 9: your option) any later version. 10: 11: GNU Classpath is distributed in the hope that it will be useful, but 12: WITHOUT ANY WARRANTY; without even the implied warranty of 13: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14: General Public License for more details. 15: 16: You should have received a copy of the GNU General Public License 17: along with GNU Classpath; if not, write to the Free Software 18: Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 19: USA 20: 21: Linking this library statically or dynamically with other modules is 22: making a combined work based on this library. Thus, the terms and 23: conditions of the GNU General Public License cover the whole 24: combination. 25: 26: As a special exception, the copyright holders of this library give you 27: permission to link this library with independent modules to produce an 28: executable, regardless of the license terms of these independent 29: modules, and to copy and distribute the resulting executable under 30: terms of your choice, provided that you also meet, for each linked 31: independent module, the terms and conditions of the license of that 32: module. An independent module is a module which is not derived from 33: or based on this library. If you modify this library, you may extend 34: this exception to your version of the library, but you are not 35: obligated to do so. If you do not wish to do so, delete this 36: exception statement from your version. */ 37: 38: 39: package gnu.javax.crypto.prng; 40: 41: import gnu.java.security.prng.BasePRNG; 42: import gnu.java.security.prng.LimitReachedException; 43: import gnu.javax.crypto.mac.HMac; 44: import gnu.javax.crypto.mac.IMac; 45: 46: import java.io.UnsupportedEncodingException; 47: import java.util.Arrays; 48: import java.util.HashMap; 49: import java.util.Map; 50: 51: /** 52: * An implementation of the <i>key derivation function</i> KDF2 from PKCS #5: 53: * Password-Based Cryptography (<b>PBE</b>). This KDF is essentially a way to 54: * transform a password and a salt into a stream of random bytes, which may then 55: * be used to initialize a cipher or a MAC. 56: * <p> 57: * This version uses a MAC as its pseudo-random function, and the password is 58: * used as the key. 59: * <p> 60: * References: 61: * <ol> 62: * <li>B. Kaliski, <a href="http://www.ietf.org/rfc/rfc2898.txt">RFC 2898: 63: * Password-Based Cryptography Specification, Version 2.0</a></li> 64: * </ol> 65: */ 66: public class PBKDF2 67: extends BasePRNG 68: implements Cloneable 69: { 70: /** 71: * The bytes fed into the MAC. This is initially the concatenation of the salt 72: * and the block number. 73: */ 74: private byte[] in; 75: /** The iteration count. */ 76: private int iterationCount; 77: /** The salt. */ 78: private byte[] salt; 79: /** The MAC (the pseudo-random function we use). */ 80: private IMac mac; 81: /** The number of hLen-sized blocks generated. */ 82: private long count; 83: 84: /** 85: * Creates a new PBKDF2 object. The argument is the MAC that will serve as the 86: * pseudo-random function. The MAC does not need to be initialized. 87: * 88: * @param mac The pseudo-random function. 89: */ 90: public PBKDF2(IMac mac) 91: { 92: super("PBKDF2-" + mac.name()); 93: this.mac = mac; 94: iterationCount = -1; 95: } 96: 97: public void setup(Map attributes) 98: { 99: Map macAttrib = new HashMap(); 100: macAttrib.put(HMac.USE_WITH_PKCS5_V2, Boolean.TRUE); 101: byte[] s = (byte[]) attributes.get(IPBE.SALT); 102: if (s == null) 103: { 104: if (salt == null) 105: throw new IllegalArgumentException("no salt specified"); 106: // Otherwise re-use. 107: } 108: else 109: salt = s; 110: byte[] macKeyMaterial; 111: char[] password = (char[]) attributes.get(IPBE.PASSWORD); 112: if (password != null) 113: { 114: String encoding = (String) attributes.get(IPBE.PASSWORD_ENCODING); 115: if (encoding == null || encoding.trim().length() == 0) 116: encoding = IPBE.DEFAULT_PASSWORD_ENCODING; 117: else 118: encoding = encoding.trim(); 119: try 120: { 121: macKeyMaterial = new String(password).getBytes(encoding); 122: } 123: catch (UnsupportedEncodingException uee) 124: { 125: throw new IllegalArgumentException("Unknown or unsupported encoding: " 126: + encoding, uee); 127: } 128: } 129: else 130: macKeyMaterial = (byte[]) attributes.get(IMac.MAC_KEY_MATERIAL); 131: 132: if (macKeyMaterial != null) 133: macAttrib.put(IMac.MAC_KEY_MATERIAL, macKeyMaterial); 134: else if (! initialised) 135: throw new IllegalArgumentException( 136: "Neither password nor key-material were specified"); 137: // otherwise re-use previous password/key-material 138: try 139: { 140: mac.init(macAttrib); 141: } 142: catch (Exception x) 143: { 144: throw new IllegalArgumentException(x.getMessage()); 145: } 146: Integer ic = (Integer) attributes.get(IPBE.ITERATION_COUNT); 147: if (ic != null) 148: iterationCount = ic.intValue(); 149: if (iterationCount <= 0) 150: throw new IllegalArgumentException("bad iteration count"); 151: count = 0L; 152: buffer = new byte[mac.macSize()]; 153: try 154: { 155: fillBlock(); 156: } 157: catch (LimitReachedException x) 158: { 159: throw new Error(x.getMessage()); 160: } 161: } 162: 163: public void fillBlock() throws LimitReachedException 164: { 165: if (++count > ((1L << 32) - 1)) 166: throw new LimitReachedException(); 167: Arrays.fill(buffer, (byte) 0x00); 168: int limit = salt.length; 169: in = new byte[limit + 4]; 170: System.arraycopy(salt, 0, in, 0, salt.length); 171: in[limit++] = (byte)(count >>> 24); 172: in[limit++] = (byte)(count >>> 16); 173: in[limit++] = (byte)(count >>> 8); 174: in[limit ] = (byte) count; 175: for (int i = 0; i < iterationCount; i++) 176: { 177: mac.reset(); 178: mac.update(in, 0, in.length); 179: in = mac.digest(); 180: for (int j = 0; j < buffer.length; j++) 181: buffer[j] ^= in[j]; 182: } 183: } 184: }