diff options
Diffstat (limited to 'libjava/classpath/gnu/javax/crypto')
273 files changed, 49113 insertions, 0 deletions
diff --git a/libjava/classpath/gnu/javax/crypto/RSACipherImpl.java b/libjava/classpath/gnu/javax/crypto/RSACipherImpl.java new file mode 100644 index 000000000..a4adff007 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/RSACipherImpl.java @@ -0,0 +1,299 @@ +/* RSACipherImpl.java -- + Copyright (C) 2005, 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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; either version 2, or (at your option) +any later version. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto; + +import gnu.classpath.debug.Component; +import gnu.classpath.debug.SystemLogger; +import gnu.java.security.sig.rsa.EME_PKCS1_V1_5; +import gnu.java.security.util.ByteArray; + +import java.math.BigInteger; +import java.security.AlgorithmParameters; +import java.security.InvalidKeyException; +import java.security.Key; +import java.security.NoSuchAlgorithmException; +import java.security.SecureRandom; +import java.security.interfaces.RSAKey; +import java.security.interfaces.RSAPrivateCrtKey; +import java.security.interfaces.RSAPrivateKey; +import java.security.interfaces.RSAPublicKey; +import java.security.spec.AlgorithmParameterSpec; + +import javax.crypto.BadPaddingException; +import javax.crypto.Cipher; +import javax.crypto.CipherSpi; +import javax.crypto.IllegalBlockSizeException; +import javax.crypto.NoSuchPaddingException; +import javax.crypto.ShortBufferException; + +public class RSACipherImpl + extends CipherSpi +{ + private static final SystemLogger logger = SystemLogger.SYSTEM; + + private static final byte[] EMPTY = new byte[0]; + private int opmode = -1; + private RSAPrivateKey decipherKey = null; + private RSAPublicKey blindingKey = null; + private RSAPublicKey encipherKey = null; + private SecureRandom random = null; + private byte[] dataBuffer = null; + private int pos = 0; + + protected void engineSetMode(String mode) throws NoSuchAlgorithmException + { + throw new NoSuchAlgorithmException("only one mode available"); + } + + protected void engineSetPadding(String pad) throws NoSuchPaddingException + { + throw new NoSuchPaddingException("only one padding available"); + } + + protected int engineGetBlockSize() + { + return 1; + } + + protected int engineGetOutputSize(int inputLen) + { + int outputLen = 0; + if (decipherKey != null) + outputLen = (decipherKey.getModulus().bitLength() + 7) / 8; + else if (encipherKey != null) + outputLen = (encipherKey.getModulus().bitLength() + 7) / 8; + else + throw new IllegalStateException("not initialized"); + if (inputLen > outputLen) + throw new IllegalArgumentException("not configured to encode " + inputLen + + "bytes; at most " + outputLen); + return outputLen; + } + + protected int engineGetKeySize(final Key key) throws InvalidKeyException + { + if (! (key instanceof RSAKey)) + throw new InvalidKeyException("not an RSA key"); + return ((RSAKey) key).getModulus().bitLength(); + } + + protected byte[] engineGetIV() + { + return null; + } + + protected AlgorithmParameters engineGetParameters() + { + return null; + } + + protected void engineInit(int opmode, Key key, SecureRandom random) + throws InvalidKeyException + { + int outputLen = 0; + if (opmode == Cipher.ENCRYPT_MODE) + { + if (! (key instanceof RSAPublicKey)) + throw new InvalidKeyException("expecting a RSAPublicKey"); + encipherKey = (RSAPublicKey) key; + decipherKey = null; + blindingKey = null; + outputLen = (encipherKey.getModulus().bitLength() + 7) / 8; + } + else if (opmode == Cipher.DECRYPT_MODE) + { + if (key instanceof RSAPrivateKey) + { + decipherKey = (RSAPrivateKey) key; + encipherKey = null; + blindingKey = null; + outputLen = (decipherKey.getModulus().bitLength() + 7) / 8; + } + else if (key instanceof RSAPublicKey) + { + if (decipherKey == null) + throw new IllegalStateException("must configure decryption key first"); + if (! decipherKey.getModulus().equals(((RSAPublicKey) key).getModulus())) + throw new InvalidKeyException("blinding key is not compatible"); + blindingKey = (RSAPublicKey) key; + return; + } + else + throw new InvalidKeyException( + "expecting either an RSAPrivateKey or an RSAPublicKey (for blinding)"); + } + else + throw new IllegalArgumentException("only encryption and decryption supported"); + this.random = random; + this.opmode = opmode; + pos = 0; + dataBuffer = new byte[outputLen]; + } + + protected void engineInit(int opmode, Key key, AlgorithmParameterSpec spec, + SecureRandom random) throws InvalidKeyException + { + engineInit(opmode, key, random); + } + + protected void engineInit(int opmode, Key key, AlgorithmParameters params, + SecureRandom random) throws InvalidKeyException + { + engineInit(opmode, key, random); + } + + protected byte[] engineUpdate(byte[] in, int offset, int length) + { + if (opmode != Cipher.ENCRYPT_MODE && opmode != Cipher.DECRYPT_MODE) + throw new IllegalStateException("not initialized"); + System.arraycopy(in, offset, dataBuffer, pos, length); + pos += length; + return EMPTY; + } + + protected int engineUpdate(byte[] in, int offset, int length, byte[] out, + int outOffset) + { + engineUpdate(in, offset, length); + return 0; + } + + protected byte[] engineDoFinal(byte[] in, int offset, int length) + throws IllegalBlockSizeException, BadPaddingException + { + engineUpdate(in, offset, length); + if (opmode == Cipher.DECRYPT_MODE) + { + BigInteger enc = new BigInteger (1, dataBuffer); + byte[] dec = rsaDecrypt (enc); + logger.log (Component.CRYPTO, "RSA: decryption produced\n{0}", + new ByteArray (dec)); + EME_PKCS1_V1_5 pkcs = EME_PKCS1_V1_5.getInstance(decipherKey); + byte[] result = pkcs.decode(dec); + return result; + } + else + { + offset = dataBuffer.length - pos; + if (offset < 3) + throw new IllegalBlockSizeException("input is too large to encrypt"); + EME_PKCS1_V1_5 pkcs = EME_PKCS1_V1_5.getInstance(encipherKey); + if (random == null) + random = new SecureRandom(); + byte[] em = new byte[pos]; + System.arraycopy(dataBuffer, 0, em, 0, pos); + byte[] dec = pkcs.encode(em, random); + logger.log (Component.CRYPTO, "RSA: produced padded plaintext\n{0}", + new ByteArray (dec)); + BigInteger x = new BigInteger (1, dec); + BigInteger y = x.modPow (encipherKey.getPublicExponent (), + encipherKey.getModulus ()); + byte[] enc = y.toByteArray (); + if (enc[0] == 0x00) + { + byte[] tmp = new byte[enc.length - 1]; + System.arraycopy(enc, 1, tmp, 0, tmp.length); + enc = tmp; + } + pos = 0; + return enc; + } + } + + protected int engineDoFinal(byte[] out, int offset) + throws ShortBufferException, IllegalBlockSizeException, + BadPaddingException + { + byte[] result = engineDoFinal(EMPTY, 0, 0); + if (out.length - offset < result.length) + throw new ShortBufferException("need " + result.length + ", have " + + (out.length - offset)); + System.arraycopy(result, 0, out, offset, result.length); + return result.length; + } + + protected int engineDoFinal(final byte[] input, final int offset, + final int length, final byte[] output, + final int outputOffset) + throws ShortBufferException, IllegalBlockSizeException, + BadPaddingException + { + byte[] result = engineDoFinal(input, offset, length); + if (output.length - outputOffset < result.length) + throw new ShortBufferException("need " + result.length + ", have " + + (output.length - outputOffset)); + System.arraycopy(result, 0, output, outputOffset, result.length); + return result.length; + } + + /** + * Decrypts the ciphertext, employing RSA blinding if possible. + */ + private byte[] rsaDecrypt(BigInteger enc) + { + if (random == null) + random = new SecureRandom(); + BigInteger n = decipherKey.getModulus(); + BigInteger r = null; + BigInteger pubExp = null; + if (blindingKey != null) + pubExp = blindingKey.getPublicExponent(); + if (pubExp != null && (decipherKey instanceof RSAPrivateCrtKey)) + pubExp = ((RSAPrivateCrtKey) decipherKey).getPublicExponent(); + if (pubExp != null) + { + r = new BigInteger(n.bitLength() - 1, random); + enc = r.modPow(pubExp, n).multiply(enc).mod(n); + } + BigInteger dec = enc.modPow(decipherKey.getPrivateExponent(), n); + if (pubExp != null) + { + dec = dec.multiply (r.modInverse (n)).mod (n); + } + + byte[] decb = dec.toByteArray(); + if (decb[0] != 0x00) + { + byte[] b = new byte[decb.length + 1]; + System.arraycopy(decb, 0, b, 1, decb.length); + decb = b; + } + return decb; + } +} diff --git a/libjava/classpath/gnu/javax/crypto/assembly/Assembly.java b/libjava/classpath/gnu/javax/crypto/assembly/Assembly.java new file mode 100644 index 000000000..f570d2012 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/assembly/Assembly.java @@ -0,0 +1,272 @@ +/* Assembly.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.assembly; + +import java.util.Map; + +/** + * An <code>Assembly</code> is a construction consisting of a chain of + * {@link Transformer} elements; each wired in pre- or post- transformation + * mode. This chain is terminated by one <code>LoopbackTransformer</code> + * element. + * <p> + * Once constructed, and correctly initialised, the bulk of the methods + * available on the <code>Assembly</code> are delegated to the <i>head</i> of + * the {@link Transformer} chain of the <code>Assembly</code>. + * + * @see Transformer + */ +public class Assembly +{ + public static final String DIRECTION = "gnu.crypto.assembly.assembly.direction"; + + /** Flag that tells if the instance is initialised or not; and if yes how. */ + private Direction wired; + + /** The first Transformer in the chain. */ + private Transformer head; + + /** + * Trivial constructor that sets the <i>chain</i> to a + * <code>LoopbackTransformer</code>. + */ + public Assembly() + { + super(); + + wired = null; + head = new LoopbackTransformer(); + } + + /** + * Adds the designated {@link Transformer} and signals that it should operate + * in pre-processing mode; i.e. it should apply its internal transformation + * algorithm on the input data stream, <b>before</b> it passes that stream to + * the next element in the <i>chain</i>. + * + * @param t the {@link Transformer} to add at the head of the current chain. + * @throws IllegalArgumentException if the designated {@link Transformer} has + * a non-null tail; i.e. it is already an element of a chain. + */ + public void addPreTransformer(Transformer t) + { + wireTransformer(t, Operation.PRE_PROCESSING); + } + + /** + * Adds the designated {@link Transformer} and signals that it should operate + * in post-processing mode; i.e. it should apply its internal transformation + * algorithm on the input data stream, <b>after</b> it passes that stream to + * the next element in the <i>chain</i>. + * + * @param t the {@link Transformer} to add at the head of the current chain. + * @throws IllegalArgumentException if the designated {@link Transformer} has + * a non-null tail; i.e. it is already an element of a chain. + */ + public void addPostTransformer(Transformer t) + { + wireTransformer(t, Operation.POST_PROCESSING); + } + + /** + * Initialises the <code>Assembly</code> for operation with specific + * characteristics. + * + * @param attributes a set of name-value pairs that describes the desired + * future behaviour of this instance. + * @throws IllegalStateException if the instance is already initialised. + */ + public void init(Map attributes) throws TransformerException + { + if (wired != null) + throw new IllegalStateException(); + Direction flow = (Direction) attributes.get(DIRECTION); + if (flow == null) + flow = Direction.FORWARD; + attributes.put(Transformer.DIRECTION, flow); + head.init(attributes); + wired = flow; + } + + /** + * Resets the <code>Assembly</code> for re-initialisation and use with other + * characteristics. This method always succeeds. + */ + public void reset() + { + head.reset(); + wired = null; + } + + /** + * Convenience method that calls the method with same name and three + * arguments, using a byte array of length <code>1</code> whose contents are + * the designated byte. + * + * @param b the byte to process. + * @return the result of transformation. + * @throws IllegalStateException if the instance is not initialised. + * @throws TransformerException if a transformation-related exception occurs + * during the operation. + * @see #update(byte[], int, int) + */ + public byte[] update(byte b) throws TransformerException + { + return update(new byte[] { b }, 0, 1); + } + + /** + * Convenience method that calls the method with same name and three + * arguments. All bytes in <code>in</code>, starting from index position + * <code>0</code> are considered. + * + * @param in the input data bytes. + * @return the result of transformation. + * @throws IllegalStateException if the instance is not initialised. + * @throws TransformerException if a transformation-related exception occurs + * during the operation. + * @see #update(byte[], int, int) + */ + public byte[] update(byte[] in) throws TransformerException + { + return update(in, 0, in.length); + } + + /** + * Processes a designated number of bytes from a given byte array. + * + * @param in the input data bytes. + * @param offset index of <code>in</code> from which to start considering + * data. + * @param length the count of bytes to process. + * @return the result of transformation. + * @throws IllegalStateException if the instance is not initialised. + * @throws TransformerException if a transformation-related exception occurs + * during the operation. + */ + public byte[] update(byte[] in, int offset, int length) + throws TransformerException + { + if (wired == null) + throw new IllegalStateException(); + return head.update(in, offset, length); + } + + /** + * Convenience method that calls the method with same name and three arguments + * using a 0-long byte array. + * + * @return the result of transformation. + * @throws IllegalStateException if the instance is not initialised. + * @throws TransformerException if a transformation-related exception occurs + * during the operation. + * @see #lastUpdate(byte[], int, int) + */ + public byte[] lastUpdate() throws TransformerException + { + return lastUpdate(new byte[0], 0, 0); + } + + /** + * Convenience method that calls the method with same name and three + * arguments, using a byte array of length <code>1</code> whose contents are + * the designated byte. + * + * @param b the byte to process. + * @return the result of transformation. + * @throws IllegalStateException if the instance is not initialised. + * @throws TransformerException if a transformation-related exception occurs + * during the operation. + * @see #lastUpdate(byte[], int, int) + */ + public byte[] lastUpdate(byte b) throws TransformerException + { + return lastUpdate(new byte[] { b }, 0, 1); + } + + /** + * Convenience method that calls the method with same name and three + * arguments. All bytes in <code>in</code>, starting from index position + * <code>0</code> are considered. + * + * @param in the input data bytes. + * @return the result of transformation. + * @throws IllegalStateException if the instance is not initialised. + * @throws TransformerException if a transformation-related exception occurs + * during the operation. + * @see #lastUpdate(byte[], int, int) + */ + public byte[] lastUpdate(byte[] in) throws TransformerException + { + return lastUpdate(in, 0, in.length); + } + + /** + * Processes a designated number of bytes from a given byte array and signals, + * at the same time, that this is the last <i>push</i> operation for this + * <code>Assembly</code>. + * + * @param in the input data bytes. + * @param offset index of <code>in</code> from which to start considering + * data. + * @param length the count of bytes to process. + * @return the result of transformation. + * @throws IllegalStateException if the instance is not initialised. + * @throws TransformerException if a transformation-related exception occurs + * during the operation. + */ + public byte[] lastUpdate(byte[] in, int offset, int length) + throws TransformerException + { + if (wired == null) + throw new IllegalStateException(); + byte[] result = head.lastUpdate(in, offset, length); + reset(); + return result; + } + + private void wireTransformer(Transformer t, Operation mode) + { + if (t.tail != null) + throw new IllegalArgumentException(); + t.setMode(mode); + t.tail = head; + head = t; + } +} diff --git a/libjava/classpath/gnu/javax/crypto/assembly/Cascade.java b/libjava/classpath/gnu/javax/crypto/assembly/Cascade.java new file mode 100644 index 000000000..685cef5b2 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/assembly/Cascade.java @@ -0,0 +1,348 @@ +/* Cascade.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.assembly; + +import java.math.BigInteger; +import java.security.InvalidKeyException; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.Map; +import java.util.Set; + +/** + * A <i>Cascade</i> Cipher is the concatenation of two or more block ciphers + * each with independent keys. Plaintext is input to the first stage; the output + * of stage <code>i</code> is input to stage <code>i + 1</code>; and the + * output of the last stage is the <i>Cascade</i>'s ciphertext output. + * <p> + * In the simplest case, all stages in a <code>Cascade</code> have <i>k</i>-bit + * keys, and the stage inputs and outputs are all n-bit quantities. The stage + * ciphers may differ (general cascade of ciphers), or all be identical (cascade + * of identical ciphers). + * <p> + * The term "block ciphers" used above refers to implementations of + * {@link gnu.javax.crypto.mode.IMode}, including the + * {@link gnu.javax.crypto.mode.ECB} mode which basically exposes a + * symmetric-key block cipher algorithm as a <i>Mode</i> of Operations. + * <p> + * References: + * <ol> + * <li><a href="http://www.cacr.math.uwaterloo.ca/hac">[HAC]</a>: Handbook of + * Applied Cryptography.<br> + * CRC Press, Inc. ISBN 0-8493-8523-7, 1997<br> + * Menezes, A., van Oorschot, P. and S. Vanstone.</li> + * </ol> + */ +public class Cascade +{ + public static final String DIRECTION = "gnu.crypto.assembly.cascade.direction"; + + /** The map of Stages chained in this cascade. */ + protected HashMap stages; + + /** The ordered list of Stage UIDs to their attribute maps. */ + protected LinkedList stageKeys; + + /** The current operational direction of this instance. */ + protected Direction wired; + + /** The curently set block-size for this instance. */ + protected int blockSize; + + public Cascade() + { + super(); + + stages = new HashMap(3); + stageKeys = new LinkedList(); + wired = null; + blockSize = 0; + } + + /** + * Returns the Least Common Multiple of two integers. + * + * @param a the first integer. + * @param b the second integer. + * @return the LCM of <code>abs(a)</code> and <code>abs(b)</code>. + */ + private static final int lcm(int a, int b) + { + BigInteger A = BigInteger.valueOf(a * 1L); + BigInteger B = BigInteger.valueOf(b * 1L); + return A.multiply(B).divide(A.gcd(B)).abs().intValue(); + } + + /** + * Adds to the end of the current chain, a designated {@link Stage}. + * + * @param stage the {@link Stage} to append to the chain. + * @return a unique identifier for this stage, within this cascade. + * @throws IllegalStateException if the instance is already initialised. + * @throws IllegalArgumentException if the designated stage is already in the + * chain, or it has incompatible characteristics with the current + * elements already in the chain. + */ + public Object append(Stage stage) throws IllegalArgumentException + { + return insert(size(), stage); + } + + /** + * Adds to the begining of the current chain, a designated {@link Stage}. + * + * @param stage the {@link Stage} to prepend to the chain. + * @return a unique identifier for this stage, within this cascade. + * @throws IllegalStateException if the instance is already initialised. + * @throws IllegalArgumentException if the designated stage is already in the + * chain, or it has incompatible characteristics with the current + * elements already in the chain. + */ + public Object prepend(Stage stage) throws IllegalArgumentException + { + return insert(0, stage); + } + + /** + * Inserts a {@link Stage} into the current chain, at the specified index + * (zero-based) position. + * + * @param stage the {@link Stage} to insert into the chain. + * @return a unique identifier for this stage, within this cascade. + * @throws IllegalArgumentException if the designated stage is already in the + * chain, or it has incompatible characteristics with the current + * elements already in the chain. + * @throws IllegalStateException if the instance is already initialised. + * @throws IndexOutOfBoundsException if <code>index</code> is less than + * <code>0</code> or greater than the current size of this + * cascade. + */ + public Object insert(int index, Stage stage) throws IllegalArgumentException, + IndexOutOfBoundsException + { + if (stages.containsValue(stage)) + throw new IllegalArgumentException(); + if (wired != null || stage == null) + throw new IllegalStateException(); + if (index < 0 || index > size()) + throw new IndexOutOfBoundsException(); + // check that there is a non-empty set of common block-sizes + Set set = stage.blockSizes(); + if (stages.isEmpty()) + { + if (set.isEmpty()) + throw new IllegalArgumentException("1st stage with no block sizes"); + } + else + { + Set common = this.blockSizes(); + common.retainAll(set); + if (common.isEmpty()) + throw new IllegalArgumentException("no common block sizes found"); + } + Object result = new Object(); + stageKeys.add(index, result); + stages.put(result, stage); + return result; + } + + /** + * Returns the current number of stages in this chain. + * + * @return the current count of stages in this chain. + */ + public int size() + { + return stages.size(); + } + + /** + * Returns an {@link Iterator} over the stages contained in this instance. + * Each element of this iterator is a concrete implementation of a {@link + * Stage}. + * + * @return an {@link Iterator} over the stages contained in this instance. + * Each element of the returned iterator is a concrete instance of a + * {@link Stage}. + */ + public Iterator stages() + { + LinkedList result = new LinkedList(); + for (Iterator it = stageKeys.listIterator(); it.hasNext();) + result.addLast(stages.get(it.next())); + return result.listIterator(); + } + + /** + * Returns the {@link Set} of supported block sizes for this + * <code>Cascade</code> that are common to all of its chained stages. Each + * element in the returned {@link Set} is an instance of {@link Integer}. + * + * @return a {@link Set} of supported block sizes common to all the stages of + * the chain. + */ + public Set blockSizes() + { + HashSet result = null; + for (Iterator it = stages.values().iterator(); it.hasNext();) + { + Stage aStage = (Stage) it.next(); + if (result == null) // first time + result = new HashSet(aStage.blockSizes()); + else + result.retainAll(aStage.blockSizes()); + } + return result == null ? Collections.EMPTY_SET : result; + } + + /** + * Initialises the chain for operation with specific characteristics. + * + * @param attributes a set of name-value pairs that describes the desired + * future behaviour of this instance. + * @throws IllegalStateException if the chain, or any of its stages, is + * already initialised. + * @throws InvalidKeyException if the intialisation data provided with the + * stage is incorrect or causes an invalid key to be generated. + * @see Direction#FORWARD + * @see Direction#REVERSED + */ + public void init(Map attributes) throws InvalidKeyException + { + if (wired != null) + throw new IllegalStateException(); + Direction flow = (Direction) attributes.get(DIRECTION); + if (flow == null) + flow = Direction.FORWARD; + int optimalSize = 0; + for (Iterator it = stageKeys.listIterator(); it.hasNext();) + { + Object id = it.next(); + Map attr = (Map) attributes.get(id); + attr.put(Stage.DIRECTION, flow); + Stage stage = (Stage) stages.get(id); + stage.init(attr); + optimalSize = optimalSize == 0 ? stage.currentBlockSize() + : lcm(optimalSize, + stage.currentBlockSize()); + } + if (flow == Direction.REVERSED) // reverse order + Collections.reverse(stageKeys); + wired = flow; + blockSize = optimalSize; + } + + /** + * Returns the currently set block size for the chain. + * + * @return the current block size for the chain. + * @throws IllegalStateException if the instance is not initialised. + */ + public int currentBlockSize() + { + if (wired == null) + throw new IllegalStateException(); + return blockSize; + } + + /** + * Resets the chain for re-initialisation and use with other characteristics. + * This method always succeeds. + */ + public void reset() + { + for (Iterator it = stageKeys.listIterator(); it.hasNext();) + ((Stage) stages.get(it.next())).reset(); + if (wired == Direction.REVERSED) // reverse it back + Collections.reverse(stageKeys); + wired = null; + blockSize = 0; + } + + /** + * Processes exactly one block of <i>plaintext</i> (if initialised in the + * {@link Direction#FORWARD} state) or <i>ciphertext</i> (if initialised in + * the {@link Direction#REVERSED} state). + * + * @param in the plaintext. + * @param inOffset index of <code>in</code> from which to start considering + * data. + * @param out the ciphertext. + * @param outOffset index of <code>out</code> from which to store result. + * @throws IllegalStateException if the instance is not initialised. + */ + public void update(byte[] in, int inOffset, byte[] out, int outOffset) + { + if (wired == null) + throw new IllegalStateException(); + int stageBlockSize, j, i = stages.size(); + for (Iterator it = stageKeys.listIterator(); it.hasNext();) + { + Stage stage = (Stage) stages.get(it.next()); + stageBlockSize = stage.currentBlockSize(); + for (j = 0; j < blockSize; j += stageBlockSize) + stage.update(in, inOffset + j, out, outOffset + j); + i--; + if (i > 0) + System.arraycopy(out, outOffset, in, inOffset, blockSize); + } + } + + /** + * Conducts a simple <i>correctness</i> test that consists of basic symmetric + * encryption / decryption test(s) for all supported block and key sizes of + * underlying block cipher(s) wrapped by Mode leafs. The test also includes + * one (1) variable key Known Answer Test (KAT) for each block cipher. + * + * @return <code>true</code> if the implementation passes simple + * <i>correctness</i> tests. Returns <code>false</code> otherwise. + */ + public boolean selfTest() + { + for (Iterator it = stageKeys.listIterator(); it.hasNext();) + { + if (! ((Stage) stages.get(it.next())).selfTest()) + return false; + } + return true; + } +} diff --git a/libjava/classpath/gnu/javax/crypto/assembly/CascadeStage.java b/libjava/classpath/gnu/javax/crypto/assembly/CascadeStage.java new file mode 100644 index 000000000..196edafdf --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/assembly/CascadeStage.java @@ -0,0 +1,93 @@ +/* CascadeStage.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.assembly; + +import java.security.InvalidKeyException; +import java.util.Collections; +import java.util.Map; +import java.util.Set; + +/** + * A Cascade <i>Stage</i> in a Cascade Cipher. + */ +class CascadeStage + extends Stage +{ + private Cascade delegate; + + CascadeStage(Cascade cascade, Direction forwardDirection) + { + super(forwardDirection); + + this.delegate = cascade; + } + + public Set blockSizes() + { + return Collections.unmodifiableSet(delegate.blockSizes()); + } + + void initDelegate(Map attributes) throws InvalidKeyException + { + Direction flow = (Direction) attributes.get(DIRECTION); + attributes.put(DIRECTION, flow.equals(forward) ? forward + : Direction.reverse(forward)); + delegate.init(attributes); + } + + public int currentBlockSize() throws IllegalStateException + { + return delegate.currentBlockSize(); + } + + void resetDelegate() + { + delegate.reset(); + } + + void updateDelegate(byte[] in, int inOffset, byte[] out, int outOffset) + { + delegate.update(in, inOffset, out, outOffset); + } + + public boolean selfTest() + { + return delegate.selfTest(); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/assembly/CascadeTransformer.java b/libjava/classpath/gnu/javax/crypto/assembly/CascadeTransformer.java new file mode 100644 index 000000000..8e3a9a5a1 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/assembly/CascadeTransformer.java @@ -0,0 +1,123 @@ +/* CascadeTransformer.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.assembly; + +import java.security.InvalidKeyException; +import java.util.Map; + +/** + * An Adapter to use any {@link Cascade} as a {@link Transformer} in an + * {@link Assembly}. + */ +class CascadeTransformer + extends Transformer +{ + private Cascade delegate; + + private int blockSize; + + CascadeTransformer(Cascade delegate) + { + super(); + + this.delegate = delegate; + } + + void initDelegate(Map attributes) throws TransformerException + { + attributes.put(Cascade.DIRECTION, wired); + try + { + delegate.init(attributes); + } + catch (InvalidKeyException x) + { + throw new TransformerException("initDelegate()", x); + } + blockSize = delegate.currentBlockSize(); + } + + int delegateBlockSize() + { + return blockSize; + } + + void resetDelegate() + { + delegate.reset(); + blockSize = 0; + } + + byte[] updateDelegate(byte[] in, int offset, int length) + throws TransformerException + { + byte[] result = updateInternal(in, offset, length); + return result; + } + + byte[] lastUpdateDelegate() throws TransformerException + { + if (inBuffer.size() != 0) + { + IllegalStateException cause = new IllegalStateException( + "Cascade transformer, after last update, must be empty but isn't"); + throw new TransformerException("lastUpdateDelegate()", cause); + } + return new byte[0]; + } + + private byte[] updateInternal(byte[] in, int offset, int length) + { + byte[] result; + for (int i = 0; i < length; i++) + { + inBuffer.write(in[offset++] & 0xFF); + if (inBuffer.size() >= blockSize) + { + result = inBuffer.toByteArray(); + inBuffer.reset(); + delegate.update(result, 0, result, 0); + outBuffer.write(result, 0, blockSize); + } + } + result = outBuffer.toByteArray(); + outBuffer.reset(); + return result; + } +} diff --git a/libjava/classpath/gnu/javax/crypto/assembly/DeflateTransformer.java b/libjava/classpath/gnu/javax/crypto/assembly/DeflateTransformer.java new file mode 100644 index 000000000..97f9f0365 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/assembly/DeflateTransformer.java @@ -0,0 +1,177 @@ +/* DeflateTransformer.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.assembly; + +import java.util.Map; +import java.util.zip.DataFormatException; +import java.util.zip.Deflater; +import java.util.zip.Inflater; + +/** + * A {@link Transformer} Adapter allowing inclusion of a DEFLATE compression + * algorithm in an {@link Assembly} chain. The {@link Direction#FORWARD} + * transformation is a compression (deflate) of input data, while the + * {@link Direction#REVERSED} one is a decompression (inflate) that restores the + * original data. + * <p> + * This {@link Transformer} uses a {@link Deflater} instance to carry on the + * compression, and an {@link Inflater} to do the decompression. + * <p> + * When using such a {@link Transformer}, in an {@link Assembly}, there must + * be at least one element behind this instance in the constructed chain; + * otherwise, a {@link TransformerException} is thrown at initialisation time. + */ +class DeflateTransformer + extends Transformer +{ + private Deflater compressor; + + private Inflater decompressor; + + private int outputBlockSize = 512; // default zlib buffer size + + private byte[] zlibBuffer; + + DeflateTransformer() + { + super(); + + } + + void initDelegate(Map attributes) throws TransformerException + { + if (tail == null) + { + IllegalStateException cause = new IllegalStateException( + "Compression transformer missing its tail!"); + throw new TransformerException("initDelegate()", cause); + } + outputBlockSize = tail.currentBlockSize(); + zlibBuffer = new byte[outputBlockSize]; + Direction flow = (Direction) attributes.get(DIRECTION); + if (flow == Direction.FORWARD) + compressor = new Deflater(); + else + decompressor = new Inflater(); + } + + int delegateBlockSize() + { + return 1; + } + + void resetDelegate() + { + compressor = null; + decompressor = null; + outputBlockSize = 1; + zlibBuffer = null; + } + + byte[] updateDelegate(byte[] in, int offset, int length) + throws TransformerException + { + byte[] result; + if (wired == Direction.FORWARD) + { + compressor.setInput(in, offset, length); + while (! compressor.needsInput()) + compress(); + } + else // decompression: inflate first and then update tail + decompress(in, offset, length); + result = inBuffer.toByteArray(); + inBuffer.reset(); + return result; + } + + byte[] lastUpdateDelegate() throws TransformerException + { + // process multiples of blocksize as much as possible + if (wired == Direction.FORWARD) // compressing + { + if (! compressor.finished()) + { + compressor.finish(); + while (! compressor.finished()) + compress(); + } + } + else // decompressing + { + if (! decompressor.finished()) + { + IllegalStateException cause = new IllegalStateException( + "Compression transformer, after last update, must be finished " + + "but isn't"); + throw new TransformerException("lastUpdateDelegate()", cause); + } + } + byte[] result = inBuffer.toByteArray(); + inBuffer.reset(); + return result; + } + + private void compress() + { + int len = compressor.deflate(zlibBuffer); + if (len > 0) + inBuffer.write(zlibBuffer, 0, len); + } + + private void decompress(byte[] in, int offset, int length) + throws TransformerException + { + decompressor.setInput(in, offset, length); + int len = 1; + while (len > 0) + { + try + { + len = decompressor.inflate(zlibBuffer); + } + catch (DataFormatException x) + { + throw new TransformerException("decompress()", x); + } + if (len > 0) + inBuffer.write(zlibBuffer, 0, len); + } + } +} diff --git a/libjava/classpath/gnu/javax/crypto/assembly/Direction.java b/libjava/classpath/gnu/javax/crypto/assembly/Direction.java new file mode 100644 index 000000000..40ddfc429 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/assembly/Direction.java @@ -0,0 +1,78 @@ +/* Direction.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.assembly; + +/** + * An enumeration type for wiring {@link Stage} instances into {@link Cascade} + * Cipher chains, as well as for operating a {@link Cascade} in a given + * direction. + * <p> + * The possible values for this type are two: + * <ol> + * <li>FORWARD: equivalent to {@link gnu.javax.crypto.mode.IMode#ENCRYPTION}, + * and its inverse value</li> + * <li>REVERSED: equivalent to {@link gnu.javax.crypto.mode.IMode#DECRYPTION}. + * </li> + * </ol> + */ +public final class Direction +{ + public static final Direction FORWARD = new Direction(1); + + public static final Direction REVERSED = new Direction(2); + + private int value; + + private Direction(int value) + { + super(); + + this.value = value; + } + + public static final Direction reverse(Direction d) + { + return (d.equals(FORWARD) ? REVERSED : FORWARD); + } + + public String toString() + { + return (this == FORWARD ? "forward" : "reversed"); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/assembly/LoopbackTransformer.java b/libjava/classpath/gnu/javax/crypto/assembly/LoopbackTransformer.java new file mode 100644 index 000000000..5bcfe5ffc --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/assembly/LoopbackTransformer.java @@ -0,0 +1,100 @@ +/* LoopbackTransformer.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.assembly; + +import java.util.Map; + +/** + * A trivial {@link Transformer} to allow closing a chain in an {@link Assembly}. + * This class is not visible outside this package. + */ +final class LoopbackTransformer + extends Transformer +{ + /** Trivial package-private constructor. */ + LoopbackTransformer() + { + super(); + } + + public void init(Map attributes) throws TransformerException + { + } + + public void reset() + { + } + + public byte[] update(byte[] in, int offset, int length) + throws TransformerException + { + return updateDelegate(in, offset, length); + } + + public byte[] lastUpdate() throws TransformerException + { + return lastUpdateDelegate(); + } + + void initDelegate(Map attributes) throws TransformerException + { + } + + int delegateBlockSize() + { + return 1; + } + + void resetDelegate() + { + } + + byte[] updateDelegate(byte[] in, int offset, int length) + throws TransformerException + { + byte[] result = new byte[length]; + System.arraycopy(in, offset, result, 0, length); + return result; + } + + byte[] lastUpdateDelegate() throws TransformerException + { + return new byte[0]; + } +} diff --git a/libjava/classpath/gnu/javax/crypto/assembly/ModeStage.java b/libjava/classpath/gnu/javax/crypto/assembly/ModeStage.java new file mode 100644 index 000000000..8bdbef7c4 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/assembly/ModeStage.java @@ -0,0 +1,112 @@ +/* ModeStage.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.assembly; + +import gnu.javax.crypto.mode.IMode; + +import java.security.InvalidKeyException; +import java.util.Collections; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Map; +import java.util.Set; + +/** + * An {@link IMode} {@link Stage} in a {@link Cascade} Cipher chain. + * <p> + * Such a stage wraps an implementation of a Block Cipher Mode of Operation + * ({@link IMode}) to allow inclusion of such an instance in a cascade of block + * ciphers. + */ +class ModeStage + extends Stage +{ + private IMode delegate; + + private transient Set cachedBlockSizes; + + ModeStage(IMode mode, Direction forwardDirection) + { + super(forwardDirection); + + delegate = mode; + cachedBlockSizes = null; + } + + public Set blockSizes() + { + if (cachedBlockSizes == null) + { + HashSet result = new HashSet(); + for (Iterator it = delegate.blockSizes(); it.hasNext();) + result.add(it.next()); + cachedBlockSizes = Collections.unmodifiableSet(result); + } + return cachedBlockSizes; + } + + void initDelegate(Map attributes) throws InvalidKeyException + { + Direction flow = (Direction) attributes.get(DIRECTION); + attributes.put(IMode.STATE, + Integer.valueOf(flow.equals(forward) ? IMode.ENCRYPTION + : IMode.DECRYPTION)); + delegate.init(attributes); + } + + public int currentBlockSize() throws IllegalStateException + { + return delegate.currentBlockSize(); + } + + void resetDelegate() + { + delegate.reset(); + } + + void updateDelegate(byte[] in, int inOffset, byte[] out, int outOffset) + { + delegate.update(in, inOffset, out, outOffset); + } + + public boolean selfTest() + { + return delegate.selfTest(); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/assembly/Operation.java b/libjava/classpath/gnu/javax/crypto/assembly/Operation.java new file mode 100644 index 000000000..6861a1377 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/assembly/Operation.java @@ -0,0 +1,73 @@ +/* Operation.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.assembly; + +/** + * An enumeration type for specifying the operation type of a + * {@link Transformer}. + * <p> + * The possible values for this type are two: + * <ol> + * <li>PRE_PROCESSING: where the input data is first processed by the current + * {@link Transformer} before being passed to the rest of the chain; and</li> + * <li>POST_PROCESSING: where the input data is first passed to the rest of the + * chain, and the resulting bytes are then processed by the current + * {@link Transformer}.</li> + * </ol> + */ +public final class Operation +{ + public static final Operation PRE_PROCESSING = new Operation(1); + + public static final Operation POST_PROCESSING = new Operation(2); + + private int value; + + private Operation(int value) + { + super(); + + this.value = value; + } + + public String toString() + { + return (this == PRE_PROCESSING ? "pre-processing" : "post-processing"); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/assembly/PaddingTransformer.java b/libjava/classpath/gnu/javax/crypto/assembly/PaddingTransformer.java new file mode 100644 index 000000000..494ca34ca --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/assembly/PaddingTransformer.java @@ -0,0 +1,164 @@ +/* PaddingTransformer.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.assembly; + +import gnu.javax.crypto.pad.IPad; +import gnu.javax.crypto.pad.WrongPaddingException; + +import java.util.Map; + +/** + * An Adapter to use any {@link IPad} as a {@link Transformer} in an + * {@link Assembly}. + * <p> + * When using such a {@link Transformer}, in an {@link Assembly}, there must + * be at least one element behind this instance in the constructed chain; + * otherwise, a {@link TransformerException} is thrown at initialisation time. + */ +class PaddingTransformer + extends Transformer +{ + private IPad delegate; + + private int outputBlockSize = 1; + + PaddingTransformer(IPad padding) + { + super(); + + this.delegate = padding; + } + + void initDelegate(Map attributes) throws TransformerException + { + if (tail == null) + { + IllegalStateException cause = new IllegalStateException( + "Padding transformer missing its tail!"); + throw new TransformerException("initDelegate()", cause); + } + outputBlockSize = tail.currentBlockSize(); + delegate.init(outputBlockSize); + } + + int delegateBlockSize() + { + return outputBlockSize; + } + + void resetDelegate() + { + delegate.reset(); + outputBlockSize = 1; + } + + byte[] updateDelegate(byte[] in, int offset, int length) + throws TransformerException + { + inBuffer.write(in, offset, length); + byte[] tmp = inBuffer.toByteArray(); + inBuffer.reset(); + byte[] result; + if (wired == Direction.FORWARD) // padding + { + // buffers remaining bytes from (inBuffer + in) that are less than 1 + // block + if (tmp.length < outputBlockSize) + { + inBuffer.write(tmp, 0, tmp.length); + result = new byte[0]; + } + else + { + int newlen = outputBlockSize * (tmp.length / outputBlockSize); + inBuffer.write(tmp, newlen, tmp.length - newlen); + result = new byte[newlen]; + System.arraycopy(tmp, 0, result, 0, newlen); + } + } + else // unpadding + { + // always keep in own buffer a max of 1 block to cater for lastUpdate + if (tmp.length < outputBlockSize) + { + inBuffer.write(tmp, 0, tmp.length); + result = new byte[0]; + } + else + { + result = new byte[tmp.length - outputBlockSize]; + System.arraycopy(tmp, 0, result, 0, result.length); + inBuffer.write(tmp, result.length, outputBlockSize); + } + } + return result; + } + + byte[] lastUpdateDelegate() throws TransformerException + { + byte[] result; + // process multiples of blocksize as much as possible + // catenate result from processing inBuffer with last-update( tail ) + if (wired == Direction.FORWARD) // padding + { + result = inBuffer.toByteArray(); + byte[] padding = delegate.pad(result, 0, result.length); + inBuffer.write(padding, 0, padding.length); + } + else // unpadding + { + byte[] tmp = inBuffer.toByteArray(); + inBuffer.reset(); + int realLength; + try + { + realLength = tmp.length; // should be outputBlockSize + realLength -= delegate.unpad(tmp, 0, tmp.length); + } + catch (WrongPaddingException x) + { + throw new TransformerException("lastUpdateDelegate()", x); + } + inBuffer.write(tmp, 0, realLength); + } + result = inBuffer.toByteArray(); + inBuffer.reset(); + return result; + } +} diff --git a/libjava/classpath/gnu/javax/crypto/assembly/Stage.java b/libjava/classpath/gnu/javax/crypto/assembly/Stage.java new file mode 100644 index 000000000..5d0ab5353 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/assembly/Stage.java @@ -0,0 +1,202 @@ +/* Stage.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.assembly; + +import gnu.javax.crypto.mode.IMode; + +import java.security.InvalidKeyException; +import java.util.Map; +import java.util.Set; + +/** + * A <i>Stage</i> in a Cascade Cipher. + * <p> + * Each stage may be either an implementation of a Block Cipher Mode of + * Operation ({@link IMode}) or another Cascade Cipher ({@link Cascade}). + * Each stage has also a <i>natural</i> operational direction when constructed + * for inclusion within a {@link Cascade}. This <i>natural</i> direction + * dictates how data flows from one stage into another when stages are chained + * together in a cascade. One can think of a stage and its natural direction as + * the specification of how to wire the stage into the chain. The following + * diagrams may help understand the paradigme. The first shows two stages + * chained each with a {@link Direction#FORWARD} direction. + * + * <pre> + * FORWARD FORWARD + * +------+ +-------+ + * | | | | + * | +--in --+ | +--in --+ + * ---+ | Stage | | | Stage | +--- + * +--out--+ | +--out--+ | + * | | | | + * +-------+ +------+ + * </pre> + * + * <p> + * The second diagram shows two stages, one in a {@link Direction#FORWARD} + * direction, while the other is wired in a {@link Direction#REVERSED} + * direction. + * + * <pre> + * FORWARD REVERSED + * +------+ +------+ + * | | | | + * | +--in --+ +--in --+ | + * ---+ | Stage | | Stage | +--- + * +--out--+ +--out--+ + * | | + * +---------------+ + * </pre> + * + * @see ModeStage + * @see CascadeStage + */ +public abstract class Stage +{ + public static final String DIRECTION = "gnu.crypto.assembly.stage.direction"; + + protected Direction forward; + + protected Direction wired; + + protected Stage(Direction forwardDirection) + { + super(); + + this.forward = forwardDirection; + this.wired = null; + } + + public static final Stage getInstance(IMode mode, Direction forwardDirection) + { + return new ModeStage(mode, forwardDirection); + } + + public static final Stage getInstance(Cascade cascade, + Direction forwardDirection) + { + return new CascadeStage(cascade, forwardDirection); + } + + /** + * Returns the {@link Set} of supported block sizes for this + * <code>Stage</code>. Each element in the returned {@link Set} is an + * instance of {@link Integer}. + * + * @return a {@link Set} of supported block sizes. + */ + public abstract Set blockSizes(); + + /** + * Initialises the stage for operation with specific characteristics. + * + * @param attributes a set of name-value pairs that describes the desired + * future behaviour of this instance. + * @throws IllegalStateException if the instance is already initialised. + * @throws InvalidKeyException if the key data is invalid. + */ + public void init(Map attributes) throws InvalidKeyException + { + if (wired != null) + throw new IllegalStateException(); + Direction flow = (Direction) attributes.get(DIRECTION); + if (flow == null) + { + flow = Direction.FORWARD; + attributes.put(DIRECTION, flow); + } + initDelegate(attributes); + wired = flow; + } + + /** + * Returns the currently set block size for the stage. + * + * @return the current block size for this stage. + * @throws IllegalStateException if the instance is not initialised. + */ + public abstract int currentBlockSize() throws IllegalStateException; + + /** + * Resets the stage for re-initialisation and use with other characteristics. + * This method always succeeds. + */ + public void reset() + { + resetDelegate(); + wired = null; + } + + /** + * Processes exactly one block of <i>plaintext</i> (if initialised in the + * {@link Direction#FORWARD} state) or <i>ciphertext</i> (if initialised in + * the {@link Direction#REVERSED} state). + * + * @param in the plaintext. + * @param inOffset index of <code>in</code> from which to start considering + * data. + * @param out the ciphertext. + * @param outOffset index of <code>out</code> from which to store result. + * @throws IllegalStateException if the instance is not initialised. + */ + public void update(byte[] in, int inOffset, byte[] out, int outOffset) + { + if (wired == null) + throw new IllegalStateException(); + updateDelegate(in, inOffset, out, outOffset); + } + + /** + * Conducts a simple <i>correctness</i> test that consists of basic symmetric + * encryption / decryption test(s) for all supported block and key sizes of + * underlying block cipher(s) wrapped by Mode leafs. The test also includes + * one (1) variable key Known Answer Test (KAT) for each block cipher. + * + * @return <code>true</code> if the implementation passes simple + * <i>correctness</i> tests. Returns <code>false</code> otherwise. + */ + public abstract boolean selfTest(); + + abstract void initDelegate(Map attributes) throws InvalidKeyException; + + abstract void resetDelegate(); + + abstract void updateDelegate(byte[] in, int inOffset, byte[] out, + int outOffset); +} diff --git a/libjava/classpath/gnu/javax/crypto/assembly/Transformer.java b/libjava/classpath/gnu/javax/crypto/assembly/Transformer.java new file mode 100644 index 000000000..1937f9950 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/assembly/Transformer.java @@ -0,0 +1,421 @@ +/* Transformer.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.assembly; + +import gnu.javax.crypto.pad.IPad; + +import java.io.ByteArrayOutputStream; +import java.util.Map; + +/** + * A <code>Transformer</code> is an abstract representation of a two-way + * <i>transformation</i> that can be chained together with other instances of + * this type. Examples of such transformations in this library are: + * {@link Cascade} cipher, {@link gnu.javax.crypto.pad.IPad} algorithm, and a + * ZLib-based deflater/inflater algorithm. A special implementation of a + * <code>Transformer</code> to close a chain is also provided. + * <p> + * A <code>Transformer</code> is characterised by the followings: + * <ul> + * <li>It can be chained to other instances, to form an {@link Assembly}.</li> + * <li>When configured in an {@link Assembly}, it can be set to apply its + * internal transformation on the input data stream before (pre-processing) or + * after (post-processing) passing the input data to the next element in the + * chain. Note that the same type <code>Transformer</code> can be used as + * either in pre-processing or a post-processing modes.</li> + * <li>A special transformer --<code>LoopbackTransformer</code>-- is used + * to close the chain.</li> + * <li>A useful type of <code>Transformer</code> --one we're interested in-- + * has internal buffers. The distinction between a casual push (update) + * operation and the last one allows to correctly flush any intermediate bytes + * that may exist in those buffers.</li> + * </ul> + * <p> + * To allow wiring <code>Transformer</code> instances together, a + * <i>minimal-output-size</i> in bytes is necessary. The trivial case of a + * value of <code>1</code> for such attribute practically means that no output + * buffering, from the previous element, is needed --which is independant of + * buffering the input if the <code>Transformer</code> implementation itself + * is block-based. + * + * @see CascadeTransformer + * @see PaddingTransformer + * @see DeflateTransformer + */ +public abstract class Transformer +{ + public static final String DIRECTION = "gnu.crypto.assembly.transformer.direction"; + + protected Direction wired; + + protected Operation mode; + + protected Transformer tail = null; + + protected ByteArrayOutputStream inBuffer = new ByteArrayOutputStream(2048); + + protected ByteArrayOutputStream outBuffer = new ByteArrayOutputStream(2048); + + /** Trivial protected constructor. */ + protected Transformer() + { + super(); + + this.wired = null; + } + + public static final Transformer getCascadeTransformer(Cascade cascade) + { + return new CascadeTransformer(cascade); + } + + public static final Transformer getPaddingTransformer(IPad padding) + { + return new PaddingTransformer(padding); + } + + public static final Transformer getDeflateTransformer() + { + return new DeflateTransformer(); + } + + /** + * Sets the operational mode of this <code>Transformer</code>. + * + * @param mode the processing mode this <code>Transformer</code> is required + * to operate in. + * @throws IllegalStateException if this instance has already been assigned an + * operational mode. + */ + public void setMode(final Operation mode) + { + if (this.mode != null) + throw new IllegalStateException(); + this.mode = mode; + } + + /** + * Returns <code>true</code> if this <code>Transformer</code> was wired in + * pre-processing mode; <code>false</code> otherwise. + * + * @return <code>true</code> if this <code>Transformer</code> has been + * wired in pre-processing mode; <code>false</code> otherwise. + * @throws IllegalStateException if this instance has not yet been assigned an + * operational <i>type</i>. + */ + public boolean isPreProcessing() + { + if (mode == null) + throw new IllegalStateException(); + return (mode == Operation.PRE_PROCESSING); + } + + /** + * Returns <code>true</code> if this <code>Transformer</code> was wired in + * post-processing mode; <code>false</code> otherwise. + * + * @return <code>true</code> if this <code>Transformer</code> has been + * wired in post-processing mode; <code>false</code> otherwise. + * @throws IllegalStateException if this instance has not yet been assigned an + * operational <i>type</i>. + */ + public boolean isPostProcessing() + { + return ! isPreProcessing(); + } + + /** + * Initialises the <code>Transformer</code> for operation with specific + * characteristics. + * + * @param attributes a set of name-value pairs that describes the desired + * future behaviour of this instance. + * @throws IllegalStateException if the instance is already initialised. + */ + public void init(Map attributes) throws TransformerException + { + if (wired != null) + throw new IllegalStateException(); + Direction flow = (Direction) attributes.get(DIRECTION); + if (flow == null) + flow = Direction.FORWARD; + wired = flow; + inBuffer.reset(); + outBuffer.reset(); + tail.init(attributes); // initialise tail first + initDelegate(attributes); // initialise this instance + } + + /** + * Returns the block-size of this <code>Transformer</code>. A value of + * <code>1</code> indicates that this instance is block-agnostic. + * + * @return the current minimal required block size. + */ + public int currentBlockSize() + { + if (wired == null) + throw new IllegalStateException(); + return delegateBlockSize(); + } + + /** + * Resets the <code>Transformer</code> for re-initialisation and use with + * other characteristics. This method always succeeds. + */ + public void reset() + { + resetDelegate(); + wired = null; + inBuffer.reset(); + outBuffer.reset(); + tail.reset(); // reset tail last + } + + /** + * Convenience method that calls the method with same name and three + * arguments, using a byte array of length <code>1</code> whose contents are + * the designated byte. + * + * @param b the byte to process. + * @return the result of transformation. + * @throws IllegalStateException if the instance is not initialised. + * @throws TransformerException if a transformation-related exception occurs + * during the operation. + * @see #update(byte[], int, int) + */ + public byte[] update(byte b) throws TransformerException + { + return update(new byte[] { b }, 0, 1); + } + + /** + * Convenience method that calls the same method with three arguments. All + * bytes in <code>in</code>, starting from index position <code>0</code> + * are considered. + * + * @param in the input data bytes. + * @return the result of transformation. + * @throws IllegalStateException if the instance is not initialised. + * @throws TransformerException if a transformation-related exception occurs + * during the operation. + * @see #update(byte[], int, int) + */ + public byte[] update(byte[] in) throws TransformerException + { + return update(in, 0, in.length); + } + + /** + * Processes a designated number of bytes from a given byte array. + * + * @param in the input data bytes. + * @param offset index of <code>in</code> from which to start considering + * data. + * @param length the count of bytes to process. + * @return the result of transformation. + * @throws IllegalStateException if the instance is not initialised. + * @throws TransformerException if a transformation-related exception occurs + * during the operation. + */ + public byte[] update(byte[] in, int offset, int length) + throws TransformerException + { + if (wired == null) + throw new IllegalStateException(); + byte[] result = (wired == Direction.FORWARD ? forwardUpdate(in, offset, length) + : inverseUpdate(in, offset, length)); + return result; + } + + /** + * Convenience method that calls the same method with three arguments. A + * zero-long byte array is used. + * + * @return the result of transformation. + * @throws IllegalStateException if the instance is not initialised. + * @throws TransformerException if a transformation-related exception occurs + * during the operation. + * @see #lastUpdate(byte[], int, int) + */ + public byte[] lastUpdate() throws TransformerException + { + byte[] result = (wired == Direction.FORWARD ? lastForwardUpdate() + : lastInverseUpdate()); + if (inBuffer.size() != 0) // we still have some buffered bytes + throw new TransformerException("lastUpdate(): input buffer not empty"); + return result; + } + + /** + * Convenience method that calls the method with same name and three + * arguments, using a byte array of length <code>1</code> whose contents are + * the designated byte. + * + * @param b the byte to process. + * @return the result of transformation. + * @throws IllegalStateException if the instance is not initialised. + * @throws TransformerException if a transformation-related exception occurs + * during the operation. + * @see #lastUpdate(byte[], int, int) + */ + public byte[] lastUpdate(byte b) throws TransformerException + { + return lastUpdate(new byte[] { b }, 0, 1); + } + + /** + * Convenience method that calls the same method with three arguments. All + * bytes in <code>in</code>, starting from index position <code>0</code> + * are considered. + * + * @param in the input data bytes. + * @return the result of transformation. + * @throws IllegalStateException if the instance is not initialised. + * @throws TransformerException if a transformation-related exception occurs + * during the operation. + * @see #lastUpdate(byte[], int, int) + */ + public byte[] lastUpdate(byte[] in) throws TransformerException + { + return lastUpdate(in, 0, in.length); + } + + /** + * Processes a designated number of bytes from a given byte array and signals, + * at the same time, that this is the last <i>push</i> operation on this + * <code>Transformer</code>. + * + * @param in the input data bytes. + * @param offset index of <code>in</code> from which to start considering + * data. + * @param length the count of bytes to process. + * @return the result of transformation. + * @throws IllegalStateException if the instance is not initialised. + * @throws TransformerException if a transformation-related exception occurs + * during the operation. + */ + public byte[] lastUpdate(byte[] in, int offset, int length) + throws TransformerException + { + byte[] result = update(in, offset, length); + byte[] rest = lastUpdate(); + if (rest.length > 0) + { + byte[] newResult = new byte[result.length + rest.length]; + System.arraycopy(result, 0, newResult, 0, result.length); + System.arraycopy(rest, 0, newResult, result.length, rest.length); + result = newResult; + } + return result; + } + + private byte[] forwardUpdate(byte[] in, int off, int len) + throws TransformerException + { + return (isPreProcessing() ? preTransform(in, off, len) + : postTransform(in, off, len)); + } + + private byte[] inverseUpdate(byte[] in, int off, int len) + throws TransformerException + { + return (isPreProcessing() ? postTransform(in, off, len) + : preTransform(in, off, len)); + } + + private byte[] preTransform(byte[] in, int off, int len) + throws TransformerException + { + byte[] result = updateDelegate(in, off, len); + result = tail.update(result); + return result; + } + + private byte[] postTransform(byte[] in, int off, int len) + throws TransformerException + { + byte[] result = tail.update(in, off, len); + result = updateDelegate(result, 0, result.length); + return result; + } + + private byte[] lastForwardUpdate() throws TransformerException + { + return (isPreProcessing() ? preLastTransform() : postLastTransform()); + } + + private byte[] lastInverseUpdate() throws TransformerException + { + return (isPreProcessing() ? postLastTransform() : preLastTransform()); + } + + private byte[] preLastTransform() throws TransformerException + { + byte[] result = lastUpdateDelegate(); + result = tail.lastUpdate(result); + return result; + } + + private byte[] postLastTransform() throws TransformerException + { + byte[] result = tail.lastUpdate(); + result = updateDelegate(result, 0, result.length); + byte[] rest = lastUpdateDelegate(); + if (rest.length > 0) + { + byte[] newResult = new byte[result.length + rest.length]; + System.arraycopy(result, 0, newResult, 0, result.length); + System.arraycopy(rest, 0, newResult, result.length, rest.length); + result = newResult; + } + return result; + } + + abstract void initDelegate(Map attributes) throws TransformerException; + + abstract int delegateBlockSize(); + + abstract void resetDelegate(); + + abstract byte[] updateDelegate(byte[] in, int off, int len) + throws TransformerException; + + abstract byte[] lastUpdateDelegate() throws TransformerException; +} diff --git a/libjava/classpath/gnu/javax/crypto/assembly/TransformerException.java b/libjava/classpath/gnu/javax/crypto/assembly/TransformerException.java new file mode 100644 index 000000000..295fded7b --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/assembly/TransformerException.java @@ -0,0 +1,140 @@ +/* TransformerException.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.assembly; + +import gnu.java.lang.CPStringBuilder; + +import java.io.PrintStream; +import java.io.PrintWriter; + +/** + */ +public class TransformerException + extends Exception +{ + private Throwable _exception = null; + + public TransformerException() + { + super(); + } + + public TransformerException(String details) + { + super(details); + } + + public TransformerException(Throwable cause) + { + super(); + + this._exception = cause; + } + + public TransformerException(String details, Throwable cause) + { + super(details); + + this._exception = cause; + } + + public Throwable getCause() + { + return _exception; + } + + /** + * Prints this exception's stack trace to <code>System.err</code>. If this + * exception has a root exception; the stack trace of the root exception is + * also printed to <code>System.err</code>. + */ + public void printStackTrace() + { + super.printStackTrace(); + if (_exception != null) + _exception.printStackTrace(); + } + + /** + * Prints this exception's stack trace to a print stream. If this exception + * has a root exception; the stack trace of the root exception is also printed + * to the print stream. + * + * @param ps the non-null print stream to which to print. + */ + public void printStackTrace(PrintStream ps) + { + super.printStackTrace(ps); + if (_exception != null) + _exception.printStackTrace(ps); + } + + /** + * Prints this exception's stack trace to a print writer. If this exception + * has a root exception; the stack trace of the root exception is also printed + * to the print writer. + * + * @param pw the non-null print writer to use for output. + */ + public void printStackTrace(PrintWriter pw) + { + super.printStackTrace(pw); + if (_exception != null) + _exception.printStackTrace(pw); + } + + /** + * Returns the string representation of this exception. The string + * representation contains this exception's class name, its detailed messsage, + * and if it has a root exception, the string representation of the root + * exception. This string representation is meant for debugging and not meant + * to be interpreted programmatically. + * + * @return the non-null string representation of this exception. + * @see Throwable#getMessage() + */ + public String toString() + { + CPStringBuilder sb = new CPStringBuilder(this.getClass().getName()) + .append(": ").append(super.toString()); + if (_exception != null) + sb.append("; caused by: ").append(_exception.toString()); + return sb.toString(); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/cipher/Anubis.java b/libjava/classpath/gnu/javax/crypto/cipher/Anubis.java new file mode 100644 index 000000000..3526ad612 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/cipher/Anubis.java @@ -0,0 +1,491 @@ +/* Anubis.java -- + Copyright (C) 2001, 2002, 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.cipher; + +import gnu.java.security.Configuration; +import gnu.java.security.Registry; +import gnu.java.security.util.Util; + +import java.security.InvalidKeyException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Iterator; +import java.util.logging.Logger; + +/** + * Anubis is a 128-bit block cipher that accepts a variable-length key. The + * cipher is a uniform substitution-permutation network whose inverse only + * differs from the forward operation in the key schedule. The design of both + * the round transformation and the key schedule is based upon the Wide Trail + * strategy and permits a wide variety of implementation trade-offs. + * <p> + * References: + * <ol> + * <li><a + * href="http://planeta.terra.com.br/informatica/paulobarreto/AnubisPage.html">The + * ANUBIS Block Cipher</a>.<br> + * <a href="mailto:paulo.barreto@terra.com.br">Paulo S.L.M. Barreto</a> and <a + * href="mailto:vincent.rijmen@esat.kuleuven.ac.be">Vincent Rijmen</a>.</li> + * </ol> + */ +public final class Anubis + extends BaseCipher +{ + private static final Logger log = Logger.getLogger(Anubis.class.getName()); + private static final int DEFAULT_BLOCK_SIZE = 16; // in bytes + private static final int DEFAULT_KEY_SIZE = 16; // in bytes + private static final String Sd = // p. 25 [ANUBIS] + "\uBA54\u2F74\u53D3\uD24D\u50AC\u8DBF\u7052\u9A4C" + + "\uEAD5\u97D1\u3351\u5BA6\uDE48\uA899\uDB32\uB7FC" + + "\uE39E\u919B\uE2BB\u416E\uA5CB\u6B95\uA1F3\uB102" + + "\uCCC4\u1D14\uC363\uDA5D\u5FDC\u7DCD\u7F5A\u6C5C" + + "\uF726\uFFED\uE89D\u6F8E\u19A0\uF089\u0F07\uAFFB" + + "\u0815\u0D04\u0164\uDF76\u79DD\u3D16\u3F37\u6D38" + + "\uB973\uE935\u5571\u7B8C\u7288\uF62A\u3E5E\u2746" + + "\u0C65\u6861\u03C1\u57D6\uD958\uD866\uD73A\uC83C" + + "\uFA96\uA798\uECB8\uC7AE\u694B\uABA9\u670A\u47F2" + + "\uB522\uE5EE\uBE2B\u8112\u831B\u0E23\uF545\u21CE" + + "\u492C\uF9E6\uB628\u1782\u1A8B\uFE8A\u09C9\u874E" + + "\uE12E\uE4E0\uEB90\uA41E\u8560\u0025\uF4F1\u940B" + + "\uE775\uEF34\u31D4\uD086\u7EAD\uFD29\u303B\u9FF8" + + "\uC613\u0605\uC511\u777C\u7A78\u361C\u3959\u1856" + + "\uB3B0\u2420\uB292\uA3C0\u4462\u10B4\u8443\u93C2" + + "\u4ABD\u8F2D\uBC9C\u6A40\uCFA2\u804F\u1FCA\uAA42"; + private static final byte[] S = new byte[256]; + private static final int[] T0 = new int[256]; + private static final int[] T1 = new int[256]; + private static final int[] T2 = new int[256]; + private static final int[] T3 = new int[256]; + private static final int[] T4 = new int[256]; + private static final int[] T5 = new int[256]; + /** + * Anubis round constants. This is the largest possible considering that we + * always use R values, R = 8 + N, and 4 <= N <= 10. + */ + private static final int[] rc = new int[18]; + /** + * KAT vector (from ecb_vk): I=83 + * KEY=000000000000000000002000000000000000000000000000 + * CT=2E66AB15773F3D32FB6C697509460DF4 + */ + private static final byte[] KAT_KEY = + Util.toBytesFromString("000000000000000000002000000000000000000000000000"); + private static final byte[] KAT_CT = + Util.toBytesFromString("2E66AB15773F3D32FB6C697509460DF4"); + /** caches the result of the correctness test, once executed. */ + private static Boolean valid; + + static + { + long time = System.currentTimeMillis(); + int ROOT = 0x11d; // para. 2.1 [ANUBIS] + int i, s, s2, s4, s6, s8, t; + char c; + for (i = 0; i < 256; i++) + { + c = Sd.charAt(i >>> 1); + s = ((i & 1) == 0 ? c >>> 8 : c) & 0xFF; + S[i] = (byte) s; + s2 = s << 1; + if (s2 > 0xFF) + s2 ^= ROOT; + s4 = s2 << 1; + if (s4 > 0xFF) + s4 ^= ROOT; + s6 = s4 ^ s2; + s8 = s4 << 1; + if (s8 > 0xFF) + s8 ^= ROOT; + T0[i] = s << 24 | s2 << 16 | s4 << 8 | s6; + T1[i] = s2 << 24 | s << 16 | s6 << 8 | s4; + T2[i] = s4 << 24 | s6 << 16 | s << 8 | s2; + T3[i] = s6 << 24 | s4 << 16 | s2 << 8 | s; + T4[i] = s << 24 | s << 16 | s << 8 | s; + T5[s] = s << 24 | s2 << 16 | s6 << 8 | s8; + } + // compute round constant + for (i = 0, s = 0; i < 18;) + rc[i++] = S[(s++) & 0xFF] << 24 + | (S[(s++) & 0xFF] & 0xFF) << 16 + | (S[(s++) & 0xFF] & 0xFF) << 8 + | (S[(s++) & 0xFF] & 0xFF); + time = System.currentTimeMillis() - time; + if (Configuration.DEBUG) + { + log.fine("Static data"); + log.fine("T0[]:"); + StringBuilder sb; + for (i = 0; i < 64; i++) + { + sb = new StringBuilder(); + for (t = 0; t < 4; t++) + sb.append("0x").append(Util.toString(T0[i * 4 + t])).append(", "); + log.fine(sb.toString()); + } + log.fine("T1[]:"); + for (i = 0; i < 64; i++) + { + sb = new StringBuilder(); + for (t = 0; t < 4; t++) + sb.append("0x").append(Util.toString(T1[i * 4 + t])).append(", "); + log.fine(sb.toString()); + } + log.fine("T2[]:"); + for (i = 0; i < 64; i++) + { + sb = new StringBuilder(); + for (t = 0; t < 4; t++) + sb.append("0x").append(Util.toString(T2[i * 4 + t])).append(", "); + log.fine(sb.toString()); + } + log.fine("T3[]:"); + for (i = 0; i < 64; i++) + { + sb = new StringBuilder(); + for (t = 0; t < 4; t++) + sb.append("0x").append(Util.toString(T3[i * 4 + t])).append(", "); + log.fine(sb.toString()); + } + log.fine("T4[]:"); + for (i = 0; i < 64; i++) + { + sb = new StringBuilder(); + for (t = 0; t < 4; t++) + sb.append("0x").append(Util.toString(T4[i * 4 + t])).append(", "); + log.fine(sb.toString()); + } + log.fine("T5[]:"); + for (i = 0; i < 64; i++) + { + sb = new StringBuilder(); + for (t = 0; t < 4; t++) + sb.append("0x").append(Util.toString(T5[i * 4 + t])).append(", "); + log.fine(sb.toString()); + } + log.fine("rc[]:"); + for (i = 0; i < 18; i++) + log.fine("0x" + Util.toString(rc[i])); + log.fine("Total initialization time: " + time + " ms."); + } + } + + /** Trivial 0-arguments constructor. */ + public Anubis() + { + super(Registry.ANUBIS_CIPHER, DEFAULT_BLOCK_SIZE, DEFAULT_KEY_SIZE); + } + + private static void anubis(byte[] in, int i, byte[] out, int j, int[][] K) + { + // extract encryption round keys + int R = K.length - 1; + int[] Ker = K[0]; + // mu function + affine key addition + int a0 = (in[i++] << 24 + | (in[i++] & 0xFF) << 16 + | (in[i++] & 0xFF) << 8 + | (in[i++] & 0xFF) ) ^ Ker[0]; + int a1 = (in[i++] << 24 + | (in[i++] & 0xFF) << 16 + | (in[i++] & 0xFF) << 8 + | (in[i++] & 0xFF) ) ^ Ker[1]; + int a2 = (in[i++] << 24 + | (in[i++] & 0xFF) << 16 + | (in[i++] & 0xFF) << 8 + | (in[i++] & 0xFF) ) ^ Ker[2]; + int a3 = (in[i++] << 24 + | (in[i++] & 0xFF) << 16 + | (in[i++] & 0xFF) << 8 + | (in[i] & 0xFF) ) ^ Ker[3]; + int b0, b1, b2, b3; + // round function + for (int r = 1; r < R; r++) + { + Ker = K[r]; + b0 = T0[ a0 >>> 24 ] + ^ T1[ a1 >>> 24 ] + ^ T2[ a2 >>> 24 ] + ^ T3[ a3 >>> 24 ] ^ Ker[0]; + b1 = T0[(a0 >>> 16) & 0xFF] + ^ T1[(a1 >>> 16) & 0xFF] + ^ T2[(a2 >>> 16) & 0xFF] + ^ T3[(a3 >>> 16) & 0xFF] ^ Ker[1]; + b2 = T0[(a0 >>> 8) & 0xFF] + ^ T1[(a1 >>> 8) & 0xFF] + ^ T2[(a2 >>> 8) & 0xFF] + ^ T3[(a3 >>> 8) & 0xFF] ^ Ker[2]; + b3 = T0[ a0 & 0xFF] + ^ T1[ a1 & 0xFF] + ^ T2[ a2 & 0xFF] + ^ T3[ a3 & 0xFF] ^ Ker[3]; + a0 = b0; + a1 = b1; + a2 = b2; + a3 = b3; + if (Configuration.DEBUG) + log.fine("T" + r + "=" + Util.toString(a0) + Util.toString(a1) + + Util.toString(a2) + Util.toString(a3)); + } + // last round function + Ker = K[R]; + int tt = Ker[0]; + out[j++] = (byte)(S[ a0 >>> 24 ] ^ (tt >>> 24)); + out[j++] = (byte)(S[ a1 >>> 24 ] ^ (tt >>> 16)); + out[j++] = (byte)(S[ a2 >>> 24 ] ^ (tt >>> 8)); + out[j++] = (byte)(S[ a3 >>> 24 ] ^ tt); + tt = Ker[1]; + out[j++] = (byte)(S[(a0 >>> 16) & 0xFF] ^ (tt >>> 24)); + out[j++] = (byte)(S[(a1 >>> 16) & 0xFF] ^ (tt >>> 16)); + out[j++] = (byte)(S[(a2 >>> 16) & 0xFF] ^ (tt >>> 8)); + out[j++] = (byte)(S[(a3 >>> 16) & 0xFF] ^ tt); + tt = Ker[2]; + out[j++] = (byte)(S[(a0 >>> 8) & 0xFF] ^ (tt >>> 24)); + out[j++] = (byte)(S[(a1 >>> 8) & 0xFF] ^ (tt >>> 16)); + out[j++] = (byte)(S[(a2 >>> 8) & 0xFF] ^ (tt >>> 8)); + out[j++] = (byte)(S[(a3 >>> 8) & 0xFF] ^ tt); + tt = Ker[3]; + out[j++] = (byte)(S[ a0 & 0xFF] ^ (tt >>> 24)); + out[j++] = (byte)(S[ a1 & 0xFF] ^ (tt >>> 16)); + out[j++] = (byte)(S[ a2 & 0xFF] ^ (tt >>> 8)); + out[j ] = (byte)(S[ a3 & 0xFF] ^ tt); + if (Configuration.DEBUG) + log.fine("T=" + Util.toString(out, j - 15, 16) + "\n"); + } + + public Object clone() + { + Anubis result = new Anubis(); + result.currentBlockSize = this.currentBlockSize; + + return result; + } + + public Iterator blockSizes() + { + ArrayList al = new ArrayList(); + al.add(Integer.valueOf(DEFAULT_BLOCK_SIZE)); + + return Collections.unmodifiableList(al).iterator(); + } + + public Iterator keySizes() + { + ArrayList al = new ArrayList(); + for (int n = 4; n < 10; n++) + al.add(Integer.valueOf(n * 32 / 8)); + return Collections.unmodifiableList(al).iterator(); + } + + /** + * Expands a user-supplied key material into a session key for a designated + * <i>block size</i>. + * + * @param uk the 32N-bit user-supplied key material; 4 <= N <= 10. + * @param bs the desired block size in bytes. + * @return an Object encapsulating the session key. + * @exception IllegalArgumentException if the block size is not 16 (128-bit). + * @exception InvalidKeyException if the key data is invalid. + */ + public Object makeKey(byte[] uk, int bs) throws InvalidKeyException + { + if (bs != DEFAULT_BLOCK_SIZE) + throw new IllegalArgumentException(); + if (uk == null) + throw new InvalidKeyException("Empty key"); + if ((uk.length % 4) != 0) + throw new InvalidKeyException("Key is not multiple of 32-bit."); + int N = uk.length / 4; + if (N < 4 || N > 10) + throw new InvalidKeyException("Key is not 32N; 4 <= N <= 10"); + int R = 8 + N; + int[][] Ke = new int[R + 1][4]; // encryption round keys + int[][] Kd = new int[R + 1][4]; // decryption round keys + int[] tk = new int[N]; + int[] kk = new int[N]; + int r, i, j, k, k0, k1, k2, k3, tt; + // apply mu to k0 + for (r = 0, i = 0; r < N;) + tk[r++] = uk[i++] << 24 + | (uk[i++] & 0xFF) << 16 + | (uk[i++] & 0xFF) << 8 + | (uk[i++] & 0xFF); + for (r = 0; r <= R; r++) + { + if (r > 0) + { + // psi = key evolution function + kk[0] = T0[(tk[0 ] >>> 24) ] + ^ T1[(tk[N - 1] >>> 16) & 0xFF] + ^ T2[(tk[N - 2] >>> 8) & 0xFF] + ^ T3[ tk[N - 3] & 0xFF]; + kk[1] = T0[(tk[1 ] >>> 24) ] + ^ T1[(tk[0 ] >>> 16) & 0xFF] + ^ T2[(tk[N - 1] >>> 8) & 0xFF] + ^ T3[ tk[N - 2] & 0xFF]; + kk[2] = T0[(tk[2 ] >>> 24) ] + ^ T1[(tk[1 ] >>> 16) & 0xFF] + ^ T2[(tk[0 ] >>> 8) & 0xFF] + ^ T3[ tk[N - 1] & 0xFF]; + kk[3] = T0[(tk[3 ] >>> 24) ] + ^ T1[(tk[2 ] >>> 16) & 0xFF] + ^ T2[(tk[1 ] >>> 8) & 0xFF] + ^ T3[ tk[0 ] & 0xFF]; + for (i = 4; i < N; i++) + kk[i] = T0[ tk[i ] >>> 24 ] + ^ T1[(tk[i - 1] >>> 16) & 0xFF] + ^ T2[(tk[i - 2] >>> 8) & 0xFF] + ^ T3[ tk[i - 3] & 0xFF]; + // apply sigma (affine addition) to round constant + tk[0] = rc[r - 1] ^ kk[0]; + for (i = 1; i < N; i++) + tk[i] = kk[i]; + } + // phi = key selection function + tt = tk[N - 1]; + k0 = T4[ tt >>> 24 ]; + k1 = T4[(tt >>> 16) & 0xFF]; + k2 = T4[(tt >>> 8) & 0xFF]; + k3 = T4[ tt & 0xFF]; + for (k = N - 2; k >= 0; k--) + { + tt = tk[k]; + k0 = T4[ tt >>> 24 ] + ^ (T5[(k0 >>> 24) & 0xFF] & 0xFF000000) + ^ (T5[(k0 >>> 16) & 0xFF] & 0x00FF0000) + ^ (T5[(k0 >>> 8) & 0xFF] & 0x0000FF00) + ^ (T5 [k0 & 0xFF] & 0x000000FF); + k1 = T4[(tt >>> 16) & 0xFF] + ^ (T5[(k1 >>> 24) & 0xFF] & 0xFF000000) + ^ (T5[(k1 >>> 16) & 0xFF] & 0x00FF0000) + ^ (T5[(k1 >>> 8) & 0xFF] & 0x0000FF00) + ^ (T5[ k1 & 0xFF] & 0x000000FF); + k2 = T4[(tt >>> 8) & 0xFF] + ^ (T5[(k2 >>> 24) & 0xFF] & 0xFF000000) + ^ (T5[(k2 >>> 16) & 0xFF] & 0x00FF0000) + ^ (T5[(k2 >>> 8) & 0xFF] & 0x0000FF00) + ^ (T5[ k2 & 0xFF] & 0x000000FF); + k3 = T4[ tt & 0xFF] + ^ (T5[(k3 >>> 24) & 0xFF] & 0xFF000000) + ^ (T5[(k3 >>> 16) & 0xFF] & 0x00FF0000) + ^ (T5[(k3 >>> 8) & 0xFF] & 0x0000FF00) + ^ (T5[ k3 & 0xFF] & 0x000000FF); + } + Ke[r][0] = k0; + Ke[r][1] = k1; + Ke[r][2] = k2; + Ke[r][3] = k3; + if (r == 0 || r == R) + { + Kd[R - r][0] = k0; + Kd[R - r][1] = k1; + Kd[R - r][2] = k2; + Kd[R - r][3] = k3; + } + else + { + Kd[R - r][0] = T0[S[ k0 >>> 24 ] & 0xFF] + ^ T1[S[(k0 >>> 16) & 0xFF] & 0xFF] + ^ T2[S[(k0 >>> 8) & 0xFF] & 0xFF] + ^ T3[S[ k0 & 0xFF] & 0xFF]; + Kd[R - r][1] = T0[S[ k1 >>> 24 ] & 0xFF] + ^ T1[S[(k1 >>> 16) & 0xFF] & 0xFF] + ^ T2[S[(k1 >>> 8) & 0xFF] & 0xFF] + ^ T3[S[ k1 & 0xFF] & 0xFF]; + Kd[R - r][2] = T0[S[ k2 >>> 24 ] & 0xFF] + ^ T1[S[(k2 >>> 16) & 0xFF] & 0xFF] + ^ T2[S[(k2 >>> 8) & 0xFF] & 0xFF] + ^ T3[S[ k2 & 0xFF] & 0xFF]; + Kd[R - r][3] = T0[S[ k3 >>> 24 ] & 0xFF] + ^ T1[S[(k3 >>> 16) & 0xFF] & 0xFF] + ^ T2[S[(k3 >>> 8) & 0xFF] & 0xFF] + ^ T3[S[ k3 & 0xFF] & 0xFF]; + } + } + if (Configuration.DEBUG) + { + log.fine("Key schedule"); + log.fine("Ke[]:"); + StringBuilder sb; + for (r = 0; r < R + 1; r++) + { + sb = new StringBuilder("#").append(r).append(": "); + for (j = 0; j < 4; j++) + sb.append("0x").append(Util.toString(Ke[r][j])).append(", "); + log.fine(sb.toString()); + } + log.fine("Kd[]:"); + for (r = 0; r < R + 1; r++) + { + sb = new StringBuilder("#").append(r).append(": "); + for (j = 0; j < 4; j++) + sb.append("0x").append(Util.toString(Kd[r][j])).append(", "); + log.fine(sb.toString()); + } + } + return new Object[] { Ke, Kd }; + } + + public void encrypt(byte[] in, int i, byte[] out, int j, Object k, int bs) + { + if (bs != DEFAULT_BLOCK_SIZE) + throw new IllegalArgumentException(); + int[][] K = (int[][])((Object[]) k)[0]; + anubis(in, i, out, j, K); + } + + public void decrypt(byte[] in, int i, byte[] out, int j, Object k, int bs) + { + if (bs != DEFAULT_BLOCK_SIZE) + throw new IllegalArgumentException(); + int[][] K = (int[][])((Object[]) k)[1]; + anubis(in, i, out, j, K); + } + + public boolean selfTest() + { + if (valid == null) + { + boolean result = super.selfTest(); // do symmetry tests + if (result) + result = testKat(KAT_KEY, KAT_CT); + valid = Boolean.valueOf(result); + } + return valid.booleanValue(); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/cipher/BaseCipher.java b/libjava/classpath/gnu/javax/crypto/cipher/BaseCipher.java new file mode 100644 index 000000000..45aa2d6fd --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/cipher/BaseCipher.java @@ -0,0 +1,249 @@ +/* BaseCipher.java -- + Copyright (C) 2001, 2002, 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.cipher; + +import gnu.java.lang.CPStringBuilder; + +import gnu.java.security.Configuration; + +import java.security.InvalidKeyException; +import java.util.Arrays; +import java.util.Iterator; +import java.util.Map; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * A basic abstract class to facilitate implementing symmetric key block + * ciphers. + */ +public abstract class BaseCipher + implements IBlockCipher, IBlockCipherSpi +{ + private static final Logger log = Logger.getLogger(BaseCipher.class.getName()); + /** The canonical name prefix of the cipher. */ + protected String name; + /** The default block size, in bytes. */ + protected int defaultBlockSize; + /** The default key size, in bytes. */ + protected int defaultKeySize; + /** The current block size, in bytes. */ + protected int currentBlockSize; + /** The session key for this instance. */ + protected transient Object currentKey; + /** The instance lock. */ + protected Object lock = new Object(); + + /** + * Trivial constructor for use by concrete subclasses. + * + * @param name the canonical name prefix of this instance. + * @param defaultBlockSize the default block size in bytes. + * @param defaultKeySize the default key size in bytes. + */ + protected BaseCipher(String name, int defaultBlockSize, int defaultKeySize) + { + super(); + + this.name = name; + this.defaultBlockSize = defaultBlockSize; + this.defaultKeySize = defaultKeySize; + } + + public abstract Object clone(); + + public String name() + { + CPStringBuilder sb = new CPStringBuilder(name).append('-'); + if (currentKey == null) + sb.append(String.valueOf(8 * defaultBlockSize)); + else + sb.append(String.valueOf(8 * currentBlockSize)); + return sb.toString(); + } + + public int defaultBlockSize() + { + return defaultBlockSize; + } + + public int defaultKeySize() + { + return defaultKeySize; + } + + public void init(Map attributes) throws InvalidKeyException + { + synchronized (lock) + { + if (currentKey != null) + throw new IllegalStateException(); + Integer bs = (Integer) attributes.get(CIPHER_BLOCK_SIZE); + if (bs == null) // no block size was specified + { + if (currentBlockSize == 0) // happy birthday + currentBlockSize = defaultBlockSize; + // else it's a clone. use as is + } + else + { + currentBlockSize = bs.intValue(); + // ensure that value is valid + Iterator it; + boolean ok = false; + for (it = blockSizes(); it.hasNext();) + { + ok = (currentBlockSize == ((Integer) it.next()).intValue()); + if (ok) + break; + } + if (! ok) + throw new IllegalArgumentException(IBlockCipher.CIPHER_BLOCK_SIZE); + } + byte[] k = (byte[]) attributes.get(KEY_MATERIAL); + currentKey = makeKey(k, currentBlockSize); + } + } + + public int currentBlockSize() + { + if (currentKey == null) + throw new IllegalStateException(); + return currentBlockSize; + } + + public void reset() + { + synchronized (lock) + { + currentKey = null; + } + } + + public void encryptBlock(byte[] in, int inOffset, byte[] out, int outOffset) + throws IllegalStateException + { + synchronized (lock) + { + if (currentKey == null) + throw new IllegalStateException(); + encrypt(in, inOffset, out, outOffset, currentKey, currentBlockSize); + } + } + + public void decryptBlock(byte[] in, int inOffset, byte[] out, int outOffset) + throws IllegalStateException + { + synchronized (lock) + { + if (currentKey == null) + throw new IllegalStateException(); + decrypt(in, inOffset, out, outOffset, currentKey, currentBlockSize); + } + } + + public boolean selfTest() + { + int ks; + Iterator bit; + // do symmetry tests for all block-size/key-size combos + for (Iterator kit = keySizes(); kit.hasNext();) + { + ks = ((Integer) kit.next()).intValue(); + for (bit = blockSizes(); bit.hasNext();) + if (! testSymmetry(ks, ((Integer) bit.next()).intValue())) + return false; + } + return true; + } + + private boolean testSymmetry(int ks, int bs) + { + try + { + byte[] kb = new byte[ks]; + byte[] pt = new byte[bs]; + byte[] ct = new byte[bs]; + byte[] cpt = new byte[bs]; + int i; + for (i = 0; i < ks; i++) + kb[i] = (byte) i; + for (i = 0; i < bs; i++) + pt[i] = (byte) i; + Object k = makeKey(kb, bs); + encrypt(pt, 0, ct, 0, k, bs); + decrypt(ct, 0, cpt, 0, k, bs); + return Arrays.equals(pt, cpt); + } + catch (Exception x) + { + if (Configuration.DEBUG) + log.log(Level.FINE, "Exception in testSymmetry() for " + name(), x); + return false; + } + } + + protected boolean testKat(byte[] kb, byte[] ct) + { + return testKat(kb, ct, new byte[ct.length]); // all-zero plaintext + } + + protected boolean testKat(byte[] kb, byte[] ct, byte[] pt) + { + try + { + int bs = pt.length; + byte[] t = new byte[bs]; + Object k = makeKey(kb, bs); + // test encryption + encrypt(pt, 0, t, 0, k, bs); + if (! Arrays.equals(t, ct)) + return false; + // test decryption + decrypt(t, 0, t, 0, k, bs); + return Arrays.equals(t, pt); + } + catch (Exception x) + { + if (Configuration.DEBUG) + log.log(Level.FINE, "Exception in testKat() for " + name(), x); + return false; + } + } +} diff --git a/libjava/classpath/gnu/javax/crypto/cipher/Blowfish.java b/libjava/classpath/gnu/javax/crypto/cipher/Blowfish.java new file mode 100644 index 000000000..0c6d9b12b --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/cipher/Blowfish.java @@ -0,0 +1,611 @@ +/* Blowfish.java -- + Copyright (C) 2001, 2002, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +// -------------------------------------------------------------------------- +// +// Based on the C implementation from the GNU Privacy Guard. +// +// -------------------------------------------------------------------------- + +package gnu.javax.crypto.cipher; + +import gnu.java.security.Registry; +import gnu.java.security.util.Sequence; +import gnu.java.security.util.Util; + +import java.util.Collections; +import java.util.Iterator; + +/** + * Blowfish is a 16-round, 64-bit Feistel cipher designed by Bruce Schneier. It + * accepts a variable-length key of up to 448 bits. + * <p> + * References: + * <ol> + * <li>Schneier, Bruce: <i>Applied Cryptography</i>, Second Edition, 336--339, + * 647--654 (1996 Bruce Schneier).</li> + * <li><a href="http://www.counterpane.com/blowfish.html">The Blowfish + * Encryption Algorithm.</a></li> + * </ol> + */ +public class Blowfish + extends BaseCipher +{ + private static final int DEFAULT_BLOCK_SIZE = 8; + private static final int DEFAULT_KEY_SIZE = 8; + private static final int MAX_KEY_LENGTH = 56; + /** Initial value of the p-array. */ + private static final int[] P = { + 0x243f6a88, 0x85a308d3, 0x13198a2e, 0x03707344, 0xa4093822, 0x299f31d0, + 0x082efa98, 0xec4e6c89, 0x452821e6, 0x38d01377, 0xbe5466cf, 0x34e90c6c, + 0xc0ac29b7, 0xc97c50dd, 0x3f84d5b5, 0xb5470917, 0x9216d5d9, 0x8979fb1b }; + /** Initial value of S-box 1. */ + static final int[] KS0 = { + 0xd1310ba6, 0x98dfb5ac, 0x2ffd72db, 0xd01adfb7, 0xb8e1afed, 0x6a267e96, + 0xba7c9045, 0xf12c7f99, 0x24a19947, 0xb3916cf7, 0x0801f2e2, 0x858efc16, + 0x636920d8, 0x71574e69, 0xa458fea3, 0xf4933d7e, 0x0d95748f, 0x728eb658, + 0x718bcd58, 0x82154aee, 0x7b54a41d, 0xc25a59b5, 0x9c30d539, 0x2af26013, + 0xc5d1b023, 0x286085f0, 0xca417918, 0xb8db38ef, 0x8e79dcb0, 0x603a180e, + 0x6c9e0e8b, 0xb01e8a3e, 0xd71577c1, 0xbd314b27, 0x78af2fda, 0x55605c60, + 0xe65525f3, 0xaa55ab94, 0x57489862, 0x63e81440, 0x55ca396a, 0x2aab10b6, + 0xb4cc5c34, 0x1141e8ce, 0xa15486af, 0x7c72e993, 0xb3ee1411, 0x636fbc2a, + 0x2ba9c55d, 0x741831f6, 0xce5c3e16, 0x9b87931e, 0xafd6ba33, 0x6c24cf5c, + 0x7a325381, 0x28958677, 0x3b8f4898, 0x6b4bb9af, 0xc4bfe81b, 0x66282193, + 0x61d809cc, 0xfb21a991, 0x487cac60, 0x5dec8032, 0xef845d5d, 0xe98575b1, + 0xdc262302, 0xeb651b88, 0x23893e81, 0xd396acc5, 0x0f6d6ff3, 0x83f44239, + 0x2e0b4482, 0xa4842004, 0x69c8f04a, 0x9e1f9b5e, 0x21c66842, 0xf6e96c9a, + 0x670c9c61, 0xabd388f0, 0x6a51a0d2, 0xd8542f68, 0x960fa728, 0xab5133a3, + 0x6eef0b6c, 0x137a3be4, 0xba3bf050, 0x7efb2a98, 0xa1f1651d, 0x39af0176, + 0x66ca593e, 0x82430e88, 0x8cee8619, 0x456f9fb4, 0x7d84a5c3, 0x3b8b5ebe, + 0xe06f75d8, 0x85c12073, 0x401a449f, 0x56c16aa6, 0x4ed3aa62, 0x363f7706, + 0x1bfedf72, 0x429b023d, 0x37d0d724, 0xd00a1248, 0xdb0fead3, 0x49f1c09b, + 0x075372c9, 0x80991b7b, 0x25d479d8, 0xf6e8def7, 0xe3fe501a, 0xb6794c3b, + 0x976ce0bd, 0x04c006ba, 0xc1a94fb6, 0x409f60c4, 0x5e5c9ec2, 0x196a2463, + 0x68fb6faf, 0x3e6c53b5, 0x1339b2eb, 0x3b52ec6f, 0x6dfc511f, 0x9b30952c, + 0xcc814544, 0xaf5ebd09, 0xbee3d004, 0xde334afd, 0x660f2807, 0x192e4bb3, + 0xc0cba857, 0x45c8740f, 0xd20b5f39, 0xb9d3fbdb, 0x5579c0bd, 0x1a60320a, + 0xd6a100c6, 0x402c7279, 0x679f25fe, 0xfb1fa3cc, 0x8ea5e9f8, 0xdb3222f8, + 0x3c7516df, 0xfd616b15, 0x2f501ec8, 0xad0552ab, 0x323db5fa, 0xfd238760, + 0x53317b48, 0x3e00df82, 0x9e5c57bb, 0xca6f8ca0, 0x1a87562e, 0xdf1769db, + 0xd542a8f6, 0x287effc3, 0xac6732c6, 0x8c4f5573, 0x695b27b0, 0xbbca58c8, + 0xe1ffa35d, 0xb8f011a0, 0x10fa3d98, 0xfd2183b8, 0x4afcb56c, 0x2dd1d35b, + 0x9a53e479, 0xb6f84565, 0xd28e49bc, 0x4bfb9790, 0xe1ddf2da, 0xa4cb7e33, + 0x62fb1341, 0xcee4c6e8, 0xef20cada, 0x36774c01, 0xd07e9efe, 0x2bf11fb4, + 0x95dbda4d, 0xae909198, 0xeaad8e71, 0x6b93d5a0, 0xd08ed1d0, 0xafc725e0, + 0x8e3c5b2f, 0x8e7594b7, 0x8ff6e2fb, 0xf2122b64, 0x8888b812, 0x900df01c, + 0x4fad5ea0, 0x688fc31c, 0xd1cff191, 0xb3a8c1ad, 0x2f2f2218, 0xbe0e1777, + 0xea752dfe, 0x8b021fa1, 0xe5a0cc0f, 0xb56f74e8, 0x18acf3d6, 0xce89e299, + 0xb4a84fe0, 0xfd13e0b7, 0x7cc43b81, 0xd2ada8d9, 0x165fa266, 0x80957705, + 0x93cc7314, 0x211a1477, 0xe6ad2065, 0x77b5fa86, 0xc75442f5, 0xfb9d35cf, + 0xebcdaf0c, 0x7b3e89a0, 0xd6411bd3, 0xae1e7e49, 0x00250e2d, 0x2071b35e, + 0x226800bb, 0x57b8e0af, 0x2464369b, 0xf009b91e, 0x5563911d, 0x59dfa6aa, + 0x78c14389, 0xd95a537f, 0x207d5ba2, 0x02e5b9c5, 0x83260376, 0x6295cfa9, + 0x11c81968, 0x4e734a41, 0xb3472dca, 0x7b14a94a, 0x1b510052, 0x9a532915, + 0xd60f573f, 0xbc9bc6e4, 0x2b60a476, 0x81e67400, 0x08ba6fb5, 0x571be91f, + 0xf296ec6b, 0x2a0dd915, 0xb6636521, 0xe7b9f9b6, 0xff34052e, 0xc5855664, + 0x53b02d5d, 0xa99f8fa1, 0x08ba4799, 0x6e85076a }; + /** Initial value of S-box 2. */ + private static final int[] KS1 = { + 0x4b7a70e9, 0xb5b32944, 0xdb75092e, 0xc4192623, 0xad6ea6b0, 0x49a7df7d, + 0x9cee60b8, 0x8fedb266, 0xecaa8c71, 0x699a17ff, 0x5664526c, 0xc2b19ee1, + 0x193602a5, 0x75094c29, 0xa0591340, 0xe4183a3e, 0x3f54989a, 0x5b429d65, + 0x6b8fe4d6, 0x99f73fd6, 0xa1d29c07, 0xefe830f5, 0x4d2d38e6, 0xf0255dc1, + 0x4cdd2086, 0x8470eb26, 0x6382e9c6, 0x021ecc5e, 0x09686b3f, 0x3ebaefc9, + 0x3c971814, 0x6b6a70a1, 0x687f3584, 0x52a0e286, 0xb79c5305, 0xaa500737, + 0x3e07841c, 0x7fdeae5c, 0x8e7d44ec, 0x5716f2b8, 0xb03ada37, 0xf0500c0d, + 0xf01c1f04, 0x0200b3ff, 0xae0cf51a, 0x3cb574b2, 0x25837a58, 0xdc0921bd, + 0xd19113f9, 0x7ca92ff6, 0x94324773, 0x22f54701, 0x3ae5e581, 0x37c2dadc, + 0xc8b57634, 0x9af3dda7, 0xa9446146, 0x0fd0030e, 0xecc8c73e, 0xa4751e41, + 0xe238cd99, 0x3bea0e2f, 0x3280bba1, 0x183eb331, 0x4e548b38, 0x4f6db908, + 0x6f420d03, 0xf60a04bf, 0x2cb81290, 0x24977c79, 0x5679b072, 0xbcaf89af, + 0xde9a771f, 0xd9930810, 0xb38bae12, 0xdccf3f2e, 0x5512721f, 0x2e6b7124, + 0x501adde6, 0x9f84cd87, 0x7a584718, 0x7408da17, 0xbc9f9abc, 0xe94b7d8c, + 0xec7aec3a, 0xdb851dfa, 0x63094366, 0xc464c3d2, 0xef1c1847, 0x3215d908, + 0xdd433b37, 0x24c2ba16, 0x12a14d43, 0x2a65c451, 0x50940002, 0x133ae4dd, + 0x71dff89e, 0x10314e55, 0x81ac77d6, 0x5f11199b, 0x043556f1, 0xd7a3c76b, + 0x3c11183b, 0x5924a509, 0xf28fe6ed, 0x97f1fbfa, 0x9ebabf2c, 0x1e153c6e, + 0x86e34570, 0xeae96fb1, 0x860e5e0a, 0x5a3e2ab3, 0x771fe71c, 0x4e3d06fa, + 0x2965dcb9, 0x99e71d0f, 0x803e89d6, 0x5266c825, 0x2e4cc978, 0x9c10b36a, + 0xc6150eba, 0x94e2ea78, 0xa5fc3c53, 0x1e0a2df4, 0xf2f74ea7, 0x361d2b3d, + 0x1939260f, 0x19c27960, 0x5223a708, 0xf71312b6, 0xebadfe6e, 0xeac31f66, + 0xe3bc4595, 0xa67bc883, 0xb17f37d1, 0x018cff28, 0xc332ddef, 0xbe6c5aa5, + 0x65582185, 0x68ab9802, 0xeecea50f, 0xdb2f953b, 0x2aef7dad, 0x5b6e2f84, + 0x1521b628, 0x29076170, 0xecdd4775, 0x619f1510, 0x13cca830, 0xeb61bd96, + 0x0334fe1e, 0xaa0363cf, 0xb5735c90, 0x4c70a239, 0xd59e9e0b, 0xcbaade14, + 0xeecc86bc, 0x60622ca7, 0x9cab5cab, 0xb2f3846e, 0x648b1eaf, 0x19bdf0ca, + 0xa02369b9, 0x655abb50, 0x40685a32, 0x3c2ab4b3, 0x319ee9d5, 0xc021b8f7, + 0x9b540b19, 0x875fa099, 0x95f7997e, 0x623d7da8, 0xf837889a, 0x97e32d77, + 0x11ed935f, 0x16681281, 0x0e358829, 0xc7e61fd6, 0x96dedfa1, 0x7858ba99, + 0x57f584a5, 0x1b227263, 0x9b83c3ff, 0x1ac24696, 0xcdb30aeb, 0x532e3054, + 0x8fd948e4, 0x6dbc3128, 0x58ebf2ef, 0x34c6ffea, 0xfe28ed61, 0xee7c3c73, + 0x5d4a14d9, 0xe864b7e3, 0x42105d14, 0x203e13e0, 0x45eee2b6, 0xa3aaabea, + 0xdb6c4f15, 0xfacb4fd0, 0xc742f442, 0xef6abbb5, 0x654f3b1d, 0x41cd2105, + 0xd81e799e, 0x86854dc7, 0xe44b476a, 0x3d816250, 0xcf62a1f2, 0x5b8d2646, + 0xfc8883a0, 0xc1c7b6a3, 0x7f1524c3, 0x69cb7492, 0x47848a0b, 0x5692b285, + 0x095bbf00, 0xad19489d, 0x1462b174, 0x23820e00, 0x58428d2a, 0x0c55f5ea, + 0x1dadf43e, 0x233f7061, 0x3372f092, 0x8d937e41, 0xd65fecf1, 0x6c223bdb, + 0x7cde3759, 0xcbee7460, 0x4085f2a7, 0xce77326e, 0xa6078084, 0x19f8509e, + 0xe8efd855, 0x61d99735, 0xa969a7aa, 0xc50c06c2, 0x5a04abfc, 0x800bcadc, + 0x9e447a2e, 0xc3453484, 0xfdd56705, 0x0e1e9ec9, 0xdb73dbd3, 0x105588cd, + 0x675fda79, 0xe3674340, 0xc5c43465, 0x713e38d8, 0x3d28f89e, 0xf16dff20, + 0x153e21e7, 0x8fb03d4a, 0xe6e39f2b, 0xdb83adf7 }; + /** Initial value of S-box 3. */ + private static final int[] KS2 = { + 0xe93d5a68, 0x948140f7, 0xf64c261c, 0x94692934, 0x411520f7, 0x7602d4f7, + 0xbcf46b2e, 0xd4a20068, 0xd4082471, 0x3320f46a, 0x43b7d4b7, 0x500061af, + 0x1e39f62e, 0x97244546, 0x14214f74, 0xbf8b8840, 0x4d95fc1d, 0x96b591af, + 0x70f4ddd3, 0x66a02f45, 0xbfbc09ec, 0x03bd9785, 0x7fac6dd0, 0x31cb8504, + 0x96eb27b3, 0x55fd3941, 0xda2547e6, 0xabca0a9a, 0x28507825, 0x530429f4, + 0x0a2c86da, 0xe9b66dfb, 0x68dc1462, 0xd7486900, 0x680ec0a4, 0x27a18dee, + 0x4f3ffea2, 0xe887ad8c, 0xb58ce006, 0x7af4d6b6, 0xaace1e7c, 0xd3375fec, + 0xce78a399, 0x406b2a42, 0x20fe9e35, 0xd9f385b9, 0xee39d7ab, 0x3b124e8b, + 0x1dc9faf7, 0x4b6d1856, 0x26a36631, 0xeae397b2, 0x3a6efa74, 0xdd5b4332, + 0x6841e7f7, 0xca7820fb, 0xfb0af54e, 0xd8feb397, 0x454056ac, 0xba489527, + 0x55533a3a, 0x20838d87, 0xfe6ba9b7, 0xd096954b, 0x55a867bc, 0xa1159a58, + 0xcca92963, 0x99e1db33, 0xa62a4a56, 0x3f3125f9, 0x5ef47e1c, 0x9029317c, + 0xfdf8e802, 0x04272f70, 0x80bb155c, 0x05282ce3, 0x95c11548, 0xe4c66d22, + 0x48c1133f, 0xc70f86dc, 0x07f9c9ee, 0x41041f0f, 0x404779a4, 0x5d886e17, + 0x325f51eb, 0xd59bc0d1, 0xf2bcc18f, 0x41113564, 0x257b7834, 0x602a9c60, + 0xdff8e8a3, 0x1f636c1b, 0x0e12b4c2, 0x02e1329e, 0xaf664fd1, 0xcad18115, + 0x6b2395e0, 0x333e92e1, 0x3b240b62, 0xeebeb922, 0x85b2a20e, 0xe6ba0d99, + 0xde720c8c, 0x2da2f728, 0xd0127845, 0x95b794fd, 0x647d0862, 0xe7ccf5f0, + 0x5449a36f, 0x877d48fa, 0xc39dfd27, 0xf33e8d1e, 0x0a476341, 0x992eff74, + 0x3a6f6eab, 0xf4f8fd37, 0xa812dc60, 0xa1ebddf8, 0x991be14c, 0xdb6e6b0d, + 0xc67b5510, 0x6d672c37, 0x2765d43b, 0xdcd0e804, 0xf1290dc7, 0xcc00ffa3, + 0xb5390f92, 0x690fed0b, 0x667b9ffb, 0xcedb7d9c, 0xa091cf0b, 0xd9155ea3, + 0xbb132f88, 0x515bad24, 0x7b9479bf, 0x763bd6eb, 0x37392eb3, 0xcc115979, + 0x8026e297, 0xf42e312d, 0x6842ada7, 0xc66a2b3b, 0x12754ccc, 0x782ef11c, + 0x6a124237, 0xb79251e7, 0x06a1bbe6, 0x4bfb6350, 0x1a6b1018, 0x11caedfa, + 0x3d25bdd8, 0xe2e1c3c9, 0x44421659, 0x0a121386, 0xd90cec6e, 0xd5abea2a, + 0x64af674e, 0xda86a85f, 0xbebfe988, 0x64e4c3fe, 0x9dbc8057, 0xf0f7c086, + 0x60787bf8, 0x6003604d, 0xd1fd8346, 0xf6381fb0, 0x7745ae04, 0xd736fccc, + 0x83426b33, 0xf01eab71, 0xb0804187, 0x3c005e5f, 0x77a057be, 0xbde8ae24, + 0x55464299, 0xbf582e61, 0x4e58f48f, 0xf2ddfda2, 0xf474ef38, 0x8789bdc2, + 0x5366f9c3, 0xc8b38e74, 0xb475f255, 0x46fcd9b9, 0x7aeb2661, 0x8b1ddf84, + 0x846a0e79, 0x915f95e2, 0x466e598e, 0x20b45770, 0x8cd55591, 0xc902de4c, + 0xb90bace1, 0xbb8205d0, 0x11a86248, 0x7574a99e, 0xb77f19b6, 0xe0a9dc09, + 0x662d09a1, 0xc4324633, 0xe85a1f02, 0x09f0be8c, 0x4a99a025, 0x1d6efe10, + 0x1ab93d1d, 0x0ba5a4df, 0xa186f20f, 0x2868f169, 0xdcb7da83, 0x573906fe, + 0xa1e2ce9b, 0x4fcd7f52, 0x50115e01, 0xa70683fa, 0xa002b5c4, 0x0de6d027, + 0x9af88c27, 0x773f8641, 0xc3604c06, 0x61a806b5, 0xf0177a28, 0xc0f586e0, + 0x006058aa, 0x30dc7d62, 0x11e69ed7, 0x2338ea63, 0x53c2dd94, 0xc2c21634, + 0xbbcbee56, 0x90bcb6de, 0xebfc7da1, 0xce591d76, 0x6f05e409, 0x4b7c0188, + 0x39720a3d, 0x7c927c24, 0x86e3725f, 0x724d9db9, 0x1ac15bb4, 0xd39eb8fc, + 0xed545578, 0x08fca5b5, 0xd83d7cd3, 0x4dad0fc4, 0x1e50ef5e, 0xb161e6f8, + 0xa28514d9, 0x6c51133c, 0x6fd5c7e7, 0x56e14ec4, 0x362abfce, 0xddc6c837, + 0xd79a3234, 0x92638212, 0x670efa8e, 0x406000e0 }; + /** Initial value of S-box 4. */ + private static final int[] KS3 = { + 0x3a39ce37, 0xd3faf5cf, 0xabc27737, 0x5ac52d1b, 0x5cb0679e, 0x4fa33742, + 0xd3822740, 0x99bc9bbe, 0xd5118e9d, 0xbf0f7315, 0xd62d1c7e, 0xc700c47b, + 0xb78c1b6b, 0x21a19045, 0xb26eb1be, 0x6a366eb4, 0x5748ab2f, 0xbc946e79, + 0xc6a376d2, 0x6549c2c8, 0x530ff8ee, 0x468dde7d, 0xd5730a1d, 0x4cd04dc6, + 0x2939bbdb, 0xa9ba4650, 0xac9526e8, 0xbe5ee304, 0xa1fad5f0, 0x6a2d519a, + 0x63ef8ce2, 0x9a86ee22, 0xc089c2b8, 0x43242ef6, 0xa51e03aa, 0x9cf2d0a4, + 0x83c061ba, 0x9be96a4d, 0x8fe51550, 0xba645bd6, 0x2826a2f9, 0xa73a3ae1, + 0x4ba99586, 0xef5562e9, 0xc72fefd3, 0xf752f7da, 0x3f046f69, 0x77fa0a59, + 0x80e4a915, 0x87b08601, 0x9b09e6ad, 0x3b3ee593, 0xe990fd5a, 0x9e34d797, + 0x2cf0b7d9, 0x022b8b51, 0x96d5ac3a, 0x017da67d, 0xd1cf3ed6, 0x7c7d2d28, + 0x1f9f25cf, 0xadf2b89b, 0x5ad6b472, 0x5a88f54c, 0xe029ac71, 0xe019a5e6, + 0x47b0acfd, 0xed93fa9b, 0xe8d3c48d, 0x283b57cc, 0xf8d56629, 0x79132e28, + 0x785f0191, 0xed756055, 0xf7960e44, 0xe3d35e8c, 0x15056dd4, 0x88f46dba, + 0x03a16125, 0x0564f0bd, 0xc3eb9e15, 0x3c9057a2, 0x97271aec, 0xa93a072a, + 0x1b3f6d9b, 0x1e6321f5, 0xf59c66fb, 0x26dcf319, 0x7533d928, 0xb155fdf5, + 0x03563482, 0x8aba3cbb, 0x28517711, 0xc20ad9f8, 0xabcc5167, 0xccad925f, + 0x4de81751, 0x3830dc8e, 0x379d5862, 0x9320f991, 0xea7a90c2, 0xfb3e7bce, + 0x5121ce64, 0x774fbe32, 0xa8b6e37e, 0xc3293d46, 0x48de5369, 0x6413e680, + 0xa2ae0810, 0xdd6db224, 0x69852dfd, 0x09072166, 0xb39a460a, 0x6445c0dd, + 0x586cdecf, 0x1c20c8ae, 0x5bbef7dd, 0x1b588d40, 0xccd2017f, 0x6bb4e3bb, + 0xdda26a7e, 0x3a59ff45, 0x3e350a44, 0xbcb4cdd5, 0x72eacea8, 0xfa6484bb, + 0x8d6612ae, 0xbf3c6f47, 0xd29be463, 0x542f5d9e, 0xaec2771b, 0xf64e6370, + 0x740e0d8d, 0xe75b1357, 0xf8721671, 0xaf537d5d, 0x4040cb08, 0x4eb4e2cc, + 0x34d2466a, 0x0115af84, 0xe1b00428, 0x95983a1d, 0x06b89fb4, 0xce6ea048, + 0x6f3f3b82, 0x3520ab82, 0x011a1d4b, 0x277227f8, 0x611560b1, 0xe7933fdc, + 0xbb3a792b, 0x344525bd, 0xa08839e1, 0x51ce794b, 0x2f32c9b7, 0xa01fbac9, + 0xe01cc87e, 0xbcc7d1f6, 0xcf0111c3, 0xa1e8aac7, 0x1a908749, 0xd44fbd9a, + 0xd0dadecb, 0xd50ada38, 0x0339c32a, 0xc6913667, 0x8df9317c, 0xe0b12b4f, + 0xf79e59b7, 0x43f5bb3a, 0xf2d519ff, 0x27d9459c, 0xbf97222c, 0x15e6fc2a, + 0x0f91fc71, 0x9b941525, 0xfae59361, 0xceb69ceb, 0xc2a86459, 0x12baa8d1, + 0xb6c1075e, 0xe3056a0c, 0x10d25065, 0xcb03a442, 0xe0ec6e0e, 0x1698db3b, + 0x4c98a0be, 0x3278e964, 0x9f1f9532, 0xe0d392df, 0xd3a0342b, 0x8971f21e, + 0x1b0a7441, 0x4ba3348c, 0xc5be7120, 0xc37632d8, 0xdf359f8d, 0x9b992f2e, + 0xe60b6f47, 0x0fe3f11d, 0xe54cda54, 0x1edad891, 0xce6279cf, 0xcd3e7e6f, + 0x1618b166, 0xfd2c1d05, 0x848fd2c5, 0xf6fb2299, 0xf523f357, 0xa6327623, + 0x93a83531, 0x56cccd02, 0xacf08162, 0x5a75ebb5, 0x6e163697, 0x88d273cc, + 0xde966292, 0x81b949d0, 0x4c50901b, 0x71c65614, 0xe6c6c7bd, 0x327a140a, + 0x45e1d006, 0xc3f27b9a, 0xc9aa53fd, 0x62a80f00, 0xbb25bfe2, 0x35bdd2f6, + 0x71126905, 0xb2040222, 0xb6cbcf7c, 0xcd769c2b, 0x53113ec0, 0x1640e3d3, + 0x38abbd60, 0x2547adf0, 0xba38209c, 0xf746ce76, 0x77afa1c5, 0x20756060, + 0x85cbfe4e, 0x8ae88dd8, 0x7aaaf9b0, 0x4cf9aa7e, 0x1948c25c, 0x02fb8a8c, + 0x01c36ae4, 0xd6ebe1f9, 0x90d4f869, 0xa65cdea0, 0x3f09252d, 0xc208e69f, + 0xb74e6132, 0xce77e25b, 0x578fdfe3, 0x3ac372e6 }; + /** Cache of the self test. */ + private static Boolean valid; + /** + * Test vector, as published in + * href="http://www.counterpane.com/vectors.txt">http://www.counterpane.com/vectors.txt</a>. + * + * KEY=0000000000000000 + * PT=0000000000000000 + * CT=4EF997456198DD78 + */ + private static final byte[] TV_KEY = Util.toBytesFromString("0000000000000000"); + private static final byte[] TV_CT = Util.toBytesFromString("4EF997456198DD78"); + + public Blowfish() + { + super(Registry.BLOWFISH_CIPHER, DEFAULT_BLOCK_SIZE, DEFAULT_KEY_SIZE); + } + + public Object clone() + { + Blowfish result = new Blowfish(); + result.currentBlockSize = currentBlockSize; + return result; + } + + public Iterator keySizes() + { + return new Sequence(8, MAX_KEY_LENGTH, 8).iterator(); + } + + public Iterator blockSizes() + { + return Collections.singleton(Integer.valueOf(DEFAULT_BLOCK_SIZE)).iterator(); + } + + public Object makeKey(byte[] k, int bs) + { + Context ctx = new Context(); + System.arraycopy(P, 0, ctx.p, 0, P.length); + System.arraycopy(KS0, 0, ctx.s0, 0, KS0.length); + System.arraycopy(KS1, 0, ctx.s1, 0, KS1.length); + System.arraycopy(KS2, 0, ctx.s2, 0, KS2.length); + System.arraycopy(KS3, 0, ctx.s3, 0, KS3.length); + // XOR the key with the P-box + int l = 0; + for (int i = 0; i < ctx.p.length; i++) + { + int data = 0; + for (int j = 0; j < 4; j++) + { + data = (data << 8) | (k[l++] & 0xff); + if (l >= k.length) + l = 0; + } + ctx.p[i] ^= data; + } + // We swap the left and right words here only, so we can avoid + // swapping altogether during encryption/decryption. + int t; + Block x = new Block(); + x.left = x.right = 0; + for (int i = 0; i < ctx.p.length; i += 2) + { + blowfishEncrypt(x, ctx); + ctx.p[i] = x.right; + ctx.p[i + 1] = x.left; + t = x.right; + x.right = x.left; + x.left = t; + } + for (int i = 0; i < ctx.s0.length; i += 2) + { + blowfishEncrypt(x, ctx); + ctx.s0[i] = x.right; + ctx.s0[i + 1] = x.left; + t = x.right; + x.right = x.left; + x.left = t; + } + for (int i = 0; i < ctx.s1.length; i += 2) + { + blowfishEncrypt(x, ctx); + ctx.s1[i] = x.right; + ctx.s1[i + 1] = x.left; + t = x.right; + x.right = x.left; + x.left = t; + } + for (int i = 0; i < ctx.s2.length; i += 2) + { + blowfishEncrypt(x, ctx); + ctx.s2[i] = x.right; + ctx.s2[i + 1] = x.left; + t = x.right; + x.right = x.left; + x.left = t; + } + for (int i = 0; i < ctx.s3.length; i += 2) + { + blowfishEncrypt(x, ctx); + ctx.s3[i] = x.right; + ctx.s3[i + 1] = x.left; + t = x.right; + x.right = x.left; + x.left = t; + } + x.left = x.right = 0; + return ctx; + } + + public void encrypt(byte[] in, int i, byte[] out, int o, Object k, int bs) + { + Block x = new Block(); + x.left = (in[i ] & 0xff) << 24 + | (in[i + 1] & 0xff) << 16 + | (in[i + 2] & 0xff) << 8 + | (in[i + 3] & 0xff); + x.right = (in[i + 4] & 0xff) << 24 + | (in[i + 5] & 0xff) << 16 + | (in[i + 6] & 0xff) << 8 + | (in[i + 7] & 0xff); + blowfishEncrypt(x, (Context) k); + out[o ] = (byte)(x.right >>> 24); + out[o + 1] = (byte)(x.right >>> 16); + out[o + 2] = (byte)(x.right >>> 8); + out[o + 3] = (byte) x.right; + out[o + 4] = (byte)(x.left >>> 24); + out[o + 5] = (byte)(x.left >>> 16); + out[o + 6] = (byte)(x.left >>> 8); + out[o + 7] = (byte) x.left; + x.left = x.right = 0; + } + + public void decrypt(byte[] in, int i, byte[] out, int o, Object k, int bs) + { + Block x = new Block(); + x.left = (in[i ] & 0xff) << 24 + | (in[i + 1] & 0xff) << 16 + | (in[i + 2] & 0xff) << 8 + | (in[i + 3] & 0xff); + x.right = (in[i + 4] & 0xff) << 24 + | (in[i + 5] & 0xff) << 16 + | (in[i + 6] & 0xff) << 8 + | (in[i + 7] & 0xff); + blowfishDecrypt(x, (Context) k); + out[o ] = (byte)(x.right >>> 24); + out[o + 1] = (byte)(x.right >>> 16); + out[o + 2] = (byte)(x.right >>> 8); + out[o + 3] = (byte) x.right; + out[o + 4] = (byte)(x.left >>> 24); + out[o + 5] = (byte)(x.left >>> 16); + out[o + 6] = (byte)(x.left >>> 8); + out[o + 7] = (byte) x.left; + x.left = x.right = 0; + } + + /** Encrypt a single pair of 32-bit integers. */ + private void blowfishEncrypt(Block x, Context ctx) + { + int[] p = ctx.p; + int[] s0 = ctx.s0, s1 = ctx.s1, s2 = ctx.s2, s3 = ctx.s3; + x.left ^= p[0]; + x.right ^= ((s0[x.left >>> 24 ] + + s1[x.left >>> 16 & 0xff]) + ^ s2[x.left >>> 8 & 0xff]) + + s3[x.left & 0xff] ^ p[1]; + x.left ^= ((s0[x.right >>> 24 ] + + s1[x.right >>> 16 & 0xff]) + ^ s2[x.right >>> 8 & 0xff]) + + s3[x.right & 0xff] ^ p[2]; + x.right ^= ((s0[x.left >>> 24 ] + + s1[x.left >>> 16 & 0xff]) + ^ s2[x.left >>> 8 & 0xff]) + + s3[x.left & 0xff] ^ p[3]; + x.left ^= ((s0[x.right >>> 24 ] + + s1[x.right >>> 16 & 0xff]) + ^ s2[x.right >>> 8 & 0xff]) + + s3[x.right & 0xff] ^ p[4]; + x.right ^= ((s0[x.left >>> 24 ] + + s1[x.left >>> 16 & 0xff]) + ^ s2[x.left >>> 8 & 0xff]) + + s3[x.left & 0xff] ^ p[5]; + x.left ^= ((s0[x.right >>> 24 ] + + s1[x.right >>> 16 & 0xff]) + ^ s2[x.right >>> 8 & 0xff]) + + s3[x.right & 0xff] ^ p[6]; + x.right ^= ((s0[x.left >>> 24 ] + + s1[x.left >>> 16 & 0xff]) + ^ s2[x.left >>> 8 & 0xff]) + + s3[x.left & 0xff] ^ p[7]; + x.left ^= ((s0[x.right >>> 24 ] + + s1[x.right >>> 16 & 0xff]) + ^ s2[x.right >>> 8 & 0xff]) + + s3[x.right & 0xff] ^ p[8]; + x.right ^= ((s0[x.left >>> 24 ] + + s1[x.left >>> 16 & 0xff]) + ^ s2[x.left >>> 8 & 0xff]) + + s3[x.left & 0xff] ^ p[9]; + x.left ^= ((s0[x.right >>> 24 ] + + s1[x.right >>> 16 & 0xff]) + ^ s2[x.right >>> 8 & 0xff]) + + s3[x.right & 0xff] ^ p[10]; + x.right ^= ((s0[x.left >>> 24 ] + + s1[x.left >>> 16 & 0xff]) + ^ s2[x.left >>> 8 & 0xff]) + + s3[x.left & 0xff] ^ p[11]; + x.left ^= ((s0[x.right >>> 24 ] + + s1[x.right >>> 16 & 0xff]) + ^ s2[x.right >>> 8 & 0xff]) + + s3[x.right & 0xff] ^ p[12]; + x.right ^= ((s0[x.left >>> 24 ] + + s1[x.left >>> 16 & 0xff]) + ^ s2[x.left >>> 8 & 0xff]) + + s3[x.left & 0xff] ^ p[13]; + x.left ^= ((s0[x.right >>> 24 ] + + s1[x.right >>> 16 & 0xff]) + ^ s2[x.right >>> 8 & 0xff]) + + s3[x.right & 0xff] ^ p[14]; + x.right ^= ((s0[x.left >>> 24 ] + + s1[x.left >>> 16 & 0xff]) + ^ s2[x.left >>> 8 & 0xff]) + + s3[x.left & 0xff] ^ p[15]; + x.left ^= ((s0[x.right >>> 24 ] + + s1[x.right >>> 16 & 0xff]) + ^ s2[x.right >>> 8 & 0xff]) + + s3[x.right & 0xff] ^ p[16]; + x.right ^= p[17]; + } + + /** Decrypt a single pair of 32-bit integers. */ + private void blowfishDecrypt(Block x, Context ctx) + { + int[] p = ctx.p; + int[] s0 = ctx.s0, s1 = ctx.s1, s2 = ctx.s2, s3 = ctx.s3; + x.left ^= p[17]; + x.right ^= ((s0[x.left >>> 24 ] + + s1[x.left >>> 16 & 0xff]) + ^ s2[x.left >>> 8 & 0xff]) + + s3[x.left & 0xff] ^ p[16]; + x.left ^= ((s0[x.right >>> 24 ] + + s1[x.right >>> 16 & 0xff]) + ^ s2[x.right >>> 8 & 0xff]) + + s3[x.right & 0xff] ^ p[15]; + x.right ^= ((s0[x.left >>> 24 ] + + s1[x.left >>> 16 & 0xff]) + ^ s2[x.left >>> 8 & 0xff]) + + s3[x.left & 0xff] ^ p[14]; + x.left ^= ((s0[x.right >>> 24 ] + + s1[x.right >>> 16 & 0xff]) + ^ s2[x.right >>> 8 & 0xff]) + + s3[x.right & 0xff] ^ p[13]; + x.right ^= ((s0[x.left >>> 24 ] + + s1[x.left >>> 16 & 0xff]) + ^ s2[x.left >>> 8 & 0xff]) + + s3[x.left & 0xff] ^ p[12]; + x.left ^= ((s0[x.right >>> 24 ] + + s1[x.right >>> 16 & 0xff]) + ^ s2[x.right >>> 8 & 0xff]) + + s3[x.right & 0xff] ^ p[11]; + x.right ^= ((s0[x.left >>> 24 ] + + s1[x.left >>> 16 & 0xff]) + ^ s2[x.left >>> 8 & 0xff]) + + s3[x.left & 0xff] ^ p[10]; + x.left ^= ((s0[x.right >>> 24 ] + + s1[x.right >>> 16 & 0xff]) + ^ s2[x.right >>> 8 & 0xff]) + + s3[x.right & 0xff] ^ p[9]; + x.right ^= ((s0[x.left >>> 24] + + s1[x.left >>> 16 & 0xff]) + ^ s2[x.left >>> 8 & 0xff]) + + s3[x.left & 0xff] ^ p[8]; + x.left ^= ((s0[x.right >>> 24 ] + + s1[x.right >>> 16 & 0xff]) + ^ s2[x.right >>> 8 & 0xff]) + + s3[x.right & 0xff] ^ p[7]; + x.right ^= ((s0[x.left >>> 24 ] + + s1[x.left >>> 16 & 0xff]) + ^ s2[x.left >>> 8 & 0xff]) + + s3[x.left & 0xff] ^ p[6]; + x.left ^= ((s0[x.right >>> 24 ] + + s1[x.right >>> 16 & 0xff]) + ^ s2[x.right >>> 8 & 0xff]) + + s3[x.right & 0xff] ^ p[5]; + x.right ^= ((s0[x.left >>> 24 ] + + s1[x.left >>> 16 & 0xff]) + ^ s2[x.left >>> 8 & 0xff]) + + s3[x.left & 0xff] ^ p[4]; + x.left ^= ((s0[x.right >>> 24 ] + + s1[x.right >>> 16 & 0xff]) + ^ s2[x.right >>> 8 & 0xff]) + + s3[x.right & 0xff] ^ p[3]; + x.right ^= ((s0[x.left >>> 24 ] + + s1[x.left >>> 16 & 0xff]) + ^ s2[x.left >>> 8 & 0xff]) + + s3[x.left & 0xff] ^ p[2]; + x.left ^= ((s0[x.right >>> 24 ] + + s1[x.right >>> 16 & 0xff]) + ^ s2[x.right >>> 8 & 0xff]) + + s3[x.right & 0xff] ^ p[1]; + x.right ^= p[0]; + } + + public boolean selfTest() + { + if (valid == null) + { + boolean result = super.selfTest(); // symmetry + if (result) + result = testKat(TV_KEY, TV_CT); + valid = Boolean.valueOf(result); + } + return valid.booleanValue(); + } + + /** A simple wrapper for the P- and S-boxes. */ + private class Context + implements Cloneable + { + /** The P-array. */ + int[] p, s0, s1, s2, s3; + + /** Default 0-arguments constructor. */ + Context() + { + p = new int[18]; + s0 = new int[256]; + s1 = new int[256]; + s2 = new int[256]; + s3 = new int[256]; + } + + /** + * Private constructor for cloneing. + * + * @param that The instance being cloned. + */ + private Context(Context that) + { + this.p = (int[]) that.p.clone(); + this.s0 = (int[]) that.s0.clone(); + this.s1 = (int[]) that.s1.clone(); + this.s2 = (int[]) that.s2.clone(); + this.s3 = (int[]) that.s3.clone(); + } + + public Object clone() + { + return new Context(this); + } + } + + private class Block + { + int left, right; + } +} diff --git a/libjava/classpath/gnu/javax/crypto/cipher/Cast5.java b/libjava/classpath/gnu/javax/crypto/cipher/Cast5.java new file mode 100644 index 000000000..47b29226f --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/cipher/Cast5.java @@ -0,0 +1,987 @@ +/* Cast5.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.cipher; + +import gnu.java.security.Registry; +import gnu.java.security.util.Util; + +import java.security.InvalidKeyException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Iterator; + +/** + * An implmenetation of the <code>CAST5</code> (a.k.a. CAST-128) algorithm, + * as per <i>RFC-2144</i>, dated May 1997. + * <p> + * In this RFC, <i>Carlisle Adams</i> (the CA in CAST, ST stands for + * <i>Stafford Tavares</i>) describes CAST5 as: + * <blockquote> + * "...a DES-like Substitution-Permutation Network (SPN) cryptosystem which + * appears to have good resistance to differential cryptanalysis, linear + * cryptanalysis, and related-key cryptanalysis. This cipher also possesses + * a number of other desirable cryptographic properties, including avalanche, + * Strict Avalanche Criterion (SAC), Bit Independence Criterion (BIC), no + * complementation property, and an absence of weak and semi-weak keys." + * </blockquote> + * <p> + * <code>CAST5</code> is a symmetric block cipher with a block-size of 8 + * bytes and a variable key-size of up to 128 bits. Its authors, and their + * employer (Entrust Technologies, a Nortel majority-owned company), made it + * available worldwide on a royalty-free basis for commercial and non-commercial + * uses. + * <p> + * The <code>CAST5</code> encryption algorithm has been designed to allow a + * key size that can vary from <code>40</code> bits to <code>128</code> bits, + * in 8-bit increments (that is, the allowable key sizes are <code>40, 48, 56, + * 64, ..., 112, 120,</code> and <code>128</code> bits. For variable keysize + * operation, the specification is as follows: + * <ol> + * <li>For key sizes up to and including <code>80</code> bits (i.e., + * <code>40, 48, 56, 64, 72,</code> and <code>80</code> bits), the algorithm + * is exactly as specified but uses <code>12</code> rounds instead of + * <code>16</code>;</li> + * <li>For key sizes greater than <code>80</code> bits, the algorithm uses + * the full <code>16</code> rounds;</li> + * <li>For key sizes less than <code>128</code> bits, the key is padded with + * zero bytes (in the rightmost, or least significant, positions) out to + * <code>128</code> bits (since the <code>CAST5</code> key schedule assumes + * an input key of <code>128</code> bits).</li> + * </ol> + * <p> + * References: + * <ol> + * <li><a href="http://www.ietf.org/rfc/rfc2144.txt">The CAST-128 Encryption + * Algorithm</a>.<br> + * <a href="mailto:cadams@entrust.com">Carlisle Adams</a>.</li> + * </ol> + */ +public class Cast5 + extends BaseCipher +{ + private static final int DEFAULT_BLOCK_SIZE = 8; // in bytes + private static final int DEFAULT_KEY_SIZE = 5; // in bytes + /** + * KAT vector (from rfc-2144): + * 40-bit key = 01 23 45 67 12 + * = 01 23 45 67 12 00 00 00 00 00 00 00 00 00 00 00 + * plaintext = 01 23 45 67 89 AB CD EF + * ciphertext = 7A C8 16 D1 6E 9B 30 2E + */ + private static final byte[] KAT_KEY = Util.toBytesFromString("0123456712"); + private static final byte[] KAT_PT = Util.toBytesFromString("0123456789ABCDEF"); + private static final byte[] KAT_CT = Util.toBytesFromString("7AC816D16E9B302E"); + /** caches the result of the correctness test, once executed. */ + private static Boolean valid; + // CAST5 S-boxes + private static final int[] S1 = { + 0x30FB40D4, 0x9FA0FF0B, 0x6BECCD2F, 0x3F258C7A, 0x1E213F2F, 0x9C004DD3, + 0x6003E540, 0xCF9FC949, 0xBFD4AF27, 0x88BBBDB5, 0xE2034090, 0x98D09675, + 0x6E63A0E0, 0x15C361D2, 0xC2E7661D, 0x22D4FF8E, 0x28683B6F, 0xC07FD059, + 0xFF2379C8, 0x775F50E2, 0x43C340D3, 0xDF2F8656, 0x887CA41A, 0xA2D2BD2D, + 0xA1C9E0D6, 0x346C4819, 0x61B76D87, 0x22540F2F, 0x2ABE32E1, 0xAA54166B, + 0x22568E3A, 0xA2D341D0, 0x66DB40C8, 0xA784392F, 0x004DFF2F, 0x2DB9D2DE, + 0x97943FAC, 0x4A97C1D8, 0x527644B7, 0xB5F437A7, 0xB82CBAEF, 0xD751D159, + 0x6FF7F0ED, 0x5A097A1F, 0x827B68D0, 0x90ECF52E, 0x22B0C054, 0xBC8E5935, + 0x4B6D2F7F, 0x50BB64A2, 0xD2664910, 0xBEE5812D, 0xB7332290, 0xE93B159F, + 0xB48EE411, 0x4BFF345D, 0xFD45C240, 0xAD31973F, 0xC4F6D02E, 0x55FC8165, + 0xD5B1CAAD, 0xA1AC2DAE, 0xA2D4B76D, 0xC19B0C50, 0x882240F2, 0x0C6E4F38, + 0xA4E4BFD7, 0x4F5BA272, 0x564C1D2F, 0xC59C5319, 0xB949E354, 0xB04669FE, + 0xB1B6AB8A, 0xC71358DD, 0x6385C545, 0x110F935D, 0x57538AD5, 0x6A390493, + 0xE63D37E0, 0x2A54F6B3, 0x3A787D5F, 0x6276A0B5, 0x19A6FCDF, 0x7A42206A, + 0x29F9D4D5, 0xF61B1891, 0xBB72275E, 0xAA508167, 0x38901091, 0xC6B505EB, + 0x84C7CB8C, 0x2AD75A0F, 0x874A1427, 0xA2D1936B, 0x2AD286AF, 0xAA56D291, + 0xD7894360, 0x425C750D, 0x93B39E26, 0x187184C9, 0x6C00B32D, 0x73E2BB14, + 0xA0BEBC3C, 0x54623779, 0x64459EAB, 0x3F328B82, 0x7718CF82, 0x59A2CEA6, + 0x04EE002E, 0x89FE78E6, 0x3FAB0950, 0x325FF6C2, 0x81383F05, 0x6963C5C8, + 0x76CB5AD6, 0xD49974C9, 0xCA180DCF, 0x380782D5, 0xC7FA5CF6, 0x8AC31511, + 0x35E79E13, 0x47DA91D0, 0xF40F9086, 0xA7E2419E, 0x31366241, 0x051EF495, + 0xAA573B04, 0x4A805D8D, 0x548300D0, 0x00322A3C, 0xBF64CDDF, 0xBA57A68E, + 0x75C6372B, 0x50AFD341, 0xA7C13275, 0x915A0BF5, 0x6B54BFAB, 0x2B0B1426, + 0xAB4CC9D7, 0x449CCD82, 0xF7FBF265, 0xAB85C5F3, 0x1B55DB94, 0xAAD4E324, + 0xCFA4BD3F, 0x2DEAA3E2, 0x9E204D02, 0xC8BD25AC, 0xEADF55B3, 0xD5BD9E98, + 0xE31231B2, 0x2AD5AD6C, 0x954329DE, 0xADBE4528, 0xD8710F69, 0xAA51C90F, + 0xAA786BF6, 0x22513F1E, 0xAA51A79B, 0x2AD344CC, 0x7B5A41F0, 0xD37CFBAD, + 0x1B069505, 0x41ECE491, 0xB4C332E6, 0x032268D4, 0xC9600ACC, 0xCE387E6D, + 0xBF6BB16C, 0x6A70FB78, 0x0D03D9C9, 0xD4DF39DE, 0xE01063DA, 0x4736F464, + 0x5AD328D8, 0xB347CC96, 0x75BB0FC3, 0x98511BFB, 0x4FFBCC35, 0xB58BCF6A, + 0xE11F0ABC, 0xBFC5FE4A, 0xA70AEC10, 0xAC39570A, 0x3F04442F, 0x6188B153, + 0xE0397A2E, 0x5727CB79, 0x9CEB418F, 0x1CACD68D, 0x2AD37C96, 0x0175CB9D, + 0xC69DFF09, 0xC75B65F0, 0xD9DB40D8, 0xEC0E7779, 0x4744EAD4, 0xB11C3274, + 0xDD24CB9E, 0x7E1C54BD, 0xF01144F9, 0xD2240EB1, 0x9675B3FD, 0xA3AC3755, + 0xD47C27AF, 0x51C85F4D, 0x56907596, 0xA5BB15E6, 0x580304F0, 0xCA042CF1, + 0x011A37EA, 0x8DBFAADB, 0x35BA3E4A, 0x3526FFA0, 0xC37B4D09, 0xBC306ED9, + 0x98A52666, 0x5648F725, 0xFF5E569D, 0x0CED63D0, 0x7C63B2CF, 0x700B45E1, + 0xD5EA50F1, 0x85A92872, 0xAF1FBDA7, 0xD4234870, 0xA7870BF3, 0x2D3B4D79, + 0x42E04198, 0x0CD0EDE7, 0x26470DB8, 0xF881814C, 0x474D6AD7, 0x7C0C5E5C, + 0xD1231959, 0x381B7298, 0xF5D2F4DB, 0xAB838653, 0x6E2F1E23, 0x83719C9E, + 0xBD91E046, 0x9A56456E, 0xDC39200C, 0x20C8C571, 0x962BDA1C, 0xE1E696FF, + 0xB141AB08, 0x7CCA89B9, 0x1A69E783, 0x02CC4843, 0xA2F7C579, 0x429EF47D, + 0x427B169C, 0x5AC9F049, 0xDD8F0F00, 0x5C8165BF }; + private static final int[] S2 = { + 0x1F201094, 0xEF0BA75B, 0x69E3CF7E, 0x393F4380, 0xFE61CF7A, 0xEEC5207A, + 0x55889C94, 0x72FC0651, 0xADA7EF79, 0x4E1D7235, 0xD55A63CE, 0xDE0436BA, + 0x99C430EF, 0x5F0C0794, 0x18DCDB7D, 0xA1D6EFF3, 0xA0B52F7B, 0x59E83605, + 0xEE15B094, 0xE9FFD909, 0xDC440086, 0xEF944459, 0xBA83CCB3, 0xE0C3CDFB, + 0xD1DA4181, 0x3B092AB1, 0xF997F1C1, 0xA5E6CF7B, 0x01420DDB, 0xE4E7EF5B, + 0x25A1FF41, 0xE180F806, 0x1FC41080, 0x179BEE7A, 0xD37AC6A9, 0xFE5830A4, + 0x98DE8B7F, 0x77E83F4E, 0x79929269, 0x24FA9F7B, 0xE113C85B, 0xACC40083, + 0xD7503525, 0xF7EA615F, 0x62143154, 0x0D554B63, 0x5D681121, 0xC866C359, + 0x3D63CF73, 0xCEE234C0, 0xD4D87E87, 0x5C672B21, 0x071F6181, 0x39F7627F, + 0x361E3084, 0xE4EB573B, 0x602F64A4, 0xD63ACD9C, 0x1BBC4635, 0x9E81032D, + 0x2701F50C, 0x99847AB4, 0xA0E3DF79, 0xBA6CF38C, 0x10843094, 0x2537A95E, + 0xF46F6FFE, 0xA1FF3B1F, 0x208CFB6A, 0x8F458C74, 0xD9E0A227, 0x4EC73A34, + 0xFC884F69, 0x3E4DE8DF, 0xEF0E0088, 0x3559648D, 0x8A45388C, 0x1D804366, + 0x721D9BFD, 0xA58684BB, 0xE8256333, 0x844E8212, 0x128D8098, 0xFED33FB4, + 0xCE280AE1, 0x27E19BA5, 0xD5A6C252, 0xE49754BD, 0xC5D655DD, 0xEB667064, + 0x77840B4D, 0xA1B6A801, 0x84DB26A9, 0xE0B56714, 0x21F043B7, 0xE5D05860, + 0x54F03084, 0x066FF472, 0xA31AA153, 0xDADC4755, 0xB5625DBF, 0x68561BE6, + 0x83CA6B94, 0x2D6ED23B, 0xECCF01DB, 0xA6D3D0BA, 0xB6803D5C, 0xAF77A709, + 0x33B4A34C, 0x397BC8D6, 0x5EE22B95, 0x5F0E5304, 0x81ED6F61, 0x20E74364, + 0xB45E1378, 0xDE18639B, 0x881CA122, 0xB96726D1, 0x8049A7E8, 0x22B7DA7B, + 0x5E552D25, 0x5272D237, 0x79D2951C, 0xC60D894C, 0x488CB402, 0x1BA4FE5B, + 0xA4B09F6B, 0x1CA815CF, 0xA20C3005, 0x8871DF63, 0xB9DE2FCB, 0x0CC6C9E9, + 0x0BEEFF53, 0xE3214517, 0xB4542835, 0x9F63293C, 0xEE41E729, 0x6E1D2D7C, + 0x50045286, 0x1E6685F3, 0xF33401C6, 0x30A22C95, 0x31A70850, 0x60930F13, + 0x73F98417, 0xA1269859, 0xEC645C44, 0x52C877A9, 0xCDFF33A6, 0xA02B1741, + 0x7CBAD9A2, 0x2180036F, 0x50D99C08, 0xCB3F4861, 0xC26BD765, 0x64A3F6AB, + 0x80342676, 0x25A75E7B, 0xE4E6D1FC, 0x20C710E6, 0xCDF0B680, 0x17844D3B, + 0x31EEF84D, 0x7E0824E4, 0x2CCB49EB, 0x846A3BAE, 0x8FF77888, 0xEE5D60F6, + 0x7AF75673, 0x2FDD5CDB, 0xA11631C1, 0x30F66F43, 0xB3FAEC54, 0x157FD7FA, + 0xEF8579CC, 0xD152DE58, 0xDB2FFD5E, 0x8F32CE19, 0x306AF97A, 0x02F03EF8, + 0x99319AD5, 0xC242FA0F, 0xA7E3EBB0, 0xC68E4906, 0xB8DA230C, 0x80823028, + 0xDCDEF3C8, 0xD35FB171, 0x088A1BC8, 0xBEC0C560, 0x61A3C9E8, 0xBCA8F54D, + 0xC72FEFFA, 0x22822E99, 0x82C570B4, 0xD8D94E89, 0x8B1C34BC, 0x301E16E6, + 0x273BE979, 0xB0FFEAA6, 0x61D9B8C6, 0x00B24869, 0xB7FFCE3F, 0x08DC283B, + 0x43DAF65A, 0xF7E19798, 0x7619B72F, 0x8F1C9BA4, 0xDC8637A0, 0x16A7D3B1, + 0x9FC393B7, 0xA7136EEB, 0xC6BCC63E, 0x1A513742, 0xEF6828BC, 0x520365D6, + 0x2D6A77AB, 0x3527ED4B, 0x821FD216, 0x095C6E2E, 0xDB92F2FB, 0x5EEA29CB, + 0x145892F5, 0x91584F7F, 0x5483697B, 0x2667A8CC, 0x85196048, 0x8C4BACEA, + 0x833860D4, 0x0D23E0F9, 0x6C387E8A, 0x0AE6D249, 0xB284600C, 0xD835731D, + 0xDCB1C647, 0xAC4C56EA, 0x3EBD81B3, 0x230EABB0, 0x6438BC87, 0xF0B5B1FA, + 0x8F5EA2B3, 0xFC184642, 0x0A036B7A, 0x4FB089BD, 0x649DA589, 0xA345415E, + 0x5C038323, 0x3E5D3BB9, 0x43D79572, 0x7E6DD07C, 0x06DFDF1E, 0x6C6CC4EF, + 0x7160A539, 0x73BFBE70, 0x83877605, 0x4523ECF1 }; + private static final int[] S3 = { + 0x8DEFC240, 0x25FA5D9F, 0xEB903DBF, 0xE810C907, 0x47607FFF, 0x369FE44B, + 0x8C1FC644, 0xAECECA90, 0xBEB1F9BF, 0xEEFBCAEA, 0xE8CF1950, 0x51DF07AE, + 0x920E8806, 0xF0AD0548, 0xE13C8D83, 0x927010D5, 0x11107D9F, 0x07647DB9, + 0xB2E3E4D4, 0x3D4F285E, 0xB9AFA820, 0xFADE82E0, 0xA067268B, 0x8272792E, + 0x553FB2C0, 0x489AE22B, 0xD4EF9794, 0x125E3FBC, 0x21FFFCEE, 0x825B1BFD, + 0x9255C5ED, 0x1257A240, 0x4E1A8302, 0xBAE07FFF, 0x528246E7, 0x8E57140E, + 0x3373F7BF, 0x8C9F8188, 0xA6FC4EE8, 0xC982B5A5, 0xA8C01DB7, 0x579FC264, + 0x67094F31, 0xF2BD3F5F, 0x40FFF7C1, 0x1FB78DFC, 0x8E6BD2C1, 0x437BE59B, + 0x99B03DBF, 0xB5DBC64B, 0x638DC0E6, 0x55819D99, 0xA197C81C, 0x4A012D6E, + 0xC5884A28, 0xCCC36F71, 0xB843C213, 0x6C0743F1, 0x8309893C, 0x0FEDDD5F, + 0x2F7FE850, 0xD7C07F7E, 0x02507FBF, 0x5AFB9A04, 0xA747D2D0, 0x1651192E, + 0xAF70BF3E, 0x58C31380, 0x5F98302E, 0x727CC3C4, 0x0A0FB402, 0x0F7FEF82, + 0x8C96FDAD, 0x5D2C2AAE, 0x8EE99A49, 0x50DA88B8, 0x8427F4A0, 0x1EAC5790, + 0x796FB449, 0x8252DC15, 0xEFBD7D9B, 0xA672597D, 0xADA840D8, 0x45F54504, + 0xFA5D7403, 0xE83EC305, 0x4F91751A, 0x925669C2, 0x23EFE941, 0xA903F12E, + 0x60270DF2, 0x0276E4B6, 0x94FD6574, 0x927985B2, 0x8276DBCB, 0x02778176, + 0xF8AF918D, 0x4E48F79E, 0x8F616DDF, 0xE29D840E, 0x842F7D83, 0x340CE5C8, + 0x96BBB682, 0x93B4B148, 0xEF303CAB, 0x984FAF28, 0x779FAF9B, 0x92DC560D, + 0x224D1E20, 0x8437AA88, 0x7D29DC96, 0x2756D3DC, 0x8B907CEE, 0xB51FD240, + 0xE7C07CE3, 0xE566B4A1, 0xC3E9615E, 0x3CF8209D, 0x6094D1E3, 0xCD9CA341, + 0x5C76460E, 0x00EA983B, 0xD4D67881, 0xFD47572C, 0xF76CEDD9, 0xBDA8229C, + 0x127DADAA, 0x438A074E, 0x1F97C090, 0x081BDB8A, 0x93A07EBE, 0xB938CA15, + 0x97B03CFF, 0x3DC2C0F8, 0x8D1AB2EC, 0x64380E51, 0x68CC7BFB, 0xD90F2788, + 0x12490181, 0x5DE5FFD4, 0xDD7EF86A, 0x76A2E214, 0xB9A40368, 0x925D958F, + 0x4B39FFFA, 0xBA39AEE9, 0xA4FFD30B, 0xFAF7933B, 0x6D498623, 0x193CBCFA, + 0x27627545, 0x825CF47A, 0x61BD8BA0, 0xD11E42D1, 0xCEAD04F4, 0x127EA392, + 0x10428DB7, 0x8272A972, 0x9270C4A8, 0x127DE50B, 0x285BA1C8, 0x3C62F44F, + 0x35C0EAA5, 0xE805D231, 0x428929FB, 0xB4FCDF82, 0x4FB66A53, 0x0E7DC15B, + 0x1F081FAB, 0x108618AE, 0xFCFD086D, 0xF9FF2889, 0x694BCC11, 0x236A5CAE, + 0x12DECA4D, 0x2C3F8CC5, 0xD2D02DFE, 0xF8EF5896, 0xE4CF52DA, 0x95155B67, + 0x494A488C, 0xB9B6A80C, 0x5C8F82BC, 0x89D36B45, 0x3A609437, 0xEC00C9A9, + 0x44715253, 0x0A874B49, 0xD773BC40, 0x7C34671C, 0x02717EF6, 0x4FEB5536, + 0xA2D02FFF, 0xD2BF60C4, 0xD43F03C0, 0x50B4EF6D, 0x07478CD1, 0x006E1888, + 0xA2E53F55, 0xB9E6D4BC, 0xA2048016, 0x97573833, 0xD7207D67, 0xDE0F8F3D, + 0x72F87B33, 0xABCC4F33, 0x7688C55D, 0x7B00A6B0, 0x947B0001, 0x570075D2, + 0xF9BB88F8, 0x8942019E, 0x4264A5FF, 0x856302E0, 0x72DBD92B, 0xEE971B69, + 0x6EA22FDE, 0x5F08AE2B, 0xAF7A616D, 0xE5C98767, 0xCF1FEBD2, 0x61EFC8C2, + 0xF1AC2571, 0xCC8239C2, 0x67214CB8, 0xB1E583D1, 0xB7DC3E62, 0x7F10BDCE, + 0xF90A5C38, 0x0FF0443D, 0x606E6DC6, 0x60543A49, 0x5727C148, 0x2BE98A1D, + 0x8AB41738, 0x20E1BE24, 0xAF96DA0F, 0x68458425, 0x99833BE5, 0x600D457D, + 0x282F9350, 0x8334B362, 0xD91D1120, 0x2B6D8DA0, 0x642B1E31, 0x9C305A00, + 0x52BCE688, 0x1B03588A, 0xF7BAEFD5, 0x4142ED9C, 0xA4315C11, 0x83323EC5, + 0xDFEF4636, 0xA133C501, 0xE9D3531C, 0xEE353783 }; + private static final int[] S4 = { + 0x9DB30420, 0x1FB6E9DE, 0xA7BE7BEF, 0xD273A298, 0x4A4F7BDB, 0x64AD8C57, + 0x85510443, 0xFA020ED1, 0x7E287AFF, 0xE60FB663, 0x095F35A1, 0x79EBF120, + 0xFD059D43, 0x6497B7B1, 0xF3641F63, 0x241E4ADF, 0x28147F5F, 0x4FA2B8CD, + 0xC9430040, 0x0CC32220, 0xFDD30B30, 0xC0A5374F, 0x1D2D00D9, 0x24147B15, + 0xEE4D111A, 0x0FCA5167, 0x71FF904C, 0x2D195FFE, 0x1A05645F, 0x0C13FEFE, + 0x081B08CA, 0x05170121, 0x80530100, 0xE83E5EFE, 0xAC9AF4F8, 0x7FE72701, + 0xD2B8EE5F, 0x06DF4261, 0xBB9E9B8A, 0x7293EA25, 0xCE84FFDF, 0xF5718801, + 0x3DD64B04, 0xA26F263B, 0x7ED48400, 0x547EEBE6, 0x446D4CA0, 0x6CF3D6F5, + 0x2649ABDF, 0xAEA0C7F5, 0x36338CC1, 0x503F7E93, 0xD3772061, 0x11B638E1, + 0x72500E03, 0xF80EB2BB, 0xABE0502E, 0xEC8D77DE, 0x57971E81, 0xE14F6746, + 0xC9335400, 0x6920318F, 0x081DBB99, 0xFFC304A5, 0x4D351805, 0x7F3D5CE3, + 0xA6C866C6, 0x5D5BCCA9, 0xDAEC6FEA, 0x9F926F91, 0x9F46222F, 0x3991467D, + 0xA5BF6D8E, 0x1143C44F, 0x43958302, 0xD0214EEB, 0x022083B8, 0x3FB6180C, + 0x18F8931E, 0x281658E6, 0x26486E3E, 0x8BD78A70, 0x7477E4C1, 0xB506E07C, + 0xF32D0A25, 0x79098B02, 0xE4EABB81, 0x28123B23, 0x69DEAD38, 0x1574CA16, + 0xDF871B62, 0x211C40B7, 0xA51A9EF9, 0x0014377B, 0x041E8AC8, 0x09114003, + 0xBD59E4D2, 0xE3D156D5, 0x4FE876D5, 0x2F91A340, 0x557BE8DE, 0x00EAE4A7, + 0x0CE5C2EC, 0x4DB4BBA6, 0xE756BDFF, 0xDD3369AC, 0xEC17B035, 0x06572327, + 0x99AFC8B0, 0x56C8C391, 0x6B65811C, 0x5E146119, 0x6E85CB75, 0xBE07C002, + 0xC2325577, 0x893FF4EC, 0x5BBFC92D, 0xD0EC3B25, 0xB7801AB7, 0x8D6D3B24, + 0x20C763EF, 0xC366A5FC, 0x9C382880, 0x0ACE3205, 0xAAC9548A, 0xECA1D7C7, + 0x041AFA32, 0x1D16625A, 0x6701902C, 0x9B757A54, 0x31D477F7, 0x9126B031, + 0x36CC6FDB, 0xC70B8B46, 0xD9E66A48, 0x56E55A79, 0x026A4CEB, 0x52437EFF, + 0x2F8F76B4, 0x0DF980A5, 0x8674CDE3, 0xEDDA04EB, 0x17A9BE04, 0x2C18F4DF, + 0xB7747F9D, 0xAB2AF7B4, 0xEFC34D20, 0x2E096B7C, 0x1741A254, 0xE5B6A035, + 0x213D42F6, 0x2C1C7C26, 0x61C2F50F, 0x6552DAF9, 0xD2C231F8, 0x25130F69, + 0xD8167FA2, 0x0418F2C8, 0x001A96A6, 0x0D1526AB, 0x63315C21, 0x5E0A72EC, + 0x49BAFEFD, 0x187908D9, 0x8D0DBD86, 0x311170A7, 0x3E9B640C, 0xCC3E10D7, + 0xD5CAD3B6, 0x0CAEC388, 0xF73001E1, 0x6C728AFF, 0x71EAE2A1, 0x1F9AF36E, + 0xCFCBD12F, 0xC1DE8417, 0xAC07BE6B, 0xCB44A1D8, 0x8B9B0F56, 0x013988C3, + 0xB1C52FCA, 0xB4BE31CD, 0xD8782806, 0x12A3A4E2, 0x6F7DE532, 0x58FD7EB6, + 0xD01EE900, 0x24ADFFC2, 0xF4990FC5, 0x9711AAC5, 0x001D7B95, 0x82E5E7D2, + 0x109873F6, 0x00613096, 0xC32D9521, 0xADA121FF, 0x29908415, 0x7FBB977F, + 0xAF9EB3DB, 0x29C9ED2A, 0x5CE2A465, 0xA730F32C, 0xD0AA3FE8, 0x8A5CC091, + 0xD49E2CE7, 0x0CE454A9, 0xD60ACD86, 0x015F1919, 0x77079103, 0xDEA03AF6, + 0x78A8565E, 0xDEE356DF, 0x21F05CBE, 0x8B75E387, 0xB3C50651, 0xB8A5C3EF, + 0xD8EEB6D2, 0xE523BE77, 0xC2154529, 0x2F69EFDF, 0xAFE67AFB, 0xF470C4B2, + 0xF3E0EB5B, 0xD6CC9876, 0x39E4460C, 0x1FDA8538, 0x1987832F, 0xCA007367, + 0xA99144F8, 0x296B299E, 0x492FC295, 0x9266BEAB, 0xB5676E69, 0x9BD3DDDA, + 0xDF7E052F, 0xDB25701C, 0x1B5E51EE, 0xF65324E6, 0x6AFCE36C, 0x0316CC04, + 0x8644213E, 0xB7DC59D0, 0x7965291F, 0xCCD6FD43, 0x41823979, 0x932BCDF6, + 0xB657C34D, 0x4EDFD282, 0x7AE5290C, 0x3CB9536B, 0x851E20FE, 0x9833557E, + 0x13ECF0B0, 0xD3FFB372, 0x3F85C5C1, 0x0AEF7ED2 }; + private static final int[] S5 = { + 0x7EC90C04, 0x2C6E74B9, 0x9B0E66DF, 0xA6337911, 0xB86A7FFF, 0x1DD358F5, + 0x44DD9D44, 0x1731167F, 0x08FBF1FA, 0xE7F511CC, 0xD2051B00, 0x735ABA00, + 0x2AB722D8, 0x386381CB, 0xACF6243A, 0x69BEFD7A, 0xE6A2E77F, 0xF0C720CD, + 0xC4494816, 0xCCF5C180, 0x38851640, 0x15B0A848, 0xE68B18CB, 0x4CAADEFF, + 0x5F480A01, 0x0412B2AA, 0x259814FC, 0x41D0EFE2, 0x4E40B48D, 0x248EB6FB, + 0x8DBA1CFE, 0x41A99B02, 0x1A550A04, 0xBA8F65CB, 0x7251F4E7, 0x95A51725, + 0xC106ECD7, 0x97A5980A, 0xC539B9AA, 0x4D79FE6A, 0xF2F3F763, 0x68AF8040, + 0xED0C9E56, 0x11B4958B, 0xE1EB5A88, 0x8709E6B0, 0xD7E07156, 0x4E29FEA7, + 0x6366E52D, 0x02D1C000, 0xC4AC8E05, 0x9377F571, 0x0C05372A, 0x578535F2, + 0x2261BE02, 0xD642A0C9, 0xDF13A280, 0x74B55BD2, 0x682199C0, 0xD421E5EC, + 0x53FB3CE8, 0xC8ADEDB3, 0x28A87FC9, 0x3D959981, 0x5C1FF900, 0xFE38D399, + 0x0C4EFF0B, 0x062407EA, 0xAA2F4FB1, 0x4FB96976, 0x90C79505, 0xB0A8A774, + 0xEF55A1FF, 0xE59CA2C2, 0xA6B62D27, 0xE66A4263, 0xDF65001F, 0x0EC50966, + 0xDFDD55BC, 0x29DE0655, 0x911E739A, 0x17AF8975, 0x32C7911C, 0x89F89468, + 0x0D01E980, 0x524755F4, 0x03B63CC9, 0x0CC844B2, 0xBCF3F0AA, 0x87AC36E9, + 0xE53A7426, 0x01B3D82B, 0x1A9E7449, 0x64EE2D7E, 0xCDDBB1DA, 0x01C94910, + 0xB868BF80, 0x0D26F3FD, 0x9342EDE7, 0x04A5C284, 0x636737B6, 0x50F5B616, + 0xF24766E3, 0x8ECA36C1, 0x136E05DB, 0xFEF18391, 0xFB887A37, 0xD6E7F7D4, + 0xC7FB7DC9, 0x3063FCDF, 0xB6F589DE, 0xEC2941DA, 0x26E46695, 0xB7566419, + 0xF654EFC5, 0xD08D58B7, 0x48925401, 0xC1BACB7F, 0xE5FF550F, 0xB6083049, + 0x5BB5D0E8, 0x87D72E5A, 0xAB6A6EE1, 0x223A66CE, 0xC62BF3CD, 0x9E0885F9, + 0x68CB3E47, 0x086C010F, 0xA21DE820, 0xD18B69DE, 0xF3F65777, 0xFA02C3F6, + 0x407EDAC3, 0xCBB3D550, 0x1793084D, 0xB0D70EBA, 0x0AB378D5, 0xD951FB0C, + 0xDED7DA56, 0x4124BBE4, 0x94CA0B56, 0x0F5755D1, 0xE0E1E56E, 0x6184B5BE, + 0x580A249F, 0x94F74BC0, 0xE327888E, 0x9F7B5561, 0xC3DC0280, 0x05687715, + 0x646C6BD7, 0x44904DB3, 0x66B4F0A3, 0xC0F1648A, 0x697ED5AF, 0x49E92FF6, + 0x309E374F, 0x2CB6356A, 0x85808573, 0x4991F840, 0x76F0AE02, 0x083BE84D, + 0x28421C9A, 0x44489406, 0x736E4CB8, 0xC1092910, 0x8BC95FC6, 0x7D869CF4, + 0x134F616F, 0x2E77118D, 0xB31B2BE1, 0xAA90B472, 0x3CA5D717, 0x7D161BBA, + 0x9CAD9010, 0xAF462BA2, 0x9FE459D2, 0x45D34559, 0xD9F2DA13, 0xDBC65487, + 0xF3E4F94E, 0x176D486F, 0x097C13EA, 0x631DA5C7, 0x445F7382, 0x175683F4, + 0xCDC66A97, 0x70BE0288, 0xB3CDCF72, 0x6E5DD2F3, 0x20936079, 0x459B80A5, + 0xBE60E2DB, 0xA9C23101, 0xEBA5315C, 0x224E42F2, 0x1C5C1572, 0xF6721B2C, + 0x1AD2FFF3, 0x8C25404E, 0x324ED72F, 0x4067B7FD, 0x0523138E, 0x5CA3BC78, + 0xDC0FD66E, 0x75922283, 0x784D6B17, 0x58EBB16E, 0x44094F85, 0x3F481D87, + 0xFCFEAE7B, 0x77B5FF76, 0x8C2302BF, 0xAAF47556, 0x5F46B02A, 0x2B092801, + 0x3D38F5F7, 0x0CA81F36, 0x52AF4A8A, 0x66D5E7C0, 0xDF3B0874, 0x95055110, + 0x1B5AD7A8, 0xF61ED5AD, 0x6CF6E479, 0x20758184, 0xD0CEFA65, 0x88F7BE58, + 0x4A046826, 0x0FF6F8F3, 0xA09C7F70, 0x5346ABA0, 0x5CE96C28, 0xE176EDA3, + 0x6BAC307F, 0x376829D2, 0x85360FA9, 0x17E3FE2A, 0x24B79767, 0xF5A96B20, + 0xD6CD2595, 0x68FF1EBF, 0x7555442C, 0xF19F06BE, 0xF9E0659A, 0xEEB9491D, + 0x34010718, 0xBB30CAB8, 0xE822FE15, 0x88570983, 0x750E6249, 0xDA627E55, + 0x5E76FFA8, 0xB1534546, 0x6D47DE08, 0xEFE9E7D4 }; + private static final int[] S6 = { + 0xF6FA8F9D, 0x2CAC6CE1, 0x4CA34867, 0xE2337F7C, 0x95DB08E7, 0x016843B4, + 0xECED5CBC, 0x325553AC, 0xBF9F0960, 0xDFA1E2ED, 0x83F0579D, 0x63ED86B9, + 0x1AB6A6B8, 0xDE5EBE39, 0xF38FF732, 0x8989B138, 0x33F14961, 0xC01937BD, + 0xF506C6DA, 0xE4625E7E, 0xA308EA99, 0x4E23E33C, 0x79CBD7CC, 0x48A14367, + 0xA3149619, 0xFEC94BD5, 0xA114174A, 0xEAA01866, 0xA084DB2D, 0x09A8486F, + 0xA888614A, 0x2900AF98, 0x01665991, 0xE1992863, 0xC8F30C60, 0x2E78EF3C, + 0xD0D51932, 0xCF0FEC14, 0xF7CA07D2, 0xD0A82072, 0xFD41197E, 0x9305A6B0, + 0xE86BE3DA, 0x74BED3CD, 0x372DA53C, 0x4C7F4448, 0xDAB5D440, 0x6DBA0EC3, + 0x083919A7, 0x9FBAEED9, 0x49DBCFB0, 0x4E670C53, 0x5C3D9C01, 0x64BDB941, + 0x2C0E636A, 0xBA7DD9CD, 0xEA6F7388, 0xE70BC762, 0x35F29ADB, 0x5C4CDD8D, + 0xF0D48D8C, 0xB88153E2, 0x08A19866, 0x1AE2EAC8, 0x284CAF89, 0xAA928223, + 0x9334BE53, 0x3B3A21BF, 0x16434BE3, 0x9AEA3906, 0xEFE8C36E, 0xF890CDD9, + 0x80226DAE, 0xC340A4A3, 0xDF7E9C09, 0xA694A807, 0x5B7C5ECC, 0x221DB3A6, + 0x9A69A02F, 0x68818A54, 0xCEB2296F, 0x53C0843A, 0xFE893655, 0x25BFE68A, + 0xB4628ABC, 0xCF222EBF, 0x25AC6F48, 0xA9A99387, 0x53BDDB65, 0xE76FFBE7, + 0xE967FD78, 0x0BA93563, 0x8E342BC1, 0xE8A11BE9, 0x4980740D, 0xC8087DFC, + 0x8DE4BF99, 0xA11101A0, 0x7FD37975, 0xDA5A26C0, 0xE81F994F, 0x9528CD89, + 0xFD339FED, 0xB87834BF, 0x5F04456D, 0x22258698, 0xC9C4C83B, 0x2DC156BE, + 0x4F628DAA, 0x57F55EC5, 0xE2220ABE, 0xD2916EBF, 0x4EC75B95, 0x24F2C3C0, + 0x42D15D99, 0xCD0D7FA0, 0x7B6E27FF, 0xA8DC8AF0, 0x7345C106, 0xF41E232F, + 0x35162386, 0xE6EA8926, 0x3333B094, 0x157EC6F2, 0x372B74AF, 0x692573E4, + 0xE9A9D848, 0xF3160289, 0x3A62EF1D, 0xA787E238, 0xF3A5F676, 0x74364853, + 0x20951063, 0x4576698D, 0xB6FAD407, 0x592AF950, 0x36F73523, 0x4CFB6E87, + 0x7DA4CEC0, 0x6C152DAA, 0xCB0396A8, 0xC50DFE5D, 0xFCD707AB, 0x0921C42F, + 0x89DFF0BB, 0x5FE2BE78, 0x448F4F33, 0x754613C9, 0x2B05D08D, 0x48B9D585, + 0xDC049441, 0xC8098F9B, 0x7DEDE786, 0xC39A3373, 0x42410005, 0x6A091751, + 0x0EF3C8A6, 0x890072D6, 0x28207682, 0xA9A9F7BE, 0xBF32679D, 0xD45B5B75, + 0xB353FD00, 0xCBB0E358, 0x830F220A, 0x1F8FB214, 0xD372CF08, 0xCC3C4A13, + 0x8CF63166, 0x061C87BE, 0x88C98F88, 0x6062E397, 0x47CF8E7A, 0xB6C85283, + 0x3CC2ACFB, 0x3FC06976, 0x4E8F0252, 0x64D8314D, 0xDA3870E3, 0x1E665459, + 0xC10908F0, 0x513021A5, 0x6C5B68B7, 0x822F8AA0, 0x3007CD3E, 0x74719EEF, + 0xDC872681, 0x073340D4, 0x7E432FD9, 0x0C5EC241, 0x8809286C, 0xF592D891, + 0x08A930F6, 0x957EF305, 0xB7FBFFBD, 0xC266E96F, 0x6FE4AC98, 0xB173ECC0, + 0xBC60B42A, 0x953498DA, 0xFBA1AE12, 0x2D4BD736, 0x0F25FAAB, 0xA4F3FCEB, + 0xE2969123, 0x257F0C3D, 0x9348AF49, 0x361400BC, 0xE8816F4A, 0x3814F200, + 0xA3F94043, 0x9C7A54C2, 0xBC704F57, 0xDA41E7F9, 0xC25AD33A, 0x54F4A084, + 0xB17F5505, 0x59357CBE, 0xEDBD15C8, 0x7F97C5AB, 0xBA5AC7B5, 0xB6F6DEAF, + 0x3A479C3A, 0x5302DA25, 0x653D7E6A, 0x54268D49, 0x51A477EA, 0x5017D55B, + 0xD7D25D88, 0x44136C76, 0x0404A8C8, 0xB8E5A121, 0xB81A928A, 0x60ED5869, + 0x97C55B96, 0xEAEC991B, 0x29935913, 0x01FDB7F1, 0x088E8DFA, 0x9AB6F6F5, + 0x3B4CBF9F, 0x4A5DE3AB, 0xE6051D35, 0xA0E1D855, 0xD36B4CF1, 0xF544EDEB, + 0xB0E93524, 0xBEBB8FBD, 0xA2D762CF, 0x49C92F54, 0x38B5F331, 0x7128A454, + 0x48392905, 0xA65B1DB8, 0x851C97BD, 0xD675CF2F }; + private static final int[] S7 = { + 0x85E04019, 0x332BF567, 0x662DBFFF, 0xCFC65693, 0x2A8D7F6F, 0xAB9BC912, + 0xDE6008A1, 0x2028DA1F, 0x0227BCE7, 0x4D642916, 0x18FAC300, 0x50F18B82, + 0x2CB2CB11, 0xB232E75C, 0x4B3695F2, 0xB28707DE, 0xA05FBCF6, 0xCD4181E9, + 0xE150210C, 0xE24EF1BD, 0xB168C381, 0xFDE4E789, 0x5C79B0D8, 0x1E8BFD43, + 0x4D495001, 0x38BE4341, 0x913CEE1D, 0x92A79C3F, 0x089766BE, 0xBAEEADF4, + 0x1286BECF, 0xB6EACB19, 0x2660C200, 0x7565BDE4, 0x64241F7A, 0x8248DCA9, + 0xC3B3AD66, 0x28136086, 0x0BD8DFA8, 0x356D1CF2, 0x107789BE, 0xB3B2E9CE, + 0x0502AA8F, 0x0BC0351E, 0x166BF52A, 0xEB12FF82, 0xE3486911, 0xD34D7516, + 0x4E7B3AFF, 0x5F43671B, 0x9CF6E037, 0x4981AC83, 0x334266CE, 0x8C9341B7, + 0xD0D854C0, 0xCB3A6C88, 0x47BC2829, 0x4725BA37, 0xA66AD22B, 0x7AD61F1E, + 0x0C5CBAFA, 0x4437F107, 0xB6E79962, 0x42D2D816, 0x0A961288, 0xE1A5C06E, + 0x13749E67, 0x72FC081A, 0xB1D139F7, 0xF9583745, 0xCF19DF58, 0xBEC3F756, + 0xC06EBA30, 0x07211B24, 0x45C28829, 0xC95E317F, 0xBC8EC511, 0x38BC46E9, + 0xC6E6FA14, 0xBAE8584A, 0xAD4EBC46, 0x468F508B, 0x7829435F, 0xF124183B, + 0x821DBA9F, 0xAFF60FF4, 0xEA2C4E6D, 0x16E39264, 0x92544A8B, 0x009B4FC3, + 0xABA68CED, 0x9AC96F78, 0x06A5B79A, 0xB2856E6E, 0x1AEC3CA9, 0xBE838688, + 0x0E0804E9, 0x55F1BE56, 0xE7E5363B, 0xB3A1F25D, 0xF7DEBB85, 0x61FE033C, + 0x16746233, 0x3C034C28, 0xDA6D0C74, 0x79AAC56C, 0x3CE4E1AD, 0x51F0C802, + 0x98F8F35A, 0x1626A49F, 0xEED82B29, 0x1D382FE3, 0x0C4FB99A, 0xBB325778, + 0x3EC6D97B, 0x6E77A6A9, 0xCB658B5C, 0xD45230C7, 0x2BD1408B, 0x60C03EB7, + 0xB9068D78, 0xA33754F4, 0xF430C87D, 0xC8A71302, 0xB96D8C32, 0xEBD4E7BE, + 0xBE8B9D2D, 0x7979FB06, 0xE7225308, 0x8B75CF77, 0x11EF8DA4, 0xE083C858, + 0x8D6B786F, 0x5A6317A6, 0xFA5CF7A0, 0x5DDA0033, 0xF28EBFB0, 0xF5B9C310, + 0xA0EAC280, 0x08B9767A, 0xA3D9D2B0, 0x79D34217, 0x021A718D, 0x9AC6336A, + 0x2711FD60, 0x438050E3, 0x069908A8, 0x3D7FEDC4, 0x826D2BEF, 0x4EEB8476, + 0x488DCF25, 0x36C9D566, 0x28E74E41, 0xC2610ACA, 0x3D49A9CF, 0xBAE3B9DF, + 0xB65F8DE6, 0x92AEAF64, 0x3AC7D5E6, 0x9EA80509, 0xF22B017D, 0xA4173F70, + 0xDD1E16C3, 0x15E0D7F9, 0x50B1B887, 0x2B9F4FD5, 0x625ABA82, 0x6A017962, + 0x2EC01B9C, 0x15488AA9, 0xD716E740, 0x40055A2C, 0x93D29A22, 0xE32DBF9A, + 0x058745B9, 0x3453DC1E, 0xD699296E, 0x496CFF6F, 0x1C9F4986, 0xDFE2ED07, + 0xB87242D1, 0x19DE7EAE, 0x053E561A, 0x15AD6F8C, 0x66626C1C, 0x7154C24C, + 0xEA082B2A, 0x93EB2939, 0x17DCB0F0, 0x58D4F2AE, 0x9EA294FB, 0x52CF564C, + 0x9883FE66, 0x2EC40581, 0x763953C3, 0x01D6692E, 0xD3A0C108, 0xA1E7160E, + 0xE4F2DFA6, 0x693ED285, 0x74904698, 0x4C2B0EDD, 0x4F757656, 0x5D393378, + 0xA132234F, 0x3D321C5D, 0xC3F5E194, 0x4B269301, 0xC79F022F, 0x3C997E7E, + 0x5E4F9504, 0x3FFAFBBD, 0x76F7AD0E, 0x296693F4, 0x3D1FCE6F, 0xC61E45BE, + 0xD3B5AB34, 0xF72BF9B7, 0x1B0434C0, 0x4E72B567, 0x5592A33D, 0xB5229301, + 0xCFD2A87F, 0x60AEB767, 0x1814386B, 0x30BCC33D, 0x38A0C07D, 0xFD1606F2, + 0xC363519B, 0x589DD390, 0x5479F8E6, 0x1CB8D647, 0x97FD61A9, 0xEA7759F4, + 0x2D57539D, 0x569A58CF, 0xE84E63AD, 0x462E1B78, 0x6580F87E, 0xF3817914, + 0x91DA55F4, 0x40A230F3, 0xD1988F35, 0xB6E318D2, 0x3FFA50BC, 0x3D40F021, + 0xC3C0BDAE, 0x4958C24C, 0x518F36B2, 0x84B1D370, 0x0FEDCE83, 0x878DDADA, + 0xF2A279C7, 0x94E01BE8, 0x90716F4B, 0x954B8AA3 }; + private static final int[] S8 = { + 0xE216300D, 0xBBDDFFFC, 0xA7EBDABD, 0x35648095, 0x7789F8B7, 0xE6C1121B, + 0x0E241600, 0x052CE8B5, 0x11A9CFB0, 0xE5952F11, 0xECE7990A, 0x9386D174, + 0x2A42931C, 0x76E38111, 0xB12DEF3A, 0x37DDDDFC, 0xDE9ADEB1, 0x0A0CC32C, + 0xBE197029, 0x84A00940, 0xBB243A0F, 0xB4D137CF, 0xB44E79F0, 0x049EEDFD, + 0x0B15A15D, 0x480D3168, 0x8BBBDE5A, 0x669DED42, 0xC7ECE831, 0x3F8F95E7, + 0x72DF191B, 0x7580330D, 0x94074251, 0x5C7DCDFA, 0xABBE6D63, 0xAA402164, + 0xB301D40A, 0x02E7D1CA, 0x53571DAE, 0x7A3182A2, 0x12A8DDEC, 0xFDAA335D, + 0x176F43E8, 0x71FB46D4, 0x38129022, 0xCE949AD4, 0xB84769AD, 0x965BD862, + 0x82F3D055, 0x66FB9767, 0x15B80B4E, 0x1D5B47A0, 0x4CFDE06F, 0xC28EC4B8, + 0x57E8726E, 0x647A78FC, 0x99865D44, 0x608BD593, 0x6C200E03, 0x39DC5FF6, + 0x5D0B00A3, 0xAE63AFF2, 0x7E8BD632, 0x70108C0C, 0xBBD35049, 0x2998DF04, + 0x980CF42A, 0x9B6DF491, 0x9E7EDD53, 0x06918548, 0x58CB7E07, 0x3B74EF2E, + 0x522FFFB1, 0xD24708CC, 0x1C7E27CD, 0xA4EB215B, 0x3CF1D2E2, 0x19B47A38, + 0x424F7618, 0x35856039, 0x9D17DEE7, 0x27EB35E6, 0xC9AFF67B, 0x36BAF5B8, + 0x09C467CD, 0xC18910B1, 0xE11DBF7B, 0x06CD1AF8, 0x7170C608, 0x2D5E3354, + 0xD4DE495A, 0x64C6D006, 0xBCC0C62C, 0x3DD00DB3, 0x708F8F34, 0x77D51B42, + 0x264F620F, 0x24B8D2BF, 0x15C1B79E, 0x46A52564, 0xF8D7E54E, 0x3E378160, + 0x7895CDA5, 0x859C15A5, 0xE6459788, 0xC37BC75F, 0xDB07BA0C, 0x0676A3AB, + 0x7F229B1E, 0x31842E7B, 0x24259FD7, 0xF8BEF472, 0x835FFCB8, 0x6DF4C1F2, + 0x96F5B195, 0xFD0AF0FC, 0xB0FE134C, 0xE2506D3D, 0x4F9B12EA, 0xF215F225, + 0xA223736F, 0x9FB4C428, 0x25D04979, 0x34C713F8, 0xC4618187, 0xEA7A6E98, + 0x7CD16EFC, 0x1436876C, 0xF1544107, 0xBEDEEE14, 0x56E9AF27, 0xA04AA441, + 0x3CF7C899, 0x92ECBAE6, 0xDD67016D, 0x151682EB, 0xA842EEDF, 0xFDBA60B4, + 0xF1907B75, 0x20E3030F, 0x24D8C29E, 0xE139673B, 0xEFA63FB8, 0x71873054, + 0xB6F2CF3B, 0x9F326442, 0xCB15A4CC, 0xB01A4504, 0xF1E47D8D, 0x844A1BE5, + 0xBAE7DFDC, 0x42CBDA70, 0xCD7DAE0A, 0x57E85B7A, 0xD53F5AF6, 0x20CF4D8C, + 0xCEA4D428, 0x79D130A4, 0x3486EBFB, 0x33D3CDDC, 0x77853B53, 0x37EFFCB5, + 0xC5068778, 0xE580B3E6, 0x4E68B8F4, 0xC5C8B37E, 0x0D809EA2, 0x398FEB7C, + 0x132A4F94, 0x43B7950E, 0x2FEE7D1C, 0x223613BD, 0xDD06CAA2, 0x37DF932B, + 0xC4248289, 0xACF3EBC3, 0x5715F6B7, 0xEF3478DD, 0xF267616F, 0xC148CBE4, + 0x9052815E, 0x5E410FAB, 0xB48A2465, 0x2EDA7FA4, 0xE87B40E4, 0xE98EA084, + 0x5889E9E1, 0xEFD390FC, 0xDD07D35B, 0xDB485694, 0x38D7E5B2, 0x57720101, + 0x730EDEBC, 0x5B643113, 0x94917E4F, 0x503C2FBA, 0x646F1282, 0x7523D24A, + 0xE0779695, 0xF9C17A8F, 0x7A5B2121, 0xD187B896, 0x29263A4D, 0xBA510CDF, + 0x81F47C9F, 0xAD1163ED, 0xEA7B5965, 0x1A00726E, 0x11403092, 0x00DA6D77, + 0x4A0CDD61, 0xAD1F4603, 0x605BDFB0, 0x9EEDC364, 0x22EBE6A8, 0xCEE7D28A, + 0xA0E736A0, 0x5564A6B9, 0x10853209, 0xC7EB8F37, 0x2DE705CA, 0x8951570F, + 0xDF09822B, 0xBD691A6C, 0xAA12E4F2, 0x87451C0F, 0xE0F6A27A, 0x3ADA4819, + 0x4CF1764F, 0x0D771C2B, 0x67CDB156, 0x350D8384, 0x5938FA0F, 0x42399EF3, + 0x36997B07, 0x0E84093D, 0x4AA93E61, 0x8360D87B, 0x1FA98B0C, 0x1149382C, + 0xE97625A5, 0x0614D1B7, 0x0E25244B, 0x0C768347, 0x589E8D82, 0x0D2059D1, + 0xA466BB1E, 0xF8DA0A82, 0x04F19130, 0xBA6E4EC0, 0x99265164, 0x1EE7230D, + 0x50B2AD80, 0xEAEE6801, 0x8DB2A283, 0xEA8BF59E }; + private static final int _12_ROUNDS = 12; + private static final int _16_ROUNDS = 16; + + /** Trivial 0-arguments constructor. */ + public Cast5() + { + super(Registry.CAST5_CIPHER, DEFAULT_BLOCK_SIZE, DEFAULT_KEY_SIZE); + } + + /** + * Assuming the input is a 32-bit block organised as: b31b30b29...b0, this + * method returns an array of 4 Java ints, containing from position 0 onward + * the values: {b31b30b29b28, b27b26b25b24, ... , b3b2b1b0}. + * + * @param x a 32-bit block. + * @return an array of 4 ints, each being the contents of an 8-bit block from + * the input. + */ + private static final int[] unscramble(int x) + { + return new int[] { x >>> 24, (x >>> 16) & 0xFF, (x >>> 8) & 0xFF, x & 0xFF }; + } + + public Object clone() + { + Cast5 result = new Cast5(); + result.currentBlockSize = this.currentBlockSize; + return result; + } + + public Iterator blockSizes() + { + ArrayList al = new ArrayList(); + al.add(Integer.valueOf(DEFAULT_BLOCK_SIZE)); + return Collections.unmodifiableList(al).iterator(); + } + + public Iterator keySizes() + { + ArrayList al = new ArrayList(); + for (int n = 5; n < 17; n++) + al.add(Integer.valueOf(n)); + return Collections.unmodifiableList(al).iterator(); + } + + public Object makeKey(byte[] uk, int bs) throws InvalidKeyException + { + if (bs != DEFAULT_BLOCK_SIZE) + throw new IllegalArgumentException(); + if (uk == null) + throw new InvalidKeyException("Empty key"); + int len = uk.length; + if (len < 5 || len > 16) + throw new InvalidKeyException("Key size (in bytes) is not in the range [5..16]"); + Cast5Key result = new Cast5Key(); + result.rounds = (len < 11) ? _12_ROUNDS : _16_ROUNDS; + byte[] kk = new byte[16]; + System.arraycopy(uk, 0, kk, 0, len); + int z0z1z2z3, z4z5z6z7, z8z9zAzB, zCzDzEzF; + int z0, z1, z2, z3, z4, z5, z6, z7, z8, z9, zA, zB, zC, zD, zE, zF; + int x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, xA, xB, xC, xD, xE, xF; + int[] b; + int x0x1x2x3 = kk[0 ] << 24 + | (kk[1 ] & 0xFF) << 16 + | (kk[2 ] & 0xFF) << 8 + | (kk[3 ] & 0xFF); + int x4x5x6x7 = kk[4 ] << 24 + | (kk[5 ] & 0xFF) << 16 + | (kk[6 ] & 0xFF) << 8 + | (kk[7 ] & 0xFF); + int x8x9xAxB = kk[8 ] << 24 + | (kk[9 ] & 0xFF) << 16 + | (kk[10] & 0xFF) << 8 + | (kk[11] & 0xFF); + int xCxDxExF = kk[12] << 24 + | (kk[13] & 0xFF) << 16 + | (kk[14] & 0xFF) << 8 + | (kk[15] & 0xFF); + b = unscramble(x0x1x2x3); + x0 = b[0]; + x1 = b[1]; + x2 = b[2]; + x3 = b[3]; + b = unscramble(x4x5x6x7); + x4 = b[0]; + x5 = b[1]; + x6 = b[2]; + x7 = b[3]; + b = unscramble(x8x9xAxB); + x8 = b[0]; + x9 = b[1]; + xA = b[2]; + xB = b[3]; + b = unscramble(xCxDxExF); + xC = b[0]; + xD = b[1]; + xE = b[2]; + xF = b[3]; + z0z1z2z3 = x0x1x2x3 ^ S5[xD] ^ S6[xF] ^ S7[xC] ^ S8[xE] ^ S7[x8]; + b = unscramble(z0z1z2z3); + z0 = b[0]; + z1 = b[1]; + z2 = b[2]; + z3 = b[3]; + z4z5z6z7 = x8x9xAxB ^ S5[z0] ^ S6[z2] ^ S7[z1] ^ S8[z3] ^ S8[xA]; + b = unscramble(z4z5z6z7); + z4 = b[0]; + z5 = b[1]; + z6 = b[2]; + z7 = b[3]; + z8z9zAzB = xCxDxExF ^ S5[z7] ^ S6[z6] ^ S7[z5] ^ S8[z4] ^ S5[x9]; + b = unscramble(z8z9zAzB); + z8 = b[0]; + z9 = b[1]; + zA = b[2]; + zB = b[3]; + zCzDzEzF = x4x5x6x7 ^ S5[zA] ^ S6[z9] ^ S7[zB] ^ S8[z8] ^ S6[xB]; + b = unscramble(zCzDzEzF); + zC = b[0]; + zD = b[1]; + zE = b[2]; + zF = b[3]; + result.Km0 = S5[z8] ^ S6[z9] ^ S7[z7] ^ S8[z6] ^ S5[z2]; + result.Km1 = S5[zA] ^ S6[zB] ^ S7[z5] ^ S8[z4] ^ S6[z6]; + result.Km2 = S5[zC] ^ S6[zD] ^ S7[z3] ^ S8[z2] ^ S7[z9]; + result.Km3 = S5[zE] ^ S6[zF] ^ S7[z1] ^ S8[z0] ^ S8[zC]; + x0x1x2x3 = z8z9zAzB ^ S5[z5] ^ S6[z7] ^ S7[z4] ^ S8[z6] ^ S7[z0]; + b = unscramble(x0x1x2x3); + x0 = b[0]; + x1 = b[1]; + x2 = b[2]; + x3 = b[3]; + x4x5x6x7 = z0z1z2z3 ^ S5[x0] ^ S6[x2] ^ S7[x1] ^ S8[x3] ^ S8[z2]; + b = unscramble(x4x5x6x7); + x4 = b[0]; + x5 = b[1]; + x6 = b[2]; + x7 = b[3]; + x8x9xAxB = z4z5z6z7 ^ S5[x7] ^ S6[x6] ^ S7[x5] ^ S8[x4] ^ S5[z1]; + b = unscramble(x8x9xAxB); + x8 = b[0]; + x9 = b[1]; + xA = b[2]; + xB = b[3]; + xCxDxExF = zCzDzEzF ^ S5[xA] ^ S6[x9] ^ S7[xB] ^ S8[x8] ^ S6[z3]; + b = unscramble(xCxDxExF); + xC = b[0]; + xD = b[1]; + xE = b[2]; + xF = b[3]; + result.Km4 = S5[x3] ^ S6[x2] ^ S7[xC] ^ S8[xD] ^ S5[x8]; + result.Km5 = S5[x1] ^ S6[x0] ^ S7[xE] ^ S8[xF] ^ S6[xD]; + result.Km6 = S5[x7] ^ S6[x6] ^ S7[x8] ^ S8[x9] ^ S7[x3]; + result.Km7 = S5[x5] ^ S6[x4] ^ S7[xA] ^ S8[xB] ^ S8[x7]; + z0z1z2z3 = x0x1x2x3 ^ S5[xD] ^ S6[xF] ^ S7[xC] ^ S8[xE] ^ S7[x8]; + b = unscramble(z0z1z2z3); + z0 = b[0]; + z1 = b[1]; + z2 = b[2]; + z3 = b[3]; + z4z5z6z7 = x8x9xAxB ^ S5[z0] ^ S6[z2] ^ S7[z1] ^ S8[z3] ^ S8[xA]; + b = unscramble(z4z5z6z7); + z4 = b[0]; + z5 = b[1]; + z6 = b[2]; + z7 = b[3]; + z8z9zAzB = xCxDxExF ^ S5[z7] ^ S6[z6] ^ S7[z5] ^ S8[z4] ^ S5[x9]; + b = unscramble(z8z9zAzB); + z8 = b[0]; + z9 = b[1]; + zA = b[2]; + zB = b[3]; + zCzDzEzF = x4x5x6x7 ^ S5[zA] ^ S6[z9] ^ S7[zB] ^ S8[z8] ^ S6[xB]; + b = unscramble(zCzDzEzF); + zC = b[0]; + zD = b[1]; + zE = b[2]; + zF = b[3]; + result.Km8 = S5[z3] ^ S6[z2] ^ S7[zC] ^ S8[zD] ^ S5[z9]; + result.Km9 = S5[z1] ^ S6[z0] ^ S7[zE] ^ S8[zF] ^ S6[zC]; + result.Km10 = S5[z7] ^ S6[z6] ^ S7[z8] ^ S8[z9] ^ S7[z2]; + result.Km11 = S5[z5] ^ S6[z4] ^ S7[zA] ^ S8[zB] ^ S8[z6]; + x0x1x2x3 = z8z9zAzB ^ S5[z5] ^ S6[z7] ^ S7[z4] ^ S8[z6] ^ S7[z0]; + b = unscramble(x0x1x2x3); + x0 = b[0]; + x1 = b[1]; + x2 = b[2]; + x3 = b[3]; + x4x5x6x7 = z0z1z2z3 ^ S5[x0] ^ S6[x2] ^ S7[x1] ^ S8[x3] ^ S8[z2]; + b = unscramble(x4x5x6x7); + x4 = b[0]; + x5 = b[1]; + x6 = b[2]; + x7 = b[3]; + x8x9xAxB = z4z5z6z7 ^ S5[x7] ^ S6[x6] ^ S7[x5] ^ S8[x4] ^ S5[z1]; + b = unscramble(x8x9xAxB); + x8 = b[0]; + x9 = b[1]; + xA = b[2]; + xB = b[3]; + xCxDxExF = zCzDzEzF ^ S5[xA] ^ S6[x9] ^ S7[xB] ^ S8[x8] ^ S6[z3]; + b = unscramble(xCxDxExF); + xC = b[0]; + xD = b[1]; + xE = b[2]; + xF = b[3]; + result.Km12 = S5[x8] ^ S6[x9] ^ S7[x7] ^ S8[x6] ^ S5[x3]; + result.Km13 = S5[xA] ^ S6[xB] ^ S7[x5] ^ S8[x4] ^ S6[x7]; + result.Km14 = S5[xC] ^ S6[xD] ^ S7[x3] ^ S8[x2] ^ S7[x8]; + result.Km15 = S5[xE] ^ S6[xF] ^ S7[x1] ^ S8[x0] ^ S8[xD]; + // The remaining half is identical to what is given above, carrying on + // from the last created x0..xF to generate keys K17 - K32. These keys + // will be used as the 'rotation' keys and as such only the five least + // significant bits are to be considered. + z0z1z2z3 = x0x1x2x3 ^ S5[xD] ^ S6[xF] ^ S7[xC] ^ S8[xE] ^ S7[x8]; + b = unscramble(z0z1z2z3); + z0 = b[0]; + z1 = b[1]; + z2 = b[2]; + z3 = b[3]; + z4z5z6z7 = x8x9xAxB ^ S5[z0] ^ S6[z2] ^ S7[z1] ^ S8[z3] ^ S8[xA]; + b = unscramble(z4z5z6z7); + z4 = b[0]; + z5 = b[1]; + z6 = b[2]; + z7 = b[3]; + z8z9zAzB = xCxDxExF ^ S5[z7] ^ S6[z6] ^ S7[z5] ^ S8[z4] ^ S5[x9]; + b = unscramble(z8z9zAzB); + z8 = b[0]; + z9 = b[1]; + zA = b[2]; + zB = b[3]; + zCzDzEzF = x4x5x6x7 ^ S5[zA] ^ S6[z9] ^ S7[zB] ^ S8[z8] ^ S6[xB]; + b = unscramble(zCzDzEzF); + zC = b[0]; + zD = b[1]; + zE = b[2]; + zF = b[3]; + result.Kr0 = (S5[z8] ^ S6[z9] ^ S7[z7] ^ S8[z6] ^ S5[z2]) & 0x1F; + result.Kr1 = (S5[zA] ^ S6[zB] ^ S7[z5] ^ S8[z4] ^ S6[z6]) & 0x1F; + result.Kr2 = (S5[zC] ^ S6[zD] ^ S7[z3] ^ S8[z2] ^ S7[z9]) & 0x1F; + result.Kr3 = (S5[zE] ^ S6[zF] ^ S7[z1] ^ S8[z0] ^ S8[zC]) & 0x1F; + x0x1x2x3 = z8z9zAzB ^ S5[z5] ^ S6[z7] ^ S7[z4] ^ S8[z6] ^ S7[z0]; + b = unscramble(x0x1x2x3); + x0 = b[0]; + x1 = b[1]; + x2 = b[2]; + x3 = b[3]; + x4x5x6x7 = z0z1z2z3 ^ S5[x0] ^ S6[x2] ^ S7[x1] ^ S8[x3] ^ S8[z2]; + b = unscramble(x4x5x6x7); + x4 = b[0]; + x5 = b[1]; + x6 = b[2]; + x7 = b[3]; + x8x9xAxB = z4z5z6z7 ^ S5[x7] ^ S6[x6] ^ S7[x5] ^ S8[x4] ^ S5[z1]; + b = unscramble(x8x9xAxB); + x8 = b[0]; + x9 = b[1]; + xA = b[2]; + xB = b[3]; + xCxDxExF = zCzDzEzF ^ S5[xA] ^ S6[x9] ^ S7[xB] ^ S8[x8] ^ S6[z3]; + b = unscramble(xCxDxExF); + xC = b[0]; + xD = b[1]; + xE = b[2]; + xF = b[3]; + result.Kr4 = (S5[x3] ^ S6[x2] ^ S7[xC] ^ S8[xD] ^ S5[x8]) & 0x1F; + result.Kr5 = (S5[x1] ^ S6[x0] ^ S7[xE] ^ S8[xF] ^ S6[xD]) & 0x1F; + result.Kr6 = (S5[x7] ^ S6[x6] ^ S7[x8] ^ S8[x9] ^ S7[x3]) & 0x1F; + result.Kr7 = (S5[x5] ^ S6[x4] ^ S7[xA] ^ S8[xB] ^ S8[x7]) & 0x1F; + z0z1z2z3 = x0x1x2x3 ^ S5[xD] ^ S6[xF] ^ S7[xC] ^ S8[xE] ^ S7[x8]; + b = unscramble(z0z1z2z3); + z0 = b[0]; + z1 = b[1]; + z2 = b[2]; + z3 = b[3]; + z4z5z6z7 = x8x9xAxB ^ S5[z0] ^ S6[z2] ^ S7[z1] ^ S8[z3] ^ S8[xA]; + b = unscramble(z4z5z6z7); + z4 = b[0]; + z5 = b[1]; + z6 = b[2]; + z7 = b[3]; + z8z9zAzB = xCxDxExF ^ S5[z7] ^ S6[z6] ^ S7[z5] ^ S8[z4] ^ S5[x9]; + b = unscramble(z8z9zAzB); + z8 = b[0]; + z9 = b[1]; + zA = b[2]; + zB = b[3]; + zCzDzEzF = x4x5x6x7 ^ S5[zA] ^ S6[z9] ^ S7[zB] ^ S8[z8] ^ S6[xB]; + b = unscramble(zCzDzEzF); + zC = b[0]; + zD = b[1]; + zE = b[2]; + zF = b[3]; + result.Kr8 = (S5[z3] ^ S6[z2] ^ S7[zC] ^ S8[zD] ^ S5[z9]) & 0x1F; + result.Kr9 = (S5[z1] ^ S6[z0] ^ S7[zE] ^ S8[zF] ^ S6[zC]) & 0x1F; + result.Kr10 = (S5[z7] ^ S6[z6] ^ S7[z8] ^ S8[z9] ^ S7[z2]) & 0x1F; + result.Kr11 = (S5[z5] ^ S6[z4] ^ S7[zA] ^ S8[zB] ^ S8[z6]) & 0x1F; + x0x1x2x3 = z8z9zAzB ^ S5[z5] ^ S6[z7] ^ S7[z4] ^ S8[z6] ^ S7[z0]; + b = unscramble(x0x1x2x3); + x0 = b[0]; + x1 = b[1]; + x2 = b[2]; + x3 = b[3]; + x4x5x6x7 = z0z1z2z3 ^ S5[x0] ^ S6[x2] ^ S7[x1] ^ S8[x3] ^ S8[z2]; + b = unscramble(x4x5x6x7); + x4 = b[0]; + x5 = b[1]; + x6 = b[2]; + x7 = b[3]; + x8x9xAxB = z4z5z6z7 ^ S5[x7] ^ S6[x6] ^ S7[x5] ^ S8[x4] ^ S5[z1]; + b = unscramble(x8x9xAxB); + x8 = b[0]; + x9 = b[1]; + xA = b[2]; + xB = b[3]; + xCxDxExF = zCzDzEzF ^ S5[xA] ^ S6[x9] ^ S7[xB] ^ S8[x8] ^ S6[z3]; + b = unscramble(xCxDxExF); + xC = b[0]; + xD = b[1]; + xE = b[2]; + xF = b[3]; + result.Kr12 = (S5[x8] ^ S6[x9] ^ S7[x7] ^ S8[x6] ^ S5[x3]) & 0x1F; + result.Kr13 = (S5[xA] ^ S6[xB] ^ S7[x5] ^ S8[x4] ^ S6[x7]) & 0x1F; + result.Kr14 = (S5[xC] ^ S6[xD] ^ S7[x3] ^ S8[x2] ^ S7[x8]) & 0x1F; + result.Kr15 = (S5[xE] ^ S6[xF] ^ S7[x1] ^ S8[x0] ^ S8[xD]) & 0x1F; + return result; + } + + /** + * The full encryption algorithm is given in the following four steps. + * <pre> + * INPUT: plaintext m1...m64; key K = k1...k128. + * OUTPUT: ciphertext c1...c64. + * </pre> + * <ol> + * <li>(key schedule) Compute 16 pairs of subkeys {Kmi, Kri} from a user + * key (see makeKey() method).</li> + * <li>(L0,R0) <-- (m1...m64). (Split the plaintext into left and right + * 32-bit halves L0 = m1...m32 and R0 = m33...m64.).</li> + * <li>(16 rounds) for i from 1 to 16, compute Li and Ri as follows: + * <ul> + * <li>Li = Ri-1;</li> + * <li>Ri = Li-1 ^ F(Ri-1,Kmi,Kri), where F is defined in method F() -- + * f is of Type 1, Type 2, or Type 3, depending on i, and ^ being the + * bitwise XOR function.</li> + * </ul> + * <li>c1...c64 <-- (R16,L16). (Exchange final blocks L16, R16 and + * concatenate to form the ciphertext.)</li> + * </ol> + * <p> + * Decryption is identical to the encryption algorithm given above, except + * that the rounds (and therefore the subkey pairs) are used in reverse order + * to compute (L0,R0) from (R16,L16). + * <p> + * Looking at the iterations/rounds in pairs we have: + * <pre> + * (1a) Li = Ri-1; + * (1b) Ri = Li-1 ^ Fi(Ri-1); + * (2a) Li+1 = Ri; + * (2b) Ri+1 = Li ^ Fi+1(Ri); + * </pre> + * which by substituting (2a) in (2b) becomes + * <pre> + * (2c) Ri+1 = Li ^ Fi+1(Li+1); + * </pre> + * by substituting (1b) in (2a) and (1a) in (2c), we get: + * <pre> + * (3a) Li+1 = Li-1 ^ Fi(Ri-1); + * (3b) Ri+1 = Ri-1 ^ Fi+1(Li+1); + * </pre> + * Using only one couple of variables L and R, initialised to L0 and R0 + * respectively, the assignments for each pair of rounds become: + * <pre> + * (4a) L ^= Fi(R); + * (4b) R ^= Fi+1(L); + * </pre> + * + * @param in contains the plain-text 64-bit block. + * @param i start index within input where data is considered. + * @param out will contain the cipher-text block. + * @param j index in out where cipher-text starts. + * @param k the session key object. + * @param bs the desired block size. + */ + public void encrypt(byte[] in, int i, byte[] out, int j, Object k, int bs) + { + if (bs != DEFAULT_BLOCK_SIZE) + throw new IllegalArgumentException(); + Cast5Key K = (Cast5Key) k; + int L = (in[i++] & 0xFF) << 24 + | (in[i++] & 0xFF) << 16 + | (in[i++] & 0xFF) << 8 + | in[i++] & 0xFF; + int R = (in[i++] & 0xFF) << 24 + | (in[i++] & 0xFF) << 16 + | (in[i++] & 0xFF) << 8 + | in[i ] & 0xFF; + L ^= f1(R, K.Km0, K.Kr0); + R ^= f2(L, K.Km1, K.Kr1); // round 2 + L ^= f3(R, K.Km2, K.Kr2); + R ^= f1(L, K.Km3, K.Kr3); // round 4 + L ^= f2(R, K.Km4, K.Kr4); + R ^= f3(L, K.Km5, K.Kr5); // round 6 + L ^= f1(R, K.Km6, K.Kr6); + R ^= f2(L, K.Km7, K.Kr7); // round 8 + L ^= f3(R, K.Km8, K.Kr8); + R ^= f1(L, K.Km9, K.Kr9); // round 10 + L ^= f2(R, K.Km10, K.Kr10); + R ^= f3(L, K.Km11, K.Kr11); // round 12 + if (K.rounds == _16_ROUNDS) + { + L ^= f1(R, K.Km12, K.Kr12); + R ^= f2(L, K.Km13, K.Kr13); // round 14 + L ^= f3(R, K.Km14, K.Kr14); + R ^= f1(L, K.Km15, K.Kr15); // round 16 + } + out[j++] = (byte)(R >>> 24); + out[j++] = (byte)(R >>> 16); + out[j++] = (byte)(R >>> 8); + out[j++] = (byte) R; + out[j++] = (byte)(L >>> 24); + out[j++] = (byte)(L >>> 16); + out[j++] = (byte)(L >>> 8); + out[j ] = (byte) L; + } + + public void decrypt(byte[] in, int i, byte[] out, int j, Object k, int bs) + { + if (bs != DEFAULT_BLOCK_SIZE) + throw new IllegalArgumentException(); + Cast5Key K = (Cast5Key) k; + int L = (in[i++] & 0xFF) << 24 + | (in[i++] & 0xFF) << 16 + | (in[i++] & 0xFF) << 8 + | in[i++] & 0xFF; + int R = (in[i++] & 0xFF) << 24 + | (in[i++] & 0xFF) << 16 + | (in[i++] & 0xFF) << 8 + | in[i ] & 0xFF; + if (K.rounds == _16_ROUNDS) + { + L ^= f1(R, K.Km15, K.Kr15); + R ^= f3(L, K.Km14, K.Kr14); + L ^= f2(R, K.Km13, K.Kr13); + R ^= f1(L, K.Km12, K.Kr12); + } + L ^= f3(R, K.Km11, K.Kr11); + R ^= f2(L, K.Km10, K.Kr10); + L ^= f1(R, K.Km9, K.Kr9); + R ^= f3(L, K.Km8, K.Kr8); + L ^= f2(R, K.Km7, K.Kr7); + R ^= f1(L, K.Km6, K.Kr6); + L ^= f3(R, K.Km5, K.Kr5); + R ^= f2(L, K.Km4, K.Kr4); + L ^= f1(R, K.Km3, K.Kr3); + R ^= f3(L, K.Km2, K.Kr2); + L ^= f2(R, K.Km1, K.Kr1); + R ^= f1(L, K.Km0, K.Kr0); + out[j++] = (byte)(R >>> 24); + out[j++] = (byte)(R >>> 16); + out[j++] = (byte)(R >>> 8); + out[j++] = (byte) R; + out[j++] = (byte)(L >>> 24); + out[j++] = (byte)(L >>> 16); + out[j++] = (byte)(L >>> 8); + out[j ] = (byte) L; + } + + public boolean selfTest() + { + if (valid == null) + { + boolean result = super.selfTest(); // do symmetry tests + if (result) + result = testKat(KAT_KEY, KAT_CT, KAT_PT); + valid = Boolean.valueOf(result); + } + return valid.booleanValue(); + } + + private final int f1(int I, int m, int r) + { + I = m + I; + I = I << r | I >>> (32 - r); + return (((S1[(I >>> 24) & 0xFF]) + ^ S2[(I >>> 16) & 0xFF]) + - S3[(I >>> 8) & 0xFF]) + + S4[ I & 0xFF]; + } + + private final int f2(int I, int m, int r) + { + I = m ^ I; + I = I << r | I >>> (32 - r); + return (((S1[(I >>> 24) & 0xFF]) + - S2[(I >>> 16) & 0xFF]) + + S3[(I >>> 8) & 0xFF]) + ^ S4[ I & 0xFF]; + } + + private final int f3(int I, int m, int r) + { + I = m - I; + I = I << r | I >>> (32 - r); + return (((S1[(I >>> 24) & 0xFF]) + + S2[(I >>> 16) & 0xFF]) + ^ S3[(I >>> 8) & 0xFF]) + - S4[ I & 0xFF]; + } + + /** An opaque CAST5 key object. */ + private class Cast5Key + { + int rounds; + /** Masking session keys. */ + int Km0, Km1, Km2, Km3, Km4, Km5, Km6, Km7, + Km8, Km9, Km10, Km11, Km12, Km13, Km14, Km15; + /** Rotation session keys. */ + int Kr0, Kr1, Kr2, Kr3, Kr4, Kr5, Kr6, Kr7, + Kr8, Kr9, Kr10, Kr11, Kr12, Kr13, Kr14, Kr15; + } +} diff --git a/libjava/classpath/gnu/javax/crypto/cipher/CipherFactory.java b/libjava/classpath/gnu/javax/crypto/cipher/CipherFactory.java new file mode 100644 index 000000000..fc9023626 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/cipher/CipherFactory.java @@ -0,0 +1,129 @@ +/* CipherFactory.java -- + Copyright (C) 2001, 2002, 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.cipher; + +import gnu.java.security.Registry; + +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; + +/** + * A <i>Factory</i> to instantiate symmetric block cipher instances. + */ +public class CipherFactory + implements Registry +{ + /** Trivial constructor to enforce Singleton pattern. */ + private CipherFactory() + { + super(); + } + + /** + * Returns an instance of a block cipher given its name. + * + * @param name the case-insensitive name of the symmetric-key block cipher + * algorithm. + * @return an instance of the designated cipher algorithm, or + * <code>null</code> if none is found. + * @exception InternalError if the implementation does not pass its self-test. + */ + public static final IBlockCipher getInstance(String name) + { + if (name == null) + return null; + name = name.trim(); + IBlockCipher result = null; + if (name.equalsIgnoreCase(ANUBIS_CIPHER)) + result = new Anubis(); + else if (name.equalsIgnoreCase(BLOWFISH_CIPHER)) + result = new Blowfish(); + else if (name.equalsIgnoreCase(DES_CIPHER)) + result = new DES(); + else if (name.equalsIgnoreCase(KHAZAD_CIPHER)) + result = new Khazad(); + else if (name.equalsIgnoreCase(RIJNDAEL_CIPHER) + || name.equalsIgnoreCase(AES_CIPHER)) + result = new Rijndael(); + else if (name.equalsIgnoreCase(SERPENT_CIPHER)) + result = new Serpent(); + else if (name.equalsIgnoreCase(SQUARE_CIPHER)) + result = new Square(); + else if (name.equalsIgnoreCase(TRIPLEDES_CIPHER) + || name.equalsIgnoreCase(DESEDE_CIPHER)) + result = new TripleDES(); + else if (name.equalsIgnoreCase(TWOFISH_CIPHER)) + result = new Twofish(); + else if (name.equalsIgnoreCase(CAST5_CIPHER) + || (name.equalsIgnoreCase(CAST128_CIPHER) + || (name.equalsIgnoreCase(CAST_128_CIPHER)))) + result = new Cast5(); + else if (name.equalsIgnoreCase(NULL_CIPHER)) + result = new NullCipher(); + + if (result != null && ! result.selfTest()) + throw new InternalError(result.name()); + + return result; + } + + /** + * Returns a {@link Set} of symmetric key block cipher implementation names + * supported by this <i>Factory</i>. + * + * @return a {@link Set} of block cipher names (Strings). + */ + public static final Set getNames() + { + HashSet hs = new HashSet(); + hs.add(ANUBIS_CIPHER); + hs.add(BLOWFISH_CIPHER); + hs.add(DES_CIPHER); + hs.add(KHAZAD_CIPHER); + hs.add(RIJNDAEL_CIPHER); + hs.add(SERPENT_CIPHER); + hs.add(SQUARE_CIPHER); + hs.add(TRIPLEDES_CIPHER); + hs.add(TWOFISH_CIPHER); + hs.add(CAST5_CIPHER); + hs.add(NULL_CIPHER); + return Collections.unmodifiableSet(hs); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/cipher/DES.java b/libjava/classpath/gnu/javax/crypto/cipher/DES.java new file mode 100644 index 000000000..ce538b75a --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/cipher/DES.java @@ -0,0 +1,652 @@ +/* DES.java -- + Copyright (C) 2002, 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.cipher; + +import gnu.java.security.Registry; +import gnu.java.security.Properties; +import gnu.java.security.util.Util; + +import java.security.InvalidKeyException; +import java.util.Arrays; +import java.util.Collections; +import java.util.Iterator; + +/** + * The Data Encryption Standard. DES is a 64-bit block cipher with a 56-bit + * key, developed by IBM in the 1970's for the standardization process begun by + * the National Bureau of Standards (now NIST). + * <p> + * New applications should not use DES except for compatibility. + * <p> + * This version is based upon the description and sample implementation in + * [1]. + * <p> + * References: + * <ol> + * <li>Bruce Schneier, <i>Applied Cryptography: Protocols, Algorithms, and + * Source Code in C, Second Edition</i>. (1996 John Wiley and Sons) ISBN + * 0-471-11709-9. Pages 265--301, 623--632.</li> + * </ol> + */ +public class DES + extends BaseCipher +{ + /** DES operates on 64 bit blocks. */ + public static final int BLOCK_SIZE = 8; + /** DES uses 56 bits of a 64 bit parity-adjusted key. */ + public static final int KEY_SIZE = 8; + // S-Boxes 1 through 8. + private static final int[] SP1 = new int[] { + 0x01010400, 0x00000000, 0x00010000, 0x01010404, 0x01010004, 0x00010404, + 0x00000004, 0x00010000, 0x00000400, 0x01010400, 0x01010404, 0x00000400, + 0x01000404, 0x01010004, 0x01000000, 0x00000004, 0x00000404, 0x01000400, + 0x01000400, 0x00010400, 0x00010400, 0x01010000, 0x01010000, 0x01000404, + 0x00010004, 0x01000004, 0x01000004, 0x00010004, 0x00000000, 0x00000404, + 0x00010404, 0x01000000, 0x00010000, 0x01010404, 0x00000004, 0x01010000, + 0x01010400, 0x01000000, 0x01000000, 0x00000400, 0x01010004, 0x00010000, + 0x00010400, 0x01000004, 0x00000400, 0x00000004, 0x01000404, 0x00010404, + 0x01010404, 0x00010004, 0x01010000, 0x01000404, 0x01000004, 0x00000404, + 0x00010404, 0x01010400, 0x00000404, 0x01000400, 0x01000400, 0x00000000, + 0x00010004, 0x00010400, 0x00000000, 0x01010004 }; + private static final int[] SP2 = new int[] { + 0x80108020, 0x80008000, 0x00008000, 0x00108020, 0x00100000, 0x00000020, + 0x80100020, 0x80008020, 0x80000020, 0x80108020, 0x80108000, 0x80000000, + 0x80008000, 0x00100000, 0x00000020, 0x80100020, 0x00108000, 0x00100020, + 0x80008020, 0x00000000, 0x80000000, 0x00008000, 0x00108020, 0x80100000, + 0x00100020, 0x80000020, 0x00000000, 0x00108000, 0x00008020, 0x80108000, + 0x80100000, 0x00008020, 0x00000000, 0x00108020, 0x80100020, 0x00100000, + 0x80008020, 0x80100000, 0x80108000, 0x00008000, 0x80100000, 0x80008000, + 0x00000020, 0x80108020, 0x00108020, 0x00000020, 0x00008000, 0x80000000, + 0x00008020, 0x80108000, 0x00100000, 0x80000020, 0x00100020, 0x80008020, + 0x80000020, 0x00100020, 0x00108000, 0x00000000, 0x80008000, 0x00008020, + 0x80000000, 0x80100020, 0x80108020, 0x00108000 }; + private static final int[] SP3 = new int[] { + 0x00000208, 0x08020200, 0x00000000, 0x08020008, 0x08000200, 0x00000000, + 0x00020208, 0x08000200, 0x00020008, 0x08000008, 0x08000008, 0x00020000, + 0x08020208, 0x00020008, 0x08020000, 0x00000208, 0x08000000, 0x00000008, + 0x08020200, 0x00000200, 0x00020200, 0x08020000, 0x08020008, 0x00020208, + 0x08000208, 0x00020200, 0x00020000, 0x08000208, 0x00000008, 0x08020208, + 0x00000200, 0x08000000, 0x08020200, 0x08000000, 0x00020008, 0x00000208, + 0x00020000, 0x08020200, 0x08000200, 0x00000000, 0x00000200, 0x00020008, + 0x08020208, 0x08000200, 0x08000008, 0x00000200, 0x00000000, 0x08020008, + 0x08000208, 0x00020000, 0x08000000, 0x08020208, 0x00000008, 0x00020208, + 0x00020200, 0x08000008, 0x08020000, 0x08000208, 0x00000208, 0x08020000, + 0x00020208, 0x00000008, 0x08020008, 0x00020200 }; + private static final int[] SP4 = new int[] { + 0x00802001, 0x00002081, 0x00002081, 0x00000080, 0x00802080, 0x00800081, + 0x00800001, 0x00002001, 0x00000000, 0x00802000, 0x00802000, 0x00802081, + 0x00000081, 0x00000000, 0x00800080, 0x00800001, 0x00000001, 0x00002000, + 0x00800000, 0x00802001, 0x00000080, 0x00800000, 0x00002001, 0x00002080, + 0x00800081, 0x00000001, 0x00002080, 0x00800080, 0x00002000, 0x00802080, + 0x00802081, 0x00000081, 0x00800080, 0x00800001, 0x00802000, 0x00802081, + 0x00000081, 0x00000000, 0x00000000, 0x00802000, 0x00002080, 0x00800080, + 0x00800081, 0x00000001, 0x00802001, 0x00002081, 0x00002081, 0x00000080, + 0x00802081, 0x00000081, 0x00000001, 0x00002000, 0x00800001, 0x00002001, + 0x00802080, 0x00800081, 0x00002001, 0x00002080, 0x00800000, 0x00802001, + 0x00000080, 0x00800000, 0x00002000, 0x00802080 }; + private static final int[] SP5 = new int[] { + 0x00000100, 0x02080100, 0x02080000, 0x42000100, 0x00080000, 0x00000100, + 0x40000000, 0x02080000, 0x40080100, 0x00080000, 0x02000100, 0x40080100, + 0x42000100, 0x42080000, 0x00080100, 0x40000000, 0x02000000, 0x40080000, + 0x40080000, 0x00000000, 0x40000100, 0x42080100, 0x42080100, 0x02000100, + 0x42080000, 0x40000100, 0x00000000, 0x42000000, 0x02080100, 0x02000000, + 0x42000000, 0x00080100, 0x00080000, 0x42000100, 0x00000100, 0x02000000, + 0x40000000, 0x02080000, 0x42000100, 0x40080100, 0x02000100, 0x40000000, + 0x42080000, 0x02080100, 0x40080100, 0x00000100, 0x02000000, 0x42080000, + 0x42080100, 0x00080100, 0x42000000, 0x42080100, 0x02080000, 0x00000000, + 0x40080000, 0x42000000, 0x00080100, 0x02000100, 0x40000100, 0x00080000, + 0x00000000, 0x40080000, 0x02080100, 0x40000100 }; + private static final int[] SP6 = new int[] { + 0x20000010, 0x20400000, 0x00004000, 0x20404010, 0x20400000, 0x00000010, + 0x20404010, 0x00400000, 0x20004000, 0x00404010, 0x00400000, 0x20000010, + 0x00400010, 0x20004000, 0x20000000, 0x00004010, 0x00000000, 0x00400010, + 0x20004010, 0x00004000, 0x00404000, 0x20004010, 0x00000010, 0x20400010, + 0x20400010, 0x00000000, 0x00404010, 0x20404000, 0x00004010, 0x00404000, + 0x20404000, 0x20000000, 0x20004000, 0x00000010, 0x20400010, 0x00404000, + 0x20404010, 0x00400000, 0x00004010, 0x20000010, 0x00400000, 0x20004000, + 0x20000000, 0x00004010, 0x20000010, 0x20404010, 0x00404000, 0x20400000, + 0x00404010, 0x20404000, 0x00000000, 0x20400010, 0x00000010, 0x00004000, + 0x20400000, 0x00404010, 0x00004000, 0x00400010, 0x20004010, 0x00000000, + 0x20404000, 0x20000000, 0x00400010, 0x20004010 }; + private static final int[] SP7 = new int[] { + 0x00200000, 0x04200002, 0x04000802, 0x00000000, 0x00000800, 0x04000802, + 0x00200802, 0x04200800, 0x04200802, 0x00200000, 0x00000000, 0x04000002, + 0x00000002, 0x04000000, 0x04200002, 0x00000802, 0x04000800, 0x00200802, + 0x00200002, 0x04000800, 0x04000002, 0x04200000, 0x04200800, 0x00200002, + 0x04200000, 0x00000800, 0x00000802, 0x04200802, 0x00200800, 0x00000002, + 0x04000000, 0x00200800, 0x04000000, 0x00200800, 0x00200000, 0x04000802, + 0x04000802, 0x04200002, 0x04200002, 0x00000002, 0x00200002, 0x04000000, + 0x04000800, 0x00200000, 0x04200800, 0x00000802, 0x00200802, 0x04200800, + 0x00000802, 0x04000002, 0x04200802, 0x04200000, 0x00200800, 0x00000000, + 0x00000002, 0x04200802, 0x00000000, 0x00200802, 0x04200000, 0x00000800, + 0x04000002, 0x04000800, 0x00000800, 0x00200002 }; + private static final int[] SP8 = new int[] { + 0x10001040, 0x00001000, 0x00040000, 0x10041040, 0x10000000, 0x10001040, + 0x00000040, 0x10000000, 0x00040040, 0x10040000, 0x10041040, 0x00041000, + 0x10041000, 0x00041040, 0x00001000, 0x00000040, 0x10040000, 0x10000040, + 0x10001000, 0x00001040, 0x00041000, 0x00040040, 0x10040040, 0x10041000, + 0x00001040, 0x00000000, 0x00000000, 0x10040040, 0x10000040, 0x10001000, + 0x00041040, 0x00040000, 0x00041040, 0x00040000, 0x10041000, 0x00001000, + 0x00000040, 0x10040040, 0x00001000, 0x00041040, 0x10001000, 0x00000040, + 0x10000040, 0x10040000, 0x10040040, 0x10000000, 0x00040000, 0x10001040, + 0x00000000, 0x10041040, 0x00040040, 0x10000040, 0x10040000, 0x10001000, + 0x10001040, 0x00000000, 0x10041040, 0x00041000, 0x00041000, 0x00001040, + 0x00001040, 0x00040040, 0x10000000, 0x10041000 }; + /** + * Constants that help in determining whether or not a byte array is parity + * adjusted. + */ + private static final byte[] PARITY = { + 8, 1, 0, 8, 0, 8, 8, 0, 0, 8, 8, 0, 8, 0, 2, 8, + 0, 8, 8, 0, 8, 0, 0, 8, 8, 0, 0, 8, 0, 8, 8, 3, + 0, 8, 8, 0, 8, 0, 0, 8, 8, 0, 0, 8, 0, 8, 8, 0, + 8, 0, 0, 8, 0, 8, 8, 0, 0, 8, 8, 0, 8, 0, 0, 8, + 0, 8, 8, 0, 8, 0, 0, 8, 8, 0, 0, 8, 0, 8, 8, 0, + 8, 0, 0, 8, 0, 8, 8, 0, 0, 8, 8, 0, 8, 0, 0, 8, + 8, 0, 0, 8, 0, 8, 8, 0, 0, 8, 8, 0, 8, 0, 0, 8, + 0, 8, 8, 0, 8, 0, 0, 8, 8, 0, 0, 8, 0, 8, 8, 0, + 0, 8, 8, 0, 8, 0, 0, 8, 8, 0, 0, 8, 0, 8, 8, 0, + 8, 0, 0, 8, 0, 8, 8, 0, 0, 8, 8, 0, 8, 0, 0, 8, + 8, 0, 0, 8, 0, 8, 8, 0, 0, 8, 8, 0, 8, 0, 0, 8, + 0, 8, 8, 0, 8, 0, 0, 8, 8, 0, 0, 8, 0, 8, 8, 0, + 8, 0, 0, 8, 0, 8, 8, 0, 0, 8, 8, 0, 8, 0, 0, 8, + 0, 8, 8, 0, 8, 0, 0, 8, 8, 0, 0, 8, 0, 8, 8, 0, + 4, 8, 8, 0, 8, 0, 0, 8, 8, 0, 0, 8, 0, 8, 8, 0, + 8, 5, 0, 8, 0, 8, 8, 0, 0, 8, 8, 0, 8, 0, 6, 8 }; + // Key schedule constants. + private static final byte[] ROTARS = { + 1, 2, 4, 6, 8, 10, 12, 14, 15, 17, 19, 21, 23, 25, 27, 28 }; + private static final byte[] PC1 = { + 56, 48, 40, 32, 24, 16, 8, 0, 57, 49, 41, 33, 25, 17, 9, 1, + 58, 50, 42, 34, 26, 18, 10, 2, 59, 51, 43, 35, 62, 54, 46, 38, + 30, 22, 14, 6, 61, 53, 45, 37, 29, 21, 13, 5, 60, 52, 44, 36, + 28, 20, 12, 4, 27, 19, 11, 3 }; + private static final byte[] PC2 = { + 13, 16, 10, 23, 0, 4, 2, 27, 14, 5, 20, 9, 22, 18, 11, 3, + 25, 7, 15, 6, 26, 19, 12, 1, 40, 51, 30, 36, 46, 54, 29, 39, + 50, 44, 32, 47, 43, 48, 38, 55, 33, 52, 45, 41, 49, 35, 28, 31 }; + /** + * Weak keys (parity adjusted): If all the bits in each half are either 0 + * or 1, then the key used for any cycle of the algorithm is the same as + * all other cycles. + */ + public static final byte[][] WEAK_KEYS = { + Util.toBytesFromString("0101010101010101"), + Util.toBytesFromString("01010101FEFEFEFE"), + Util.toBytesFromString("FEFEFEFE01010101"), + Util.toBytesFromString("FEFEFEFEFEFEFEFE") }; + /** + * Semi-weak keys (parity adjusted): Some pairs of keys encrypt plain text + * to identical cipher text. In other words, one key in the pair can decrypt + * messages that were encrypted with the other key. These keys are called + * semi-weak keys. This occurs because instead of 16 different sub-keys being + * generated, these semi-weak keys produce only two different sub-keys. + */ + public static final byte[][] SEMIWEAK_KEYS = { + Util.toBytesFromString("01FE01FE01FE01FE"), + Util.toBytesFromString("FE01FE01FE01FE01"), + Util.toBytesFromString("1FE01FE00EF10EF1"), + Util.toBytesFromString("E01FE01FF10EF10E"), + Util.toBytesFromString("01E001E001F101F1"), + Util.toBytesFromString("E001E001F101F101"), + Util.toBytesFromString("1FFE1FFE0EFE0EFE"), + Util.toBytesFromString("FE1FFE1FFE0EFE0E"), + Util.toBytesFromString("011F011F010E010E"), + Util.toBytesFromString("1F011F010E010E01"), + Util.toBytesFromString("E0FEE0FEF1FEF1FE"), + Util.toBytesFromString("FEE0FEE0FEF1FEF1") }; + /** Possible weak keys (parity adjusted) --produce 4 instead of 16 subkeys. */ + public static final byte[][] POSSIBLE_WEAK_KEYS = { + Util.toBytesFromString("1F1F01010E0E0101"), + Util.toBytesFromString("011F1F01010E0E01"), + Util.toBytesFromString("1F01011F0E01010E"), + Util.toBytesFromString("01011F1F01010E0E"), + Util.toBytesFromString("E0E00101F1F10101"), + Util.toBytesFromString("FEFE0101FEFE0101"), + Util.toBytesFromString("FEE01F01FEF10E01"), + Util.toBytesFromString("E0FE1F01F1FE0E01"), + Util.toBytesFromString("FEE0011FFEF1010E"), + Util.toBytesFromString("E0FE011FF1FE010E"), + Util.toBytesFromString("E0E01F1FF1F10E0E"), + Util.toBytesFromString("FEFE1F1FFEFE0E0E"), + Util.toBytesFromString("1F1F01010E0E0101"), + Util.toBytesFromString("011F1F01010E0E01"), + Util.toBytesFromString("1F01011F0E01010E"), + Util.toBytesFromString("01011F1F01010E0E"), + Util.toBytesFromString("01E0E00101F1F101"), + Util.toBytesFromString("1FFEE0010EFEF001"), + Util.toBytesFromString("1FE0FE010EF1FE01"), + Util.toBytesFromString("01FEFE0101FEFE01"), + Util.toBytesFromString("1FE0E01F0EF1F10E"), + Util.toBytesFromString("01FEE01F01FEF10E"), + Util.toBytesFromString("01E0FE1F01F1FE0E"), + Util.toBytesFromString("1FFEFE1F0EFEFE0E"), + + Util.toBytesFromString("E00101E0F10101F1"), + Util.toBytesFromString("FE1F01E0FE0E0EF1"), + Util.toBytesFromString("FE011FE0FE010EF1"), + Util.toBytesFromString("E01F1FE0F10E0EF1"), + Util.toBytesFromString("FE0101FEFE0101FE"), + Util.toBytesFromString("E01F01FEF10E01FE"), + Util.toBytesFromString("E0011FFEF1010EFE"), + Util.toBytesFromString("FE1F1FFEFE0E0EFE"), + Util.toBytesFromString("1FFE01E00EFE01F1"), + Util.toBytesFromString("01FE1FE001FE0EF1"), + Util.toBytesFromString("1FE001FE0EF101FE"), + Util.toBytesFromString("01E01FFE01F10EFE"), + Util.toBytesFromString("0101E0E00101F1F1"), + Util.toBytesFromString("1F1FE0E00E0EF1F1"), + Util.toBytesFromString("1F01FEE00E01FEF1"), + Util.toBytesFromString("011FFEE0010EFEF1"), + Util.toBytesFromString("1F01E0FE0E01F1FE"), + Util.toBytesFromString("011FE0FE010EF1FE"), + Util.toBytesFromString("0101FEFE0001FEFE"), + Util.toBytesFromString("1F1FFEFE0E0EFEFE"), + Util.toBytesFromString("FEFEE0E0FEFEF1F1"), + Util.toBytesFromString("E0FEFEE0F1FEFEF1"), + Util.toBytesFromString("FEE0E0FEFEF1F1FE"), + Util.toBytesFromString("E0E0FEFEF1F1FEFE") }; + + /** Default 0-argument constructor. */ + public DES() + { + super(Registry.DES_CIPHER, BLOCK_SIZE, KEY_SIZE); + } + + /** + * Adjust the parity for a raw key array. This essentially means that each + * byte in the array will have an odd number of '1' bits (the last bit in + * each byte is unused. + * + * @param kb The key array, to be parity-adjusted. + * @param offset The starting index into the key bytes. + */ + public static void adjustParity(byte[] kb, int offset) + { + for (int i = offset; i < offset + KEY_SIZE; i++) + kb[i] ^= (PARITY[kb[i] & 0xff] == 8) ? 1 : 0; + } + + /** + * Test if a byte array, which must be at least 8 bytes long, is parity + * adjusted. + * + * @param kb The key bytes. + * @param offset The starting index into the key bytes. + * @return <code>true</code> if the first 8 bytes of <i>kb</i> have been + * parity adjusted. <code>false</code> otherwise. + */ + public static boolean isParityAdjusted(byte[] kb, int offset) + { + int w = 0x88888888; + int n = PARITY[kb[offset + 0] & 0xff]; + n <<= 4; + n |= PARITY[kb[offset + 1] & 0xff]; + n <<= 4; + n |= PARITY[kb[offset + 2] & 0xff]; + n <<= 4; + n |= PARITY[kb[offset + 3] & 0xff]; + n <<= 4; + n |= PARITY[kb[offset + 4] & 0xff]; + n <<= 4; + n |= PARITY[kb[offset + 5] & 0xff]; + n <<= 4; + n |= PARITY[kb[offset + 6] & 0xff]; + n <<= 4; + n |= PARITY[kb[offset + 7] & 0xff]; + return (n & w) == 0; + } + + /** + * Test if a key is a weak key. + * + * @param kb The key to test. + * @return <code>true</code> if the key is weak. + */ + public static boolean isWeak(byte[] kb) + { + for (int i = 0; i < WEAK_KEYS.length; i++) + if (Arrays.equals(WEAK_KEYS[i], kb)) + return true; + return false; + } + + /** + * Test if a key is a semi-weak key. + * + * @param kb The key to test. + * @return <code>true</code> if this key is semi-weak. + */ + public static boolean isSemiWeak(byte[] kb) + { + for (int i = 0; i < SEMIWEAK_KEYS.length; i++) + if (Arrays.equals(SEMIWEAK_KEYS[i], kb)) + return true; + return false; + } + + /** + * Test if the designated byte array represents a possibly weak key. + * + * @param kb the byte array to test. + * @return <code>true</code> if <code>kb</code>represents a possibly weak key. + * Returns <code>false</code> otherwise. + */ + public static boolean isPossibleWeak(byte[] kb) + { + for (int i = 0; i < POSSIBLE_WEAK_KEYS.length; i++) + if (Arrays.equals(POSSIBLE_WEAK_KEYS[i], kb)) + return true; + return false; + } + + /** + * The core DES function. This is used for both encryption and decryption, + * the only difference being the key. + * + * @param in The input bytes. + * @param i The starting offset into the input bytes. + * @param out The output bytes. + * @param o The starting offset into the output bytes. + * @param key The working key. + */ + private static void desFunc(byte[] in, int i, byte[] out, int o, int[] key) + { + int right, left, work; + // Load. + left = (in[i++] & 0xff) << 24 + | (in[i++] & 0xff) << 16 + | (in[i++] & 0xff) << 8 + | in[i++] & 0xff; + right = (in[i++] & 0xff) << 24 + | (in[i++] & 0xff) << 16 + | (in[i++] & 0xff) << 8 + | in[i ] & 0xff; + // Initial permutation. + work = ((left >>> 4) ^ right) & 0x0F0F0F0F; + left ^= work << 4; + right ^= work; + + work = ((left >>> 16) ^ right) & 0x0000FFFF; + left ^= work << 16; + right ^= work; + + work = ((right >>> 2) ^ left) & 0x33333333; + right ^= work << 2; + left ^= work; + + work = ((right >>> 8) ^ left) & 0x00FF00FF; + right ^= work << 8; + left ^= work; + + right = ((right << 1) | ((right >>> 31) & 1)) & 0xFFFFFFFF; + work = (left ^ right) & 0xAAAAAAAA; + left ^= work; + right ^= work; + left = ((left << 1) | ((left >>> 31) & 1)) & 0xFFFFFFFF; + + int k = 0, t; + for (int round = 0; round < 8; round++) + { + work = right >>> 4 | right << 28; + work ^= key[k++]; + t = SP7[work & 0x3F]; + work >>>= 8; + t |= SP5[work & 0x3F]; + work >>>= 8; + t |= SP3[work & 0x3F]; + work >>>= 8; + t |= SP1[work & 0x3F]; + work = right ^ key[k++]; + t |= SP8[work & 0x3F]; + work >>>= 8; + t |= SP6[work & 0x3F]; + work >>>= 8; + t |= SP4[work & 0x3F]; + work >>>= 8; + t |= SP2[work & 0x3F]; + left ^= t; + + work = left >>> 4 | left << 28; + work ^= key[k++]; + t = SP7[work & 0x3F]; + work >>>= 8; + t |= SP5[work & 0x3F]; + work >>>= 8; + t |= SP3[work & 0x3F]; + work >>>= 8; + t |= SP1[work & 0x3F]; + work = left ^ key[k++]; + t |= SP8[work & 0x3F]; + work >>>= 8; + t |= SP6[work & 0x3F]; + work >>>= 8; + t |= SP4[work & 0x3F]; + work >>>= 8; + t |= SP2[work & 0x3F]; + right ^= t; + } + // The final permutation. + right = (right << 31) | (right >>> 1); + work = (left ^ right) & 0xAAAAAAAA; + left ^= work; + right ^= work; + left = (left << 31) | (left >>> 1); + + work = ((left >>> 8) ^ right) & 0x00FF00FF; + left ^= work << 8; + right ^= work; + + work = ((left >>> 2) ^ right) & 0x33333333; + left ^= work << 2; + right ^= work; + + work = ((right >>> 16) ^ left) & 0x0000FFFF; + right ^= work << 16; + left ^= work; + + work = ((right >>> 4) ^ left) & 0x0F0F0F0F; + right ^= work << 4; + left ^= work; + + out[o++] = (byte)(right >>> 24); + out[o++] = (byte)(right >>> 16); + out[o++] = (byte)(right >>> 8); + out[o++] = (byte) right; + out[o++] = (byte)(left >>> 24); + out[o++] = (byte)(left >>> 16); + out[o++] = (byte)(left >>> 8); + out[o ] = (byte) left; + } + + public Object clone() + { + return new DES(); + } + + public Iterator blockSizes() + { + return Collections.singleton(Integer.valueOf(BLOCK_SIZE)).iterator(); + } + + public Iterator keySizes() + { + return Collections.singleton(Integer.valueOf(KEY_SIZE)).iterator(); + } + + public Object makeKey(byte[] kb, int bs) throws InvalidKeyException + { + if (kb == null || kb.length != KEY_SIZE) + throw new InvalidKeyException("DES keys must be 8 bytes long"); + + if (Properties.checkForWeakKeys() + && (isWeak(kb) || isSemiWeak(kb) || isPossibleWeak(kb))) + throw new WeakKeyException(); + + int i, j, l, m, n; + long pc1m = 0, pcr = 0; + + for (i = 0; i < 56; i++) + { + l = PC1[i]; + pc1m |= ((kb[l >>> 3] & (0x80 >>> (l & 7))) != 0) ? (1L << (55 - i)) + : 0; + } + Context ctx = new Context(); + // Encryption key first. + for (i = 0; i < 16; i++) + { + pcr = 0; + m = i << 1; + n = m + 1; + for (j = 0; j < 28; j++) + { + l = j + ROTARS[i]; + if (l < 28) + pcr |= ((pc1m & 1L << (55 - l)) != 0) ? (1L << (55 - j)) : 0; + else + pcr |= ((pc1m & 1L << (55 - (l - 28))) != 0) ? (1L << (55 - j)) + : 0; + } + for (j = 28; j < 56; j++) + { + l = j + ROTARS[i]; + if (l < 56) + pcr |= ((pc1m & 1L << (55 - l)) != 0) ? (1L << (55 - j)) : 0; + else + pcr |= ((pc1m & 1L << (55 - (l - 28))) != 0) ? (1L << (55 - j)) + : 0; + } + for (j = 0; j < 24; j++) + { + if ((pcr & 1L << (55 - PC2[j])) != 0) + ctx.ek[m] |= 1 << (23 - j); + if ((pcr & 1L << (55 - PC2[j + 24])) != 0) + ctx.ek[n] |= 1 << (23 - j); + } + } + // The decryption key is the same, but in reversed order. + for (i = 0; i < Context.EXPANDED_KEY_SIZE; i += 2) + { + ctx.dk[30 - i] = ctx.ek[i]; + ctx.dk[31 - i] = ctx.ek[i + 1]; + } + // "Cook" the keys. + for (i = 0; i < 32; i += 2) + { + int x, y; + x = ctx.ek[i]; + y = ctx.ek[i + 1]; + ctx.ek[i ] = ((x & 0x00FC0000) << 6) + | ((x & 0x00000FC0) << 10) + | ((y & 0x00FC0000) >>> 10) + | ((y & 0x00000FC0) >>> 6); + ctx.ek[i + 1] = ((x & 0x0003F000) << 12) + | ((x & 0x0000003F) << 16) + | ((y & 0x0003F000) >>> 4) + | (y & 0x0000003F); + x = ctx.dk[i]; + y = ctx.dk[i + 1]; + ctx.dk[i ] = ((x & 0x00FC0000) << 6) + | ((x & 0x00000FC0) << 10) + | ((y & 0x00FC0000) >>> 10) + | ((y & 0x00000FC0) >>> 6); + ctx.dk[i + 1] = ((x & 0x0003F000) << 12) + | ((x & 0x0000003F) << 16) + | ((y & 0x0003F000) >>> 4) + | (y & 0x0000003F); + } + return ctx; + } + + public void encrypt(byte[] in, int i, byte[] out, int o, Object K, int bs) + { + desFunc(in, i, out, o, ((Context) K).ek); + } + + public void decrypt(byte[] in, int i, byte[] out, int o, Object K, int bs) + { + desFunc(in, i, out, o, ((Context) K).dk); + } + + /** + * Simple wrapper class around the session keys. Package-private so TripleDES + * can see it. + */ + final class Context + { + private static final int EXPANDED_KEY_SIZE = 32; + + /** The encryption key. */ + int[] ek; + + /** The decryption key. */ + int[] dk; + + /** Default 0-arguments constructor. */ + Context() + { + ek = new int[EXPANDED_KEY_SIZE]; + dk = new int[EXPANDED_KEY_SIZE]; + } + + byte[] getEncryptionKeyBytes() + { + return toByteArray(ek); + } + + byte[] getDecryptionKeyBytes() + { + return toByteArray(dk); + } + + byte[] toByteArray(int[] k) + { + byte[] result = new byte[4 * k.length]; + for (int i = 0, j = 0; i < k.length; i++) + { + result[j++] = (byte)(k[i] >>> 24); + result[j++] = (byte)(k[i] >>> 16); + result[j++] = (byte)(k[i] >>> 8); + result[j++] = (byte) k[i]; + } + return result; + } + } +} diff --git a/libjava/classpath/gnu/javax/crypto/cipher/IBlockCipher.java b/libjava/classpath/gnu/javax/crypto/cipher/IBlockCipher.java new file mode 100644 index 000000000..86f8b34e0 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/cipher/IBlockCipher.java @@ -0,0 +1,195 @@ +/* IBlockCipher.java -- + Copyright (C) 2001, 2002, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.cipher; + +import java.security.InvalidKeyException; +import java.util.Iterator; +import java.util.Map; + +/** + * The basic visible methods of any symmetric key block cipher. + * <p> + * A symmetric key block cipher is a function that maps n-bit plaintext blocks + * to n-bit ciphertext blocks; n being the cipher's <i>block size</i>. This + * encryption function is parameterised by a k-bit key, and is invertible. Its + * inverse is the decryption function. + * <p> + * Possible initialisation values for an instance of this type are: + * <ul> + * <li>The block size in which to operate this block cipher instance. This + * value is <b>optional</b>, if unspecified, the block cipher's default block + * size shall be used.</li> + * <li>The byte array containing the user supplied key material to use for + * generating the cipher's session key(s). This value is <b>mandatory</b> and + * should be included in the initialisation parameters. If it isn't, an + * {@link IllegalStateException} will be thrown if any method, other than + * <code>reset()</code> is invoked on the instance. Furthermore, the size of + * this key material shall be taken as an indication on the key size in which to + * operate this instance.</li> + * </ul> + * <p> + * <b>IMPLEMENTATION NOTE</b>: Although all the concrete classes in this + * package implement the {@link Cloneable} interface, it is important to note + * here that such an operation <b>DOES NOT</b> clone any session key material + * that may have been used in initialising the source cipher (the instance to be + * cloned). Instead a clone of an already initialised cipher is another instance + * that operates with the <b>same block size</b> but without any knowledge of + * neither key material nor key size. + */ +public interface IBlockCipher + extends Cloneable +{ + /** + * Property name of the block size in which to operate a block cipher. The + * value associated with this property name is taken to be an {@link Integer}. + */ + String CIPHER_BLOCK_SIZE = "gnu.crypto.cipher.block.size"; + /** + * Property name of the user-supplied key material. The value associated to + * this property name is taken to be a byte array. + */ + String KEY_MATERIAL = "gnu.crypto.cipher.key.material"; + + /** + * Returns the canonical name of this instance. + * + * @return the canonical name of this instance. + */ + String name(); + + /** + * Returns the default value, in bytes, of the algorithm's block size. + * + * @return the default value, in bytes, of the algorithm's block size. + */ + int defaultBlockSize(); + + /** + * Returns the default value, in bytes, of the algorithm's key size. + * + * @return the default value, in bytes, of the algorithm's key size. + */ + int defaultKeySize(); + + /** + * Returns an {@link Iterator} over the supported block sizes. Each element + * returned by this object is an {@link Integer}. + * + * @return an {@link Iterator} over the supported block sizes. + */ + Iterator blockSizes(); + + /** + * Returns an {@link Iterator} over the supported key sizes. Each element + * returned by this object is an {@link Integer}. + * + * @return an {@link Iterator} over the supported key sizes. + */ + Iterator keySizes(); + + /** + * Returns a clone of this instance. + * + * @return a clone copy of this instance. + */ + Object clone(); + + /** + * Initialises the algorithm with designated attributes. Permissible names and + * values are described in the class documentation above. + * + * @param attributes a set of name-value pairs that describes the desired + * future behaviour of this instance. + * @exception InvalidKeyException if the key data is invalid. + * @exception IllegalStateException if the instance is already initialised. + * @see #KEY_MATERIAL + * @see #CIPHER_BLOCK_SIZE + */ + void init(Map attributes) throws InvalidKeyException, IllegalStateException; + + /** + * Returns the currently set block size for this instance. + * + * @return the current block size for this instance. + * @exception IllegalStateException if the instance is not initialised. + */ + int currentBlockSize() throws IllegalStateException; + + /** + * Resets the algorithm instance for re-initialisation and use with other + * characteristics. This method always succeeds. + */ + void reset(); + + /** + * Encrypts exactly one block of plaintext. + * + * @param in the plaintext. + * @param inOffset index of <code>in</code> from which to start considering + * data. + * @param out the ciphertext. + * @param outOffset index of <code>out</code> from which to store result. + * @exception IllegalStateException if the instance is not initialised. + */ + void encryptBlock(byte[] in, int inOffset, byte[] out, int outOffset) + throws IllegalStateException; + + /** + * Decrypts exactly one block of ciphertext. + * + * @param in the plaintext. + * @param inOffset index of <code>in</code> from which to start considering + * data. + * @param out the ciphertext. + * @param outOffset index of <code>out</code> from which to store result. + * @exception IllegalStateException if the instance is not initialised. + */ + void decryptBlock(byte[] in, int inOffset, byte[] out, int outOffset) + throws IllegalStateException; + + /** + * A <i>correctness</i> test that consists of basic symmetric encryption / + * decryption test(s) for all supported block and key sizes, as well as one + * (1) variable key Known Answer Test (KAT). + * + * @return <code>true</code> if the implementation passes simple + * <i>correctness</i> tests. Returns <code>false</code> otherwise. + */ + boolean selfTest(); +} diff --git a/libjava/classpath/gnu/javax/crypto/cipher/IBlockCipherSpi.java b/libjava/classpath/gnu/javax/crypto/cipher/IBlockCipherSpi.java new file mode 100644 index 000000000..9b2172158 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/cipher/IBlockCipherSpi.java @@ -0,0 +1,124 @@ +/* IBlockCipherSpi.java -- + Copyright (C) 2001, 2002, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.cipher; + +import java.security.InvalidKeyException; +import java.util.Iterator; + +/** + * Package-private interface exposing mandatory methods to be implemented by + * concrete {@link BaseCipher} sub-classes. + */ +interface IBlockCipherSpi + extends Cloneable +{ + /** + * Returns an {@link Iterator} over the supported block sizes. Each element + * returned by this object is a {@link java.lang.Integer}. + * + * @return an <code>Iterator</code> over the supported block sizes. + */ + Iterator blockSizes(); + + /** + * Returns an {@link Iterator} over the supported key sizes. Each element + * returned by this object is a {@link java.lang.Integer}. + * + * @return an <code>Iterator</code> over the supported key sizes. + */ + Iterator keySizes(); + + /** + * Expands a user-supplied key material into a session key for a designated + * <i>block size</i>. + * + * @param k the user-supplied key material. + * @param bs the desired block size in bytes. + * @return an Object encapsulating the session key. + * @exception IllegalArgumentException if the block size is invalid. + * @exception InvalidKeyException if the key data is invalid. + */ + Object makeKey(byte[] k, int bs) throws InvalidKeyException; + + /** + * Encrypts exactly one block of plaintext. + * + * @param in the plaintext. + * @param inOffset index of <code>in</code> from which to start considering + * data. + * @param out the ciphertext. + * @param outOffset index of <code>out</code> from which to store the + * result. + * @param k the session key to use. + * @param bs the block size to use. + * @exception IllegalArgumentException if the block size is invalid. + * @exception ArrayIndexOutOfBoundsException if there is not enough room in + * either the plaintext or ciphertext buffers. + */ + void encrypt(byte[] in, int inOffset, byte[] out, int outOffset, Object k, + int bs); + + /** + * Decrypts exactly one block of ciphertext. + * + * @param in the ciphertext. + * @param inOffset index of <code>in</code> from which to start considering + * data. + * @param out the plaintext. + * @param outOffset index of <code>out</code> from which to store the + * result. + * @param k the session key to use. + * @param bs the block size to use. + * @exception IllegalArgumentException if the block size is invalid. + * @exception ArrayIndexOutOfBoundsException if there is not enough room in + * either the plaintext or ciphertext buffers. + */ + void decrypt(byte[] in, int inOffset, byte[] out, int outOffset, Object k, + int bs); + + /** + * A <i>correctness</i> test that consists of basic symmetric encryption / + * decryption test(s) for all supported block and key sizes, as well as one + * (1) variable key Known Answer Test (KAT). + * + * @return <code>true</code> if the implementation passes simple + * <i>correctness</i> tests. Returns <code>false</code> otherwise. + */ + boolean selfTest(); +} diff --git a/libjava/classpath/gnu/javax/crypto/cipher/Khazad.java b/libjava/classpath/gnu/javax/crypto/cipher/Khazad.java new file mode 100644 index 000000000..55e42628b --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/cipher/Khazad.java @@ -0,0 +1,449 @@ +/* Khazad.java -- + Copyright (C) 2001, 2002, 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.cipher; + +import gnu.java.security.Configuration; +import gnu.java.security.Registry; +import gnu.java.security.util.Util; + +import java.security.InvalidKeyException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Iterator; +import java.util.logging.Logger; + +/** + * Khazad is a 64-bit (legacy-level) block cipher that accepts a 128-bit key. + * The cipher is a uniform substitution-permutation network whose inverse only + * differs from the forward operation in the key schedule. The overall cipher + * design follows the Wide Trail strategy, favours component reuse, and permits + * a wide variety of implementation trade-offs. + * <p> + * References: + * <ol> + * <li><a + * href="http://planeta.terra.com.br/informatica/paulobarreto/KhazadPage.html">The + * Khazad Block Cipher</a>.<br> + * <a href="mailto:paulo.barreto@terra.com.br">Paulo S.L.M. Barreto</a> and <a + * href="mailto:vincent.rijmen@esat.kuleuven.ac.be">Vincent Rijmen</a>.</li> + * </ol> + */ +public final class Khazad + extends BaseCipher +{ + private static final Logger log = Logger.getLogger(Khazad.class.getName()); + private static final int DEFAULT_BLOCK_SIZE = 8; // in bytes + private static final int DEFAULT_KEY_SIZE = 16; // in bytes + private static final int R = 8; // standard number of rounds; para. 3.7 + private static final String Sd = // p. 20 [KHAZAD] + "\uBA54\u2F74\u53D3\uD24D\u50AC\u8DBF\u7052\u9A4C" + + "\uEAD5\u97D1\u3351\u5BA6\uDE48\uA899\uDB32\uB7FC" + + "\uE39E\u919B\uE2BB\u416E\uA5CB\u6B95\uA1F3\uB102" + + "\uCCC4\u1D14\uC363\uDA5D\u5FDC\u7DCD\u7F5A\u6C5C" + + "\uF726\uFFED\uE89D\u6F8E\u19A0\uF089\u0F07\uAFFB" + + "\u0815\u0D04\u0164\uDF76\u79DD\u3D16\u3F37\u6D38" + + "\uB973\uE935\u5571\u7B8C\u7288\uF62A\u3E5E\u2746" + + "\u0C65\u6861\u03C1\u57D6\uD958\uD866\uD73A\uC83C" + + "\uFA96\uA798\uECB8\uC7AE\u694B\uABA9\u670A\u47F2" + + "\uB522\uE5EE\uBE2B\u8112\u831B\u0E23\uF545\u21CE" + + "\u492C\uF9E6\uB628\u1782\u1A8B\uFE8A\u09C9\u874E" + + "\uE12E\uE4E0\uEB90\uA41E\u8560\u0025\uF4F1\u940B" + + "\uE775\uEF34\u31D4\uD086\u7EAD\uFD29\u303B\u9FF8" + + "\uC613\u0605\uC511\u777C\u7A78\u361C\u3959\u1856" + + "\uB3B0\u2420\uB292\uA3C0\u4462\u10B4\u8443\u93C2" + + "\u4ABD\u8F2D\uBC9C\u6A40\uCFA2\u804F\u1FCA\uAA42"; + private static final byte[] S = new byte[256]; + private static final int[] T0 = new int[256]; + private static final int[] T1 = new int[256]; + private static final int[] T2 = new int[256]; + private static final int[] T3 = new int[256]; + private static final int[] T4 = new int[256]; + private static final int[] T5 = new int[256]; + private static final int[] T6 = new int[256]; + private static final int[] T7 = new int[256]; + private static final int[][] rc = new int[R + 1][2]; // round constants + /** + * KAT vector (from ecb_vk): I=120 KEY=00000000000000000000000000000100 + * CT=A0C86A1BBE2CBF4C + */ + private static final byte[] KAT_KEY = + Util.toBytesFromString("00000000000000000000000000000100"); + private static final byte[] KAT_CT = Util.toBytesFromString("A0C86A1BBE2CBF4C"); + /** caches the result of the correctness test, once executed. */ + private static Boolean valid; + + static + { + long time = System.currentTimeMillis(); + long ROOT = 0x11d; // para. 2.1 [KHAZAD] + int i, j; + int s, s2, s3, s4, s5, s6, s7, s8, sb; + char c; + for (i = 0; i < 256; i++) + { + c = Sd.charAt(i >>> 1); + s = ((i & 1) == 0 ? c >>> 8 : c) & 0xFF; + S[i] = (byte) s; + s2 = s << 1; + if (s2 > 0xFF) + s2 ^= ROOT; + s3 = s2 ^ s; + s4 = s2 << 1; + if (s4 > 0xFF) + s4 ^= ROOT; + s5 = s4 ^ s; + s6 = s4 ^ s2; + s7 = s6 ^ s; + s8 = s4 << 1; + if (s8 > 0xFF) + s8 ^= ROOT; + sb = s8 ^ s2 ^ s; + T0[i] = s << 24 | s3 << 16 | s4 << 8 | s5; + T1[i] = s3 << 24 | s << 16 | s5 << 8 | s4; + T2[i] = s4 << 24 | s5 << 16 | s << 8 | s3; + T3[i] = s5 << 24 | s4 << 16 | s3 << 8 | s; + T4[i] = s6 << 24 | s8 << 16 | sb << 8 | s7; + T5[i] = s8 << 24 | s6 << 16 | s7 << 8 | sb; + T6[i] = sb << 24 | s7 << 16 | s6 << 8 | s8; + T7[i] = s7 << 24 | sb << 16 | s8 << 8 | s6; + } + for (i = 0, j = 0; i < R + 1; i++) // compute round constant + { + rc[i][0] = S[j++] << 24 + | (S[j++] & 0xFF) << 16 + | (S[j++] & 0xFF) << 8 + | (S[j++] & 0xFF); + rc[i][1] = S[j++] << 24 + | (S[j++] & 0xFF) << 16 + | (S[j++] & 0xFF) << 8 + | (S[j++] & 0xFF); + } + time = System.currentTimeMillis() - time; + if (Configuration.DEBUG) + { + log.fine("Static data"); + log.fine("T0[]:"); + StringBuilder b; + for (i = 0; i < 64; i++) + { + b = new StringBuilder(); + for (j = 0; j < 4; j++) + b.append("0x").append(Util.toString(T0[i * 4 + j])).append(", "); + log.fine(b.toString()); + } + log.fine("T1[]:"); + for (i = 0; i < 64; i++) + { + b = new StringBuilder(); + for (j = 0; j < 4; j++) + b.append("0x").append(Util.toString(T1[i * 4 + j])).append(", "); + log.fine(b.toString()); + } + log.fine("T2[]:"); + for (i = 0; i < 64; i++) + { + b = new StringBuilder(); + for (j = 0; j < 4; j++) + b.append("0x").append(Util.toString(T2[i * 4 + j])).append(", "); + log.fine(b.toString()); + } + log.fine("T3[]:"); + for (i = 0; i < 64; i++) + { + b = new StringBuilder(); + for (j = 0; j < 4; j++) + b.append("0x").append(Util.toString(T3[i * 4 + j])).append(", "); + log.fine(b.toString()); + } + log.fine("T4[]:"); + for (i = 0; i < 64; i++) + { + b = new StringBuilder(); + for (j = 0; j < 4; j++) + b.append("0x").append(Util.toString(T4[i * 4 + j])).append(", "); + log.fine(b.toString()); + } + log.fine("T5[]:"); + for (i = 0; i < 64; i++) + { + b = new StringBuilder(); + for (j = 0; j < 4; j++) + b.append("0x").append(Util.toString(T5[i * 4 + j])).append(", "); + log.fine(b.toString()); + } + log.fine("T6[]:"); + for (i = 0; i < 64; i++) + { + b = new StringBuilder(); + for (j = 0; j < 4; j++) + b.append("0x").append(Util.toString(T6[i * 4 + j])).append(", "); + log.fine(b.toString()); + } + log.fine("T7[]:"); + for (i = 0; i < 64; i++) + { + b = new StringBuilder(); + for (j = 0; j < 4; j++) + b.append("0x").append(Util.toString(T7[i * 4 + j])).append(", "); + log.fine(b.toString()); + } + log.fine("rc[]:"); + for (i = 0; i < R + 1; i++) + log.fine("0x" + Util.toString(rc[i][0]) + Util.toString(rc[i][1])); + log.fine("Total initialization time: " + time + " ms."); + } + } + + /** Trivial 0-arguments constructor. */ + public Khazad() + { + super(Registry.KHAZAD_CIPHER, DEFAULT_BLOCK_SIZE, DEFAULT_KEY_SIZE); + } + + private static void khazad(byte[] in, int i, byte[] out, int j, int[][] K) + { + // sigma(K[0]) + int k0 = K[0][0]; + int k1 = K[0][1]; + int a0 = (in[i++] << 24 + | (in[i++] & 0xFF) << 16 + | (in[i++] & 0xFF) << 8 + | (in[i++] & 0xFF) ) ^ k0; + int a1 = (in[i++] << 24 + | (in[i++] & 0xFF) << 16 + | (in[i++] & 0xFF) << 8 + | (in[i ] & 0xFF) ) ^ k1; + int b0, b1; + // round function + for (int r = 1; r < R; r++) + { + k0 = K[r][0]; + k1 = K[r][1]; + b0 = T0[ a0 >>> 24 ] + ^ T1[(a0 >>> 16) & 0xFF] + ^ T2[(a0 >>> 8) & 0xFF] + ^ T3[ a0 & 0xFF] + ^ T4[ a1 >>> 24 ] + ^ T5[(a1 >>> 16) & 0xFF] + ^ T6[(a1 >>> 8) & 0xFF] + ^ T7[ a1 & 0xFF] ^ k0; + b1 = T0[ a1 >>> 24 ] + ^ T1[(a1 >>> 16) & 0xFF] + ^ T2[(a1 >>> 8) & 0xFF] + ^ T3[ a1 & 0xFF] + ^ T4[ a0 >>> 24 ] + ^ T5[(a0 >>> 16) & 0xFF] + ^ T6[(a0 >>> 8) & 0xFF] + ^ T7[ a0 & 0xFF] ^ k1; + a0 = b0; + a1 = b1; + if (Configuration.DEBUG) + log.fine("T" + r + "=" + Util.toString(a0) + Util.toString(a1)); + } + // sigma(K[R]) o gamma applied to previous output + k0 = K[R][0]; + k1 = K[R][1]; + out[j++] = (byte)(S[ a0 >>> 24 ] ^ (k0 >>> 24)); + out[j++] = (byte)(S[(a0 >>> 16) & 0xFF] ^ (k0 >>> 16)); + out[j++] = (byte)(S[(a0 >>> 8) & 0xFF] ^ (k0 >>> 8)); + out[j++] = (byte)(S[ a0 & 0xFF] ^ k0 ); + out[j++] = (byte)(S[ a1 >>> 24 ] ^ (k1 >>> 24)); + out[j++] = (byte)(S[(a1 >>> 16) & 0xFF] ^ (k1 >>> 16)); + out[j++] = (byte)(S[(a1 >>> 8) & 0xFF] ^ (k1 >>> 8)); + out[j ] = (byte)(S[ a1 & 0xFF] ^ k1 ); + if (Configuration.DEBUG) + log.fine("T=" + Util.toString(out, j - 7, 8) + "\n"); + } + + public Object clone() + { + Khazad result = new Khazad(); + result.currentBlockSize = this.currentBlockSize; + + return result; + } + + public Iterator blockSizes() + { + ArrayList al = new ArrayList(); + al.add(Integer.valueOf(DEFAULT_BLOCK_SIZE)); + + return Collections.unmodifiableList(al).iterator(); + } + + public Iterator keySizes() + { + ArrayList al = new ArrayList(); + al.add(Integer.valueOf(DEFAULT_KEY_SIZE)); + return Collections.unmodifiableList(al).iterator(); + } + + /** + * Expands a user-supplied key material into a session key for a designated + * <i>block size</i>. + * + * @param uk the 128-bit user-supplied key material. + * @param bs the desired block size in bytes. + * @return an Object encapsulating the session key. + * @exception IllegalArgumentException if the block size is not 16 (128-bit). + * @exception InvalidKeyException if the key data is invalid. + */ + public Object makeKey(byte[] uk, int bs) throws InvalidKeyException + { + if (bs != DEFAULT_BLOCK_SIZE) + throw new IllegalArgumentException(); + if (uk == null) + throw new InvalidKeyException("Empty key"); + if (uk.length != 16) + throw new InvalidKeyException("Key is not 128-bit."); + int[][] Ke = new int[R + 1][2]; // encryption round keys + int[][] Kd = new int[R + 1][2]; // decryption round keys + int r, i; + int k20, k21, k10, k11, rc0, rc1, kr0, kr1; + i = 0; + k20 = uk[i++] << 24 + | (uk[i++] & 0xFF) << 16 + | (uk[i++] & 0xFF) << 8 + | (uk[i++] & 0xFF); + k21 = uk[i++] << 24 + | (uk[i++] & 0xFF) << 16 + | (uk[i++] & 0xFF) << 8 + | (uk[i++] & 0xFF); + k10 = uk[i++] << 24 + | (uk[i++] & 0xFF) << 16 + | (uk[i++] & 0xFF) << 8 + | (uk[i++] & 0xFF); + k11 = uk[i++] << 24 + | (uk[i++] & 0xFF) << 16 + | (uk[i++] & 0xFF) << 8 + | (uk[i++] & 0xFF); + for (r = 0, i = 0; r <= R; r++) + { + rc0 = rc[r][0]; + rc1 = rc[r][1]; + kr0 = T0[ k10 >>> 24 ] + ^ T1[(k10 >>> 16) & 0xFF] + ^ T2[(k10 >>> 8) & 0xFF] + ^ T3[ k10 & 0xFF] + ^ T4[(k11 >>> 24) & 0xFF] + ^ T5[(k11 >>> 16) & 0xFF] + ^ T6[(k11 >>> 8) & 0xFF] + ^ T7[ k11 & 0xFF] ^ rc0 ^ k20; + kr1 = T0[ k11 >>> 24 ] + ^ T1[(k11 >>> 16) & 0xFF] + ^ T2[(k11 >>> 8) & 0xFF] + ^ T3[ k11 & 0xFF] + ^ T4[(k10 >>> 24) & 0xFF] + ^ T5[(k10 >>> 16) & 0xFF] + ^ T6[(k10 >>> 8) & 0xFF] + ^ T7[ k10 & 0xFF] ^ rc1 ^ k21; + Ke[r][0] = kr0; + Ke[r][1] = kr1; + k20 = k10; + k21 = k11; + k10 = kr0; + k11 = kr1; + if (r == 0 || r == R) + { + Kd[R - r][0] = kr0; + Kd[R - r][1] = kr1; + } + else + { + Kd[R - r][0] = T0[S[ kr0 >>> 24 ] & 0xFF] + ^ T1[S[(kr0 >>> 16) & 0xFF] & 0xFF] + ^ T2[S[(kr0 >>> 8) & 0xFF] & 0xFF] + ^ T3[S[ kr0 & 0xFF] & 0xFF] + ^ T4[S[ kr1 >>> 24 ] & 0xFF] + ^ T5[S[(kr1 >>> 16) & 0xFF] & 0xFF] + ^ T6[S[(kr1 >>> 8) & 0xFF] & 0xFF] + ^ T7[S[ kr1 & 0xFF] & 0xFF]; + Kd[R - r][1] = T0[S[ kr1 >>> 24 ] & 0xFF] + ^ T1[S[(kr1 >>> 16) & 0xFF] & 0xFF] + ^ T2[S[(kr1 >>> 8) & 0xFF] & 0xFF] + ^ T3[S[ kr1 & 0xFF] & 0xFF] + ^ T4[S[ kr0 >>> 24 ] & 0xFF] + ^ T5[S[(kr0 >>> 16) & 0xFF] & 0xFF] + ^ T6[S[(kr0 >>> 8) & 0xFF] & 0xFF] + ^ T7[S[ kr0 & 0xFF] & 0xFF]; + } + } + if (Configuration.DEBUG) + { + log.fine("Key schedule"); + log.fine("Ke[]:"); + for (r = 0; r < R + 1; r++) + log.fine("#" + r + ": 0x" + Util.toString(Ke[r][0]) + + Util.toString(Ke[r][1])); + log.fine("Kd[]:"); + for (r = 0; r < R + 1; r++) + log.fine("#" + r + ": 0x" + Util.toString(Kd[r][0]) + + Util.toString(Kd[r][1])); + } + return new Object[] { Ke, Kd }; + } + + public void encrypt(byte[] in, int i, byte[] out, int j, Object k, int bs) + { + if (bs != DEFAULT_BLOCK_SIZE) + throw new IllegalArgumentException(); + int[][] K = (int[][])((Object[]) k)[0]; + khazad(in, i, out, j, K); + } + + public void decrypt(byte[] in, int i, byte[] out, int j, Object k, int bs) + { + if (bs != DEFAULT_BLOCK_SIZE) + throw new IllegalArgumentException(); + int[][] K = (int[][])((Object[]) k)[1]; + khazad(in, i, out, j, K); + } + + public boolean selfTest() + { + if (valid == null) + { + boolean result = super.selfTest(); // do symmetry tests + if (result) + result = testKat(KAT_KEY, KAT_CT); + valid = Boolean.valueOf(result); + } + return valid.booleanValue(); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/cipher/NullCipher.java b/libjava/classpath/gnu/javax/crypto/cipher/NullCipher.java new file mode 100644 index 000000000..f23ea489f --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/cipher/NullCipher.java @@ -0,0 +1,108 @@ +/* NullCipher.java -- + Copyright (C) 2001, 2002, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.cipher; + +import gnu.java.security.Registry; + +import java.security.InvalidKeyException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Iterator; + +/** + * The implementation of a Null block cipher. + * <p> + * This cipher does not alter its input at all, claims to process block sizes + * 128-, 192- and 256-bit long, and key sizes from 64- to 512-bit in 8-bit + * increments. + */ +public final class NullCipher + extends BaseCipher +{ + /** Trivial 0-arguments constructor. */ + public NullCipher() + { + super(Registry.NULL_CIPHER, 16, 16); + } + + public Object clone() + { + NullCipher result = new NullCipher(); + result.currentBlockSize = this.currentBlockSize; + return result; + } + + public Iterator blockSizes() + { + ArrayList al = new ArrayList(); + al.add(Integer.valueOf(64 / 8)); + al.add(Integer.valueOf(128 / 8)); + al.add(Integer.valueOf(192 / 8)); + al.add(Integer.valueOf(256 / 8)); + return Collections.unmodifiableList(al).iterator(); + } + + public Iterator keySizes() + { + ArrayList al = new ArrayList(); + for (int n = 8; n < 64; n++) + al.add(Integer.valueOf(n)); + return Collections.unmodifiableList(al).iterator(); + } + + public Object makeKey(byte[] uk, int bs) throws InvalidKeyException + { + return new Object(); + } + + public void encrypt(byte[] in, int i, byte[] out, int j, Object k, int bs) + { + System.arraycopy(in, i, out, j, bs); + } + + public void decrypt(byte[] in, int i, byte[] out, int j, Object k, int bs) + { + System.arraycopy(in, i, out, j, bs); + } + + public boolean selfTest() + { + return true; + } +} diff --git a/libjava/classpath/gnu/javax/crypto/cipher/Rijndael.java b/libjava/classpath/gnu/javax/crypto/cipher/Rijndael.java new file mode 100644 index 000000000..0463fe51d --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/cipher/Rijndael.java @@ -0,0 +1,704 @@ +/* Rijndael.java -- + Copyright (C) 2001, 2002, 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.cipher; + +import gnu.java.security.Configuration; +import gnu.java.security.Registry; +import gnu.java.security.util.Util; + +import java.security.InvalidKeyException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Iterator; +import java.util.logging.Logger; + +/** + * Rijndael --pronounced Reindaal-- is the AES. It is a variable block-size + * (128-, 192- and 256-bit), variable key-size (128-, 192- and 256-bit) + * symmetric key block cipher. + * <p> + * References: + * <ol> + * <li><a href="http://www.esat.kuleuven.ac.be/~rijmen/rijndael/">The Rijndael + * Block Cipher - AES Proposal</a>.<br> + * <a href="mailto:vincent.rijmen@esat.kuleuven.ac.be">Vincent Rijmen</a> and + * <a href="mailto:daemen.j@protonworld.com">Joan Daemen</a>.</li> + * </ol> + */ +public final class Rijndael + extends BaseCipher +{ + private static final Logger log = Logger.getLogger(Rijndael.class.getName()); + private static final int DEFAULT_BLOCK_SIZE = 16; // in bytes + private static final int DEFAULT_KEY_SIZE = 16; // in bytes + private static final String SS = + "\u637C\u777B\uF26B\u6FC5\u3001\u672B\uFED7\uAB76" + + "\uCA82\uC97D\uFA59\u47F0\uADD4\uA2AF\u9CA4\u72C0" + + "\uB7FD\u9326\u363F\uF7CC\u34A5\uE5F1\u71D8\u3115" + + "\u04C7\u23C3\u1896\u059A\u0712\u80E2\uEB27\uB275" + + "\u0983\u2C1A\u1B6E\u5AA0\u523B\uD6B3\u29E3\u2F84" + + "\u53D1\u00ED\u20FC\uB15B\u6ACB\uBE39\u4A4C\u58CF" + + "\uD0EF\uAAFB\u434D\u3385\u45F9\u027F\u503C\u9FA8" + + "\u51A3\u408F\u929D\u38F5\uBCB6\uDA21\u10FF\uF3D2" + + "\uCD0C\u13EC\u5F97\u4417\uC4A7\u7E3D\u645D\u1973" + + "\u6081\u4FDC\u222A\u9088\u46EE\uB814\uDE5E\u0BDB" + + "\uE032\u3A0A\u4906\u245C\uC2D3\uAC62\u9195\uE479" + + "\uE7C8\u376D\u8DD5\u4EA9\u6C56\uF4EA\u657A\uAE08" + + "\uBA78\u252E\u1CA6\uB4C6\uE8DD\u741F\u4BBD\u8B8A" + + "\u703E\uB566\u4803\uF60E\u6135\u57B9\u86C1\u1D9E" + + "\uE1F8\u9811\u69D9\u8E94\u9B1E\u87E9\uCE55\u28DF" + + "\u8CA1\u890D\uBFE6\u4268\u4199\u2D0F\uB054\uBB16"; + private static final byte[] S = new byte[256]; + private static final byte[] Si = new byte[256]; + private static final int[] T1 = new int[256]; + private static final int[] T2 = new int[256]; + private static final int[] T3 = new int[256]; + private static final int[] T4 = new int[256]; + private static final int[] T5 = new int[256]; + private static final int[] T6 = new int[256]; + private static final int[] T7 = new int[256]; + private static final int[] T8 = new int[256]; + private static final int[] U1 = new int[256]; + private static final int[] U2 = new int[256]; + private static final int[] U3 = new int[256]; + private static final int[] U4 = new int[256]; + private static final byte[] rcon = new byte[30]; + private static final int[][][] shifts = new int[][][] { + { { 0, 0 }, { 1, 3 }, { 2, 2 }, { 3, 1 } }, + { { 0, 0 }, { 1, 5 }, { 2, 4 }, { 3, 3 } }, + { { 0, 0 }, { 1, 7 }, { 3, 5 }, { 4, 4 } } }; + /** + * KAT vector (from ecb_vk): I=96 + * KEY=0000000000000000000000010000000000000000000000000000000000000000 + * CT=E44429474D6FC3084EB2A6B8B46AF754 + */ + private static final byte[] KAT_KEY = Util.toBytesFromString( + "0000000000000000000000010000000000000000000000000000000000000000"); + private static final byte[] KAT_CT = Util.toBytesFromString( + "E44429474D6FC3084EB2A6B8B46AF754"); + /** caches the result of the correctness test, once executed. */ + private static Boolean valid; + + static + { + long time = System.currentTimeMillis(); + int ROOT = 0x11B; + int i, j = 0; + // S-box, inverse S-box, T-boxes, U-boxes + int s, s2, s3, i2, i4, i8, i9, ib, id, ie, t; + char c; + for (i = 0; i < 256; i++) + { + c = SS.charAt(i >>> 1); + S[i] = (byte)(((i & 1) == 0) ? c >>> 8 : c & 0xFF); + s = S[i] & 0xFF; + Si[s] = (byte) i; + s2 = s << 1; + if (s2 >= 0x100) + s2 ^= ROOT; + s3 = s2 ^ s; + i2 = i << 1; + if (i2 >= 0x100) + i2 ^= ROOT; + i4 = i2 << 1; + if (i4 >= 0x100) + i4 ^= ROOT; + i8 = i4 << 1; + if (i8 >= 0x100) + i8 ^= ROOT; + i9 = i8 ^ i; + ib = i9 ^ i2; + id = i9 ^ i4; + ie = i8 ^ i4 ^ i2; + T1[i] = t = (s2 << 24) | (s << 16) | (s << 8) | s3; + T2[i] = (t >>> 8) | (t << 24); + T3[i] = (t >>> 16) | (t << 16); + T4[i] = (t >>> 24) | (t << 8); + T5[s] = U1[i] = t = (ie << 24) | (i9 << 16) | (id << 8) | ib; + T6[s] = U2[i] = (t >>> 8) | (t << 24); + T7[s] = U3[i] = (t >>> 16) | (t << 16); + T8[s] = U4[i] = (t >>> 24) | (t << 8); + } + // round constants + int r = 1; + rcon[0] = 1; + for (i = 1; i < 30; i++) + { + r <<= 1; + if (r >= 0x100) + r ^= ROOT; + rcon[i] = (byte) r; + } + time = System.currentTimeMillis() - time; + if (Configuration.DEBUG) + { + log.fine("Static Data"); + log.fine("S[]:"); + StringBuilder sb; + for (i = 0; i < 16; i++) + { + sb = new StringBuilder(); + for (j = 0; j < 16; j++) + sb.append("0x").append(Util.toString(S[i * 16 + j])).append(", "); + log.fine(sb.toString()); + } + log.fine("Si[]:"); + for (i = 0; i < 16; i++) + { + sb = new StringBuilder(); + for (j = 0; j < 16; j++) + sb.append("0x").append(Util.toString(Si[i * 16 + j])).append(", "); + log.fine(sb.toString()); + } + + log.fine("T1[]:"); + for (i = 0; i < 64; i++) + { + sb = new StringBuilder(); + for (j = 0; j < 4; j++) + sb.append("0x").append(Util.toString(T1[i * 4 + j])).append(", "); + log.fine(sb.toString()); + } + log.fine("T2[]:"); + for (i = 0; i < 64; i++) + { + sb = new StringBuilder(); + for (j = 0; j < 4; j++) + sb.append("0x").append(Util.toString(T2[i * 4 + j])).append(", "); + log.fine(sb.toString()); + } + log.fine("T3[]:"); + for (i = 0; i < 64; i++) + { + sb = new StringBuilder(); + for (j = 0; j < 4; j++) + sb.append("0x").append(Util.toString(T3[i * 4 + j])).append(", "); + log.fine(sb.toString()); + } + log.fine("T4[]:"); + for (i = 0; i < 64; i++) + { + sb = new StringBuilder(); + for (j = 0; j < 4; j++) + sb.append("0x").append(Util.toString(T4[i * 4 + j])).append(", "); + log.fine(sb.toString()); + } + log.fine("T5[]:"); + for (i = 0; i < 64; i++) + { + sb = new StringBuilder(); + for (j = 0; j < 4; j++) + sb.append("0x").append(Util.toString(T5[i * 4 + j])).append(", "); + log.fine(sb.toString()); + } + log.fine("T6[]:"); + for (i = 0; i < 64; i++) + { + sb = new StringBuilder(); + for (j = 0; j < 4; j++) + sb.append("0x").append(Util.toString(T6[i * 4 + j])).append(", "); + log.fine(sb.toString()); + } + log.fine("T7[]:"); + for (i = 0; i < 64; i++) + { + sb = new StringBuilder(); + for (j = 0; j < 4; j++) + sb.append("0x").append(Util.toString(T7[i * 4 + j])).append(", "); + log.fine(sb.toString()); + } + log.fine("T8[]:"); + for (i = 0; i < 64; i++) + { + sb = new StringBuilder(); + for (j = 0; j < 4; j++) + sb.append("0x").append(Util.toString(T8[i * 4 + j])).append(", "); + log.fine(sb.toString()); + } + + log.fine("U1[]:"); + for (i = 0; i < 64; i++) + { + sb = new StringBuilder(); + for (j = 0; j < 4; j++) + sb.append("0x").append(Util.toString(U1[i * 4 + j])).append(", "); + log.fine(sb.toString()); + } + log.fine("U2[]:"); + for (i = 0; i < 64; i++) + { + sb = new StringBuilder(); + for (j = 0; j < 4; j++) + sb.append("0x").append(Util.toString(U2[i * 4 + j])).append(", "); + log.fine(sb.toString()); + } + log.fine("U3[]:"); + for (i = 0; i < 64; i++) + { + sb = new StringBuilder(); + for (j = 0; j < 4; j++) + sb.append("0x").append(Util.toString(U3[i * 4 + j])).append(", "); + log.fine(sb.toString()); + } + log.fine("U4[]:"); + for (i = 0; i < 64; i++) + { + sb = new StringBuilder(); + for (j = 0; j < 4; j++) + sb.append("0x").append(Util.toString(U4[i * 4 + j])).append(", "); + log.fine(sb.toString()); + } + + log.fine("rcon[]:"); + for (i = 0; i < 5; i++) + { + sb = new StringBuilder(); + for (j = 0; j < 6; j++) + sb.append("0x").append(Util.toString(rcon[i * 6 + j])).append(", "); + log.fine(sb.toString()); + } + log.fine("Total initialization time: " + time + " ms."); + } + } + + /** Trivial 0-arguments constructor. */ + public Rijndael() + { + super(Registry.RIJNDAEL_CIPHER, DEFAULT_BLOCK_SIZE, DEFAULT_KEY_SIZE); + } + + /** + * Returns the number of rounds for a given Rijndael's key and block sizes. + * + * @param ks the size of the user key material in bytes. + * @param bs the desired block size in bytes. + * @return the number of rounds for a given Rijndael's key and block sizes. + */ + public static int getRounds(int ks, int bs) + { + switch (ks) + { + case 16: + return bs == 16 ? 10 : (bs == 24 ? 12 : 14); + case 24: + return bs != 32 ? 12 : 14; + default: // 32 bytes = 256 bits + return 14; + } + } + + private static void rijndaelEncrypt(byte[] in, int inOffset, byte[] out, + int outOffset, Object sessionKey, int bs) + { + Object[] sKey = (Object[]) sessionKey; // extract encryption round keys + int[][] Ke = (int[][]) sKey[0]; + int BC = bs / 4; + int ROUNDS = Ke.length - 1; + int SC = BC == 4 ? 0 : (BC == 6 ? 1 : 2); + int s1 = shifts[SC][1][0]; + int s2 = shifts[SC][2][0]; + int s3 = shifts[SC][3][0]; + int[] a = new int[BC]; + int[] t = new int[BC]; // temporary work array + int i, tt; + for (i = 0; i < BC; i++) // plaintext to ints + key + t[i] = (in[inOffset++] << 24 + | (in[inOffset++] & 0xFF) << 16 + | (in[inOffset++] & 0xFF) << 8 + | (in[inOffset++] & 0xFF) ) ^ Ke[0][i]; + for (int r = 1; r < ROUNDS; r++) // apply round transforms + { + for (i = 0; i < BC; i++) + a[i] = (T1[(t[ i ] >>> 24) ] + ^ T2[(t[(i + s1) % BC] >>> 16) & 0xFF] + ^ T3[(t[(i + s2) % BC] >>> 8) & 0xFF] + ^ T4[ t[(i + s3) % BC] & 0xFF]) ^ Ke[r][i]; + System.arraycopy(a, 0, t, 0, BC); + if (Configuration.DEBUG) + log.fine("CT" + r + "=" + Util.toString(t)); + } + for (i = 0; i < BC; i++) // last round is special + { + tt = Ke[ROUNDS][i]; + out[outOffset++] = (byte)(S[(t[ i ] >>> 24) ] ^ (tt >>> 24)); + out[outOffset++] = (byte)(S[(t[(i + s1) % BC] >>> 16) & 0xFF] ^ (tt >>> 16)); + out[outOffset++] = (byte)(S[(t[(i + s2) % BC] >>> 8) & 0xFF] ^ (tt >>> 8)); + out[outOffset++] = (byte)(S[ t[(i + s3) % BC] & 0xFF] ^ tt ); + } + if (Configuration.DEBUG) + log.fine("CT=" + Util.toString(out, outOffset - bs, bs)); + } + + private static void rijndaelDecrypt(byte[] in, int inOffset, byte[] out, + int outOffset, Object sessionKey, int bs) + { + Object[] sKey = (Object[]) sessionKey; // extract decryption round keys + int[][] Kd = (int[][]) sKey[1]; + int BC = bs / 4; + int ROUNDS = Kd.length - 1; + int SC = BC == 4 ? 0 : (BC == 6 ? 1 : 2); + int s1 = shifts[SC][1][1]; + int s2 = shifts[SC][2][1]; + int s3 = shifts[SC][3][1]; + int[] a = new int[BC]; + int[] t = new int[BC]; // temporary work array + int i, tt; + for (i = 0; i < BC; i++) // ciphertext to ints + key + t[i] = (in[inOffset++] << 24 + | (in[inOffset++] & 0xFF) << 16 + | (in[inOffset++] & 0xFF) << 8 + | (in[inOffset++] & 0xFF) ) ^ Kd[0][i]; + for (int r = 1; r < ROUNDS; r++) // apply round transforms + { + for (i = 0; i < BC; i++) + a[i] = (T5[(t[ i ] >>> 24) ] + ^ T6[(t[(i + s1) % BC] >>> 16) & 0xFF] + ^ T7[(t[(i + s2) % BC] >>> 8) & 0xFF] + ^ T8[ t[(i + s3) % BC] & 0xFF]) ^ Kd[r][i]; + System.arraycopy(a, 0, t, 0, BC); + if (Configuration.DEBUG) + log.fine("PT" + r + "=" + Util.toString(t)); + } + for (i = 0; i < BC; i++) // last round is special + { + tt = Kd[ROUNDS][i]; + out[outOffset++] = (byte)(Si[(t[ i ] >>> 24) ] ^ (tt >>> 24)); + out[outOffset++] = (byte)(Si[(t[(i + s1) % BC] >>> 16) & 0xFF] ^ (tt >>> 16)); + out[outOffset++] = (byte)(Si[(t[(i + s2) % BC] >>> 8) & 0xFF] ^ (tt >>> 8)); + out[outOffset++] = (byte)(Si[ t[(i + s3) % BC] & 0xFF] ^ tt ); + } + if (Configuration.DEBUG) + log.fine("PT=" + Util.toString(out, outOffset - bs, bs)); + } + + private static void aesEncrypt(byte[] in, int i, byte[] out, int j, Object key) + { + int[][] Ke = (int[][])((Object[]) key)[0]; // extract encryption round keys + int ROUNDS = Ke.length - 1; + int[] Ker = Ke[0]; + // plaintext to ints + key + int t0 = (in[i++] << 24 + | (in[i++] & 0xFF) << 16 + | (in[i++] & 0xFF) << 8 + | (in[i++] & 0xFF) ) ^ Ker[0]; + int t1 = (in[i++] << 24 + | (in[i++] & 0xFF) << 16 + | (in[i++] & 0xFF) << 8 + | (in[i++] & 0xFF) ) ^ Ker[1]; + int t2 = (in[i++] << 24 + | (in[i++] & 0xFF) << 16 + | (in[i++] & 0xFF) << 8 + | (in[i++] & 0xFF) ) ^ Ker[2]; + int t3 = (in[i++] << 24 + | (in[i++] & 0xFF) << 16 + | (in[i++] & 0xFF) << 8 + | (in[i++] & 0xFF) ) ^ Ker[3]; + int a0, a1, a2, a3; + for (int r = 1; r < ROUNDS; r++) // apply round transforms + { + Ker = Ke[r]; + a0 = (T1[(t0 >>> 24) ] + ^ T2[(t1 >>> 16) & 0xFF] + ^ T3[(t2 >>> 8) & 0xFF] + ^ T4[ t3 & 0xFF]) ^ Ker[0]; + a1 = (T1[(t1 >>> 24) ] + ^ T2[(t2 >>> 16) & 0xFF] + ^ T3[(t3 >>> 8) & 0xFF] + ^ T4[ t0 & 0xFF]) ^ Ker[1]; + a2 = (T1[(t2 >>> 24) ] + ^ T2[(t3 >>> 16) & 0xFF] + ^ T3[(t0 >>> 8) & 0xFF] + ^ T4[ t1 & 0xFF]) ^ Ker[2]; + a3 = (T1[(t3 >>> 24) ] + ^ T2[(t0 >>> 16) & 0xFF] + ^ T3[(t1 >>> 8) & 0xFF] + ^ T4[ t2 & 0xFF]) ^ Ker[3]; + t0 = a0; + t1 = a1; + t2 = a2; + t3 = a3; + if (Configuration.DEBUG) + log.fine("CT" + r + "=" + Util.toString(t0) + Util.toString(t1) + + Util.toString(t2) + Util.toString(t3)); + } + // last round is special + Ker = Ke[ROUNDS]; + int tt = Ker[0]; + out[j++] = (byte)(S[(t0 >>> 24) ] ^ (tt >>> 24)); + out[j++] = (byte)(S[(t1 >>> 16) & 0xFF] ^ (tt >>> 16)); + out[j++] = (byte)(S[(t2 >>> 8) & 0xFF] ^ (tt >>> 8)); + out[j++] = (byte)(S[ t3 & 0xFF] ^ tt ); + tt = Ker[1]; + out[j++] = (byte)(S[(t1 >>> 24) ] ^ (tt >>> 24)); + out[j++] = (byte)(S[(t2 >>> 16) & 0xFF] ^ (tt >>> 16)); + out[j++] = (byte)(S[(t3 >>> 8) & 0xFF] ^ (tt >>> 8)); + out[j++] = (byte)(S[ t0 & 0xFF] ^ tt ); + tt = Ker[2]; + out[j++] = (byte)(S[(t2 >>> 24) ] ^ (tt >>> 24)); + out[j++] = (byte)(S[(t3 >>> 16) & 0xFF] ^ (tt >>> 16)); + out[j++] = (byte)(S[(t0 >>> 8) & 0xFF] ^ (tt >>> 8)); + out[j++] = (byte)(S[ t1 & 0xFF] ^ tt ); + tt = Ker[3]; + out[j++] = (byte)(S[(t3 >>> 24) ] ^ (tt >>> 24)); + out[j++] = (byte)(S[(t0 >>> 16) & 0xFF] ^ (tt >>> 16)); + out[j++] = (byte)(S[(t1 >>> 8) & 0xFF] ^ (tt >>> 8)); + out[j++] = (byte)(S[ t2 & 0xFF] ^ tt ); + if (Configuration.DEBUG) + log.fine("CT=" + Util.toString(out, j - 16, 16)); + } + + private static void aesDecrypt(byte[] in, int i, byte[] out, int j, Object key) + { + int[][] Kd = (int[][])((Object[]) key)[1]; // extract decryption round keys + int ROUNDS = Kd.length - 1; + int[] Kdr = Kd[0]; + // ciphertext to ints + key + int t0 = (in[i++] << 24 + | (in[i++] & 0xFF) << 16 + | (in[i++] & 0xFF) << 8 + | (in[i++] & 0xFF) ) ^ Kdr[0]; + int t1 = (in[i++] << 24 + | (in[i++] & 0xFF) << 16 + | (in[i++] & 0xFF) << 8 + | (in[i++] & 0xFF) ) ^ Kdr[1]; + int t2 = (in[i++] << 24 + | (in[i++] & 0xFF) << 16 + | (in[i++] & 0xFF) << 8 + | (in[i++] & 0xFF) ) ^ Kdr[2]; + int t3 = (in[i++] << 24 + | (in[i++] & 0xFF) << 16 + | (in[i++] & 0xFF) << 8 + | (in[i++] & 0xFF) ) ^ Kdr[3]; + + int a0, a1, a2, a3; + for (int r = 1; r < ROUNDS; r++) // apply round transforms + { + Kdr = Kd[r]; + a0 = (T5[(t0 >>> 24) ] + ^ T6[(t3 >>> 16) & 0xFF] + ^ T7[(t2 >>> 8) & 0xFF] + ^ T8[ t1 & 0xFF]) ^ Kdr[0]; + a1 = (T5[(t1 >>> 24) ] + ^ T6[(t0 >>> 16) & 0xFF] + ^ T7[(t3 >>> 8) & 0xFF] + ^ T8[ t2 & 0xFF]) ^ Kdr[1]; + a2 = (T5[(t2 >>> 24) ] + ^ T6[(t1 >>> 16) & 0xFF] + ^ T7[(t0 >>> 8) & 0xFF] + ^ T8[ t3 & 0xFF]) ^ Kdr[2]; + a3 = (T5[(t3 >>> 24) ] + ^ T6[(t2 >>> 16) & 0xFF] + ^ T7[(t1 >>> 8) & 0xFF] + ^ T8[ t0 & 0xFF]) ^ Kdr[3]; + t0 = a0; + t1 = a1; + t2 = a2; + t3 = a3; + if (Configuration.DEBUG) + log.fine("PT" + r + "=" + Util.toString(t0) + Util.toString(t1) + + Util.toString(t2) + Util.toString(t3)); + } + // last round is special + Kdr = Kd[ROUNDS]; + int tt = Kdr[0]; + out[j++] = (byte)(Si[(t0 >>> 24) ] ^ (tt >>> 24)); + out[j++] = (byte)(Si[(t3 >>> 16) & 0xFF] ^ (tt >>> 16)); + out[j++] = (byte)(Si[(t2 >>> 8) & 0xFF] ^ (tt >>> 8)); + out[j++] = (byte)(Si[ t1 & 0xFF] ^ tt ); + tt = Kdr[1]; + out[j++] = (byte)(Si[(t1 >>> 24) ] ^ (tt >>> 24)); + out[j++] = (byte)(Si[(t0 >>> 16) & 0xFF] ^ (tt >>> 16)); + out[j++] = (byte)(Si[(t3 >>> 8) & 0xFF] ^ (tt >>> 8)); + out[j++] = (byte)(Si[ t2 & 0xFF] ^ tt ); + tt = Kdr[2]; + out[j++] = (byte)(Si[(t2 >>> 24) ] ^ (tt >>> 24)); + out[j++] = (byte)(Si[(t1 >>> 16) & 0xFF] ^ (tt >>> 16)); + out[j++] = (byte)(Si[(t0 >>> 8) & 0xFF] ^ (tt >>> 8)); + out[j++] = (byte)(Si[ t3 & 0xFF] ^ tt ); + tt = Kdr[3]; + out[j++] = (byte)(Si[(t3 >>> 24) ] ^ (tt >>> 24)); + out[j++] = (byte)(Si[(t2 >>> 16) & 0xFF] ^ (tt >>> 16)); + out[j++] = (byte)(Si[(t1 >>> 8) & 0xFF] ^ (tt >>> 8)); + out[j++] = (byte)(Si[ t0 & 0xFF] ^ tt ); + if (Configuration.DEBUG) + log.fine("PT=" + Util.toString(out, j - 16, 16)); + } + + public Object clone() + { + Rijndael result = new Rijndael(); + result.currentBlockSize = this.currentBlockSize; + + return result; + } + + public Iterator blockSizes() + { + ArrayList al = new ArrayList(); + al.add(Integer.valueOf(128 / 8)); + al.add(Integer.valueOf(192 / 8)); + al.add(Integer.valueOf(256 / 8)); + + return Collections.unmodifiableList(al).iterator(); + } + + public Iterator keySizes() + { + ArrayList al = new ArrayList(); + al.add(Integer.valueOf(128 / 8)); + al.add(Integer.valueOf(192 / 8)); + al.add(Integer.valueOf(256 / 8)); + + return Collections.unmodifiableList(al).iterator(); + } + + /** + * Expands a user-supplied key material into a session key for a designated + * <i>block size</i>. + * + * @param k the 128/192/256-bit user-key to use. + * @param bs the block size in bytes of this Rijndael. + * @return an Object encapsulating the session key. + * @exception IllegalArgumentException if the block size is not 16, 24 or 32. + * @exception InvalidKeyException if the key data is invalid. + */ + public Object makeKey(byte[] k, int bs) throws InvalidKeyException + { + if (k == null) + throw new InvalidKeyException("Empty key"); + if (! (k.length == 16 || k.length == 24 || k.length == 32)) + throw new InvalidKeyException("Incorrect key length"); + if (! (bs == 16 || bs == 24 || bs == 32)) + throw new IllegalArgumentException(); + int ROUNDS = getRounds(k.length, bs); + int BC = bs / 4; + int[][] Ke = new int[ROUNDS + 1][BC]; // encryption round keys + int[][] Kd = new int[ROUNDS + 1][BC]; // decryption round keys + int ROUND_KEY_COUNT = (ROUNDS + 1) * BC; + int KC = k.length / 4; + int[] tk = new int[KC]; + int i, j; + // copy user material bytes into temporary ints + for (i = 0, j = 0; i < KC;) + tk[i++] = k[j++] << 24 + | (k[j++] & 0xFF) << 16 + | (k[j++] & 0xFF) << 8 + | (k[j++] & 0xFF); + // copy values into round key arrays + int t = 0; + for (j = 0; (j < KC) && (t < ROUND_KEY_COUNT); j++, t++) + { + Ke[t / BC][t % BC] = tk[j]; + Kd[ROUNDS - (t / BC)][t % BC] = tk[j]; + } + int tt, rconpointer = 0; + while (t < ROUND_KEY_COUNT) + { + // extrapolate using phi (the round key evolution function) + tt = tk[KC - 1]; + tk[0] ^= (S[(tt >>> 16) & 0xFF] & 0xFF) << 24 + ^ (S[(tt >>> 8) & 0xFF] & 0xFF) << 16 + ^ (S[ tt & 0xFF] & 0xFF) << 8 + ^ (S[(tt >>> 24) ] & 0xFF) ^ rcon[rconpointer++] << 24; + if (KC != 8) + for (i = 1, j = 0; i < KC;) + tk[i++] ^= tk[j++]; + else + { + for (i = 1, j = 0; i < KC / 2;) + tk[i++] ^= tk[j++]; + tt = tk[KC / 2 - 1]; + tk[KC / 2] ^= (S[ tt & 0xFF] & 0xFF) + ^ (S[(tt >>> 8) & 0xFF] & 0xFF) << 8 + ^ (S[(tt >>> 16) & 0xFF] & 0xFF) << 16 + ^ S[(tt >>> 24) & 0xFF] << 24; + for (j = KC / 2, i = j + 1; i < KC;) + tk[i++] ^= tk[j++]; + } + // copy values into round key arrays + for (j = 0; (j < KC) && (t < ROUND_KEY_COUNT); j++, t++) + { + Ke[t / BC][t % BC] = tk[j]; + Kd[ROUNDS - (t / BC)][t % BC] = tk[j]; + } + } + for (int r = 1; r < ROUNDS; r++) // inverse MixColumn where needed + for (j = 0; j < BC; j++) + { + tt = Kd[r][j]; + Kd[r][j] = U1[(tt >>> 24) ] + ^ U2[(tt >>> 16) & 0xFF] + ^ U3[(tt >>> 8) & 0xFF] + ^ U4[ tt & 0xFF]; + } + return new Object[] { Ke, Kd }; + } + + public void encrypt(byte[] in, int i, byte[] out, int j, Object k, int bs) + { + if (! (bs == 16 || bs == 24 || bs == 32)) + throw new IllegalArgumentException(); + if (bs == DEFAULT_BLOCK_SIZE) + aesEncrypt(in, i, out, j, k); + else + rijndaelEncrypt(in, i, out, j, k, bs); + } + + public void decrypt(byte[] in, int i, byte[] out, int j, Object k, int bs) + { + if (! (bs == 16 || bs == 24 || bs == 32)) + throw new IllegalArgumentException(); + if (bs == DEFAULT_BLOCK_SIZE) + aesDecrypt(in, i, out, j, k); + else + rijndaelDecrypt(in, i, out, j, k, bs); + } + + public boolean selfTest() + { + if (valid == null) + { + boolean result = super.selfTest(); // do symmetry tests + if (result) + result = testKat(KAT_KEY, KAT_CT); + valid = Boolean.valueOf(result); + } + return valid.booleanValue(); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/cipher/Serpent.java b/libjava/classpath/gnu/javax/crypto/cipher/Serpent.java new file mode 100644 index 000000000..1175fcfd2 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/cipher/Serpent.java @@ -0,0 +1,1781 @@ +/* Serpent.java -- + Copyright (C) 2001, 2002, 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.cipher; + +import gnu.java.security.Registry; +import gnu.java.security.util.Util; + +import java.security.InvalidKeyException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Iterator; + +/** + * Serpent is a 32-round substitution-permutation network block cipher, + * operating on 128-bit blocks and accepting keys of 128, 192, and 256 bits in + * length. At each round the plaintext is XORed with a 128 bit portion of the + * session key -- a 4224 bit key computed from the input key -- then one of + * eight S-boxes are applied, and finally a simple linear transformation is + * done. Decryption does the exact same thing in reverse order, and using the + * eight inverses of the S-boxes. + * <p> + * Serpent was designed by Ross Anderson, Eli Biham, and Lars Knudsen as a + * proposed cipher for the Advanced Encryption Standard. + * <p> + * Serpent can be sped up greatly by replacing S-box substitution with a + * sequence of binary operations, and the optimal implementation depends upon + * finding the fastest sequence of binary operations that reproduce this + * substitution. This implementation uses the S-boxes discovered by <a + * href="http://www.ii.uib.no/~osvik/">Dag Arne Osvik</a>, which are optimized + * for the Pentium family of processors. + * <p> + * References: + * <ol> + * <li><a href="http://www.cl.cam.ac.uk/~rja14/serpent.html">Serpent: A + * Candidate Block Cipher for the Advanced Encryption Standard.</a></li> + * </ol> + */ +public class Serpent + extends BaseCipher +{ + private static final int DEFAULT_KEY_SIZE = 16; + private static final int DEFAULT_BLOCK_SIZE = 16; + private static final int ROUNDS = 32; + /** The fractional part of the golden ratio, (sqrt(5)+1)/2. */ + private static final int PHI = 0x9e3779b9; + /** + * KAT vector (from ecb_vk): I=9 + * KEY=008000000000000000000000000000000000000000000000 + * CT=5587B5BCB9EE5A28BA2BACC418005240 + */ + private static final byte[] KAT_KEY = Util.toReversedBytesFromString( + "008000000000000000000000000000000000000000000000"); + private static final byte[] KAT_CT = + Util.toReversedBytesFromString("5587B5BCB9EE5A28BA2BACC418005240"); + /** caches the result of the correctness test, once executed. */ + private static Boolean valid; + private int x0, x1, x2, x3, x4; + + /** Trivial zero-argument constructor. */ + public Serpent() + { + super(Registry.SERPENT_CIPHER, DEFAULT_BLOCK_SIZE, DEFAULT_KEY_SIZE); + } + + public Object clone() + { + Serpent result = new Serpent(); + result.currentBlockSize = this.currentBlockSize; + return result; + } + + public Iterator blockSizes() + { + return Collections.singleton(Integer.valueOf(DEFAULT_BLOCK_SIZE)).iterator(); + } + + public Iterator keySizes() + { + ArrayList keySizes = new ArrayList(); + keySizes.add(Integer.valueOf(16)); + keySizes.add(Integer.valueOf(24)); + keySizes.add(Integer.valueOf(32)); + return Collections.unmodifiableList(keySizes).iterator(); + } + + public Object makeKey(byte[] kb, int blockSize) throws InvalidKeyException + { + // Not strictly true, but here to conform with the AES proposal. + // This restriction can be removed if deemed necessary. + if (kb.length != 16 && kb.length != 24 && kb.length != 32) + throw new InvalidKeyException("Key length is not 16, 24, or 32 bytes"); + Key key = new Key(); + // Here w is our "pre-key". + int[] w = new int[4 * (ROUNDS + 1)]; + int i, j; + for (i = 0, j = 0; i < 8 && j < kb.length; i++) + w[i] = (kb[j++] & 0xff) + | (kb[j++] & 0xff) << 8 + | (kb[j++] & 0xff) << 16 + | (kb[j++] & 0xff) << 24; + // Pad key if < 256 bits. + if (i != 8) + w[i] = 1; + // Transform using w_i-8 ... w_i-1 + for (i = 8, j = 0; i < 16; i++) + { + int t = w[j] ^ w[i - 5] ^ w[i - 3] ^ w[i - 1] ^ PHI ^ j++; + w[i] = t << 11 | t >>> 21; + } + // Translate by 8. + for (i = 0; i < 8; i++) + w[i] = w[i + 8]; + // Transform the rest of the key. + for (; i < w.length; i++) + { + int t = w[i - 8] ^ w[i - 5] ^ w[i - 3] ^ w[i - 1] ^ PHI ^ i; + w[i] = t << 11 | t >>> 21; + } + // After these s-boxes the pre-key (w, above) will become the + // session key (key, below). + sbox3(w[0], w[1], w[2], w[3]); + key.k0 = x0; + key.k1 = x1; + key.k2 = x2; + key.k3 = x3; + sbox2(w[4], w[5], w[6], w[7]); + key.k4 = x0; + key.k5 = x1; + key.k6 = x2; + key.k7 = x3; + sbox1(w[8], w[9], w[10], w[11]); + key.k8 = x0; + key.k9 = x1; + key.k10 = x2; + key.k11 = x3; + sbox0(w[12], w[13], w[14], w[15]); + key.k12 = x0; + key.k13 = x1; + key.k14 = x2; + key.k15 = x3; + sbox7(w[16], w[17], w[18], w[19]); + key.k16 = x0; + key.k17 = x1; + key.k18 = x2; + key.k19 = x3; + sbox6(w[20], w[21], w[22], w[23]); + key.k20 = x0; + key.k21 = x1; + key.k22 = x2; + key.k23 = x3; + sbox5(w[24], w[25], w[26], w[27]); + key.k24 = x0; + key.k25 = x1; + key.k26 = x2; + key.k27 = x3; + sbox4(w[28], w[29], w[30], w[31]); + key.k28 = x0; + key.k29 = x1; + key.k30 = x2; + key.k31 = x3; + sbox3(w[32], w[33], w[34], w[35]); + key.k32 = x0; + key.k33 = x1; + key.k34 = x2; + key.k35 = x3; + sbox2(w[36], w[37], w[38], w[39]); + key.k36 = x0; + key.k37 = x1; + key.k38 = x2; + key.k39 = x3; + sbox1(w[40], w[41], w[42], w[43]); + key.k40 = x0; + key.k41 = x1; + key.k42 = x2; + key.k43 = x3; + sbox0(w[44], w[45], w[46], w[47]); + key.k44 = x0; + key.k45 = x1; + key.k46 = x2; + key.k47 = x3; + sbox7(w[48], w[49], w[50], w[51]); + key.k48 = x0; + key.k49 = x1; + key.k50 = x2; + key.k51 = x3; + sbox6(w[52], w[53], w[54], w[55]); + key.k52 = x0; + key.k53 = x1; + key.k54 = x2; + key.k55 = x3; + sbox5(w[56], w[57], w[58], w[59]); + key.k56 = x0; + key.k57 = x1; + key.k58 = x2; + key.k59 = x3; + sbox4(w[60], w[61], w[62], w[63]); + key.k60 = x0; + key.k61 = x1; + key.k62 = x2; + key.k63 = x3; + sbox3(w[64], w[65], w[66], w[67]); + key.k64 = x0; + key.k65 = x1; + key.k66 = x2; + key.k67 = x3; + sbox2(w[68], w[69], w[70], w[71]); + key.k68 = x0; + key.k69 = x1; + key.k70 = x2; + key.k71 = x3; + sbox1(w[72], w[73], w[74], w[75]); + key.k72 = x0; + key.k73 = x1; + key.k74 = x2; + key.k75 = x3; + sbox0(w[76], w[77], w[78], w[79]); + key.k76 = x0; + key.k77 = x1; + key.k78 = x2; + key.k79 = x3; + sbox7(w[80], w[81], w[82], w[83]); + key.k80 = x0; + key.k81 = x1; + key.k82 = x2; + key.k83 = x3; + sbox6(w[84], w[85], w[86], w[87]); + key.k84 = x0; + key.k85 = x1; + key.k86 = x2; + key.k87 = x3; + sbox5(w[88], w[89], w[90], w[91]); + key.k88 = x0; + key.k89 = x1; + key.k90 = x2; + key.k91 = x3; + sbox4(w[92], w[93], w[94], w[95]); + key.k92 = x0; + key.k93 = x1; + key.k94 = x2; + key.k95 = x3; + sbox3(w[96], w[97], w[98], w[99]); + key.k96 = x0; + key.k97 = x1; + key.k98 = x2; + key.k99 = x3; + sbox2(w[100], w[101], w[102], w[103]); + key.k100 = x0; + key.k101 = x1; + key.k102 = x2; + key.k103 = x3; + sbox1(w[104], w[105], w[106], w[107]); + key.k104 = x0; + key.k105 = x1; + key.k106 = x2; + key.k107 = x3; + sbox0(w[108], w[109], w[110], w[111]); + key.k108 = x0; + key.k109 = x1; + key.k110 = x2; + key.k111 = x3; + sbox7(w[112], w[113], w[114], w[115]); + key.k112 = x0; + key.k113 = x1; + key.k114 = x2; + key.k115 = x3; + sbox6(w[116], w[117], w[118], w[119]); + key.k116 = x0; + key.k117 = x1; + key.k118 = x2; + key.k119 = x3; + sbox5(w[120], w[121], w[122], w[123]); + key.k120 = x0; + key.k121 = x1; + key.k122 = x2; + key.k123 = x3; + sbox4(w[124], w[125], w[126], w[127]); + key.k124 = x0; + key.k125 = x1; + key.k126 = x2; + key.k127 = x3; + sbox3(w[128], w[129], w[130], w[131]); + key.k128 = x0; + key.k129 = x1; + key.k130 = x2; + key.k131 = x3; + return key; + } + + public synchronized void encrypt(byte[] in, int i, byte[] out, int o, + Object K, int bs) + { + Key key = (Key) K; + x0 = (in[i ] & 0xff) + | (in[i + 1] & 0xff) << 8 + | (in[i + 2] & 0xff) << 16 + | (in[i + 3] & 0xff) << 24; + x1 = (in[i + 4] & 0xff) + | (in[i + 5] & 0xff) << 8 + | (in[i + 6] & 0xff) << 16 + | (in[i + 7] & 0xff) << 24; + x2 = (in[i + 8] & 0xff) + | (in[i + 9] & 0xff) << 8 + | (in[i + 10] & 0xff) << 16 + | (in[i + 11] & 0xff) << 24; + x3 = (in[i + 12] & 0xff) + | (in[i + 13] & 0xff) << 8 + | (in[i + 14] & 0xff) << 16 + | (in[i + 15] & 0xff) << 24; + x0 ^= key.k0; + x1 ^= key.k1; + x2 ^= key.k2; + x3 ^= key.k3; + sbox0(); + x1 ^= key.k4; + x4 ^= key.k5; + x2 ^= key.k6; + x0 ^= key.k7; + sbox1(); + x0 ^= key.k8; + x4 ^= key.k9; + x2 ^= key.k10; + x1 ^= key.k11; + sbox2(); + x2 ^= key.k12; + x1 ^= key.k13; + x4 ^= key.k14; + x3 ^= key.k15; + sbox3(); + x1 ^= key.k16; + x4 ^= key.k17; + x3 ^= key.k18; + x0 ^= key.k19; + sbox4(); + x4 ^= key.k20; + x2 ^= key.k21; + x1 ^= key.k22; + x0 ^= key.k23; + sbox5(); + x2 ^= key.k24; + x0 ^= key.k25; + x4 ^= key.k26; + x1 ^= key.k27; + sbox6(); + x2 ^= key.k28; + x0 ^= key.k29; + x3 ^= key.k30; + x4 ^= key.k31; + sbox7(); + x0 = x3; + x3 = x2; + x2 = x4; + x0 ^= key.k32; + x1 ^= key.k33; + x2 ^= key.k34; + x3 ^= key.k35; + sbox0(); + x1 ^= key.k36; + x4 ^= key.k37; + x2 ^= key.k38; + x0 ^= key.k39; + sbox1(); + x0 ^= key.k40; + x4 ^= key.k41; + x2 ^= key.k42; + x1 ^= key.k43; + sbox2(); + x2 ^= key.k44; + x1 ^= key.k45; + x4 ^= key.k46; + x3 ^= key.k47; + sbox3(); + x1 ^= key.k48; + x4 ^= key.k49; + x3 ^= key.k50; + x0 ^= key.k51; + sbox4(); + x4 ^= key.k52; + x2 ^= key.k53; + x1 ^= key.k54; + x0 ^= key.k55; + sbox5(); + x2 ^= key.k56; + x0 ^= key.k57; + x4 ^= key.k58; + x1 ^= key.k59; + sbox6(); + x2 ^= key.k60; + x0 ^= key.k61; + x3 ^= key.k62; + x4 ^= key.k63; + sbox7(); + x0 = x3; + x3 = x2; + x2 = x4; + x0 ^= key.k64; + x1 ^= key.k65; + x2 ^= key.k66; + x3 ^= key.k67; + sbox0(); + x1 ^= key.k68; + x4 ^= key.k69; + x2 ^= key.k70; + x0 ^= key.k71; + sbox1(); + x0 ^= key.k72; + x4 ^= key.k73; + x2 ^= key.k74; + x1 ^= key.k75; + sbox2(); + x2 ^= key.k76; + x1 ^= key.k77; + x4 ^= key.k78; + x3 ^= key.k79; + sbox3(); + x1 ^= key.k80; + x4 ^= key.k81; + x3 ^= key.k82; + x0 ^= key.k83; + sbox4(); + x4 ^= key.k84; + x2 ^= key.k85; + x1 ^= key.k86; + x0 ^= key.k87; + sbox5(); + x2 ^= key.k88; + x0 ^= key.k89; + x4 ^= key.k90; + x1 ^= key.k91; + sbox6(); + x2 ^= key.k92; + x0 ^= key.k93; + x3 ^= key.k94; + x4 ^= key.k95; + sbox7(); + x0 = x3; + x3 = x2; + x2 = x4; + x0 ^= key.k96; + x1 ^= key.k97; + x2 ^= key.k98; + x3 ^= key.k99; + sbox0(); + x1 ^= key.k100; + x4 ^= key.k101; + x2 ^= key.k102; + x0 ^= key.k103; + sbox1(); + x0 ^= key.k104; + x4 ^= key.k105; + x2 ^= key.k106; + x1 ^= key.k107; + sbox2(); + x2 ^= key.k108; + x1 ^= key.k109; + x4 ^= key.k110; + x3 ^= key.k111; + sbox3(); + x1 ^= key.k112; + x4 ^= key.k113; + x3 ^= key.k114; + x0 ^= key.k115; + sbox4(); + x4 ^= key.k116; + x2 ^= key.k117; + x1 ^= key.k118; + x0 ^= key.k119; + sbox5(); + x2 ^= key.k120; + x0 ^= key.k121; + x4 ^= key.k122; + x1 ^= key.k123; + sbox6(); + x2 ^= key.k124; + x0 ^= key.k125; + x3 ^= key.k126; + x4 ^= key.k127; + sbox7noLT(); + x0 = x3; + x3 = x2; + x2 = x4; + x0 ^= key.k128; + x1 ^= key.k129; + x2 ^= key.k130; + x3 ^= key.k131; + out[o ] = (byte) x0; + out[o + 1] = (byte)(x0 >>> 8); + out[o + 2] = (byte)(x0 >>> 16); + out[o + 3] = (byte)(x0 >>> 24); + out[o + 4] = (byte) x1; + out[o + 5] = (byte)(x1 >>> 8); + out[o + 6] = (byte)(x1 >>> 16); + out[o + 7] = (byte)(x1 >>> 24); + out[o + 8] = (byte) x2; + out[o + 9] = (byte)(x2 >>> 8); + out[o + 10] = (byte)(x2 >>> 16); + out[o + 11] = (byte)(x2 >>> 24); + out[o + 12] = (byte) x3; + out[o + 13] = (byte)(x3 >>> 8); + out[o + 14] = (byte)(x3 >>> 16); + out[o + 15] = (byte)(x3 >>> 24); + } + + public synchronized void decrypt(byte[] in, int i, byte[] out, int o, + Object K, int bs) + { + Key key = (Key) K; + x0 = (in[i ] & 0xff) + | (in[i + 1] & 0xff) << 8 + | (in[i + 2] & 0xff) << 16 + | (in[i + 3] & 0xff) << 24; + x1 = (in[i + 4] & 0xff) + | (in[i + 5] & 0xff) << 8 + | (in[i + 6] & 0xff) << 16 + | (in[i + 7] & 0xff) << 24; + x2 = (in[i + 8] & 0xff) + | (in[i + 9] & 0xff) << 8 + | (in[i + 10] & 0xff) << 16 + | (in[i + 11] & 0xff) << 24; + x3 = (in[i + 12] & 0xff) + | (in[i + 13] & 0xff) << 8 + | (in[i + 14] & 0xff) << 16 + | (in[i + 15] & 0xff) << 24; + x0 ^= key.k128; + x1 ^= key.k129; + x2 ^= key.k130; + x3 ^= key.k131; + sboxI7noLT(); + x3 ^= key.k124; + x0 ^= key.k125; + x1 ^= key.k126; + x4 ^= key.k127; + sboxI6(); + x0 ^= key.k120; + x1 ^= key.k121; + x2 ^= key.k122; + x4 ^= key.k123; + sboxI5(); + x1 ^= key.k116; + x3 ^= key.k117; + x4 ^= key.k118; + x2 ^= key.k119; + sboxI4(); + x1 ^= key.k112; + x2 ^= key.k113; + x4 ^= key.k114; + x0 ^= key.k115; + sboxI3(); + x0 ^= key.k108; + x1 ^= key.k109; + x4 ^= key.k110; + x2 ^= key.k111; + sboxI2(); + x1 ^= key.k104; + x3 ^= key.k105; + x4 ^= key.k106; + x2 ^= key.k107; + sboxI1(); + x0 ^= key.k100; + x1 ^= key.k101; + x2 ^= key.k102; + x4 ^= key.k103; + sboxI0(); + x0 ^= key.k96; + x3 ^= key.k97; + x1 ^= key.k98; + x4 ^= key.k99; + sboxI7(); + x1 = x3; + x3 = x4; + x4 = x2; + x3 ^= key.k92; + x0 ^= key.k93; + x1 ^= key.k94; + x4 ^= key.k95; + sboxI6(); + x0 ^= key.k88; + x1 ^= key.k89; + x2 ^= key.k90; + x4 ^= key.k91; + sboxI5(); + x1 ^= key.k84; + x3 ^= key.k85; + x4 ^= key.k86; + x2 ^= key.k87; + sboxI4(); + x1 ^= key.k80; + x2 ^= key.k81; + x4 ^= key.k82; + x0 ^= key.k83; + sboxI3(); + x0 ^= key.k76; + x1 ^= key.k77; + x4 ^= key.k78; + x2 ^= key.k79; + sboxI2(); + x1 ^= key.k72; + x3 ^= key.k73; + x4 ^= key.k74; + x2 ^= key.k75; + sboxI1(); + x0 ^= key.k68; + x1 ^= key.k69; + x2 ^= key.k70; + x4 ^= key.k71; + sboxI0(); + x0 ^= key.k64; + x3 ^= key.k65; + x1 ^= key.k66; + x4 ^= key.k67; + sboxI7(); + x1 = x3; + x3 = x4; + x4 = x2; + x3 ^= key.k60; + x0 ^= key.k61; + x1 ^= key.k62; + x4 ^= key.k63; + sboxI6(); + x0 ^= key.k56; + x1 ^= key.k57; + x2 ^= key.k58; + x4 ^= key.k59; + sboxI5(); + x1 ^= key.k52; + x3 ^= key.k53; + x4 ^= key.k54; + x2 ^= key.k55; + sboxI4(); + x1 ^= key.k48; + x2 ^= key.k49; + x4 ^= key.k50; + x0 ^= key.k51; + sboxI3(); + x0 ^= key.k44; + x1 ^= key.k45; + x4 ^= key.k46; + x2 ^= key.k47; + sboxI2(); + x1 ^= key.k40; + x3 ^= key.k41; + x4 ^= key.k42; + x2 ^= key.k43; + sboxI1(); + x0 ^= key.k36; + x1 ^= key.k37; + x2 ^= key.k38; + x4 ^= key.k39; + sboxI0(); + x0 ^= key.k32; + x3 ^= key.k33; + x1 ^= key.k34; + x4 ^= key.k35; + sboxI7(); + x1 = x3; + x3 = x4; + x4 = x2; + x3 ^= key.k28; + x0 ^= key.k29; + x1 ^= key.k30; + x4 ^= key.k31; + sboxI6(); + x0 ^= key.k24; + x1 ^= key.k25; + x2 ^= key.k26; + x4 ^= key.k27; + sboxI5(); + x1 ^= key.k20; + x3 ^= key.k21; + x4 ^= key.k22; + x2 ^= key.k23; + sboxI4(); + x1 ^= key.k16; + x2 ^= key.k17; + x4 ^= key.k18; + x0 ^= key.k19; + sboxI3(); + x0 ^= key.k12; + x1 ^= key.k13; + x4 ^= key.k14; + x2 ^= key.k15; + sboxI2(); + x1 ^= key.k8; + x3 ^= key.k9; + x4 ^= key.k10; + x2 ^= key.k11; + sboxI1(); + x0 ^= key.k4; + x1 ^= key.k5; + x2 ^= key.k6; + x4 ^= key.k7; + sboxI0(); + x2 = x1; + x1 = x3; + x3 = x4; + x0 ^= key.k0; + x1 ^= key.k1; + x2 ^= key.k2; + x3 ^= key.k3; + out[o ] = (byte) x0; + out[o + 1] = (byte)(x0 >>> 8); + out[o + 2] = (byte)(x0 >>> 16); + out[o + 3] = (byte)(x0 >>> 24); + out[o + 4] = (byte) x1; + out[o + 5] = (byte)(x1 >>> 8); + out[o + 6] = (byte)(x1 >>> 16); + out[o + 7] = (byte)(x1 >>> 24); + out[o + 8] = (byte) x2; + out[o + 9] = (byte)(x2 >>> 8); + out[o + 10] = (byte)(x2 >>> 16); + out[o + 11] = (byte)(x2 >>> 24); + out[o + 12] = (byte) x3; + out[o + 13] = (byte)(x3 >>> 8); + out[o + 14] = (byte)(x3 >>> 16); + out[o + 15] = (byte)(x3 >>> 24); + } + + public boolean selfTest() + { + if (valid == null) + { + boolean result = super.selfTest(); // do symmetry tests + if (result) + result = testKat(KAT_KEY, KAT_CT); + valid = Boolean.valueOf(result); + } + return valid.booleanValue(); + } + + // These first few S-boxes operate directly on the "registers", + // x0..x4, and perform the linear transform. + private void sbox0() + { + x3 ^= x0; + x4 = x1; + x1 &= x3; + x4 ^= x2; + x1 ^= x0; + x0 |= x3; + x0 ^= x4; + x4 ^= x3; + x3 ^= x2; + x2 |= x1; + x2 ^= x4; + x4 ^= -1; + x4 |= x1; + x1 ^= x3; + x1 ^= x4; + x3 |= x0; + x1 ^= x3; + x4 ^= x3; + + x1 = (x1 << 13) | (x1 >>> 19); + x4 ^= x1; + x3 = x1 << 3; + x2 = (x2 << 3) | (x2 >>> 29); + x4 ^= x2; + x0 ^= x2; + x4 = (x4 << 1) | (x4 >>> 31); + x0 ^= x3; + x0 = (x0 << 7) | (x0 >>> 25); + x3 = x4; + x1 ^= x4; + x3 <<= 7; + x1 ^= x0; + x2 ^= x0; + x2 ^= x3; + x1 = (x1 << 5) | (x1 >>> 27); + x2 = (x2 << 22) | (x2 >>> 10); + } + + private void sbox1() + { + x4 = ~x4; + x3 = x1; + x1 ^= x4; + x3 |= x4; + x3 ^= x0; + x0 &= x1; + x2 ^= x3; + x0 ^= x4; + x0 |= x2; + x1 ^= x3; + x0 ^= x1; + x4 &= x2; + x1 |= x4; + x4 ^= x3; + x1 ^= x2; + x3 |= x0; + x1 ^= x3; + x3 = ~x3; + x4 ^= x0; + x3 &= x2; + x4 = ~x4; + x3 ^= x1; + x4 ^= x3; + + x0 = (x0 << 13) | (x0 >>> 19); + x4 ^= x0; + x3 = x0 << 3; + x2 = (x2 << 3) | (x2 >>> 29); + x4 ^= x2; + x1 ^= x2; + x4 = (x4 << 1) | (x4 >>> 31); + x1 ^= x3; + x1 = (x1 << 7) | (x1 >>> 25); + x3 = x4; + x0 ^= x4; + x3 <<= 7; + x0 ^= x1; + x2 ^= x1; + x2 ^= x3; + x0 = (x0 << 5) | (x0 >>> 27); + x2 = (x2 << 22) | (x2 >>> 10); + } + + private void sbox2() + { + x3 = x0; + x0 = x0 & x2; + x0 = x0 ^ x1; + x2 = x2 ^ x4; + x2 = x2 ^ x0; + x1 = x1 | x3; + x1 = x1 ^ x4; + x3 = x3 ^ x2; + x4 = x1; + x1 = x1 | x3; + x1 = x1 ^ x0; + x0 = x0 & x4; + x3 = x3 ^ x0; + x4 = x4 ^ x1; + x4 = x4 ^ x3; + x3 = ~x3; + + x2 = (x2 << 13) | (x2 >>> 19); + x1 ^= x2; + x0 = x2 << 3; + x4 = (x4 << 3) | (x4 >>> 29); + x1 ^= x4; + x3 ^= x4; + x1 = (x1 << 1) | (x1 >>> 31); + x3 ^= x0; + x3 = (x3 << 7) | (x3 >>> 25); + x0 = x1; + x2 ^= x1; + x0 <<= 7; + x2 ^= x3; + x4 ^= x3; + x4 ^= x0; + x2 = (x2 << 5) | (x2 >>> 27); + x4 = (x4 << 22) | (x4 >>> 10); + } + + private void sbox3() + { + x0 = x2; + x2 = x2 | x3; + x3 = x3 ^ x1; + x1 = x1 & x0; + x0 = x0 ^ x4; + x4 = x4 ^ x3; + x3 = x3 & x2; + x0 = x0 | x1; + x3 = x3 ^ x0; + x2 = x2 ^ x1; + x0 = x0 & x2; + x1 = x1 ^ x3; + x0 = x0 ^ x4; + x1 = x1 | x2; + x1 = x1 ^ x4; + x2 = x2 ^ x3; + x4 = x1; + x1 = x1 | x3; + x1 = x1 ^ x2; + + x1 = (x1 << 13) | (x1 >>> 19); + x4 ^= x1; + x2 = x1 << 3; + x3 = (x3 << 3) | (x3 >>> 29); + x4 ^= x3; + x0 ^= x3; + x4 = (x4 << 1) | (x4 >>> 31); + x0 ^= x2; + x0 = (x0 << 7) | (x0 >>> 25); + x2 = x4; + x1 ^= x4; + x2 <<= 7; + x1 ^= x0; + x3 ^= x0; + x3 ^= x2; + x1 = (x1 << 5) | (x1 >>> 27); + x3 = (x3 << 22) | (x3 >>> 10); + } + + private void sbox4() + { + x4 = x4 ^ x0; + x0 = ~x0; + x3 = x3 ^ x0; + x0 = x0 ^ x1; + x2 = x4; + x4 = x4 & x0; + x4 = x4 ^ x3; + x2 = x2 ^ x0; + x1 = x1 ^ x2; + x3 = x3 & x2; + x3 = x3 ^ x1; + x1 = x1 & x4; + x0 = x0 ^ x1; + x2 = x2 | x4; + x2 = x2 ^ x1; + x1 = x1 | x0; + x1 = x1 ^ x3; + x3 = x3 & x0; + x1 = ~x1; + x2 = x2 ^ x3; + + x4 = (x4 << 13) | (x4 >>> 19); + x2 ^= x4; + x3 = x4 << 3; + x1 = (x1 << 3) | (x1 >>> 29); + x2 ^= x1; + x0 ^= x1; + x2 = (x2 << 1) | (x2 >>> 31); + x0 ^= x3; + x0 = (x0 << 7) | (x0 >>> 25); + x3 = x2; + x4 ^= x2; + x3 <<= 7; + x4 ^= x0; + x1 ^= x0; + x1 ^= x3; + x4 = (x4 << 5) | (x4 >>> 27); + x1 = (x1 << 22) | (x1 >>> 10); + } + + private void sbox5() + { + x4 = x4 ^ x2; + x2 = x2 ^ x0; + x0 = ~x0; + x3 = x2; + x2 = x2 & x4; + x1 = x1 ^ x0; + x2 = x2 ^ x1; + x1 = x1 | x3; + x3 = x3 ^ x0; + x0 = x0 & x2; + x0 = x0 ^ x4; + x3 = x3 ^ x2; + x3 = x3 ^ x1; + x1 = x1 ^ x4; + x4 = x4 & x0; + x1 = ~x1; + x4 = x4 ^ x3; + x3 = x3 | x0; + x1 = x1 ^ x3; + + x2 = (x2 << 13) | (x2 >>> 19); + x0 ^= x2; + x3 = x2 << 3; + x4 = (x4 << 3) | (x4 >>> 29); + x0 ^= x4; + x1 ^= x4; + x0 = (x0 << 1) | (x0 >>> 31); + x1 ^= x3; + x1 = (x1 << 7) | (x1 >>> 25); + x3 = x0; + x2 ^= x0; + x3 <<= 7; + x2 ^= x1; + x4 ^= x1; + x4 ^= x3; + x2 = (x2 << 5) | (x2 >>> 27); + x4 = (x4 << 22) | (x4 >>> 10); + } + + private void sbox6() + { + x4 = ~x4; + x3 = x1; + x1 = x1 & x2; + x2 = x2 ^ x3; + x1 = x1 ^ x4; + x4 = x4 | x3; + x0 = x0 ^ x1; + x4 = x4 ^ x2; + x2 = x2 | x0; + x4 = x4 ^ x0; + x3 = x3 ^ x2; + x2 = x2 | x1; + x2 = x2 ^ x4; + x3 = x3 ^ x1; + x3 = x3 ^ x2; + x1 = ~x1; + x4 = x4 & x3; + x4 = x4 ^ x1; + x2 = (x2 << 13) | (x2 >>> 19); + x0 ^= x2; + x1 = x2 << 3; + x3 = (x3 << 3) | (x3 >>> 29); + x0 ^= x3; + x4 ^= x3; + x0 = (x0 << 1) | (x0 >>> 31); + x4 ^= x1; + x4 = (x4 << 7) | (x4 >>> 25); + x1 = x0; + x2 ^= x0; + x1 <<= 7; + x2 ^= x4; + x3 ^= x4; + x3 ^= x1; + x2 = (x2 << 5) | (x2 >>> 27); + x3 = (x3 << 22) | (x3 >>> 10); + } + + private void sbox7() + { + x1 = x3; + x3 = x3 & x0; + x3 = x3 ^ x4; + x4 = x4 & x0; + x1 = x1 ^ x3; + x3 = x3 ^ x0; + x0 = x0 ^ x2; + x2 = x2 | x1; + x2 = x2 ^ x3; + x4 = x4 ^ x0; + x3 = x3 ^ x4; + x4 = x4 & x2; + x4 = x4 ^ x1; + x1 = x1 ^ x3; + x3 = x3 & x2; + x1 = ~x1; + x3 = x3 ^ x1; + x1 = x1 & x2; + x0 = x0 ^ x4; + x1 = x1 ^ x0; + x3 = (x3 << 13) | (x3 >>> 19); + x1 ^= x3; + x0 = x3 << 3; + x4 = (x4 << 3) | (x4 >>> 29); + x1 ^= x4; + x2 ^= x4; + x1 = (x1 << 1) | (x1 >>> 31); + x2 ^= x0; + x2 = (x2 << 7) | (x2 >>> 25); + x0 = x1; + x3 ^= x1; + x0 <<= 7; + x3 ^= x2; + x4 ^= x2; + x4 ^= x0; + x3 = (x3 << 5) | (x3 >>> 27); + x4 = (x4 << 22) | (x4 >>> 10); + } + + /** The final S-box, with no transform. */ + private void sbox7noLT() + { + x1 = x3; + x3 = x3 & x0; + x3 = x3 ^ x4; + x4 = x4 & x0; + x1 = x1 ^ x3; + x3 = x3 ^ x0; + x0 = x0 ^ x2; + x2 = x2 | x1; + x2 = x2 ^ x3; + x4 = x4 ^ x0; + x3 = x3 ^ x4; + x4 = x4 & x2; + x4 = x4 ^ x1; + x1 = x1 ^ x3; + x3 = x3 & x2; + x1 = ~x1; + x3 = x3 ^ x1; + x1 = x1 & x2; + x0 = x0 ^ x4; + x1 = x1 ^ x0; + } + + private void sboxI7noLT() + { + x4 = x2; + x2 ^= x0; + x0 &= x3; + x2 = ~x2; + x4 |= x3; + x3 ^= x1; + x1 |= x0; + x0 ^= x2; + x2 &= x4; + x1 ^= x2; + x2 ^= x0; + x0 |= x2; + x3 &= x4; + x0 ^= x3; + x4 ^= x1; + x3 ^= x4; + x4 |= x0; + x3 ^= x2; + x4 ^= x2; + } + + private void sboxI6() + { + x1 = (x1 >>> 22) | (x1 << 10); + x3 = (x3 >>> 5) | (x3 << 27); + x2 = x0; + x1 ^= x4; + x2 <<= 7; + x3 ^= x4; + x1 ^= x2; + x3 ^= x0; + x4 = (x4 >>> 7) | (x4 << 25); + x0 = (x0 >>> 1) | (x0 << 31); + x0 ^= x3; + x2 = x3 << 3; + x4 ^= x2; + x3 = (x3 >>> 13) | (x3 << 19); + x0 ^= x1; + x4 ^= x1; + x1 = (x1 >>> 3) | (x1 << 29); + x3 ^= x1; + x2 = x1; + x1 &= x3; + x2 ^= x4; + x1 = ~x1; + x4 ^= x0; + x1 ^= x4; + x2 |= x3; + x3 ^= x1; + x4 ^= x2; + x2 ^= x0; + x0 &= x4; + x0 ^= x3; + x3 ^= x4; + x3 |= x1; + x4 ^= x0; + x2 ^= x3; + } + + private void sboxI5() + { + x2 = (x2 >>> 22) | (x2 << 10); + x0 = (x0 >>> 5) | (x0 << 27); + x3 = x1; + x2 ^= x4; + x3 <<= 7; + x0 ^= x4; + x2 ^= x3; + x0 ^= x1; + x4 = (x4 >>> 7) | (x4 << 25); + x1 = (x1 >>> 1) | (x1 << 31); + x1 ^= x0; + x3 = x0 << 3; + x4 ^= x3; + x0 = (x0 >>> 13) | (x0 << 19); + x1 ^= x2; + x4 ^= x2; + x2 = (x2 >>> 3) | (x2 << 29); + x1 = ~x1; + x3 = x4; + x2 ^= x1; + x4 |= x0; + x4 ^= x2; + x2 |= x1; + x2 &= x0; + x3 ^= x4; + x2 ^= x3; + x3 |= x0; + x3 ^= x1; + x1 &= x2; + x1 ^= x4; + x3 ^= x2; + x4 &= x3; + x3 ^= x1; + x4 ^= x0; + x4 ^= x3; + x3 = ~x3; + } + + private void sboxI4() + { + x4 = (x4 >>> 22) | (x4 << 10); + x1 = (x1 >>> 5) | (x1 << 27); + x0 = x3; + x4 ^= x2; + x0 <<= 7; + x1 ^= x2; + x4 ^= x0; + x1 ^= x3; + x2 = (x2 >>> 7) | (x2 << 25); + x3 = (x3 >>> 1) | (x3 << 31); + x3 ^= x1; + x0 = x1 << 3; + x2 ^= x0; + x1 = (x1 >>> 13) | (x1 << 19); + x3 ^= x4; + x2 ^= x4; + x4 = (x4 >>> 3) | (x4 << 29); + x0 = x4; + x4 &= x2; + x4 ^= x3; + x3 |= x2; + x3 &= x1; + x0 ^= x4; + x0 ^= x3; + x3 &= x4; + x1 = ~x1; + x2 ^= x0; + x3 ^= x2; + x2 &= x1; + x2 ^= x4; + x1 ^= x3; + x4 &= x1; + x2 ^= x1; + x4 ^= x0; + x4 |= x2; + x2 ^= x1; + x4 ^= x3; + } + + private void sboxI3() + { + x4 = (x4 >>> 22) | (x4 << 10); + x1 = (x1 >>> 5) | (x1 << 27); + x3 = x2; + x4 ^= x0; + x3 <<= 7; + x1 ^= x0; + x4 ^= x3; + x1 ^= x2; + x0 = (x0 >>> 7) | (x0 << 25); + x2 = (x2 >>> 1) | (x2 << 31); + x2 ^= x1; + x3 = x1 << 3; + x0 ^= x3; + x1 = (x1 >>> 13) | (x1 << 19); + x2 ^= x4; + x0 ^= x4; + x4 = (x4 >>> 3) | (x4 << 29); + x3 = x4; + x4 ^= x2; + x2 &= x4; + x2 ^= x1; + x1 &= x3; + x3 ^= x0; + x0 |= x2; + x0 ^= x4; + x1 ^= x3; + x4 ^= x1; + x1 |= x0; + x1 ^= x2; + x3 ^= x4; + x4 &= x0; + x2 |= x0; + x2 ^= x4; + x3 ^= x1; + x4 ^= x3; + } + + private void sboxI2() + { + x4 = (x4 >>> 22) | (x4 << 10); + x0 = (x0 >>> 5) | (x0 << 27); + x3 = x1; + x4 ^= x2; + x3 <<= 7; + x0 ^= x2; + x4 ^= x3; + x0 ^= x1; + x2 = (x2 >>> 7) | (x2 << 25); + x1 = (x1 >>> 1) | (x1 << 31); + x1 ^= x0; + x3 = x0 << 3; + x2 ^= x3; + x0 = (x0 >>> 13) | (x0 << 19); + x1 ^= x4; + x2 ^= x4; + x4 = (x4 >>> 3) | (x4 << 29); + x4 ^= x2; + x2 ^= x0; + x3 = x2; + x2 &= x4; + x2 ^= x1; + x1 |= x4; + x1 ^= x3; + x3 &= x2; + x4 ^= x2; + x3 &= x0; + x3 ^= x4; + x4 &= x1; + x4 |= x0; + x2 = ~x2; + x4 ^= x2; + x0 ^= x2; + x0 &= x1; + x2 ^= x3; + x2 ^= x0; + } + + private void sboxI1() + { + x4 = (x4 >>> 22) | (x4 << 10); + x1 = (x1 >>> 5) | (x1 << 27); + x0 = x3; + x4 ^= x2; + x0 <<= 7; + x1 ^= x2; + x4 ^= x0; + x1 ^= x3; + x2 = (x2 >>> 7) | (x2 << 25); + x3 = (x3 >>> 1) | (x3 << 31); + x3 ^= x1; + x0 = x1 << 3; + x2 ^= x0; + x1 = (x1 >>> 13) | (x1 << 19); + x3 ^= x4; + x2 ^= x4; + x4 = (x4 >>> 3) | (x4 << 29); + x0 = x3; + x3 ^= x2; + x2 &= x3; + x0 ^= x4; + x2 ^= x1; + x1 |= x3; + x4 ^= x2; + x1 ^= x0; + x1 |= x4; + x3 ^= x2; + x1 ^= x3; + x3 |= x2; + x3 ^= x1; + x0 = ~x0; + x0 ^= x3; + x3 |= x1; + x3 ^= x1; + x3 |= x0; + x2 ^= x3; + } + + private void sboxI0() + { + x2 = (x2 >>> 22) | (x2 << 10); + x0 = (x0 >>> 5) | (x0 << 27); + x3 = x1; + x2 ^= x4; + x3 <<= 7; + x0 ^= x4; + x2 ^= x3; + x0 ^= x1; + x4 = (x4 >>> 7) | (x4 << 25); + x1 = (x1 >>> 1) | (x1 << 31); + x1 ^= x0; + x3 = x0 << 3; + x4 ^= x3; + x0 = (x0 >>> 13) | (x0 << 19); + x1 ^= x2; + x4 ^= x2; + x2 = (x2 >>> 3) | (x2 << 29); + x2 = ~x2; + x3 = x1; + x1 |= x0; + x3 = ~x3; + x1 ^= x2; + x2 |= x3; + x1 ^= x4; + x0 ^= x3; + x2 ^= x0; + x0 &= x4; + x3 ^= x0; + x0 |= x1; + x0 ^= x2; + x4 ^= x3; + x2 ^= x1; + x4 ^= x0; + x4 ^= x1; + x2 &= x4; + x3 ^= x2; + } + + private void sboxI7() + { + x1 = (x1 >>> 22) | (x1 << 10); + x0 = (x0 >>> 5) | (x0 << 27); + x2 = x3; + x1 ^= x4; + x2 <<= 7; + x0 ^= x4; + x1 ^= x2; + x0 ^= x3; + x4 = (x4 >>> 7) | (x4 << 25); + x3 = (x3 >>> 1) | (x3 << 31); + x3 ^= x0; + x2 = x0 << 3; + x4 ^= x2; + x0 = (x0 >>> 13) | (x0 << 19); + x3 ^= x1; + x4 ^= x1; + x1 = (x1 >>> 3) | (x1 << 29); + x2 = x1; + x1 ^= x0; + x0 &= x4; + x1 = ~x1; + x2 |= x4; + x4 ^= x3; + x3 |= x0; + x0 ^= x1; + x1 &= x2; + x3 ^= x1; + x1 ^= x0; + x0 |= x1; + x4 &= x2; + x0 ^= x4; + x2 ^= x3; + x4 ^= x2; + x2 |= x0; + x4 ^= x1; + x2 ^= x1; + } + + /** S-Box 0. */ + private void sbox0(int r0, int r1, int r2, int r3) + { + int r4 = r1 ^ r2; + r3 ^= r0; + r1 = r1 & r3 ^ r0; + r0 = (r0 | r3) ^ r4; + r4 ^= r3; + r3 ^= r2; + r2 = (r2 | r1) ^ r4; + r4 = ~r4 | r1; + r1 ^= r3 ^ r4; + r3 |= r0; + x0 = r1 ^ r3; + x1 = r4 ^ r3; + x2 = r2; + x3 = r0; + } + + /** S-Box 1. */ + private void sbox1(int r0, int r1, int r2, int r3) + { + r0 = ~r0; + int r4 = r0; + r2 = ~r2; + r0 &= r1; + r2 ^= r0; + r0 |= r3; + r3 ^= r2; + r1 ^= r0; + r0 ^= r4; + r4 |= r1; + r1 ^= r3; + r2 = (r2 | r0) & r4; + r0 ^= r1; + x0 = r2; + x1 = r0 & r2 ^ r4; + x2 = r3; + x3 = r1 & r2 ^ r0; + } + + /** S-Box 2. */ + private void sbox2(int r0, int r1, int r2, int r3) + { + int r4 = r0; + r0 = r0 & r2 ^ r3; + r2 = r2 ^ r1 ^ r0; + r3 = (r3 | r4) ^ r1; + r4 ^= r2; + r1 = r3; + r3 = (r3 | r4) ^ r0; + r0 &= r1; + r4 ^= r0; + x0 = r2; + x1 = r3; + x2 = r1 ^ r3 ^ r4; + x3 = ~r4; + } + + /** S-Box 3. */ + private void sbox3(int r0, int r1, int r2, int r3) + { + int r4 = r0; + r0 |= r3; + r3 ^= r1; + r1 &= r4; + r4 = r4 ^ r2 | r1; + r2 ^= r3; + r3 = r3 & r0 ^ r4; + r0 ^= r1; + r4 = r4 & r0 ^ r2; + r1 = (r1 ^ r3 | r0) ^ r2; + r0 ^= r3; + x0 = (r1 | r3) ^ r0; + x1 = r1; + x2 = r3; + x3 = r4; + } + + /** S-Box 4. */ + private void sbox4(int r0, int r1, int r2, int r3) + { + r1 ^= r3; + int r4 = r1; + r3 = ~r3; + r2 ^= r3; + r3 ^= r0; + r1 = r1 & r3 ^ r2; + r4 ^= r3; + r0 ^= r4; + r2 = r2 & r4 ^ r0; + r0 &= r1; + r3 ^= r0; + r4 = (r4 | r1) ^ r0; + x0 = r1; + x1 = r4 ^ (r2 & r3); + x2 = ~((r0 | r3) ^ r2); + x3 = r3; + } + + /** S-Box 5. */ + private void sbox5(int r0, int r1, int r2, int r3) + { + r0 ^= r1; + r1 ^= r3; + int r4 = r1; + r3 = ~r3; + r1 &= r0; + r2 ^= r3; + r1 ^= r2; + r2 |= r4; + r4 ^= r3; + r3 = r3 & r1 ^ r0; + r4 = r4 ^ r1 ^ r2; + x0 = r1; + x1 = r3; + x2 = r0 & r3 ^ r4; + x3 = ~(r2 ^ r0) ^ (r4 | r3); + } + + /** S-Box 6. */ + private void sbox6(int r0, int r1, int r2, int r3) + { + int r4 = r3; + r2 = ~r2; + r3 = r3 & r0 ^ r2; + r0 ^= r4; + r2 = (r2 | r4) ^ r0; + r1 ^= r3; + r0 |= r1; + r2 ^= r1; + r4 ^= r0; + r0 = (r0 | r3) ^ r2; + r4 = r4 ^ r3 ^ r0; + x0 = r0; + x1 = r1; + x2 = r4; + x3 = r2 & r4 ^ ~r3; + } + + /** S-Box 7. */ + private void sbox7(int r0, int r1, int r2, int r3) + { + int r4 = r1; + r1 = (r1 | r2) ^ r3; + r4 ^= r2; + r2 ^= r1; + r3 = (r3 | r4) & r0; + r4 ^= r2; + r3 ^= r1; + r1 = (r1 | r4) ^ r0; + r0 = (r0 | r4) ^ r2; + r1 ^= r4; + r2 ^= r1; + x0 = r4 ^ (~r2 | r0); + x1 = r3; + x2 = r1 & r0 ^ r4; + x3 = r0; + } + + private class Key + implements Cloneable + { + int k0, k1, k2, k3, k4, k5, k6, k7, k8, k9, k10, k11, k12, k13, k14, k15, + k16, k17, k18, k19, k20, k21, k22, k23, k24, k25, k26, k27, k28, k29, + k30, k31, k32, k33, k34, k35, k36, k37, k38, k39, k40, k41, k42, k43, + k44, k45, k46, k47, k48, k49, k50, k51, k52, k53, k54, k55, k56, k57, + k58, k59, k60, k61, k62, k63, k64, k65, k66, k67, k68, k69, k70, k71, + k72, k73, k74, k75, k76, k77, k78, k79, k80, k81, k82, k83, k84, k85, + k86, k87, k88, k89, k90, k91, k92, k93, k94, k95, k96, k97, k98, k99, + k100, k101, k102, k103, k104, k105, k106, k107, k108, k109, k110, k111, + k112, k113, k114, k115, k116, k117, k118, k119, k120, k121, k122, k123, + k124, k125, k126, k127, k128, k129, k130, k131; + + /** Trivial 0-arguments constructor. */ + Key() + { + } + + /** Cloning constructor. */ + private Key(Key that) + { + this.k0 = that.k0; + this.k1 = that.k1; + this.k2 = that.k2; + this.k3 = that.k3; + this.k4 = that.k4; + this.k5 = that.k5; + this.k6 = that.k6; + this.k7 = that.k7; + this.k8 = that.k8; + this.k9 = that.k9; + this.k10 = that.k10; + this.k11 = that.k11; + this.k12 = that.k12; + this.k13 = that.k13; + this.k14 = that.k14; + this.k15 = that.k15; + this.k16 = that.k16; + this.k17 = that.k17; + this.k18 = that.k18; + this.k19 = that.k19; + this.k20 = that.k20; + this.k21 = that.k21; + this.k22 = that.k22; + this.k23 = that.k23; + this.k24 = that.k24; + this.k25 = that.k25; + this.k26 = that.k26; + this.k27 = that.k27; + this.k28 = that.k28; + this.k29 = that.k29; + this.k30 = that.k30; + this.k31 = that.k31; + this.k32 = that.k32; + this.k33 = that.k33; + this.k34 = that.k34; + this.k35 = that.k35; + this.k36 = that.k36; + this.k37 = that.k37; + this.k38 = that.k38; + this.k39 = that.k39; + this.k40 = that.k40; + this.k41 = that.k41; + this.k42 = that.k42; + this.k43 = that.k43; + this.k44 = that.k44; + this.k45 = that.k45; + this.k46 = that.k46; + this.k47 = that.k47; + this.k48 = that.k48; + this.k49 = that.k49; + this.k50 = that.k50; + this.k51 = that.k51; + this.k52 = that.k52; + this.k53 = that.k53; + this.k54 = that.k54; + this.k55 = that.k55; + this.k56 = that.k56; + this.k57 = that.k57; + this.k58 = that.k58; + this.k59 = that.k59; + this.k60 = that.k60; + this.k61 = that.k61; + this.k62 = that.k62; + this.k63 = that.k63; + this.k64 = that.k64; + this.k65 = that.k65; + this.k66 = that.k66; + this.k67 = that.k67; + this.k68 = that.k68; + this.k69 = that.k69; + this.k70 = that.k70; + this.k71 = that.k71; + this.k72 = that.k72; + this.k73 = that.k73; + this.k74 = that.k74; + this.k75 = that.k75; + this.k76 = that.k76; + this.k77 = that.k77; + this.k78 = that.k78; + this.k79 = that.k79; + this.k80 = that.k80; + this.k81 = that.k81; + this.k82 = that.k82; + this.k83 = that.k83; + this.k84 = that.k84; + this.k85 = that.k85; + this.k86 = that.k86; + this.k87 = that.k87; + this.k88 = that.k88; + this.k89 = that.k89; + this.k90 = that.k90; + this.k91 = that.k91; + this.k92 = that.k92; + this.k93 = that.k93; + this.k94 = that.k94; + this.k95 = that.k95; + this.k96 = that.k96; + this.k97 = that.k97; + this.k98 = that.k98; + this.k99 = that.k99; + this.k100 = that.k100; + this.k101 = that.k101; + this.k102 = that.k102; + this.k103 = that.k103; + this.k104 = that.k104; + this.k105 = that.k105; + this.k106 = that.k106; + this.k107 = that.k107; + this.k108 = that.k108; + this.k109 = that.k109; + this.k110 = that.k110; + this.k111 = that.k111; + this.k112 = that.k112; + this.k113 = that.k113; + this.k114 = that.k114; + this.k115 = that.k115; + this.k116 = that.k116; + this.k117 = that.k117; + this.k118 = that.k118; + this.k119 = that.k119; + this.k120 = that.k120; + this.k121 = that.k121; + this.k122 = that.k122; + this.k123 = that.k123; + this.k124 = that.k124; + this.k125 = that.k125; + this.k126 = that.k126; + this.k127 = that.k127; + this.k128 = that.k128; + this.k129 = that.k129; + this.k130 = that.k130; + this.k131 = that.k131; + } + + public Object clone() + { + return new Key(this); + } + } +} diff --git a/libjava/classpath/gnu/javax/crypto/cipher/Square.java b/libjava/classpath/gnu/javax/crypto/cipher/Square.java new file mode 100644 index 000000000..231df0a47 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/cipher/Square.java @@ -0,0 +1,425 @@ +/* Square.java -- + Copyright (C) 2001, 2002, 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.cipher; + +import gnu.java.security.Registry; +import gnu.java.security.util.Util; + +import java.security.InvalidKeyException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Iterator; + +/** + * Square is a 128-bit key, 128-bit block cipher algorithm developed by Joan + * Daemen, Lars Knudsen and Vincent Rijmen. + * <p> + * References: + * <ol> + * <li><a href="http://www.esat.kuleuven.ac.be/~rijmen/square/">The block + * cipher Square</a>.<br> + * <a href="mailto:daemen.j@protonworld.com">Joan Daemen</a>, <a + * href="mailto:lars.knudsen@esat.kuleuven.ac.be">Lars Knudsen</a> and <a + * href="mailto:vincent.rijmen@esat.kuleuven.ac.be">Vincent Rijmen</a>.</li> + * </ol> + */ +public final class Square + extends BaseCipher +{ + private static final int DEFAULT_BLOCK_SIZE = 16; // in bytes + private static final int DEFAULT_KEY_SIZE = 16; // in bytes + private static final int ROUNDS = 8; + private static final int ROOT = 0x1F5; // for generating GF(2**8) + private static final int[] OFFSET = new int[ROUNDS]; + private static final String Sdata = + "\uB1CE\uC395\u5AAD\uE702\u4D44\uFB91\u0C87\uA150" + + "\uCB67\u54DD\u468F\uE14E\uF0FD\uFCEB\uF9C4\u1A6E" + + "\u5EF5\uCC8D\u1C56\u43FE\u0761\uF875\u59FF\u0322" + + "\u8AD1\u13EE\u8800\u0E34\u1580\u94E3\uEDB5\u5323" + + "\u4B47\u17A7\u9035\uABD8\uB8DF\u4F57\u9A92\uDB1B" + + "\u3CC8\u9904\u8EE0\uD77D\u85BB\u402C\u3A45\uF142" + + "\u6520\u4118\u7225\u9370\u3605\uF20B\uA379\uEC08" + + "\u2731\u32B6\u7CB0\u0A73\u5B7B\uB781\uD20D\u6A26" + + "\u9E58\u9C83\u74B3\uAC30\u7A69\u770F\uAE21\uDED0" + + "\u2E97\u10A4\u98A8\uD468\u2D62\u296D\u1649\u76C7" + + "\uE8C1\u9637\uE5CA\uF4E9\u6312\uC2A6\u14BC\uD328" + + "\uAF2F\uE624\u52C6\uA009\uBD8C\uCF5D\u115F\u01C5" + + "\u9F3D\uA29B\uC93B\uBE51\u191F\u3F5C\uB2EF\u4ACD" + + "\uBFBA\u6F64\uD9F3\u3EB4\uAADC\uD506\uC07E\uF666" + + "\u6C84\u7138\uB91D\u7F9D\u488B\u2ADA\uA533\u8239" + + "\uD678\u86FA\uE42B\uA91E\u8960\u6BEA\u554C\uF7E2"; + /** Substitution boxes for encryption and decryption. */ + private static final byte[] Se = new byte[256]; + private static final byte[] Sd = new byte[256]; + /** Transposition boxes for encryption and decryption. */ + private static final int[] Te = new int[256]; + private static final int[] Td = new int[256]; + /** + * KAT vector (from ecb_vk): I=87 KEY=00000000000000000000020000000000 + * CT=A9DF031B4E25E89F527EFFF89CB0BEBA + */ + private static final byte[] KAT_KEY = + Util.toBytesFromString("00000000000000000000020000000000"); + private static final byte[] KAT_CT = + Util.toBytesFromString("A9DF031B4E25E89F527EFFF89CB0BEBA"); + /** caches the result of the correctness test, once executed. */ + private static Boolean valid; + static + { + int i, j; + // re-construct Se box values + int limit = Sdata.length(); + char c1; + for (i = 0, j = 0; i < limit; i++) + { + c1 = Sdata.charAt(i); + Se[j++] = (byte)(c1 >>> 8); + Se[j++] = (byte) c1; + } + // compute Sd box values + for (i = 0; i < 256; i++) + Sd[Se[i] & 0xFF] = (byte) i; + // generate OFFSET values + OFFSET[0] = 1; + for (i = 1; i < ROUNDS; i++) + { + OFFSET[i] = mul(OFFSET[i - 1], 2); + OFFSET[i - 1] <<= 24; + } + OFFSET[ROUNDS - 1] <<= 24; + // generate Te and Td boxes if we're not reading their values + // Notes: + // (1) The function mul() computes the product of two elements of GF(2**8) + // with ROOT as reduction polynomial. + // (2) the values used in computing the Te and Td are the GF(2**8) + // coefficients of the diffusion polynomial c(x) and its inverse + // (modulo x**4 + 1) d(x), defined in sections 2.1 and 4 of the Square + // paper. + for (i = 0; i < 256; i++) + { + j = Se[i] & 0xFF; + Te[i] = (Se[i & 3] == 0) ? 0 + : mul(j, 2) << 24 + | j << 16 + | j << 8 + | mul(j, 3); + j = Sd[i] & 0xFF; + Td[i] = (Sd[i & 3] == 0) ? 0 + : mul(j, 14) << 24 + | mul(j, 9) << 16 + | mul(j, 13) << 8 + | mul(j, 11); + } + } + + /** Trivial 0-arguments constructor. */ + public Square() + { + super(Registry.SQUARE_CIPHER, DEFAULT_BLOCK_SIZE, DEFAULT_KEY_SIZE); + } + + private static void square(byte[] in, int i, byte[] out, int j, int[][] K, + int[] T, byte[] S) + { + int a = ((in[i++]) << 24 + | (in[i++] & 0xFF) << 16 + | (in[i++] & 0xFF) << 8 + | (in[i++] & 0xFF) ) ^ K[0][0]; + int b = ((in[i++]) << 24 + | (in[i++] & 0xFF) << 16 + | (in[i++] & 0xFF) << 8 + | (in[i++] & 0xFF) ) ^ K[0][1]; + int c = ((in[i++]) << 24 + | (in[i++] & 0xFF) << 16 + | (in[i++] & 0xFF) << 8 + | (in[i++] & 0xFF) ) ^ K[0][2]; + int d = ((in[i++]) << 24 + | (in[i++] & 0xFF) << 16 + | (in[i++] & 0xFF) << 8 + | (in[i ] & 0xFF) ) ^ K[0][3]; + int r, aa, bb, cc, dd; + for (r = 1; r < ROUNDS; r++) + { // R - 1 full rounds + aa = T[(a >>> 24) ] + ^ rot32R(T[(b >>> 24) ], 8) + ^ rot32R(T[(c >>> 24) ], 16) + ^ rot32R(T[(d >>> 24) ], 24) ^ K[r][0]; + bb = T[(a >>> 16) & 0xFF] + ^ rot32R(T[(b >>> 16) & 0xFF], 8) + ^ rot32R(T[(c >>> 16) & 0xFF], 16) + ^ rot32R(T[(d >>> 16) & 0xFF], 24) ^ K[r][1]; + cc = T[(a >>> 8) & 0xFF] + ^ rot32R(T[(b >>> 8) & 0xFF], 8) + ^ rot32R(T[(c >>> 8) & 0xFF], 16) + ^ rot32R(T[(d >>> 8) & 0xFF], 24) ^ K[r][2]; + dd = T[ a & 0xFF] + ^ rot32R(T[ b & 0xFF], 8) + ^ rot32R(T[ c & 0xFF], 16) + ^ rot32R(T[ d & 0xFF], 24) ^ K[r][3]; + a = aa; + b = bb; + c = cc; + d = dd; + } + // last round (diffusion becomes only transposition) + aa = ((S[(a >>> 24) ] ) << 24 + | (S[(b >>> 24) ] & 0xFF) << 16 + | (S[(c >>> 24) ] & 0xFF) << 8 + | (S[(d >>> 24) ] & 0xFF) ) ^ K[r][0]; + bb = ((S[(a >>> 16) & 0xFF] ) << 24 + | (S[(b >>> 16) & 0xFF] & 0xFF) << 16 + | (S[(c >>> 16) & 0xFF] & 0xFF) << 8 + | (S[(d >>> 16) & 0xFF] & 0xFF) ) ^ K[r][1]; + cc = ((S[(a >>> 8) & 0xFF] ) << 24 + | (S[(b >>> 8) & 0xFF] & 0xFF) << 16 + | (S[(c >>> 8) & 0xFF] & 0xFF) << 8 + | (S[(d >>> 8) & 0xFF] & 0xFF) ) ^ K[r][2]; + dd = ((S[ a & 0xFF] ) << 24 + | (S[ b & 0xFF] & 0xFF) << 16 + | (S[ c & 0xFF] & 0xFF) << 8 + | (S[ d & 0xFF] & 0xFF) ) ^ K[r][3]; + out[j++] = (byte)(aa >>> 24); + out[j++] = (byte)(aa >>> 16); + out[j++] = (byte)(aa >>> 8); + out[j++] = (byte) aa; + out[j++] = (byte)(bb >>> 24); + out[j++] = (byte)(bb >>> 16); + out[j++] = (byte)(bb >>> 8); + out[j++] = (byte) bb; + out[j++] = (byte)(cc >>> 24); + out[j++] = (byte)(cc >>> 16); + out[j++] = (byte)(cc >>> 8); + out[j++] = (byte) cc; + out[j++] = (byte)(dd >>> 24); + out[j++] = (byte)(dd >>> 16); + out[j++] = (byte)(dd >>> 8); + out[j ] = (byte) dd; + } + + /** + * Applies the Theta function to an input <i>in</i> in order to produce in + * <i>out</i> an internal session sub-key. + * <p> + * Both <i>in</i> and <i>out</i> are arrays of four ints. + * <p> + * Pseudo-code is: + * <pre> + * for (i = 0; i < 4; i++) + * { + * out[i] = 0; + * for (j = 0, n = 24; j < 4; j++, n -= 8) + * { + * k = mul(in[i] >>> 24, G[0][j]) ˆ mul(in[i] >>> 16, G[1][j]) + * ˆ mul(in[i] >>> 8, G[2][j]) ˆ mul(in[i], G[3][j]); + * out[i] ˆ= k << n; + * } + * } + * </pre> + */ + private static void transform(int[] in, int[] out) + { + int l3, l2, l1, l0, m; + for (int i = 0; i < 4; i++) + { + l3 = in[i]; + l2 = l3 >>> 8; + l1 = l3 >>> 16; + l0 = l3 >>> 24; + m = ((mul(l0, 2) ^ mul(l1, 3) ^ l2 ^ l3) & 0xFF) << 24; + m ^= ((l0 ^ mul(l1, 2) ^ mul(l2, 3) ^ l3) & 0xFF) << 16; + m ^= ((l0 ^ l1 ^ mul(l2, 2) ^ mul(l3, 3)) & 0xFF) << 8; + m ^= ((mul(l0, 3) ^ l1 ^ l2 ^ mul(l3, 2)) & 0xFF); + out[i] = m; + } + } + + /** + * Left rotate a 32-bit chunk. + * + * @param x the 32-bit data to rotate + * @param s number of places to left-rotate by + * @return the newly permutated value. + */ + private static int rot32L(int x, int s) + { + return x << s | x >>> (32 - s); + } + + /** + * Right rotate a 32-bit chunk. + * + * @param x the 32-bit data to rotate + * @param s number of places to right-rotate by + * @return the newly permutated value. + */ + private static int rot32R(int x, int s) + { + return x >>> s | x << (32 - s); + } + + /** + * Returns the product of two binary numbers a and b, using the generator ROOT + * as the modulus: p = (a * b) mod ROOT. ROOT Generates a suitable Galois + * Field in GF(2**8). + * <p> + * For best performance call it with abs(b) < abs(a). + * + * @param a operand for multiply. + * @param b operand for multiply. + * @return the result of (a * b) % ROOT. + */ + private static final int mul(int a, int b) + { + if (a == 0) + return 0; + a &= 0xFF; + b &= 0xFF; + int result = 0; + while (b != 0) + { + if ((b & 0x01) != 0) + result ^= a; + b >>>= 1; + a <<= 1; + if (a > 0xFF) + a ^= ROOT; + } + return result & 0xFF; + } + + public Object clone() + { + Square result = new Square(); + result.currentBlockSize = this.currentBlockSize; + + return result; + } + + public Iterator blockSizes() + { + ArrayList al = new ArrayList(); + al.add(Integer.valueOf(DEFAULT_BLOCK_SIZE)); + + return Collections.unmodifiableList(al).iterator(); + } + + public Iterator keySizes() + { + ArrayList al = new ArrayList(); + al.add(Integer.valueOf(DEFAULT_KEY_SIZE)); + + return Collections.unmodifiableList(al).iterator(); + } + + public Object makeKey(byte[] uk, int bs) throws InvalidKeyException + { + if (bs != DEFAULT_BLOCK_SIZE) + throw new IllegalArgumentException(); + if (uk == null) + throw new InvalidKeyException("Empty key"); + if (uk.length != DEFAULT_KEY_SIZE) + throw new InvalidKeyException("Key is not 128-bit."); + int[][] Ke = new int[ROUNDS + 1][4]; + int[][] Kd = new int[ROUNDS + 1][4]; + int[][] tK = new int[ROUNDS + 1][4]; + int i = 0; + Ke[0][0] = (uk[i++] & 0xFF) << 24 + | (uk[i++] & 0xFF) << 16 + | (uk[i++] & 0xFF) << 8 + | (uk[i++] & 0xFF); + tK[0][0] = Ke[0][0]; + Ke[0][1] = (uk[i++] & 0xFF) << 24 + | (uk[i++] & 0xFF) << 16 + | (uk[i++] & 0xFF) << 8 + | (uk[i++] & 0xFF); + tK[0][1] = Ke[0][1]; + Ke[0][2] = (uk[i++] & 0xFF) << 24 + | (uk[i++] & 0xFF) << 16 + | (uk[i++] & 0xFF) << 8 + | (uk[i++] & 0xFF); + tK[0][2] = Ke[0][2]; + Ke[0][3] = (uk[i++] & 0xFF) << 24 + | (uk[i++] & 0xFF) << 16 + | (uk[i++] & 0xFF) << 8 + | (uk[i ] & 0xFF); + tK[0][3] = Ke[0][3]; + int j; + for (i = 1, j = 0; i < ROUNDS + 1; i++, j++) + { + tK[i][0] = tK[j][0] ^ rot32L(tK[j][3], 8) ^ OFFSET[j]; + tK[i][1] = tK[j][1] ^ tK[i][0]; + tK[i][2] = tK[j][2] ^ tK[i][1]; + tK[i][3] = tK[j][3] ^ tK[i][2]; + System.arraycopy(tK[i], 0, Ke[i], 0, 4); + transform(Ke[j], Ke[j]); + } + for (i = 0; i < ROUNDS; i++) + System.arraycopy(tK[ROUNDS - i], 0, Kd[i], 0, 4); + transform(tK[0], Kd[ROUNDS]); + return new Object[] { Ke, Kd }; + } + + public void encrypt(byte[] in, int i, byte[] out, int j, Object k, int bs) + { + if (bs != DEFAULT_BLOCK_SIZE) + throw new IllegalArgumentException(); + int[][] K = (int[][])((Object[]) k)[0]; + square(in, i, out, j, K, Te, Se); + } + + public void decrypt(byte[] in, int i, byte[] out, int j, Object k, int bs) + { + if (bs != DEFAULT_BLOCK_SIZE) + throw new IllegalArgumentException(); + int[][] K = (int[][])((Object[]) k)[1]; + square(in, i, out, j, K, Td, Sd); + } + + public boolean selfTest() + { + if (valid == null) + { + boolean result = super.selfTest(); // do symmetry tests + if (result) + result = testKat(KAT_KEY, KAT_CT); + valid = Boolean.valueOf(result); + } + return valid.booleanValue(); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/cipher/TripleDES.java b/libjava/classpath/gnu/javax/crypto/cipher/TripleDES.java new file mode 100644 index 000000000..1d684c20a --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/cipher/TripleDES.java @@ -0,0 +1,257 @@ +/* TripleDES.java -- + Copyright (C) 2002, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.cipher; + +import gnu.java.security.Registry; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Iterator; +import java.security.InvalidKeyException; + +/** + * Triple-DES, 3DES, or DESede is a <i>combined cipher</i> that uses three + * iterations of the Data Encryption Standard cipher to theoretically improve + * the security of plain DES, at the cost of speed. + * <p> + * Triple-DES runs the DES algorithm three times with one, two or three + * independent 56-bit (DES) keys. When used with one DES key, the cipher behaves + * exactly like a (slower) DES. + * <p> + * To encrypt: + * <blockquote><i>C<sub>i</sub> = E<sub>k3</sub> ( E<sub>k2</sub><sup>-1</sup> ( + * E<sub>k1</sub> ( P<sub>i</sub> )))</i> + * </blockquote> + * <p> + * And to decrypt: + * <blockquote><i>P<sub>i</sub> = E<sub>k1</sub><sup>-1</sup> ( + * E<sub>k2</sub> ( E<sub>k3</sub><sup>-1</sup> ( C<sub>i</sub> )))</i> + * </blockquote> + * <p> + * (The "ede" comes from the encryption operation, which runs + * Encrypt-Decrypt-Encrypt) + * <p> + * References: + * <ol> + * <li>Bruce Schneier, <i>Applied Cryptography: Protocols, Algorithms, and + * Source Code in C, Second Edition</i>. (1996 John Wiley and Sons) ISBN + * 0-471-11709-9. Page 294--295.</li> + * </ol> + */ +public class TripleDES + extends BaseCipher +{ + /** Triple-DES only operates on 64 bit blocks. */ + public static final int BLOCK_SIZE = 8; + /** By default, Triple-DES uses 168 bits of a parity-adjusted 192 bit key. */ + public static final int KEY_SIZE = 24; + /** The underlying DES instance. */ + private DES des; + + /** + * Default 0-arguments constructor. + */ + public TripleDES() + { + super(Registry.TRIPLEDES_CIPHER, BLOCK_SIZE, KEY_SIZE); + des = new DES(); + } + + /** + * Convenience method which calls the method with same name and three + * arguments, passing <code>3</code> as the value of the first parameter. + * + * @param kb The key bytes to adjust. + * @param offset The starting offset into the key bytes. + */ + public static void adjustParity(byte[] kb, int offset) + { + adjustParity(3, kb, offset); + } + + /** + * Adjusts, in-situ, the parity of the designated bytes, so they can be used + * as DES keys for a 3-DES 1-, 2- or 3-key cipher. + * + * @param keyCount the number of independent DES keys. Can be either + * <code>1</code>, <code>2</code> or <code>3</code>. Any other value + * will cause an {@link IllegalArgumentException} to be raised. + * @param kb the array containing the key bytes to adjust. MUST have at least + * <code>8 * keyCount</code> bytes starting at offset position + * <code>offset</code>, otherwise an + * {@link ArrayIndexOutOfBoundsException} will be raised. + * @param offset the starting offset into the array. + * @see DES#adjustParity(byte[],int) + */ + public static void adjustParity(int keyCount, byte[] kb, int offset) + { + if (keyCount < 1 || keyCount > 3) + throw new IllegalArgumentException("Invalid keyCount value: " + keyCount); + DES.adjustParity(kb, offset); + if (keyCount > 1) + DES.adjustParity(kb, offset + 8); + if (keyCount > 2) + DES.adjustParity(kb, offset + 16); + } + + /** + * Convenience method which calls the method with same name and three + * arguments, passing <code>3</code> as the value of the first parameter. + * + * @param kb The key bytes to test. + * @param offset The starting offset into the key bytes. + * @return <code>true</code> if the bytes in <i>kb</i> starting at + * <i>offset</i> are parity adjusted. + * @see DES#isParityAdjusted(byte[],int) + * @see #adjustParity(byte[],int) + */ + public static boolean isParityAdjusted(byte[] kb, int offset) + { + return isParityAdjusted(3, kb, offset); + } + + /** + * Tests if enough bytes, expected to be used as DES keys for a 3-DES 1-, 2- + * or 3-key cipher, located in a designated byte array, has already been + * parity adjusted. + * + * @param keyCount the number of independent DES keys. Can be either + * <code>1</code>, <code>2</code> or <code>3</code>. Any other value + * will cause an {@link IllegalArgumentException} to be raised. + * @param kb the array containing the key bytes to test. MUST have at least + * <code>8 * keyCount</code> bytes starting at offset position + * <code>offset</code>, otherwise an + * {@link ArrayIndexOutOfBoundsException} will be raised. + * @param offset the starting offset into the array. + * @return <code>true</code> if the bytes in <i>kb</i> starting at + * <i>offset</i> are parity adjusted. + * @see DES#isParityAdjusted(byte[],int) + * @see #adjustParity(int,byte[],int) + */ + public static boolean isParityAdjusted(int keyCount, byte[] kb, int offset) + { + if (keyCount < 1 || keyCount > 3) + throw new IllegalArgumentException("Invalid keyCount value: " + keyCount); + boolean result = DES.isParityAdjusted(kb, offset); + if (keyCount > 1) + result = result && DES.isParityAdjusted(kb, offset + 8); + if (keyCount > 2) + result = result && DES.isParityAdjusted(kb, offset + 16); + return result; + } + + public Object clone() + { + return new TripleDES(); + } + + public Iterator blockSizes() + { + return Collections.singleton(Integer.valueOf(BLOCK_SIZE)).iterator(); + } + + public Iterator keySizes() + { + ArrayList al = new ArrayList(); + al.add(Integer.valueOf(8)); + al.add(Integer.valueOf(16)); + al.add(Integer.valueOf(24)); + return Collections.unmodifiableList(al).iterator(); + } + + public Object makeKey(byte[] kb, int bs) throws InvalidKeyException + { + if (kb.length != 8 && kb.length != 16 && kb.length != 24) + throw new InvalidKeyException("TripleDES key must be 8, 16 or 24 bytes: " + + kb.length); + Context ctx = new Context(); + byte[] k1 = new byte[DES.KEY_SIZE]; + System.arraycopy(kb, 0, k1, 0, DES.KEY_SIZE); + if (! DES.isParityAdjusted(k1, 0)) + DES.adjustParity(k1, 0); + ctx.k1 = (DES.Context) des.makeKey(k1, bs); + + if (kb.length == 8) + { + ctx.k2 = (DES.Context) des.makeKey(k1, bs); + ctx.k3 = (DES.Context) des.makeKey(k1, bs); + } + else + { + byte[] k2 = new byte[DES.KEY_SIZE]; + System.arraycopy(kb, DES.KEY_SIZE, k2, 0, DES.KEY_SIZE); + if (! DES.isParityAdjusted(k2, 0)) + DES.adjustParity(k2, 0); + ctx.k2 = (DES.Context) des.makeKey(k2, bs); + + byte[] k3 = new byte[DES.KEY_SIZE]; + if (kb.length == 16) + ctx.k3 = (DES.Context) des.makeKey(k1, bs); + else + { + System.arraycopy(kb, 2 * DES.KEY_SIZE, k3, 0, DES.KEY_SIZE); + if (! DES.isParityAdjusted(k3, 0)) + DES.adjustParity(k3, 0); + ctx.k3 = (DES.Context) des.makeKey(k3, bs); + } + } + return ctx; + } + + public void encrypt(byte[] in, int i, byte[] out, int o, Object K, int bs) + { + byte[] temp = new byte[BLOCK_SIZE]; + des.encrypt(in, i, temp, 0, ((Context) K).k1, bs); + des.decrypt(temp, 0, temp, 0, ((Context) K).k2, bs); + des.encrypt(temp, 0, out, o, ((Context) K).k3, bs); + } + + public void decrypt(byte[] in, int i, byte[] out, int o, Object K, int bs) + { + byte[] temp = new byte[BLOCK_SIZE]; + des.decrypt(in, i, temp, 0, ((Context) K).k3, bs); + des.encrypt(temp, 0, temp, 0, ((Context) K).k2, bs); + des.decrypt(temp, 0, out, o, ((Context) K).k1, bs); + } + + private final class Context + { + DES.Context k1, k2, k3; + } +} diff --git a/libjava/classpath/gnu/javax/crypto/cipher/Twofish.java b/libjava/classpath/gnu/javax/crypto/cipher/Twofish.java new file mode 100644 index 000000000..c9789a699 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/cipher/Twofish.java @@ -0,0 +1,737 @@ +/* Twofish.java -- + Copyright (C) 2001, 2002, 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.cipher; + +import gnu.java.security.Configuration; +import gnu.java.security.Registry; +import gnu.java.security.util.Util; + +import java.security.InvalidKeyException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Iterator; +import java.util.logging.Logger; + +/** + * Twofish is a balanced 128-bit Feistel cipher, consisting of 16 rounds. In + * each round, a 64-bit S-box value is computed from 64 bits of the block, and + * this value is xored into the other half of the block. The two half-blocks are + * then exchanged, and the next round begins. Before the first round, all input + * bits are xored with key-dependent "whitening" subkeys, and after the final + * round the output bits are xored with other key-dependent whitening subkeys; + * these subkeys are not used anywhere else in the algorithm. + * <p> + * Twofish is designed by Bruce Schneier, Doug Whiting, John Kelsey, Chris + * Hall, David Wagner and Niels Ferguson. + * <p> + * References: + * <ol> + * <li><a href="http://www.counterpane.com/twofish-paper.html">Twofish: A + * 128-bit Block Cipher</a>.</li> + * </ol> + */ +public final class Twofish + extends BaseCipher +{ + private static final Logger log = Logger.getLogger(Twofish.class.getName()); + private static final int DEFAULT_BLOCK_SIZE = 16; // in bytes + private static final int DEFAULT_KEY_SIZE = 16; // in bytes + private static final int MAX_ROUNDS = 16; // max # rounds (for allocating subkeys) + private static final int ROUNDS = MAX_ROUNDS; + // subkey array indices + private static final int INPUT_WHITEN = 0; + private static final int OUTPUT_WHITEN = INPUT_WHITEN + DEFAULT_BLOCK_SIZE / 4; + private static final int ROUND_SUBKEYS = OUTPUT_WHITEN + DEFAULT_BLOCK_SIZE / 4; + private static final int SK_STEP = 0x02020202; + private static final int SK_BUMP = 0x01010101; + private static final int SK_ROTL = 9; + private static final String[] Pm = new String[] { + // p0 + "\uA967\uB3E8\u04FD\uA376\u9A92\u8078\uE4DD\uD138" + + "\u0DC6\u3598\u18F7\uEC6C\u4375\u3726\uFA13\u9448" + + "\uF2D0\u8B30\u8454\uDF23\u195B\u3D59\uF3AE\uA282" + + "\u6301\u832E\uD951\u9B7C\uA6EB\uA5BE\u160C\uE361" + + "\uC08C\u3AF5\u732C\u250B\uBB4E\u896B\u536A\uB4F1" + + "\uE1E6\uBD45\uE2F4\uB666\uCC95\u0356\uD41C\u1ED7" + + "\uFBC3\u8EB5\uE9CF\uBFBA\uEA77\u39AF\u33C9\u6271" + + "\u8179\u09AD\u24CD\uF9D8\uE5C5\uB94D\u4408\u86E7" + + "\uA11D\uAAED\u0670\uB2D2\u417B\uA011\u31C2\u2790" + + "\u20F6\u60FF\u965C\uB1AB\u9E9C\u521B\u5F93\u0AEF" + + "\u9185\u49EE\u2D4F\u8F3B\u4787\u6D46\uD63E\u6964" + + "\u2ACE\uCB2F\uFC97\u057A\uAC7F\uD51A\u4B0E\uA75A" + + "\u2814\u3F29\u883C\u4C02\uB8DA\uB017\u551F\u8A7D" + + "\u57C7\u8D74\uB7C4\u9F72\u7E15\u2212\u5807\u9934" + + "\u6E50\uDE68\u65BC\uDBF8\uC8A8\u2B40\uDCFE\u32A4" + + "\uCA10\u21F0\uD35D\u0F00\u6F9D\u3642\u4A5E\uC1E0", + // p1 + "\u75F3\uC6F4\uDB7B\uFBC8\u4AD3\uE66B\u457D\uE84B" + + "\uD632\uD8FD\u3771\uF1E1\u300F\uF81B\u87FA\u063F" + + "\u5EBA\uAE5B\u8A00\uBC9D\u6DC1\uB10E\u805D\uD2D5" + + "\uA084\u0714\uB590\u2CA3\uB273\u4C54\u9274\u3651" + + "\u38B0\uBD5A\uFC60\u6296\u6C42\uF710\u7C28\u278C" + + "\u1395\u9CC7\u2446\u3B70\uCAE3\u85CB\u11D0\u93B8" + + "\uA683\u20FF\u9F77\uC3CC\u036F\u08BF\u40E7\u2BE2" + + "\u790C\uAA82\u413A\uEAB9\uE49A\uA497\u7EDA\u7A17" + + "\u6694\uA11D\u3DF0\uDEB3\u0B72\uA71C\uEFD1\u533E" + + "\u8F33\u265F\uEC76\u2A49\u8188\uEE21\uC41A\uEBD9" + + "\uC539\u99CD\uAD31\u8B01\u1823\uDD1F\u4E2D\uF948" + + "\u4FF2\u658E\u785C\u5819\u8DE5\u9857\u677F\u0564" + + "\uAF63\uB6FE\uF5B7\u3CA5\uCEE9\u6844\uE04D\u4369" + + "\u292E\uAC15\u59A8\u0A9E\u6E47\uDF34\u356A\uCFDC" + + "\u22C9\uC09B\u89D4\uEDAB\u12A2\u0D52\uBB02\u2FA9" + + "\uD761\u1EB4\u5004\uF6C2\u1625\u8656\u5509\uBE91" }; + /** Fixed 8x8 permutation S-boxes */ + private static final byte[][] P = new byte[2][256]; // blank final + /** + * Define the fixed p0/p1 permutations used in keyed S-box lookup. By + * changing the following constant definitions, the S-boxes will + * automatically get changed in the Twofish engine. + */ + private static final int P_00 = 1; + private static final int P_01 = 0; + private static final int P_02 = 0; + private static final int P_03 = P_01 ^ 1; + private static final int P_04 = 1; + private static final int P_10 = 0; + private static final int P_11 = 0; + private static final int P_12 = 1; + private static final int P_13 = P_11 ^ 1; + private static final int P_14 = 0; + private static final int P_20 = 1; + private static final int P_21 = 1; + private static final int P_22 = 0; + private static final int P_23 = P_21 ^ 1; + private static final int P_24 = 0; + private static final int P_30 = 0; + private static final int P_31 = 1; + private static final int P_32 = 1; + private static final int P_33 = P_31 ^ 1; + private static final int P_34 = 1; + /** Primitive polynomial for GF(256) */ + private static final int GF256_FDBK_2 = 0x169 / 2; + private static final int GF256_FDBK_4 = 0x169 / 4; + /** MDS matrix */ + private static final int[][] MDS = new int[4][256]; // blank final + private static final int RS_GF_FDBK = 0x14D; // field generator + /** + * KAT vector (from ecb_vk): + * I=183 + * KEY=0000000000000000000000000000000000000000000002000000000000000000 + * CT=F51410475B33FBD3DB2117B5C17C82D4 + */ + private static final byte[] KAT_KEY = Util.toBytesFromString( + "0000000000000000000000000000000000000000000002000000000000000000"); + private static final byte[] KAT_CT = + Util.toBytesFromString("F51410475B33FBD3DB2117B5C17C82D4"); + /** caches the result of the correctness test, once executed. */ + private static Boolean valid; + static + { + long time = System.currentTimeMillis(); + // expand the P arrays + int i; + char c; + for (i = 0; i < 256; i++) + { + c = Pm[0].charAt(i >>> 1); + P[0][i] = (byte)((i & 1) == 0 ? c >>> 8 : c); + c = Pm[1].charAt(i >>> 1); + P[1][i] = (byte)((i & 1) == 0 ? c >>> 8 : c); + } + // precompute the MDS matrix + int[] m1 = new int[2]; + int[] mX = new int[2]; + int[] mY = new int[2]; + int j; + for (i = 0; i < 256; i++) + { + j = P[0][i] & 0xFF; // compute all the matrix elements + m1[0] = j; + mX[0] = Mx_X(j) & 0xFF; + mY[0] = Mx_Y(j) & 0xFF; + j = P[1][i] & 0xFF; + m1[1] = j; + mX[1] = Mx_X(j) & 0xFF; + mY[1] = Mx_Y(j) & 0xFF; + MDS[0][i] = m1[P_00] << 0 + | mX[P_00] << 8 + | mY[P_00] << 16 + | mY[P_00] << 24; + MDS[1][i] = mY[P_10] << 0 + | mY[P_10] << 8 + | mX[P_10] << 16 + | m1[P_10] << 24; + MDS[2][i] = mX[P_20] << 0 + | mY[P_20] << 8 + | m1[P_20] << 16 + | mY[P_20] << 24; + MDS[3][i] = mX[P_30] << 0 + | m1[P_30] << 8 + | mY[P_30] << 16 + | mX[P_30] << 24; + } + time = System.currentTimeMillis() - time; + if (Configuration.DEBUG) + { + log.fine("Static Data"); + log.fine("MDS[0][]:"); + StringBuilder sb; + for (i = 0; i < 64; i++) + { + sb = new StringBuilder(); + for (j = 0; j < 4; j++) + sb.append("0x").append(Util.toString(MDS[0][i * 4 + j])).append(", "); + log.fine(sb.toString()); + } + log.fine("MDS[1][]:"); + for (i = 0; i < 64; i++) + { + sb = new StringBuilder(); + for (j = 0; j < 4; j++) + sb.append("0x").append(Util.toString(MDS[1][i * 4 + j])).append(", "); + log.fine(sb.toString()); + } + log.fine("MDS[2][]:"); + for (i = 0; i < 64; i++) + { + sb = new StringBuilder(); + for (j = 0; j < 4; j++) + sb.append("0x").append(Util.toString(MDS[2][i * 4 + j])).append(", "); + log.fine(sb.toString()); + } + log.fine("MDS[3][]:"); + for (i = 0; i < 64; i++) + { + sb = new StringBuilder(); + for (j = 0; j < 4; j++) + sb.append("0x").append(Util.toString(MDS[3][i * 4 + j])).append(", "); + log.fine(sb.toString()); + } + log.fine("Total initialization time: " + time + " ms."); + } + } + + private static final int LFSR1(int x) + { + return (x >> 1) ^ ((x & 0x01) != 0 ? GF256_FDBK_2 : 0); + } + + private static final int LFSR2(int x) + { + return (x >> 2) + ^ ((x & 0x02) != 0 ? GF256_FDBK_2 : 0) + ^ ((x & 0x01) != 0 ? GF256_FDBK_4 : 0); + } + + private static final int Mx_X(int x) + { // 5B + return x ^ LFSR2(x); + } + + private static final int Mx_Y(int x) + { // EF + return x ^ LFSR1(x) ^ LFSR2(x); + } + + /** Trivial 0-arguments constructor. */ + public Twofish() + { + super(Registry.TWOFISH_CIPHER, DEFAULT_BLOCK_SIZE, DEFAULT_KEY_SIZE); + } + + private static final int b0(int x) + { + return x & 0xFF; + } + + private static final int b1(int x) + { + return (x >>> 8) & 0xFF; + } + + private static final int b2(int x) + { + return (x >>> 16) & 0xFF; + } + + private static final int b3(int x) + { + return (x >>> 24) & 0xFF; + } + + /** + * Use (12, 8) Reed-Solomon code over GF(256) to produce a key S-box 32-bit + * entity from two key material 32-bit entities. + * + * @param k0 1st 32-bit entity. + * @param k1 2nd 32-bit entity. + * @return remainder polynomial generated using RS code + */ + private static final int RS_MDS_Encode(int k0, int k1) + { + int r = k1; + int i; + for (i = 0; i < 4; i++) // shift 1 byte at a time + r = RS_rem(r); + r ^= k0; + for (i = 0; i < 4; i++) + r = RS_rem(r); + return r; + } + + /** + * Reed-Solomon code parameters: (12, 8) reversible code:<p> + * <pre> + * g(x) = x**4 + (a + 1/a) x**3 + a x**2 + (a + 1/a) x + 1 + * </pre> + * where a = primitive root of field generator 0x14D + */ + private static final int RS_rem(int x) + { + int b = (x >>> 24) & 0xFF; + int g2 = ((b << 1) ^ ((b & 0x80) != 0 ? RS_GF_FDBK : 0)) & 0xFF; + int g3 = (b >>> 1) ^ ((b & 0x01) != 0 ? (RS_GF_FDBK >>> 1) : 0) ^ g2; + int result = (x << 8) ^ (g3 << 24) ^ (g2 << 16) ^ (g3 << 8) ^ b; + return result; + } + + private static final int F32(int k64Cnt, int x, int[] k32) + { + int b0 = b0(x); + int b1 = b1(x); + int b2 = b2(x); + int b3 = b3(x); + int k0 = k32[0]; + int k1 = k32[1]; + int k2 = k32[2]; + int k3 = k32[3]; + int result = 0; + switch (k64Cnt & 3) + { + case 1: + result = MDS[0][(P[P_01][b0] & 0xFF) ^ b0(k0)] + ^ MDS[1][(P[P_11][b1] & 0xFF) ^ b1(k0)] + ^ MDS[2][(P[P_21][b2] & 0xFF) ^ b2(k0)] + ^ MDS[3][(P[P_31][b3] & 0xFF) ^ b3(k0)]; + break; + case 0: // same as 4 + b0 = (P[P_04][b0] & 0xFF) ^ b0(k3); + b1 = (P[P_14][b1] & 0xFF) ^ b1(k3); + b2 = (P[P_24][b2] & 0xFF) ^ b2(k3); + b3 = (P[P_34][b3] & 0xFF) ^ b3(k3); + case 3: + b0 = (P[P_03][b0] & 0xFF) ^ b0(k2); + b1 = (P[P_13][b1] & 0xFF) ^ b1(k2); + b2 = (P[P_23][b2] & 0xFF) ^ b2(k2); + b3 = (P[P_33][b3] & 0xFF) ^ b3(k2); + case 2: // 128-bit keys (optimize for this case) + result = MDS[0][(P[P_01][(P[P_02][b0] & 0xFF) ^ b0(k1)] & 0xFF) ^ b0(k0)] + ^ MDS[1][(P[P_11][(P[P_12][b1] & 0xFF) ^ b1(k1)] & 0xFF) ^ b1(k0)] + ^ MDS[2][(P[P_21][(P[P_22][b2] & 0xFF) ^ b2(k1)] & 0xFF) ^ b2(k0)] + ^ MDS[3][(P[P_31][(P[P_32][b3] & 0xFF) ^ b3(k1)] & 0xFF) ^ b3(k0)]; + break; + } + return result; + } + + private static final int Fe32(int[] sBox, int x, int R) + { + return sBox[ 2 * _b(x, R ) ] + ^ sBox[ 2 * _b(x, R + 1) + 1] + ^ sBox[0x200 + 2 * _b(x, R + 2) ] + ^ sBox[0x200 + 2 * _b(x, R + 3) + 1]; + } + + private static final int _b(int x, int N) + { + switch (N % 4) + { + case 0: + return x & 0xFF; + case 1: + return (x >>> 8) & 0xFF; + case 2: + return (x >>> 16) & 0xFF; + default: + return x >>> 24; + } + } + + public Object clone() + { + Twofish result = new Twofish(); + result.currentBlockSize = this.currentBlockSize; + return result; + } + + public Iterator blockSizes() + { + ArrayList al = new ArrayList(); + al.add(Integer.valueOf(DEFAULT_BLOCK_SIZE)); + return Collections.unmodifiableList(al).iterator(); + } + + public Iterator keySizes() + { + ArrayList al = new ArrayList(); + al.add(Integer.valueOf(8)); // 64-bit + al.add(Integer.valueOf(16)); // 128-bit + al.add(Integer.valueOf(24)); // 192-bit + al.add(Integer.valueOf(32)); // 256-bit + return Collections.unmodifiableList(al).iterator(); + } + + /** + * Expands a user-supplied key material into a session key for a designated + * <i>block size</i>. + * + * @param k the 64/128/192/256-bit user-key to use. + * @param bs the desired block size in bytes. + * @return an Object encapsulating the session key. + * @exception IllegalArgumentException if the block size is not 16 (128-bit). + * @exception InvalidKeyException if the key data is invalid. + */ + public Object makeKey(byte[] k, int bs) throws InvalidKeyException + { + if (bs != DEFAULT_BLOCK_SIZE) + throw new IllegalArgumentException(); + if (k == null) + throw new InvalidKeyException("Empty key"); + int length = k.length; + if (! (length == 8 || length == 16 || length == 24 || length == 32)) + throw new InvalidKeyException("Incorrect key length"); + int k64Cnt = length / 8; + int subkeyCnt = ROUND_SUBKEYS + 2 * ROUNDS; + int[] k32e = new int[4]; // even 32-bit entities + int[] k32o = new int[4]; // odd 32-bit entities + int[] sBoxKey = new int[4]; + // split user key material into even and odd 32-bit entities and + // compute S-box keys using (12, 8) Reed-Solomon code over GF(256) + int i, j, offset = 0; + for (i = 0, j = k64Cnt - 1; i < 4 && offset < length; i++, j--) + { + k32e[i] = (k[offset++] & 0xFF) + | (k[offset++] & 0xFF) << 8 + | (k[offset++] & 0xFF) << 16 + | (k[offset++] & 0xFF) << 24; + k32o[i] = (k[offset++] & 0xFF) + | (k[offset++] & 0xFF) << 8 + | (k[offset++] & 0xFF) << 16 + | (k[offset++] & 0xFF) << 24; + sBoxKey[j] = RS_MDS_Encode(k32e[i], k32o[i]); // reverse order + } + // compute the round decryption subkeys for PHT. these same subkeys + // will be used in encryption but will be applied in reverse order. + int q, A, B; + int[] subKeys = new int[subkeyCnt]; + for (i = q = 0; i < subkeyCnt / 2; i++, q += SK_STEP) + { + A = F32(k64Cnt, q, k32e); // A uses even key entities + B = F32(k64Cnt, q + SK_BUMP, k32o); // B uses odd key entities + B = B << 8 | B >>> 24; + A += B; + subKeys[2 * i] = A; // combine with a PHT + A += B; + subKeys[2 * i + 1] = A << SK_ROTL | A >>> (32 - SK_ROTL); + } + // fully expand the table for speed + int k0 = sBoxKey[0]; + int k1 = sBoxKey[1]; + int k2 = sBoxKey[2]; + int k3 = sBoxKey[3]; + int b0, b1, b2, b3; + int[] sBox = new int[4 * 256]; + for (i = 0; i < 256; i++) + { + b0 = b1 = b2 = b3 = i; + switch (k64Cnt & 3) + { + case 1: + sBox[ 2 * i ] = MDS[0][(P[P_01][b0] & 0xFF) ^ b0(k0)]; + sBox[ 2 * i + 1] = MDS[1][(P[P_11][b1] & 0xFF) ^ b1(k0)]; + sBox[0x200 + 2 * i ] = MDS[2][(P[P_21][b2] & 0xFF) ^ b2(k0)]; + sBox[0x200 + 2 * i + 1] = MDS[3][(P[P_31][b3] & 0xFF) ^ b3(k0)]; + break; + case 0: // same as 4 + b0 = (P[P_04][b0] & 0xFF) ^ b0(k3); + b1 = (P[P_14][b1] & 0xFF) ^ b1(k3); + b2 = (P[P_24][b2] & 0xFF) ^ b2(k3); + b3 = (P[P_34][b3] & 0xFF) ^ b3(k3); + case 3: + b0 = (P[P_03][b0] & 0xFF) ^ b0(k2); + b1 = (P[P_13][b1] & 0xFF) ^ b1(k2); + b2 = (P[P_23][b2] & 0xFF) ^ b2(k2); + b3 = (P[P_33][b3] & 0xFF) ^ b3(k2); + case 2: // 128-bit keys + sBox[ 2 * i ] = MDS[0][(P[P_01][(P[P_02][b0] & 0xFF) + ^ b0(k1)] & 0xFF) ^ b0(k0)]; + sBox[ 2 * i + 1] = MDS[1][(P[P_11][(P[P_12][b1] & 0xFF) + ^ b1(k1)] & 0xFF) ^ b1(k0)]; + sBox[0x200 + 2 * i ] = MDS[2][(P[P_21][(P[P_22][b2] & 0xFF) + ^ b2(k1)] & 0xFF) ^ b2(k0)]; + sBox[0x200 + 2 * i + 1] = MDS[3][(P[P_31][(P[P_32][b3] & 0xFF) + ^ b3(k1)] & 0xFF) ^ b3(k0)]; + } + } + if (Configuration.DEBUG) + { + StringBuilder sb; + log.fine("S-box[]:"); + for (i = 0; i < 64; i++) + { + sb = new StringBuilder(); + for (j = 0; j < 4; j++) + sb.append("0x").append(Util.toString(sBox[i * 4 + j])).append(", "); + log.fine(sb.toString()); + } + log.fine(""); + for (i = 0; i < 64; i++) + { + sb = new StringBuilder(); + for (j = 0; j < 4; j++) + sb.append("0x").append(Util.toString(sBox[256 + i * 4 + j])).append(", "); + log.fine(sb.toString()); + } + log.fine(""); + for (i = 0; i < 64; i++) + { + sb = new StringBuilder(); + for (j = 0; j < 4; j++) + sb.append("0x").append(Util.toString(sBox[512 + i * 4 + j])).append(", "); + log.fine(sb.toString()); + } + log.fine(""); + for (i = 0; i < 64; i++) + { + sb = new StringBuilder(); + for (j = 0; j < 4; j++) + sb.append("0x").append(Util.toString(sBox[768 + i * 4 + j])).append(", "); + log.fine(sb.toString()); + } + log.fine("User (odd, even) keys --> S-Box keys:"); + for (i = 0; i < k64Cnt; i++) + log.fine("0x" + Util.toString(k32o[i]) + + " 0x" + Util.toString(k32e[i]) + + " --> 0x" + Util.toString(sBoxKey[k64Cnt - 1 - i])); + log.fine("Round keys:"); + for (i = 0; i < ROUND_SUBKEYS + 2 * ROUNDS; i += 2) + log.fine("0x" + Util.toString(subKeys[i]) + + " 0x" + Util.toString(subKeys[i + 1])); + } + return new Object[] { sBox, subKeys }; + } + + public void encrypt(byte[] in, int inOffset, byte[] out, int outOffset, + Object sessionKey, int bs) + { + if (bs != DEFAULT_BLOCK_SIZE) + throw new IllegalArgumentException(); + Object[] sk = (Object[]) sessionKey; // extract S-box and session key + int[] sBox = (int[]) sk[0]; + int[] sKey = (int[]) sk[1]; + if (Configuration.DEBUG) + log.fine("PT=" + Util.toString(in, inOffset, bs)); + int x0 = (in[inOffset++] & 0xFF) + | (in[inOffset++] & 0xFF) << 8 + | (in[inOffset++] & 0xFF) << 16 + | (in[inOffset++] & 0xFF) << 24; + int x1 = (in[inOffset++] & 0xFF) + | (in[inOffset++] & 0xFF) << 8 + | (in[inOffset++] & 0xFF) << 16 + | (in[inOffset++] & 0xFF) << 24; + int x2 = (in[inOffset++] & 0xFF) + | (in[inOffset++] & 0xFF) << 8 + | (in[inOffset++] & 0xFF) << 16 + | (in[inOffset++] & 0xFF) << 24; + int x3 = (in[inOffset++] & 0xFF) + | (in[inOffset++] & 0xFF) << 8 + | (in[inOffset++] & 0xFF) << 16 + | (in[inOffset++] & 0xFF) << 24; + x0 ^= sKey[INPUT_WHITEN]; + x1 ^= sKey[INPUT_WHITEN + 1]; + x2 ^= sKey[INPUT_WHITEN + 2]; + x3 ^= sKey[INPUT_WHITEN + 3]; + if (Configuration.DEBUG) + log.fine("PTw=" + Util.toString(x0) + Util.toString(x1) + + Util.toString(x2) + Util.toString(x3)); + int t0, t1; + int k = ROUND_SUBKEYS; + for (int R = 0; R < ROUNDS; R += 2) + { + t0 = Fe32(sBox, x0, 0); + t1 = Fe32(sBox, x1, 3); + x2 ^= t0 + t1 + sKey[k++]; + x2 = x2 >>> 1 | x2 << 31; + x3 = x3 << 1 | x3 >>> 31; + x3 ^= t0 + 2 * t1 + sKey[k++]; + if (Configuration.DEBUG) + log.fine("CT" + (R) + "=" + Util.toString(x0) + Util.toString(x1) + + Util.toString(x2) + Util.toString(x3)); + t0 = Fe32(sBox, x2, 0); + t1 = Fe32(sBox, x3, 3); + x0 ^= t0 + t1 + sKey[k++]; + x0 = x0 >>> 1 | x0 << 31; + x1 = x1 << 1 | x1 >>> 31; + x1 ^= t0 + 2 * t1 + sKey[k++]; + if (Configuration.DEBUG) + log.fine("CT" + (R + 1) + "=" + Util.toString(x0) + Util.toString(x1) + + Util.toString(x2) + Util.toString(x3)); + } + x2 ^= sKey[OUTPUT_WHITEN]; + x3 ^= sKey[OUTPUT_WHITEN + 1]; + x0 ^= sKey[OUTPUT_WHITEN + 2]; + x1 ^= sKey[OUTPUT_WHITEN + 3]; + if (Configuration.DEBUG) + log.fine("CTw=" + Util.toString(x0) + Util.toString(x1) + + Util.toString(x2) + Util.toString(x3)); + out[outOffset++] = (byte) x2; + out[outOffset++] = (byte)(x2 >>> 8); + out[outOffset++] = (byte)(x2 >>> 16); + out[outOffset++] = (byte)(x2 >>> 24); + out[outOffset++] = (byte) x3; + out[outOffset++] = (byte)(x3 >>> 8); + out[outOffset++] = (byte)(x3 >>> 16); + out[outOffset++] = (byte)(x3 >>> 24); + out[outOffset++] = (byte) x0; + out[outOffset++] = (byte)(x0 >>> 8); + out[outOffset++] = (byte)(x0 >>> 16); + out[outOffset++] = (byte)(x0 >>> 24); + out[outOffset++] = (byte) x1; + out[outOffset++] = (byte)(x1 >>> 8); + out[outOffset++] = (byte)(x1 >>> 16); + out[outOffset ] = (byte)(x1 >>> 24); + if (Configuration.DEBUG) + log.fine("CT=" + Util.toString(out, outOffset - 15, 16) + "\n"); + } + + public void decrypt(byte[] in, int inOffset, byte[] out, int outOffset, + Object sessionKey, int bs) + { + if (bs != DEFAULT_BLOCK_SIZE) + throw new IllegalArgumentException(); + Object[] sk = (Object[]) sessionKey; // extract S-box and session key + int[] sBox = (int[]) sk[0]; + int[] sKey = (int[]) sk[1]; + if (Configuration.DEBUG) + log.fine("CT=" + Util.toString(in, inOffset, bs)); + int x2 = (in[inOffset++] & 0xFF) + | (in[inOffset++] & 0xFF) << 8 + | (in[inOffset++] & 0xFF) << 16 + | (in[inOffset++] & 0xFF) << 24; + int x3 = (in[inOffset++] & 0xFF) + | (in[inOffset++] & 0xFF) << 8 + | (in[inOffset++] & 0xFF) << 16 + | (in[inOffset++] & 0xFF) << 24; + int x0 = (in[inOffset++] & 0xFF) + | (in[inOffset++] & 0xFF) << 8 + | (in[inOffset++] & 0xFF) << 16 + | (in[inOffset++] & 0xFF) << 24; + int x1 = (in[inOffset++] & 0xFF) + | (in[inOffset++] & 0xFF) << 8 + | (in[inOffset++] & 0xFF) << 16 + | (in[inOffset++] & 0xFF) << 24; + x2 ^= sKey[OUTPUT_WHITEN]; + x3 ^= sKey[OUTPUT_WHITEN + 1]; + x0 ^= sKey[OUTPUT_WHITEN + 2]; + x1 ^= sKey[OUTPUT_WHITEN + 3]; + if (Configuration.DEBUG) + log.fine("CTw=" + Util.toString(x2) + Util.toString(x3) + + Util.toString(x0) + Util.toString(x1)); + int k = ROUND_SUBKEYS + 2 * ROUNDS - 1; + int t0, t1; + for (int R = 0; R < ROUNDS; R += 2) + { + t0 = Fe32(sBox, x2, 0); + t1 = Fe32(sBox, x3, 3); + x1 ^= t0 + 2 * t1 + sKey[k--]; + x1 = x1 >>> 1 | x1 << 31; + x0 = x0 << 1 | x0 >>> 31; + x0 ^= t0 + t1 + sKey[k--]; + if (Configuration.DEBUG) + log.fine("PT" + (ROUNDS - R) + "=" + Util.toString(x2) + + Util.toString(x3) + Util.toString(x0) + Util.toString(x1)); + t0 = Fe32(sBox, x0, 0); + t1 = Fe32(sBox, x1, 3); + x3 ^= t0 + 2 * t1 + sKey[k--]; + x3 = x3 >>> 1 | x3 << 31; + x2 = x2 << 1 | x2 >>> 31; + x2 ^= t0 + t1 + sKey[k--]; + if (Configuration.DEBUG) + log.fine("PT" + (ROUNDS - R - 1) + "=" + Util.toString(x2) + + Util.toString(x3) + Util.toString(x0) + Util.toString(x1)); + } + x0 ^= sKey[INPUT_WHITEN]; + x1 ^= sKey[INPUT_WHITEN + 1]; + x2 ^= sKey[INPUT_WHITEN + 2]; + x3 ^= sKey[INPUT_WHITEN + 3]; + if (Configuration.DEBUG) + log.fine("PTw=" + Util.toString(x2) + Util.toString(x3) + + Util.toString(x0) + Util.toString(x1)); + out[outOffset++] = (byte) x0; + out[outOffset++] = (byte)(x0 >>> 8); + out[outOffset++] = (byte)(x0 >>> 16); + out[outOffset++] = (byte)(x0 >>> 24); + out[outOffset++] = (byte) x1; + out[outOffset++] = (byte)(x1 >>> 8); + out[outOffset++] = (byte)(x1 >>> 16); + out[outOffset++] = (byte)(x1 >>> 24); + out[outOffset++] = (byte) x2; + out[outOffset++] = (byte)(x2 >>> 8); + out[outOffset++] = (byte)(x2 >>> 16); + out[outOffset++] = (byte)(x2 >>> 24); + out[outOffset++] = (byte) x3; + out[outOffset++] = (byte)(x3 >>> 8); + out[outOffset++] = (byte)(x3 >>> 16); + out[outOffset ] = (byte)(x3 >>> 24); + if (Configuration.DEBUG) + log.fine("PT=" + Util.toString(out, outOffset - 15, 16) + "\n"); + } + + public boolean selfTest() + { + if (valid == null) + { + boolean result = super.selfTest(); // do symmetry tests + if (result) + result = testKat(KAT_KEY, KAT_CT); + valid = Boolean.valueOf(result); + } + return valid.booleanValue(); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/cipher/WeakKeyException.java b/libjava/classpath/gnu/javax/crypto/cipher/WeakKeyException.java new file mode 100644 index 000000000..e12f899e4 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/cipher/WeakKeyException.java @@ -0,0 +1,59 @@ +/* WeakKeyException.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.cipher; + +import java.security.InvalidKeyException; + +/** + * Checked exception thrown to indicate that a weak key has been generated and + * or specified instead of a valid non-weak value. + */ +public class WeakKeyException + extends InvalidKeyException +{ + public WeakKeyException() + { + super(); + } + + public WeakKeyException(String msg) + { + super(msg); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/DiffieHellmanImpl.java b/libjava/classpath/gnu/javax/crypto/jce/DiffieHellmanImpl.java new file mode 100644 index 000000000..205b5ed57 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/DiffieHellmanImpl.java @@ -0,0 +1,171 @@ +/* DiffieHellmanImpl.java -- implementation of the Diffie-Hellman key agreement. + Copyright (C) 2005, 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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; either version 2, or (at your option) +any later version. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.jce; + +import java.math.BigInteger; +import java.security.InvalidKeyException; +import java.security.Key; +import java.security.SecureRandom; +import java.security.spec.AlgorithmParameterSpec; + +import javax.crypto.KeyAgreementSpi; +import javax.crypto.SecretKey; +import javax.crypto.ShortBufferException; +import javax.crypto.interfaces.DHPrivateKey; +import javax.crypto.interfaces.DHPublicKey; +import javax.crypto.spec.DHParameterSpec; +import javax.crypto.spec.SecretKeySpec; + +/** + * The JCE implementation of a 2-party Diffie-Hellman key agreement. + * + * @author Casey Marshall (csm@gnu.org) + */ +public final class DiffieHellmanImpl + extends KeyAgreementSpi +{ + /** The private key being used for this agreement. */ + private DHPrivateKey key; + + /** The current result. */ + private byte[] result; + + /** True if the caller told us we are done. */ + private boolean last_phase_done; + + /** Trivial default constructor. */ + public DiffieHellmanImpl() + { + super(); + + key = null; + result = null; + last_phase_done = false; + } + + protected Key engineDoPhase(Key incoming, boolean lastPhase) + throws InvalidKeyException + { + if (key == null) + throw new IllegalStateException("Not initialized"); + + if (last_phase_done) + throw new IllegalStateException("Last phase already done"); + + if (! (incoming instanceof DHPublicKey)) + throw new InvalidKeyException("Key MUST be a DHPublicKey"); + + DHPublicKey pub = (DHPublicKey) incoming; + DHParameterSpec s1 = key.getParams(); + DHParameterSpec s2 = pub.getParams(); + if (! s1.getG().equals(s2.getG()) || ! s1.getP().equals(s2.getP())) + throw new InvalidKeyException("Incompatible key"); + if (! lastPhase) + throw new IllegalArgumentException( + "This key-agreement MUST be concluded in one step only"); + BigInteger resultBI = pub.getY().modPow(key.getX(), s1.getP()); + result = resultBI.toByteArray(); + if (result[0] == 0x00) + { + byte[] buf = new byte[result.length - 1]; + System.arraycopy(result, 1, buf, 0, buf.length); + result = buf; + } + last_phase_done = true; + return null; + } + + protected byte[] engineGenerateSecret() + { + checkState(); + byte[] res = (byte[]) result.clone(); + reset(); + return res; + } + + protected int engineGenerateSecret(byte[] secret, int offset) + throws ShortBufferException + { + checkState(); + if (result.length > secret.length - offset) + throw new ShortBufferException(); + System.arraycopy(result, 0, secret, offset, result.length); + int res = result.length; + reset(); + return res; + } + + protected SecretKey engineGenerateSecret(String algorithm) + throws InvalidKeyException + { + checkState(); + byte[] s = (byte[]) result.clone(); + SecretKey res = new SecretKeySpec(s, algorithm); + reset(); + return res; + } + + protected void engineInit(Key key, SecureRandom random) + throws InvalidKeyException + { + if (! (key instanceof DHPrivateKey)) + throw new InvalidKeyException("Key MUST be a DHPrivateKey"); + this.key = (DHPrivateKey) key; + reset(); + } + + protected void engineInit(Key key, AlgorithmParameterSpec params, + SecureRandom random) + throws InvalidKeyException + { + engineInit(key, random); + } + + private void reset() + { + result = null; + last_phase_done = false; + } + + private void checkState() + { + if (result == null || ! last_phase_done) + throw new IllegalStateException("Not finished"); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/GnuCrypto.java b/libjava/classpath/gnu/javax/crypto/jce/GnuCrypto.java new file mode 100644 index 000000000..ec335b735 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/GnuCrypto.java @@ -0,0 +1,598 @@ +/* GnuCrypto.java -- + Copyright (C) 2004, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.jce; + +import gnu.java.security.Registry; +import gnu.javax.crypto.cipher.CipherFactory; +import gnu.javax.crypto.mac.MacFactory; + +import java.security.AccessController; +import java.security.PrivilegedAction; +import java.security.Provider; +import java.util.HashSet; +import java.util.Set; + +/** + * The additional GNU algorithm implementation as a Java Cryptographic Extension + * (JCE) Provider. + * + * @see java.security.Provider + */ +public final class GnuCrypto + extends Provider +{ + public GnuCrypto() + { + super(Registry.GNU_CRYPTO, 2.1, "GNU Crypto JCE Provider"); + + AccessController.doPrivileged(new PrivilegedAction() + { + public Object run() + { + // Cipher + put("Cipher.ANUBIS", + gnu.javax.crypto.jce.cipher.AnubisSpi.class.getName()); + put("Cipher.ANUBIS ImplementedIn", "Software"); + put("Cipher.ARCFOUR", + gnu.javax.crypto.jce.cipher.ARCFourSpi.class.getName()); + put("Cipher.ARCFOUR ImplementedIn", "Software"); + put("Cipher.BLOWFISH", + gnu.javax.crypto.jce.cipher.BlowfishSpi.class.getName()); + put("Cipher.BLOWFISH ImplementedIn", "Software"); + put("Cipher.DES", gnu.javax.crypto.jce.cipher.DESSpi.class.getName()); + put("Cipher.DES ImplementedIn", "Software"); + put("Cipher.KHAZAD", + gnu.javax.crypto.jce.cipher.KhazadSpi.class.getName()); + put("Cipher.KHAZAD ImplementedIn", "Software"); + put("Cipher.NULL", + gnu.javax.crypto.jce.cipher.NullCipherSpi.class.getName()); + put("Cipher.NULL ImplementedIn", "Software"); + put("Cipher.AES", + gnu.javax.crypto.jce.cipher.RijndaelSpi.class.getName()); + put("Cipher.AES ImplementedIn", "Software"); + put("Cipher.RIJNDAEL", + gnu.javax.crypto.jce.cipher.RijndaelSpi.class.getName()); + put("Cipher.RIJNDAEL ImplementedIn", "Software"); + put("Cipher.SERPENT", + gnu.javax.crypto.jce.cipher.SerpentSpi.class.getName()); + put("Cipher.SERPENT ImplementedIn", "Software"); + put("Cipher.SQUARE", + gnu.javax.crypto.jce.cipher.SquareSpi.class.getName()); + put("Cipher.SQUARE ImplementedIn", "Software"); + put("Cipher.TRIPLEDES", + gnu.javax.crypto.jce.cipher.TripleDESSpi.class.getName()); + put("Cipher.TRIPLEDES ImplementedIn", "Software"); + put("Cipher.TWOFISH", + gnu.javax.crypto.jce.cipher.TwofishSpi.class.getName()); + put("Cipher.TWOFISH ImplementedIn", "Software"); + put("Cipher.CAST5", + gnu.javax.crypto.jce.cipher.Cast5Spi.class.getName()); + put("Cipher.CAST5 ImplementedIn", "Software"); + + // PBES2 ciphers. + put("Cipher.PBEWithHMacHavalAndAES", + gnu.javax.crypto.jce.cipher.PBES2.HMacHaval.AES.class.getName()); + put("Cipher.PBEWithHMacHavalAndAnubis", + gnu.javax.crypto.jce.cipher.PBES2.HMacHaval.Anubis.class.getName()); + put("Cipher.PBEWithHMacHavalAndBlowfish", + gnu.javax.crypto.jce.cipher.PBES2.HMacHaval.Blowfish.class.getName()); + put("Cipher.PBEWithHMacHavalAndCast5", + gnu.javax.crypto.jce.cipher.PBES2.HMacHaval.Cast5.class.getName()); + put("Cipher.PBEWithHMacHavalAndDES", + gnu.javax.crypto.jce.cipher.PBES2.HMacHaval.DES.class.getName()); + put("Cipher.PBEWithHMacHavalAndKhazad", + gnu.javax.crypto.jce.cipher.PBES2.HMacHaval.Khazad.class.getName()); + put("Cipher.PBEWithHMacHavalAndSerpent", + gnu.javax.crypto.jce.cipher.PBES2.HMacHaval.Serpent.class.getName()); + put("Cipher.PBEWithHMacHavalAndSquare", + gnu.javax.crypto.jce.cipher.PBES2.HMacHaval.Square.class.getName()); + put("Cipher.PBEWithHMacHavalAndTripleDES", + gnu.javax.crypto.jce.cipher.PBES2.HMacHaval.TripleDES.class.getName()); + put("Cipher.PBEWithHMacHavalAndTwofish", + gnu.javax.crypto.jce.cipher.PBES2.HMacHaval.Twofish.class.getName()); + + put("Cipher.PBEWithHMacMD2AndAES", + gnu.javax.crypto.jce.cipher.PBES2.HMacMD2.AES.class.getName()); + put("Cipher.PBEWithHMacMD2AndAnubis", + gnu.javax.crypto.jce.cipher.PBES2.HMacMD2.Anubis.class.getName()); + put("Cipher.PBEWithHMacMD2AndBlowfish", + gnu.javax.crypto.jce.cipher.PBES2.HMacMD2.Blowfish.class.getName()); + put("Cipher.PBEWithHMacMD2AndCast5", + gnu.javax.crypto.jce.cipher.PBES2.HMacMD2.Cast5.class.getName()); + put("Cipher.PBEWithHMacMD2AndDES", + gnu.javax.crypto.jce.cipher.PBES2.HMacMD2.DES.class.getName()); + put("Cipher.PBEWithHMacMD2AndKhazad", + gnu.javax.crypto.jce.cipher.PBES2.HMacMD2.Khazad.class.getName()); + put("Cipher.PBEWithHMacMD2AndSerpent", + gnu.javax.crypto.jce.cipher.PBES2.HMacMD2.Serpent.class.getName()); + put("Cipher.PBEWithHMacMD2AndSquare", + gnu.javax.crypto.jce.cipher.PBES2.HMacMD2.Square.class.getName()); + put("Cipher.PBEWithHMacMD2AndTripleDES", + gnu.javax.crypto.jce.cipher.PBES2.HMacMD2.TripleDES.class.getName()); + put("Cipher.PBEWithHMacMD2AndTwofish", + gnu.javax.crypto.jce.cipher.PBES2.HMacMD2.Twofish.class.getName()); + + put("Cipher.PBEWithHMacMD4AndAES", + gnu.javax.crypto.jce.cipher.PBES2.HMacMD4.AES.class.getName()); + put("Cipher.PBEWithHMacMD4AndAnubis", + gnu.javax.crypto.jce.cipher.PBES2.HMacMD4.Anubis.class.getName()); + put("Cipher.PBEWithHMacMD4AndBlowfish", + gnu.javax.crypto.jce.cipher.PBES2.HMacMD4.Blowfish.class.getName()); + put("Cipher.PBEWithHMacMD4AndCast5", + gnu.javax.crypto.jce.cipher.PBES2.HMacMD4.Cast5.class.getName()); + put("Cipher.PBEWithHMacMD4AndDES", + gnu.javax.crypto.jce.cipher.PBES2.HMacMD4.DES.class.getName()); + put("Cipher.PBEWithHMacMD4AndKhazad", + gnu.javax.crypto.jce.cipher.PBES2.HMacMD4.Khazad.class.getName()); + put("Cipher.PBEWithHMacMD4AndSerpent", + gnu.javax.crypto.jce.cipher.PBES2.HMacMD4.Serpent.class.getName()); + put("Cipher.PBEWithHMacMD4AndSquare", + gnu.javax.crypto.jce.cipher.PBES2.HMacMD4.Square.class.getName()); + put("Cipher.PBEWithHMacMD4AndTripleDES", + gnu.javax.crypto.jce.cipher.PBES2.HMacMD4.TripleDES.class.getName()); + put("Cipher.PBEWithHMacMD4AndTwofish", + gnu.javax.crypto.jce.cipher.PBES2.HMacMD4.Twofish.class.getName()); + + put("Cipher.PBEWithHMacMD5AndAES", + gnu.javax.crypto.jce.cipher.PBES2.HMacMD5.AES.class.getName()); + put("Cipher.PBEWithHMacMD5AndAnubis", + gnu.javax.crypto.jce.cipher.PBES2.HMacMD5.Anubis.class.getName()); + put("Cipher.PBEWithHMacMD5AndBlowfish", + gnu.javax.crypto.jce.cipher.PBES2.HMacMD5.Blowfish.class.getName()); + put("Cipher.PBEWithHMacMD5AndCast5", + gnu.javax.crypto.jce.cipher.PBES2.HMacMD5.Cast5.class.getName()); + put("Cipher.PBEWithHMacMD5AndDES", + gnu.javax.crypto.jce.cipher.PBES2.HMacMD5.DES.class.getName()); + put("Cipher.PBEWithHMacMD5AndKhazad", + gnu.javax.crypto.jce.cipher.PBES2.HMacMD5.Khazad.class.getName()); + put("Cipher.PBEWithHMacMD5AndSerpent", + gnu.javax.crypto.jce.cipher.PBES2.HMacMD5.Serpent.class.getName()); + put("Cipher.PBEWithHMacMD5AndSquare", + gnu.javax.crypto.jce.cipher.PBES2.HMacMD5.Square.class.getName()); + put("Cipher.PBEWithHMacMD5AndTripleDES", + gnu.javax.crypto.jce.cipher.PBES2.HMacMD5.TripleDES.class.getName()); + put("Cipher.PBEWithHMacMD5AndTwofish", + gnu.javax.crypto.jce.cipher.PBES2.HMacMD5.Twofish.class.getName()); + + put("Cipher.PBEWithHMacSHA1AndAES", + gnu.javax.crypto.jce.cipher.PBES2.HMacSHA1.AES.class.getName()); + put("Cipher.PBEWithHMacSHA1AndAnubis", + gnu.javax.crypto.jce.cipher.PBES2.HMacSHA1.Anubis.class.getName()); + put("Cipher.PBEWithHMacSHA1AndBlowfish", + gnu.javax.crypto.jce.cipher.PBES2.HMacSHA1.Blowfish.class.getName()); + put("Cipher.PBEWithHMacSHA1AndCast5", + gnu.javax.crypto.jce.cipher.PBES2.HMacSHA1.Cast5.class.getName()); + put("Cipher.PBEWithHMacSHA1AndDES", + gnu.javax.crypto.jce.cipher.PBES2.HMacSHA1.DES.class.getName()); + put("Cipher.PBEWithHMacSHA1AndKhazad", + gnu.javax.crypto.jce.cipher.PBES2.HMacSHA1.Khazad.class.getName()); + put("Cipher.PBEWithHMacSHA1AndSerpent", + gnu.javax.crypto.jce.cipher.PBES2.HMacSHA1.Serpent.class.getName()); + put("Cipher.PBEWithHMacSHA1AndSquare", + gnu.javax.crypto.jce.cipher.PBES2.HMacSHA1.Square.class.getName()); + put( + "Cipher.PBEWithHMacSHA1AndTripleDES", + gnu.javax.crypto.jce.cipher.PBES2.HMacSHA1.TripleDES.class.getName()); + put("Cipher.PBEWithHMacSHA1AndTwofish", + gnu.javax.crypto.jce.cipher.PBES2.HMacSHA1.Twofish.class.getName()); + + put("Cipher.PBEWithHMacSHA256AndAES", + gnu.javax.crypto.jce.cipher.PBES2.HMacSHA256.AES.class.getName()); + put("Cipher.PBEWithHMacSHA256AndAnubis", + gnu.javax.crypto.jce.cipher.PBES2.HMacSHA256.Anubis.class.getName()); + put("Cipher.PBEWithHMacSHA256AndBlowfish", + gnu.javax.crypto.jce.cipher.PBES2.HMacSHA256.Blowfish.class.getName()); + put("Cipher.PBEWithHMacSHA256AndCast5", + gnu.javax.crypto.jce.cipher.PBES2.HMacSHA256.Cast5.class.getName()); + put("Cipher.PBEWithHMacSHA256AndDES", + gnu.javax.crypto.jce.cipher.PBES2.HMacSHA256.DES.class.getName()); + put("Cipher.PBEWithHMacSHA256AndKhazad", + gnu.javax.crypto.jce.cipher.PBES2.HMacSHA256.Khazad.class.getName()); + put("Cipher.PBEWithHMacSHA256AndSerpent", + gnu.javax.crypto.jce.cipher.PBES2.HMacSHA256.Serpent.class.getName()); + put("Cipher.PBEWithHMacSHA256AndSquare", + gnu.javax.crypto.jce.cipher.PBES2.HMacSHA256.Square.class.getName()); + put("Cipher.PBEWithHMacSHA256AndTripleDES", + gnu.javax.crypto.jce.cipher.PBES2.HMacSHA256.TripleDES.class.getName()); + put("Cipher.PBEWithHMacSHA256AndTwofish", + gnu.javax.crypto.jce.cipher.PBES2.HMacSHA256.Twofish.class.getName()); + + put("Cipher.PBEWithHMacSHA384AndAES", + gnu.javax.crypto.jce.cipher.PBES2.HMacSHA384.AES.class.getName()); + put("Cipher.PBEWithHMacSHA384AndAnubis", + gnu.javax.crypto.jce.cipher.PBES2.HMacSHA384.Anubis.class.getName()); + put("Cipher.PBEWithHMacSHA384AndBlowfish", + gnu.javax.crypto.jce.cipher.PBES2.HMacSHA384.Blowfish.class.getName()); + put("Cipher.PBEWithHMacSHA384AndCast5", + gnu.javax.crypto.jce.cipher.PBES2.HMacSHA384.Cast5.class.getName()); + put("Cipher.PBEWithHMacSHA384AndDES", + gnu.javax.crypto.jce.cipher.PBES2.HMacSHA384.DES.class.getName()); + put("Cipher.PBEWithHMacSHA384AndKhazad", + gnu.javax.crypto.jce.cipher.PBES2.HMacSHA384.Khazad.class.getName()); + put("Cipher.PBEWithHMacSHA384AndSerpent", + gnu.javax.crypto.jce.cipher.PBES2.HMacSHA384.Serpent.class.getName()); + put("Cipher.PBEWithHMacSHA384AndSquare", + gnu.javax.crypto.jce.cipher.PBES2.HMacSHA384.Square.class.getName()); + put("Cipher.PBEWithHMacSHA384AndTripleDES", + gnu.javax.crypto.jce.cipher.PBES2.HMacSHA384.TripleDES.class.getName()); + put("Cipher.PBEWithHMacSHA384AndTwofish", + gnu.javax.crypto.jce.cipher.PBES2.HMacSHA384.Twofish.class.getName()); + + put("Cipher.PBEWithHMacSHA512AndAES", + gnu.javax.crypto.jce.cipher.PBES2.HMacSHA512.AES.class.getName()); + put("Cipher.PBEWithHMacSHA512AndAnubis", + gnu.javax.crypto.jce.cipher.PBES2.HMacSHA512.Anubis.class.getName()); + put("Cipher.PBEWithHMacSHA512AndBlowfish", + gnu.javax.crypto.jce.cipher.PBES2.HMacSHA512.Blowfish.class.getName()); + put("Cipher.PBEWithHMacSHA512AndCast5", + gnu.javax.crypto.jce.cipher.PBES2.HMacSHA512.Cast5.class.getName()); + put("Cipher.PBEWithHMacSHA512AndDES", + gnu.javax.crypto.jce.cipher.PBES2.HMacSHA512.DES.class.getName()); + put("Cipher.PBEWithHMacSHA512AndKhazad", + gnu.javax.crypto.jce.cipher.PBES2.HMacSHA512.Khazad.class.getName()); + put("Cipher.PBEWithHMacSHA512AndSerpent", + gnu.javax.crypto.jce.cipher.PBES2.HMacSHA512.Serpent.class.getName()); + put("Cipher.PBEWithHMacSHA512AndSquare", + gnu.javax.crypto.jce.cipher.PBES2.HMacSHA512.Square.class.getName()); + put("Cipher.PBEWithHMacSHA512AndTripleDES", + gnu.javax.crypto.jce.cipher.PBES2.HMacSHA512.TripleDES.class.getName()); + put("Cipher.PBEWithHMacSHA512AndTwofish", + gnu.javax.crypto.jce.cipher.PBES2.HMacSHA512.Twofish.class.getName()); + + put("Cipher.PBEWithHMacTigerAndAES", + gnu.javax.crypto.jce.cipher.PBES2.HMacTiger.AES.class.getName()); + put("Cipher.PBEWithHMacTigerAndAnubis", + gnu.javax.crypto.jce.cipher.PBES2.HMacTiger.Anubis.class.getName()); + put("Cipher.PBEWithHMacTigerAndBlowfish", + gnu.javax.crypto.jce.cipher.PBES2.HMacTiger.Blowfish.class.getName()); + put("Cipher.PBEWithHMacTigerAndCast5", + gnu.javax.crypto.jce.cipher.PBES2.HMacTiger.Cast5.class.getName()); + put("Cipher.PBEWithHMacTigerAndDES", + gnu.javax.crypto.jce.cipher.PBES2.HMacTiger.DES.class.getName()); + put("Cipher.PBEWithHMacTigerAndKhazad", + gnu.javax.crypto.jce.cipher.PBES2.HMacTiger.Khazad.class.getName()); + put("Cipher.PBEWithHMacTigerAndSerpent", + gnu.javax.crypto.jce.cipher.PBES2.HMacTiger.Serpent.class.getName()); + put("Cipher.PBEWithHMacTigerAndSquare", + gnu.javax.crypto.jce.cipher.PBES2.HMacTiger.Square.class.getName()); + put("Cipher.PBEWithHMacTigerAndTripleDES", + gnu.javax.crypto.jce.cipher.PBES2.HMacTiger.TripleDES.class.getName()); + put("Cipher.PBEWithHMacTigerAndTwofish", + gnu.javax.crypto.jce.cipher.PBES2.HMacTiger.Twofish.class.getName()); + + put("Cipher.PBEWithHMacWhirlpoolAndAES", + gnu.javax.crypto.jce.cipher.PBES2.HMacWhirlpool.AES.class.getName()); + put("Cipher.PBEWithHMacWhirlpoolAndAnubis", + gnu.javax.crypto.jce.cipher.PBES2.HMacWhirlpool.Anubis.class.getName()); + put("Cipher.PBEWithHMacWhirlpoolAndBlowfish", + gnu.javax.crypto.jce.cipher.PBES2.HMacWhirlpool.Blowfish.class.getName()); + put("Cipher.PBEWithHMacWhirlpoolAndCast5", + gnu.javax.crypto.jce.cipher.PBES2.HMacWhirlpool.Cast5.class.getName()); + put("Cipher.PBEWithHMacWhirlpoolAndDES", + gnu.javax.crypto.jce.cipher.PBES2.HMacWhirlpool.DES.class.getName()); + put("Cipher.PBEWithHMacWhirlpoolAndKhazad", + gnu.javax.crypto.jce.cipher.PBES2.HMacWhirlpool.Khazad.class.getName()); + put("Cipher.PBEWithHMacWhirlpoolAndSerpent", + gnu.javax.crypto.jce.cipher.PBES2.HMacWhirlpool.Serpent.class.getName()); + put("Cipher.PBEWithHMacWhirlpoolAndSquare", + gnu.javax.crypto.jce.cipher.PBES2.HMacWhirlpool.Square.class.getName()); + put("Cipher.PBEWithHMacWhirlpoolAndTripleDES", + gnu.javax.crypto.jce.cipher.PBES2.HMacWhirlpool.TripleDES.class.getName()); + put("Cipher.PBEWithHMacWhirlpoolAndTwofish", + gnu.javax.crypto.jce.cipher.PBES2.HMacWhirlpool.Twofish.class.getName()); + + // Key Wrapping Algorithm cipher + put("Cipher." + Registry.AES128_KWA, + gnu.javax.crypto.jce.cipher.AES128KeyWrapSpi.class.getName()); + put("Cipher." + Registry.AES192_KWA, + gnu.javax.crypto.jce.cipher.AES192KeyWrapSpi.class.getName()); + put("Cipher." + Registry.AES256_KWA, + gnu.javax.crypto.jce.cipher.AES256KeyWrapSpi.class.getName()); + put("Cipher." + Registry.TRIPLEDES_KWA, + gnu.javax.crypto.jce.cipher.TripleDESKeyWrapSpi.class.getName()); + + // SecretKeyFactory interface to PBKDF2. + put("SecretKeyFactory.PBKDF2WithHMacHaval", + gnu.javax.crypto.jce.PBKDF2SecretKeyFactory.HMacHaval.class.getName()); + put("SecretKeyFactory.PBKDF2WithHMacMD2", + gnu.javax.crypto.jce.PBKDF2SecretKeyFactory.HMacMD2.class.getName()); + put("SecretKeyFactory.PBKDF2WithHMacMD4", + gnu.javax.crypto.jce.PBKDF2SecretKeyFactory.HMacMD4.class.getName()); + put("SecretKeyFactory.PBKDF2WithHMacMD5", + gnu.javax.crypto.jce.PBKDF2SecretKeyFactory.HMacMD5.class.getName()); + put("SecretKeyFactory.PBKDF2WithHMacSHA1", + gnu.javax.crypto.jce.PBKDF2SecretKeyFactory.HMacSHA1.class.getName()); + put("SecretKeyFactory.PBKDF2WithHMacSHA256", + gnu.javax.crypto.jce.PBKDF2SecretKeyFactory.HMacSHA256.class.getName()); + put("SecretKeyFactory.PBKDF2WithHMacSHA384", + gnu.javax.crypto.jce.PBKDF2SecretKeyFactory.HMacSHA384.class.getName()); + put("SecretKeyFactory.PBKDF2WithHMacSHA512", + gnu.javax.crypto.jce.PBKDF2SecretKeyFactory.HMacSHA512.class.getName()); + put("SecretKeyFactory.PBKDF2WithHMacTiger", + gnu.javax.crypto.jce.PBKDF2SecretKeyFactory.HMacTiger.class.getName()); + put("SecretKeyFactory.PBKDF2WithHMacWhirlpool", + gnu.javax.crypto.jce.PBKDF2SecretKeyFactory.HMacWhirlpool.class.getName()); + + // Simple SecretKeyFactory implementations. + put("SecretKeyFactory.Anubis", + gnu.javax.crypto.jce.key.AnubisSecretKeyFactoryImpl.class.getName()); + put("SecretKeyFactory.Blowfish", + gnu.javax.crypto.jce.key.BlowfishSecretKeyFactoryImpl.class.getName()); + put("SecretKeyFactory.Cast5", + gnu.javax.crypto.jce.key.Cast5SecretKeyFactoryImpl.class.getName()); + put("SecretKeyFactory.DES", + gnu.javax.crypto.jce.key.DESSecretKeyFactoryImpl.class.getName()); + put("SecretKeyFactory.Khazad", + gnu.javax.crypto.jce.key.KhazadSecretKeyFactoryImpl.class.getName()); + put("SecretKeyFactory.Rijndael", + gnu.javax.crypto.jce.key.RijndaelSecretKeyFactoryImpl.class.getName()); + put("SecretKeyFactory.Serpent", + gnu.javax.crypto.jce.key.SerpentSecretKeyFactoryImpl.class.getName()); + put("SecretKeyFactory.Square", + gnu.javax.crypto.jce.key.SquareSecretKeyFactoryImpl.class.getName()); + put("SecretKeyFactory.TripleDES", + gnu.javax.crypto.jce.key.DESedeSecretKeyFactoryImpl.class.getName()); + put("Alg.Alias.SecretKeyFactory.AES", "Rijndael"); + put("Alg.Alias.SecretKeyFactory.DESede", "TripleDES"); + put("Alg.Alias.SecretKeyFactory.3-DES", "TripleDES"); + put("Alg.Alias.SecretKeyFactory.3DES", "TripleDES"); + + put("AlgorithmParameters.BlockCipherParameters", + gnu.javax.crypto.jce.params.BlockCipherParameters.class.getName()); + put("Alg.Alias.AlgorithmParameters.Anubis", "BlockCipherParameters"); + put("Alg.Alias.AlgorithmParameters.Blowfish", "BlockCipherParameters"); + put("Alg.Alias.AlgorithmParameters.Cast5", "BlockCipherParameters"); + put("Alg.Alias.AlgorithmParameters.DES", "BlockCipherParameters"); + put("Alg.Alias.AlgorithmParameters.Khazad", "BlockCipherParameters"); + put("Alg.Alias.AlgorithmParameters.Rijndael", "BlockCipherParameters"); + put("Alg.Alias.AlgorithmParameters.AES", "BlockCipherParameters"); + put("Alg.Alias.AlgorithmParameters.Serpent", "BlockCipherParameters"); + put("Alg.Alias.AlgorithmParameters.Square", "BlockCipherParameters"); + put("Alg.Alias.AlgorithmParameters.TripleDES", "BlockCipherParameters"); + put("Alg.Alias.AlgorithmParameters.DESede", "BlockCipherParameters"); + put("Alg.Alias.AlgorithmParameters.3-DES", "BlockCipherParameters"); + put("Alg.Alias.AlgorithmParameters.3DES", "BlockCipherParameters"); + + // KeyGenerator Adapter implementations + put("KeyGenerator.Anubis", + gnu.javax.crypto.jce.key.AnubisKeyGeneratorImpl.class.getName()); + put("KeyGenerator.Blowfish", + gnu.javax.crypto.jce.key.BlowfishKeyGeneratorImpl.class.getName()); + put("KeyGenerator.Cast5", + gnu.javax.crypto.jce.key.Cast5KeyGeneratorImpl.class.getName()); + put("KeyGenerator.DES", + gnu.javax.crypto.jce.key.DESKeyGeneratorImpl.class.getName()); + put("KeyGenerator.Khazad", + gnu.javax.crypto.jce.key.KhazadKeyGeneratorImpl.class.getName()); + put("KeyGenerator.Rijndael", + gnu.javax.crypto.jce.key.RijndaelKeyGeneratorImpl.class.getName()); + put("KeyGenerator.Serpent", + gnu.javax.crypto.jce.key.SerpentKeyGeneratorImpl.class.getName()); + put("KeyGenerator.Square", + gnu.javax.crypto.jce.key.SquareKeyGeneratorImpl.class.getName()); + put("KeyGenerator.TripleDES", + gnu.javax.crypto.jce.key.TripleDESKeyGeneratorImpl.class.getName()); + put("Alg.Alias.KeyGenerator.AES", "Rijndael"); + put("Alg.Alias.KeyGenerator.DESede", "TripleDES"); + put("Alg.Alias.KeyGenerator.3-DES", "TripleDES"); + put("Alg.Alias.KeyGenerator.3DES", "TripleDES"); + + // MAC + put("Mac.HMAC-MD2", gnu.javax.crypto.jce.mac.HMacMD2Spi.class.getName()); + put("Mac.HMAC-MD4", gnu.javax.crypto.jce.mac.HMacMD4Spi.class.getName()); + put("Mac.HMAC-MD5", gnu.javax.crypto.jce.mac.HMacMD5Spi.class.getName()); + put("Mac.HMAC-RIPEMD128", + gnu.javax.crypto.jce.mac.HMacRipeMD128Spi.class.getName()); + put("Mac.HMAC-RIPEMD160", + gnu.javax.crypto.jce.mac.HMacRipeMD160Spi.class.getName()); + put("Mac.HMAC-SHA160", + gnu.javax.crypto.jce.mac.HMacSHA160Spi.class.getName()); + put("Mac.HMAC-SHA256", + gnu.javax.crypto.jce.mac.HMacSHA256Spi.class.getName()); + put("Mac.HMAC-SHA384", + gnu.javax.crypto.jce.mac.HMacSHA384Spi.class.getName()); + put("Mac.HMAC-SHA512", + gnu.javax.crypto.jce.mac.HMacSHA512Spi.class.getName()); + put("Mac.HMAC-TIGER", + gnu.javax.crypto.jce.mac.HMacTigerSpi.class.getName()); + put("Mac.HMAC-HAVAL", + gnu.javax.crypto.jce.mac.HMacHavalSpi.class.getName()); + put("Mac.HMAC-WHIRLPOOL", + gnu.javax.crypto.jce.mac.HMacWhirlpoolSpi.class.getName()); + put("Mac.TMMH16", gnu.javax.crypto.jce.mac.TMMH16Spi.class.getName()); + put("Mac.UHASH32", gnu.javax.crypto.jce.mac.UHash32Spi.class.getName()); + put("Mac.UMAC32", gnu.javax.crypto.jce.mac.UMac32Spi.class.getName()); + + put("Mac.OMAC-ANUBIS", + gnu.javax.crypto.jce.mac.OMacAnubisImpl.class.getName()); + put("Mac.OMAC-BLOWFISH", + gnu.javax.crypto.jce.mac.OMacBlowfishImpl.class.getName()); + put("Mac.OMAC-CAST5", + gnu.javax.crypto.jce.mac.OMacCast5Impl.class.getName()); + put("Mac.OMAC-DES", + gnu.javax.crypto.jce.mac.OMacDESImpl.class.getName()); + put("Mac.OMAC-KHAZAD", + gnu.javax.crypto.jce.mac.OMacKhazadImpl.class.getName()); + put("Mac.OMAC-RIJNDAEL", + gnu.javax.crypto.jce.mac.OMacRijndaelImpl.class.getName()); + put("Mac.OMAC-SERPENT", + gnu.javax.crypto.jce.mac.OMacSerpentImpl.class.getName()); + put("Mac.OMAC-SQUARE", + gnu.javax.crypto.jce.mac.OMacSquareImpl.class.getName()); + put("Mac.OMAC-TRIPLEDES", + gnu.javax.crypto.jce.mac.OMacTripleDESImpl.class.getName()); + put("Mac.OMAC-TWOFISH", + gnu.javax.crypto.jce.mac.OMacTwofishImpl.class.getName()); + + // Aliases + put("Alg.Alias.AlgorithmParameters.AES", "BlockCipherParameters"); + put("Alg.Alias.AlgorithmParameters.BLOWFISH", "BlockCipherParameters"); + put("Alg.Alias.AlgorithmParameters.ANUBIS", "BlockCipherParameters"); + put("Alg.Alias.AlgorithmParameters.KHAZAD", "BlockCipherParameters"); + put("Alg.Alias.AlgorithmParameters.NULL", "BlockCipherParameters"); + put("Alg.Alias.AlgorithmParameters.RIJNDAEL", "BlockCipherParameters"); + put("Alg.Alias.AlgorithmParameters.SERPENT", "BlockCipherParameters"); + put("Alg.Alias.AlgorithmParameters.SQUARE", "BlockCipherParameters"); + put("Alg.Alias.AlgorithmParameters.TWOFISH", "BlockCipherParameters"); + put("Alg.Alias.Cipher.RC4", "ARCFOUR"); + put("Alg.Alias.Cipher.3-DES", "TRIPLEDES"); + put("Alg.Alias.Cipher.3DES", "TRIPLEDES"); + put("Alg.Alias.Cipher.DES-EDE", "TRIPLEDES"); + put("Alg.Alias.Cipher.DESede", "TRIPLEDES"); + put("Alg.Alias.Cipher.CAST128", "CAST5"); + put("Alg.Alias.Cipher.CAST-128", "CAST5"); + put("Alg.Alias.Mac.HMAC-SHS", "HMAC-SHA160"); + put("Alg.Alias.Mac.HMAC-SHA", "HMAC-SHA160"); + put("Alg.Alias.Mac.HMAC-SHA1", "HMAC-SHA160"); + put("Alg.Alias.Mac.HMAC-SHA-160", "HMAC-SHA160"); + put("Alg.Alias.Mac.HMAC-SHA-256", "HMAC-SHA256"); + put("Alg.Alias.Mac.HMAC-SHA-384", "HMAC-SHA384"); + put("Alg.Alias.Mac.HMAC-SHA-512", "HMAC-SHA512"); + put("Alg.Alias.Mac.HMAC-RIPEMD-160", "HMAC-RIPEMD160"); + put("Alg.Alias.Mac.HMAC-RIPEMD-128", "HMAC-RIPEMD128"); + put("Alg.Alias.Mac.OMAC-AES", "OMAC-RIJNDAEL"); + put("Alg.Alias.Mac.OMAC-3DES", "OMAC-3DES"); + put("Alg.Alias.Mac.HmacMD4", "HMAC-MD4"); + put("Alg.Alias.Mac.HmacMD5", "HMAC-MD5"); + put("Alg.Alias.Mac.HmacSHA-1", "HMAC-SHA-1"); + put("Alg.Alias.Mac.HmacSHA1", "HMAC-SHA1"); + put("Alg.Alias.Mac.HmacSHA-160", "HMAC-SHA-160"); + put("Alg.Alias.Mac.HmacSHA160", "HMAC-SHA-160"); + put("Alg.Alias.Mac.HmacSHA-256", "HMAC-SHA-256"); + put("Alg.Alias.Mac.HmacSHA256", "HMAC-SHA-256"); + put("Alg.Alias.Mac.HmacSHA-384", "HMAC-SHA-384"); + put("Alg.Alias.Mac.HmacSHA384", "HMAC-SHA-384"); + put("Alg.Alias.Mac.HmacSHA-512", "HMAC-SHA-512"); + put("Alg.Alias.Mac.HmacSHA512", "HMAC-SHA-512"); + put("Alg.Alias.Mac.HmacRIPEMD128", "HMAC-RIPEMD128"); + put("Alg.Alias.Mac.HmacRIPEMD-128", "HMAC-RIPEMD128"); + put("Alg.Alias.Mac.HmacRIPEMD160", "HMAC-RIPEMD160"); + put("Alg.Alias.Mac.HmacRIPEMD-160", "HMAC-RIPEMD160"); + put("Alg.Alias.Mac.HmacTiger", "HMAC-TIGER"); + put("Alg.Alias.Mac.HmacHaval", "HMAC-HAVAL"); + put("Alg.Alias.Mac.HmacWhirlpool", "HMAC-WHIRLPOOL"); + + // KeyAgreement + put("KeyAgreement.DH", + gnu.javax.crypto.jce.DiffieHellmanImpl.class.getName()); + put("Alg.Alias.KeyAgreement.DiffieHellman", "DH"); + + // Cipher + put("Cipher.RSAES-PKCS1-v1_5", + gnu.javax.crypto.RSACipherImpl.class.getName()); + put("Alg.Alias.Cipher.RSA", "RSAES-PKCS1-v1_5"); + + // SecureRandom + put("SecureRandom.ARCFOUR", + gnu.javax.crypto.jce.prng.ARCFourRandomSpi.class.getName()); + put("SecureRandom.ARCFOUR ImplementedIn", "Software"); + put("SecureRandom.CSPRNG", + gnu.javax.crypto.jce.prng.CSPRNGSpi.class.getName()); + put("SecureRandom.CSPRNG ImplementedIn", "Software"); + put("SecureRandom.ICM", + gnu.javax.crypto.jce.prng.ICMRandomSpi.class.getName()); + put("SecureRandom.ICM ImplementedIn", "Software"); + put("SecureRandom.UMAC-KDF", + gnu.javax.crypto.jce.prng.UMacRandomSpi.class.getName()); + put("SecureRandom.UMAC-KDF ImplementedIn", "Software"); + put("SecureRandom.Fortuna", + gnu.javax.crypto.jce.prng.FortunaImpl.class.getName()); + put("SecureRandom.Fortuna ImplementedIn", "Software"); + + // KeyStore + put("KeyStore.GKR", + gnu.javax.crypto.jce.keyring.GnuKeyring.class.getName()); + put("Alg.Alias.KeyStore.GnuKeyring", "GKR"); + + // KeyPairGenerator --------------------------------------------------- + put("KeyPairGenerator.DH", + gnu.javax.crypto.jce.sig.DHKeyPairGeneratorSpi.class.getName()); + put("KeyPairGenerator.DH KeySize", "512"); + put("KeyPairGenerator.DH ImplementedIn", "Software"); + + put("Alg.Alias.KeyPairGenerator.DiffieHellman", "DH"); + + // KeyFactory --------------------------------------------------------- + put("KeyFactory.DH", + gnu.javax.crypto.jce.sig.DHKeyFactory.class.getName()); + + put("Alg.Alias,KeyFactory.DiffieHellman", "DH"); + + // Algorithm Parameters ----------------------------------------------- + put("AlgorithmParameters.DH", + gnu.javax.crypto.jce.sig.DHParameters.class.getName()); + + put("Alg.Alias.AlgorithmParameters.DiffieHellman", "DH"); + + // Algorithm Parameters Generator ------------------------------------- + put("AlgorithmParameterGenerator.DH", + gnu.javax.crypto.jce.sig.DHParametersGenerator.class.getName()); + + put("Alg.Alias.AlgorithmParameterGenerator.DiffieHellman", "DH"); + + return null; + } + }); + } + + /** + * Returns a {@link Set} of names of symmetric key block cipher algorithms + * available from this {@link Provider}. + * + * @return a {@link Set} of cipher names (Strings). + */ + public static final Set getCipherNames() + { + HashSet s = new HashSet(); + s.addAll(CipherFactory.getNames()); + s.add(Registry.ARCFOUR_PRNG); + return s; + } + + /** + * Returns a {@link Set} of names of MAC algorithms available from this + * {@link Provider}. + * + * @return a {@link Set} of MAC names (Strings). + */ + public static final Set getMacNames() + { + return MacFactory.getNames(); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/GnuSasl.java b/libjava/classpath/gnu/javax/crypto/jce/GnuSasl.java new file mode 100644 index 000000000..6ab89e2fa --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/GnuSasl.java @@ -0,0 +1,124 @@ +/* GnuSasl.java -- javax.security.sasl algorithms. + Copyright (C) 2004, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.jce; + +import gnu.java.security.Registry; +import gnu.javax.crypto.sasl.ClientFactory; +import gnu.javax.crypto.sasl.ServerFactory; + +import java.security.AccessController; +import java.security.PrivilegedAction; +import java.security.Provider; +import java.util.Set; + +public final class GnuSasl + extends Provider +{ + public GnuSasl() + { + super(Registry.GNU_SASL, 2.1, "GNU SASL Provider"); + + AccessController.doPrivileged(new PrivilegedAction() + { + public Object run() + { + // SASL Client and Server mechanisms + put("SaslClientFactory.ANONYMOUS", + gnu.javax.crypto.sasl.ClientFactory.class.getName()); + put("SaslClientFactory.PLAIN", + gnu.javax.crypto.sasl.ClientFactory.class.getName()); + put("SaslClientFactory.CRAM-MD5", + gnu.javax.crypto.sasl.ClientFactory.class.getName()); + put("SaslClientFactory.SRP", + gnu.javax.crypto.sasl.ClientFactory.class.getName()); + + put("SaslServerFactory.ANONYMOUS", + gnu.javax.crypto.sasl.ServerFactory.class.getName()); + put("SaslServerFactory.PLAIN", + gnu.javax.crypto.sasl.ServerFactory.class.getName()); + put("SaslServerFactory.CRAM-MD5", + gnu.javax.crypto.sasl.ServerFactory.class.getName()); + put("SaslServerFactory.SRP-MD5", + gnu.javax.crypto.sasl.ServerFactory.class.getName()); + put("SaslServerFactory.SRP-SHA-160", + gnu.javax.crypto.sasl.ServerFactory.class.getName()); + put("SaslServerFactory.SRP-RIPEMD128", + gnu.javax.crypto.sasl.ServerFactory.class.getName()); + put("SaslServerFactory.SRP-RIPEMD160", + gnu.javax.crypto.sasl.ServerFactory.class.getName()); + put("SaslServerFactory.SRP-TIGER", + gnu.javax.crypto.sasl.ServerFactory.class.getName()); + put("SaslServerFactory.SRP-WHIRLPOOL", + gnu.javax.crypto.sasl.ServerFactory.class.getName()); + + put("Alg.Alias.SaslServerFactory.SRP-SHS", "SRP-SHA-160"); + put("Alg.Alias.SaslServerFactory.SRP-SHA", "SRP-SHA-160"); + put("Alg.Alias.SaslServerFactory.SRP-SHA1", "SRP-SHA-160"); + put("Alg.Alias.SaslServerFactory.SRP-SHA-1", "SRP-SHA-160"); + put("Alg.Alias.SaslServerFactory.SRP-SHA160", "SRP-SHA-160"); + put("Alg.Alias.SaslServerFactory.SRP-RIPEMD-128", "SRP-RIPEMD128"); + put("Alg.Alias.SaslServerFactory.SRP-RIPEMD-160", "SRP-RIPEMD160"); + + return null; + } + }); + } + + /** + * Returns a {@link Set} of names of SASL Client mechanisms available from + * this {@link Provider}. + * + * @return a {@link Set} of SASL Client mechanisms (Strings). + */ + public static final Set getSaslClientMechanismNames() + { + return ClientFactory.getNames(); + } + + /** + * Returns a {@link Set} of names of SASL Server mechanisms available from + * this {@link Provider}. + * + * @return a {@link Set} of SASL Server mechanisms (Strings). + */ + public static final Set getSaslServerMechanismNames() + { + return ServerFactory.getNames(); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/PBKDF2SecretKeyFactory.java b/libjava/classpath/gnu/javax/crypto/jce/PBKDF2SecretKeyFactory.java new file mode 100644 index 000000000..cda8f34e8 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/PBKDF2SecretKeyFactory.java @@ -0,0 +1,218 @@ +/* PBKDF2SecretKeyFactory.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.jce; + +import java.security.spec.InvalidKeySpecException; +import java.security.spec.KeySpec; + +import java.util.HashMap; + +import javax.crypto.SecretKey; +import javax.crypto.SecretKeyFactorySpi; +import javax.crypto.spec.PBEKeySpec; +import javax.crypto.spec.SecretKeySpec; + +import gnu.javax.crypto.prng.IPBE; +import gnu.java.security.prng.IRandom; +import gnu.java.security.prng.LimitReachedException; +import gnu.javax.crypto.prng.PRNGFactory; + +public abstract class PBKDF2SecretKeyFactory + extends SecretKeyFactorySpi +{ + protected String macName; + private static final int DEFAULT_ITERATION_COUNT = 1000; + private static final int DEFAULT_KEY_LEN = 32; + + protected PBKDF2SecretKeyFactory(String macName) + { + this.macName = macName; + } + + protected SecretKey engineGenerateSecret(KeySpec spec) + throws InvalidKeySpecException + { + if (! (spec instanceof PBEKeySpec)) + throw new InvalidKeySpecException("not a PBEKeySpec"); + IRandom kdf = PRNGFactory.getInstance("PBKDF2-" + macName); + HashMap attr = new HashMap(); + attr.put(IPBE.PASSWORD, ((PBEKeySpec) spec).getPassword()); + byte[] salt = ((PBEKeySpec) spec).getSalt(); + if (salt == null) + salt = new byte[0]; + attr.put(IPBE.SALT, salt); + int ic = ((PBEKeySpec) spec).getIterationCount(); + if (ic <= 0) + ic = DEFAULT_ITERATION_COUNT; + attr.put(IPBE.ITERATION_COUNT, Integer.valueOf(ic)); + kdf.init(attr); + int len = ((PBEKeySpec) spec).getKeyLength(); + if (len <= 0) + len = DEFAULT_KEY_LEN; + byte[] dk = new byte[len]; + try + { + kdf.nextBytes(dk, 0, len); + } + catch (LimitReachedException lre) + { + throw new IllegalArgumentException(lre.toString()); + } + return new SecretKeySpec(dk, "PBKDF2"); + } + + protected KeySpec engineGetKeySpec(SecretKey key, Class clazz) + throws InvalidKeySpecException + { + throw new InvalidKeySpecException("not supported"); + } + + protected SecretKey engineTranslateKey(SecretKey key) + { + return new SecretKeySpec(key.getEncoded(), key.getAlgorithm()); + } + + public static class HMacHaval + extends PBKDF2SecretKeyFactory + { + public HMacHaval() + { + super("HMAC-HAVAL"); + } + } + + public static class HMacMD2 + extends PBKDF2SecretKeyFactory + { + public HMacMD2() + { + super("HMAC-MD2"); + } + } + + public static class HMacMD4 + extends PBKDF2SecretKeyFactory + { + public HMacMD4() + { + super("HMAC-MD4"); + } + } + + public static class HMacMD5 + extends PBKDF2SecretKeyFactory + { + public HMacMD5() + { + super("HMAC-MD5"); + } + } + + public static class HMacRipeMD128 + extends PBKDF2SecretKeyFactory + { + public HMacRipeMD128() + { + super("HMAC-RIPEMD128"); + } + } + + public static class HMacRipeMD160 + extends PBKDF2SecretKeyFactory + { + public HMacRipeMD160() + { + super("HMAC-RIPEMD160"); + } + } + + public static class HMacSHA1 + extends PBKDF2SecretKeyFactory + { + public HMacSHA1() + { + super("HMAC-SHA1"); + } + } + + public static class HMacSHA256 + extends PBKDF2SecretKeyFactory + { + public HMacSHA256() + { + super("HMAC-SHA256"); + } + } + + public static class HMacSHA384 + extends PBKDF2SecretKeyFactory + { + public HMacSHA384() + { + super("HMAC-SHA384"); + } + } + + public static class HMacSHA512 + extends PBKDF2SecretKeyFactory + { + public HMacSHA512() + { + super("HMAC-SHA512"); + } + } + + public static class HMacTiger + extends PBKDF2SecretKeyFactory + { + public HMacTiger() + { + super("HMAC-TIGER"); + } + } + + public static class HMacWhirlpool + extends PBKDF2SecretKeyFactory + { + public HMacWhirlpool() + { + super("HMAC-WHIRLPOOL"); + } + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/cipher/AES128KeyWrapSpi.java b/libjava/classpath/gnu/javax/crypto/jce/cipher/AES128KeyWrapSpi.java new file mode 100644 index 000000000..14ce480ae --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/cipher/AES128KeyWrapSpi.java @@ -0,0 +1,54 @@ +/* AESKeyWrapSpi.java -- AES (128-bit key) Key Wrapping Algorithm JCE Adapter + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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; either version 2, or (at your option) +any later version. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.jce.cipher; + +import gnu.java.security.Registry; + +/** + * The JCE Cipher Adapter implementation over the GNU AES Key Wrapping + * Algorithm with a 128-bit key-size. + */ +public final class AES128KeyWrapSpi + extends AESKeyWrapSpi +{ + public AES128KeyWrapSpi() + { + super(Registry.AES128_KWA, 128 / 8, Registry.ECB_MODE); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/cipher/AES192KeyWrapSpi.java b/libjava/classpath/gnu/javax/crypto/jce/cipher/AES192KeyWrapSpi.java new file mode 100644 index 000000000..784fc5a15 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/cipher/AES192KeyWrapSpi.java @@ -0,0 +1,54 @@ +/* AES192KeyWrapSpi.java -- AES (192-bit key) Key Wrapping Algorithm JCE Adapter + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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; either version 2, or (at your option) +any later version. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.jce.cipher; + +import gnu.java.security.Registry; + +/** + * The JCE Cipher Adapter implementation over the GNU AES Key Wrapping + * Algorithm with a 192-bit key-size. + */ +public final class AES192KeyWrapSpi + extends AESKeyWrapSpi +{ + public AES192KeyWrapSpi() + { + super(Registry.AES192_KWA, 192 / 8, Registry.ECB_MODE); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/cipher/AES256KeyWrapSpi.java b/libjava/classpath/gnu/javax/crypto/jce/cipher/AES256KeyWrapSpi.java new file mode 100644 index 000000000..dd7357b0e --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/cipher/AES256KeyWrapSpi.java @@ -0,0 +1,54 @@ +/* AES256KeyWrapSpi.java -- AES (256-bit key) Key Wrapping Algorithm JCE Adapter + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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; either version 2, or (at your option) +any later version. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.jce.cipher; + +import gnu.java.security.Registry; + +/** + * The JCE Cipher Adapter implementation over the GNU AES Key Wrapping + * Algorithm with a 256-bit key-size. + */ +public final class AES256KeyWrapSpi + extends AESKeyWrapSpi +{ + public AES256KeyWrapSpi() + { + super(Registry.AES256_KWA, 256 / 8, Registry.ECB_MODE); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/cipher/AESKeyWrapSpi.java b/libjava/classpath/gnu/javax/crypto/jce/cipher/AESKeyWrapSpi.java new file mode 100644 index 000000000..08f4e7820 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/cipher/AESKeyWrapSpi.java @@ -0,0 +1,88 @@ +/* AESKeyWrapSpi.java -- Common AES Key Wrapping Algorithm methods + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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; either version 2, or (at your option) +any later version. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.jce.cipher; + +/** + * Base abstract class to group common AES Key Wrapping Algorithm Adapter + * methods. + */ +abstract class AESKeyWrapSpi + extends KeyWrappingAlgorithmAdapter +{ + protected AESKeyWrapSpi(String name, int keySize, String supportedMode) + { + super(name, 16, keySize, supportedMode); + } + + /** + * AES Key Wrapping algorithms operate on an 8-byte block; a block half the + * size of the AES block itself. + * <p> + * In wrapping, the number of 8-byte output blocks is ALWAYS one block longer + * than the input. + * + * @param inputLength the size of the plain text. + * @return the size in bytes of <code>n + 1</code> 8-byte blocks where + * <code>n</code> is the smallest number of 8-byte blocks that contain the + * designated number of input bytes. + */ + protected int getOutputSizeForWrap(int inputLength) + { + int n = (inputLength + 7) / 8; + return 8 * (n + 1); + } + + /** + * AES Key Wrapping algorithms operate on an 8-byte block; a block half the + * size of the AES block itself. + * <p> + * In unwrapping, the number of 8-byte output blocks is ALWAYS one block + * shorter than the input. + * + * @param inputLength the size of the cipher text. + * @return the size in bytes of <code>n - 1</code> 8-byte blocks where + * <code>n</code> is the smallest number of 8-byte blocks that contain the + * designated number of input bytes. + */ + protected int getOutputSizeForUnwrap(int inputLength) + { + int n = (inputLength + 7) / 8; + return 8 * (n - 1); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/cipher/AESSpi.java b/libjava/classpath/gnu/javax/crypto/jce/cipher/AESSpi.java new file mode 100644 index 000000000..4c3e1aecc --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/cipher/AESSpi.java @@ -0,0 +1,92 @@ +/* AESSpi.java -- + Copyright (C) 2002, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.jce.cipher; + +import gnu.java.security.Registry; +import gnu.javax.crypto.jce.spec.BlockCipherParameterSpec; + +import java.security.AlgorithmParameters; +import java.security.InvalidAlgorithmParameterException; +import java.security.InvalidKeyException; +import java.security.Key; +import java.security.SecureRandom; +import java.security.spec.AlgorithmParameterSpec; +import java.security.spec.InvalidParameterSpecException; + +/** + * The implementation of the AES <i>Service Provider Interface</i> (<b>SPI</b>) + * adapter. + */ +public final class AESSpi + extends CipherAdapter +{ + public AESSpi() + { + super(Registry.AES_CIPHER, 16); + } + + protected void engineInit(int opmode, Key key, AlgorithmParameterSpec params, + SecureRandom random) throws InvalidKeyException, + InvalidAlgorithmParameterException + { + if (params instanceof BlockCipherParameterSpec) + { + if (((BlockCipherParameterSpec) params).getBlockSize() != 16) + throw new InvalidAlgorithmParameterException( + "AES block size must be 16 bytes"); + } + super.engineInit(opmode, key, params, random); + } + + protected void engineInit(int opmode, Key key, AlgorithmParameters params, + SecureRandom random) throws InvalidKeyException, + InvalidAlgorithmParameterException + { + AlgorithmParameterSpec spec = null; + try + { + if (params != null) + spec = params.getParameterSpec(BlockCipherParameterSpec.class); + } + catch (InvalidParameterSpecException ipse) + { + } + engineInit(opmode, key, spec, random); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/cipher/ARCFourSpi.java b/libjava/classpath/gnu/javax/crypto/jce/cipher/ARCFourSpi.java new file mode 100644 index 000000000..2e1422e6b --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/cipher/ARCFourSpi.java @@ -0,0 +1,183 @@ +/* ARCFourSpi.java -- + Copyright (C) 2002, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.jce.cipher; + +import gnu.java.security.Registry; +import gnu.javax.crypto.prng.ARCFour; +import gnu.java.security.prng.IRandom; +import gnu.java.security.prng.LimitReachedException; +import gnu.javax.crypto.prng.PRNGFactory; + +import java.security.AlgorithmParameters; +import java.security.InvalidAlgorithmParameterException; +import java.security.InvalidKeyException; +import java.security.Key; +import java.security.NoSuchAlgorithmException; +import java.security.SecureRandom; +import java.security.spec.AlgorithmParameterSpec; + +import java.util.HashMap; + +import javax.crypto.BadPaddingException; +import javax.crypto.Cipher; +import javax.crypto.CipherSpi; +import javax.crypto.IllegalBlockSizeException; +import javax.crypto.NoSuchPaddingException; +import javax.crypto.ShortBufferException; + +/** + * The <i>Service Provider Interface</i> (<b>SPI</b>) for the ARCFOUR stream + * cipher. + */ +public class ARCFourSpi + extends CipherSpi +{ + private IRandom keystream; + + public ARCFourSpi() + { + super(); + keystream = PRNGFactory.getInstance(Registry.ARCFOUR_PRNG); + } + + protected int engineGetBlockSize() + { + return 0; // stream cipher. + } + + protected void engineSetMode(String s) throws NoSuchAlgorithmException + { + // ignored. + } + + protected void engineSetPadding(String s) throws NoSuchPaddingException + { + // ignored. + } + + protected byte[] engineGetIV() + { + return null; + } + + protected int engineGetOutputSize(int in) + { + return in; + } + + protected AlgorithmParameters engineGetParameters() + { + return null; + } + + protected void engineInit(int mode, Key key, SecureRandom r) + throws InvalidKeyException + { + if (mode != Cipher.ENCRYPT_MODE && mode != Cipher.DECRYPT_MODE) + throw new IllegalArgumentException( + "arcfour is for encryption or decryption only"); + if (key == null || ! key.getFormat().equalsIgnoreCase("RAW")) + throw new InvalidKeyException("key must be non-null raw bytes"); + HashMap attrib = new HashMap(); + attrib.put(ARCFour.ARCFOUR_KEY_MATERIAL, key.getEncoded()); + keystream.init(attrib); + } + + protected void engineInit(int mode, Key key, AlgorithmParameterSpec p, + SecureRandom r) throws InvalidKeyException, + InvalidAlgorithmParameterException + { + engineInit(mode, key, r); + } + + protected void engineInit(int mode, Key key, AlgorithmParameters p, + SecureRandom r) throws InvalidKeyException, + InvalidAlgorithmParameterException + { + engineInit(mode, key, r); + } + + protected byte[] engineUpdate(byte[] in, int offset, int length) + { + if (length < 0 || offset < 0 || length + offset > in.length) + throw new ArrayIndexOutOfBoundsException(); + byte[] result = new byte[length]; + try + { + for (int i = 0; i < length; i++) + result[i] = (byte)(in[i + offset] ^ keystream.nextByte()); + } + catch (LimitReachedException wontHappen) + { + } + return result; + } + + protected int engineUpdate(byte[] in, int inOffset, int length, byte[] out, + int outOffset) throws ShortBufferException + { + if (length < 0 || inOffset < 0 || length + inOffset > in.length + || outOffset < 0) + throw new ArrayIndexOutOfBoundsException(); + if (outOffset + length > out.length) + throw new ShortBufferException(); + try + { + for (int i = 0; i < length; i++) + out[i + outOffset] = (byte)(in[i + inOffset] ^ keystream.nextByte()); + } + catch (LimitReachedException wontHappen) + { + } + return length; + } + + protected byte[] engineDoFinal(byte[] in, int offset, int length) + throws IllegalBlockSizeException, BadPaddingException + { + return engineUpdate(in, offset, length); + } + + protected int engineDoFinal(byte[] in, int inOffset, int length, byte[] out, + int outOffset) throws ShortBufferException, + IllegalBlockSizeException, BadPaddingException + { + return engineUpdate(in, inOffset, length, out, outOffset); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/cipher/AnubisSpi.java b/libjava/classpath/gnu/javax/crypto/jce/cipher/AnubisSpi.java new file mode 100644 index 000000000..ab0c64867 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/cipher/AnubisSpi.java @@ -0,0 +1,54 @@ +/* AnubisSpi.java -- + Copyright (C) 2002, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.jce.cipher; + +import gnu.java.security.Registry; + +/** + * The implementation of the Anubis <i>Service Provider Interface</i> + * (<b>SPI</b>) adapter. + */ +public final class AnubisSpi + extends CipherAdapter +{ + public AnubisSpi() + { + super(Registry.ANUBIS_CIPHER); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/cipher/BlowfishSpi.java b/libjava/classpath/gnu/javax/crypto/jce/cipher/BlowfishSpi.java new file mode 100644 index 000000000..55d71dbf5 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/cipher/BlowfishSpi.java @@ -0,0 +1,54 @@ +/* BlowfishSpi.java -- + Copyright (C) 2002, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.jce.cipher; + +import gnu.java.security.Registry; + +/** + * The implementation of the Blowfish <i>Service Provider Interface</i> + * (<b>SPI</b>) adapter. + */ +public final class BlowfishSpi + extends CipherAdapter +{ + public BlowfishSpi() + { + super(Registry.BLOWFISH_CIPHER); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/cipher/Cast5Spi.java b/libjava/classpath/gnu/javax/crypto/jce/cipher/Cast5Spi.java new file mode 100644 index 000000000..95a663e2f --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/cipher/Cast5Spi.java @@ -0,0 +1,54 @@ +/* Cast5Spi.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.jce.cipher; + +import gnu.java.security.Registry; + +/** + * The implementation of the <code>CAST5</code> (a.k.a. CAST-128) <i>Service + * Provider Interface</i> (<b>SPI</b>) Adapter. + */ +public class Cast5Spi + extends CipherAdapter +{ + public Cast5Spi() + { + super(Registry.CAST5_CIPHER); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/cipher/CipherAdapter.java b/libjava/classpath/gnu/javax/crypto/jce/cipher/CipherAdapter.java new file mode 100644 index 000000000..0871c5402 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/cipher/CipherAdapter.java @@ -0,0 +1,531 @@ +/* CipherAdapter.java -- + Copyright (C) 2002, 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.jce.cipher; + +import gnu.java.security.Registry; +import gnu.javax.crypto.cipher.CipherFactory; +import gnu.javax.crypto.cipher.IBlockCipher; +import gnu.javax.crypto.jce.spec.BlockCipherParameterSpec; +import gnu.javax.crypto.mode.IMode; +import gnu.javax.crypto.mode.ModeFactory; +import gnu.javax.crypto.pad.IPad; +import gnu.javax.crypto.pad.PadFactory; +import gnu.javax.crypto.pad.WrongPaddingException; + +import java.security.AlgorithmParameters; +import java.security.InvalidAlgorithmParameterException; +import java.security.InvalidKeyException; +import java.security.Key; +import java.security.NoSuchAlgorithmException; +import java.security.SecureRandom; +import java.security.spec.AlgorithmParameterSpec; +import java.security.spec.InvalidParameterSpecException; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; + +import javax.crypto.BadPaddingException; +import javax.crypto.Cipher; +import javax.crypto.CipherSpi; +import javax.crypto.IllegalBlockSizeException; +import javax.crypto.NoSuchPaddingException; +import javax.crypto.ShortBufferException; +import javax.crypto.spec.IvParameterSpec; + +/** + * The implementation of a generic {@link Cipher} <i>Adapter</i> class to wrap + * GNU cipher instances. + * <p> + * This class defines the <i>Service Provider Interface</i> (<b>SPI</b>) for + * the {@link Cipher} class, which provides the functionality of symmetric-key + * block ciphers, such as the AES. + * <p> + * This base class defines all of the abstract methods in {@link CipherSpi}, + * but does not define the (non-abstract) key wrapping functions that extended + * the base cipher SPI, and these methods thus immediately throw an + * {@link UnsupportedOperationException}. If a cipher implementation provides + * this functionality, or if it in fact accepts parameters other than the key + * and the initialization vector, the subclass should override those methods. + * Otherwise a subclass need only call the {@link #CipherAdapter(String)} + * constructor with the name of the cipher. + */ +class CipherAdapter + extends CipherSpi +{ + /** Our cipher instance. */ + protected IBlockCipher cipher; + /** Our mode instance. */ + protected IMode mode; + /** Our padding instance. */ + protected IPad pad; + /** The current key size. */ + protected int keyLen; + /** Our attributes map. */ + protected Map attributes; + /** An incomplete block. */ + protected byte[] partBlock; + /** The number of bytes in {@link #partBlock}. */ + protected int partLen; + /** The length of blocks we are processing. */ + protected int blockLen; + + /** + * Protected constructor to be called by subclasses. The cipher name argument + * should be the appropriate one listed in {@link Registry}. The basic cipher + * instance is created, along with an instance of the + * {@link gnu.javax.crypto.mode.ECB} mode and no padding. + * + * @param cipherName The cipher to instantiate. + * @param blockLen The block length to use. + */ + protected CipherAdapter(String cipherName, int blockLen) + { + cipher = CipherFactory.getInstance(cipherName); + attributes = new HashMap(); + this.blockLen = blockLen; + mode = ModeFactory.getInstance("ECB", cipher, blockLen); + attributes.put(IBlockCipher.CIPHER_BLOCK_SIZE, Integer.valueOf(blockLen)); + } + + /** + * Creates a new cipher adapter with the default block size. + * + * @param cipherName The cipher to instantiate. + */ + protected CipherAdapter(String cipherName) + { + cipher = CipherFactory.getInstance(cipherName); + blockLen = cipher.defaultBlockSize(); + attributes = new HashMap(); + mode = ModeFactory.getInstance("ECB", cipher, blockLen); + attributes.put(IBlockCipher.CIPHER_BLOCK_SIZE, Integer.valueOf(blockLen)); + } + + protected void engineSetMode(String modeName) throws NoSuchAlgorithmException + { + if (modeName.length() >= 3 + && modeName.substring(0, 3).equalsIgnoreCase("CFB")) + { + if (modeName.length() > 3) + { + try + { + int bs = Integer.parseInt(modeName.substring(3)); + attributes.put(IMode.MODE_BLOCK_SIZE, Integer.valueOf(bs / 8)); + } + catch (NumberFormatException nfe) + { + throw new NoSuchAlgorithmException(modeName); + } + modeName = "CFB"; + } + } + else + attributes.remove(IMode.MODE_BLOCK_SIZE); + mode = ModeFactory.getInstance(modeName, cipher, blockLen); + if (mode == null) + throw new NoSuchAlgorithmException(modeName); + } + + protected void engineSetPadding(String padName) throws NoSuchPaddingException + { + if (padName.equalsIgnoreCase("NoPadding")) + { + pad = null; + return; + } + pad = PadFactory.getInstance(padName); + if (pad == null) + throw new NoSuchPaddingException(padName); + } + + protected int engineGetBlockSize() + { + if (cipher != null) + return blockLen; + return 0; + } + + protected int engineGetOutputSize(int inputLen) + { + final int blockSize = mode.currentBlockSize(); + return ((inputLen + partLen) / blockSize) * blockSize; + } + + protected byte[] engineGetIV() + { + byte[] iv = (byte[]) attributes.get(IMode.IV); + if (iv == null) + return null; + return (byte[]) iv.clone(); + } + + protected AlgorithmParameters engineGetParameters() + { + byte[] iv = (byte[]) attributes.get(IMode.IV); + int cipherBlockSize = cipher.currentBlockSize(); + BlockCipherParameterSpec spec = new BlockCipherParameterSpec(iv, + cipherBlockSize, + keyLen); + AlgorithmParameters params; + try + { + params = AlgorithmParameters.getInstance("BlockCipherParameters"); + params.init(spec); + } + catch (NoSuchAlgorithmException nsae) + { + return null; + } + catch (InvalidParameterSpecException ipse) + { + return null; + } + return params; + } + + protected void engineInit(int opmode, Key key, SecureRandom random) + throws InvalidKeyException + { + try + { + engineInit(opmode, key, (AlgorithmParameterSpec) null, random); + } + catch (InvalidAlgorithmParameterException e) + { + throw new InvalidKeyException(e.getMessage(), e); + } + } + + /** + * Executes initialization logic after all parameters have been handled by the + * engineInit()s. + * + * @param opmode the desired mode of operation for this instance. + * @param key the key material to use for initialization. + * @param random a source of randmoness to use if/when needed. + * @throws InvalidKeyException if <code>key</code> is invalid or the cipher + * needs extra parameters which can not be derived from + * <code>key</code>; e.g. an IV. + */ + private void engineInitHandler(int opmode, Key key, SecureRandom random) + throws InvalidKeyException + { + switch (opmode) + { + case Cipher.ENCRYPT_MODE: + attributes.put(IMode.STATE, Integer.valueOf(IMode.ENCRYPTION)); + break; + case Cipher.DECRYPT_MODE: + attributes.put(IMode.STATE, Integer.valueOf(IMode.DECRYPTION)); + break; + } + if (! key.getFormat().equalsIgnoreCase("RAW")) + throw new InvalidKeyException("bad key format " + key.getFormat()); + byte[] kb = key.getEncoded(); + int kbLength = kb.length; + if (keyLen == 0) + { + // no key-size given; instead key-material is provided in kb --which + // can be more than what we need. if we don't cull this down to what + // the cipher likes/wants we may get an InvalidKeyException. + // + // try to find the largest key-size value that is less than or equal + // to kbLength + for (Iterator it = cipher.keySizes(); it.hasNext();) + { + int aKeySize = ((Integer) it.next()).intValue(); + if (aKeySize == kbLength) + { + keyLen = aKeySize; + break; + } + else if (aKeySize < kbLength) + keyLen = aKeySize; + else // all remaining key-sizes are longer than kb.length + break; + } + } + if (keyLen == 0) + { + // we were unable to find a key-size, among those advertised by the + // cipher, that is less than or equal to the length of the kb array. + // set keyLen to kbLength. either the cipher implementation will throw + // an InvalidKeyException, or it is implemented in a way which can deal + // with an unsupported key-size. + keyLen = kbLength; + } + if (keyLen < kbLength) + { + byte[] kbb = kb; + kb = new byte[keyLen]; + System.arraycopy(kbb, 0, kb, 0, keyLen); + } + attributes.put(IBlockCipher.KEY_MATERIAL, kb); + reset(); + } + + protected void engineInit(int opmode, Key key, AlgorithmParameterSpec params, + SecureRandom random) throws InvalidKeyException, + InvalidAlgorithmParameterException + { + if (params == null) + { + // All cipher modes require parameters (like an IV) except ECB. When + // these cant be derived from the given key then it must be generated + // randomly if in ENCRYPT or WRAP mode. Parameters that have defaults + // for our cipher must be set to these defaults. + if (! mode.name().toLowerCase().startsWith(Registry.ECB_MODE + "(")) + { + switch (opmode) + { + case Cipher.ENCRYPT_MODE: + case Cipher.WRAP_MODE: + byte[] iv = new byte[blockLen]; + random.nextBytes(iv); + attributes.put(IMode.IV, iv); + break; + default: + throw new InvalidAlgorithmParameterException( + "Required algorithm parameters are missing for mode: " + + mode.name()); + } + } + // Add default for block length etc. + blockLen = cipher.defaultBlockSize(); + attributes.put(IBlockCipher.CIPHER_BLOCK_SIZE, + Integer.valueOf(blockLen)); + keyLen = 0; + } + else if (params instanceof BlockCipherParameterSpec) + { + BlockCipherParameterSpec bcps = (BlockCipherParameterSpec) params; + blockLen = bcps.getBlockSize(); + attributes.put(IBlockCipher.CIPHER_BLOCK_SIZE, Integer.valueOf(blockLen)); + attributes.put(IMode.IV, bcps.getIV()); + keyLen = bcps.getKeySize(); + } + else if (params instanceof IvParameterSpec) + { + // The size of the IV must match the block size + if (((IvParameterSpec) params).getIV().length != cipher.defaultBlockSize()) + { + throw new InvalidAlgorithmParameterException(); + } + + attributes.put(IMode.IV, ((IvParameterSpec) params).getIV()); + blockLen = cipher.defaultBlockSize(); + attributes.put(IBlockCipher.CIPHER_BLOCK_SIZE, Integer.valueOf(blockLen)); + keyLen = 0; + } + engineInitHandler(opmode, key, random); + } + + protected void engineInit(int opmode, Key key, AlgorithmParameters params, + SecureRandom random) throws InvalidKeyException, + InvalidAlgorithmParameterException + { + AlgorithmParameterSpec spec = null; + try + { + if (params != null) + spec = params.getParameterSpec(BlockCipherParameterSpec.class); + } + catch (InvalidParameterSpecException ignored) + { + } + engineInit(opmode, key, spec, random); + } + + protected byte[] engineUpdate(byte[] input, int inOff, int inLen) + { + if (inLen == 0) // nothing to process + return new byte[0]; + final int blockSize = mode.currentBlockSize(); + int blockCount = (partLen + inLen) / blockSize; + + // always keep data for unpadding in padded decryption mode; + // might even be a complete block + if (pad != null + && ((Integer) attributes.get(IMode.STATE)).intValue() == IMode.DECRYPTION + && (partLen + inLen) % blockSize == 0) + blockCount--; + + final byte[] out = new byte[blockCount * blockSize]; + try + { + engineUpdate(input, inOff, inLen, out, 0); + } + catch (ShortBufferException x) // should not happen + { + x.printStackTrace(System.err); + } + return out; + } + + protected int engineUpdate(byte[] in, int inOff, int inLen, byte[] out, + int outOff) throws ShortBufferException + { + if (inLen == 0) // nothing to process + return 0; + final int blockSize = mode.currentBlockSize(); + int blockCount = (partLen + inLen) / blockSize; + + // always keep data for unpadding in padded decryption mode; + // might even be a complete block + if (pad != null + && ((Integer) attributes.get(IMode.STATE)).intValue() == IMode.DECRYPTION + && (partLen + inLen) % blockSize == 0) + blockCount--; + + final int result = blockCount * blockSize; + if (result > out.length - outOff) + throw new ShortBufferException(); + if (blockCount == 0) // not enough bytes for even 1 block + { + System.arraycopy(in, inOff, partBlock, partLen, inLen); + partLen += inLen; + return 0; + } + final byte[] buf; + // we have enough bytes for at least 1 block + if (partLen == 0) // if no cached bytes use input + buf = in; + else // prefix input with cached bytes + { + buf = new byte[partLen + inLen]; + System.arraycopy(partBlock, 0, buf, 0, partLen); + if (in != null && inLen > 0) + System.arraycopy(in, inOff, buf, partLen, inLen); + inOff = 0; + } + for (int i = 0; i < blockCount; i++) // update blockCount * blockSize + { + mode.update(buf, inOff, out, outOff); + inOff += blockSize; + outOff += blockSize; + } + partLen += inLen - result; + if (partLen > 0) // cache remaining bytes from buf + System.arraycopy(buf, inOff, partBlock, 0, partLen); + return result; + } + + protected byte[] engineDoFinal(byte[] input, int off, int len) + throws IllegalBlockSizeException, BadPaddingException + { + final byte[] result; + final byte[] buf = engineUpdate(input, off, len); + if (pad != null) + { + switch (((Integer) attributes.get(IMode.STATE)).intValue()) + { + case IMode.ENCRYPTION: + byte[] padding = pad.pad(partBlock, 0, partLen); + byte[] buf2 = engineUpdate(padding, 0, padding.length); + result = new byte[buf.length + buf2.length]; + System.arraycopy(buf, 0, result, 0, buf.length); + System.arraycopy(buf2, 0, result, buf.length, buf2.length); + break; + case IMode.DECRYPTION: + int padLen; + byte[] buf3 = new byte[buf.length + partLen]; + try + { + if (partLen != mode.currentBlockSize()) + throw new WrongPaddingException(); + System.arraycopy(buf, 0, buf3, 0, buf.length); + mode.update(partBlock, 0, buf3, buf.length); + padLen = pad.unpad(buf3, 0, buf3.length); + } + catch (WrongPaddingException wpe) + { + throw new BadPaddingException(wpe.getMessage()); + } + result = new byte[buf3.length - padLen]; + System.arraycopy(buf3, 0, result, 0, result.length); + break; + default: + throw new IllegalStateException(); + } + } + else + { + if (partLen > 0) + throw new IllegalBlockSizeException(partLen + " trailing bytes"); + result = buf; + } + + try + { + reset(); + } + catch (InvalidKeyException ike) + { + // Should not happen; if we initialized it with the current + // parameters before, we should be able to do it again. + throw new Error(ike); + } + return result; + } + + protected int engineDoFinal(byte[] in, int inOff, int inLen, byte[] out, + int outOff) throws BadPaddingException, + IllegalBlockSizeException, ShortBufferException + { + byte[] buf = engineDoFinal(in, inOff, inLen); + if (out.length + outOff < buf.length) + throw new ShortBufferException(); + System.arraycopy(buf, 0, out, outOff, buf.length); + return buf.length; + } + + private void reset() throws InvalidKeyException + { + mode.reset(); + mode.init(attributes); + if (pad != null) + { + pad.reset(); + pad.init(blockLen); + } + partBlock = new byte[blockLen]; + partLen = 0; + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/cipher/DESSpi.java b/libjava/classpath/gnu/javax/crypto/jce/cipher/DESSpi.java new file mode 100644 index 000000000..0da913a44 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/cipher/DESSpi.java @@ -0,0 +1,54 @@ +/* DESSpi.java -- + Copyright (C) 2002, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.jce.cipher; + +import gnu.java.security.Registry; + +/** + * The implementation of the DES <i>Service Provider Interface</i> (<b>SPI</b>) + * adapter. + */ +public final class DESSpi + extends CipherAdapter +{ + public DESSpi() + { + super(Registry.DES_CIPHER); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/cipher/KeyWrappingAlgorithmAdapter.java b/libjava/classpath/gnu/javax/crypto/jce/cipher/KeyWrappingAlgorithmAdapter.java new file mode 100644 index 000000000..97fdd5331 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/cipher/KeyWrappingAlgorithmAdapter.java @@ -0,0 +1,423 @@ +/* KeyWrappingAlgorithmAdapter.java -- Base Adapter for Key Wrapping algorithms + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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; either version 2, or (at your option) +any later version. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.jce.cipher; + +import gnu.java.security.Configuration; +import gnu.java.security.Registry; +import gnu.javax.crypto.jce.spec.BlockCipherParameterSpec; +import gnu.javax.crypto.kwa.IKeyWrappingAlgorithm; +import gnu.javax.crypto.kwa.KeyUnwrappingException; +import gnu.javax.crypto.kwa.KeyWrappingAlgorithmFactory; + +import java.security.AlgorithmParameters; +import java.security.InvalidAlgorithmParameterException; +import java.security.InvalidKeyException; +import java.security.Key; +import java.security.KeyFactory; +import java.security.NoSuchAlgorithmException; +import java.security.SecureRandom; +import java.security.spec.AlgorithmParameterSpec; +import java.security.spec.InvalidKeySpecException; +import java.security.spec.InvalidParameterSpecException; +import java.security.spec.X509EncodedKeySpec; +import java.util.HashMap; +import java.util.Map; +import java.util.logging.Logger; + +import javax.crypto.BadPaddingException; +import javax.crypto.Cipher; +import javax.crypto.CipherSpi; +import javax.crypto.IllegalBlockSizeException; +import javax.crypto.NoSuchPaddingException; +import javax.crypto.ShortBufferException; +import javax.crypto.spec.IvParameterSpec; +import javax.crypto.spec.SecretKeySpec; + +/** + * An abstract base class to facilitate implementations of JCE Adapters for + * symmetric key block ciphers capable of providing key-wrapping functionality. + */ +abstract class KeyWrappingAlgorithmAdapter + extends CipherSpi +{ + private static final Logger log = Logger.getLogger(KeyWrappingAlgorithmAdapter.class.getName()); + /** JCE canonical name of a null-padder. */ + private static final String NO_PADDING = "nopadding"; + /** Concrete Key Wrapping Algorithm SPI. */ + protected IKeyWrappingAlgorithm kwAlgorithm; + /** Size in bytes of the padding block to be provided by external padders. */ + protected int kwaBlockSize; + /** KEK size in bytes. */ + protected int kwaKeySize; + /** Name of the supported mode. */ + protected String supportedMode; + /** Operational mode in which this instance was initialised. */ + protected int opmode = -1; + /** Initialisation Vector if/when user wants to override default one. */ + byte[] iv; + + /** + * Creates a new JCE Adapter for the designated Key Wrapping Algorithm name. + * + * @param name the canonical name of the key-wrapping algorithm. + * @param blockSize the block size in bytes of the underlying symmetric-key + * block cipher algorithm. + * @param keySize the allowed size in bytes of the KEK bytes to initialise the + * underlying symmetric-key block cipher algorithm with. + * @param supportedMode canonical name of the block mode the underlying cipher + * is supporting. + */ + protected KeyWrappingAlgorithmAdapter(String name, int blockSize, int keySize, + String supportedMode) + { + super(); + + this.kwAlgorithm = KeyWrappingAlgorithmFactory.getInstance(name); + this.kwaBlockSize = blockSize; + this.kwaKeySize = keySize; + this.supportedMode = supportedMode; + } + + /** + * Wraps the encoded form of a designated {@link Key}. + * + * @param key the key-material to wrap. + * @return the wrapped key. + * @throws InvalidKeyException If the key cannot be wrapped. + */ + protected byte[] engineWrap(Key key) + throws InvalidKeyException, IllegalBlockSizeException + { + byte[] keyMaterial = key.getEncoded(); + byte[] result = kwAlgorithm.wrap(keyMaterial, 0, keyMaterial.length); + return result; + } + + /** + * Unwraps a previously-wrapped key-material. + * + * @param wrappedKey the wrapped key-material to unwrap. + * @param wrappedKeyAlgorithm the canonical name of the algorithm, which the + * unwrapped key-material represents. This name is used to + * instantiate a concrete instance of a {@link Key} for that + * algorithm. For example, if the value of this parameter is + * <code>DSS</code> and the type (the next parameter) is + * {@link Cipher#PUBLIC_KEY} then an attempt to construct a concrete + * instance of a {@link java.security.interfaces.DSAPublicKey}, + * using the unwrapped key material, shall be made. + * @param wrappedKeyType the type of wrapped key-material. MUST be one of + * {@link Cipher#PRIVATE_KEY}, {@link Cipher#PUBLIC_KEY}, or + * {@link Cipher#SECRET_KEY}. + * @return the unwrapped key-material as an instance of {@link Key} or one of + * its subclasses. + * @throws InvalidKeyException If the key cannot be unwrapped, or if + * <code>wrappedKeyType</code> is an inappropriate type for the + * unwrapped key. + * @throws NoSuchAlgorithmException If the <code>wrappedKeyAlgorithm</code> + * is unknown to every currently installed Security Provider. + */ + protected Key engineUnwrap(byte[] wrappedKey, String wrappedKeyAlgorithm, + int wrappedKeyType) + throws InvalidKeyException, NoSuchAlgorithmException + { + byte[] keyBytes; + try + { + keyBytes = kwAlgorithm.unwrap(wrappedKey, 0, wrappedKey.length); + } + catch (KeyUnwrappingException x) + { + InvalidKeyException y = new InvalidKeyException("engineUnwrap()"); + y.initCause(x); + throw y; + } + Key result; + switch (wrappedKeyType) + { + case Cipher.SECRET_KEY: + result = new SecretKeySpec(keyBytes, wrappedKeyAlgorithm); + break; + case Cipher.PRIVATE_KEY: + case Cipher.PUBLIC_KEY: + X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes); + KeyFactory keyFactory = KeyFactory.getInstance(wrappedKeyAlgorithm); + try + { + if (wrappedKeyType == Cipher.PRIVATE_KEY) + result = keyFactory.generatePrivate(keySpec); + else + result = keyFactory.generatePublic(keySpec); + } + catch (InvalidKeySpecException x) + { + InvalidKeyException y = new InvalidKeyException("engineUnwrap()"); + y.initCause(x); + throw y; + } + break; + default: + IllegalArgumentException x = new IllegalArgumentException("Invalid 'wrappedKeyType': " + + wrappedKeyType); + InvalidKeyException y = new InvalidKeyException("engineUnwrap()"); + y.initCause(x); + throw y; + } + return result; + } + + protected int engineGetBlockSize() + { + return kwaBlockSize; + } + + protected byte[] engineGetIV() + { + return iv == null ? null : (byte[]) iv.clone(); + } + + protected int engineGetOutputSize(int inputLength) + { + switch (opmode) + { + case Cipher.WRAP_MODE: + return getOutputSizeForWrap(inputLength); + case Cipher.UNWRAP_MODE: + return getOutputSizeForUnwrap(inputLength); + default: + throw new IllegalStateException(); + } + } + + protected AlgorithmParameters engineGetParameters() + { + BlockCipherParameterSpec spec = new BlockCipherParameterSpec(iv, + kwaBlockSize, + kwaKeySize); + AlgorithmParameters result = null; + try + { + result = AlgorithmParameters.getInstance("BlockCipherParameters"); + result.init(spec); + } + catch (NoSuchAlgorithmException x) + { + if (Configuration.DEBUG) + log.fine("Unable to find BlockCipherParameters. Return null"); + } + catch (InvalidParameterSpecException x) + { + if (Configuration.DEBUG) + log.fine("Unable to initialise BlockCipherParameters. Return null"); + } + return result; + } + + protected void engineInit(int opmode, Key key, SecureRandom random) + throws InvalidKeyException + { + checkOpMode(opmode); + byte[] kekBytes = checkAndGetKekBytes(key); + initAlgorithm(opmode, kekBytes, null, random); + } + + protected void engineInit(int opmode, Key key, AlgorithmParameters params, + SecureRandom random) + throws InvalidAlgorithmParameterException, InvalidKeyException + { + AlgorithmParameterSpec spec = null; + try + { + if (params != null) + spec = params.getParameterSpec(BlockCipherParameterSpec.class); + } + catch (InvalidParameterSpecException x) + { + if (Configuration.DEBUG) + log.fine("Unable to translate algorithm parameters into an instance " + + "of BlockCipherParameterSpec. Discard"); + } + engineInit(opmode, key, spec, random); + } + + protected void engineInit(int opmode, Key key, AlgorithmParameterSpec params, + SecureRandom random) + throws InvalidAlgorithmParameterException, InvalidKeyException + { + checkOpMode(opmode); + byte[] kekBytes = checkAndGetKekBytes(key); + byte[] ivBytes = null; + if (params instanceof BlockCipherParameterSpec) + ivBytes = ((BlockCipherParameterSpec) params).getIV(); + else if (params instanceof IvParameterSpec) + ivBytes = ((IvParameterSpec) params).getIV(); + + initAlgorithm(opmode, kekBytes, ivBytes, random); + } + + protected void engineSetMode(String mode) throws NoSuchAlgorithmException + { + if (! supportedMode.equalsIgnoreCase(mode)) + throw new UnsupportedOperationException("Only " + supportedMode + + " is supported"); + } + + /** + * NoPadding is the only padding algorithm supported by Key Wrapping Algorithm + * implementations in RI. + */ + protected void engineSetPadding(String padding) throws NoSuchPaddingException + { + if (! NO_PADDING.equalsIgnoreCase(padding)) + throw new UnsupportedOperationException("Only NoPadding is supported"); + } + + protected byte[] engineUpdate(byte[] input, int inputOffset, int inputLength) + { + throw new UnsupportedOperationException(); + } + + protected int engineUpdate(byte[] input, int inputOffset, int inputLength, + byte[] output, int outputOffset) + throws ShortBufferException + { + throw new UnsupportedOperationException(); + } + + protected byte[] engineDoFinal(byte[] input, int inputOffset, int inputLength) + throws IllegalBlockSizeException, BadPaddingException + { + throw new UnsupportedOperationException(); + } + + protected int engineDoFinal(byte[] input, int inputOffset, int inputLength, + byte[] output, int outputOffset) + throws IllegalBlockSizeException, BadPaddingException, ShortBufferException + { + throw new UnsupportedOperationException(); + } + + /** + * Return the minimum size in bytes of a place holder large enough to receive + * the cipher text resulting from a wrap method with the designated size of + * the plain text. + * <p> + * This default implementation ALWAYS returns the smallest multiple of the + * <code>kwaBlockSize</code> --passed to this method through its + * constructor-- greater than or equal to the designated + * <code>inputLength</code>. + * + * @param inputLength the size of a plain text. + * @return an estimate of the size, in bytes, of the place holder to receive + * the resulting bytes of a wrap method. + */ + protected int getOutputSizeForWrap(int inputLength) + { + return kwaBlockSize * (inputLength + kwaBlockSize - 1) / kwaBlockSize; + } + + /** + * Return the minimum size in bytes of a place holder large enough to receive + * the plain text resulting from an unwrap method with the designated size of + * the cipher text. + * <p> + * This default implementation ALWAYS returns the smallest multiple of the + * <code>paddingBlockSize</code> --passed to this method through its + * constructor-- greater than or equal to the designated + * <code>inputLength</code>. + * + * @param inputLength the size of a cipher text. + * @return an estimate of the size, in bytes, of the place holder to receive + * the resulting bytes of an uwrap method. + */ + protected int getOutputSizeForUnwrap(int inputLength) + { + return kwaBlockSize * (inputLength + kwaBlockSize - 1) / kwaBlockSize; + } + + private void checkOpMode(int opmode) + { + switch (opmode) + { + case Cipher.WRAP_MODE: + case Cipher.UNWRAP_MODE: + return; + } + throw new IllegalArgumentException("Unsupported operational mode: " + opmode); + } + + /** + * Returns the key bytes, iff it was in RAW format. + * + * @param key the opaque JCE secret key to use as the KEK. + * @return the bytes of the encoded form of the designated kek, iff it was in + * RAW format. + * @throws InvalidKeyException if the designated key is not in the RAW format. + */ + private byte[] checkAndGetKekBytes(Key key) throws InvalidKeyException + { + if (! Registry.RAW_ENCODING_SHORT_NAME.equalsIgnoreCase(key.getFormat())) + throw new InvalidKeyException("Only RAW key format is supported"); + byte[] result = key.getEncoded(); + int kekSize = result.length; + if (kekSize != kwaKeySize) + throw new InvalidKeyException("Invalid key material size. Expected " + + kwaKeySize + " but found " + kekSize); + return result; + } + + private void initAlgorithm(int opmode, byte[] kek, byte[] ivBytes, + SecureRandom rnd) + throws InvalidKeyException + { + this.opmode = opmode; + Map attributes = new HashMap(); + attributes.put(IKeyWrappingAlgorithm.KEY_ENCRYPTION_KEY_MATERIAL, kek); + if (ivBytes != null) + { + this.iv = (byte[]) ivBytes.clone(); + attributes.put(IKeyWrappingAlgorithm.INITIAL_VALUE, this.iv); + } + else + this.iv = null; + if (rnd != null) + attributes.put(IKeyWrappingAlgorithm.SOURCE_OF_RANDOMNESS, rnd); + + kwAlgorithm.init(attributes); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/cipher/KhazadSpi.java b/libjava/classpath/gnu/javax/crypto/jce/cipher/KhazadSpi.java new file mode 100644 index 000000000..df0833fb5 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/cipher/KhazadSpi.java @@ -0,0 +1,54 @@ +/* KhazadSpi.java -- + Copyright (C) 2002, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.jce.cipher; + +import gnu.java.security.Registry; + +/** + * The implementation of the Khazad <i>Service Provider Interface</i> + * (<b>SPI</b>) adapter. + */ +public final class KhazadSpi + extends CipherAdapter +{ + public KhazadSpi() + { + super(Registry.KHAZAD_CIPHER); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/cipher/NullCipherSpi.java b/libjava/classpath/gnu/javax/crypto/jce/cipher/NullCipherSpi.java new file mode 100644 index 000000000..70ff575da --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/cipher/NullCipherSpi.java @@ -0,0 +1,54 @@ +/* NullCipherSpi.java -- + Copyright (C) 2002, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.jce.cipher; + +import gnu.java.security.Registry; + +/** + * The implementation of the Null cipher <i>Service Provider Interface</i> + * (<b>SPI</b>) adapter. + */ +public final class NullCipherSpi + extends CipherAdapter +{ + public NullCipherSpi() + { + super(Registry.NULL_CIPHER); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/cipher/PBES2.java b/libjava/classpath/gnu/javax/crypto/jce/cipher/PBES2.java new file mode 100644 index 000000000..9961c15b1 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/cipher/PBES2.java @@ -0,0 +1,1379 @@ +/* PBES2.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.jce.cipher; + +import gnu.javax.crypto.prng.IPBE; +import gnu.java.security.prng.IRandom; +import gnu.java.security.prng.LimitReachedException; +import gnu.javax.crypto.prng.PRNGFactory; + +import java.security.AlgorithmParameters; +import java.security.InvalidAlgorithmParameterException; +import java.security.InvalidKeyException; +import java.security.Key; +import java.security.SecureRandom; +import java.security.spec.AlgorithmParameterSpec; +import java.util.HashMap; + +import javax.crypto.interfaces.PBEKey; +import javax.crypto.spec.SecretKeySpec; + +/** + */ +public abstract class PBES2 + extends CipherAdapter +{ + /** The HMac (PRF) algorithm name. */ + protected String macName; + + protected PBES2(String cipherName, int blockLen, String macName) + { + super(cipherName, blockLen); + this.macName = macName; + } + + protected PBES2(String cipherName, String macName) + { + super(cipherName); + this.macName = macName; + } + + protected void engineInit(int opmode, Key key, SecureRandom random) + throws InvalidKeyException + { + if (! (key instanceof PBEKey)) + throw new InvalidKeyException("not a PBE key"); + super.engineInit(opmode, genkey((PBEKey) key), random); + } + + protected void engineInit(int opmode, Key key, AlgorithmParameterSpec params, + SecureRandom random) throws InvalidKeyException, + InvalidAlgorithmParameterException + { + if (! (key instanceof PBEKey)) + throw new InvalidKeyException("not a PBE key"); + super.engineInit(opmode, genkey((PBEKey) key), params, random); + } + + protected void engineInit(int opmode, Key key, AlgorithmParameters params, + SecureRandom random) throws InvalidKeyException, + InvalidAlgorithmParameterException + { + if (! (key instanceof PBEKey)) + throw new InvalidKeyException("not a PBE key"); + super.engineInit(opmode, genkey((PBEKey) key), params, random); + } + + private SecretKeySpec genkey(PBEKey key) throws InvalidKeyException + { + IRandom kdf = PRNGFactory.getInstance("PBKDF2-" + macName); + if (kdf == null) + throw new IllegalArgumentException("no such KDF: PBKDF2-" + macName); + HashMap attrib = new HashMap(); + attrib.put(IPBE.ITERATION_COUNT, Integer.valueOf(key.getIterationCount())); + attrib.put(IPBE.PASSWORD, key.getPassword()); + attrib.put(IPBE.SALT, key.getSalt()); + try + { + kdf.init(attrib); + } + catch (IllegalArgumentException iae) + { + throw new InvalidKeyException(iae.toString()); + } + byte[] dk = new byte[mode.defaultKeySize()]; + try + { + kdf.nextBytes(dk, 0, dk.length); + } + catch (LimitReachedException shouldNotHappen) + { + throw new Error(String.valueOf(shouldNotHappen)); + } + return new SecretKeySpec(dk, cipher.name()); + } + + public static class HMacSHA1 + extends PBES2 + { + public HMacSHA1(String cipher, int blockLen) + { + super(cipher, blockLen, "HMAC-SHA1"); + } + + public HMacSHA1(String cipher) + { + super(cipher, "HMAC-SHA1"); + } + + public static class AES + extends HMacSHA1 + { + public AES() + { + super("AES"); + } + } + + public static class Anubis + extends HMacSHA1 + { + public Anubis() + { + super("Anubis"); + } + } + + public static class Blowfish + extends HMacSHA1 + { + public Blowfish() + { + super("Blowfish"); + } + } + + public static class Cast5 + extends HMacSHA1 + { + public Cast5() + { + super("Cast5"); + } + } + + public static class DES + extends HMacSHA1 + { + public DES() + { + super("DES"); + } + } + + public static class Khazad + extends HMacSHA1 + { + public Khazad() + { + super("Khazad"); + } + } + + public static class Serpent + extends HMacSHA1 + { + public Serpent() + { + super("Serpent"); + } + } + + public static class Square + extends HMacSHA1 + { + public Square() + { + super("Square"); + } + } + + public static class TripleDES + extends HMacSHA1 + { + public TripleDES() + { + super("TripleDES"); + } + } + + public static class Twofish + extends HMacSHA1 + { + public Twofish() + { + super("Twofish"); + } + } + } + + public static class HMacMD5 + extends PBES2 + { + public HMacMD5(String cipher, int blockLen) + { + super(cipher, blockLen, "HMAC-MD5"); + } + + public HMacMD5(String cipher) + { + super(cipher, "HMAC-MD5"); + } + + public static class AES + extends HMacMD5 + { + public AES() + { + super("AES"); + } + } + + public static class Anubis + extends HMacMD5 + { + public Anubis() + { + super("Anubis"); + } + } + + public static class Blowfish + extends HMacMD5 + { + public Blowfish() + { + super("Blowfish"); + } + } + + public static class Cast5 + extends HMacMD5 + { + public Cast5() + { + super("Cast5"); + } + } + + public static class DES + extends HMacMD5 + { + public DES() + { + super("DES"); + } + } + + public static class Khazad + extends HMacMD5 + { + public Khazad() + { + super("Khazad"); + } + } + + public static class Serpent + extends HMacMD5 + { + public Serpent() + { + super("Serpent"); + } + } + + public static class Square + extends HMacMD5 + { + public Square() + { + super("Square"); + } + } + + public static class TripleDES + extends HMacMD5 + { + public TripleDES() + { + super("TripleDES"); + } + } + + public static class Twofish + extends HMacMD5 + { + public Twofish() + { + super("Twofish"); + } + } + } + + public static class HMacMD2 + extends PBES2 + { + public HMacMD2(String cipher, int blockLen) + { + super(cipher, blockLen, "HMAC-MD2"); + } + + public HMacMD2(String cipher) + { + super(cipher, "HMAC-MD2"); + } + + public static class AES + extends HMacMD2 + { + public AES() + { + super("AES"); + } + } + + public static class Anubis + extends HMacMD2 + { + public Anubis() + { + super("Anubis"); + } + } + + public static class Blowfish + extends HMacMD2 + { + public Blowfish() + { + super("Blowfish"); + } + } + + public static class Cast5 + extends HMacMD2 + { + public Cast5() + { + super("Cast5"); + } + } + + public static class DES + extends HMacMD2 + { + public DES() + { + super("DES"); + } + } + + public static class Khazad + extends HMacMD2 + { + public Khazad() + { + super("Khazad"); + } + } + + public static class Serpent + extends HMacMD2 + { + public Serpent() + { + super("Serpent"); + } + } + + public static class Square + extends HMacMD2 + { + public Square() + { + super("Square"); + } + } + + public static class TripleDES + extends HMacMD2 + { + public TripleDES() + { + super("TripleDES"); + } + } + + public static class Twofish + extends HMacMD2 + { + public Twofish() + { + super("Twofish"); + } + } + } + + public static class HMacMD4 + extends PBES2 + { + public HMacMD4(String cipher, int blockLen) + { + super(cipher, blockLen, "HMAC-MD4"); + } + + public HMacMD4(String cipher) + { + super(cipher, "HMAC-MD4"); + } + + public static class AES + extends HMacMD4 + { + public AES() + { + super("AES"); + } + } + + public static class Anubis + extends HMacMD4 + { + public Anubis() + { + super("Anubis"); + } + } + + public static class Blowfish + extends HMacMD4 + { + public Blowfish() + { + super("Blowfish"); + } + } + + public static class Cast5 + extends HMacMD4 + { + public Cast5() + { + super("Cast5"); + } + } + + public static class DES + extends HMacMD4 + { + public DES() + { + super("DES"); + } + } + + public static class Khazad + extends HMacMD4 + { + public Khazad() + { + super("Khazad"); + } + } + + public static class Serpent + extends HMacMD4 + { + public Serpent() + { + super("Serpent"); + } + } + + public static class Square + extends HMacMD4 + { + public Square() + { + super("Square"); + } + } + + public static class TripleDES + extends HMacMD4 + { + public TripleDES() + { + super("TripleDES"); + } + } + + public static class Twofish + extends HMacMD4 + { + public Twofish() + { + super("Twofish"); + } + } + } + + public static class HMacHaval + extends PBES2 + { + public HMacHaval(String cipher, int blockLen) + { + super(cipher, blockLen, "HMAC-HAVAL"); + } + + public HMacHaval(String cipher) + { + super(cipher, "HMAC-HAVAL"); + } + + public static class AES + extends HMacHaval + { + public AES() + { + super("AES"); + } + } + + public static class Anubis + extends HMacHaval + { + public Anubis() + { + super("Anubis"); + } + } + + public static class Blowfish + extends HMacHaval + { + public Blowfish() + { + super("Blowfish"); + } + } + + public static class Cast5 + extends HMacHaval + { + public Cast5() + { + super("Cast5"); + } + } + + public static class DES + extends HMacHaval + { + public DES() + { + super("DES"); + } + } + + public static class Khazad + extends HMacHaval + { + public Khazad() + { + super("Khazad"); + } + } + + public static class Serpent + extends HMacHaval + { + public Serpent() + { + super("Serpent"); + } + } + + public static class Square + extends HMacHaval + { + public Square() + { + super("Square"); + } + } + + public static class TripleDES + extends HMacHaval + { + public TripleDES() + { + super("TripleDES"); + } + } + + public static class Twofish + extends HMacHaval + { + public Twofish() + { + super("Twofish"); + } + } + } + + public static class HMacRipeMD128 + extends PBES2 + { + public HMacRipeMD128(String cipher, int blockLen) + { + super(cipher, blockLen, "HMAC-RIPEMD128"); + } + + public HMacRipeMD128(String cipher) + { + super(cipher, "HMAC-RIPEMD128"); + } + + public static class AES + extends HMacRipeMD128 + { + public AES() + { + super("AES"); + } + } + + public static class Anubis + extends HMacRipeMD128 + { + public Anubis() + { + super("Anubis"); + } + } + + public static class Blowfish + extends HMacRipeMD128 + { + public Blowfish() + { + super("Blowfish"); + } + } + + public static class Cast5 + extends HMacRipeMD128 + { + public Cast5() + { + super("Cast5"); + } + } + + public static class DES + extends HMacRipeMD128 + { + public DES() + { + super("DES"); + } + } + + public static class Khazad + extends HMacRipeMD128 + { + public Khazad() + { + super("Khazad"); + } + } + + public static class Serpent + extends HMacRipeMD128 + { + public Serpent() + { + super("Serpent"); + } + } + + public static class Square + extends HMacRipeMD128 + { + public Square() + { + super("Square"); + } + } + + public static class TripleDES + extends HMacRipeMD128 + { + public TripleDES() + { + super("TripleDES"); + } + } + + public static class Twofish + extends HMacRipeMD128 + { + public Twofish() + { + super("Twofish"); + } + } + } + + public static class HMacRipeMD160 + extends PBES2 + { + public HMacRipeMD160(String cipher, int blockLen) + { + super(cipher, blockLen, "HMAC-RIPEMD160"); + } + + public HMacRipeMD160(String cipher) + { + super(cipher, "HMAC-RIPEMD160"); + } + + public static class AES + extends HMacRipeMD160 + { + public AES() + { + super("AES"); + } + } + + public static class Anubis + extends HMacRipeMD160 + { + public Anubis() + { + super("Anubis"); + } + } + + public static class Blowfish + extends HMacRipeMD160 + { + public Blowfish() + { + super("Blowfish"); + } + } + + public static class Cast5 + extends HMacRipeMD160 + { + public Cast5() + { + super("Cast5"); + } + } + + public static class DES + extends HMacRipeMD160 + { + public DES() + { + super("DES"); + } + } + + public static class Khazad + extends HMacRipeMD160 + { + public Khazad() + { + super("Khazad"); + } + } + + public static class Serpent + extends HMacRipeMD160 + { + public Serpent() + { + super("Serpent"); + } + } + + public static class Square + extends HMacRipeMD160 + { + public Square() + { + super("Square"); + } + } + + public static class TripleDES + extends HMacRipeMD160 + { + public TripleDES() + { + super("TripleDES"); + } + } + + public static class Twofish + extends HMacRipeMD160 + { + public Twofish() + { + super("Twofish"); + } + } + } + + public static class HMacSHA256 + extends PBES2 + { + public HMacSHA256(String cipher, int blockLen) + { + super(cipher, blockLen, "HMAC-SHA-256"); + } + + public HMacSHA256(String cipher) + { + super(cipher, "HMAC-SHA-256"); + } + + public static class AES + extends HMacSHA256 + { + public AES() + { + super("AES"); + } + } + + public static class Anubis + extends HMacSHA256 + { + public Anubis() + { + super("Anubis"); + } + } + + public static class Blowfish + extends HMacSHA256 + { + public Blowfish() + { + super("Blowfish"); + } + } + + public static class Cast5 + extends HMacSHA256 + { + public Cast5() + { + super("Cast5"); + } + } + + public static class DES + extends HMacSHA256 + { + public DES() + { + super("DES"); + } + } + + public static class Khazad + extends HMacSHA256 + { + public Khazad() + { + super("Khazad"); + } + } + + public static class Serpent + extends HMacSHA256 + { + public Serpent() + { + super("Serpent"); + } + } + + public static class Square + extends HMacSHA256 + { + public Square() + { + super("Square"); + } + } + + public static class TripleDES + extends HMacSHA256 + { + public TripleDES() + { + super("TripleDES"); + } + } + + public static class Twofish + extends HMacSHA256 + { + public Twofish() + { + super("Twofish"); + } + } + } + + public static class HMacSHA384 + extends PBES2 + { + public HMacSHA384(String cipher, int blockLen) + { + super(cipher, blockLen, "HMAC-SHA-384"); + } + + public HMacSHA384(String cipher) + { + super(cipher, "HMAC-SHA-384"); + } + + public static class AES + extends HMacSHA384 + { + public AES() + { + super("AES"); + } + } + + public static class Anubis + extends HMacSHA384 + { + public Anubis() + { + super("Anubis"); + } + } + + public static class Blowfish + extends HMacSHA384 + { + public Blowfish() + { + super("Blowfish"); + } + } + + public static class Cast5 + extends HMacSHA384 + { + public Cast5() + { + super("Cast5"); + } + } + + public static class DES + extends HMacSHA384 + { + public DES() + { + super("DES"); + } + } + + public static class Khazad + extends HMacSHA384 + { + public Khazad() + { + super("Khazad"); + } + } + + public static class Serpent + extends HMacSHA384 + { + public Serpent() + { + super("Serpent"); + } + } + + public static class Square + extends HMacSHA384 + { + public Square() + { + super("Square"); + } + } + + public static class TripleDES + extends HMacSHA384 + { + public TripleDES() + { + super("TripleDES"); + } + } + + public static class Twofish + extends HMacSHA384 + { + public Twofish() + { + super("Twofish"); + } + } + } + + public static class HMacSHA512 + extends PBES2 + { + public HMacSHA512(String cipher, int blockLen) + { + super(cipher, blockLen, "HMAC-SHA-512"); + } + + public HMacSHA512(String cipher) + { + super(cipher, "HMAC-SHA-512"); + } + + public static class AES + extends HMacSHA512 + { + public AES() + { + super("AES"); + } + } + + public static class Anubis + extends HMacSHA512 + { + public Anubis() + { + super("Anubis"); + } + } + + public static class Blowfish + extends HMacSHA512 + { + public Blowfish() + { + super("Blowfish"); + } + } + + public static class Cast5 + extends HMacSHA512 + { + public Cast5() + { + super("Cast5"); + } + } + + public static class DES + extends HMacSHA512 + { + public DES() + { + super("DES"); + } + } + + public static class Khazad + extends HMacSHA512 + { + public Khazad() + { + super("Khazad"); + } + } + + public static class Serpent + extends HMacSHA512 + { + public Serpent() + { + super("Serpent"); + } + } + + public static class Square + extends HMacSHA512 + { + public Square() + { + super("Square"); + } + } + + public static class TripleDES + extends HMacSHA512 + { + public TripleDES() + { + super("TripleDES"); + } + } + + public static class Twofish + extends HMacSHA512 + { + public Twofish() + { + super("Twofish"); + } + } + } + + public static class HMacTiger + extends PBES2 + { + public HMacTiger(String cipher, int blockLen) + { + super(cipher, blockLen, "HMAC-TIGER"); + } + + public HMacTiger(String cipher) + { + super(cipher, "HMAC-TIGER"); + } + + public static class AES + extends HMacTiger + { + public AES() + { + super("AES"); + } + } + + public static class Anubis + extends HMacTiger + { + public Anubis() + { + super("Anubis"); + } + } + + public static class Blowfish + extends HMacTiger + { + public Blowfish() + { + super("Blowfish"); + } + } + + public static class Cast5 + extends HMacTiger + { + public Cast5() + { + super("Cast5"); + } + } + + public static class DES + extends HMacTiger + { + public DES() + { + super("DES"); + } + } + + public static class Khazad + extends HMacTiger + { + public Khazad() + { + super("Khazad"); + } + } + + public static class Serpent + extends HMacTiger + { + public Serpent() + { + super("Serpent"); + } + } + + public static class Square + extends HMacTiger + { + public Square() + { + super("Square"); + } + } + + public static class TripleDES + extends HMacTiger + { + public TripleDES() + { + super("TripleDES"); + } + } + + public static class Twofish + extends HMacTiger + { + public Twofish() + { + super("Twofish"); + } + } + } + + public static class HMacWhirlpool + extends PBES2 + { + public HMacWhirlpool(String cipher, int blockLen) + { + super(cipher, blockLen, "HMAC-WHIRLPOOL"); + } + + public HMacWhirlpool(String cipher) + { + super(cipher, "HMAC-WHIRLPOOL"); + } + + public static class AES + extends HMacWhirlpool + { + public AES() + { + super("AES"); + } + } + + public static class Anubis + extends HMacWhirlpool + { + public Anubis() + { + super("Anubis"); + } + } + + public static class Blowfish + extends HMacWhirlpool + { + public Blowfish() + { + super("Blowfish"); + } + } + + public static class Cast5 + extends HMacWhirlpool + { + public Cast5() + { + super("Cast5"); + } + } + + public static class DES + extends HMacWhirlpool + { + public DES() + { + super("DES"); + } + } + + public static class Khazad + extends HMacWhirlpool + { + public Khazad() + { + super("Khazad"); + } + } + + public static class Serpent + extends HMacWhirlpool + { + public Serpent() + { + super("Serpent"); + } + } + + public static class Square + extends HMacWhirlpool + { + public Square() + { + super("Square"); + } + } + + public static class TripleDES + extends HMacWhirlpool + { + public TripleDES() + { + super("TripleDES"); + } + } + + public static class Twofish + extends HMacWhirlpool + { + public Twofish() + { + super("Twofish"); + } + } + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/cipher/RijndaelSpi.java b/libjava/classpath/gnu/javax/crypto/jce/cipher/RijndaelSpi.java new file mode 100644 index 000000000..f25aca028 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/cipher/RijndaelSpi.java @@ -0,0 +1,54 @@ +/* RijndaelSpi.java -- + Copyright (C) 2002, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.jce.cipher; + +import gnu.java.security.Registry; + +/** + * The implementation of the Rijndael <i>Service Provider Interface</i> + * (<b>SPI</b>) adapter. + */ +public final class RijndaelSpi + extends CipherAdapter +{ + public RijndaelSpi() + { + super(Registry.RIJNDAEL_CIPHER, 16); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/cipher/SerpentSpi.java b/libjava/classpath/gnu/javax/crypto/jce/cipher/SerpentSpi.java new file mode 100644 index 000000000..1f17b18c8 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/cipher/SerpentSpi.java @@ -0,0 +1,54 @@ +/* SerpentSpi.java -- + Copyright (C) 2002, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.jce.cipher; + +import gnu.java.security.Registry; + +/** + * The implementation of the Serpent <i>Service Provider Interface</i> + * (<b>SPI</b>) adapter. + */ +public final class SerpentSpi + extends CipherAdapter +{ + public SerpentSpi() + { + super(Registry.SERPENT_CIPHER); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/cipher/SquareSpi.java b/libjava/classpath/gnu/javax/crypto/jce/cipher/SquareSpi.java new file mode 100644 index 000000000..d08aa2cd3 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/cipher/SquareSpi.java @@ -0,0 +1,54 @@ +/* SquareSpi.java -- + Copyright (C) 2002, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.jce.cipher; + +import gnu.java.security.Registry; + +/** + * The implementation of the Square <i>Service Provider Interface</i> + * (<b>SPI</b>) adapter. + */ +public final class SquareSpi + extends CipherAdapter +{ + public SquareSpi() + { + super(Registry.SQUARE_CIPHER); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/cipher/TripleDESKeyWrapSpi.java b/libjava/classpath/gnu/javax/crypto/jce/cipher/TripleDESKeyWrapSpi.java new file mode 100644 index 000000000..55087755e --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/cipher/TripleDESKeyWrapSpi.java @@ -0,0 +1,54 @@ +/* TripleDESKeyWrapSpi.java -- DES-EDE Key Wrapping Algorithm JCE Adapter + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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; either version 2, or (at your option) +any later version. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.jce.cipher; + +import gnu.java.security.Registry; + +/** + * The JCE Cipher Adapter implementation over the GNU TripleDES Key Wrapping + * Algorithm. + */ +public final class TripleDESKeyWrapSpi + extends KeyWrappingAlgorithmAdapter +{ + public TripleDESKeyWrapSpi() + { + super(Registry.TRIPLEDES_KWA, 8, 192 / 8, Registry.CBC_MODE); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/cipher/TripleDESSpi.java b/libjava/classpath/gnu/javax/crypto/jce/cipher/TripleDESSpi.java new file mode 100644 index 000000000..c22409020 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/cipher/TripleDESSpi.java @@ -0,0 +1,54 @@ +/* TripleDESSpi.java -- + Copyright (C) 2002, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.jce.cipher; + +import gnu.java.security.Registry; + +/** + * The implementation of the Triple-DES <i>Service Provider Interface</i> + * (<b>SPI</b>) adapter. + */ +public final class TripleDESSpi + extends CipherAdapter +{ + public TripleDESSpi() + { + super(Registry.TRIPLEDES_CIPHER); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/cipher/TwofishSpi.java b/libjava/classpath/gnu/javax/crypto/jce/cipher/TwofishSpi.java new file mode 100644 index 000000000..a1bbe4b71 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/cipher/TwofishSpi.java @@ -0,0 +1,54 @@ +/* TwofishSpi.java -- + Copyright (C) 2002, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.jce.cipher; + +import gnu.java.security.Registry; + +/** + * The implementation of the Twofish <i>Service Provider Interface</i> + * (<b>SPI</b>) adapter. + */ +public final class TwofishSpi + extends CipherAdapter +{ + public TwofishSpi() + { + super(Registry.TWOFISH_CIPHER); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/key/AnubisKeyGeneratorImpl.java b/libjava/classpath/gnu/javax/crypto/jce/key/AnubisKeyGeneratorImpl.java new file mode 100644 index 000000000..a1cc8fd7f --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/key/AnubisKeyGeneratorImpl.java @@ -0,0 +1,50 @@ +/* AnubisKeyGeneratorImpl.java -- Anubis key generator. + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.jce.key; + +import gnu.java.security.Registry; + +public class AnubisKeyGeneratorImpl + extends SecretKeyGeneratorImpl +{ + public AnubisKeyGeneratorImpl() + { + super(Registry.ANUBIS_CIPHER); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/key/AnubisSecretKeyFactoryImpl.java b/libjava/classpath/gnu/javax/crypto/jce/key/AnubisSecretKeyFactoryImpl.java new file mode 100644 index 000000000..dc99b332b --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/key/AnubisSecretKeyFactoryImpl.java @@ -0,0 +1,47 @@ +/* AnubisSecretKeyFactoryImpl.java -- + Copyright (C) 2004, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.jce.key; + +public class AnubisSecretKeyFactoryImpl + extends SecretKeyFactoryImpl +{ + public AnubisSecretKeyFactoryImpl() + { + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/key/BlowfishKeyGeneratorImpl.java b/libjava/classpath/gnu/javax/crypto/jce/key/BlowfishKeyGeneratorImpl.java new file mode 100644 index 000000000..2297980fb --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/key/BlowfishKeyGeneratorImpl.java @@ -0,0 +1,50 @@ +/* BlowfishKeyGeneratorImpl.java -- Blowfish key generator. + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.jce.key; + +import gnu.java.security.Registry; + +public class BlowfishKeyGeneratorImpl + extends SecretKeyGeneratorImpl +{ + public BlowfishKeyGeneratorImpl() + { + super(Registry.BLOWFISH_CIPHER); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/key/BlowfishSecretKeyFactoryImpl.java b/libjava/classpath/gnu/javax/crypto/jce/key/BlowfishSecretKeyFactoryImpl.java new file mode 100644 index 000000000..8d964bb96 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/key/BlowfishSecretKeyFactoryImpl.java @@ -0,0 +1,47 @@ +/* BlowfishSecretKeyFactoryImpl.java -- + Copyright (C) 2004, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.jce.key; + +public class BlowfishSecretKeyFactoryImpl + extends SecretKeyFactoryImpl +{ + public BlowfishSecretKeyFactoryImpl() + { + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/key/Cast5KeyGeneratorImpl.java b/libjava/classpath/gnu/javax/crypto/jce/key/Cast5KeyGeneratorImpl.java new file mode 100644 index 000000000..b328e48b3 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/key/Cast5KeyGeneratorImpl.java @@ -0,0 +1,50 @@ +/* Cast5KeyGeneratorImpl.java -- CAST-5 key generator. + Copyright (C) 2004, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.jce.key; + +import gnu.java.security.Registry; + +public class Cast5KeyGeneratorImpl + extends SecretKeyGeneratorImpl +{ + public Cast5KeyGeneratorImpl() + { + super(Registry.CAST5_CIPHER); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/key/Cast5SecretKeyFactoryImpl.java b/libjava/classpath/gnu/javax/crypto/jce/key/Cast5SecretKeyFactoryImpl.java new file mode 100644 index 000000000..f2681eda1 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/key/Cast5SecretKeyFactoryImpl.java @@ -0,0 +1,47 @@ +/* Cast5SecretKeyFactoryImpl.java -- + Copyright (C) 2004, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.jce.key; + +public class Cast5SecretKeyFactoryImpl + extends SecretKeyFactoryImpl +{ + public Cast5SecretKeyFactoryImpl() + { + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/key/DESKeyGeneratorImpl.java b/libjava/classpath/gnu/javax/crypto/jce/key/DESKeyGeneratorImpl.java new file mode 100644 index 000000000..2cd29a67f --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/key/DESKeyGeneratorImpl.java @@ -0,0 +1,68 @@ +/* DESKeyGeneratorImpl.java -- DES key generator. + Copyright (C) 2004, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.jce.key; + +import gnu.java.security.Registry; +import gnu.javax.crypto.cipher.DES; + +import javax.crypto.SecretKey; +import javax.crypto.spec.SecretKeySpec; + +public class DESKeyGeneratorImpl + extends SecretKeyGeneratorImpl +{ + public DESKeyGeneratorImpl() + { + super(Registry.DES_CIPHER); + } + + protected SecretKey engineGenerateKey() + { + if (! init) + throw new IllegalStateException("not initialized"); + byte[] buf = new byte[currentKeySize]; + do + { + random.nextBytes(buf); + } + while (DES.isWeak(buf) || DES.isSemiWeak(buf)); + DES.adjustParity(buf, 0); + return new SecretKeySpec(buf, algorithm); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/key/DESSecretKeyFactoryImpl.java b/libjava/classpath/gnu/javax/crypto/jce/key/DESSecretKeyFactoryImpl.java new file mode 100644 index 000000000..a138e2902 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/key/DESSecretKeyFactoryImpl.java @@ -0,0 +1,82 @@ +/* DESSecretKeyFactoryImpl.java -- DES key factory. + Copyright (C) 2004, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.jce.key; + +import java.security.InvalidKeyException; +import java.security.spec.InvalidKeySpecException; +import java.security.spec.KeySpec; + +import javax.crypto.SecretKey; +import javax.crypto.spec.DESKeySpec; +import javax.crypto.spec.SecretKeySpec; + +public class DESSecretKeyFactoryImpl + extends SecretKeyFactoryImpl +{ + + public DESSecretKeyFactoryImpl() + { + } + + protected SecretKey engineGenerateSecret(KeySpec spec) + throws InvalidKeySpecException + { + if (spec instanceof DESKeySpec) + return new SecretKeySpec(((DESKeySpec) spec).getKey(), "DES"); + return super.engineGenerateSecret(spec); + } + + protected KeySpec engineGetKeySpec(SecretKey key, Class spec) + throws InvalidKeySpecException + { + if (spec.isAssignableFrom(DESKeySpec.class)) + try + { + return new DESKeySpec(key.getEncoded()); + } + catch (InvalidKeyException ike) + { + InvalidKeySpecException ikse = new InvalidKeySpecException( + "can't create DES key spec"); + ikse.initCause(ike); + throw ikse; + } + return super.engineGetKeySpec(key, spec); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/key/DESedeSecretKeyFactoryImpl.java b/libjava/classpath/gnu/javax/crypto/jce/key/DESedeSecretKeyFactoryImpl.java new file mode 100644 index 000000000..f380603e4 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/key/DESedeSecretKeyFactoryImpl.java @@ -0,0 +1,82 @@ +/* DESedeSecretKeyFactoryImpl.java -- DESede key factory. + Copyright (C) 2004, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.jce.key; + +import java.security.InvalidKeyException; +import java.security.spec.InvalidKeySpecException; +import java.security.spec.KeySpec; + +import javax.crypto.SecretKey; +import javax.crypto.spec.DESedeKeySpec; +import javax.crypto.spec.SecretKeySpec; + +public class DESedeSecretKeyFactoryImpl + extends SecretKeyFactoryImpl +{ + + public DESedeSecretKeyFactoryImpl() + { + } + + protected SecretKey engineGenerateSecret(KeySpec spec) + throws InvalidKeySpecException + { + if (spec instanceof DESedeKeySpec) + return new SecretKeySpec(((DESedeKeySpec) spec).getKey(), "DESede"); + return super.engineGenerateSecret(spec); + } + + protected KeySpec engineGetKeySpec(SecretKey key, Class spec) + throws InvalidKeySpecException + { + if (spec.equals(DESedeKeySpec.class)) + try + { + return new DESedeKeySpec(key.getEncoded()); + } + catch (InvalidKeyException ike) + { + InvalidKeySpecException ikse = new InvalidKeySpecException( + "can't create DESede key spec"); + ikse.initCause(ike); + throw ikse; + } + return super.engineGetKeySpec(key, spec); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/key/KhazadKeyGeneratorImpl.java b/libjava/classpath/gnu/javax/crypto/jce/key/KhazadKeyGeneratorImpl.java new file mode 100644 index 000000000..21ae627eb --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/key/KhazadKeyGeneratorImpl.java @@ -0,0 +1,50 @@ +/* KhazadKeyGeneratorImpl.java -- Khazad key generator. + Copyright (C) 2004, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.jce.key; + +import gnu.java.security.Registry; + +public class KhazadKeyGeneratorImpl + extends SecretKeyGeneratorImpl +{ + public KhazadKeyGeneratorImpl() + { + super(Registry.KHAZAD_CIPHER); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/key/KhazadSecretKeyFactoryImpl.java b/libjava/classpath/gnu/javax/crypto/jce/key/KhazadSecretKeyFactoryImpl.java new file mode 100644 index 000000000..19315d22e --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/key/KhazadSecretKeyFactoryImpl.java @@ -0,0 +1,47 @@ +/* KhazadSecretKeyFactoryImpl.java -- simple byte array-wrapping factory. + Copyright (C) 2004, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.jce.key; + +public class KhazadSecretKeyFactoryImpl + extends SecretKeyFactoryImpl +{ + public KhazadSecretKeyFactoryImpl() + { + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/key/RijndaelKeyGeneratorImpl.java b/libjava/classpath/gnu/javax/crypto/jce/key/RijndaelKeyGeneratorImpl.java new file mode 100644 index 000000000..b60f7d6d0 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/key/RijndaelKeyGeneratorImpl.java @@ -0,0 +1,50 @@ +/* RijndaelKeyGeneratorImpl.java -- Rijndael key generator. + Copyright (C) 2004, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.jce.key; + +import gnu.java.security.Registry; + +public class RijndaelKeyGeneratorImpl + extends SecretKeyGeneratorImpl +{ + public RijndaelKeyGeneratorImpl() + { + super(Registry.RIJNDAEL_CIPHER); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/key/RijndaelSecretKeyFactoryImpl.java b/libjava/classpath/gnu/javax/crypto/jce/key/RijndaelSecretKeyFactoryImpl.java new file mode 100644 index 000000000..f88b07752 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/key/RijndaelSecretKeyFactoryImpl.java @@ -0,0 +1,47 @@ +/* RijndaelSecretKeyFactoryImpl.java -- simple byte array-wrapping factory. + Copyright (C) 2004, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.jce.key; + +public class RijndaelSecretKeyFactoryImpl + extends SecretKeyFactoryImpl +{ + public RijndaelSecretKeyFactoryImpl() + { + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/key/SecretKeyFactoryImpl.java b/libjava/classpath/gnu/javax/crypto/jce/key/SecretKeyFactoryImpl.java new file mode 100644 index 000000000..4bba171f9 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/key/SecretKeyFactoryImpl.java @@ -0,0 +1,87 @@ +/* SecretKeyFactoryImpl.java -- simple byte array-wrapping factory. + Copyright (C) 2004, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.jce.key; + +import java.security.InvalidKeyException; +import java.security.spec.InvalidKeySpecException; +import java.security.spec.KeySpec; + +import javax.crypto.SecretKey; +import javax.crypto.SecretKeyFactorySpi; +import javax.crypto.spec.SecretKeySpec; + +public abstract class SecretKeyFactoryImpl + extends SecretKeyFactorySpi +{ + + protected SecretKeyFactoryImpl() + { + } + + protected SecretKey engineGenerateSecret(KeySpec spec) + throws InvalidKeySpecException + { + if (spec instanceof SecretKeySpec) + return (SecretKey) spec; + throw new InvalidKeySpecException("unknown key spec: " + + spec.getClass().getName()); + } + + protected KeySpec engineGetKeySpec(SecretKey key, Class spec) + throws InvalidKeySpecException + { + if (spec.equals(SecretKeySpec.class)) + { + if (key instanceof SecretKeySpec) + return (KeySpec) key; + else + return new SecretKeySpec(key.getEncoded(), key.getAlgorithm()); + } + throw new InvalidKeySpecException("unsupported key spec: " + spec.getName()); + } + + protected SecretKey engineTranslateKey(SecretKey key) + throws InvalidKeyException + { + if (! "RAW".equals(key.getFormat())) + throw new InvalidKeyException("only raw keys are supported"); + // SecretKeySpec is good enough for our purposes. + return new SecretKeySpec(key.getEncoded(), key.getAlgorithm()); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/key/SecretKeyGeneratorImpl.java b/libjava/classpath/gnu/javax/crypto/jce/key/SecretKeyGeneratorImpl.java new file mode 100644 index 000000000..d2acf8716 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/key/SecretKeyGeneratorImpl.java @@ -0,0 +1,111 @@ +/* SecretKeyGeneratorImpl.java -- symmetric key pair generator. + Copyright (C) 2004, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.jce.key; + +import gnu.javax.crypto.cipher.CipherFactory; +import gnu.javax.crypto.cipher.IBlockCipher; + +import java.security.InvalidAlgorithmParameterException; +import java.security.InvalidParameterException; +import java.security.SecureRandom; +import java.security.spec.AlgorithmParameterSpec; + +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; + +import javax.crypto.KeyGeneratorSpi; +import javax.crypto.SecretKey; +import javax.crypto.spec.SecretKeySpec; + +public class SecretKeyGeneratorImpl + extends KeyGeneratorSpi +{ + protected final int defaultKeySize; + protected final List keySizes; + protected final String algorithm; + protected boolean init; + protected int currentKeySize; + protected SecureRandom random; + + protected SecretKeyGeneratorImpl(final String algorithm) + { + this.algorithm = algorithm; + IBlockCipher cipher = CipherFactory.getInstance(algorithm); + if (cipher == null) + throw new IllegalArgumentException("no such cipher: " + algorithm); + defaultKeySize = cipher.defaultKeySize(); + keySizes = new LinkedList(); + for (Iterator it = cipher.keySizes(); it.hasNext();) + keySizes.add(it.next()); + init = false; + } + + protected SecretKey engineGenerateKey() + { + if (! init) + throw new IllegalStateException("not initialized"); + byte[] buf = new byte[currentKeySize]; + random.nextBytes(buf); + return new SecretKeySpec(buf, algorithm); + } + + protected void engineInit(AlgorithmParameterSpec params, SecureRandom random) + throws InvalidAlgorithmParameterException + { + throw new InvalidAlgorithmParameterException( + algorithm + " does not support algorithm paramaters"); + } + + protected void engineInit(int keySize, SecureRandom random) + { + keySize >>>= 3; // Use bytes. + if (! keySizes.contains(Integer.valueOf(keySize))) + throw new InvalidParameterException("unsupported key size: " + keySize + + ", valid sizes are: " + keySizes); + currentKeySize = keySize; + this.random = random; + init = true; + } + + protected void engineInit(SecureRandom random) + { + engineInit(defaultKeySize << 3, random); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/key/SerpentKeyGeneratorImpl.java b/libjava/classpath/gnu/javax/crypto/jce/key/SerpentKeyGeneratorImpl.java new file mode 100644 index 000000000..c53190514 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/key/SerpentKeyGeneratorImpl.java @@ -0,0 +1,50 @@ +/* SerpentKeyGeneratorImpl.java -- Serpent key generator. + Copyright (C) 2004, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.jce.key; + +import gnu.java.security.Registry; + +public class SerpentKeyGeneratorImpl + extends SecretKeyGeneratorImpl +{ + public SerpentKeyGeneratorImpl() + { + super(Registry.SERPENT_CIPHER); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/key/SerpentSecretKeyFactoryImpl.java b/libjava/classpath/gnu/javax/crypto/jce/key/SerpentSecretKeyFactoryImpl.java new file mode 100644 index 000000000..5d5ac88df --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/key/SerpentSecretKeyFactoryImpl.java @@ -0,0 +1,47 @@ +/* SerpentSecretKeyFactoryImpl.java -- simple byte array-wrapping factory. + Copyright (C) 2004, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.jce.key; + +public class SerpentSecretKeyFactoryImpl + extends SecretKeyFactoryImpl +{ + public SerpentSecretKeyFactoryImpl() + { + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/key/SquareKeyGeneratorImpl.java b/libjava/classpath/gnu/javax/crypto/jce/key/SquareKeyGeneratorImpl.java new file mode 100644 index 000000000..3d496e8a9 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/key/SquareKeyGeneratorImpl.java @@ -0,0 +1,50 @@ +/* SquareKeyGeneratorImpl.java -- Square key generator. + Copyright (C) 2004, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.jce.key; + +import gnu.java.security.Registry; + +public class SquareKeyGeneratorImpl + extends SecretKeyGeneratorImpl +{ + public SquareKeyGeneratorImpl() + { + super(Registry.SQUARE_CIPHER); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/key/SquareSecretKeyFactoryImpl.java b/libjava/classpath/gnu/javax/crypto/jce/key/SquareSecretKeyFactoryImpl.java new file mode 100644 index 000000000..f35835912 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/key/SquareSecretKeyFactoryImpl.java @@ -0,0 +1,47 @@ +/* SquareSecretKeyFactoryImpl.java -- simple byte array-wrapping factory. + Copyright (C) 2004, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.jce.key; + +public class SquareSecretKeyFactoryImpl + extends SecretKeyFactoryImpl +{ + public SquareSecretKeyFactoryImpl() + { + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/key/TripleDESKeyGeneratorImpl.java b/libjava/classpath/gnu/javax/crypto/jce/key/TripleDESKeyGeneratorImpl.java new file mode 100644 index 000000000..6fd557ccb --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/key/TripleDESKeyGeneratorImpl.java @@ -0,0 +1,50 @@ +/* TripleDESKeyGeneratorImpl.java -- TripleDES key generator. + Copyright (C) 2004, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.jce.key; + +import gnu.java.security.Registry; + +public class TripleDESKeyGeneratorImpl + extends SecretKeyGeneratorImpl +{ + public TripleDESKeyGeneratorImpl() + { + super(Registry.TRIPLEDES_CIPHER); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/key/TwofishKeyGeneratorImpl.java b/libjava/classpath/gnu/javax/crypto/jce/key/TwofishKeyGeneratorImpl.java new file mode 100644 index 000000000..9dd5a8f30 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/key/TwofishKeyGeneratorImpl.java @@ -0,0 +1,50 @@ +/* TwofishKeyGeneratorImpl.java -- Twofish key generator. + Copyright (C) 2004, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.jce.key; + +import gnu.java.security.Registry; + +public class TwofishKeyGeneratorImpl + extends SecretKeyGeneratorImpl +{ + public TwofishKeyGeneratorImpl() + { + super(Registry.TWOFISH_CIPHER); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/key/TwofishSecretKeyFactoryImpl.java b/libjava/classpath/gnu/javax/crypto/jce/key/TwofishSecretKeyFactoryImpl.java new file mode 100644 index 000000000..0767d4cac --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/key/TwofishSecretKeyFactoryImpl.java @@ -0,0 +1,47 @@ +/* TwofishSecretKeyFactoryImpl.java -- simple byte array-wrapping factory. + Copyright (C) 2004, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.jce.key; + +public class TwofishSecretKeyFactoryImpl + extends SecretKeyFactoryImpl +{ + public TwofishSecretKeyFactoryImpl() + { + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/keyring/GnuKeyring.java b/libjava/classpath/gnu/javax/crypto/jce/keyring/GnuKeyring.java new file mode 100644 index 000000000..c30da69a2 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/keyring/GnuKeyring.java @@ -0,0 +1,507 @@ +/* GnuKeyring.java -- KeyStore adapter for a pair of private and public Keyrings + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.jce.keyring; + +import gnu.java.security.Configuration; +import gnu.java.security.Registry; +import gnu.javax.crypto.keyring.GnuPrivateKeyring; +import gnu.javax.crypto.keyring.GnuPublicKeyring; +import gnu.javax.crypto.keyring.IKeyring; +import gnu.javax.crypto.keyring.IPrivateKeyring; +import gnu.javax.crypto.keyring.IPublicKeyring; +import gnu.javax.crypto.keyring.MalformedKeyringException; +import gnu.javax.crypto.keyring.PrimitiveEntry; + +import java.io.BufferedInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.security.Key; +import java.security.KeyStoreException; +import java.security.KeyStoreSpi; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.security.UnrecoverableKeyException; +import java.security.cert.Certificate; +import java.util.Collections; +import java.util.Date; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Set; +import java.util.logging.Logger; + +import javax.crypto.SecretKey; + +/** + * An <i>Adapter</i> over a pair of one private, and one public keyrings to + * emulate the keystore operations. + */ +public class GnuKeyring + extends KeyStoreSpi +{ + private static final Logger log = Logger.getLogger(GnuKeyring.class.getName()); + private static final String NOT_LOADED = "not loaded"; + + /** TRUE if the keystore is loaded; FALSE otherwise. */ + private boolean loaded; + /** our underlying private keyring. */ + private IPrivateKeyring privateKR; + /** our underlying public keyring. */ + private IPublicKeyring publicKR; + + // default 0-arguments constructor + + public Enumeration engineAliases() + { + if (Configuration.DEBUG) + log.entering(this.getClass().getName(), "engineAliases"); + ensureLoaded(); + Enumeration result; + if (privateKR == null) + result = Collections.enumeration(Collections.EMPTY_SET); + else + { + Set aliases = new HashSet(); + for (Enumeration e = privateKR.aliases(); e.hasMoreElements();) + { + String alias = (String) e.nextElement(); + if (alias != null) + { + alias = alias.trim(); + if (alias.length() > 0) + { + if (Configuration.DEBUG) + log.fine("Adding alias (from private keyring): " + alias); + aliases.add(alias); + } + } + } + for (Enumeration e = publicKR.aliases(); e.hasMoreElements();) + { + String alias = (String) e.nextElement(); + if (alias != null) + { + alias = alias.trim(); + if (alias.length() > 0) + { + if (Configuration.DEBUG) + log.fine("Adding alias (from public keyring): " + alias); + aliases.add(alias); + } + } + } + if (Configuration.DEBUG) + log.fine("Will enumerate: " + aliases); + result = Collections.enumeration(aliases); + } + if (Configuration.DEBUG) + log.exiting(this.getClass().getName(), "engineAliases"); + return result; + } + + public boolean engineContainsAlias(String alias) + { + if (Configuration.DEBUG) + log.entering(this.getClass().getName(), "engineContainsAlias", alias); + ensureLoaded(); + boolean inPrivateKR = privateKR.containsAlias(alias); + if (Configuration.DEBUG) + log.fine("inPrivateKR=" + inPrivateKR); + boolean inPublicKR = publicKR.containsAlias(alias); + if (Configuration.DEBUG) + log.fine("inPublicKR=" + inPublicKR); + boolean result = inPrivateKR || inPublicKR; + if (Configuration.DEBUG) + log.exiting(this.getClass().getName(), "engineContainsAlias", + Boolean.valueOf(result)); + return result; + } + + public void engineDeleteEntry(String alias) + { + if (Configuration.DEBUG) + log.entering(this.getClass().getName(), "engineDeleteEntry", alias); + ensureLoaded(); + if (privateKR.containsAlias(alias)) + privateKR.remove(alias); + else if (publicKR.containsAlias(alias)) + publicKR.remove(alias); + else if (Configuration.DEBUG) + log.fine("Unknwon alias: " + alias); + if (Configuration.DEBUG) + log.exiting(this.getClass().getName(), "engineDeleteEntry"); + } + + public Certificate engineGetCertificate(String alias) + { + if (Configuration.DEBUG) + log.entering(this.getClass().getName(), "engineGetCertificate", alias); + ensureLoaded(); + Certificate result = publicKR.getCertificate(alias); + if (Configuration.DEBUG) + log.exiting(this.getClass().getName(), "engineGetCertificate", result); + return result; + } + + public String engineGetCertificateAlias(Certificate cert) + { + if (Configuration.DEBUG) + log.entering(this.getClass().getName(), "engineGetCertificateAlias", cert); + ensureLoaded(); + String result = null; + for (Enumeration aliases = publicKR.aliases(); aliases.hasMoreElements();) + { + String alias = (String) aliases.nextElement(); + Certificate cert2 = publicKR.getCertificate(alias); + if (cert.equals(cert2)) + { + result = alias; + break; + } + } + if (Configuration.DEBUG) + log.exiting(this.getClass().getName(), "engineGetCertificateAlias", result); + return result; + } + + public void engineSetCertificateEntry(String alias, Certificate cert) + throws KeyStoreException + { + if (Configuration.DEBUG) + log.entering(this.getClass().getName(), "engineSetCertificateEntry", + new Object[] { alias, cert }); + ensureLoaded(); + if (privateKR.containsAlias(alias)) + throw new KeyStoreException("Alias [" + alias + + "] already exists and DOES NOT identify a " + + "Trusted Certificate Entry"); + if (publicKR.containsCertificate(alias)) + { + if (Configuration.DEBUG) + log.fine("Public keyring already contains Alias [" + alias + + "]. Will remove it"); + publicKR.remove(alias); + } + publicKR.putCertificate(alias, cert); + if (Configuration.DEBUG) + log.exiting(this.getClass().getName(), "engineSetCertificateEntry"); + } + + public Certificate[] engineGetCertificateChain(String alias) + { + if (Configuration.DEBUG) + log.entering(this.getClass().getName(), "engineGetCertificateChain", alias); + ensureLoaded(); + Certificate[] result = privateKR.getCertPath(alias); + if (Configuration.DEBUG) + log.exiting(this.getClass().getName(), "engineGetCertificateChain", result); + return result; + } + + public Date engineGetCreationDate(String alias) + { + if (Configuration.DEBUG) + log.entering(this.getClass().getName(), "engineGetCreationDate", alias); + ensureLoaded(); + Date result = getCreationDate(alias, privateKR); + if (result == null) + result = getCreationDate(alias, publicKR); + + if (Configuration.DEBUG) + log.exiting(this.getClass().getName(), "engineGetCreationDate", result); + return result; + } + + public Key engineGetKey(String alias, char[] password) + throws UnrecoverableKeyException + { + if (Configuration.DEBUG) + log.entering(this.getClass().getName(), "engineGetKey", alias); + ensureLoaded(); + Key result = null; + if (password == null) + { + if (privateKR.containsPublicKey(alias)) + result = privateKR.getPublicKey(alias); + } + else if (privateKR.containsPrivateKey(alias)) + result = privateKR.getPrivateKey(alias, password); + + if (Configuration.DEBUG) + log.exiting(this.getClass().getName(), "engineGetKey", + result == null ? "null" : result.getClass().getName()); + return result; + } + + public void engineSetKeyEntry(String alias, Key key, char[] password, + Certificate[] chain) + throws KeyStoreException + { + if (Configuration.DEBUG) + log.entering(this.getClass().getName(), "engineSetKeyEntry", + new Object[] { alias, key.getClass().getName(), chain }); + ensureLoaded(); + if (publicKR.containsAlias(alias)) + throw new KeyStoreException("Alias [" + alias + + "] already exists and DOES NOT identify a " + + "Key Entry"); + if (key instanceof PublicKey) + { + privateKR.remove(alias); + PublicKey pk = (PublicKey) key; + privateKR.putPublicKey(alias, pk); + } + else + { + if (! (key instanceof PrivateKey) && ! (key instanceof SecretKey)) + throw new KeyStoreException("cannot store keys of type " + + key.getClass().getName()); + privateKR.remove(alias); + privateKR.putCertPath(alias, chain); + if (Configuration.DEBUG) + log.fine("About to put private key in keyring..."); + privateKR.putPrivateKey(alias, key, password); + } + if (Configuration.DEBUG) + log.exiting(this.getClass().getName(), "engineSetKeyEntry"); + } + + public void engineSetKeyEntry(String alias, byte[] key, Certificate[] chain) + throws KeyStoreException + { + KeyStoreException x = new KeyStoreException("method not supported"); + if (Configuration.DEBUG) + log.throwing(this.getClass().getName(), "engineSetKeyEntry(3)", x); + throw x; + } + + public boolean engineIsCertificateEntry(String alias) + { + if (Configuration.DEBUG) + log.entering(this.getClass().getName(), "engineIsCertificateEntry", alias); + ensureLoaded(); + boolean result = publicKR.containsCertificate(alias); + if (Configuration.DEBUG) + log.exiting(this.getClass().getName(), "engineIsCertificateEntry", + Boolean.valueOf(result)); + return result; + } + + public boolean engineIsKeyEntry(String alias) + { + if (Configuration.DEBUG) + log.entering(this.getClass().getName(), "engineIsKeyEntry", alias); + ensureLoaded(); + boolean result = privateKR.containsPublicKey(alias) + || privateKR.containsPrivateKey(alias); + if (Configuration.DEBUG) + log.exiting(this.getClass().getName(), "engineIsKeyEntry", + Boolean.valueOf(result)); + return result; + } + + public void engineLoad(InputStream in, char[] password) throws IOException + { + if (Configuration.DEBUG) + log.entering(this.getClass().getName(), "engineLoad"); + if (in != null) + { + if (! in.markSupported()) + in = new BufferedInputStream(in); + + loadPrivateKeyring(in, password); + loadPublicKeyring(in, password); + } + else + createNewKeyrings(); + + loaded = true; + if (Configuration.DEBUG) + log.exiting(this.getClass().getName(), "engineLoad"); + } + + public void engineStore(OutputStream out, char[] password) throws IOException + { + if (Configuration.DEBUG) + log.entering(this.getClass().getName(), "engineStore"); + ensureLoaded(); + HashMap attr = new HashMap(); + attr.put(IKeyring.KEYRING_DATA_OUT, out); + attr.put(IKeyring.KEYRING_PASSWORD, password); + + privateKR.store(attr); + publicKR.store(attr); + if (Configuration.DEBUG) + log.exiting(this.getClass().getName(), "engineStore"); + } + + public int engineSize() + { + if (Configuration.DEBUG) + log.entering(this.getClass().getName(), "engineSize"); + int result = 0; + for (Enumeration e = engineAliases(); e.hasMoreElements(); result++) + e.nextElement(); + + if (Configuration.DEBUG) + log.exiting(this.getClass().getName(), "engineSize", Integer.valueOf(result)); + return result; + } + + /** + * Ensure that the underlying keyring pair is loaded. Throw an exception if it + * isn't; otherwise returns silently. + * + * @throws IllegalStateException if the keyring is not loaded. + */ + private void ensureLoaded() + { + if (! loaded) + throw new IllegalStateException(NOT_LOADED); + } + + /** + * Load the private keyring from the designated input stream. + * + * @param in the input stream to process. + * @param password the password protecting the keyring. + * @throws MalformedKeyringException if the keyring is not a private one. + * @throws IOException if an I/O related exception occurs during the process. + */ + private void loadPrivateKeyring(InputStream in, char[] password) + throws MalformedKeyringException, IOException + { + if (Configuration.DEBUG) + log.entering(this.getClass().getName(), "loadPrivateKeyring"); + in.mark(5); + for (int i = 0; i < 4; i++) + if (in.read() != Registry.GKR_MAGIC[i]) + throw new MalformedKeyringException("incorrect magic"); + + int usage = in.read(); + in.reset(); + if (usage != GnuPrivateKeyring.USAGE) + throw new MalformedKeyringException( + "Was expecting a private keyring but got a wrong USAGE: " + + Integer.toBinaryString(usage)); + HashMap attr = new HashMap(); + attr.put(IKeyring.KEYRING_DATA_IN, in); + attr.put(IKeyring.KEYRING_PASSWORD, password); + privateKR = new GnuPrivateKeyring(); + privateKR.load(attr); + if (Configuration.DEBUG) + log.exiting(this.getClass().getName(), "loadPrivateKeyring"); + } + + /** + * Load the public keyring from the designated input stream. + * + * @param in the input stream to process. + * @param password the password protecting the keyring. + * @throws MalformedKeyringException if the keyring is not a public one. + * @throws IOException if an I/O related exception occurs during the process. + */ + private void loadPublicKeyring(InputStream in, char[] password) + throws MalformedKeyringException, IOException + { + if (Configuration.DEBUG) + log.entering(this.getClass().getName(), "loadPublicKeyring"); + in.mark(5); + for (int i = 0; i < 4; i++) + if (in.read() != Registry.GKR_MAGIC[i]) + throw new MalformedKeyringException("incorrect magic"); + + int usage = in.read(); + in.reset(); + if (usage != GnuPublicKeyring.USAGE) + throw new MalformedKeyringException( + "Was expecting a public keyring but got a wrong USAGE: " + + Integer.toBinaryString(usage)); + HashMap attr = new HashMap(); + attr.put(IKeyring.KEYRING_DATA_IN, in); + attr.put(IKeyring.KEYRING_PASSWORD, password); + publicKR = new GnuPublicKeyring(); + publicKR.load(attr); + if (Configuration.DEBUG) + log.exiting(this.getClass().getName(), "loadPublicKeyring"); + } + + /** + * Return the creation date of a named alias in a designated keyring. + * + * @param alias the alias to look for. + * @param keyring the keyring to search. + * @return the creattion date of the entry named <code>alias</code>. Return + * <code>null</code> if <code>alias</code> was not found in + * <code>keyring</code>. + */ + private Date getCreationDate(String alias, IKeyring keyring) + { + if (Configuration.DEBUG) + log.entering(this.getClass().getName(), "getCreationDate", + new Object[] { alias, keyring }); + Date result = null; + if (keyring != null) + for (Iterator it = keyring.get(alias).iterator(); it.hasNext();) + { + Object o = it.next(); + if (o instanceof PrimitiveEntry) + { + result = ((PrimitiveEntry) o).getCreationDate(); + break; + } + } + if (Configuration.DEBUG) + log.exiting(this.getClass().getName(), "getCreationDate", result); + return result; + } + + /** Create empty keyrings. */ + private void createNewKeyrings() + { + if (Configuration.DEBUG) + log.entering(this.getClass().getName(), "createNewKeyrings"); + privateKR = new GnuPrivateKeyring("HMAC-SHA-1", 20, "AES", "OFB", 16); + publicKR = new GnuPublicKeyring("HMAC-SHA-1", 20); + if (Configuration.DEBUG) + log.exiting(this.getClass().getName(), "createNewKeyrings"); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/mac/HMacHavalSpi.java b/libjava/classpath/gnu/javax/crypto/jce/mac/HMacHavalSpi.java new file mode 100644 index 000000000..fc5f3b578 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/mac/HMacHavalSpi.java @@ -0,0 +1,54 @@ +/* HMacHavalSpi.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.jce.mac; + +import gnu.java.security.Registry; + +/** + * The implementation of the HMAC-HAVAL <i>Service Provider Interface</i> + * (<b>SPI</b>) Adapter. + */ +public class HMacHavalSpi + extends MacAdapter +{ + public HMacHavalSpi() + { + super(Registry.HMAC_NAME_PREFIX + Registry.HAVAL_HASH); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/mac/HMacMD2Spi.java b/libjava/classpath/gnu/javax/crypto/jce/mac/HMacMD2Spi.java new file mode 100644 index 000000000..c50feb8cf --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/mac/HMacMD2Spi.java @@ -0,0 +1,54 @@ +/* HMacMD2Spi.java -- + Copyright (C) 2002, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.jce.mac; + +import gnu.java.security.Registry; + +/** + * The implementation of the HMAC-MD2 <i>Service Provider Interface</i> + * (<b>SPI</b>) adapter. + */ +public final class HMacMD2Spi + extends MacAdapter +{ + public HMacMD2Spi() + { + super(Registry.HMAC_NAME_PREFIX + Registry.MD2_HASH); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/mac/HMacMD4Spi.java b/libjava/classpath/gnu/javax/crypto/jce/mac/HMacMD4Spi.java new file mode 100644 index 000000000..c0eae5b22 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/mac/HMacMD4Spi.java @@ -0,0 +1,54 @@ +/* HMacMD4Spi.java -- + Copyright (C) 2002, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.jce.mac; + +import gnu.java.security.Registry; + +/** + * The implementation of the HMAC-MD4 <i>Service Provider Interface</i> + * (<b>SPI</b>) adapter. + */ +public final class HMacMD4Spi + extends MacAdapter +{ + public HMacMD4Spi() + { + super(Registry.HMAC_NAME_PREFIX + Registry.MD4_HASH); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/mac/HMacMD5Spi.java b/libjava/classpath/gnu/javax/crypto/jce/mac/HMacMD5Spi.java new file mode 100644 index 000000000..78e884761 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/mac/HMacMD5Spi.java @@ -0,0 +1,54 @@ +/* HMacMD5Spi.java -- + Copyright (C) 2002, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.jce.mac; + +import gnu.java.security.Registry; + +/** + * The implementation of the HMAC-MD5 <i>Service Provider Interface</i> + * (<b>SPI</b>) adapter. + */ +public final class HMacMD5Spi + extends MacAdapter +{ + public HMacMD5Spi() + { + super(Registry.HMAC_NAME_PREFIX + Registry.MD5_HASH); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/mac/HMacRipeMD128Spi.java b/libjava/classpath/gnu/javax/crypto/jce/mac/HMacRipeMD128Spi.java new file mode 100644 index 000000000..b5835177c --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/mac/HMacRipeMD128Spi.java @@ -0,0 +1,54 @@ +/* HMacRipeMD128Spi.java -- + Copyright (C) 2002, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.jce.mac; + +import gnu.java.security.Registry; + +/** + * The implementation of the HMAC-RIPEMD-128 <i>Service Provider Interface</i> + * (<b>SPI</b>) adapter. + */ +public final class HMacRipeMD128Spi + extends MacAdapter +{ + public HMacRipeMD128Spi() + { + super(Registry.HMAC_NAME_PREFIX + Registry.RIPEMD128_HASH); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/mac/HMacRipeMD160Spi.java b/libjava/classpath/gnu/javax/crypto/jce/mac/HMacRipeMD160Spi.java new file mode 100644 index 000000000..4d7c6caec --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/mac/HMacRipeMD160Spi.java @@ -0,0 +1,54 @@ +/* HMacRipeMD160Spi.java -- + Copyright (C) 2002, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.jce.mac; + +import gnu.java.security.Registry; + +/** + * The implementation of the HMAC-RIPEMD-160 <i>Service Provider Interface</i> + * (<b>SPI</b>) adapter. + */ +public final class HMacRipeMD160Spi + extends MacAdapter +{ + public HMacRipeMD160Spi() + { + super(Registry.HMAC_NAME_PREFIX + Registry.RIPEMD160_HASH); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/mac/HMacSHA160Spi.java b/libjava/classpath/gnu/javax/crypto/jce/mac/HMacSHA160Spi.java new file mode 100644 index 000000000..1c7c9443d --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/mac/HMacSHA160Spi.java @@ -0,0 +1,54 @@ +/* HMacSHA160Spi.java -- + Copyright (C) 2002, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.jce.mac; + +import gnu.java.security.Registry; + +/** + * The implementation of the HMAC-SHA-160 <i>Service Provider Interface</i> + * (<b>SPI</b>) adapter. + */ +public final class HMacSHA160Spi + extends MacAdapter +{ + public HMacSHA160Spi() + { + super(Registry.HMAC_NAME_PREFIX + Registry.SHA160_HASH); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/mac/HMacSHA256Spi.java b/libjava/classpath/gnu/javax/crypto/jce/mac/HMacSHA256Spi.java new file mode 100644 index 000000000..7d7c91de6 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/mac/HMacSHA256Spi.java @@ -0,0 +1,54 @@ +/* HMacSHA256Spi.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.jce.mac; + +import gnu.java.security.Registry; + +/** + * The implementation of the HMAC-SHA-256 <i>Service Provider Interface</i> + * (<b>SPI</b>) adapter. + */ +public final class HMacSHA256Spi + extends MacAdapter +{ + public HMacSHA256Spi() + { + super(Registry.HMAC_NAME_PREFIX + Registry.SHA256_HASH); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/mac/HMacSHA384Spi.java b/libjava/classpath/gnu/javax/crypto/jce/mac/HMacSHA384Spi.java new file mode 100644 index 000000000..b66b0f0f3 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/mac/HMacSHA384Spi.java @@ -0,0 +1,54 @@ +/* HMacSHA384Spi.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.jce.mac; + +import gnu.java.security.Registry; + +/** + * The implementation of the HMAC-SHA-384 <i>Service Provider Interface</i> + * (<b>SPI</b>) adapter. + */ +public class HMacSHA384Spi + extends MacAdapter +{ + public HMacSHA384Spi() + { + super(Registry.HMAC_NAME_PREFIX + Registry.SHA384_HASH); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/mac/HMacSHA512Spi.java b/libjava/classpath/gnu/javax/crypto/jce/mac/HMacSHA512Spi.java new file mode 100644 index 000000000..c825a14e9 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/mac/HMacSHA512Spi.java @@ -0,0 +1,54 @@ +/* HMacSHA512Spi.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.jce.mac; + +import gnu.java.security.Registry; + +/** + * The implementation of the HMAC-SHA-512 <i>Service Provider Interface</i> + * (<b>SPI</b>) adapter. + */ +public class HMacSHA512Spi + extends MacAdapter +{ + public HMacSHA512Spi() + { + super(Registry.HMAC_NAME_PREFIX + Registry.SHA512_HASH); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/mac/HMacTigerSpi.java b/libjava/classpath/gnu/javax/crypto/jce/mac/HMacTigerSpi.java new file mode 100644 index 000000000..0d979f08f --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/mac/HMacTigerSpi.java @@ -0,0 +1,54 @@ +/* HMacTigerSpi.java -- + Copyright (C) 2002, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.jce.mac; + +import gnu.java.security.Registry; + +/** + * The implementation of the Tiger <i>Service Provider Interface</i> + * (<b>SPI</b>) adapter. + */ +public final class HMacTigerSpi + extends MacAdapter +{ + public HMacTigerSpi() + { + super(Registry.HMAC_NAME_PREFIX + Registry.TIGER_HASH); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/mac/HMacWhirlpoolSpi.java b/libjava/classpath/gnu/javax/crypto/jce/mac/HMacWhirlpoolSpi.java new file mode 100644 index 000000000..6dde69b7e --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/mac/HMacWhirlpoolSpi.java @@ -0,0 +1,54 @@ +/* HMacWhirlpoolSpi.java -- + Copyright (C) 2002, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.jce.mac; + +import gnu.java.security.Registry; + +/** + * The implementation of the HMAC-Whirlpool <i>Service Provider Interface</i> + * (<b>SPI</b>) adapter. + */ +public final class HMacWhirlpoolSpi + extends MacAdapter +{ + public HMacWhirlpoolSpi() + { + super(Registry.HMAC_NAME_PREFIX + Registry.WHIRLPOOL_HASH); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/mac/MacAdapter.java b/libjava/classpath/gnu/javax/crypto/jce/mac/MacAdapter.java new file mode 100644 index 000000000..cb3d934fa --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/mac/MacAdapter.java @@ -0,0 +1,136 @@ +/* MacAdapter.java -- + Copyright (C) 2002, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.jce.mac; + +import gnu.javax.crypto.mac.IMac; +import gnu.javax.crypto.mac.MacFactory; + +import java.security.InvalidAlgorithmParameterException; +import java.security.InvalidKeyException; +import java.security.Key; +import java.security.spec.AlgorithmParameterSpec; +import java.util.HashMap; +import java.util.Map; +import javax.crypto.MacSpi; + +/** + * The implementation of a generic {@link javax.crypto.Mac} adapter class to + * wrap GNU MAC instances. + * <p> + * This class defines the <i>Service Provider Interface</i> (<b>SPI</b>) for + * the {@link javax.crypto.Mac} class, which provides the functionality of a + * message authentication code algorithm, such as the <i>Hashed Message + * Authentication Code</i> (<b>HMAC</b>) algorithms. + */ +class MacAdapter + extends MacSpi + implements Cloneable +{ + /** Our MAC instance. */ + protected IMac mac; + /** Our MAC attributes. */ + protected Map attributes; + + /** + * Creates a new Mac instance for the given name. + * + * @param name The name of the mac to create. + */ + protected MacAdapter(String name) + { + mac = MacFactory.getInstance(name); + attributes = new HashMap(); + } + + /** + * Private constructor for cloning purposes. + * + * @param mac a clone of the internal {@link IMac} instance. + * @param attributes a clone of the current {@link Map} of attributes. + */ + private MacAdapter(IMac mac, Map attributes) + { + super(); + + this.mac = mac; + this.attributes = attributes; + } + + public Object clone() throws CloneNotSupportedException + { + return new MacAdapter((IMac) mac.clone(), new HashMap(attributes)); + } + + protected byte[] engineDoFinal() + { + byte[] result = mac.digest(); + engineReset(); + return result; + } + + protected int engineGetMacLength() + { + return mac.macSize(); + } + + protected void engineInit(Key key, AlgorithmParameterSpec params) + throws InvalidKeyException, InvalidAlgorithmParameterException + { + if (! key.getFormat().equalsIgnoreCase("RAW")) + throw new InvalidKeyException("unknown key format " + key.getFormat()); + attributes.put(IMac.MAC_KEY_MATERIAL, key.getEncoded()); + mac.reset(); + mac.init(attributes); + } + + protected void engineReset() + { + mac.reset(); + } + + protected void engineUpdate(byte b) + { + mac.update(b); + } + + protected void engineUpdate(byte[] in, int off, int len) + { + mac.update(in, off, len); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/mac/OMacAnubisImpl.java b/libjava/classpath/gnu/javax/crypto/jce/mac/OMacAnubisImpl.java new file mode 100644 index 000000000..566e56fd1 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/mac/OMacAnubisImpl.java @@ -0,0 +1,50 @@ +/* OMacAnubisImpl.java -- OMAC-ANUBIS adapter. + Copyright (C) 2004, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.jce.mac; + +import gnu.java.security.Registry; + +public class OMacAnubisImpl + extends MacAdapter +{ + public OMacAnubisImpl() + { + super(Registry.OMAC_PREFIX + Registry.ANUBIS_CIPHER); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/mac/OMacBlowfishImpl.java b/libjava/classpath/gnu/javax/crypto/jce/mac/OMacBlowfishImpl.java new file mode 100644 index 000000000..55768166f --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/mac/OMacBlowfishImpl.java @@ -0,0 +1,50 @@ +/* OMacBlowfishImpl.java -- OMAC-BLOWFISH adapter. + Copyright (C) 2004, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.jce.mac; + +import gnu.java.security.Registry; + +public class OMacBlowfishImpl + extends MacAdapter +{ + public OMacBlowfishImpl() + { + super(Registry.OMAC_PREFIX + Registry.BLOWFISH_CIPHER); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/mac/OMacCast5Impl.java b/libjava/classpath/gnu/javax/crypto/jce/mac/OMacCast5Impl.java new file mode 100644 index 000000000..535352c39 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/mac/OMacCast5Impl.java @@ -0,0 +1,50 @@ +/* OMacCast5Impl.java -- OMAC-CAST5 adapter. + Copyright (C) 2004, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.jce.mac; + +import gnu.java.security.Registry; + +public class OMacCast5Impl + extends MacAdapter +{ + public OMacCast5Impl() + { + super(Registry.OMAC_PREFIX + Registry.CAST5_CIPHER); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/mac/OMacDESImpl.java b/libjava/classpath/gnu/javax/crypto/jce/mac/OMacDESImpl.java new file mode 100644 index 000000000..a01c0ac87 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/mac/OMacDESImpl.java @@ -0,0 +1,50 @@ +/* OMacDESImpl.java -- OMAC-DES adapter. + Copyright (C) 2004, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.jce.mac; + +import gnu.java.security.Registry; + +public class OMacDESImpl + extends MacAdapter +{ + public OMacDESImpl() + { + super(Registry.OMAC_PREFIX + Registry.DES_CIPHER); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/mac/OMacImpl.java b/libjava/classpath/gnu/javax/crypto/jce/mac/OMacImpl.java new file mode 100644 index 000000000..960c68aaf --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/mac/OMacImpl.java @@ -0,0 +1,140 @@ +/* OMacImpl.java -- OMAC adapter. + Copyright (C) 2004, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.jce.mac; + +import gnu.java.security.Registry; + +public abstract class OMacImpl + extends MacAdapter +{ + protected OMacImpl(String name) + { + super(Registry.OMAC_PREFIX + name); + } + + public class Anubis + extends OMacImpl + { + public Anubis() + { + super(Registry.ANUBIS_CIPHER); + } + } + + public class Blowfish + extends OMacImpl + { + public Blowfish() + { + super(Registry.BLOWFISH_CIPHER); + } + } + + public class Cast5 + extends OMacImpl + { + public Cast5() + { + super(Registry.CAST5_CIPHER); + } + } + + public class DES + extends OMacImpl + { + public DES() + { + super(Registry.DES_CIPHER); + } + } + + public class Khazad + extends OMacImpl + { + public Khazad() + { + super(Registry.KHAZAD_CIPHER); + } + } + + public class Rijndael + extends OMacImpl + { + public Rijndael() + { + super(Registry.RIJNDAEL_CIPHER); + } + } + + public class Serpent + extends OMacImpl + { + public Serpent() + { + super(Registry.SERPENT_CIPHER); + } + } + + public class Square + extends OMacImpl + { + public Square() + { + super(Registry.SQUARE_CIPHER); + } + } + + public class TripleDES + extends OMacImpl + { + public TripleDES() + { + super(Registry.TRIPLEDES_CIPHER); + } + } + + public class Twofish + extends OMacImpl + { + public Twofish() + { + super(Registry.TWOFISH_CIPHER); + } + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/mac/OMacKhazadImpl.java b/libjava/classpath/gnu/javax/crypto/jce/mac/OMacKhazadImpl.java new file mode 100644 index 000000000..c349f9f5e --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/mac/OMacKhazadImpl.java @@ -0,0 +1,50 @@ +/* OMacKhazadImpl.java -- OMAC-KHAZAD adapter. + Copyright (C) 2004, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.jce.mac; + +import gnu.java.security.Registry; + +public class OMacKhazadImpl + extends MacAdapter +{ + public OMacKhazadImpl() + { + super(Registry.OMAC_PREFIX + Registry.KHAZAD_CIPHER); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/mac/OMacRijndaelImpl.java b/libjava/classpath/gnu/javax/crypto/jce/mac/OMacRijndaelImpl.java new file mode 100644 index 000000000..d63b777a3 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/mac/OMacRijndaelImpl.java @@ -0,0 +1,50 @@ +/* OMacRijndaelImpl.java -- OMAC-RIJNDAEL adapter. + Copyright (C) 2004, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.jce.mac; + +import gnu.java.security.Registry; + +public class OMacRijndaelImpl + extends MacAdapter +{ + public OMacRijndaelImpl() + { + super(Registry.OMAC_PREFIX + Registry.RIJNDAEL_CIPHER); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/mac/OMacSerpentImpl.java b/libjava/classpath/gnu/javax/crypto/jce/mac/OMacSerpentImpl.java new file mode 100644 index 000000000..5c1b8a9b9 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/mac/OMacSerpentImpl.java @@ -0,0 +1,50 @@ +/* OMacSerpentImpl.java -- OMAC-SERPENT adapter. + Copyright (C) 2004, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.jce.mac; + +import gnu.java.security.Registry; + +public class OMacSerpentImpl + extends MacAdapter +{ + public OMacSerpentImpl() + { + super(Registry.OMAC_PREFIX + Registry.SERPENT_CIPHER); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/mac/OMacSquareImpl.java b/libjava/classpath/gnu/javax/crypto/jce/mac/OMacSquareImpl.java new file mode 100644 index 000000000..c9d1b1aca --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/mac/OMacSquareImpl.java @@ -0,0 +1,50 @@ +/* OMacSquareImpl.java -- OMAC-SQUARE adapter. + Copyright (C) 2004, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.jce.mac; + +import gnu.java.security.Registry; + +public class OMacSquareImpl + extends MacAdapter +{ + public OMacSquareImpl() + { + super(Registry.OMAC_PREFIX + Registry.SQUARE_CIPHER); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/mac/OMacTripleDESImpl.java b/libjava/classpath/gnu/javax/crypto/jce/mac/OMacTripleDESImpl.java new file mode 100644 index 000000000..4f58723d3 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/mac/OMacTripleDESImpl.java @@ -0,0 +1,50 @@ +/* OMacTripleDESImpl.java -- OMAC-TRIPLEDES adapter. + Copyright (C) 2004, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.jce.mac; + +import gnu.java.security.Registry; + +public class OMacTripleDESImpl + extends MacAdapter +{ + public OMacTripleDESImpl() + { + super(Registry.OMAC_PREFIX + Registry.TRIPLEDES_CIPHER); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/mac/OMacTwofishImpl.java b/libjava/classpath/gnu/javax/crypto/jce/mac/OMacTwofishImpl.java new file mode 100644 index 000000000..4c816a096 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/mac/OMacTwofishImpl.java @@ -0,0 +1,50 @@ +/* OMacTwofishImpl.java -- OMAC-TWOFISH adapter. + Copyright (C) 2004, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.jce.mac; + +import gnu.java.security.Registry; + +public class OMacTwofishImpl + extends MacAdapter +{ + public OMacTwofishImpl() + { + super(Registry.OMAC_PREFIX + Registry.TWOFISH_CIPHER); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/mac/TMMH16Spi.java b/libjava/classpath/gnu/javax/crypto/jce/mac/TMMH16Spi.java new file mode 100644 index 000000000..d610cc0c2 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/mac/TMMH16Spi.java @@ -0,0 +1,81 @@ +/* TMMH16Spi.java -- + Copyright (C) 2002, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.jce.mac; + +import gnu.java.security.Registry; +import gnu.javax.crypto.mac.TMMH16; +import gnu.javax.crypto.jce.spec.TMMHParameterSpec; + +import java.security.InvalidAlgorithmParameterException; +import java.security.InvalidKeyException; +import java.security.Key; +import java.security.spec.AlgorithmParameterSpec; + +/** + * The implementation of the TMMH16 <i>Service Provider Interface</i> + * (<b>SPI</b>) adapter. + */ +public final class TMMH16Spi + extends MacAdapter +{ + public TMMH16Spi() + { + super(Registry.TMMH16); + } + + protected void engineInit(Key key, AlgorithmParameterSpec params) + throws InvalidKeyException, InvalidAlgorithmParameterException + { + if (! (params instanceof TMMHParameterSpec)) + throw new InvalidAlgorithmParameterException(); + TMMHParameterSpec spec = (TMMHParameterSpec) params; + attributes.put(TMMH16.TAG_LENGTH, spec.getTagLength()); + attributes.put(TMMH16.KEYSTREAM, spec.getKeystream()); + attributes.put(TMMH16.PREFIX, spec.getPrefix()); + try + { + mac.reset(); + mac.init(attributes); + } + catch (IllegalArgumentException iae) + { + throw new InvalidAlgorithmParameterException(iae.getMessage()); + } + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/mac/UHash32Spi.java b/libjava/classpath/gnu/javax/crypto/jce/mac/UHash32Spi.java new file mode 100644 index 000000000..c6784d633 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/mac/UHash32Spi.java @@ -0,0 +1,54 @@ +/* UHash32Spi.java -- + Copyright (C) 2002, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.jce.mac; + +import gnu.java.security.Registry; + +/** + * The implementation of the UHash-32 <i>Service Provider Interface</i> + * (<b>SPI</b>) adapter. + */ +public final class UHash32Spi + extends MacAdapter +{ + public UHash32Spi() + { + super(Registry.UHASH32); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/mac/UMac32Spi.java b/libjava/classpath/gnu/javax/crypto/jce/mac/UMac32Spi.java new file mode 100644 index 000000000..85c859c38 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/mac/UMac32Spi.java @@ -0,0 +1,79 @@ +/* UMac32Spi.java -- + Copyright (C) 2002, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.jce.mac; + +import gnu.java.security.Registry; +import gnu.javax.crypto.mac.UMac32; +import gnu.javax.crypto.jce.spec.UMac32ParameterSpec; + +import java.security.InvalidAlgorithmParameterException; +import java.security.InvalidKeyException; +import java.security.Key; +import java.security.spec.AlgorithmParameterSpec; + +/** + * The implementation of the UMAC-32 <i>Service Provider Interface</i> + * (<b>SPI</b>) adapter. + */ +public final class UMac32Spi + extends MacAdapter +{ + public UMac32Spi() + { + super(Registry.UMAC32); + } + + protected void engineInit(Key key, AlgorithmParameterSpec params) + throws InvalidKeyException, InvalidAlgorithmParameterException + { + if (! (params instanceof UMac32ParameterSpec)) + throw new InvalidAlgorithmParameterException(); + if (params != null) + attributes.put(UMac32.NONCE_MATERIAL, + ((UMac32ParameterSpec) params).getNonce()); + try + { + super.engineInit(key, null); + } + catch (IllegalArgumentException iae) + { + throw new InvalidAlgorithmParameterException(iae.getMessage()); + } + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/params/BlockCipherParameters.java b/libjava/classpath/gnu/javax/crypto/jce/params/BlockCipherParameters.java new file mode 100644 index 000000000..fde83b1f3 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/params/BlockCipherParameters.java @@ -0,0 +1,149 @@ +/* BlockCipherParameters.java -- + Copyright (C) 2002, 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.jce.params; + +import gnu.java.security.Configuration; +import gnu.javax.crypto.jce.spec.BlockCipherParameterSpec; + +import java.io.IOException; +import java.math.BigInteger; + +import java.security.AlgorithmParametersSpi; +import java.security.spec.AlgorithmParameterSpec; +import java.security.spec.InvalidParameterSpecException; +import java.util.logging.Logger; + +import javax.crypto.spec.IvParameterSpec; + +/** + * An implementation of algorithm parameters for the GNU block ciphers. This + * encompasses the cipher's block size, its key size, and an optional + * initialization vector (IV). + */ +public class BlockCipherParameters + extends AlgorithmParametersSpi +{ + private static final Logger log = Logger.getLogger(BlockCipherParameters.class.getName()); + /** The underlying block cipher specification. */ + protected BlockCipherParameterSpec cipherSpec; + private static final String DEFAULT_FORMAT = "ASN.1"; + + /** + * Return these parameters encoded in ASN.1 (DER). + * <p> + * For GNU block ciphers we will define these parameters as + * <pre> + * BlockCipherParameters ::= SEQUENCE { + * blockSize INTEGER, + * keySize INTEGER, + * initializationVector OCTET STRING OPTIONAL } + * </pre> + * + * @return The parameters, encoded an an ASN.1 DER sequence. + * @throws java.io.IOException If encoding these parameters fails. + */ + protected byte[] engineGetEncoded() throws IOException + { + return engineGetEncoded(DEFAULT_FORMAT); + } + + protected byte[] engineGetEncoded(String format) throws IOException + { + if (! format.equalsIgnoreCase(DEFAULT_FORMAT) + && ! format.equalsIgnoreCase("asn1")) + throw new IOException("unknown format \"" + format + "\""); + DERWriter writer = new DERWriter(); + int cipherBlockSize = cipherSpec.getBlockSize(); + int cipherKeySize = cipherSpec.getKeySize(); + byte[] iv = cipherSpec.getIV(); + return writer.joinarrays( + writer.writeBigInteger(BigInteger.valueOf(cipherBlockSize)), + writer.writeBigInteger(BigInteger.valueOf(cipherKeySize)), + (iv != null) ? writer.writeBigInteger(new BigInteger(iv)) + : new byte[0]); + } + + protected void engineInit(AlgorithmParameterSpec spec) + throws InvalidParameterSpecException + { + if (spec instanceof BlockCipherParameterSpec) + cipherSpec = (BlockCipherParameterSpec) spec; + else + throw new InvalidParameterSpecException(); + } + + protected void engineInit(byte[] encoded, String format) throws IOException + { + if (! format.equalsIgnoreCase(DEFAULT_FORMAT) + && ! format.equalsIgnoreCase("ASN1")) + throw new IOException("invalid format: only accepts ASN.1"); + engineInit(encoded); + } + + protected void engineInit(byte[] encoded) throws IOException + { + DERReader reader = new DERReader(encoded); + int bs = reader.getBigInteger().intValue(); + int ks = reader.getBigInteger().intValue(); + byte[] iv = null; + if (reader.hasMorePrimitives()) + iv = reader.getBigInteger().toByteArray(); + cipherSpec = new BlockCipherParameterSpec(iv, bs, ks); + if (Configuration.DEBUG) + log.fine("cipherSpec: " + cipherSpec); + } + + protected AlgorithmParameterSpec engineGetParameterSpec(Class c) + throws InvalidParameterSpecException + { + if (c.isInstance(cipherSpec)) + return cipherSpec; + if (IvParameterSpec.class.isAssignableFrom(c)) + { + IvParameterSpec result = new IvParameterSpec(cipherSpec.getIV()); + return result; + } + throw new InvalidParameterSpecException(); + } + + protected String engineToString() + { + return cipherSpec.toString(); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/params/DEREncodingException.java b/libjava/classpath/gnu/javax/crypto/jce/params/DEREncodingException.java new file mode 100644 index 000000000..436f5d4cd --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/params/DEREncodingException.java @@ -0,0 +1,54 @@ +/* DEREncodingException.java -- + Copyright (C) 1999, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.jce.params; + +class DEREncodingException + extends java.io.IOException +{ + + public DEREncodingException() + { + super(); + } + + public DEREncodingException(String msg) + { + super(msg); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/params/DERReader.java b/libjava/classpath/gnu/javax/crypto/jce/params/DERReader.java new file mode 100644 index 000000000..9fc1e2cd7 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/params/DERReader.java @@ -0,0 +1,139 @@ +/* DERReader.java -- + Copyright (C) 1999, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.jce.params; + +import java.math.BigInteger; + +class DERReader +{ + byte source[]; + int pos; + static final int UNIVERSAL = 1; + static final int APPLICATION = 2; + static final int CONTEXT_SPECIFIC = 3; + static final int PRIVATE = 4; + + public DERReader() + { + source = null; + pos = 0; + } + + public DERReader(byte source[]) + { + init(source); + } + + public void init(String source) + { + init(source.getBytes()); + } + + public void init(byte source[]) + { + this.source = source; + pos = 0; + } + + public boolean hasMorePrimitives() + { + return pos < source.length; + } + + public BigInteger getBigInteger() throws DEREncodingException + { + return new BigInteger(getPrimitive()); + } + + // Reads Primitive, definite-length method + private byte[] getPrimitive() throws DEREncodingException + { + int tmp = pos; + // Read Identifier + byte identifier = source[tmp++]; + if ((0x20 & identifier) != 0) + throw new DEREncodingException(); + int type = translateLeadIdentifierByte(identifier); + // get tag + int tag = (0x1f & identifier); + // get length + byte len = source[tmp]; // may be length of length parameter + long length = 0x7f & len; + int i; + if ((0x80 & len) != 0) + { + len &= 0x7f; + // get length here + length = 0; + for (i = 0; i < len; i++) + { + tmp++; + length <<= 8; + length += (source[tmp] < 0) ? (256 + source[tmp]) : source[tmp]; + } + tmp++; + } + else + tmp++; + + byte tmpb[] = new byte[(int) length]; + System.arraycopy(source, tmp, tmpb, 0, (int) length); + pos = (int) (tmp + length); + return tmpb; + } + + private int translateLeadIdentifierByte(byte b) + { + if ((0x3f & b) == b) + return UNIVERSAL; + else if ((0x7f & b) == b) + return APPLICATION; + else if ((0xbf & b) == b) + return CONTEXT_SPECIFIC; + else + return PRIVATE; + } + + private int getIdentifier(int tpos) + { + while ((0x80 & source[tpos]) != 0) + tpos++; + return tpos; + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/params/DERWriter.java b/libjava/classpath/gnu/javax/crypto/jce/params/DERWriter.java new file mode 100644 index 000000000..7553e20d2 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/params/DERWriter.java @@ -0,0 +1,143 @@ +/* DERWriter.java -- + Copyright (C) 1999, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.jce.params; + +import java.math.BigInteger; + +class DERWriter +{ + static final int UNIVERSAL = 1; + static final int APPLICATION = 2; + static final int CONTEXT_SPECIFIC = 3; + static final int PRIVATE = 4; + + public DERWriter() + { + } + + public byte[] writeBigInteger(BigInteger i) + { + return writePrimitive(0x02, + UNIVERSAL, + (int) Math.ceil((double) i.bitLength() / 8), + i.toByteArray()); + } + + private byte[] writePrimitive(int identifier, int identifierencoding, + int length, byte contents[]) + { + return joinarrays(generateIdentifier(identifier, identifierencoding), + generateLength(length), contents); + } + + public byte[] joinarrays(byte a[], byte b[]) + { + byte d[] = new byte[a.length + b.length]; + System.arraycopy(a, 0, d, 0, a.length); + System.arraycopy(b, 0, d, a.length, b.length); + return d; + } + + public byte[] joinarrays(byte a[], byte b[], byte c[]) + { + byte d[] = new byte[a.length + b.length + c.length]; + System.arraycopy(a, 0, d, 0, a.length); + System.arraycopy(b, 0, d, a.length, b.length); + System.arraycopy(c, 0, d, a.length + b.length, c.length); + return d; + } + + private byte[] generateIdentifier(int identifier, int identifierencoding) + { + byte b[]; + if (identifier > 31) + { + int count = (int) (Math.log(identifier) / Math.log(256)); + b = new byte[count + 1]; + b[0] = (byte)(translateLeadIdentifierByte(identifierencoding) | 0x1f); + int i; + for (i = 1; i < (count + 1); i++) + { + b[i] = (byte) (0x7f & (identifier >> (7 * (count - i)))); + b[i] |= 0x80; + } + b[i - 1] ^= 0x80; + return b; + } + else + { + b = new byte[1]; + b[0] = (byte)((translateLeadIdentifierByte(identifierencoding) + | (byte)(identifier & 0x1f)) & 0xdf); + return b; + } + } + + private byte translateLeadIdentifierByte(int b) + { + if (b == UNIVERSAL) + return (byte) 0x3f; + else if (b == APPLICATION) + return (byte) 0x7f; + else if (b == CONTEXT_SPECIFIC) + return (byte) 0xbf; + else + return (byte) 0xC0; + } + + private byte[] generateLength(int length) + { + byte b[]; + if (length > 127) + { + int count = (int) Math.ceil(Math.log(length) / Math.log(256)); + b = new byte[count + 1]; + b[0] = (byte)((count & 0x7f) | 0x80); + for (int i = 1; i < (count + 1); i++) + b[i] = (byte) (length >>> (8 * (count - i))); + return b; + } + else + { + b = new byte[1]; + b[0] = (byte) (length & 0x7f); + return b; + } + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/prng/ARCFourRandomSpi.java b/libjava/classpath/gnu/javax/crypto/jce/prng/ARCFourRandomSpi.java new file mode 100644 index 000000000..3816fb648 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/prng/ARCFourRandomSpi.java @@ -0,0 +1,102 @@ +/* ARCFourRandomSpi.java -- + Copyright (C) 2002, 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.jce.prng; + +import gnu.java.security.Registry; + +import gnu.java.security.jce.prng.SecureRandomAdapter; + +import gnu.java.security.prng.IRandom; +import gnu.java.security.prng.LimitReachedException; + +import gnu.javax.crypto.prng.ARCFour; +import gnu.javax.crypto.prng.PRNGFactory; + +import java.security.SecureRandomSpi; + +import java.util.HashMap; + +/** + * Implementation of the <i>Service Provider Interface</i> (<b>SPI</b>) for + * the ARCFOUR keystream generator. + */ +public class ARCFourRandomSpi + extends SecureRandomSpi +{ + /** Our underlying prng instance. */ + private IRandom adaptee; + /** Have we been initialized? */ + private boolean virgin; + + /** + * Default 0-arguments constructor. + */ + public ARCFourRandomSpi() + { + super(); + adaptee = PRNGFactory.getInstance(Registry.ARCFOUR_PRNG); + virgin = true; + } + + public byte[] engineGenerateSeed(int numBytes) + { + return SecureRandomAdapter.getSeed(numBytes); + } + + public void engineNextBytes(byte[] bytes) + { + if (virgin) + this.engineSetSeed(engineGenerateSeed(32)); + try + { + adaptee.nextBytes(bytes, 0, bytes.length); + } + catch (LimitReachedException ignored) + { + } + } + + public void engineSetSeed(byte[] seed) + { + HashMap attributes = new HashMap(); + attributes.put(ARCFour.ARCFOUR_KEY_MATERIAL, seed); + adaptee.init(attributes); + virgin = false; + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/prng/CSPRNGSpi.java b/libjava/classpath/gnu/javax/crypto/jce/prng/CSPRNGSpi.java new file mode 100644 index 000000000..9a893af9d --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/prng/CSPRNGSpi.java @@ -0,0 +1,97 @@ +/* CSPRNGSpi.java -- + Copyright (C) 2004, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.jce.prng; + +import gnu.java.security.prng.IRandom; +import gnu.java.security.prng.LimitReachedException; +import gnu.java.security.jce.prng.SecureRandomAdapter; +import gnu.javax.crypto.prng.CSPRNG; + +import java.net.MalformedURLException; +import java.security.SecureRandomSpi; + +/** + * The implementation of the continuously-seeded SecureRandom <i>Service + * Provider Interface</i> (<b>SPI</b>) adapter. + */ +public class CSPRNGSpi + extends SecureRandomSpi +{ + private final IRandom adaptee; + private boolean virgin = true; + + public CSPRNGSpi() throws ClassNotFoundException, MalformedURLException, + NumberFormatException + { + super(); + + adaptee = CSPRNG.getSystemInstance(); + } + + protected byte[] engineGenerateSeed(final int numBytes) + { + return SecureRandomAdapter.getSeed(numBytes); + } + + protected void engineNextBytes(final byte[] buffer) + { + if (buffer == null) + throw new NullPointerException(); + if (virgin) + { + engineSetSeed(engineGenerateSeed(32)); + } + try + { + adaptee.nextBytes(buffer, 0, buffer.length); + } + catch (LimitReachedException lre) + { + throw new RuntimeException("random-number generator has been exhausted"); + } + } + + protected void engineSetSeed(final byte[] seed) + { + if (seed == null) + throw new NullPointerException(); + adaptee.addRandomBytes(seed, 0, seed.length); + virgin = false; + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/prng/FortunaImpl.java b/libjava/classpath/gnu/javax/crypto/jce/prng/FortunaImpl.java new file mode 100644 index 000000000..d2073b98d --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/prng/FortunaImpl.java @@ -0,0 +1,100 @@ +/* FortunaImpl.java -- Fortuna SecureRandom adapter. + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.jce.prng; + +import gnu.java.security.prng.LimitReachedException; + +import gnu.java.security.jce.prng.SecureRandomAdapter; + +import gnu.javax.crypto.prng.Fortuna; + +import java.security.SecureRandomSpi; +import java.util.Collections; + +public final class FortunaImpl + extends SecureRandomSpi +{ + private boolean virgin = true; + private final Fortuna adaptee; + + public FortunaImpl() + { + adaptee = new Fortuna(); + } + + protected void engineSetSeed(byte[] seed) + { + synchronized (adaptee) + { + if (virgin) + { + adaptee.init (Collections.singletonMap (Fortuna.SEED, seed)); + virgin = false; + } + else + { + adaptee.addRandomBytes (seed); + } + } + } + + protected void engineNextBytes(byte[] buffer) + { + synchronized (adaptee) + { + if (virgin) + { + this.engineSetSeed(engineGenerateSeed(32)); + } + try + { + adaptee.nextBytes(buffer); + } + catch (LimitReachedException shouldNotHappen) + { + throw new Error(shouldNotHappen); + } + } + } + + protected byte[] engineGenerateSeed(int numBytes) + { + return SecureRandomAdapter.getSeed(numBytes); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/prng/ICMRandomSpi.java b/libjava/classpath/gnu/javax/crypto/jce/prng/ICMRandomSpi.java new file mode 100644 index 000000000..bbd5d4768 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/prng/ICMRandomSpi.java @@ -0,0 +1,206 @@ +/* ICMRandomSpi.java -- + Copyright (C) 2001, 2002, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.jce.prng; + +import gnu.java.security.Configuration; +import gnu.java.security.Registry; +import gnu.java.security.jce.prng.SecureRandomAdapter; +import gnu.java.security.prng.LimitReachedException; +import gnu.javax.crypto.cipher.IBlockCipher; +import gnu.javax.crypto.prng.ICMGenerator; + +import java.math.BigInteger; +import java.security.SecureRandomSpi; +import java.util.HashMap; +import java.util.Random; +import java.util.logging.Logger; + +/** + * An <em>Adapter</em> class around {@link ICMGenerator} to allow using this + * algorithm as a JCE {@link java.security.SecureRandom}. + */ +public class ICMRandomSpi + extends SecureRandomSpi +{ + private static final Logger log = Logger.getLogger(ICMRandomSpi.class.getName()); + /** Class-wide prng to generate random material for the underlying prng. */ + private static final ICMGenerator prng; // blank final + static + { + prng = new ICMGenerator(); + resetLocalPRNG(); + } + + // error messages + private static final String MSG = "Exception while setting up an " + + Registry.ICM_PRNG + " SPI: "; + private static final String RETRY = "Retry..."; + private static final String LIMIT_REACHED_MSG = "Limit reached: "; + private static final String RESEED = "Re-seed..."; + /** Our underlying prng instance. */ + private ICMGenerator adaptee = new ICMGenerator(); + + // default 0-arguments constructor + + private static void resetLocalPRNG() + { + if (Configuration.DEBUG) + log.entering(ICMRandomSpi.class.getName(), "resetLocalPRNG"); + HashMap attributes = new HashMap(); + attributes.put(ICMGenerator.CIPHER, Registry.AES_CIPHER); + byte[] key = new byte[128 / 8]; // AES default key size + Random rand = new Random(System.currentTimeMillis()); + rand.nextBytes(key); + attributes.put(IBlockCipher.KEY_MATERIAL, key); + int aesBlockSize = 128 / 8; // AES block size in bytes + byte[] offset = new byte[aesBlockSize]; + rand.nextBytes(offset); + attributes.put(ICMGenerator.OFFSET, offset); + int ndxLen = 0; // the segment length + // choose a random value between 1 and aesBlockSize / 2 + int limit = aesBlockSize / 2; + while (ndxLen < 1 || ndxLen > limit) + ndxLen = rand.nextInt(limit + 1); + attributes.put(ICMGenerator.SEGMENT_INDEX_LENGTH, Integer.valueOf(ndxLen)); + byte[] index = new byte[ndxLen]; + rand.nextBytes(index); + attributes.put(ICMGenerator.SEGMENT_INDEX, new BigInteger(1, index)); + prng.setup(attributes); + if (Configuration.DEBUG) + log.exiting(ICMRandomSpi.class.getName(), "resetLocalPRNG"); + } + + public byte[] engineGenerateSeed(int numBytes) + { + return SecureRandomAdapter.getSeed(numBytes); + } + + public void engineNextBytes(byte[] bytes) + { + if (Configuration.DEBUG) + log.entering(this.getClass().getName(), "engineNextBytes"); + if (! adaptee.isInitialised()) + this.engineSetSeed(engineGenerateSeed(32)); + while (true) + { + try + { + adaptee.nextBytes(bytes, 0, bytes.length); + break; + } + catch (LimitReachedException x) + { // reseed the generator + if (Configuration.DEBUG) + { + log.fine(LIMIT_REACHED_MSG + String.valueOf(x)); + log.fine(RESEED); + } + resetLocalPRNG(); + } + } + if (Configuration.DEBUG) + log.exiting(this.getClass().getName(), "engineNextBytes"); + } + + public void engineSetSeed(byte[] seed) + { + if (Configuration.DEBUG) + log.entering(this.getClass().getName(), "engineSetSeed"); + // compute the total number of random bytes required to setup adaptee + int materialLength = 0; + materialLength += 16; // key material size + materialLength += 16; // offset size + materialLength += 8; // index size == half of an AES block + byte[] material = new byte[materialLength]; + // use as much as possible bytes from the seed + int materialOffset = 0; + int materialLeft = material.length; + if (seed.length > 0) + { // copy some bytes into key and update indices + int lenToCopy = Math.min(materialLength, seed.length); + System.arraycopy(seed, 0, material, 0, lenToCopy); + materialOffset += lenToCopy; + materialLeft -= lenToCopy; + } + if (materialOffset > 0) // generate the rest + { + while (true) + { + try + { + prng.nextBytes(material, materialOffset, materialLeft); + break; + } + catch (IllegalStateException x) + { // should not happen + throw new InternalError(MSG + String.valueOf(x)); + } + catch (LimitReachedException x) + { + if (Configuration.DEBUG) + { + log.fine(MSG + String.valueOf(x)); + log.fine(RETRY); + } + } + } + } + // setup the underlying adaptee instance + HashMap attributes = new HashMap(); + // use AES cipher with 128-bit block size + attributes.put(ICMGenerator.CIPHER, Registry.AES_CIPHER); + // use an index the size of quarter of an AES block + attributes.put(ICMGenerator.SEGMENT_INDEX_LENGTH, Integer.valueOf(4)); + // specify the key + byte[] key = new byte[16]; + System.arraycopy(material, 0, key, 0, 16); + attributes.put(IBlockCipher.KEY_MATERIAL, key); + // specify the offset + byte[] offset = new byte[16]; + System.arraycopy(material, 16, offset, 0, 16); + attributes.put(ICMGenerator.OFFSET, offset); + // specify the index + byte[] index = new byte[4]; + System.arraycopy(material, 32, index, 0, 4); + attributes.put(ICMGenerator.SEGMENT_INDEX, new BigInteger(1, index)); + adaptee.init(attributes); + if (Configuration.DEBUG) + log.exiting(this.getClass().getName(), "engineSetSeed"); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/prng/UMacRandomSpi.java b/libjava/classpath/gnu/javax/crypto/jce/prng/UMacRandomSpi.java new file mode 100644 index 000000000..910e65c70 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/prng/UMacRandomSpi.java @@ -0,0 +1,166 @@ +/* UMacRandomSpi.java -- + Copyright (C) 2001, 2002, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.jce.prng; + +import gnu.java.security.Configuration; +import gnu.java.security.Registry; +import gnu.java.security.prng.LimitReachedException; +import gnu.java.security.jce.prng.SecureRandomAdapter; +import gnu.javax.crypto.cipher.IBlockCipher; +import gnu.javax.crypto.prng.UMacGenerator; + +import java.security.SecureRandomSpi; +import java.util.HashMap; +import java.util.Random; +import java.util.logging.Logger; + +/** + * An <em>Adapter</em> class around {@link UMacGenerator} to allow using this + * algorithm as a JCE {@link java.security.SecureRandom}. + */ +public class UMacRandomSpi + extends SecureRandomSpi +{ + private static final Logger log = Logger.getLogger(UMacRandomSpi.class.getName()); + + /** Class-wide prng to generate random material for the underlying prng. */ + private static final UMacGenerator prng; // blank final + static + { + prng = new UMacGenerator(); + resetLocalPRNG(); + } + // error messages + private static final String MSG = "Exception while setting up a " + + Registry.UMAC_PRNG + " SPI: "; + private static final String RETRY = "Retry..."; + /** Our underlying prng instance. */ + private UMacGenerator adaptee = new UMacGenerator(); + + // default 0-arguments constructor + + private static void resetLocalPRNG() + { + HashMap attributes = new HashMap(); + attributes.put(UMacGenerator.CIPHER, Registry.AES_CIPHER); + byte[] key = new byte[128 / 8]; // AES default key size + Random rand = new Random(System.currentTimeMillis()); + rand.nextBytes(key); + attributes.put(IBlockCipher.KEY_MATERIAL, key); + int index = rand.nextInt() & 0xFF; + attributes.put(UMacGenerator.INDEX, Integer.valueOf(index)); + prng.setup(attributes); + } + + public byte[] engineGenerateSeed(int numBytes) + { + return SecureRandomAdapter.getSeed(numBytes); + } + + public void engineNextBytes(byte[] bytes) + { + if (! adaptee.isInitialised()) + engineSetSeed(engineGenerateSeed(32)); + while (true) + { + try + { + adaptee.nextBytes(bytes, 0, bytes.length); + break; + } + catch (LimitReachedException x) + { // reseed the generator + resetLocalPRNG(); + } + } + } + + public void engineSetSeed(byte[] seed) + { + // compute the total number of random bytes required to setup adaptee + int materialLength = 0; + materialLength += 16; // key material size + materialLength++; // index size + byte[] material = new byte[materialLength]; + // use as much as possible bytes from the seed + int materialOffset = 0; + int materialLeft = material.length; + if (seed.length > 0) + { // copy some bytes into key and update indices + int lenToCopy = Math.min(materialLength, seed.length); + System.arraycopy(seed, 0, material, 0, lenToCopy); + materialOffset += lenToCopy; + materialLeft -= lenToCopy; + } + if (materialOffset > 0) // generate the rest + { + while (true) + { + try + { + prng.nextBytes(material, materialOffset, materialLeft); + break; + } + catch (IllegalStateException x) // should not happen + { + throw new InternalError(MSG + String.valueOf(x)); + } + catch (LimitReachedException x) + { + if (Configuration.DEBUG) + { + log.fine(MSG + String.valueOf(x)); + log.fine(RETRY); + } + } + } + } + // setup the underlying adaptee instance + HashMap attributes = new HashMap(); + // use AES cipher with 128-bit block size + attributes.put(UMacGenerator.CIPHER, Registry.AES_CIPHER); + // specify the key + byte[] key = new byte[16]; + System.arraycopy(material, 0, key, 0, 16); + attributes.put(IBlockCipher.KEY_MATERIAL, key); + // use a 1-byte index + attributes.put(UMacGenerator.INDEX, Integer.valueOf(material[16] & 0xFF)); + adaptee.init(attributes); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/sig/DHKeyFactory.java b/libjava/classpath/gnu/javax/crypto/jce/sig/DHKeyFactory.java new file mode 100644 index 000000000..98b265dd3 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/sig/DHKeyFactory.java @@ -0,0 +1,219 @@ +/* DHKeyFactory.java -- DH key-factory JCE Adapter + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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; either version 2, or (at your option) +any later version. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.jce.sig; + +import gnu.java.security.Registry; +import gnu.javax.crypto.key.dh.DHKeyPairPKCS8Codec; +import gnu.javax.crypto.key.dh.DHKeyPairX509Codec; +import gnu.javax.crypto.key.dh.GnuDHPrivateKey; +import gnu.javax.crypto.key.dh.GnuDHPublicKey; + +import java.math.BigInteger; +import java.security.InvalidKeyException; +import java.security.Key; +import java.security.KeyFactorySpi; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.security.spec.InvalidKeySpecException; +import java.security.spec.KeySpec; +import java.security.spec.PKCS8EncodedKeySpec; +import java.security.spec.X509EncodedKeySpec; + +import javax.crypto.interfaces.DHPrivateKey; +import javax.crypto.interfaces.DHPublicKey; +import javax.crypto.spec.DHPrivateKeySpec; +import javax.crypto.spec.DHPublicKeySpec; + +/** + * Implementation of a JCE Adapter for DH a key-factory. + */ +public class DHKeyFactory + extends KeyFactorySpi +{ + // implicit 0-arguments constructor + + protected PublicKey engineGeneratePublic(KeySpec keySpec) + throws InvalidKeySpecException + { + if (keySpec instanceof DHPublicKeySpec) + { + DHPublicKeySpec spec = (DHPublicKeySpec) keySpec; + BigInteger p = spec.getP(); + BigInteger g = spec.getG(); + BigInteger y = spec.getY(); + return new GnuDHPublicKey(Registry.X509_ENCODING_ID, null, p, g, y); + } + if (keySpec instanceof X509EncodedKeySpec) + { + X509EncodedKeySpec spec = (X509EncodedKeySpec) keySpec; + byte[] encoded = spec.getEncoded(); + PublicKey result; + try + { + result = new DHKeyPairX509Codec().decodePublicKey(encoded); + return result; + } + catch (RuntimeException x) + { + InvalidKeySpecException y = new InvalidKeySpecException(); + y.initCause(x); + throw y; + } + } + throw new InvalidKeySpecException("Unsupported (public) key specification"); + } + + protected PrivateKey engineGeneratePrivate(KeySpec keySpec) + throws InvalidKeySpecException + { + if (keySpec instanceof DHPrivateKeySpec) + { + DHPrivateKeySpec spec = (DHPrivateKeySpec) keySpec; + BigInteger p = spec.getP(); + BigInteger g = spec.getG(); + BigInteger x = spec.getX(); + return new GnuDHPrivateKey(Registry.PKCS8_ENCODING_ID, null, p, g, x); + } + if (keySpec instanceof PKCS8EncodedKeySpec) + { + PKCS8EncodedKeySpec spec = (PKCS8EncodedKeySpec) keySpec; + byte[] encoded = spec.getEncoded(); + PrivateKey result; + try + { + result = new DHKeyPairPKCS8Codec().decodePrivateKey(encoded); + return result; + } + catch (RuntimeException x) + { + InvalidKeySpecException y = new InvalidKeySpecException(); + y.initCause(x); + throw y; + } + } + throw new InvalidKeySpecException("Unsupported (private) key specification"); + } + + protected KeySpec engineGetKeySpec(Key key, Class keySpec) + throws InvalidKeySpecException + { + if (key instanceof DHPublicKey) + { + if (keySpec.isAssignableFrom(DHPublicKeySpec.class)) + { + DHPublicKey dssKey = (DHPublicKey) key; + BigInteger p = dssKey.getParams().getP(); + BigInteger g = dssKey.getParams().getG(); + BigInteger y = dssKey.getY(); + return new DHPublicKeySpec(y, p, g); + } + if (keySpec.isAssignableFrom(X509EncodedKeySpec.class)) + { + if (key instanceof GnuDHPublicKey) + { + GnuDHPublicKey dhKey = (GnuDHPublicKey) key; + byte[] encoded = dhKey.getEncoded(Registry.X509_ENCODING_ID); + return new X509EncodedKeySpec(encoded); + } + if (Registry.X509_ENCODING_SORT_NAME.equalsIgnoreCase(key.getFormat())) + { + byte[] encoded = key.getEncoded(); + return new X509EncodedKeySpec(encoded); + } + throw new InvalidKeySpecException( + "Wrong key type or unsupported (public) key specification"); + } + throw new InvalidKeySpecException("Unsupported (public) key specification"); + } + if (key instanceof DHPrivateKey) + { + if (keySpec.isAssignableFrom(DHPrivateKeySpec.class)) + { + DHPrivateKey dhKey = (DHPrivateKey) key; + BigInteger p = dhKey.getParams().getP(); + BigInteger g = dhKey.getParams().getG(); + BigInteger x = dhKey.getX(); + return new DHPrivateKeySpec(x, p, g); + } + if (keySpec.isAssignableFrom(PKCS8EncodedKeySpec.class)) + { + if (key instanceof GnuDHPrivateKey) + { + GnuDHPrivateKey dhKey = (GnuDHPrivateKey) key; + byte[] encoded = dhKey.getEncoded(Registry.PKCS8_ENCODING_ID); + return new PKCS8EncodedKeySpec(encoded); + } + if (Registry.PKCS8_ENCODING_SHORT_NAME.equalsIgnoreCase(key.getFormat())) + { + byte[] encoded = key.getEncoded(); + return new PKCS8EncodedKeySpec(encoded); + } + throw new InvalidKeySpecException( + "Wrong key type or unsupported (private) key specification"); + } + throw new InvalidKeySpecException( + "Unsupported (private) key specification"); + } + throw new InvalidKeySpecException( + "Wrong key type or unsupported key specification"); + } + + protected Key engineTranslateKey(Key key) throws InvalidKeyException + { + if ((key instanceof GnuDHPublicKey) || (key instanceof GnuDHPrivateKey)) + return key; + if (key instanceof DHPublicKey) + { + DHPublicKey dsaKey = (DHPublicKey) key; + BigInteger p = dsaKey.getParams().getP(); + BigInteger g = dsaKey.getParams().getG(); + BigInteger y = dsaKey.getY(); + return new GnuDHPublicKey(Registry.X509_ENCODING_ID, null, p, g, y); + } + if (key instanceof DHPrivateKey) + { + DHPrivateKey dsaKey = (DHPrivateKey) key; + BigInteger p = dsaKey.getParams().getP(); + BigInteger g = dsaKey.getParams().getG(); + BigInteger x = dsaKey.getX(); + return new GnuDHPrivateKey(Registry.PKCS8_ENCODING_ID, null, p, g, x); + } + throw new InvalidKeyException("Wrong key type"); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/sig/DHKeyPairGeneratorSpi.java b/libjava/classpath/gnu/javax/crypto/jce/sig/DHKeyPairGeneratorSpi.java new file mode 100644 index 000000000..e26f07124 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/sig/DHKeyPairGeneratorSpi.java @@ -0,0 +1,93 @@ +/* DHKeyPairGeneratorSpi.java -- DH key-pair generator JCE Adapter + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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; either version 2, or (at your option) +any later version. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.jce.sig; + +import java.security.InvalidAlgorithmParameterException; +import java.security.SecureRandom; +import java.security.spec.AlgorithmParameterSpec; +import java.util.HashMap; + +import javax.crypto.spec.DHGenParameterSpec; +import javax.crypto.spec.DHParameterSpec; + +import gnu.java.security.Registry; +import gnu.java.security.jce.sig.KeyPairGeneratorAdapter; +import gnu.javax.crypto.key.dh.GnuDHKeyPairGenerator; + +public class DHKeyPairGeneratorSpi + extends KeyPairGeneratorAdapter +{ + public DHKeyPairGeneratorSpi() + { + super(Registry.DH_KPG); + } + + public void initialize(int keysize, SecureRandom random) + { + HashMap attributes = new HashMap(); + attributes.put(GnuDHKeyPairGenerator.PRIME_SIZE, Integer.valueOf(keysize)); + if (random != null) + attributes.put(GnuDHKeyPairGenerator.SOURCE_OF_RANDOMNESS, random); + + attributes.put(GnuDHKeyPairGenerator.PREFERRED_ENCODING_FORMAT, + Integer.valueOf(Registry.ASN1_ENCODING_ID)); + adaptee.setup(attributes); + } + + public void initialize(AlgorithmParameterSpec params, SecureRandom random) + throws InvalidAlgorithmParameterException + { + HashMap attributes = new HashMap(); + if (params != null) + { + if (! (params instanceof DHGenParameterSpec) && + ! (params instanceof DHParameterSpec)) + throw new InvalidAlgorithmParameterException("params"); + + attributes.put(GnuDHKeyPairGenerator.DH_PARAMETERS, params); + } + + if (random != null) + attributes.put(GnuDHKeyPairGenerator.SOURCE_OF_RANDOMNESS, random); + + attributes.put(GnuDHKeyPairGenerator.PREFERRED_ENCODING_FORMAT, + Integer.valueOf(Registry.ASN1_ENCODING_ID)); + adaptee.setup(attributes); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/sig/DHParameters.java b/libjava/classpath/gnu/javax/crypto/jce/sig/DHParameters.java new file mode 100644 index 000000000..cc656d2c8 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/sig/DHParameters.java @@ -0,0 +1,222 @@ +/* DHParameters.java -- DH parameters DAO + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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; either version 2, or (at your option) +any later version. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.jce.sig; + +import gnu.java.lang.CPStringBuilder; + +import gnu.java.security.Registry; +import gnu.java.security.der.DER; +import gnu.java.security.der.DERReader; +import gnu.java.security.der.DERValue; +import gnu.java.security.der.DERWriter; +import gnu.java.security.util.DerUtil; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.math.BigInteger; +import java.security.AlgorithmParametersSpi; +import java.security.spec.AlgorithmParameterSpec; +import java.security.spec.InvalidParameterSpecException; +import java.util.ArrayList; + +import javax.crypto.spec.DHGenParameterSpec; +import javax.crypto.spec.DHParameterSpec; + +/** + * A JCE-specific Data Access Object (DAO) for DH parameters. + */ +public class DHParameters + extends AlgorithmParametersSpi +{ + /** The prime public modulus. */ + private BigInteger p; + + /** The generator. */ + private BigInteger g; + + /** A prime factor of p-1. */ + private BigInteger q; + + /** The (private) random exponent's size (in bits). */ + private int l; + + // default 0-arguments constructor + + protected void engineInit(AlgorithmParameterSpec spec) + throws InvalidParameterSpecException + { + if (! (spec instanceof DHParameterSpec)) + throw new InvalidParameterSpecException("Wrong AlgorithmParameterSpec type: " + + spec.getClass().getName()); + DHParameterSpec dhSpec = (DHParameterSpec) spec; + p = dhSpec.getP(); + g = dhSpec.getG(); + l = dhSpec.getL(); + } + + /** + * Decodes the set of DH parameters as per RFC-2459; i.e. the DER-encoded + * form of the following ASN.1 construct: + * + * <pre> + * DhParams ::= SEQUENCE { + * p INTEGER, -- odd prime, p=jq +1 + * g INTEGER, -- generator, g + * q INTEGER -- factor of p-1 + * } + * </pre> + */ + protected void engineInit(byte[] params) throws IOException + { + DERReader der = new DERReader(params); + + DERValue derParams = der.read(); + DerUtil.checkIsConstructed(derParams, "Wrong DH Parameters field"); + + DERValue val = der.read(); + DerUtil.checkIsBigInteger(val, "Wrong P field"); + p = (BigInteger) val.getValue(); + val = der.read(); + DerUtil.checkIsBigInteger(val, "Wrong G field"); + g = (BigInteger) val.getValue(); + val = der.read(); + DerUtil.checkIsBigInteger(val, "Wrong Q field"); + q = (BigInteger) val.getValue(); + l = q.bitLength(); + } + + protected void engineInit(byte[] params, String format) throws IOException + { + if (format != null) + { + format = format.trim(); + if (format.length() == 0) + throw new IOException("Format MUST NOT be an empty string"); + + if (! format.equalsIgnoreCase(Registry.ASN1_ENCODING_SHORT_NAME)) + throw new IOException("Unknown or unsupported format: " + format); + } + + engineInit(params); + } + + protected AlgorithmParameterSpec engineGetParameterSpec(Class paramSpec) + throws InvalidParameterSpecException + { + if (paramSpec.isAssignableFrom(DHParameterSpec.class)) + return new DHParameterSpec(p, g, l); + + if (paramSpec.isAssignableFrom(DHGenParameterSpec.class)) + return new DHGenParameterSpec(p.bitLength(), l); + + throw new InvalidParameterSpecException("Wrong AlgorithmParameterSpec type: " + + paramSpec.getName()); + } + + /** + * Encodes the set of DH parameters as per RFC-2459; i.e. as the DER-encoded + * form of the following ASN.1 construct: + * + * <pre> + * DhParams ::= SEQUENCE { + * p INTEGER, -- odd prime, p=jq +1 + * g INTEGER, -- generator, g + * q INTEGER -- factor of p-1 + * } + * </pre> + */ + protected byte[] engineGetEncoded() throws IOException + { + DERValue derP = new DERValue(DER.INTEGER, p); + DERValue derG = new DERValue(DER.INTEGER, g); + DERValue derQ = new DERValue(DER.INTEGER, q); + + ArrayList params = new ArrayList(3); + params.add(derP); + params.add(derG); + params.add(derQ); + DERValue derParams = new DERValue(DER.CONSTRUCTED | DER.SEQUENCE, params); + + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + DERWriter.write(baos, derParams); + byte[] result = baos.toByteArray(); + + return result; + } + + protected byte[] engineGetEncoded(String format) throws IOException + { + if (format != null) + { + format = format.trim(); + if (format.length() == 0) + throw new IOException("Format MUST NOT be an empty string"); + + if (! format.equalsIgnoreCase(Registry.ASN1_ENCODING_SHORT_NAME)) + throw new IOException("Unknown or unsupported format: " + format); + } + + return engineGetEncoded(); + } + + protected String engineToString() + { + CPStringBuilder sb = new CPStringBuilder("p="); + if (p == null) + sb.append("???"); + else + sb.append("0x").append(p.toString(16)); + + sb.append(", g="); + if (g == null) + sb.append("???"); + else + sb.append("0x").append(g.toString(16)); + + sb.append(", q="); + if (q == null) + sb.append("???"); + else + sb.append("0x").append(q.toString(16)); + + sb.append(", l=").append(l); + + return sb.toString(); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/sig/DHParametersGenerator.java b/libjava/classpath/gnu/javax/crypto/jce/sig/DHParametersGenerator.java new file mode 100644 index 000000000..3687ac3ca --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/sig/DHParametersGenerator.java @@ -0,0 +1,152 @@ +/* DHParametersGenerator.java -- JCE Adapter for a generator of DH parameters + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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; either version 2, or (at your option) +any later version. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.jce.sig; + +import gnu.java.security.Registry; +import gnu.javax.crypto.jce.GnuCrypto; +import gnu.javax.crypto.key.dh.GnuDHKeyPairGenerator; +import gnu.javax.crypto.key.dh.RFC2631; + +import java.math.BigInteger; +import java.security.AlgorithmParameterGeneratorSpi; +import java.security.AlgorithmParameters; +import java.security.InvalidAlgorithmParameterException; +import java.security.InvalidParameterException; +import java.security.NoSuchAlgorithmException; +import java.security.Provider; +import java.security.SecureRandom; +import java.security.spec.AlgorithmParameterSpec; +import java.security.spec.InvalidParameterSpecException; + +import javax.crypto.spec.DHGenParameterSpec; +import javax.crypto.spec.DHParameterSpec; + +/** + * A JCE Adapter for a generator of DH parameters. + */ +public class DHParametersGenerator + extends AlgorithmParameterGeneratorSpi +{ + private static final Provider GNU_CRYPTO = new GnuCrypto(); + + /** Size of the prime (public) modulus in bits. */ + private int modulusSize = -1; + + /** Size of the prime (private) modulus in bits. */ + private int exponentSize = -1; + + /** User specified source of randomness. */ + private SecureRandom rnd; + + /** Our concrete DH parameters generator. */ + private RFC2631 rfc2631; + + + protected void engineInit(int size, SecureRandom random) + { + if ((size % 256) != 0 || size < GnuDHKeyPairGenerator.DEFAULT_PRIME_SIZE) + throw new InvalidParameterException("Prime modulus (p) size (in bits) " + + "MUST be a multiple of 256, and " + + "greater than or equal to 1024"); + this.modulusSize = size; + this.rnd = random; + } + + protected void engineInit(AlgorithmParameterSpec spec, SecureRandom random) + throws InvalidAlgorithmParameterException + { + if (spec instanceof DHParameterSpec) + { + DHParameterSpec dhSpec = (DHParameterSpec) spec; + BigInteger p = dhSpec.getP(); + int size = p.bitLength(); + this.engineInit(size, random); + } + else if (spec instanceof DHGenParameterSpec) + { + DHGenParameterSpec dhSpec = (DHGenParameterSpec) spec; + int size = dhSpec.getPrimeSize(); + this.engineInit(size, random); + exponentSize = dhSpec.getExponentSize(); + + if ((exponentSize % 8) != 0 + || exponentSize < GnuDHKeyPairGenerator.DEFAULT_EXPONENT_SIZE) + throw new InvalidParameterException("Random exponent size (in bits) " + + "MUST be a multiple of 8, and " + + "greater than or equal to " + + GnuDHKeyPairGenerator.DEFAULT_EXPONENT_SIZE); + if (exponentSize > modulusSize) + throw new InvalidParameterException("Random exponent size (in bits) " + + "MUST be less than that of the " + + "public prime modulus (p)"); + } + + throw new InvalidAlgorithmParameterException("Wrong AlgorithmParameterSpec type: " + + spec.getClass().getName()); + } + + protected AlgorithmParameters engineGenerateParameters() + { + if (modulusSize < 1) + modulusSize = GnuDHKeyPairGenerator.DEFAULT_PRIME_SIZE; + + if (exponentSize < 1) + exponentSize = GnuDHKeyPairGenerator.DEFAULT_EXPONENT_SIZE; + + rfc2631 = new RFC2631(exponentSize, modulusSize, rnd); + BigInteger[] params = rfc2631.generateParameters(); + BigInteger p = params[RFC2631.DH_PARAMS_P]; + BigInteger g = params[RFC2631.DH_PARAMS_G]; + int l = params[RFC2631.DH_PARAMS_Q].bitLength(); + DHParameterSpec spec = new DHParameterSpec(p, g, l); + AlgorithmParameters result = null; + try + { + result = AlgorithmParameters.getInstance(Registry.DH_KPG, GNU_CRYPTO); + result.init(spec); + } + catch (NoSuchAlgorithmException ignore) + { + } + catch (InvalidParameterSpecException ignore) + { + } + return result; + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/spec/BlockCipherParameterSpec.java b/libjava/classpath/gnu/javax/crypto/jce/spec/BlockCipherParameterSpec.java new file mode 100644 index 000000000..b17fa3497 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/spec/BlockCipherParameterSpec.java @@ -0,0 +1,122 @@ +/* BlockCipherParameterSpec.java -- + Copyright (C) 2002, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.jce.spec; + +import gnu.java.security.util.Util; + +import java.security.spec.AlgorithmParameterSpec; + +/** + * Block cipher parameters in GNU are the cipher's name, its block and key + * sizes, and an optional initialization vector. + */ +public class BlockCipherParameterSpec + implements AlgorithmParameterSpec +{ + /** The initialization vector. */ + protected byte[] iv; + /** The cipher's block size, in bytes. */ + protected int blockSize; + /** The cipher's key size, in bytes. */ + protected int keySize; + + /** + * Create a new parameter specification. + * + * @param iv The initialization vector, or <code>null</code> if there is no + * IV. + * @param blockSize The cipher's block size, in bytes. + * @param keySize The cipher's key size, in bytes. + */ + public BlockCipherParameterSpec(byte[] iv, int blockSize, int keySize) + { + this.iv = (iv != null) ? (byte[]) iv.clone() : null; + this.blockSize = blockSize; + this.keySize = keySize; + } + + /** + * Create a new parameter specification with no IV. + * + * @param blockSize The cipher's block size, in bytes. + * @param keySize The cipher's key size, in bytes. + */ + public BlockCipherParameterSpec(int blockSize, int keySize) + { + this(null, blockSize, keySize); + } + + /** + * Get the initialization vector for the cipher, or <code>null</code> if + * there is no IV. + * + * @return The IV. + */ + public byte[] getIV() + { + return iv; + } + + /** + * Get the block size of the cipher these parameters are for. + * + * @return The block size. + */ + public int getBlockSize() + { + return blockSize; + } + + /** + * Get the key size of the cipher these parameters are for. + * + * @return The block size. + */ + public int getKeySize() + { + return keySize; + } + + public String toString() + { + return getClass().getName() + " { " + + ((iv != null) ? ("IV=" + Util.toString(iv)) + ", " : "") + + "BS=" + blockSize + ", KS=" + keySize + " }"; + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/spec/TMMHParameterSpec.java b/libjava/classpath/gnu/javax/crypto/jce/spec/TMMHParameterSpec.java new file mode 100644 index 000000000..31199538c --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/spec/TMMHParameterSpec.java @@ -0,0 +1,117 @@ +/* TMMHParameterSpec.java -- + Copyright (C) 2002, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.jce.spec; + +import gnu.java.security.prng.IRandom; + +import java.security.spec.AlgorithmParameterSpec; + +/** + * This class represents the algorithm parameters for the Truncated + * Multi-Modular Hash function for use with JCE-derived instances of + * {@link gnu.javax.crypto.mac.TMMH16}. + * <p> + * This class is little more than a container for the key stream, tag length, + * and prefix parameters for the TMMH algorithm. + */ +public class TMMHParameterSpec + implements AlgorithmParameterSpec +{ + /** The keystream. */ + protected IRandom keystream; + /** The tag length. */ + protected Integer tagLength; + /** The prefix. */ + protected byte[] prefix; + + /** + * Create a new parameter specification. + * + * @param keystream The (PRNG) key stream. + * @param tagLength The tag length. + * @param prefix The prefix. + */ + public TMMHParameterSpec(IRandom keystream, Integer tagLength, byte[] prefix) + { + this.keystream = keystream; + this.tagLength = tagLength; + this.prefix = prefix; + } + + /** + * Create a new parameter specification with no prefix. + * + * @param keystream The (PRNG) key stream. + * @param tagLength The tag length. + */ + public TMMHParameterSpec(IRandom keystream, Integer tagLength) + { + this(keystream, tagLength, null); + } + + /** + * Return the key stream this specification was initialized with. + * + * @return The key stream. + */ + public IRandom getKeystream() + { + return keystream; + } + + /** + * Return the tag length this specification was initialized with. + * + * @return The tag length. + */ + public Integer getTagLength() + { + return tagLength; + } + + /** + * Return the prefix, or <code>null</code> if no prefix was specified. + * + * @return The prefix. + */ + public byte[] getPrefix() + { + return prefix; + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/spec/UMac32ParameterSpec.java b/libjava/classpath/gnu/javax/crypto/jce/spec/UMac32ParameterSpec.java new file mode 100644 index 000000000..3c13faf04 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/spec/UMac32ParameterSpec.java @@ -0,0 +1,73 @@ +/* UMac32ParameterSpec.java -- + Copyright (C) 2002, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.jce.spec; + +import java.security.spec.AlgorithmParameterSpec; + +/** + * This class represents the parameters for the UMAC-32 message authentication + * code algorithm. In practice this means the <i>Nonce</i> material used to + * initialize the algorithm. + */ +public class UMac32ParameterSpec + implements AlgorithmParameterSpec +{ + /** The <i>Nonce</i> material. */ + protected byte[] nonce; + + /** + * Create a new parameter instance. + * + * @param nonce The nonce material. + */ + public UMac32ParameterSpec(byte[] nonce) + { + this.nonce = nonce; + } + + /** + * Return the nonce material. + * + * @return The nonce material. + */ + public byte[] getNonce() + { + return nonce; + } +} diff --git a/libjava/classpath/gnu/javax/crypto/key/BaseKeyAgreementParty.java b/libjava/classpath/gnu/javax/crypto/key/BaseKeyAgreementParty.java new file mode 100644 index 000000000..3f4e0a22c --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/key/BaseKeyAgreementParty.java @@ -0,0 +1,168 @@ +/* BaseKeyAgreementParty.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.key; + +import gnu.java.security.prng.IRandom; +import gnu.java.security.prng.LimitReachedException; +import gnu.java.security.util.PRNG; + +import java.math.BigInteger; +import java.security.SecureRandom; +import java.util.Map; + +/** + * A base abstract class to facilitate implementations of concrete key agreement + * protocol handlers. + */ +public abstract class BaseKeyAgreementParty + implements IKeyAgreementParty +{ + protected static final BigInteger TWO = BigInteger.valueOf(2L); + /** The canonical name of the protocol. */ + protected String name; + /** Whether the instance is initialised or not. */ + protected boolean initialised = false; + /** The current step index of the protocol exchange. */ + protected int step = -1; + /** Whether the exchange has concluded or not. */ + protected boolean complete = false; + /** The optional {@link SecureRandom} instance to use. */ + protected SecureRandom rnd = null; + /** The optional {@link IRandom} instance to use. */ + protected IRandom irnd = null; + /** Our default source of randomness. */ + private PRNG prng = null; + + protected BaseKeyAgreementParty(String name) + { + super(); + + this.name = name; + } + + public String name() + { + return name; + } + + public void init(Map attributes) throws KeyAgreementException + { + if (initialised) + throw new IllegalStateException("already initialised"); + this.engineInit(attributes); + initialised = true; + this.step = -1; + this.complete = false; + } + + public OutgoingMessage processMessage(IncomingMessage in) + throws KeyAgreementException + { + if (! initialised) + throw new IllegalStateException("not initialised"); + if (complete) + throw new IllegalStateException("exchange has already concluded"); + step++; + return this.engineProcessMessage(in); + } + + public boolean isComplete() + { + return complete; + } + + public byte[] getSharedSecret() throws KeyAgreementException + { + if (! initialised) + throw new KeyAgreementException("not yet initialised"); + if (! isComplete()) + throw new KeyAgreementException("not yet computed"); + return engineSharedSecret(); + } + + public void reset() + { + if (initialised) + { + this.engineReset(); + initialised = false; + } + } + + protected abstract void engineInit(Map attributes) + throws KeyAgreementException; + + protected abstract OutgoingMessage engineProcessMessage(IncomingMessage in) + throws KeyAgreementException; + + protected abstract byte[] engineSharedSecret() throws KeyAgreementException; + + protected abstract void engineReset(); + + /** + * Fills the designated byte array with random data. + * + * @param buffer the byte array to fill with random data. + */ + protected void nextRandomBytes(byte[] buffer) + { + if (rnd != null) + rnd.nextBytes(buffer); + else if (irnd != null) + try + { + irnd.nextBytes(buffer, 0, buffer.length); + } + catch (LimitReachedException lre) + { + irnd = null; + getDefaultPRNG().nextBytes(buffer); + } + else + getDefaultPRNG().nextBytes(buffer); + } + + private PRNG getDefaultPRNG() + { + if (prng == null) + prng = PRNG.getInstance(); + + return prng; + } +} diff --git a/libjava/classpath/gnu/javax/crypto/key/GnuPBEKey.java b/libjava/classpath/gnu/javax/crypto/key/GnuPBEKey.java new file mode 100644 index 000000000..5642e59ed --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/key/GnuPBEKey.java @@ -0,0 +1,95 @@ +/* GnuPBEKey.java -- A password-based encryption key. + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.key; + +import javax.crypto.interfaces.PBEKey; +import javax.crypto.spec.PBEKeySpec; + +/** + * An implementation of a password-based encryption key. + * + * @author Casey Marshall (csm@gnu.org) + */ +public class GnuPBEKey + implements PBEKey +{ + private final PBEKeySpec spec; + + public GnuPBEKey (final PBEKeySpec spec) + { + if (spec == null) + throw new NullPointerException (); + this.spec = spec; + } + + public GnuPBEKey (char[] password, byte[] salt, int iterationCount) + { + this (new PBEKeySpec (password, salt, iterationCount)); + } + + public int getIterationCount () + { + return spec.getIterationCount (); + } + + public char[] getPassword () + { + return spec.getPassword (); + } + + public byte[] getSalt () + { + return spec.getSalt (); + } + + public String getAlgorithm () + { + return "PBE"; + } + + public String getFormat () + { + return "NONE"; // FIXME? + } + + public byte[] getEncoded () + { + return null; // FIXME? + } +} diff --git a/libjava/classpath/gnu/javax/crypto/key/GnuSecretKey.java b/libjava/classpath/gnu/javax/crypto/key/GnuSecretKey.java new file mode 100644 index 000000000..c8ca1edab --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/key/GnuSecretKey.java @@ -0,0 +1,131 @@ +/* GnuSecretKey.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.key; + +import gnu.java.security.util.Util; +import java.security.Key; + +/** + * A secret key composed of a sequence of raw, unformatted octets. This class is + * analogous to the {@link javax.crypto.spec.SecretKeySpec} class, but is + * provided for platforms that do not or cannot contain that class. + */ +public class GnuSecretKey + implements Key +{ + private final byte[] key; + private final String algorithm; + + /** + * Creates a new secret key. The supplied byte array is copied by this + * constructor. + * + * @param key The raw, secret key. + * @param algorithm The algorithm name, which can be null or empty. + */ + public GnuSecretKey(byte[] key, String algorithm) + { + this(key, 0, key.length, algorithm); + } + + /** + * Creates a new secret key from a portion of a byte array. + * + * @param key The raw, secret key. + * @param offset The offset at which the key begins. + * @param length The number of bytes that comprise the key. + * @param algorithm The algorithm name, which can be null or empty. + */ + public GnuSecretKey(byte[] key, int offset, int length, String algorithm) + { + this.key = new byte[length]; + System.arraycopy(key, offset, this.key, 0, length); + this.algorithm = algorithm; + } + + /** + * Returns the algorithm name, if any. + * + * @return The algorithm name. + */ + public String getAlgorithm() + { + return null; + } + + /** + * Returns the encoded key, which is merely the byte array this class was + * created with. A reference to the internal byte array is returned, so the + * caller can delete this key from memory by modifying the returned array. + * + * @return The raw key. + */ + public byte[] getEncoded() + { + return key; + } + + /** + * Returns the string "RAW". + * + * @return The string "RAW". + */ + public String getFormat() + { + return "RAW"; + } + + public boolean equals(Object o) + { + if (! (o instanceof GnuSecretKey)) + return false; + if (key.length != ((GnuSecretKey) o).key.length) + return false; + byte[] key2 = ((GnuSecretKey) o).key; + for (int i = 0; i < key.length; i++) + if (key[i] != key2[i]) + return false; + return true; + } + + public String toString() + { + return "GnuSecretKey [ " + algorithm + " " + Util.toString(key) + " ]"; + } +} diff --git a/libjava/classpath/gnu/javax/crypto/key/IKeyAgreementParty.java b/libjava/classpath/gnu/javax/crypto/key/IKeyAgreementParty.java new file mode 100644 index 000000000..64434212f --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/key/IKeyAgreementParty.java @@ -0,0 +1,100 @@ +/* IKeyAgreementParty.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.key; + +import java.util.Map; + +/** + * The visible methods of an key agreement protocol participating party. + */ +public interface IKeyAgreementParty +{ + /** + * Returns the canonical name of the key agreement protocol. + * + * @return the canonical name of the key agreement protocol. + */ + String name(); + + /** + * Sets up the instance to operate with specific attributes. + * + * @param attributes a map of name-values used by concrete implementations. + * @throws KeyAgreementException if an exception occurs during the setup. + */ + void init(Map attributes) throws KeyAgreementException; + + /** + * Processes an incoming message at one end, generating a message that will be + * processed by the other party(ies). + * + * @param in the incoming message. + * @return an outgoing message, or <code>null</code> if this is an + * intermediary step that does not cause any output. + * @throws KeyAgreementException if an exception occurs during the processing + * of the incoming message, or during the generation of the outgoing + * message. + */ + OutgoingMessage processMessage(IncomingMessage in) + throws KeyAgreementException; + + /** + * Returns <code>true</code> if the party in the key agreement protocol + * exchange has completed its part of the exchange. If this is the case an + * {@link IllegalStateException} is thrown for any method invocation except + * <code>init()</code> or <code>reset()</code>. + * + * @return <code>true</code> if this party has completed its part of the key + * agreement protocol exchange; <code>false</code> otherwise. + */ + boolean isComplete(); + + /** + * Returns the byte array containing the shared secret as generated by this + * party. + * + * @return the generated shared secret. + * @throws KeyAgreementException if the key agreement is not yet initialised, + * or is initialised but the exchange is still in progress. + */ + byte[] getSharedSecret() throws KeyAgreementException; + + /** Resets this instance for re-use with another set of attributes. */ + void reset(); +} diff --git a/libjava/classpath/gnu/javax/crypto/key/IncomingMessage.java b/libjava/classpath/gnu/javax/crypto/key/IncomingMessage.java new file mode 100644 index 000000000..3b68392d6 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/key/IncomingMessage.java @@ -0,0 +1,318 @@ +/* IncomingMessage.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.key; + +import gnu.java.security.Registry; +import gnu.java.security.key.IKeyPairCodec; +import gnu.java.security.key.dss.DSSKeyPairPKCS8Codec; +import gnu.java.security.key.dss.DSSKeyPairRawCodec; +import gnu.java.security.key.dss.DSSKeyPairX509Codec; +import gnu.java.security.key.rsa.RSAKeyPairPKCS8Codec; +import gnu.java.security.key.rsa.RSAKeyPairRawCodec; +import gnu.java.security.key.rsa.RSAKeyPairX509Codec; +import gnu.javax.crypto.key.dh.DHKeyPairPKCS8Codec; +import gnu.javax.crypto.key.dh.DHKeyPairRawCodec; +import gnu.javax.crypto.key.dh.DHKeyPairX509Codec; +import gnu.javax.crypto.key.srp6.SRPKeyPairRawCodec; + +import java.io.ByteArrayInputStream; +import java.io.UnsupportedEncodingException; +import java.math.BigInteger; +import java.security.PrivateKey; +import java.security.PublicKey; + +/** + * An implementation of an incoming message for use with key agreement + * protocols. + */ +public class IncomingMessage +{ + /** The internal buffer stream containing the message's contents. */ + protected ByteArrayInputStream in; + /** The length of the message contents, according to its 4-byte header. */ + protected int length; + + /** + * Constructs an incoming message given the message's encoded form, including + * its header bytes. + * + * @param b the encoded form, including the header bytes, of an incoming + * message. + * @throws KeyAgreementException if the buffer is malformed. + */ + public IncomingMessage(byte[] b) throws KeyAgreementException + { + this(); + + if (b.length < 4) + throw new KeyAgreementException("message header too short"); + length = b[0] << 24 + | (b[1] & 0xFF) << 16 + | (b[2] & 0xFF) << 8 + | (b[3] & 0xFF); + if (length > Registry.SASL_BUFFER_MAX_LIMIT || length < 0) + throw new KeyAgreementException("message size limit exceeded"); + in = new ByteArrayInputStream(b, 4, length); + } + + /** Trivial private constructor for use by the class method. */ + private IncomingMessage() + { + super(); + } + + /** + * Returns an instance of a message given its encoded contents, excluding the + * message's header bytes. + * <p> + * Calls the method with the same name and three arguments as: + * <code>getInstance(raw, 0, raw.length)</code>. + * + * @param raw the encoded form, excluding the header bytes. + * @return a new instance of <code>IncomingMessage</code>. + */ + public static IncomingMessage getInstance(byte[] raw) + { + return getInstance(raw, 0, raw.length); + } + + /** + * Returns an instance of a message given its encoded contents, excluding the + * message's header bytes. + * + * @param raw the encoded form, excluding the header bytes. + * @param offset offset where to start using raw bytes from. + * @param len number of bytes to use. + * @return a new instance of <code>IncomingMessage</code>. + */ + public static IncomingMessage getInstance(byte[] raw, int offset, int len) + { + IncomingMessage result = new IncomingMessage(); + result.in = new ByteArrayInputStream(raw, offset, len); + return result; + } + + /** + * Converts two octets into the number that they represent. + * + * @param b the two octets. + * @return the length. + */ + public static int twoBytesToLength(byte[] b) throws KeyAgreementException + { + int result = (b[0] & 0xFF) << 8 | (b[1] & 0xFF); + if (result > Registry.SASL_TWO_BYTE_MAX_LIMIT) + throw new KeyAgreementException("encoded MPI size limit exceeded"); + return result; + } + + /** + * Converts four octets into the number that they represent. + * + * @param b the four octets. + * @return the length. + */ + public static int fourBytesToLength(byte[] b) throws KeyAgreementException + { + int result = b[0] << 24 + | (b[1] & 0xFF) << 16 + | (b[2] & 0xFF) << 8 + | (b[3] & 0xFF); + if (result > Registry.SASL_FOUR_BYTE_MAX_LIMIT || result < 0) + throw new KeyAgreementException("encoded entity size limit exceeded"); + return result; + } + + public boolean hasMoreElements() + { + return (in.available() > 0); + } + + /** + * Decodes a public key from the message. + * <p> + * See {@link OutgoingMessage#writePublicKey(java.security.PublicKey)} for + * more details on the internal format. + * + * @throws KeyAgreementException if an encoding size constraint is violated or + * a mismatch was detected in the encoding. + */ + public PublicKey readPublicKey() throws KeyAgreementException + { + if (in.available() < 5) + throw new KeyAgreementException("not enough bytes for a public key in message"); + byte[] elementLengthBytes = new byte[4]; + in.read(elementLengthBytes, 0, 4); + int elementLength = fourBytesToLength(elementLengthBytes); + if (in.available() < elementLength) + throw new KeyAgreementException("illegal public key encoding"); + int keyTypeAndFormatID = in.read() & 0xFF; + elementLength--; + byte[] kb = new byte[elementLength]; + in.read(kb, 0, elementLength); + // instantiate the right codec and decode + IKeyPairCodec kpc = getKeyPairCodec(keyTypeAndFormatID); + return kpc.decodePublicKey(kb); + } + + /** + * Decodes a private key from the message. + * <p> + * See {@link OutgoingMessage#writePrivateKey(java.security.PrivateKey)} for + * more details. + * + * @throws KeyAgreementException if an encoding size constraint is violated or + * a mismatch was detected in the encoding. + */ + public PrivateKey readPrivateKey() throws KeyAgreementException + { + if (in.available() < 5) + throw new KeyAgreementException("not enough bytes for a private key in message"); + byte[] elementLengthBytes = new byte[4]; + in.read(elementLengthBytes, 0, 4); + int elementLength = fourBytesToLength(elementLengthBytes); + if (in.available() < elementLength) + throw new KeyAgreementException("illegal private key encoding"); + int keyTypeAndFormatID = in.read() & 0xFF; + elementLength--; + byte[] kb = new byte[elementLength]; + in.read(kb, 0, elementLength); + // instantiate the right codec and decode + IKeyPairCodec kpc = getKeyPairCodec(keyTypeAndFormatID); + return kpc.decodePrivateKey(kb); + } + + /** + * Decodes an MPI from the current message's contents. + * + * @return a native representation of an MPI. + * @throws KeyAgreementException if an encoding exception occurs during the + * operation. + */ + public BigInteger readMPI() throws KeyAgreementException + { + if (in.available() < 2) + throw new KeyAgreementException("not enough bytes for an MPI in message"); + byte[] elementLengthBytes = new byte[2]; + in.read(elementLengthBytes, 0, 2); + int elementLength = twoBytesToLength(elementLengthBytes); + if (in.available() < elementLength) + throw new KeyAgreementException("illegal MPI encoding"); + byte[] element = new byte[elementLength]; + in.read(element, 0, element.length); + return new BigInteger(1, element); + } + + public String readString() throws KeyAgreementException + { + if (in.available() < 2) + throw new KeyAgreementException("not enough bytes for a text in message"); + byte[] elementLengthBytes = new byte[2]; + in.read(elementLengthBytes, 0, 2); + int elementLength = twoBytesToLength(elementLengthBytes); + if (in.available() < elementLength) + throw new KeyAgreementException("illegal text encoding"); + byte[] element = new byte[elementLength]; + in.read(element, 0, element.length); + String result = null; + try + { + result = new String(element, "UTF8"); + } + catch (UnsupportedEncodingException x) + { + throw new KeyAgreementException("unxupported UTF8 encoding", x); + } + return result; + } + + private IKeyPairCodec getKeyPairCodec(int keyTypeAndFormatID) + throws KeyAgreementException + { + int keyType = (keyTypeAndFormatID >>> 4) & 0x0F; + int formatID = keyTypeAndFormatID & 0x0F; + switch (formatID) + { + case Registry.RAW_ENCODING_ID: + switch (keyType) + { + case 0: + return new DSSKeyPairRawCodec(); + case 1: + return new RSAKeyPairRawCodec(); + case 2: + return new DHKeyPairRawCodec(); + case 3: + return new SRPKeyPairRawCodec(); + default: + throw new KeyAgreementException("Unknown key-type for Raw format: " + + keyType); + } + case Registry.X509_ENCODING_ID: + switch (keyType) + { + case 0: + return new DSSKeyPairX509Codec(); + case 1: + return new RSAKeyPairX509Codec(); + case 2: + return new DHKeyPairX509Codec(); + default: + throw new KeyAgreementException("Unknown key-type for X.509 format: " + + keyType); + } + case Registry.PKCS8_ENCODING_ID: + switch (keyType) + { + case 0: + return new DSSKeyPairPKCS8Codec(); + case 1: + return new RSAKeyPairPKCS8Codec(); + case 2: + return new DHKeyPairPKCS8Codec(); + default: + throw new KeyAgreementException("Unknown key-type for PKCS#8 format: " + + keyType); + } + default: + throw new KeyAgreementException("Unknown format identifier: " + + formatID); + } + } +} diff --git a/libjava/classpath/gnu/javax/crypto/key/KeyAgreementException.java b/libjava/classpath/gnu/javax/crypto/key/KeyAgreementException.java new file mode 100644 index 000000000..06a7db70b --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/key/KeyAgreementException.java @@ -0,0 +1,168 @@ +/* KeyAgreementException.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.key; + +import gnu.java.lang.CPStringBuilder; + +import java.io.PrintStream; +import java.io.PrintWriter; +import java.io.Serializable; +import java.security.KeyManagementException; + +/** + * A generic exception indicating that an unexpected condition has been detected + * during the setup and/or processing of a key agreement protocol exchange. + */ +public class KeyAgreementException + extends KeyManagementException + implements Serializable +{ + /** @serial The possibly <code>null</code> <i>root</i> cause exception. */ + private Throwable cause = null; + + /** + * Constructs a new instance of <code>KeyAgreementException</code>. The + * root exception and the detailed message are <code>null</code>. + */ + public KeyAgreementException() + { + super(); + } + + /** + * Constructs a new instance of <code>KeyAgreementException</code> with a + * detailed message. The <i>root</i> exception is <code>null</code>. + * + * @param detail a possibly <code>null</code> string containing details of + * the exception. + * @see Throwable#getMessage() + */ + public KeyAgreementException(String detail) + { + super(detail); + } + + /** + * Constructs a new instance of <code>KeyAgreementException</code> with a + * detailed message and a <i>root</i> exception. + * + * @param detail a possibly <code>null</code> string containing details of + * the exception. + * @param cause a possibly <code>null</code> root exception that caused this + * exception. + * @see Throwable#getMessage() + * @see #getCause() + */ + public KeyAgreementException(String detail, Throwable cause) + { + super(detail); + this.cause = cause; + } + + /** + * Returns the cause of this throwable or <code>null</code> if the cause is + * nonexistent or unknown. The <i>cause</i> is the throwable that caused this + * exception to be thrown. + * + * @return the possibly <code>null</code> exception that caused this one. + */ + public Throwable getCause() + { + return cause; + } + + /** + * Prints this exception's stack trace to <code>System.err</code>. If this + * exception has a <i>root</i> exception; the stack trace of the <i>root</i> + * exception is also printed to <code>System.err</code>. + */ + public void printStackTrace() + { + super.printStackTrace(); + if (cause != null) + cause.printStackTrace(); + } + + /** + * Prints this exception's stack trace to a print stream. If this exception + * has a <i>root</i> exception; the stack trace of the <i>root</i> exception + * is also printed to the print stream. + * + * @param ps the non-null print stream to which to print. + */ + public void printStackTrace(PrintStream ps) + { + super.printStackTrace(ps); + if (cause != null) + cause.printStackTrace(ps); + } + + /** + * Prints this exception's stack trace to a print writer. If this exception + * has a <i>root</i> exception; the stack trace of the <i>root</i> exception + * is also printed to the print writer. + * + * @param pw the non-null print writer to use for output. + */ + public void printStackTrace(PrintWriter pw) + { + super.printStackTrace(pw); + if (cause != null) + cause.printStackTrace(pw); + } + + /** + * Returns the string representation of this exception. The string + * representation contains this exception's class name, its detailed messsage, + * and if it has a <i>root</i> exception, the string representation of the + * root exception. This string representation is meant for debugging and is + * not meant to be interpreted programmatically. + * + * @return the non-null string representation of this exception. + * @see Throwable#getMessage() + */ + public String toString() + { + CPStringBuilder sb = new CPStringBuilder(this.getClass().getName()).append(": ") + .append(super.toString()); + if (cause != null) + sb.append("; caused by: ").append(cause.toString()); + return sb.toString(); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/key/KeyAgreementFactory.java b/libjava/classpath/gnu/javax/crypto/key/KeyAgreementFactory.java new file mode 100644 index 000000000..a4e14bc69 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/key/KeyAgreementFactory.java @@ -0,0 +1,143 @@ +/* KeyAgreementFactory.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.key; + +import gnu.java.security.Registry; + +import gnu.javax.crypto.key.dh.DiffieHellmanSender; +import gnu.javax.crypto.key.dh.DiffieHellmanReceiver; +import gnu.javax.crypto.key.dh.ElGamalSender; +import gnu.javax.crypto.key.dh.ElGamalReceiver; +import gnu.javax.crypto.key.srp6.SRP6Host; +import gnu.javax.crypto.key.srp6.SRP6User; +import gnu.javax.crypto.key.srp6.SRP6SaslClient; +import gnu.javax.crypto.key.srp6.SRP6SaslServer; +import gnu.javax.crypto.key.srp6.SRP6TLSClient; +import gnu.javax.crypto.key.srp6.SRP6TLSServer; + +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; + +/** + * A <i>Factory</i> class to generate key agreement protocol handlers. + */ +public class KeyAgreementFactory +{ + /** Trivial constructor to enforce <i>Singleton</i> pattern. */ + private KeyAgreementFactory() + { + super(); + } + + /** + * Returns an instance of a key agreeent protocol handler, for party + * <code>A</code> in a two-party <code>A..B</code> exchange, given the + * canonical name of this protocol. Party <code>A</code> is usually the + * initiator of the exchange. + * + * @param name the case-insensitive key agreement protocol name. + * @return an instance of the key agreement protocol handler for party + * <code>A</code>, or <code>null</code> if none found. + */ + public static IKeyAgreementParty getPartyAInstance(String name) + { + if (name == null) + return null; + name = name.trim(); + IKeyAgreementParty result = null; + if (name.equalsIgnoreCase(Registry.DH_KA)) + result = new DiffieHellmanSender(); + else if (name.equalsIgnoreCase(Registry.ELGAMAL_KA)) + result = new ElGamalSender(); + else if (name.equalsIgnoreCase(Registry.SRP6_KA)) + result = new SRP6User(); + else if (name.equalsIgnoreCase(Registry.SRP_SASL_KA)) + result = new SRP6SaslClient(); + else if (name.equalsIgnoreCase(Registry.SRP_TLS_KA)) + result = new SRP6TLSClient(); + return result; + } + + /** + * Returns an instance of a key agreeent protocol handler, for party + * <code>B</code> in a two-party <code>A..B</code> exchange, given the + * canonical name of this protocol. + * + * @param name the case-insensitive key agreement protocol name. + * @return an instance of the key agreement protocol handler for party + * <code>B</code>, or <code>null</code> if none found. + */ + public static IKeyAgreementParty getPartyBInstance(String name) + { + if (name == null) + return null; + name = name.trim(); + IKeyAgreementParty result = null; + if (name.equalsIgnoreCase(Registry.DH_KA)) + result = new DiffieHellmanReceiver(); + else if (name.equalsIgnoreCase(Registry.ELGAMAL_KA)) + result = new ElGamalReceiver(); + else if (name.equalsIgnoreCase(Registry.SRP6_KA)) + result = new SRP6Host(); + else if (name.equalsIgnoreCase(Registry.SRP_SASL_KA)) + result = new SRP6SaslServer(); + else if (name.equalsIgnoreCase(Registry.SRP_TLS_KA)) + result = new SRP6TLSServer(); + return result; + } + + /** + * Returns a {@link Set} of key agreement protocol names supported by this + * <i>Factory</i>. + * + * @return a {@link Set} of key agreement protocol names (Strings). + */ + public static final Set getNames() + { + HashSet hs = new HashSet(); + hs.add(Registry.DH_KA); + hs.add(Registry.ELGAMAL_KA); + hs.add(Registry.SRP6_KA); + hs.add(Registry.SRP_SASL_KA); + hs.add(Registry.SRP_TLS_KA); + + return Collections.unmodifiableSet(hs); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/key/OutgoingMessage.java b/libjava/classpath/gnu/javax/crypto/key/OutgoingMessage.java new file mode 100644 index 000000000..e011330fe --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/key/OutgoingMessage.java @@ -0,0 +1,234 @@ +/* OutgoingMessage.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.key; + +import gnu.java.security.Registry; +import gnu.java.security.key.dss.DSSKey; +import gnu.java.security.key.rsa.GnuRSAKey; +import gnu.java.security.util.FormatUtil; +import gnu.javax.crypto.key.dh.GnuDHKey; +import gnu.javax.crypto.key.srp6.SRPKey; + +import java.io.ByteArrayOutputStream; +import java.io.UnsupportedEncodingException; +import java.security.Key; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.math.BigInteger; + +/** + * An implementation of outgoing messages for use with key agreement protocols. + */ +public class OutgoingMessage +{ + /** The internal output stream. */ + private ByteArrayOutputStream out; + + public OutgoingMessage() + { + super(); + + out = new ByteArrayOutputStream(); + } + + /** + * Returns the encoded form of the current message including the 4-byte length + * header. + * + * @throws KeyAgreementException if an encoding size constraint is violated. + */ + public byte[] toByteArray() throws KeyAgreementException + { + byte[] buffer = wrap(); + int length = buffer.length; + byte[] result = new byte[length + 4]; + result[0] = (byte)(length >>> 24); + result[1] = (byte)(length >>> 16); + result[2] = (byte)(length >>> 8); + result[3] = (byte) length; + System.arraycopy(buffer, 0, result, 4, length); + return result; + } + + /** + * Returns the encoded form of the current message excluding the 4-byte length + * header. + * + * @throws KeyAgreementException if an encoding size constraint is violated. + */ + public byte[] wrap() throws KeyAgreementException + { + int length = out.size(); + if (length > Registry.SASL_BUFFER_MAX_LIMIT || length < 0) + throw new KeyAgreementException("message content is too long"); + return out.toByteArray(); + } + + /** + * Encodes a public key into the message. + * <p> + * When a public key is encoded into an outgoing message, the byte array of + * the encoded key --according to its encoding/decoding format specified when + * the key was first instantiated-- are put in the message (a) preceeded by + * one byte representing both the type of key (upper 4-bit) and the identifier + * of the format used (lower 4-bit), and (b) preceeed by a 4-byte entity + * representing the total length, excluding these 4 bytes, of the bytes + * representing the encoded key and the one-byte representing the key-type and + * format; i.e. + * <pre> + * key --> 4-byte-length || 1-byte-type-and-format || encoded-key-bytes + * </pre> + * + * @param k the public key to encode. + * @throws KeyAgreementException if an encoding size constraint is violated. + */ + public void writePublicKey(PublicKey k) throws KeyAgreementException + { + writeKey(k); + } + + /** + * Encodes a private key into the message. + * <p> + * When a private key is encoded into an outgoing message, the byte array of + * the encoded key --according to its encoding/decoding format specified when + * the key was first instantiated-- are put in the message (a) preceeded by + * one byte representing both the type of key (upper 4-bit) and the identifier + * of the format used (lower 4-bit), and (b) preceeed by a 4-byte entity + * representing the total length, excluding these 4 bytes, of the bytes + * representing the encoded key and the one-byte representing the key-type and + * format; i.e. + * <pre> + * key --> 4-byte-length || 1-byte-type-and-format || encoded-key-bytes + * </pre> + * + * @param k the private key to encode. + * @throws KeyAgreementException if an encoding size constraint is violated. + */ + public void writePrivateKey(PrivateKey k) throws KeyAgreementException + { + writeKey(k); + } + + /** + * Encodes an MPI into the message. + * + * @param val the MPI to encode. + * @throws KeyAgreementException if an encoding size constraint is violated. + */ + public void writeMPI(BigInteger val) throws KeyAgreementException + { + byte[] b = val.toByteArray(); + int length = b.length; + if (length > Registry.SASL_TWO_BYTE_MAX_LIMIT) + throw new KeyAgreementException("MPI is too long"); + byte[] lengthBytes = { (byte)(length >>> 8), (byte) length }; + out.write(lengthBytes, 0, 2); + out.write(b, 0, b.length); + } + + /** + * Encodes a string into the message. + * + * @param s the string to encode. + * @throws KeyAgreementException if the UTF8 encoding is not supported on this + * platform, or if an encoding size constraint is violated. + */ + public void writeString(String s) throws KeyAgreementException + { + byte[] b = null; + try + { + b = s.getBytes("UTF8"); + } + catch (UnsupportedEncodingException x) + { + throw new KeyAgreementException("unxupported UTF8 encoding", x); + } + int length = b.length; + if (length > Registry.SASL_TWO_BYTE_MAX_LIMIT) + throw new KeyAgreementException("text too long"); + byte[] lengthBytes = { (byte)(length >>> 8), (byte) length }; + out.write(lengthBytes, 0, 2); + out.write(b, 0, b.length); + } + + /** + * @param k the key to encode. + * @throws KeyAgreementException if an encoding size constraint is violated. + */ + private void writeKey(Key k) throws KeyAgreementException + { + byte[] b = k.getEncoded(); + int keyType = getKeyType(k); + int formatID = FormatUtil.getFormatID(k.getFormat()); + int length = b.length + 1; + if (length > Registry.SASL_FOUR_BYTE_MAX_LIMIT) + throw new KeyAgreementException("Encoded key is too long"); + byte[] lengthBytes = { + (byte)(length >>> 24), + (byte)(length >>> 16), + (byte)(length >>> 8), + (byte) length }; + out.write(lengthBytes, 0, 4); + out.write(((keyType & 0x0F) << 4) | (formatID & 0x0F)); + out.write(b, 0, b.length); + } + + /** + * @param k the key to find an identifier for. + * @return an integer from <code>0</code> to <code>3</code> identifying + * the type of key. + * @throws KeyAgreementException if the designated key is of unknown or + * unsupported type. + */ + private int getKeyType(Key k) throws KeyAgreementException + { + if (k instanceof DSSKey) + return 0; + if (k instanceof GnuRSAKey) + return 1; + if (k instanceof GnuDHKey) + return 2; + if (k instanceof SRPKey) + return 3; + throw new KeyAgreementException("Unknown or unsupported key type: " + + k.getClass().getName()); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/key/dh/DHKeyPairPKCS8Codec.java b/libjava/classpath/gnu/javax/crypto/key/dh/DHKeyPairPKCS8Codec.java new file mode 100644 index 000000000..8c03cbb00 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/key/dh/DHKeyPairPKCS8Codec.java @@ -0,0 +1,240 @@ +/* DHKeyPairPKCS8Codec.java -- PKCS#8 encoder/decoder for DH keys + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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; either version 2, or (at your option) +any later version. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.key.dh; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.math.BigInteger; +import java.security.InvalidParameterException; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.util.ArrayList; + +import gnu.java.security.OID; +import gnu.java.security.Registry; +import gnu.java.security.der.DER; +import gnu.java.security.der.DERReader; +import gnu.java.security.der.DERValue; +import gnu.java.security.der.DERWriter; +import gnu.java.security.key.IKeyPairCodec; +import gnu.java.security.util.DerUtil; +import gnu.java.security.util.Util; + +public class DHKeyPairPKCS8Codec + implements IKeyPairCodec +{ + private static final OID DH_ALG_OID = new OID(Registry.DH_OID_STRING); + + // implicit 0-arguments constructor + + public int getFormatID() + { + return PKCS8_FORMAT; + } + + /** + * @throws InvalidParameterException ALWAYS. + */ + public byte[] encodePublicKey(PublicKey key) + { + throw new InvalidParameterException("Wrong format for public keys"); + } + + /** + * Returns the DER-encoded form of the PKCS#8 ASN.1 <i>PrivateKeyInfo</i> + * representation of a DH private key. The ASN.1 specification is as follows: + * + * <pre> + * PrivateKeyInfo ::= SEQUENCE { + * version INTEGER, -- MUST be 0 + * privateKeyAlgorithm AlgorithmIdentifier, + * privateKey OCTET STRING + * } + * + * AlgorithmIdentifier ::= SEQUENCE { + * algorithm OBJECT IDENTIFIER, + * parameters ANY DEFINED BY algorithm OPTIONAL + * } + * + * DhParams ::= SEQUENCE { + * p INTEGER, -- odd prime, p=jq +1 + * g INTEGER, -- generator, g + * q INTEGER -- factor of p-1 + * } + * </pre> + * <p> + * <b>IMPORTANT</b>: with RI's {@link javax.crypto.spec.DHGenParameterSpec} + * and {@link javax.crypto.spec.DHParameterSpec} classes, we may end up with + * Diffie-Hellman keys that have a <code>null</code> for the <code>q</code> + * parameter. RFC-2631 DOES NOT allow for an <i>optional</i> value for that + * parameter, hence we replace such null values with <code>0</code>, and do + * the reverse in the corresponding decode method. + * + * @return the DER encoded form of the ASN.1 representation of the + * <i>PrivateKeyInfo</i> field in an X.509 certificate. + * @throw InvalidParameterException if an error occurs during the marshalling + * process. + */ + public byte[] encodePrivateKey(PrivateKey key) + { + if (! (key instanceof GnuDHPrivateKey)) + throw new InvalidParameterException("Wrong key type"); + + DERValue derVersion = new DERValue(DER.INTEGER, BigInteger.ZERO); + + DERValue derOID = new DERValue(DER.OBJECT_IDENTIFIER, DH_ALG_OID); + + GnuDHPrivateKey pk = (GnuDHPrivateKey) key; + BigInteger p = pk.getParams().getP(); + BigInteger g = pk.getParams().getG(); + BigInteger q = pk.getQ(); + if (q == null) + q = BigInteger.ZERO; + BigInteger x = pk.getX(); + + ArrayList params = new ArrayList(3); + params.add(new DERValue(DER.INTEGER, p)); + params.add(new DERValue(DER.INTEGER, g)); + params.add(new DERValue(DER.INTEGER, q)); + DERValue derParams = new DERValue(DER.CONSTRUCTED | DER.SEQUENCE, params); + + ArrayList algorithmID = new ArrayList(2); + algorithmID.add(derOID); + algorithmID.add(derParams); + DERValue derAlgorithmID = new DERValue(DER.CONSTRUCTED | DER.SEQUENCE, + algorithmID); + + DERValue derPrivateKey = new DERValue(DER.OCTET_STRING, Util.trim(x)); + + ArrayList pki = new ArrayList(3); + pki.add(derVersion); + pki.add(derAlgorithmID); + pki.add(derPrivateKey); + DERValue derPKI = new DERValue(DER.CONSTRUCTED | DER.SEQUENCE, pki); + + byte[] result; + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + try + { + DERWriter.write(baos, derPKI); + result = baos.toByteArray(); + } + catch (IOException e) + { + InvalidParameterException y = new InvalidParameterException(); + y.initCause(e); + throw y; + } + + return result; + } + + /** + * @throws InvalidParameterException ALWAYS. + */ + public PublicKey decodePublicKey(byte[] input) + { + throw new InvalidParameterException("Wrong format for public keys"); + } + + /** + * @param input the byte array to unmarshall into a valid DH + * {@link PrivateKey} instance. MUST NOT be null. + * @return a new instance of a {@link GnuDHPrivateKey} decoded from the + * <i>PrivateKeyInfo</i> material fed as <code>input</code>. + * @throw InvalidParameterException if an exception occurs during the + * unmarshalling process. + */ + public PrivateKey decodePrivateKey(byte[] input) + { + if (input == null) + throw new InvalidParameterException("Input bytes MUST NOT be null"); + + BigInteger version, p, q, g, x; + DERReader der = new DERReader(input); + try + { + DERValue derPKI = der.read(); + DerUtil.checkIsConstructed(derPKI, "Wrong PrivateKeyInfo field"); + + DERValue derVersion = der.read(); + if (! (derVersion.getValue() instanceof BigInteger)) + throw new InvalidParameterException("Wrong Version field"); + + version = (BigInteger) derVersion.getValue(); + if (version.compareTo(BigInteger.ZERO) != 0) + throw new InvalidParameterException("Unexpected Version: " + version); + + DERValue derAlgoritmID = der.read(); + DerUtil.checkIsConstructed(derAlgoritmID, "Wrong AlgorithmIdentifier field"); + + DERValue derOID = der.read(); + OID algOID = (OID) derOID.getValue(); + if (! algOID.equals(DH_ALG_OID)) + throw new InvalidParameterException("Unexpected OID: " + algOID); + + DERValue derParams = der.read(); + DerUtil.checkIsConstructed(derParams, "Wrong DSS Parameters field"); + + DERValue val = der.read(); + DerUtil.checkIsBigInteger(val, "Wrong P field"); + p = (BigInteger) val.getValue(); + val = der.read(); + DerUtil.checkIsBigInteger(val, "Wrong G field"); + g = (BigInteger) val.getValue(); + val = der.read(); + DerUtil.checkIsBigInteger(val, "Wrong Q field"); + q = (BigInteger) val.getValue(); + if (q.compareTo(BigInteger.ZERO) == 0) + q = null; + + val = der.read(); + byte[] xBytes = (byte[]) val.getValue(); + x = new BigInteger(1, xBytes); + } + catch (IOException e) + { + InvalidParameterException y = new InvalidParameterException(); + y.initCause(e); + throw y; + } + + return new GnuDHPrivateKey(Registry.PKCS8_ENCODING_ID, q, p, g, x); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/key/dh/DHKeyPairRawCodec.java b/libjava/classpath/gnu/javax/crypto/key/dh/DHKeyPairRawCodec.java new file mode 100644 index 000000000..4275389ce --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/key/dh/DHKeyPairRawCodec.java @@ -0,0 +1,336 @@ +/* DHKeyPairRawCodec.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.key.dh; + +import gnu.java.security.Registry; +import gnu.java.security.key.IKeyPairCodec; + +import java.io.ByteArrayOutputStream; +import java.math.BigInteger; +import java.security.PrivateKey; +import java.security.PublicKey; + +/** + * An object that implements the {@link IKeyPairCodec} operations for the + * <i>Raw</i> format to use with Diffie-Hellman keypairs. + */ +public class DHKeyPairRawCodec + implements IKeyPairCodec +{ + public int getFormatID() + { + return RAW_FORMAT; + } + + /** + * Returns the encoded form of the designated Diffie-Hellman public key + * according to the <i>Raw</i> format supported by this library. + * <p> + * The <i>Raw</i> format for a DH public key, in this implementation, is a + * byte sequence consisting of the following: + * <ol> + * <li>4-byte magic consisting of the value of the literal + * {@link Registry#MAGIC_RAW_DH_PUBLIC_KEY},</li> + * <li>1-byte version consisting of the constant: 0x01,</li> + * <li>4-byte count of following bytes representing the DH parameter + * <code>q</code> in internet order,</li> + * <li>n-bytes representation of a {@link BigInteger} obtained by invoking + * the <code>toByteArray()</code> method on the DH parameter <code>q</code>, + * </li> + * <li>4-byte count of following bytes representing the DH parameter + * <code>p</code> in internet order,</li> + * <li>n-bytes representation of a {@link BigInteger} obtained by invoking + * the <code>toByteArray()</code> method on the DH parameter <code>p</code>, + * </li> + * <li>4-byte count of following bytes representing the DH parameter + * <code>g</code>,</li> + * <li>n-bytes representation of a {@link BigInteger} obtained by invoking + * the <code>toByteArray()</code> method on the DH parameter <code>g</code>, + * </li> + * <li>4-byte count of following bytes representing the DH parameter + * <code>y</code>,</li> + * <li>n-bytes representation of a {@link BigInteger} obtained by invoking + * the <code>toByteArray()</code> method on the DH parameter <code>y</code>, + * </li> + * </ol> + * + * @param key the key to encode. + * @return the <i>Raw</i> format encoding of the designated key. + * @throws IllegalArgumentException if the designated key is not a DH one. + * @see Registry#MAGIC_RAW_DH_PUBLIC_KEY + */ + public byte[] encodePublicKey(PublicKey key) + { + if (! (key instanceof GnuDHPublicKey)) + throw new IllegalArgumentException("key"); + GnuDHPublicKey dhKey = (GnuDHPublicKey) key; + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + // magic + baos.write(Registry.MAGIC_RAW_DH_PUBLIC_KEY[0]); + baos.write(Registry.MAGIC_RAW_DH_PUBLIC_KEY[1]); + baos.write(Registry.MAGIC_RAW_DH_PUBLIC_KEY[2]); + baos.write(Registry.MAGIC_RAW_DH_PUBLIC_KEY[3]); + // version + baos.write(0x01); + // q + byte[] buffer = dhKey.getQ().toByteArray(); + int length = buffer.length; + baos.write( length >>> 24); + baos.write((length >>> 16) & 0xFF); + baos.write((length >>> 8) & 0xFF); + baos.write( length & 0xFF); + baos.write(buffer, 0, length); + // p + buffer = dhKey.getParams().getP().toByteArray(); + length = buffer.length; + baos.write( length >>> 24); + baos.write((length >>> 16) & 0xFF); + baos.write((length >>> 8) & 0xFF); + baos.write( length & 0xFF); + baos.write(buffer, 0, length); + // g + buffer = dhKey.getParams().getG().toByteArray(); + length = buffer.length; + baos.write( length >>> 24); + baos.write((length >>> 16) & 0xFF); + baos.write((length >>> 8) & 0xFF); + baos.write( length & 0xFF); + baos.write(buffer, 0, length); + // y + buffer = dhKey.getY().toByteArray(); + length = buffer.length; + baos.write( length >>> 24); + baos.write((length >>> 16) & 0xFF); + baos.write((length >>> 8) & 0xFF); + baos.write( length & 0xFF); + baos.write(buffer, 0, length); + return baos.toByteArray(); + } + + public PublicKey decodePublicKey(byte[] k) + { + // magic + if (k[0] != Registry.MAGIC_RAW_DH_PUBLIC_KEY[0] + || k[1] != Registry.MAGIC_RAW_DH_PUBLIC_KEY[1] + || k[2] != Registry.MAGIC_RAW_DH_PUBLIC_KEY[2] + || k[3] != Registry.MAGIC_RAW_DH_PUBLIC_KEY[3]) + throw new IllegalArgumentException("magic"); + // version + if (k[4] != 0x01) + throw new IllegalArgumentException("version"); + int i = 5; + int l; + byte[] buffer; + // q + l = k[i++] << 24 + | (k[i++] & 0xFF) << 16 + | (k[i++] & 0xFF) << 8 + | (k[i++] & 0xFF); + buffer = new byte[l]; + System.arraycopy(k, i, buffer, 0, l); + i += l; + BigInteger q = new BigInteger(1, buffer); + // p + l = k[i++] << 24 + | (k[i++] & 0xFF) << 16 + | (k[i++] & 0xFF) << 8 + | (k[i++] & 0xFF); + buffer = new byte[l]; + System.arraycopy(k, i, buffer, 0, l); + i += l; + BigInteger p = new BigInteger(1, buffer); + // g + l = k[i++] << 24 + | (k[i++] & 0xFF) << 16 + | (k[i++] & 0xFF) << 8 + | (k[i++] & 0xFF); + buffer = new byte[l]; + System.arraycopy(k, i, buffer, 0, l); + i += l; + BigInteger g = new BigInteger(1, buffer); + // y + l = k[i++] << 24 + | (k[i++] & 0xFF) << 16 + | (k[i++] & 0xFF) << 8 + | (k[i++] & 0xFF); + buffer = new byte[l]; + System.arraycopy(k, i, buffer, 0, l); + i += l; + BigInteger y = new BigInteger(1, buffer); + return new GnuDHPublicKey(q, p, g, y); + } + + /** + * Returns the encoded form of the designated Diffie-Hellman private key + * according to the <i>Raw</i> format supported by this library. + * <p> + * The <i>Raw</i> format for a DH private key, in this implementation, is a + * byte sequence consisting of the following: + * <ol> + * <li>4-byte magic consisting of the value of the literal + * {@link Registry#MAGIC_RAW_DH_PRIVATE_KEY},</li> + * <li>1-byte version consisting of the constant: 0x01,</li> + * <li>4-byte count of following bytes representing the DH parameter + * <code>q</code>,</li> + * <li>n-bytes representation of a {@link BigInteger} obtained by invoking + * the <code>toByteArray()</code> method on the DH parameter <code>q</code>, + * </li> + * <li>4-byte count of following bytes representing the DH parameter + * <code>p</code> in internet order,</li> + * <li>n-bytes representation of a {@link BigInteger} obtained by invoking + * the <code>toByteArray()</code> method on the DH parameter <code>p</code>, + * </li> + * <li>4-byte count of following bytes representing the DH parameter + * <code>g</code>,</li> + * <li>n-bytes representation of a {@link BigInteger} obtained by invoking + * the <code>toByteArray()</code> method on the DH parameter <code>g</code>, + * </li> + * <li>4-byte count of following bytes representing the DH parameter + * <code>x</code>,</li> + * <li>n-bytes representation of a {@link BigInteger} obtained by invoking + * the <code>toByteArray()</code> method on the DH parameter <code>x</code>, + * </li> + * </ol> + * + * @param key the key to encode. + * @return the <i>Raw</i> format encoding of the designated key. + * @throws IllegalArgumentException if the designated key is not a DH one. + * @see Registry#MAGIC_RAW_DH_PRIVATE_KEY + */ + public byte[] encodePrivateKey(PrivateKey key) + { + if (! (key instanceof GnuDHPrivateKey)) + throw new IllegalArgumentException("key"); + GnuDHPrivateKey dhKey = (GnuDHPrivateKey) key; + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + // magic + baos.write(Registry.MAGIC_RAW_DH_PRIVATE_KEY[0]); + baos.write(Registry.MAGIC_RAW_DH_PRIVATE_KEY[1]); + baos.write(Registry.MAGIC_RAW_DH_PRIVATE_KEY[2]); + baos.write(Registry.MAGIC_RAW_DH_PRIVATE_KEY[3]); + // version + baos.write(0x01); + // q + byte[] buffer = dhKey.getQ().toByteArray(); + int length = buffer.length; + baos.write( length >>> 24); + baos.write((length >>> 16) & 0xFF); + baos.write((length >>> 8) & 0xFF); + baos.write( length & 0xFF); + baos.write(buffer, 0, length); + // p + buffer = dhKey.getParams().getP().toByteArray(); + length = buffer.length; + baos.write( length >>> 24); + baos.write((length >>> 16) & 0xFF); + baos.write((length >>> 8) & 0xFF); + baos.write( length & 0xFF); + baos.write(buffer, 0, length); + // g + buffer = dhKey.getParams().getG().toByteArray(); + length = buffer.length; + baos.write( length >>> 24); + baos.write((length >>> 16) & 0xFF); + baos.write((length >>> 8) & 0xFF); + baos.write( length & 0xFF); + baos.write(buffer, 0, length); + // x + buffer = dhKey.getX().toByteArray(); + length = buffer.length; + baos.write( length >>> 24); + baos.write((length >>> 16) & 0xFF); + baos.write((length >>> 8) & 0xFF); + baos.write( length & 0xFF); + baos.write(buffer, 0, length); + return baos.toByteArray(); + } + + public PrivateKey decodePrivateKey(byte[] k) + { + // magic + if (k[0] != Registry.MAGIC_RAW_DH_PRIVATE_KEY[0] + || k[1] != Registry.MAGIC_RAW_DH_PRIVATE_KEY[1] + || k[2] != Registry.MAGIC_RAW_DH_PRIVATE_KEY[2] + || k[3] != Registry.MAGIC_RAW_DH_PRIVATE_KEY[3]) + throw new IllegalArgumentException("magic"); + // version + if (k[4] != 0x01) + throw new IllegalArgumentException("version"); + int i = 5; + int l; + byte[] buffer; + // q + l = k[i++] << 24 + | (k[i++] & 0xFF) << 16 + | (k[i++] & 0xFF) << 8 + | (k[i++] & 0xFF); + buffer = new byte[l]; + System.arraycopy(k, i, buffer, 0, l); + i += l; + BigInteger q = new BigInteger(1, buffer); + // p + l = k[i++] << 24 + | (k[i++] & 0xFF) << 16 + | (k[i++] & 0xFF) << 8 + | (k[i++] & 0xFF); + buffer = new byte[l]; + System.arraycopy(k, i, buffer, 0, l); + i += l; + BigInteger p = new BigInteger(1, buffer); + // g + l = k[i++] << 24 + | (k[i++] & 0xFF) << 16 + | (k[i++] & 0xFF) << 8 + | (k[i++] & 0xFF); + buffer = new byte[l]; + System.arraycopy(k, i, buffer, 0, l); + i += l; + BigInteger g = new BigInteger(1, buffer); + // x + l = k[i++] << 24 + | (k[i++] & 0xFF) << 16 + | (k[i++] & 0xFF) << 8 + | (k[i++] & 0xFF); + buffer = new byte[l]; + System.arraycopy(k, i, buffer, 0, l); + i += l; + BigInteger x = new BigInteger(1, buffer); + return new GnuDHPrivateKey(q, p, g, x); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/key/dh/DHKeyPairX509Codec.java b/libjava/classpath/gnu/javax/crypto/key/dh/DHKeyPairX509Codec.java new file mode 100644 index 000000000..893716eef --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/key/dh/DHKeyPairX509Codec.java @@ -0,0 +1,255 @@ +/* DHKeyPairX509Codec.java -- X.509 DER encoder/decoder for DH keys + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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; either version 2, or (at your option) +any later version. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.key.dh; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.math.BigInteger; +import java.security.InvalidParameterException; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.util.ArrayList; + +import gnu.java.security.OID; +import gnu.java.security.Registry; +import gnu.java.security.der.BitString; +import gnu.java.security.der.DER; +import gnu.java.security.der.DERReader; +import gnu.java.security.der.DERValue; +import gnu.java.security.der.DERWriter; +import gnu.java.security.key.IKeyPairCodec; +import gnu.java.security.util.DerUtil; + +public class DHKeyPairX509Codec + implements IKeyPairCodec +{ + private static final OID DH_ALG_OID = new OID(Registry.DH_OID_STRING); + + // implicit 0-arguments constructor + + public int getFormatID() + { + return X509_FORMAT; + } + + /** + * Returns the DER-encoded form of the X.509 ASN.1 <i>SubjectPublicKeyInfo</i> + * representation of a DH public key. The ASN.1 specification, as defined in + * RFC-3280, and RFC-2459, is as follows: + * + * <pre> + * SubjectPublicKeyInfo ::= SEQUENCE { + * algorithm AlgorithmIdentifier, + * subjectPublicKey BIT STRING + * } + * + * AlgorithmIdentifier ::= SEQUENCE { + * algorithm OBJECT IDENTIFIER, + * parameters ANY DEFINED BY algorithm OPTIONAL + * } + * + * DhParams ::= SEQUENCE { + * p INTEGER, -- odd prime, p=jq +1 + * g INTEGER, -- generator, g + * q INTEGER -- factor of p-1 + * } + * </pre> + * + * <p>The <i>subjectPublicKey</i> field, which is a BIT STRING, contains the + * DER-encoded form of the DH public key as an INTEGER.</p> + * + * <pre> + * DHPublicKey ::= INTEGER -- public key, y = g^x mod p + * </pre> + * <p> + * <b>IMPORTANT</b>: with RI's {@link javax.crypto.spec.DHGenParameterSpec} + * and {@link javax.crypto.spec.DHParameterSpec} classes, we may end up with + * Diffie-Hellman keys that have a <code>null</code> for the <code>q</code> + * parameter. RFC-2631 DOES NOT allow for an <i>optional</i> value for that + * parameter, hence we replace such null values with <code>0</code>, and do + * the reverse in the corresponding decode method. + * + * @param key the {@link PublicKey} instance to encode. MUST be an instance of + * {@link GnuDHPublicKey}. + * @return the DER-encoded form of the ASN.1 representation of the + * <i>SubjectPublicKeyInfo</i> in an X.509 certificate. + * @throw InvalidParameterException if <code>key</code> is not an instance + * of {@link GnuDHPublicKey} or if an exception occurs during the + * marshalling process. + */ + public byte[] encodePublicKey(PublicKey key) + { + if (! (key instanceof GnuDHPublicKey)) + throw new InvalidParameterException("Wrong key type"); + + DERValue derOID = new DERValue(DER.OBJECT_IDENTIFIER, DH_ALG_OID); + + GnuDHPublicKey dhKey = (GnuDHPublicKey) key; + BigInteger p = dhKey.getParams().getP(); + BigInteger g = dhKey.getParams().getG(); + BigInteger q = dhKey.getQ(); + if (q == null) + q = BigInteger.ZERO; + BigInteger y = dhKey.getY(); + + DERValue derP = new DERValue(DER.INTEGER, p); + DERValue derG = new DERValue(DER.INTEGER, g); + DERValue derQ = new DERValue(DER.INTEGER, q); + + ArrayList params = new ArrayList(3); + params.add(derP); + params.add(derG); + params.add(derQ); + DERValue derParams = new DERValue(DER.CONSTRUCTED | DER.SEQUENCE, params); + + ArrayList algorithmID = new ArrayList(2); + algorithmID.add(derOID); + algorithmID.add(derParams); + DERValue derAlgorithmID = new DERValue(DER.CONSTRUCTED | DER.SEQUENCE, + algorithmID); + + DERValue derDHPublicKey = new DERValue(DER.INTEGER, y); + byte[] yBytes = derDHPublicKey.getEncoded(); + DERValue derSPK = new DERValue(DER.BIT_STRING, new BitString(yBytes)); + + ArrayList spki = new ArrayList(2); + spki.add(derAlgorithmID); + spki.add(derSPK); + DERValue derSPKI = new DERValue(DER.CONSTRUCTED | DER.SEQUENCE, spki); + + byte[] result; + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + try + { + DERWriter.write(baos, derSPKI); + result = baos.toByteArray(); + } + catch (IOException x) + { + InvalidParameterException e = new InvalidParameterException(); + e.initCause(x); + throw e; + } + + return result; + } + + /** + * @throws InvalidParameterException ALWAYS. + */ + public byte[] encodePrivateKey(PrivateKey key) + { + throw new InvalidParameterException("Wrong format for private keys"); + } + + /** + * @param input the byte array to unmarshall into a valid DH + * {@link PublicKey} instance. MUST NOT be null. + * @return a new instance of a {@link GnuDHPublicKey} decoded from the + * <i>SubjectPublicKeyInfo</i> material in an X.509 certificate. + * @throw InvalidParameterException if an exception occurs during the + * unmarshalling process. + */ + public PublicKey decodePublicKey(byte[] input) + { + if (input == null) + throw new InvalidParameterException("Input bytes MUST NOT be null"); + + BigInteger p, g, q, y; + DERReader der = new DERReader(input); + try + { + DERValue derSPKI = der.read(); + DerUtil.checkIsConstructed(derSPKI, "Wrong SubjectPublicKeyInfo field"); + + DERValue derAlgorithmID = der.read(); + DerUtil.checkIsConstructed(derAlgorithmID, "Wrong AlgorithmIdentifier field"); + + DERValue derOID = der.read(); + if (! (derOID.getValue() instanceof OID)) + throw new InvalidParameterException("Wrong Algorithm field"); + + OID algOID = (OID) derOID.getValue(); + if (! algOID.equals(DH_ALG_OID)) + throw new InvalidParameterException("Unexpected OID: " + algOID); + + DERValue derParams = der.read(); + DerUtil.checkIsConstructed(derParams, "Wrong DH Parameters field"); + + DERValue val = der.read(); + DerUtil.checkIsBigInteger(val, "Wrong P field"); + p = (BigInteger) val.getValue(); + val = der.read(); + DerUtil.checkIsBigInteger(val, "Wrong G field"); + g = (BigInteger) val.getValue(); + val = der.read(); + DerUtil.checkIsBigInteger(val, "Wrong Q field"); + q = (BigInteger) val.getValue(); + if (q.compareTo(BigInteger.ZERO) == 0) + q = null; + + val = der.read(); + if (! (val.getValue() instanceof BitString)) + throw new InvalidParameterException("Wrong SubjectPublicKey field"); + + byte[] yBytes = ((BitString) val.getValue()).toByteArray(); + + DERReader dhPub = new DERReader(yBytes); + val = dhPub.read(); + DerUtil.checkIsBigInteger(val, "Wrong Y field"); + y = (BigInteger) val.getValue(); + } + catch (IOException x) + { + InvalidParameterException e = new InvalidParameterException(); + e.initCause(x); + throw e; + } + + return new GnuDHPublicKey(Registry.X509_ENCODING_ID, q, p, g, y); + } + + /** + * @throws InvalidParameterException ALWAYS. + */ + public PrivateKey decodePrivateKey(byte[] input) + { + throw new InvalidParameterException("Wrong format for private keys"); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/key/dh/DiffieHellmanKeyAgreement.java b/libjava/classpath/gnu/javax/crypto/key/dh/DiffieHellmanKeyAgreement.java new file mode 100644 index 000000000..893d84d32 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/key/dh/DiffieHellmanKeyAgreement.java @@ -0,0 +1,119 @@ +/* DiffieHellmanKeyAgreement.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.key.dh; + +import gnu.java.security.Registry; +import gnu.java.security.util.Util; + +import gnu.javax.crypto.key.BaseKeyAgreementParty; +import gnu.javax.crypto.key.KeyAgreementException; + +import java.math.BigInteger; + +import javax.crypto.interfaces.DHPrivateKey; + +/** + * The basic version of the Diffie-Hellman key agreement is described in the + * Handbook of Applied Cryptography [HAC] as follows: + * <ul> + * <li>An appropriate prime p and generator g of Z<sub>p</sub><sup>*</sup> + * (2 <= g <= p-2) are selected and published.</li> + * <li>A and B each send the other one message over an open channel; as a + * result, they both can then compute a shared secret key K which they can use + * to protect their future communication.</li> + * <li>A chooses a random secret x, 1 <= x <= p-2, and sends B message + * (1) which is g^x mod p.</li> + * <li>B chooses a random secret y, 1 <= y <= p-2, and sends A message + * (2) which is g^y mod p.</li> + * <li>B receives message (1) and computes the shared key as K = (g^x)^y mod p. + * </li> + * <li>A receives message (2) and computes the shared key as K = (g^y)^x mod p. + * </li> + * </ul> + * <p> + * RFC-2631 describes a <i>Static-Static Mode</i> of operations with + * Diffie-Hellman keypairs as follows: + * <pre> + * "In Static-Static mode, both the sender and the recipient have a + * static (and certified) key pair. Since the sender's and recipient's + * keys are therefore the same for each message, ZZ will be the same for + * each message. Thus, partyAInfo MUST be used (and different for each + * message) in order to ensure that different messages use different + * KEKs. Implementations MAY implement Static-Static mode." + * </pre> + * + * <p> + * Reference: + * <ol> + * <li><a href="http://www.ietf.org/rfc/rfc2631.txt">Diffie-Hellman Key + * Agreement Method</a><br> + * Eric Rescorla.</li> + * <li><a href="http://www.cacr.math.uwaterloo.ca/hac">[HAC]</a>: Handbook of + * Applied Cryptography.<br> + * CRC Press, Inc. ISBN 0-8493-8523-7, 1997<br> + * Menezes, A., van Oorschot, P. and S. Vanstone.</li> + * </ol> + */ +public abstract class DiffieHellmanKeyAgreement + extends BaseKeyAgreementParty +{ + public static final String SOURCE_OF_RANDOMNESS = "gnu.crypto.dh.ka.prng"; + public static final String KA_DIFFIE_HELLMAN_OWNER_PRIVATE_KEY = + "gnu.crypto.dh.ka.owner.private.key"; + /** The key agreement party's private key. */ + protected DHPrivateKey ownerKey; + /** The shared secret key. */ + protected BigInteger ZZ; + + protected DiffieHellmanKeyAgreement() + { + super(Registry.DH_KA); + } + + protected byte[] engineSharedSecret() throws KeyAgreementException + { + return Util.trim(ZZ); + } + + protected void engineReset() + { + ownerKey = null; + ZZ = null; + } +} diff --git a/libjava/classpath/gnu/javax/crypto/key/dh/DiffieHellmanReceiver.java b/libjava/classpath/gnu/javax/crypto/key/dh/DiffieHellmanReceiver.java new file mode 100644 index 000000000..3194f682d --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/key/dh/DiffieHellmanReceiver.java @@ -0,0 +1,117 @@ +/* DiffieHellmanReceiver.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.key.dh; + +import gnu.java.security.prng.IRandom; + +import gnu.javax.crypto.key.KeyAgreementException; +import gnu.javax.crypto.key.IncomingMessage; +import gnu.javax.crypto.key.OutgoingMessage; + +import java.math.BigInteger; +import java.security.SecureRandom; +import java.util.Map; + +import javax.crypto.interfaces.DHPrivateKey; + +/** + * This implementation is the receiver's part of the basic version of the + * Diffie-Hellman key agreement exchange (B in [HAC]). + * + * @see DiffieHellmanKeyAgreement + */ +public class DiffieHellmanReceiver + extends DiffieHellmanKeyAgreement +{ + private BigInteger y; // the receiver's random secret + + // default 0-arguments constructor + + protected void engineInit(Map attributes) throws KeyAgreementException + { + Object random = attributes.get(SOURCE_OF_RANDOMNESS); + rnd = null; + irnd = null; + if (random instanceof SecureRandom) + rnd = (SecureRandom) random; + else if (random instanceof IRandom) + irnd = (IRandom) random; + ownerKey = (DHPrivateKey) attributes.get(KA_DIFFIE_HELLMAN_OWNER_PRIVATE_KEY); + if (ownerKey == null) + throw new KeyAgreementException("missing owner's private key"); + } + + protected OutgoingMessage engineProcessMessage(IncomingMessage in) + throws KeyAgreementException + { + switch (step) + { + case 0: + return computeSharedSecret(in); + default: + throw new IllegalStateException("unexpected state"); + } + } + + private OutgoingMessage computeSharedSecret(IncomingMessage in) + throws KeyAgreementException + { + BigInteger m1 = in.readMPI(); + if (m1 == null) + throw new KeyAgreementException("missing message (1)"); + BigInteger p = ownerKey.getParams().getP(); + BigInteger g = ownerKey.getParams().getG(); + // B chooses a random integer y, 1 <= y <= p-2 + // rfc-2631 restricts y to only be in [2, p-1] + BigInteger p_minus_2 = p.subtract(TWO); + byte[] xBytes = new byte[(p_minus_2.bitLength() + 7) / 8]; + do + { + nextRandomBytes(xBytes); + y = new BigInteger(1, xBytes); + } + while (! (y.compareTo(TWO) >= 0 && y.compareTo(p_minus_2) <= 0)); + ZZ = m1.modPow(y, p); // ZZ = (yb ^ xa) mod p + complete = true; + // B sends A the message: g^y mod p + OutgoingMessage result = new OutgoingMessage(); + result.writeMPI(g.modPow(y, p)); // message (2) + return result; + } +} diff --git a/libjava/classpath/gnu/javax/crypto/key/dh/DiffieHellmanSender.java b/libjava/classpath/gnu/javax/crypto/key/dh/DiffieHellmanSender.java new file mode 100644 index 000000000..7fc997354 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/key/dh/DiffieHellmanSender.java @@ -0,0 +1,126 @@ +/* DiffieHellmanSender.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.key.dh; + +import gnu.java.security.prng.IRandom; + +import gnu.javax.crypto.key.KeyAgreementException; +import gnu.javax.crypto.key.IncomingMessage; +import gnu.javax.crypto.key.OutgoingMessage; + +import java.math.BigInteger; +import java.security.SecureRandom; +import java.util.Map; + +import javax.crypto.interfaces.DHPrivateKey; + +/** + * This implementation is the sender's part of the basic version of the + * Diffie-Hellman key agreement exchange (A in [HAC]). + * + * @see DiffieHellmanKeyAgreement + */ +public class DiffieHellmanSender + extends DiffieHellmanKeyAgreement +{ + private BigInteger x; // the sender's random secret + + // default 0-arguments constructor + + protected void engineInit(Map attributes) throws KeyAgreementException + { + Object random = attributes.get(SOURCE_OF_RANDOMNESS); + rnd = null; + irnd = null; + if (random instanceof SecureRandom) + rnd = (SecureRandom) random; + else if (random instanceof IRandom) + irnd = (IRandom) random; + ownerKey = (DHPrivateKey) attributes.get(KA_DIFFIE_HELLMAN_OWNER_PRIVATE_KEY); + if (ownerKey == null) + throw new KeyAgreementException("missing owner's private key"); + } + + protected OutgoingMessage engineProcessMessage(IncomingMessage in) + throws KeyAgreementException + { + switch (step) + { + case 0: + return sendRandomSecret(in); + case 1: + return computeSharedSecret(in); + default: + throw new IllegalStateException("unexpected state"); + } + } + + private OutgoingMessage sendRandomSecret(IncomingMessage in) + throws KeyAgreementException + { + BigInteger p = ownerKey.getParams().getP(); + BigInteger g = ownerKey.getParams().getG(); + // A chooses a random integer x, 1 <= x <= p-2 + // rfc-2631 restricts x to only be in [2, p-1] + BigInteger p_minus_2 = p.subtract(TWO); + byte[] xBytes = new byte[(p_minus_2.bitLength() + 7) / 8]; + do + { + nextRandomBytes(xBytes); + x = new BigInteger(1, xBytes); + } + while (! (x.compareTo(TWO) >= 0 && x.compareTo(p_minus_2) <= 0)); + // A sends B the message: g^x mod p + OutgoingMessage result = new OutgoingMessage(); + result.writeMPI(g.modPow(x, p)); + return result; + } + + private OutgoingMessage computeSharedSecret(IncomingMessage in) + throws KeyAgreementException + { + BigInteger m1 = in.readMPI(); + if (m1 == null) + throw new KeyAgreementException("missing message (2)"); + BigInteger p = ownerKey.getParams().getP(); + ZZ = m1.modPow(x, p); // ZZ = (yb ^ xa) mod p + complete = true; + return null; + } +} diff --git a/libjava/classpath/gnu/javax/crypto/key/dh/ElGamalKeyAgreement.java b/libjava/classpath/gnu/javax/crypto/key/dh/ElGamalKeyAgreement.java new file mode 100644 index 000000000..4283dc59b --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/key/dh/ElGamalKeyAgreement.java @@ -0,0 +1,115 @@ +/* ElGamalKeyAgreement.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.key.dh; + +import gnu.java.security.Registry; +import gnu.java.security.util.Util; + +import gnu.javax.crypto.key.BaseKeyAgreementParty; +import gnu.javax.crypto.key.KeyAgreementException; + +import java.math.BigInteger; + +/** + * The ElGamal key agreement, also known as the half-certified Diffie-Hellman + * key agreement, is described in the Handbook of Applied Cryptography [HAC] as + * follows: + * <ul> + * <li>A sends to B a single message allowing one-pass key agreement.</li> + * <li>A obtains an authentic copy of B's public key (p, g, yb), where yb = + * g**xb.</li> + * <li>A chooses a random integer x, 1 <= x <= p-2, and sends B the + * message g**x. A computes the shared secret key K as yb**x.</li> + * <li>B computes the same key K on receipt of the previous message as + * (g**x)**xb.</li> + * </ul> + * <p> + * RFC-2631 describes an <i>Ephemeral-Static Mode</i> of operations with + * Diffie-Hellman keypairs as follows: + * <pre> + * "In Ephemeral-Static mode, the recipient has a static (and certified) + * key pair, but the sender generates a new key pair for each message + * and sends it using the originatorKey production. If the sender's key + * is freshly generated for each message, the shared secret ZZ will be + * similarly different for each message and partyAInfo MAY be omitted, + * since it serves merely to decouple multiple KEKs generated by the + * same set of pairwise keys. If, however, the same ephemeral sender key + * is used for multiple messages (e.g. it is cached as a performance + * optimization) then a separate partyAInfo MUST be used for each + * message. All implementations of this standard MUST implement + * Ephemeral-Static mode." + * </pre> + * <p> + * Reference: + * <ol> + * <li><a href="http://www.ietf.org/rfc/rfc2631.txt">Diffie-Hellman Key + * Agreement Method</a><br> + * Eric Rescorla.</li> + * <li><a href="http://www.cacr.math.uwaterloo.ca/hac">[HAC]</a>: Handbook of + * Applied Cryptography.<br> + * CRC Press, Inc. ISBN 0-8493-8523-7, 1997<br> + * Menezes, A., van Oorschot, P. and S. Vanstone.</li> + * </ol> + */ +public abstract class ElGamalKeyAgreement + extends BaseKeyAgreementParty +{ + public static final String SOURCE_OF_RANDOMNESS = "gnu.crypto.elgamal.ka.prng"; + public static final String KA_ELGAMAL_RECIPIENT_PRIVATE_KEY = + "gnu.crypto.elgamal.ka.recipient.private.key"; + public static final String KA_ELGAMAL_RECIPIENT_PUBLIC_KEY = + "gnu.crypto.elgamal.ka.recipient.public.key"; + /** The shared secret key. */ + protected BigInteger ZZ; + + protected ElGamalKeyAgreement() + { + super(Registry.ELGAMAL_KA); + } + + protected byte[] engineSharedSecret() throws KeyAgreementException + { + return Util.trim(ZZ); + } + + protected void engineReset() + { + ZZ = null; + } +} diff --git a/libjava/classpath/gnu/javax/crypto/key/dh/ElGamalReceiver.java b/libjava/classpath/gnu/javax/crypto/key/dh/ElGamalReceiver.java new file mode 100644 index 000000000..ad606f6c9 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/key/dh/ElGamalReceiver.java @@ -0,0 +1,99 @@ +/* ElGamalReceiver.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.key.dh; + +import gnu.javax.crypto.key.KeyAgreementException; +import gnu.javax.crypto.key.IncomingMessage; +import gnu.javax.crypto.key.OutgoingMessage; + +import java.math.BigInteger; +import java.security.SecureRandom; +import java.util.Map; + +import javax.crypto.interfaces.DHPrivateKey; + +/** + * This implementation is the receiver's part of the ElGamal key agreement + * exchange (B in [HAC]). + * + * @see ElGamalKeyAgreement + */ +public class ElGamalReceiver + extends ElGamalKeyAgreement +{ + /** The recipient's private key. */ + private DHPrivateKey B; + + // default 0-arguments constructor + + protected void engineInit(Map attributes) throws KeyAgreementException + { + rnd = (SecureRandom) attributes.get(SOURCE_OF_RANDOMNESS); + // One-time setup (key generation and publication). Each user B generates + // a keypair and publishes its public key + B = (DHPrivateKey) attributes.get(KA_ELGAMAL_RECIPIENT_PRIVATE_KEY); + if (B == null) + throw new KeyAgreementException("missing recipient private key"); + } + + protected OutgoingMessage engineProcessMessage(IncomingMessage in) + throws KeyAgreementException + { + switch (step) + { + case 0: + return computeSharedSecret(in); + default: + throw new IllegalStateException("unexpected state"); + } + } + + private OutgoingMessage computeSharedSecret(IncomingMessage in) + throws KeyAgreementException + { + // (b) B computes the same key on receipt of message (1) as + // K = (g^x)^xb mod p + BigInteger m1 = in.readMPI(); + if (m1 == null) + throw new KeyAgreementException("missing message (1)"); + ZZ = m1.modPow(B.getX(), B.getParams().getP()); // ZZ = (ya ^ xb) mod p + complete = true; + return null; + } +} diff --git a/libjava/classpath/gnu/javax/crypto/key/dh/ElGamalSender.java b/libjava/classpath/gnu/javax/crypto/key/dh/ElGamalSender.java new file mode 100644 index 000000000..bc9643500 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/key/dh/ElGamalSender.java @@ -0,0 +1,112 @@ +/* ElGamalSender.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.key.dh; + +import gnu.javax.crypto.key.KeyAgreementException; +import gnu.javax.crypto.key.IncomingMessage; +import gnu.javax.crypto.key.OutgoingMessage; + +import java.math.BigInteger; +import java.security.SecureRandom; +import java.util.Map; + +import javax.crypto.interfaces.DHPublicKey; + +/** + * This implementation is the sender's part of the ElGamal key agreement + * exchange (A in [HAC]). + * + * @see ElGamalKeyAgreement + */ +public class ElGamalSender + extends ElGamalKeyAgreement +{ + /** The recipient's public key. */ + private DHPublicKey B; + + // default 0-arguments constructor + + protected void engineInit(Map attributes) throws KeyAgreementException + { + rnd = (SecureRandom) attributes.get(SOURCE_OF_RANDOMNESS); + // One-time setup (key generation and publication). Each user B generates + // a keypair and publishes its public key + B = (DHPublicKey) attributes.get(KA_ELGAMAL_RECIPIENT_PUBLIC_KEY); + if (B == null) + throw new KeyAgreementException("missing recipient public key"); + } + + protected OutgoingMessage engineProcessMessage(IncomingMessage in) + throws KeyAgreementException + { + switch (step) + { + case 0: + return computeSharedSecret(in); + default: + throw new IllegalStateException("unexpected state"); + } + } + + private OutgoingMessage computeSharedSecret(IncomingMessage in) + throws KeyAgreementException + { + BigInteger p = B.getParams().getP(); + BigInteger g = B.getParams().getG(); + BigInteger yb = B.getY(); + // A chooses a random integer x, 1 <= x <= p-2 + // rfc-2631 restricts x to only be in [2, p-1] + BigInteger p_minus_2 = p.subtract(TWO); + byte[] xBytes = new byte[(p_minus_2.bitLength() + 7) / 8]; + BigInteger x; + do + { + nextRandomBytes(xBytes); + x = new BigInteger(1, xBytes); + } + while (x.compareTo(TWO) >= 0 && x.compareTo(p_minus_2) <= 0); + // A sends B the message: g^x mod p + OutgoingMessage result = new OutgoingMessage(); + result.writeMPI(g.modPow(x, p)); + // A computes the key as K = (yb)^x mod p + ZZ = yb.modPow(x, p); // ZZ = (yb ^ xa) mod p + complete = true; + return result; + } +} diff --git a/libjava/classpath/gnu/javax/crypto/key/dh/GnuDHKey.java b/libjava/classpath/gnu/javax/crypto/key/dh/GnuDHKey.java new file mode 100644 index 000000000..03a18c310 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/key/dh/GnuDHKey.java @@ -0,0 +1,174 @@ +/* GnuDHKey.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.key.dh; + +import gnu.java.security.Registry; +import gnu.java.security.action.GetPropertyAction; +import gnu.java.security.util.FormatUtil; + +import java.math.BigInteger; +import java.security.AccessController; +import java.security.Key; + +import javax.crypto.interfaces.DHKey; +import javax.crypto.spec.DHParameterSpec; + +/** + * A base asbtract class for both public and private Diffie-Hellman keys. It + * encapsulates the two DH numbers: <code>p</code>, and <code>g</code>. + * <p> + * According to the JDK, cryptographic <i>Keys</i> all have a <i>format</i>. + * The format used in this implementation is called <i>Raw</i>, and basically + * consists of the raw byte sequences of algorithm parameters. The exact order + * of the byte sequences and the implementation details are given in each of the + * relevant <code>getEncoded()</code> methods of each of the private and + * public keys. + * <p> + * Reference: + * <ol> + * <li><a href="http://www.ietf.org/rfc/rfc2631.txt">Diffie-Hellman Key + * Agreement Method</a><br> + * Eric Rescorla.</li> + * </ol> + */ +public abstract class GnuDHKey + implements Key, DHKey +{ + /** The public prime q. A prime divisor of p-1. */ + protected BigInteger q; + /** The public prime p. */ + protected BigInteger p; + /** The generator g. */ + protected BigInteger g; + /** + * Identifier of the default encoding format to use when externalizing the key + * material. + */ + protected final int defaultFormat; + /** String representation of this key. Cached for speed. */ + private transient String str; + + /** + * Trivial protected constructor. + * + * @param defaultFormat the identifier of the encoding format to use by + * default when externalizing the key. + * @param q a prime divisor of p-1. + * @param p the public prime. + * @param g the generator of the group. + */ + protected GnuDHKey(int defaultFormat, BigInteger q, BigInteger p, BigInteger g) + { + super(); + + this.defaultFormat = defaultFormat <= 0 ? Registry.RAW_ENCODING_ID + : defaultFormat; + this.q = q; + this.p = p; + this.g = g; + } + + public DHParameterSpec getParams() + { + if (q == null) + return new DHParameterSpec(p, g); + return new DHParameterSpec(p, g, q.bitLength()); + } + + public String getAlgorithm() + { + return Registry.DH_KPG; + } + + /** @deprecated see getEncoded(int). */ + public byte[] getEncoded() + { + return getEncoded(defaultFormat); + } + + public String getFormat() + { + return FormatUtil.getEncodingShortName(defaultFormat); + } + + public BigInteger getQ() + { + return q; + } + + /** + * Returns <code>true</code> if the designated object is an instance of + * {@link DHKey} and has the same Diffie-Hellman parameter values as this one. + * + * @param obj the other non-null DH key to compare to. + * @return <code>true</code> if the designated object is of the same type + * and value as this one. + */ + public boolean equals(Object obj) + { + if (obj == null) + return false; + if (! (obj instanceof DHKey)) + return false; + DHKey that = (DHKey) obj; + return p.equals(that.getParams().getP()) + && g.equals(that.getParams().getG()); + } + + public String toString() + { + if (str == null) + { + String ls = (String) AccessController.doPrivileged + (new GetPropertyAction("line.separator")); + StringBuilder sb = new StringBuilder(ls) + .append("defaultFormat=").append(defaultFormat).append(",").append(ls); + if (q == null) + sb.append("q=null,"); + else + sb.append("q=0x").append(q.toString(16)).append(","); + sb.append(ls).append("p=0x").append(p.toString(16)).append(",").append(ls) + .append("g=0x").append(g.toString(16)); + str = sb.toString(); + } + return str; + } + + public abstract byte[] getEncoded(int format); +} diff --git a/libjava/classpath/gnu/javax/crypto/key/dh/GnuDHKeyPairGenerator.java b/libjava/classpath/gnu/javax/crypto/key/dh/GnuDHKeyPairGenerator.java new file mode 100644 index 000000000..89e9c4c80 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/key/dh/GnuDHKeyPairGenerator.java @@ -0,0 +1,235 @@ +/* GnuDHKeyPairGenerator.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.key.dh; + +import gnu.java.security.Configuration; +import gnu.java.security.Registry; +import gnu.java.security.hash.Sha160; +import gnu.java.security.key.IKeyPairGenerator; +import gnu.java.security.util.PRNG; + +import java.math.BigInteger; +import java.security.KeyPair; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.security.SecureRandom; +import java.util.Map; +import java.util.logging.Logger; + +import javax.crypto.spec.DHGenParameterSpec; +import javax.crypto.spec.DHParameterSpec; + +/** + * An implementation of a Diffie-Hellman keypair generator. + * <p> + * Reference: + * <ol> + * <li><a href="http://www.ietf.org/rfc/rfc2631.txt">Diffie-Hellman Key + * Agreement Method</a><br> + * Eric Rescorla.</li> + * </ol> + */ +public class GnuDHKeyPairGenerator + implements IKeyPairGenerator +{ + private static final Logger log = Logger.getLogger(GnuDHKeyPairGenerator.class.getName()); + /** + * Property name of an optional {@link SecureRandom} instance to use. The + * default is to use a classloader singleton from {@link PRNG}. + */ + public static final String SOURCE_OF_RANDOMNESS = "gnu.crypto.dh.prng"; + /** + * Property name of an optional {@link DHGenParameterSpec} or + * {@link DHParameterSpec} instance to use for this generator. + */ + public static final String DH_PARAMETERS = "gnu.crypto.dh.params"; + /** Property name of the size in bits (Integer) of the public prime (p). */ + public static final String PRIME_SIZE = "gnu.crypto.dh.L"; + /** Property name of the size in bits (Integer) of the private exponent (x). */ + public static final String EXPONENT_SIZE = "gnu.crypto.dh.m"; + /** + * Property name of the preferred encoding format to use when externalizing + * generated instance of key-pairs from this generator. The property is taken + * to be an {@link Integer} that encapsulates an encoding format identifier. + */ + public static final String PREFERRED_ENCODING_FORMAT = "gnu.crypto.dh.encoding"; + /** Default value for the size in bits of the public prime (p). */ + public static final int DEFAULT_PRIME_SIZE = 512; + /** Default value for the size in bits of the private exponent (x). */ + public static final int DEFAULT_EXPONENT_SIZE = 160; + /** Default encoding format to use when none was specified. */ + private static final int DEFAULT_ENCODING_FORMAT = Registry.RAW_ENCODING_ID; + /** The SHA instance to use. */ + private Sha160 sha = new Sha160(); + /** The optional {@link SecureRandom} instance to use. */ + private SecureRandom rnd = null; + /** The desired size in bits of the public prime (p). */ + private int l; + /** The desired size in bits of the private exponent (x). */ + private int m; + private BigInteger seed; + private BigInteger counter; + private BigInteger q; + private BigInteger p; + private BigInteger j; + private BigInteger g; + /** Our default source of randomness. */ + private PRNG prng = null; + /** Preferred encoding format of generated keys. */ + private int preferredFormat; + + // default 0-arguments constructor + + public String name() + { + return Registry.DH_KPG; + } + + public void setup(Map attributes) + { + // do we have a SecureRandom, or should we use our own? + rnd = (SecureRandom) attributes.get(SOURCE_OF_RANDOMNESS); + // are we given a set of Diffie-Hellman generation parameters or we shall + // use our own? + Object params = attributes.get(DH_PARAMETERS); + // find out the desired sizes + if (params instanceof DHGenParameterSpec) + { + DHGenParameterSpec jceSpec = (DHGenParameterSpec) params; + l = jceSpec.getPrimeSize(); + m = jceSpec.getExponentSize(); + } + else if (params instanceof DHParameterSpec) + { + // FIXME: I'm not sure this is correct. It seems to behave the + // same way as Sun's RI, but I don't know if this behavior is + // documented anywhere. + DHParameterSpec jceSpec = (DHParameterSpec) params; + p = jceSpec.getP(); + g = jceSpec.getG(); + l = p.bitLength(); + m = jceSpec.getL(); + // If no exponent size was given, generate an exponent as + // large as the prime. + if (m == 0) + m = l; + } + else + { + Integer bi = (Integer) attributes.get(PRIME_SIZE); + l = (bi == null ? DEFAULT_PRIME_SIZE : bi.intValue()); + bi = (Integer) attributes.get(EXPONENT_SIZE); + m = (bi == null ? DEFAULT_EXPONENT_SIZE : bi.intValue()); + } + if ((l % 256) != 0 || l < DEFAULT_PRIME_SIZE) + throw new IllegalArgumentException("invalid modulus size"); + if ((m % 8) != 0 || m < DEFAULT_EXPONENT_SIZE) + throw new IllegalArgumentException("invalid exponent size"); + if (m > l) + throw new IllegalArgumentException("exponent size > modulus size"); + // what is the preferred encoding format + Integer formatID = (Integer) attributes.get(PREFERRED_ENCODING_FORMAT); + preferredFormat = formatID == null ? DEFAULT_ENCODING_FORMAT + : formatID.intValue(); + } + + public KeyPair generate() + { + if (p == null) + { + BigInteger[] params = new RFC2631(m, l, rnd).generateParameters(); + seed = params[RFC2631.DH_PARAMS_SEED]; + counter = params[RFC2631.DH_PARAMS_COUNTER]; + q = params[RFC2631.DH_PARAMS_Q]; + p = params[RFC2631.DH_PARAMS_P]; + j = params[RFC2631.DH_PARAMS_J]; + g = params[RFC2631.DH_PARAMS_G]; + if (Configuration.DEBUG) + { + log.fine("seed: 0x" + seed.toString(16)); + log.fine("counter: " + counter.intValue()); + log.fine("q: 0x" + q.toString(16)); + log.fine("p: 0x" + p.toString(16)); + log.fine("j: 0x" + j.toString(16)); + log.fine("g: 0x" + g.toString(16)); + } + } + // generate a private number x of length m such as: 1 < x < q - 1 + BigInteger q_minus_1 = null; + if (q != null) + q_minus_1 = q.subtract(BigInteger.ONE); + // We already check if m is modulo 8 in `setup.' This could just + // be m >>> 3. + byte[] mag = new byte[(m + 7) / 8]; + BigInteger x; + while (true) + { + nextRandomBytes(mag); + x = new BigInteger(1, mag); + if (x.bitLength() == m && x.compareTo(BigInteger.ONE) > 0 + && (q_minus_1 == null || x.compareTo(q_minus_1) < 0)) + break; + } + BigInteger y = g.modPow(x, p); + PrivateKey secK = new GnuDHPrivateKey(preferredFormat, q, p, g, x); + PublicKey pubK = new GnuDHPublicKey(preferredFormat, q, p, g, y); + return new KeyPair(pubK, secK); + } + + /** + * Fills the designated byte array with random data. + * + * @param buffer the byte array to fill with random data. + */ + private void nextRandomBytes(byte[] buffer) + { + if (rnd != null) + rnd.nextBytes(buffer); + else + getDefaultPRNG().nextBytes(buffer); + } + + private PRNG getDefaultPRNG() + { + if (prng == null) + prng = PRNG.getInstance(); + + return prng; + } +} diff --git a/libjava/classpath/gnu/javax/crypto/key/dh/GnuDHPrivateKey.java b/libjava/classpath/gnu/javax/crypto/key/dh/GnuDHPrivateKey.java new file mode 100644 index 000000000..881421a74 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/key/dh/GnuDHPrivateKey.java @@ -0,0 +1,200 @@ +/* GnuDHPrivateKey.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.key.dh; + +import gnu.java.security.Configuration; +import gnu.java.security.Registry; +import gnu.java.security.action.GetPropertyAction; +import gnu.java.security.key.IKeyPairCodec; + +import java.math.BigInteger; +import java.security.AccessController; + +import javax.crypto.interfaces.DHPrivateKey; + +/** + * An implementation of the Diffie-Hellman private key. + * <p> + * Reference: + * <ol> + * <li><a href="http://www.ietf.org/rfc/rfc2631.txt">Diffie-Hellman Key + * Agreement Method</a><br> + * Eric Rescorla.</li> + * </ol> + */ +public class GnuDHPrivateKey + extends GnuDHKey + implements DHPrivateKey +{ + /** The private exponent. */ + private final BigInteger x; + /** String representation of this key. Cached for speed. */ + private transient String str; + + /** + * Convenience constructor. Calls the constructor with five arguments passing + * {@link Registry#RAW_ENCODING_ID} as the value of its first argument. + * + * @param q a prime divisor of p-1. + * @param p the public prime. + * @param g the generator of the group. + * @param x the private value x. + */ + public GnuDHPrivateKey(BigInteger q, BigInteger p, BigInteger g, BigInteger x) + { + this(Registry.RAW_ENCODING_ID, q, p, g, x); + } + + /** + * Constructs a new instance of <code>GnuDHPrivateKey</code> given the + * designated parameters. + * + * @param preferredFormat the identifier of the encoding format to use by + * default when externalizing the key. + * @param q a prime divisor of p-1. + * @param p the public prime. + * @param g the generator of the group. + * @param x the private value x. + */ + public GnuDHPrivateKey(int preferredFormat, BigInteger q, BigInteger p, + BigInteger g, BigInteger x) + { + super(preferredFormat == Registry.ASN1_ENCODING_ID ? Registry.PKCS8_ENCODING_ID + : preferredFormat, + q, p, g); + this.x = x; + } + + /** + * A class method that takes the output of the <code>encodePrivateKey()</code> + * method of a DH keypair codec object (an instance implementing + * {@link IKeyPairCodec} for DH keys, and re-constructs an instance of this + * object. + * + * @param k the contents of a previously encoded instance of this object. + * @exception ArrayIndexOutOfBoundsException if there is not enough bytes, in + * <code>k</code>, to represent a valid encoding of an + * instance of this object. + * @exception IllegalArgumentException if the byte sequence does not represent + * a valid encoding of an instance of this object. + */ + public static GnuDHPrivateKey valueOf(byte[] k) + { + // try RAW codec + if (k[0] == Registry.MAGIC_RAW_DH_PRIVATE_KEY[0]) + try + { + return (GnuDHPrivateKey) new DHKeyPairRawCodec().decodePrivateKey(k); + } + catch (IllegalArgumentException ignored) + { + } + // try PKCS#8 codec + return (GnuDHPrivateKey) new DHKeyPairPKCS8Codec().decodePrivateKey(k); + } + + public BigInteger getX() + { + return x; + } + + /** + * Returns the encoded form of this private key according to the designated + * format. + * + * @param format the desired format identifier of the resulting encoding. + * @return the byte sequence encoding this key according to the designated + * format. + * @exception IllegalArgumentException if the format is not supported. + * @see DHKeyPairRawCodec + */ + public byte[] getEncoded(int format) + { + byte[] result; + switch (format) + { + case IKeyPairCodec.RAW_FORMAT: + result = new DHKeyPairRawCodec().encodePrivateKey(this); + break; + case IKeyPairCodec.PKCS8_FORMAT: + result = new DHKeyPairPKCS8Codec().encodePrivateKey(this); + break; + default: + throw new IllegalArgumentException("Unsupported encoding format: " + + format); + } + return result; + } + + /** + * Returns <code>true</code> if the designated object is an instance of + * {@link DHPrivateKey} and has the same parameter values as this one. + * + * @param obj the other non-null DH key to compare to. + * @return <code>true</code> if the designated object is of the same type + * and value as this one. + */ + public boolean equals(Object obj) + { + if (obj == null) + return false; + + if (! (obj instanceof DHPrivateKey)) + return false; + + DHPrivateKey that = (DHPrivateKey) obj; + return super.equals(that) && x.equals(that.getX()); + } + + public String toString() + { + if (str == null) + { + String ls = (String) AccessController.doPrivileged + (new GetPropertyAction("line.separator")); + str = new StringBuilder(this.getClass().getName()).append("(") + .append(super.toString()).append(",").append(ls) + .append("x=0x").append(Configuration.DEBUG ? x.toString(16) + : "**...*").append(ls) + .append(")") + .toString(); + } + return str; + } +} diff --git a/libjava/classpath/gnu/javax/crypto/key/dh/GnuDHPublicKey.java b/libjava/classpath/gnu/javax/crypto/key/dh/GnuDHPublicKey.java new file mode 100644 index 000000000..5f1771bb0 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/key/dh/GnuDHPublicKey.java @@ -0,0 +1,196 @@ +/* GnuDHPublicKey.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.key.dh; + +import gnu.java.security.Registry; +import gnu.java.security.action.GetPropertyAction; +import gnu.java.security.key.IKeyPairCodec; + +import java.math.BigInteger; +import java.security.AccessController; + +import javax.crypto.interfaces.DHPublicKey; + +/** + * An implementation of the Diffie-Hellman public key. + * <p> + * Reference: + * <ol> + * <li><a href="http://www.ietf.org/rfc/rfc2631.txt">Diffie-Hellman Key + * Agreement Method</a><br> + * Eric Rescorla.</li> + * </ol> + */ +public class GnuDHPublicKey + extends GnuDHKey + implements DHPublicKey +{ + private BigInteger y; + /** String representation of this key. Cached for speed. */ + private transient String str; + + /** + * Convenience constructor. Calls the constructor with five arguments passing + * {@link Registry#RAW_ENCODING_ID} as the value of its first argument. + * + * @param q a prime divisor of p-1. + * @param p the public prime. + * @param g the generator of the group. + * @param y the public value y. + */ + public GnuDHPublicKey(BigInteger q, BigInteger p, BigInteger g, BigInteger y) + { + this(Registry.RAW_ENCODING_ID, q, p, g, y); + } + + /** + * Constructs a new instance of <code>GnuDHPublicKey</code> given the + * designated parameters. + * + * @param preferredFormat the identifier of the encoding format to use by + * default when externalizing the key. + * @param q a prime divisor of p-1. + * @param p the public prime. + * @param g the generator of the group. + * @param y the public value y. + */ + public GnuDHPublicKey(int preferredFormat, BigInteger q, BigInteger p, + BigInteger g, BigInteger y) + { + super(preferredFormat == Registry.ASN1_ENCODING_ID ? Registry.X509_ENCODING_ID + : preferredFormat, + q, p, g); + this.y = y; + } + + /** + * A class method that takes the output of the <code>encodePublicKey()</code> + * method of a DH keypair codec object (an instance implementing + * {@link IKeyPairCodec} for DSS keys, and re-constructs an instance of this + * object. + * + * @param k the contents of a previously encoded instance of this object. + * @exception ArrayIndexOutOfBoundsException if there is not enough bytes, in + * <code>k</code>, to represent a valid encoding of an + * instance of this object. + * @exception IllegalArgumentException if the byte sequence does not represent + * a valid encoding of an instance of this object. + */ + public static GnuDHPublicKey valueOf(byte[] k) + { + // try RAW codec + if (k[0] == Registry.MAGIC_RAW_DH_PUBLIC_KEY[0]) + try + { + return (GnuDHPublicKey) new DHKeyPairRawCodec().decodePublicKey(k); + } + catch (IllegalArgumentException ignored) + { + } + // try X.509 codec + return (GnuDHPublicKey) new DHKeyPairX509Codec().decodePublicKey(k); + } + + public BigInteger getY() + { + return y; + } + + /** + * Returns the encoded form of this public key according to the designated + * format. + * + * @param format the desired format identifier of the resulting encoding. + * @return the byte sequence encoding this key according to the designated + * format. + * @exception IllegalArgumentException if the format is not supported. + */ + public byte[] getEncoded(int format) + { + byte[] result; + switch (format) + { + case IKeyPairCodec.RAW_FORMAT: + result = new DHKeyPairRawCodec().encodePublicKey(this); + break; + case IKeyPairCodec.X509_FORMAT: + result = new DHKeyPairX509Codec().encodePublicKey(this); + break; + default: + throw new IllegalArgumentException("Unsupported encoding format: " + + format); + } + return result; + } + + /** + * Returns <code>true</code> if the designated object is an instance of + * {@link DHPublicKey} and has the same parameter values as this one. + * + * @param obj the other non-null DH key to compare to. + * @return <code>true</code> if the designated object is of the same type + * and value as this one. + */ + public boolean equals(Object obj) + { + if (obj == null) + return false; + + if (! (obj instanceof DHPublicKey)) + return false; + + DHPublicKey that = (DHPublicKey) obj; + return super.equals(that) && y.equals(that.getY()); + } + + public String toString() + { + if (str == null) + { + String ls = (String) AccessController.doPrivileged + (new GetPropertyAction("line.separator")); + str = new StringBuilder(this.getClass().getName()).append("(") + .append(super.toString()).append(",").append(ls) + .append("y=0x").append(y.toString(16)).append(ls) + .append(")") + .toString(); + } + return str; + } +} diff --git a/libjava/classpath/gnu/javax/crypto/key/dh/RFC2631.java b/libjava/classpath/gnu/javax/crypto/key/dh/RFC2631.java new file mode 100644 index 000000000..60ef49409 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/key/dh/RFC2631.java @@ -0,0 +1,217 @@ +/* RFC2631.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.key.dh; + +import gnu.java.security.hash.Sha160; +import gnu.java.security.util.PRNG; + +import java.math.BigInteger; +import java.security.SecureRandom; + +/** + * An implementation of the Diffie-Hellman parameter generation as defined in + * RFC-2631. + * <p> + * Reference: + * <ol> + * <li><a href="http://www.ietf.org/rfc/rfc2631.txt">Diffie-Hellman Key + * Agreement Method</a><br> + * Eric Rescorla.</li> + * </ol> + */ +public class RFC2631 +{ + public static final int DH_PARAMS_SEED = 0; + public static final int DH_PARAMS_COUNTER = 1; + public static final int DH_PARAMS_Q = 2; + public static final int DH_PARAMS_P = 3; + public static final int DH_PARAMS_J = 4; + public static final int DH_PARAMS_G = 5; + private static final BigInteger TWO = BigInteger.valueOf(2L); + /** The SHA instance to use. */ + private Sha160 sha = new Sha160(); + /** Length of private modulus and of q. */ + private int m; + /** Length of public modulus p. */ + private int L; + /** The optional {@link SecureRandom} instance to use. */ + private SecureRandom rnd = null; + /** Our default source of randomness. */ + private PRNG prng = null; + + public RFC2631(int m, int L, SecureRandom rnd) + { + super(); + + this.m = m; + this.L = L; + this.rnd = rnd; + } + + public BigInteger[] generateParameters() + { + int i, j, counter; + byte[] u1, u2, v; + byte[] seedBytes = new byte[m / 8]; + BigInteger SEED, U, q, R, V, W, X, p, g; + // start by genrating p and q, where q is of length m and p is of length L + // 1. Set m' = m/160 where / represents integer division with rounding + // upwards. I.e. 200/160 = 2. + int m_ = (m + 159) / 160; + // 2. Set L'= L/160 + int L_ = (L + 159) / 160; + // 3. Set N'= L/1024 + int N_ = (L + 1023) / 1024; + algorithm: while (true) + { + step4: while (true) + { + // 4. Select an arbitrary bit string SEED such that length of + // SEED >= m + nextRandomBytes(seedBytes); + SEED = new BigInteger(1, seedBytes).setBit(m - 1).setBit(0); + // 5. Set U = 0 + U = BigInteger.ZERO; + // 6. For i = 0 to m' - 1 + // U = U + (SHA1[SEED + i] XOR SHA1[(SEED + m' + i)) * 2^(160 * i) + // Note that for m=160, this reduces to the algorithm of FIPS-186 + // U = SHA1[SEED] XOR SHA1[(SEED+1) mod 2^160 ]. + for (i = 0; i < m_; i++) + { + u1 = SEED.add(BigInteger.valueOf(i)).toByteArray(); + u2 = SEED.add(BigInteger.valueOf(m_ + i)).toByteArray(); + sha.update(u1, 0, u1.length); + u1 = sha.digest(); + sha.update(u2, 0, u2.length); + u2 = sha.digest(); + for (j = 0; j < u1.length; j++) + u1[j] ^= u2[j]; + U = U.add(new BigInteger(1, u1).multiply(TWO.pow(160 * i))); + } + // 5. Form q from U by computing U mod (2^m) and setting the most + // significant bit (the 2^(m-1) bit) and the least significant + // bit to 1. In terms of boolean operations, q = U OR 2^(m-1) OR + // 1. Note that 2^(m-1) < q < 2^m + q = U.setBit(m - 1).setBit(0); + // 6. Use a robust primality algorithm to test whether q is prime. + // 7. If q is not prime then go to 4. + if (q.isProbablePrime(80)) + break step4; + } + // 8. Let counter = 0 + counter = 0; + while (true) + { + // 9. Set R = seed + 2*m' + (L' * counter) + R = SEED + .add(BigInteger.valueOf(2 * m_)) + .add(BigInteger.valueOf(L_ * counter)); + // 10. Set V = 0 + V = BigInteger.ZERO; + // 12. For i = 0 to L'-1 do: V = V + SHA1(R + i) * 2^(160 * i) + for (i = 0; i < L_; i++) + { + v = R.toByteArray(); + sha.update(v, 0, v.length); + v = sha.digest(); + V = V.add(new BigInteger(1, v).multiply(TWO.pow(160 * i))); + } + // 13. Set W = V mod 2^L + W = V.mod(TWO.pow(L)); + // 14. Set X = W OR 2^(L-1) + // Note that 0 <= W < 2^(L-1) and hence X >= 2^(L-1) + X = W.setBit(L - 1); + // 15. Set p = X - (X mod (2*q)) + 1 + p = X.add(BigInteger.ONE).subtract(X.mod(TWO.multiply(q))); + // 16. If p > 2^(L-1) use a robust primality test to test whether p + // is prime. Else go to 18. + // 17. If p is prime output p, q, seed, counter and stop. + if (p.isProbablePrime(80)) + { + break algorithm; + } + // 18. Set counter = counter + 1 + counter++; + // 19. If counter < (4096 * N) then go to 8. + // 20. Output "failure" + if (counter >= 4096 * N_) + continue algorithm; + } + } + // compute g. from FIPS-186, Appendix 4: + // 1. Generate p and q as specified in Appendix 2. + // 2. Let e = (p - 1) / q + BigInteger e = p.subtract(BigInteger.ONE).divide(q); + BigInteger h = TWO; + BigInteger p_minus_1 = p.subtract(BigInteger.ONE); + g = TWO; + // 3. Set h = any integer, where 1 < h < p - 1 and h differs from any + // value previously tried + for (; h.compareTo(p_minus_1) < 0; h = h.add(BigInteger.ONE)) + { + // 4. Set g = h**e mod p + g = h.modPow(e, p); + // 5. If g = 1, go to step 3 + if (! g.equals(BigInteger.ONE)) + break; + } + return new BigInteger[] { SEED, BigInteger.valueOf(counter), q, p, e, g }; + } + + /** + * Fills the designated byte array with random data. + * + * @param buffer the byte array to fill with random data. + */ + private void nextRandomBytes(byte[] buffer) + { + if (rnd != null) + rnd.nextBytes(buffer); + else + getDefaultPRNG().nextBytes(buffer); + } + + private PRNG getDefaultPRNG() + { + if (prng == null) + prng = PRNG.getInstance(); + + return prng; + } +} diff --git a/libjava/classpath/gnu/javax/crypto/key/srp6/SRP6Host.java b/libjava/classpath/gnu/javax/crypto/key/srp6/SRP6Host.java new file mode 100644 index 000000000..2c8e66fa2 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/key/srp6/SRP6Host.java @@ -0,0 +1,161 @@ +/* SRP6Host.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.key.srp6; + +import gnu.java.security.Registry; +import gnu.java.security.hash.IMessageDigest; +import gnu.java.security.util.Util; +import gnu.javax.crypto.key.KeyAgreementException; +import gnu.javax.crypto.key.IncomingMessage; +import gnu.javax.crypto.key.OutgoingMessage; +import gnu.javax.crypto.sasl.srp.SRP; +import gnu.javax.crypto.sasl.srp.SRPAuthInfoProvider; +import gnu.javax.crypto.sasl.srp.SRPRegistry; + +import java.io.IOException; +import java.math.BigInteger; +import java.security.KeyPair; +import java.security.SecureRandom; +import java.util.HashMap; +import java.util.Map; + +/** + * The implementation of the Host in the SRP-6 key agreement protocol. + * <p> + * Reference: + * <ol> + * <li><a href="http://srp.stanford.edu/design.html">SRP Protocol Design</a><br> + * Thomas J. Wu.</li> + * </ol> + */ +public class SRP6Host + extends SRP6KeyAgreement +{ + /** The user's ephemeral key pair. */ + private KeyPair hostKeyPair; + + /** The SRP password database. */ + private SRPAuthInfoProvider passwordDB; + + // default 0-arguments constructor + + protected void engineInit(final Map attributes) throws KeyAgreementException + { + rnd = (SecureRandom) attributes.get(SOURCE_OF_RANDOMNESS); + N = (BigInteger) attributes.get(SHARED_MODULUS); + if (N == null) + throw new KeyAgreementException("missing shared modulus"); + g = (BigInteger) attributes.get(GENERATOR); + if (g == null) + throw new KeyAgreementException("missing generator"); + final String md = (String) attributes.get(HASH_FUNCTION); + if (md == null || md.trim().length() == 0) + throw new KeyAgreementException("missing hash function"); + srp = SRP.instance(md); + passwordDB = (SRPAuthInfoProvider) attributes.get(HOST_PASSWORD_DB); + if (passwordDB == null) + throw new KeyAgreementException("missing SRP password database"); + } + + protected OutgoingMessage engineProcessMessage(final IncomingMessage in) + throws KeyAgreementException + { + switch (step) + { + case 0: + return computeSharedSecret(in); + default: + throw new IllegalStateException("unexpected state"); + } + } + + protected void engineReset() + { + hostKeyPair = null; + super.engineReset(); + } + + private OutgoingMessage computeSharedSecret(final IncomingMessage in) + throws KeyAgreementException + { + final String I = in.readString(); + final BigInteger A = in.readMPI(); + // get s and v for user identified by I + // ---------------------------------------------------------------------- + final Map credentials; + try + { + final Map userID = new HashMap(); + userID.put(Registry.SASL_USERNAME, I); + userID.put(SRPRegistry.MD_NAME_FIELD, srp.getAlgorithm()); + credentials = passwordDB.lookup(userID); + } + catch (IOException x) + { + throw new KeyAgreementException("computeSharedSecret()", x); + } + final BigInteger s = new BigInteger( + 1,Util.fromBase64((String) credentials.get(SRPRegistry.SALT_FIELD))); + final BigInteger v = new BigInteger( + 1, Util.fromBase64((String) credentials.get(SRPRegistry.USER_VERIFIER_FIELD))); + final SRPKeyPairGenerator kpg = new SRPKeyPairGenerator(); + final Map attributes = new HashMap(); + if (rnd != null) + attributes.put(SRPKeyPairGenerator.SOURCE_OF_RANDOMNESS, rnd); + attributes.put(SRPKeyPairGenerator.SHARED_MODULUS, N); + attributes.put(SRPKeyPairGenerator.GENERATOR, g); + attributes.put(SRPKeyPairGenerator.USER_VERIFIER, v); + kpg.setup(attributes); + hostKeyPair = kpg.generate(); + final BigInteger B = ((SRPPublicKey) hostKeyPair.getPublic()).getY(); + final BigInteger u = uValue(A, B); // u = H(A | B) + // compute S = (Av^u) ^ b + final BigInteger b = ((SRPPrivateKey) hostKeyPair.getPrivate()).getX(); + final BigInteger S = A.multiply(v.modPow(u, N)).modPow(b, N); + final byte[] sBytes = Util.trim(S); + final IMessageDigest hash = srp.newDigest(); + hash.update(sBytes, 0, sBytes.length); + K = new BigInteger(1, hash.digest()); + final OutgoingMessage result = new OutgoingMessage(); + result.writeMPI(s); + result.writeMPI(B); + complete = true; + return result; + } +} diff --git a/libjava/classpath/gnu/javax/crypto/key/srp6/SRP6KeyAgreement.java b/libjava/classpath/gnu/javax/crypto/key/srp6/SRP6KeyAgreement.java new file mode 100644 index 000000000..d3d27b381 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/key/srp6/SRP6KeyAgreement.java @@ -0,0 +1,141 @@ +/* SRP6KeyAgreement.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.key.srp6; + +import gnu.java.security.Registry; +import gnu.java.security.hash.IMessageDigest; +import gnu.java.security.util.Util; + +import gnu.javax.crypto.key.BaseKeyAgreementParty; +import gnu.javax.crypto.key.KeyAgreementException; +import gnu.javax.crypto.sasl.srp.SRP; + +import java.math.BigInteger; + +/** + * The Secure Remote Password (SRP) key agreement protocol, also known as SRP-6, + * is designed by Thomas J. Wu (see references). The protocol, and its elements + * are described as follows: + * <pre> + * N A large safe prime (N = 2q+1, where q is prime) + * All arithmetic is done modulo N. + * g A generator modulo N + * s User's salt + * I Username + * p Cleartext Password + * H() One-way hash function + * ˆ (Modular) Exponentiation + * u Random scrambling parameter + * a,b Secret ephemeral values + * A,B Public ephemeral values + * x Private key (derived from p and s) + * v Password verifier + * + * The host stores passwords using the following formula: + * x = H(s | H(I ":" p)) (s is chosen randomly) + * v = gˆx (computes password verifier) + * + * The host then keeps {I, s, v} in its password database. + * + * The authentication protocol itself goes as follows: + * User -> Host: I, A = gˆa (identifies self, a = random number) + * Host -> User: s, B = 3v + gˆb (sends salt, b = random number) + * + * Both: u = H(A, B) + * + * User: x = H(s, p) (user enters password) + * User: S = (B - 3gˆx) ˆ (a + ux) (computes session key) + * User: K = H(S) + * + * Host: S = (Avˆu) ˆ b (computes session key) + * Host: K = H(S) + * </pre> + * <p> + * Reference: + * <ol> + * <li><a href="http://srp.stanford.edu/design.html">SRP Protocol Design</a><br> + * Thomas J. Wu.</li> + * </ol> + */ +public abstract class SRP6KeyAgreement + extends BaseKeyAgreementParty +{ + public static final String SOURCE_OF_RANDOMNESS = "gnu.crypto.srp6.ka.prng"; + public static final String SHARED_MODULUS = "gnu.crypto.srp6.ka.N"; + public static final String GENERATOR = "gnu.crypto.srp6.ka.g"; + public static final String HASH_FUNCTION = "gnu.crypto.srp6.ka.H"; + public static final String USER_IDENTITY = "gnu.crypto.srp6.ka.I"; + public static final String USER_PASSWORD = "gnu.crypto.srp6.ka.p"; + public static final String HOST_PASSWORD_DB = "gnu.crypto.srp6.ka.password.db"; + protected static final BigInteger THREE = BigInteger.valueOf(3L); + protected SRP srp; + protected BigInteger N; + protected BigInteger g; + /** The shared secret key. */ + protected BigInteger K; + + protected SRP6KeyAgreement() + { + super(Registry.SRP6_KA); + } + + protected byte[] engineSharedSecret() throws KeyAgreementException + { + return Util.trim(K); + } + + protected void engineReset() + { + srp = null; + N = null; + g = null; + K = null; + } + + protected BigInteger uValue(final BigInteger A, final BigInteger B) + { + final IMessageDigest hash = srp.newDigest(); + byte[] b; + b = Util.trim(A); + hash.update(b, 0, b.length); + b = Util.trim(B); + hash.update(b, 0, b.length); + return new BigInteger(1, hash.digest()); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/key/srp6/SRP6SaslClient.java b/libjava/classpath/gnu/javax/crypto/key/srp6/SRP6SaslClient.java new file mode 100644 index 000000000..ec5cd7f17 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/key/srp6/SRP6SaslClient.java @@ -0,0 +1,90 @@ +/* SRP6SaslClient.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.key.srp6; + +import gnu.java.security.hash.IMessageDigest; +import gnu.java.security.util.Util; + +import gnu.javax.crypto.key.KeyAgreementException; +import gnu.javax.crypto.key.IncomingMessage; +import gnu.javax.crypto.key.OutgoingMessage; + +import java.math.BigInteger; + +/** + * A variation of the SRP-6 protocol as used in the SASL-SRP mechanism, for the + * User (client side). + * <p> + * In this alternative, the exchange goes as follows: + * + * <pre> + * C -> S: I (identifies self) + * S -> C: N, g, s, B = 3v + gˆb (sends salt, b = random number) + * C -> S: A = gˆa (a = random number) + * </pre> + * + * <p> + * All elements are computed the same way as in the standard version. + * <p> + * Reference: + * <ol> + * <li><a + * href="http://www.ietf.org/internet-drafts/draft-burdis-cat-srp-sasl-09.txt"> + * Secure Remote Password Authentication Mechanism</a><br> + * K. Burdis, R. Naffah.</li> + * <li><a href="http://srp.stanford.edu/design.html">SRP Protocol Design</a><br> + * Thomas J. Wu.</li> + * </ol> + */ +public class SRP6SaslClient + extends SRP6TLSClient +{ + // default 0-arguments constructor + + protected OutgoingMessage computeSharedSecret(final IncomingMessage in) + throws KeyAgreementException + { + final OutgoingMessage result = super.computeSharedSecret(in); + final byte[] sBytes = Util.trim(K); + final IMessageDigest hash = srp.newDigest(); + hash.update(sBytes, 0, sBytes.length); + K = new BigInteger(1, hash.digest()); + return result; + } +} diff --git a/libjava/classpath/gnu/javax/crypto/key/srp6/SRP6SaslServer.java b/libjava/classpath/gnu/javax/crypto/key/srp6/SRP6SaslServer.java new file mode 100644 index 000000000..a4313f4d3 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/key/srp6/SRP6SaslServer.java @@ -0,0 +1,90 @@ +/* SRP6SaslServer.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.key.srp6; + +import gnu.java.security.hash.IMessageDigest; +import gnu.java.security.util.Util; + +import gnu.javax.crypto.key.KeyAgreementException; +import gnu.javax.crypto.key.IncomingMessage; +import gnu.javax.crypto.key.OutgoingMessage; + +import java.math.BigInteger; + +/** + * A variation of the SRP-6 protocol as used in the SASL-SRP mechanism, for the + * Host (server side). + * <p> + * In this alternative, the exchange goes as follows: + * + * <pre> + * C -> S: I (identifies self) + * S -> C: N, g, s, B = 3v + gˆb (sends salt, b = random number) + * C -> S: A = gˆa (a = random number) + * </pre> + * + * <p> + * All elements are computed the same way as in the standard version. + * <p> + * Reference: + * <ol> + * <li><a + * href="http://www.ietf.org/internet-drafts/draft-burdis-cat-srp-sasl-09.txt"> + * Secure Remote Password Authentication Mechanism</a><br> + * K. Burdis, R. Naffah.</li> + * <li><a href="http://srp.stanford.edu/design.html">SRP Protocol Design</a><br> + * Thomas J. Wu.</li> + * </ol> + */ +public class SRP6SaslServer + extends SRP6TLSServer +{ + // default 0-arguments constructor + + protected OutgoingMessage computeSharedSecret(final IncomingMessage in) + throws KeyAgreementException + { + super.computeSharedSecret(in); + final byte[] sBytes = Util.trim(K); + final IMessageDigest hash = srp.newDigest(); + hash.update(sBytes, 0, sBytes.length); + K = new BigInteger(1, hash.digest()); + return null; + } +} diff --git a/libjava/classpath/gnu/javax/crypto/key/srp6/SRP6TLSClient.java b/libjava/classpath/gnu/javax/crypto/key/srp6/SRP6TLSClient.java new file mode 100644 index 000000000..c2459f620 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/key/srp6/SRP6TLSClient.java @@ -0,0 +1,155 @@ +/* SRP6TLSClient.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.key.srp6; + +import gnu.java.security.util.Util; +import gnu.javax.crypto.key.KeyAgreementException; +import gnu.javax.crypto.key.IncomingMessage; +import gnu.javax.crypto.key.OutgoingMessage; +import gnu.javax.crypto.sasl.srp.SRP; + +import java.math.BigInteger; +import java.security.KeyPair; +import java.security.SecureRandom; +import java.util.HashMap; +import java.util.Map; + +/** + * A variation of the SRP6 key agreement protocol, for the client-side as + * proposed in <a + * href="http://www.ietf.org/internet-drafts/draft-ietf-tls-srp-05.txt">Using + * SRP for TLS Authentication</a>. The only difference between it and the SASL + * variant is that the shared secret is the entity <code>S</code> and not + * <code>H(S)</code>. + */ +public class SRP6TLSClient + extends SRP6KeyAgreement +{ + /** The user's identity. */ + private String I; + /** The user's cleartext password. */ + private byte[] p; + /** The user's ephemeral key pair. */ + private KeyPair userKeyPair; + + // default 0-arguments constructor + + protected void engineInit(final Map attributes) throws KeyAgreementException + { + rnd = (SecureRandom) attributes.get(SOURCE_OF_RANDOMNESS); + final String md = (String) attributes.get(HASH_FUNCTION); + if (md == null || md.trim().length() == 0) + throw new KeyAgreementException("missing hash function"); + srp = SRP.instance(md); + I = (String) attributes.get(USER_IDENTITY); + if (I == null) + throw new KeyAgreementException("missing user identity"); + p = (byte[]) attributes.get(USER_PASSWORD); + if (p == null) + throw new KeyAgreementException("missing user password"); + } + + protected OutgoingMessage engineProcessMessage(final IncomingMessage in) + throws KeyAgreementException + { + switch (step) + { + case 0: + return sendIdentity(in); + case 1: + return computeSharedSecret(in); + default: + throw new IllegalStateException("unexpected state"); + } + } + + protected void engineReset() + { + I = null; + p = null; + userKeyPair = null; + super.engineReset(); + } + + private OutgoingMessage sendIdentity(final IncomingMessage in) + throws KeyAgreementException + { + final OutgoingMessage result = new OutgoingMessage(); + result.writeString(I); + return result; + } + + protected OutgoingMessage computeSharedSecret(final IncomingMessage in) + throws KeyAgreementException + { + N = in.readMPI(); + g = in.readMPI(); + final BigInteger s = in.readMPI(); + final BigInteger B = in.readMPI(); + // generate an ephemeral keypair + final SRPKeyPairGenerator kpg = new SRPKeyPairGenerator(); + final Map attributes = new HashMap(); + if (rnd != null) + attributes.put(SRPKeyPairGenerator.SOURCE_OF_RANDOMNESS, rnd); + attributes.put(SRPKeyPairGenerator.SHARED_MODULUS, N); + attributes.put(SRPKeyPairGenerator.GENERATOR, g); + kpg.setup(attributes); + userKeyPair = kpg.generate(); + final BigInteger A = ((SRPPublicKey) userKeyPair.getPublic()).getY(); + final BigInteger u = uValue(A, B); // u = H(A | B) + final BigInteger x; + try + { + x = new BigInteger(1, srp.computeX(Util.trim(s), I, p)); + } + catch (Exception e) + { + throw new KeyAgreementException("computeSharedSecret()", e); + } + // compute S = (B - 3g^x) ^ (a + ux) + final BigInteger a = ((SRPPrivateKey) userKeyPair.getPrivate()).getX(); + final BigInteger S = B.subtract(THREE.multiply(g.modPow(x, N))) + .modPow(a.add(u.multiply(x)), N); + K = S; + final OutgoingMessage result = new OutgoingMessage(); + result.writeMPI(A); + complete = true; + return result; + } +} diff --git a/libjava/classpath/gnu/javax/crypto/key/srp6/SRP6TLSServer.java b/libjava/classpath/gnu/javax/crypto/key/srp6/SRP6TLSServer.java new file mode 100644 index 000000000..42e3d9cb1 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/key/srp6/SRP6TLSServer.java @@ -0,0 +1,177 @@ +/* SRP6TLSServer.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.key.srp6; + +import gnu.java.security.Registry; +import gnu.java.security.util.Util; +import gnu.javax.crypto.key.KeyAgreementException; +import gnu.javax.crypto.key.OutgoingMessage; +import gnu.javax.crypto.key.IncomingMessage; +import gnu.javax.crypto.sasl.srp.SRP; +import gnu.javax.crypto.sasl.srp.SRPAuthInfoProvider; +import gnu.javax.crypto.sasl.srp.SRPRegistry; + +import java.io.IOException; +import java.math.BigInteger; +import java.security.KeyPair; +import java.security.SecureRandom; +import java.util.HashMap; +import java.util.Map; + +/** + * A variation of the SRP6 key agreement protocol, for the server-side as + * proposed in <a + * href="http://www.ietf.org/internet-drafts/draft-ietf-tls-srp-05.txt">Using + * SRP for TLS Authentication</a>. The only difference between it and the SASL + * variant is that the shared secret is the entity <code>S</code> and not + * <code>H(S)</code>. + */ +public class SRP6TLSServer + extends SRP6KeyAgreement +{ + /** The user's ephemeral key pair. */ + private KeyPair hostKeyPair; + /** The SRP password database. */ + private SRPAuthInfoProvider passwordDB; + + // default 0-arguments constructor + + protected void engineInit(final Map attributes) throws KeyAgreementException + { + rnd = (SecureRandom) attributes.get(SOURCE_OF_RANDOMNESS); + final String md = (String) attributes.get(HASH_FUNCTION); + if (md == null || md.trim().length() == 0) + throw new KeyAgreementException("missing hash function"); + srp = SRP.instance(md); + passwordDB = (SRPAuthInfoProvider) attributes.get(HOST_PASSWORD_DB); + if (passwordDB == null) + throw new KeyAgreementException("missing SRP password database"); + } + + protected OutgoingMessage engineProcessMessage(final IncomingMessage in) + throws KeyAgreementException + { + switch (step) + { + case 0: + return sendParameters(in); + case 1: + return computeSharedSecret(in); + default: + throw new IllegalStateException("unexpected state"); + } + } + + protected void engineReset() + { + hostKeyPair = null; + super.engineReset(); + } + + private OutgoingMessage sendParameters(final IncomingMessage in) + throws KeyAgreementException + { + final String I = in.readString(); + // get s and v for user identified by I + // ---------------------------------------------------------------------- + final Map credentials; + try + { + final Map userID = new HashMap(); + userID.put(Registry.SASL_USERNAME, I); + userID.put(SRPRegistry.MD_NAME_FIELD, srp.getAlgorithm()); + credentials = passwordDB.lookup(userID); + } + catch (IOException x) + { + throw new KeyAgreementException("computeSharedSecret()", x); + } + + final BigInteger s = new BigInteger( + 1, Util.fromBase64((String) credentials.get(SRPRegistry.SALT_FIELD))); + final BigInteger v = new BigInteger( + 1, Util.fromBase64((String) credentials.get(SRPRegistry.USER_VERIFIER_FIELD))); + final Map configuration; + try + { + final String mode = (String) credentials.get(SRPRegistry.CONFIG_NDX_FIELD); + configuration = passwordDB.getConfiguration(mode); + } + catch (IOException x) + { + throw new KeyAgreementException("computeSharedSecret()", x); + } + N = new BigInteger( + 1, Util.fromBase64((String) configuration.get(SRPRegistry.SHARED_MODULUS))); + g = new BigInteger( + 1, Util.fromBase64((String) configuration.get(SRPRegistry.FIELD_GENERATOR))); + // generate an ephemeral keypair + final SRPKeyPairGenerator kpg = new SRPKeyPairGenerator(); + final Map attributes = new HashMap(); + if (rnd != null) + attributes.put(SRPKeyPairGenerator.SOURCE_OF_RANDOMNESS, rnd); + attributes.put(SRPKeyPairGenerator.SHARED_MODULUS, N); + attributes.put(SRPKeyPairGenerator.GENERATOR, g); + attributes.put(SRPKeyPairGenerator.USER_VERIFIER, v); + kpg.setup(attributes); + hostKeyPair = kpg.generate(); + final BigInteger B = ((SRPPublicKey) hostKeyPair.getPublic()).getY(); + final OutgoingMessage result = new OutgoingMessage(); + result.writeMPI(N); + result.writeMPI(g); + result.writeMPI(s); + result.writeMPI(B); + return result; + } + + protected OutgoingMessage computeSharedSecret(final IncomingMessage in) + throws KeyAgreementException + { + final BigInteger A = in.readMPI(); + final BigInteger B = ((SRPPublicKey) hostKeyPair.getPublic()).getY(); + final BigInteger u = uValue(A, B); // u = H(A | B) + // compute S = (Av^u) ^ b + final BigInteger b = ((SRPPrivateKey) hostKeyPair.getPrivate()).getX(); + final BigInteger v = ((SRPPrivateKey) hostKeyPair.getPrivate()).getV(); + final BigInteger S = A.multiply(v.modPow(u, N)).modPow(b, N); + K = S; + complete = true; + return null; + } +} diff --git a/libjava/classpath/gnu/javax/crypto/key/srp6/SRP6User.java b/libjava/classpath/gnu/javax/crypto/key/srp6/SRP6User.java new file mode 100644 index 000000000..4a1e8dda9 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/key/srp6/SRP6User.java @@ -0,0 +1,163 @@ +/* SRP6User.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.key.srp6; + +import gnu.java.security.hash.IMessageDigest; +import gnu.java.security.util.Util; +import gnu.javax.crypto.key.KeyAgreementException; +import gnu.javax.crypto.key.IncomingMessage; +import gnu.javax.crypto.key.OutgoingMessage; +import gnu.javax.crypto.sasl.srp.SRP; + +import java.math.BigInteger; +import java.security.KeyPair; +import java.security.SecureRandom; +import java.util.HashMap; +import java.util.Map; + +/** + * The implementation of the User in the SRP-6 protocol. + * <p> + * Reference: + * <ol> + * <li><a href="http://srp.stanford.edu/design.html">SRP Protocol Design</a><br> + * Thomas J. Wu.</li> + * </ol> + */ +public class SRP6User + extends SRP6KeyAgreement +{ + /** The user's identity. */ + private String I; + /** The user's cleartext password. */ + private byte[] p; + /** The user's ephemeral key pair. */ + private KeyPair userKeyPair; + + // default 0-arguments constructor + + protected void engineInit(final Map attributes) throws KeyAgreementException + { + rnd = (SecureRandom) attributes.get(SOURCE_OF_RANDOMNESS); + N = (BigInteger) attributes.get(SHARED_MODULUS); + if (N == null) + throw new KeyAgreementException("missing shared modulus"); + g = (BigInteger) attributes.get(GENERATOR); + if (g == null) + throw new KeyAgreementException("missing generator"); + final String md = (String) attributes.get(HASH_FUNCTION); + if (md == null || md.trim().length() == 0) + throw new KeyAgreementException("missing hash function"); + srp = SRP.instance(md); + I = (String) attributes.get(USER_IDENTITY); + if (I == null) + throw new KeyAgreementException("missing user identity"); + p = (byte[]) attributes.get(USER_PASSWORD); + if (p == null) + throw new KeyAgreementException("missing user password"); + } + + protected OutgoingMessage engineProcessMessage(final IncomingMessage in) + throws KeyAgreementException + { + switch (step) + { + case 0: + return sendIdentity(in); + case 1: + return computeSharedSecret(in); + default: + throw new IllegalStateException("unexpected state"); + } + } + + protected void engineReset() + { + I = null; + p = null; + userKeyPair = null; + super.engineReset(); + } + + private OutgoingMessage sendIdentity(final IncomingMessage in) + throws KeyAgreementException + { + // generate an ephemeral keypair + final SRPKeyPairGenerator kpg = new SRPKeyPairGenerator(); + final Map attributes = new HashMap(); + if (rnd != null) + attributes.put(SRPKeyPairGenerator.SOURCE_OF_RANDOMNESS, rnd); + attributes.put(SRPKeyPairGenerator.SHARED_MODULUS, N); + attributes.put(SRPKeyPairGenerator.GENERATOR, g); + kpg.setup(attributes); + userKeyPair = kpg.generate(); + final OutgoingMessage result = new OutgoingMessage(); + result.writeString(I); + result.writeMPI(((SRPPublicKey) userKeyPair.getPublic()).getY()); + return result; + } + + private OutgoingMessage computeSharedSecret(final IncomingMessage in) + throws KeyAgreementException + { + final BigInteger s = in.readMPI(); + final BigInteger B = in.readMPI(); + final BigInteger A = ((SRPPublicKey) userKeyPair.getPublic()).getY(); + final BigInteger u = uValue(A, B); // u = H(A | B) + final BigInteger x; + try + { + x = new BigInteger(1, srp.computeX(Util.trim(s), I, p)); + } + catch (Exception e) + { + throw new KeyAgreementException("computeSharedSecret()", e); + } + // compute S = (B - 3g^x) ^ (a + ux) + final BigInteger a = ((SRPPrivateKey) userKeyPair.getPrivate()).getX(); + final BigInteger S = B.subtract(THREE.multiply(g.modPow(x, N))) + .modPow(a.add(u.multiply(x)), N); + final byte[] sBytes = Util.trim(S); + final IMessageDigest hash = srp.newDigest(); + hash.update(sBytes, 0, sBytes.length); + K = new BigInteger(1, hash.digest()); + complete = true; + return null; + } +} diff --git a/libjava/classpath/gnu/javax/crypto/key/srp6/SRPAlgorithm.java b/libjava/classpath/gnu/javax/crypto/key/srp6/SRPAlgorithm.java new file mode 100644 index 000000000..fb8249e05 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/key/srp6/SRPAlgorithm.java @@ -0,0 +1,131 @@ +/* SRPAlgorithm.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.key.srp6; + +import gnu.javax.crypto.sasl.srp.SRPRegistry; + +import java.math.BigInteger; + +/** + * Utilities for use with SRP-6 based methods and protocols. + * <p> + * Reference: + * <ol> + * <li><a href="http://srp.stanford.edu/design.html">SRP Protocol Design</a><br> + * Thomas J. Wu.</li> + * </ol> + */ +public class SRPAlgorithm +{ + // lifted from draft-burdis-cat-srp-sasl-09 + public static final BigInteger N_2048 = new BigInteger( + "AC6BDB41324A9A9BF166DE5E1389582FAF72B6651987EE07FC3192943DB56050" + + "A37329CBB4A099ED8193E0757767A13DD52312AB4B03310DCD7F48A9DA04FD50" + + "E8083969EDB767B0CF6095179A163AB3661A05FBD5FAAAE82918A9962F0B93B8" + + "55F97993EC975EEAA80D740ADBF4FF747359D041D5C33EA71D281E446B14773B" + + "CA97B43A23FB801676BD207A436C6481F1D2B9078717461A5B9D32E688F87748" + + "544523B524B0D57D5EA77A2775D2ECFA032CFBDBF52FB3786160279004E57AE6" + + "AF874E7303CE53299CCC041C7BC308D82A5698F3A8D0C38271AE35F8E9DBFBB6" + + "94B5C803D89F7AE435DE236D525F54759B65E372FCD68EF20FA7111F9E4AFF73", 16); + public static final BigInteger N_1536 = new BigInteger( + "9DEF3CAFB939277AB1F12A8617A47BBBDBA51DF499AC4C80BEEEA9614B19CC4D" + + "5F4F5F556E27CBDE51C6A94BE4607A291558903BA0D0F84380B655BB9A22E8DC" + + "DF028A7CEC67F0D08134B1C8B97989149B609E0BE3BAB63D47548381DBC5B1FC" + + "764E3F4B53DD9DA1158BFD3E2B9C8CF56EDF019539349627DB2FD53D24B7C486" + + "65772E437D6C7F8CE442734AF7CCB7AE837C264AE3A9BEB87F8A2FE9B8B5292E" + + "5A021FFF5E91479E8CE7A28C2442C6F315180F93499A234DCF76E3FED135F9BB", 16); + public static final BigInteger N_1280 = new BigInteger( + "D77946826E811914B39401D56A0A7843A8E7575D738C672A090AB1187D690DC4" + + "3872FC06A7B6A43F3B95BEAEC7DF04B9D242EBDC481111283216CE816E004B78" + + "6C5FCE856780D41837D95AD787A50BBE90BD3A9C98AC0F5FC0DE744B1CDE1891" + + "690894BC1F65E00DE15B4B2AA6D87100C9ECC2527E45EB849DEB14BB2049B163" + + "EA04187FD27C1BD9C7958CD40CE7067A9C024F9B7C5A0B4F5003686161F0605B", 16); + public static final BigInteger N_1024 = new BigInteger( + "EEAF0AB9ADB38DD69C33F80AFA8FC5E86072618775FF3C0B9EA2314C9C256576" + + "D674DF7496EA81D3383B4813D692C6E0E0D5D8E250B98BE48E495C1D6089DAD1" + + "5DC7D7B46154D6B6CE8EF4AD69B15D4982559B297BCF1885C529F566660E57EC" + + "68EDBC3C05726CC02FD4CBF4976EAA9AFD5138FE8376435B9FC61D2FC0EB06E3", 16); + public static final BigInteger N_768 = new BigInteger( + "B344C7C4F8C495031BB4E04FF8F84EE95008163940B9558276744D91F7CC9F40" + + "2653BE7147F00F576B93754BCDDF71B636F2099E6FFF90E79575F3D0DE694AFF" + + "737D9BE9713CEF8D837ADA6380B1093E94B6A529A8C6C2BE33E0867C60C3262B", 16); + public static final BigInteger N_640 = new BigInteger( + "C94D67EB5B1A2346E8AB422FC6A0EDAEDA8C7F894C9EEEC42F9ED250FD7F0046" + + "E5AF2CF73D6B2FA26BB08033DA4DE322E144E7A8E9B12A0E4637F6371F34A207" + + "1C4B3836CBEEAB15034460FAA7ADF483", 16); + public static final BigInteger N_512 = new BigInteger( + "D4C7F8A2B32C11B8FBA9581EC4BA4F1B04215642EF7355E37C0FC0443EF756EA" + + "2C6B8EEB755A1C723027663CAA265EF785B8FF6A9B35227A52D86633DBDFCA43", 16); + public static final BigInteger N_384 = new BigInteger( + "8025363296FB943FCE54BE717E0E2958A02A9672EF561953B2BAA3BAACC3ED57" + + "54EB764C7AB7184578C57D5949CCB41B", 16); + public static final BigInteger N_264 = new BigInteger( + "115B8B692E0E045692CF280B436735C77A5A9E8A9E7ED56C965F87DB5B2A2ECE3", 16); + private static final BigInteger ZERO = BigInteger.ZERO; + private static final BigInteger ONE = BigInteger.ONE; + private static final BigInteger TWO = BigInteger.valueOf(2L); + + /** Trivial constructor to enforce usage through class methods. */ + private SRPAlgorithm() + { + super(); + } + + public static void checkParams(final BigInteger N, final BigInteger g) + { + // 1. N should be at least 512-bit long + final int blen = N.bitLength(); + if (blen < SRPRegistry.MINIMUM_MODULUS_BITLENGTH) + throw new IllegalArgumentException("Bit length of N (" + + blen + + ") is too low. Should be at least " + + SRPRegistry.MINIMUM_MODULUS_BITLENGTH); + // 2. N should be a prime + if (! N.isProbablePrime(80)) + throw new IllegalArgumentException("N should be prime but isn't"); + // 3. N should be of the form 2*q + 1, where q is prime + final BigInteger q = N.subtract(ONE).divide(TWO); + if (! q.isProbablePrime(80)) + throw new IllegalArgumentException("(N-1)/2 should be prime but isn't"); + // 4. g**q should be -1 mod N + final BigInteger gq = g.modPow(q, N).add(ONE).mod(N); + if (gq.compareTo(ZERO) != 0) + throw new IllegalArgumentException("g**q should be -1 (mod N) but isn't"); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/key/srp6/SRPKey.java b/libjava/classpath/gnu/javax/crypto/key/srp6/SRPKey.java new file mode 100644 index 000000000..72ce8d2cf --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/key/srp6/SRPKey.java @@ -0,0 +1,147 @@ +/* SRPKey.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.key.srp6; + +import gnu.java.security.Registry; +import gnu.java.security.key.IKeyPairCodec; + +import java.io.Serializable; +import java.math.BigInteger; +import java.security.Key; + +/** + * An abstract representation of a base SRP ephemeral key. + * <p> + * This object encapsulates the two numbers: + * <ul> + * <li><b>N</b>: A large safe prime (N = 2q+1, where q is prime).</li> + * <li><b>g</b>: A generator modulo N.</li> + * </ul> + * <p> + * Note that in SRP, all arithmetic is done modulo N. + * <p> + * Reference: + * <ol> + * <li><a href="http://srp.stanford.edu/design.html">SRP Protocol Design</a><br> + * Thomas J. Wu.</li> + * </ol> + */ +public abstract class SRPKey + implements Key, Serializable +{ + /** The public, Germaine prime, shared modulus. */ + protected final BigInteger N; + /** The generator. */ + protected final BigInteger g; + + protected SRPKey(BigInteger N, BigInteger g) + { + super(); + + this.N = N; + this.g = g; + } + + /** + * Returns the standard algorithm name for this key. + * + * @return the standard algorithm name for this key. + */ + public String getAlgorithm() + { + return Registry.SRP_KPG; + } + + /** @deprecated see getEncoded(int). */ + public byte[] getEncoded() + { + return getEncoded(IKeyPairCodec.RAW_FORMAT); + } + + /** + * Returns {@link Registry#RAW_ENCODING_SHORT_NAME} which is the sole format + * supported for this type of keys. + * + * @return {@link Registry#RAW_ENCODING_SHORT_NAME} ALWAYS. + */ + public String getFormat() + { + return Registry.RAW_ENCODING_SHORT_NAME; + } + + /** + * Returns the public shared modulus. + * + * @return <code>N</code>. + */ + public BigInteger getN() + { + return N; + } + + /** + * Returns the generator. + * + * @return <code>g</code>. + */ + public BigInteger getG() + { + return g; + } + + /** + * Returns <code>true</code> if the designated object is an instance of + * <code>SRPKey</code> and has the same SRP parameter values as this one. + * + * @param obj the other non-null SRP key to compare to. + * @return <code>true</code> if the designated object is of the same type + * and value as this one. + */ + public boolean equals(Object obj) + { + if (obj == null) + return false; + if (! (obj instanceof SRPKey)) + return false; + SRPKey that = (SRPKey) obj; + return N.equals(that.getN()) && g.equals(that.getG()); + } + + public abstract byte[] getEncoded(int format); +} diff --git a/libjava/classpath/gnu/javax/crypto/key/srp6/SRPKeyPairGenerator.java b/libjava/classpath/gnu/javax/crypto/key/srp6/SRPKeyPairGenerator.java new file mode 100644 index 000000000..59e5bc943 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/key/srp6/SRPKeyPairGenerator.java @@ -0,0 +1,282 @@ +/* SRPKeyPairGenerator.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.key.srp6; + +import gnu.java.security.Configuration; +import gnu.java.security.Registry; +import gnu.java.security.key.IKeyPairGenerator; +import gnu.java.security.util.PRNG; + +import java.math.BigInteger; +import java.security.KeyPair; +import java.security.SecureRandom; +import java.util.Map; +import java.util.logging.Logger; + +/** + * Reference: + * <ol> + * <li><a href="http://srp.stanford.edu/design.html">SRP Protocol Design</a><br> + * Thomas J. Wu.</li> + * </ol> + */ +public class SRPKeyPairGenerator + implements IKeyPairGenerator +{ + private static final Logger log = Logger.getLogger(SRPKeyPairGenerator.class.getName()); + private static final BigInteger ZERO = BigInteger.ZERO; + private static final BigInteger ONE = BigInteger.ONE; + private static final BigInteger TWO = BigInteger.valueOf(2L); + private static final BigInteger THREE = BigInteger.valueOf(3L); + /** Property name of the length (Integer) of the modulus (N) of an SRP key. */ + public static final String MODULUS_LENGTH = "gnu.crypto.srp.L"; + /** Property name of the Boolean indicating wether or not to use defaults. */ + public static final String USE_DEFAULTS = "gnu.crypto.srp.use.defaults"; + /** Property name of the modulus (N) of an SRP key. */ + public static final String SHARED_MODULUS = "gnu.crypto.srp.N"; + /** Property name of the generator (g) of an SRP key. */ + public static final String GENERATOR = "gnu.crypto.srp.g"; + /** Property name of the user's verifier (v) for a Server SRP key. */ + public static final String USER_VERIFIER = "gnu.crypto.srp.v"; + /** + * Property name of an optional {@link SecureRandom} instance to use. The + * default is to use a classloader singleton from {@link PRNG}. + */ + public static final String SOURCE_OF_RANDOMNESS = "gnu.crypto.srp.prng"; + /** Default value for the modulus length. */ + private static final int DEFAULT_MODULUS_LENGTH = 1024; + /** The optional {@link SecureRandom} instance to use. */ + private SecureRandom rnd = null; + /** Bit length of the shared modulus. */ + private int l; + /** The shared public modulus. */ + private BigInteger N; + /** The Field generator. */ + private BigInteger g; + /** The user's verifier MPI. */ + private BigInteger v; + /** Our default source of randomness. */ + private PRNG prng = null; + + // implicit 0-arguments constructor + + public String name() + { + return Registry.SRP_KPG; + } + + public void setup(Map attributes) + { + // do we have a SecureRandom, or should we use our own? + rnd = (SecureRandom) attributes.get(SOURCE_OF_RANDOMNESS); + N = (BigInteger) attributes.get(SHARED_MODULUS); + if (N != null) + { + l = N.bitLength(); + g = (BigInteger) attributes.get(GENERATOR); + if (g == null) + g = TWO; + SRPAlgorithm.checkParams(N, g); + } + else + { // generate or use default values for N and g + Boolean useDefaults = (Boolean) attributes.get(USE_DEFAULTS); + if (useDefaults == null) + useDefaults = Boolean.TRUE; + Integer L = (Integer) attributes.get(MODULUS_LENGTH); + l = DEFAULT_MODULUS_LENGTH; + if (useDefaults.equals(Boolean.TRUE)) + { + if (L != null) + { + l = L.intValue(); + switch (l) + { + case 512: + N = SRPAlgorithm.N_512; + break; + case 640: + N = SRPAlgorithm.N_640; + break; + case 768: + N = SRPAlgorithm.N_768; + break; + case 1024: + N = SRPAlgorithm.N_1024; + break; + case 1280: + N = SRPAlgorithm.N_1280; + break; + case 1536: + N = SRPAlgorithm.N_1536; + break; + case 2048: + N = SRPAlgorithm.N_2048; + break; + default: + throw new IllegalArgumentException( + "unknown default shared modulus bit length"); + } + g = TWO; + l = N.bitLength(); + } + } + else // generate new N and g + { + if (L != null) + { + l = L.intValue(); + if ((l % 256) != 0 || l < 512 || l > 2048) + throw new IllegalArgumentException( + "invalid shared modulus bit length"); + } + } + } + // are we using this generator on the server side, or the client side? + v = (BigInteger) attributes.get(USER_VERIFIER); + } + + public KeyPair generate() + { + if (N == null) + { + BigInteger[] params = generateParameters(); + BigInteger q = params[0]; + N = params[1]; + g = params[2]; + if (Configuration.DEBUG) + { + log.fine("q: " + q.toString(16)); + log.fine("N: " + N.toString(16)); + log.fine("g: " + g.toString(16)); + } + } + return (v != null ? hostKeyPair() : userKeyPair()); + } + + private synchronized BigInteger[] generateParameters() + { + // N A large safe prime (N = 2q+1, where q is prime) + // g A generator modulo N + BigInteger q, p, g; + byte[] qBytes = new byte[l / 8]; + do + { + do + { + nextRandomBytes(qBytes); + q = new BigInteger(1, qBytes); + q = q.setBit(0).setBit(l - 2).clearBit(l - 1); + } + while (! q.isProbablePrime(80)); + p = q.multiply(TWO).add(ONE); + } + while (p.bitLength() != l || ! p.isProbablePrime(80)); + // compute g. from FIPS-186, Appendix 4: e == 2 + BigInteger p_minus_1 = p.subtract(ONE); + g = TWO; + // Set h = any integer, where 1 < h < p - 1 and + // h differs from any value previously tried + for (BigInteger h = TWO; h.compareTo(p_minus_1) < 0; h = h.add(ONE)) + { + // Set g = h**2 mod p + g = h.modPow(TWO, p); + // If g = 1, go to step 3 + if (! g.equals(ONE)) + break; + } + return new BigInteger[] { q, p, g }; + } + + private KeyPair hostKeyPair() + { + byte[] bBytes = new byte[(l + 7) / 8]; + BigInteger b, B; + do + { + do + { + nextRandomBytes(bBytes); + b = new BigInteger(1, bBytes); + } + while (b.compareTo(ONE) <= 0 || b.compareTo(N) >= 0); + B = THREE.multiply(v).add(g.modPow(b, N)).mod(N); + } + while (B.compareTo(ZERO) == 0 || B.compareTo(N) >= 0); + KeyPair result = new KeyPair(new SRPPublicKey(new BigInteger[] { N, g, B }), + new SRPPrivateKey(new BigInteger[] { N, g, b, v })); + return result; + } + + private KeyPair userKeyPair() + { + byte[] aBytes = new byte[(l + 7) / 8]; + BigInteger a, A; + do + { + do + { + nextRandomBytes(aBytes); + a = new BigInteger(1, aBytes); + } + while (a.compareTo(ONE) <= 0 || a.compareTo(N) >= 0); + A = g.modPow(a, N); + } + while (A.compareTo(ZERO) == 0 || A.compareTo(N) >= 0); + KeyPair result = new KeyPair(new SRPPublicKey(new BigInteger[] { N, g, A }), + new SRPPrivateKey(new BigInteger[] { N, g, a })); + return result; + } + + private void nextRandomBytes(byte[] buffer) + { + if (rnd != null) + rnd.nextBytes(buffer); + else + getDefaultPRNG().nextBytes(buffer); + } + + private PRNG getDefaultPRNG() + { + if (prng == null) + prng = PRNG.getInstance(); + + return prng; + } +} diff --git a/libjava/classpath/gnu/javax/crypto/key/srp6/SRPKeyPairRawCodec.java b/libjava/classpath/gnu/javax/crypto/key/srp6/SRPKeyPairRawCodec.java new file mode 100644 index 000000000..b7cc53693 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/key/srp6/SRPKeyPairRawCodec.java @@ -0,0 +1,334 @@ +/* SRPKeyPairRawCodec.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.key.srp6; + +import gnu.java.security.Registry; +import gnu.java.security.key.IKeyPairCodec; + +import java.io.ByteArrayOutputStream; +import java.math.BigInteger; +import java.security.PrivateKey; +import java.security.PublicKey; + +/** + * An object that implements the {@link IKeyPairCodec} operations for the + * <i>Raw</i> format to use with SRP keypairs. + * <p> + * Reference: + * <ol> + * <li><a href="http://srp.stanford.edu/design.html">SRP Protocol Design</a><br> + * Thomas J. Wu.</li> + * </ol> + */ +public class SRPKeyPairRawCodec + implements IKeyPairCodec +{ + // implicit 0-arguments constructor + + public int getFormatID() + { + return RAW_FORMAT; + } + + /** + * Returns the encoded form of the designated SRP public key according to the + * <i>Raw</i> format supported by this library. + * <p> + * The <i>Raw</i> format for an SRP public key, in this implementation, is a + * byte sequence consisting of the following: + * <ol> + * <li>4-byte magic consisting of the value of the literal + * {@link Registry#MAGIC_RAW_SRP_PUBLIC_KEY},</li> + * <li>1-byte version consisting of the constant: 0x01,</li> + * <li>4-byte count of following bytes representing the SRP parameter + * <code>N</code> in internet order,</li> + * <li>n-bytes representation of a {@link BigInteger} obtained by invoking + * the <code>toByteArray()</code> method on the SRP parameter <code>N</code>, + * </li> + * <li>4-byte count of following bytes representing the SRP parameter + * <code>g</code>,</li> + * <li>n-bytes representation of a {@link BigInteger} obtained by invoking + * the <code>toByteArray()</code> method on the SRP parameter <code>g</code>, + * </li> + * <li>4-byte count of following bytes representing the SRP parameter + * <code>y</code>,</li> + * <li>n-bytes representation of a {@link BigInteger} obtained by invoking + * the <code>toByteArray()</code> method on the SRP parameter <code>y</code>, + * </li> + * </ol> + * + * @param key the key to encode. + * @return the <i>Raw</i> format encoding of the designated key. + * @throws IllegalArgumentException if the designated key is not an SRP one. + */ + public byte[] encodePublicKey(PublicKey key) + { + if (! (key instanceof SRPPublicKey)) + throw new IllegalArgumentException("key"); + SRPPublicKey srpKey = (SRPPublicKey) key; + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + // magic + baos.write(Registry.MAGIC_RAW_SRP_PUBLIC_KEY[0]); + baos.write(Registry.MAGIC_RAW_SRP_PUBLIC_KEY[1]); + baos.write(Registry.MAGIC_RAW_SRP_PUBLIC_KEY[2]); + baos.write(Registry.MAGIC_RAW_SRP_PUBLIC_KEY[3]); + // version + baos.write(0x01); + // N + byte[] buffer = srpKey.getN().toByteArray(); + int length = buffer.length; + baos.write( length >>> 24); + baos.write((length >>> 16) & 0xFF); + baos.write((length >>> 8) & 0xFF); + baos.write( length & 0xFF); + baos.write(buffer, 0, length); + // g + buffer = srpKey.getG().toByteArray(); + length = buffer.length; + baos.write( length >>> 24); + baos.write((length >>> 16) & 0xFF); + baos.write((length >>> 8) & 0xFF); + baos.write( length & 0xFF); + baos.write(buffer, 0, length); + // y + buffer = srpKey.getY().toByteArray(); + length = buffer.length; + baos.write( length >>> 24); + baos.write((length >>> 16) & 0xFF); + baos.write((length >>> 8) & 0xFF); + baos.write( length & 0xFF); + baos.write(buffer, 0, length); + return baos.toByteArray(); + } + + public PublicKey decodePublicKey(byte[] k) + { + // magic + if (k[0] != Registry.MAGIC_RAW_SRP_PUBLIC_KEY[0] + || k[1] != Registry.MAGIC_RAW_SRP_PUBLIC_KEY[1] + || k[2] != Registry.MAGIC_RAW_SRP_PUBLIC_KEY[2] + || k[3] != Registry.MAGIC_RAW_SRP_PUBLIC_KEY[3]) + throw new IllegalArgumentException("magic"); + // version + if (k[4] != 0x01) + throw new IllegalArgumentException("version"); + int i = 5; + int l; + byte[] buffer; + // N + l = k[i++] << 24 + | (k[i++] & 0xFF) << 16 + | (k[i++] & 0xFF) << 8 + | (k[i++] & 0xFF); + buffer = new byte[l]; + System.arraycopy(k, i, buffer, 0, l); + i += l; + BigInteger N = new BigInteger(1, buffer); + // g + l = k[i++] << 24 + | (k[i++] & 0xFF) << 16 + | (k[i++] & 0xFF) << 8 + | (k[i++] & 0xFF); + buffer = new byte[l]; + System.arraycopy(k, i, buffer, 0, l); + i += l; + BigInteger g = new BigInteger(1, buffer); + // y + l = k[i++] << 24 + | (k[i++] & 0xFF) << 16 + | (k[i++] & 0xFF) << 8 + | (k[i++] & 0xFF); + buffer = new byte[l]; + System.arraycopy(k, i, buffer, 0, l); + i += l; + BigInteger y = new BigInteger(1, buffer); + return new SRPPublicKey(N, g, y); + } + + /** + * Returns the encoded form of the designated SRP private key according to the + * <i>Raw</i> format supported by this library. + * <p> + * The <i>Raw</i> format for an SRP private key, in this implementation, is a + * byte sequence consisting of the following: + * <ol> + * <li>4-byte magic consisting of the value of the literal + * {@link Registry#MAGIC_RAW_SRP_PRIVATE_KEY},</li> + * <li>1-byte version consisting of the constant: 0x01,</li> + * <li>4-byte count of following bytes representing the SRP parameter + * <code>N</code> in internet order,</li> + * <li>n-bytes representation of a {@link BigInteger} obtained by invoking + * the <code>toByteArray()</code> method on the SRP parameter <code>N</code>, + * </li> + * <li>4-byte count of following bytes representing the SRP parameter + * <code>g</code>,</li> + * <li>n-bytes representation of a {@link BigInteger} obtained by invoking + * the <code>toByteArray()</code> method on the SRP parameter <code>g</code>, + * </li> + * <li>4-byte count of following bytes representing the SRP parameter + * <code>x</code>,</li> + * <li>n-bytes representation of a {@link BigInteger} obtained by invoking + * the <code>toByteArray()</code> method on the SRP parameter <code>x</code>, + * </li> + * <li>one byte which indicates whether the SRP parameter <code>v</code> is + * included in this encoding (value <code>0x01</code>) or not (value + * <code>0x00</code>).</li> + * <li>4-byte count of following bytes representing the SRP parameter + * <code>v</code>,</li> + * <li>n-bytes representation of a {@link BigInteger} obtained by invoking + * the <code>toByteArray()</code> method on the SRP parameter <code>v</code>, + * </li> + * </ol> + * + * @param key the key to encode. + * @return the <i>Raw</i> format encoding of the designated key. + * @throws IllegalArgumentException if the designated key is not an SRP one. + */ + public byte[] encodePrivateKey(PrivateKey key) + { + if (! (key instanceof SRPPrivateKey)) + throw new IllegalArgumentException("key"); + SRPPrivateKey srpKey = (SRPPrivateKey) key; + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + // magic + baos.write(Registry.MAGIC_RAW_SRP_PRIVATE_KEY[0]); + baos.write(Registry.MAGIC_RAW_SRP_PRIVATE_KEY[1]); + baos.write(Registry.MAGIC_RAW_SRP_PRIVATE_KEY[2]); + baos.write(Registry.MAGIC_RAW_SRP_PRIVATE_KEY[3]); + // version + baos.write(0x01); + // N + byte[] buffer = srpKey.getN().toByteArray(); + int length = buffer.length; + baos.write( length >>> 24); + baos.write((length >>> 16) & 0xFF); + baos.write((length >>> 8) & 0xFF); + baos.write( length & 0xFF); + baos.write(buffer, 0, length); + // g + buffer = srpKey.getG().toByteArray(); + length = buffer.length; + baos.write( length >>> 24); + baos.write((length >>> 16) & 0xFF); + baos.write((length >>> 8) & 0xFF); + baos.write( length & 0xFF); + baos.write(buffer, 0, length); + // x + buffer = srpKey.getX().toByteArray(); + length = buffer.length; + baos.write( length >>> 24); + baos.write((length >>> 16) & 0xFF); + baos.write((length >>> 8) & 0xFF); + baos.write( length & 0xFF); + baos.write(buffer, 0, length); + // v + if (srpKey.getV() != null) + { + baos.write(0x01); + buffer = srpKey.getV().toByteArray(); + length = buffer.length; + baos.write( length >>> 24); + baos.write((length >>> 16) & 0xFF); + baos.write((length >>> 8) & 0xFF); + baos.write( length & 0xFF); + baos.write(buffer, 0, length); + } + else + baos.write(0x00); + return baos.toByteArray(); + } + + public PrivateKey decodePrivateKey(byte[] k) + { + // magic + if (k[0] != Registry.MAGIC_RAW_SRP_PRIVATE_KEY[0] + || k[1] != Registry.MAGIC_RAW_SRP_PRIVATE_KEY[1] + || k[2] != Registry.MAGIC_RAW_SRP_PRIVATE_KEY[2] + || k[3] != Registry.MAGIC_RAW_SRP_PRIVATE_KEY[3]) + throw new IllegalArgumentException("magic"); + // version + if (k[4] != 0x01) + throw new IllegalArgumentException("version"); + int i = 5; + int l; + byte[] buffer; + // N + l = k[i++] << 24 + | (k[i++] & 0xFF) << 16 + | (k[i++] & 0xFF) << 8 + | (k[i++] & 0xFF); + buffer = new byte[l]; + System.arraycopy(k, i, buffer, 0, l); + i += l; + BigInteger N = new BigInteger(1, buffer); + // g + l = k[i++] << 24 + | (k[i++] & 0xFF) << 16 + | (k[i++] & 0xFF) << 8 + | (k[i++] & 0xFF); + buffer = new byte[l]; + System.arraycopy(k, i, buffer, 0, l); + i += l; + BigInteger g = new BigInteger(1, buffer); + // x + l = k[i++] << 24 + | (k[i++] & 0xFF) << 16 + | (k[i++] & 0xFF) << 8 + | (k[i++] & 0xFF); + buffer = new byte[l]; + System.arraycopy(k, i, buffer, 0, l); + i += l; + BigInteger x = new BigInteger(1, buffer); + // v + l = k[i++]; + if (l == 0x01) + { + l = k[i++] << 24 + | (k[i++] & 0xFF) << 16 + | (k[i++] & 0xFF) << 8 + | (k[i++] & 0xFF); + buffer = new byte[l]; + System.arraycopy(k, i, buffer, 0, l); + i += l; + BigInteger v = new BigInteger(1, buffer); + return new SRPPrivateKey(N, g, x, v); + } + return new SRPPrivateKey(N, g, x); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/key/srp6/SRPPrivateKey.java b/libjava/classpath/gnu/javax/crypto/key/srp6/SRPPrivateKey.java new file mode 100644 index 000000000..c2e13be82 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/key/srp6/SRPPrivateKey.java @@ -0,0 +1,227 @@ +/* SRPPrivateKey.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.key.srp6; + +import gnu.java.security.Registry; +import gnu.java.security.key.IKeyPairCodec; + +import java.math.BigInteger; +import java.security.PrivateKey; + +/** + * A representation of an SRP ephemeral private key. + * <p> + * Reference: + * <ol> + * <li><a href="http://srp.stanford.edu/design.html">SRP Protocol Design</a><br> + * Thomas J. Wu.</li> + * </ol> + */ +public class SRPPrivateKey + extends SRPKey + implements PrivateKey +{ + /** + * The private exponent for either the server or the client engaged in the SRP + * protocol exchange. + */ + private final BigInteger X; + /** + * The user's verifier (v) --for the server-- also computed at the client side + * as g.modPow(x, N), where x is the hashed output of the user name and + * password . + */ + private final BigInteger v; + + /** + * Public constructor for use from outside this package. + * + * @param N the public shared modulus. + * @param g the generator. + * @param x the private exponent of the ephemeral key. + */ + public SRPPrivateKey(BigInteger N, BigInteger g, BigInteger x) + { + this(N, g, x, null); + } + + /** + * Public constructor for use from outside this package. + * + * @param N the public shared modulus. + * @param g the generator. + * @param x the private exponent of the ephemeral key. + * @param v the user's verifier value (for the server side only). + */ + public SRPPrivateKey(BigInteger N, BigInteger g, BigInteger x, BigInteger v) + { + super(N, g); + + SRPAlgorithm.checkParams(N, g); + this.X = x; + this.v = v; + } + + /** + * Default constructor. Assumes N and g are already validated. + * + * @param params an array of either 3 or 4 values representing N, g, and + * either v and X for the server, or just X for the client. Those + * values represent the following: + * <ol> + * <li>v (server side): the user's verifier.</li> + * <li>X (both sides): the server's or client's ephemeral private + * exponent.</li> + * </ol> + */ + SRPPrivateKey(BigInteger[] params) + { + super(params[0], params[1]); + + if (params.length == 3) + { + X = params[2]; + v = null; + } + else if (params.length == 4) + { + X = params[2]; + v = params[3]; + } + else + throw new IllegalArgumentException("invalid number of SRP parameters"); + } + + /** + * A class method that takes the output of the <code>encodePrivateKey()</code> + * method of an SRP keypair codec object (an instance implementing + * {@link IKeyPairCodec} for DSS keys, and re-constructs an instance of this + * object. + * + * @param k the contents of a previously encoded instance of this object. + * @throws ArrayIndexOutOfBoundsException if there is not enough bytes, in + * <code>k</code>, to represent a valid encoding of an instance + * of this object. + * @throws IllegalArgumentException if the byte sequence does not represent a + * valid encoding of an instance of this object. + */ + public static SRPPrivateKey valueOf(byte[] k) + { + // check magic... + // we should parse here enough bytes to know which codec to use, and + // direct the byte array to the appropriate codec. since we only have one + // codec, we could have immediately tried it; nevertheless since testing + // one byte is cheaper than instatiating a codec that will fail we test + // the first byte before we carry on. + if (k[0] == Registry.MAGIC_RAW_SRP_PRIVATE_KEY[0]) + { + // it's likely to be in raw format. get a raw codec and hand it over + IKeyPairCodec codec = new SRPKeyPairRawCodec(); + return (SRPPrivateKey) codec.decodePrivateKey(k); + } + throw new IllegalArgumentException("magic"); + } + + /** + * Returns the private exponent of the key as a {@link BigInteger}. + * + * @return the private exponent of the key as a {@link BigInteger}. + */ + public BigInteger getX() + { + return X; + } + + /** + * Returns the user's verifier as a {@link BigInteger}. + * + * @return the user's verifier as a {@link BigInteger} if this is an SRP + * private key of a Host, or <code>null</code> if this is a private + * SRP key for a User. + */ + public BigInteger getV() + { + return v; + } + + /** + * Returns the encoded form of this private key according to the designated + * format. + * + * @param format the desired format identifier of the resulting encoding. + * @return the byte sequence encoding this key according to the designated + * format. + * @throws IllegalArgumentException if the format is not supported. + */ + public byte[] getEncoded(int format) + { + byte[] result; + switch (format) + { + case IKeyPairCodec.RAW_FORMAT: + result = new SRPKeyPairRawCodec().encodePrivateKey(this); + break; + default: + throw new IllegalArgumentException("format"); + } + return result; + } + + /** + * Returns <code>true</code> if the designated object is an instance of + * <code>SRPPrivateKey</code> and has the same SRP parameter values as this + * one. + * + * @param obj the other non-null SRP key to compare to. + * @return <code>true</code> if the designated object is of the same type + * and value as this one. + */ + public boolean equals(Object obj) + { + if (obj == null) + return false; + if (! (obj instanceof SRPPrivateKey)) + return false; + SRPPrivateKey that = (SRPPrivateKey) obj; + boolean result = super.equals(that) && X.equals(that.getX()); + if (v != null) + result = result && v.equals(that.getV()); + return result; + } +} diff --git a/libjava/classpath/gnu/javax/crypto/key/srp6/SRPPublicKey.java b/libjava/classpath/gnu/javax/crypto/key/srp6/SRPPublicKey.java new file mode 100644 index 000000000..2db13ff4c --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/key/srp6/SRPPublicKey.java @@ -0,0 +1,175 @@ +/* SRPPublicKey.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.key.srp6; + +import gnu.java.security.Registry; +import gnu.java.security.key.IKeyPairCodec; + +import java.math.BigInteger; +import java.security.PublicKey; + +/** + * A representation of an SRP ephemeral public key. + * <p> + * Reference: + * <ol> + * <li><a href="http://srp.stanford.edu/design.html">SRP Protocol Design</a><br> + * Thomas J. Wu.</li> + * </ol> + */ +public class SRPPublicKey + extends SRPKey + implements PublicKey +{ + /** + * The public exponent for either the server or the client engaged in the SRP + * protocol exchange. + */ + private final BigInteger Y; + + /** + * Public constructor for use from outside this package. + * + * @param N the public shared modulus. + * @param g the generator. + * @param Y the public exponent of the ephemeral key. + */ + public SRPPublicKey(BigInteger N, BigInteger g, BigInteger Y) + { + super(N, g); + + SRPAlgorithm.checkParams(N, g); + this.Y = Y; + } + + /** + * Default constructor. Assumes that N and g are already validated. + * + * @param params an array of 3 values representing N, g and Y; the latter + * being the client's or server's public exponent. + */ + SRPPublicKey(BigInteger[] params) + { + super(params[0], params[1]); + + this.Y = params[2]; + } + + /** + * A class method that takes the output of the <code>encodePublicKey()</code> + * method of an SRP keypair codec object (an instance implementing + * {@link IKeyPairCodec} for SRP keys, and re-constructs an instance of this + * object. + * + * @param k the contents of a previously encoded instance of this object. + * @throws ArrayIndexOutOfBoundsException if there is not enough bytes, in + * <code>k</code>, to represent a valid encoding of an instance + * of this object. + * @throws IllegalArgumentException if the byte sequence does not represent a + * valid encoding of an instance of this object. + */ + public static SRPPublicKey valueOf(byte[] k) + { + // check magic... + // we should parse here enough bytes to know which codec to use, and + // direct the byte array to the appropriate codec. since we only have one + // codec, we could have immediately tried it; nevertheless since testing + // one byte is cheaper than instatiating a codec that will fail we test + // the first byte before we carry on. + if (k[0] == Registry.MAGIC_RAW_SRP_PUBLIC_KEY[0]) + { + // it's likely to be in raw format. get a raw codec and hand it over + IKeyPairCodec codec = new SRPKeyPairRawCodec(); + return (SRPPublicKey) codec.decodePublicKey(k); + } + throw new IllegalArgumentException("magic"); + } + + /** + * Returns the public exponent of the key as a {@link BigInteger}. + * + * @return the public exponent of the key as a {@link BigInteger}. + */ + public BigInteger getY() + { + return Y; + } + + /** + * Returns the encoded form of this public key according to the designated + * format. + * + * @param format the desired format identifier of the resulting encoding. + * @return the byte sequence encoding this key according to the designated + * format. + * @throws IllegalArgumentException if the format is not supported. + */ + public byte[] getEncoded(int format) + { + byte[] result; + switch (format) + { + case IKeyPairCodec.RAW_FORMAT: + result = new SRPKeyPairRawCodec().encodePublicKey(this); + break; + default: + throw new IllegalArgumentException("format"); + } + return result; + } + + /** + * Returns <code>true</code> if the designated object is an instance of + * <code>SRPPublicKey</code>and has the same SRP parameter values as this + * one. + * + * @param obj the other non-null SRP key to compare to. + * @return <code>true</code> if the designated object is of the same type + * and value as this one. + */ + public boolean equals(Object obj) + { + if (obj == null) + return false; + if (! (obj instanceof SRPPublicKey)) + return false; + SRPPublicKey that = (SRPPublicKey) obj; + return super.equals(that) && Y.equals(that.getY()); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/keyring/AuthenticatedEntry.java b/libjava/classpath/gnu/javax/crypto/keyring/AuthenticatedEntry.java new file mode 100644 index 000000000..91c3bc6e2 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/keyring/AuthenticatedEntry.java @@ -0,0 +1,176 @@ +/* AuthenticatedEntry.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.keyring; + +import gnu.java.security.Registry; +import gnu.javax.crypto.mac.IMac; +import gnu.javax.crypto.mac.MacFactory; +import gnu.javax.crypto.mac.MacOutputStream; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.security.InvalidKeyException; +import java.util.Arrays; +import java.util.HashMap; +import java.util.Iterator; + +public final class AuthenticatedEntry + extends MaskableEnvelopeEntry + implements Registry +{ + public static final int TYPE = 2; + + public AuthenticatedEntry(String mac, int macLen, Properties properties) + { + super(TYPE, properties); + if (macLen <= 0) + throw new IllegalArgumentException("invalid mac length"); + this.properties.put("mac", mac); + this.properties.put("maclen", String.valueOf(macLen)); + setMasked(false); + } + + private AuthenticatedEntry() + { + super(TYPE); + setMasked(true); + } + + public static AuthenticatedEntry decode(DataInputStream in) + throws IOException + { + AuthenticatedEntry entry = new AuthenticatedEntry(); + entry.properties.decode(in); + if (! entry.properties.containsKey("mac")) + throw new MalformedKeyringException("no mac specified"); + if (! entry.properties.containsKey("maclen")) + throw new MalformedKeyringException("no mac length specified"); + return entry; + } + + /** + * Computes the mac over this envelope's data. This method <b>must</b> be + * called before this entry in encoded. + * + * @param key The key to authenticate with. + * @throws IOException If encoding fails. + * @throws InvalidKeyException If the supplied key is bad. + */ + public void authenticate(byte[] key) throws IOException, InvalidKeyException + { + if (isMasked()) + throw new IllegalStateException("entry is masked"); + IMac m = getMac(key); + ByteArrayOutputStream bout = new ByteArrayOutputStream(1024); + MacOutputStream macout = new MacOutputStream(bout, m); + DataOutputStream out2 = new DataOutputStream(macout); + for (Iterator it = entries.iterator(); it.hasNext();) + { + Entry entry = (Entry) it.next(); + entry.encode(out2); + } + bout.write(m.digest()); + payload = bout.toByteArray(); + } + + /** + * Verifies this entry's payload. This method will unmask this entry, thus it + * must be called before accessing its contents. + * + * @param key The key to use to authenticate. + * @throws InvalidKeyException If the given key is improper. + */ + public void verify(byte[] key) throws InvalidKeyException + { + if (! isMasked() || payload == null) + return; + IMac m = getMac(key); + m.update(payload, 0, payload.length - m.macSize()); + byte[] macValue = new byte[m.macSize()]; + System.arraycopy(payload, payload.length - macValue.length, macValue, 0, + macValue.length); + if (! Arrays.equals(macValue, m.digest())) + throw new IllegalArgumentException("MAC verification failed"); + try + { + int len = payload.length - m.macSize(); + ByteArrayInputStream bais = new ByteArrayInputStream(payload, 0, len); + DataInputStream in = new DataInputStream(bais); + decodeEnvelope(in); + } + catch (IOException ioe) + { + throw new IllegalArgumentException("malformed keyring fragment"); + } + setMasked(false); + payload = null; + } + + protected void encodePayload() throws IOException + { + if (payload == null) + throw new IllegalStateException("not authenticated"); + } + + private IMac getMac(byte[] key) throws InvalidKeyException + { + IMac mac = MacFactory.getInstance(properties.get("mac")); + if (mac == null) + throw new IllegalArgumentException("no such mac: " + properties.get("mac")); + int maclen = 0; + if (! properties.containsKey("maclen")) + throw new IllegalArgumentException("no MAC length"); + try + { + maclen = Integer.parseInt(properties.get("maclen")); + } + catch (NumberFormatException nfe) + { + throw new IllegalArgumentException("bad MAC length"); + } + HashMap macAttr = new HashMap(); + macAttr.put(IMac.MAC_KEY_MATERIAL, key); + macAttr.put(IMac.TRUNCATED_SIZE, Integer.valueOf(maclen)); + mac.init(macAttr); + return mac; + } +} diff --git a/libjava/classpath/gnu/javax/crypto/keyring/BaseKeyring.java b/libjava/classpath/gnu/javax/crypto/keyring/BaseKeyring.java new file mode 100644 index 000000000..e93ca8fa3 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/keyring/BaseKeyring.java @@ -0,0 +1,158 @@ +/* BaseKeyring.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.keyring; + +import gnu.java.security.Registry; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.Enumeration; +import java.util.List; +import java.util.Map; +import java.util.StringTokenizer; + +public abstract class BaseKeyring + implements IKeyring +{ + /** The top-level keyring data. */ + protected PasswordAuthenticatedEntry keyring; + protected CompressedEntry keyring2; + + public BaseKeyring() + { + } + + public void load(Map attributes) throws IOException + { + InputStream in = (InputStream) attributes.get(KEYRING_DATA_IN); + if (in == null) + throw new IllegalArgumentException("no input stream"); + char[] password = (char[]) attributes.get(KEYRING_PASSWORD); + if (password == null) + password = new char[0]; + + if (in.read() != Registry.GKR_MAGIC[0] + || in.read() != Registry.GKR_MAGIC[1] + || in.read() != Registry.GKR_MAGIC[2] + || in.read() != Registry.GKR_MAGIC[3]) + throw new MalformedKeyringException("magic"); + + load(in, password); + List l = keyring.getEntries(); + if (l.size() == 1 && (l.get(0) instanceof CompressedEntry)) + keyring2 = (CompressedEntry) l.get(0); + } + + public void store(Map attributes) throws IOException + { + OutputStream out = (OutputStream) attributes.get(KEYRING_DATA_OUT); + if (out == null) + throw new IllegalArgumentException("no output stream"); + char[] password = (char[]) attributes.get(KEYRING_PASSWORD); + if (password == null) + password = new char[0]; + if (keyring == null) + throw new IllegalStateException("empty keyring"); + + out.write(Registry.GKR_MAGIC); + store(out, password); + } + + public void reset() + { + keyring = null; + } + + public int size() + { + if (keyring == null) + throw new IllegalStateException("keyring not loaded"); + return ((StringTokenizer) aliases()).countTokens(); + } + + public Enumeration aliases() + { + if (keyring == null) + throw new IllegalStateException("keyring not loaded"); + return new StringTokenizer(keyring.getAliasList(), ";"); + } + + public boolean containsAlias(String alias) + { + if (keyring == null) + throw new IllegalStateException("keyring not loaded"); + return keyring.containsAlias(alias); + } + + public List get(String alias) + { + if (keyring == null) + throw new IllegalStateException("keyring not loaded"); + return keyring.get(alias); + } + + public void add(Entry entry) + { + if (keyring == null) + throw new IllegalStateException("keyring not loaded"); + if (keyring2 != null) + keyring2.add(entry); + else + keyring.add(entry); + } + + public void remove(String alias) + { + if (keyring == null) + throw new IllegalStateException("keyring not loaded"); + keyring.remove(alias); + } + + protected String fixAlias(String alias) + { + return alias.replace(';', '_'); + } + + protected abstract void load(InputStream in, char[] password) + throws IOException; + + protected abstract void store(OutputStream out, char[] password) + throws IOException; +} diff --git a/libjava/classpath/gnu/javax/crypto/keyring/BinaryDataEntry.java b/libjava/classpath/gnu/javax/crypto/keyring/BinaryDataEntry.java new file mode 100644 index 000000000..8fb1e0f39 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/keyring/BinaryDataEntry.java @@ -0,0 +1,111 @@ +/* BinaryDataEntry.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.keyring; + +import java.io.DataInputStream; +import java.io.IOException; +import java.util.Date; + +/** + * A binary data entry is a primitive entry that simply contains some amount of + * arbitrary binary data and an optional content type. + */ +public class BinaryDataEntry + extends PrimitiveEntry +{ + public static final int TYPE = 9; + + /** + * Creates a new binary data entry. + * + * @param contentType The content type of this entry. This parameter can be + * <code>null</code> if no content type is needed. + * @param data The data. + * @param creationDate The creation date. + * @param properties This entry's properties. + */ + public BinaryDataEntry(String contentType, byte[] data, Date creationDate, + Properties properties) + { + super(TYPE, creationDate, properties); + if (data == null) + throw new IllegalArgumentException("no data"); + payload = (byte[]) data.clone(); + if (contentType != null) + this.properties.put("content-type", contentType); + } + + private BinaryDataEntry() + { + super(TYPE); + } + + public static BinaryDataEntry decode(DataInputStream in) throws IOException + { + BinaryDataEntry entry = new BinaryDataEntry(); + entry.defaultDecode(in); + return entry; + } + + /** + * Returns the content type of this entry, or <code>null</code> if this + * property is not set. + * + * @return The content type. + */ + public String getContentType() + { + return properties.get("content-type"); + } + + /** + * Returns this object's data field. + * + * @return The data. + */ + public byte[] getData() + { + return getPayload(); + } + + protected void encodePayload() + { + // Empty. + } +} diff --git a/libjava/classpath/gnu/javax/crypto/keyring/CertPathEntry.java b/libjava/classpath/gnu/javax/crypto/keyring/CertPathEntry.java new file mode 100644 index 000000000..e798a93ce --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/keyring/CertPathEntry.java @@ -0,0 +1,112 @@ +/* CertPathEntry.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.keyring; + +import java.io.ByteArrayOutputStream; +import java.io.DataInputStream; +import java.io.IOException; +import java.security.cert.Certificate; +import java.security.cert.CertificateEncodingException; +import java.security.cert.CertificateException; +import java.security.cert.CertificateFactory; +import java.util.Date; + +/** + * A primitive entry that contains a path of X.509 certificates. + */ +public final class CertPathEntry + extends PrimitiveEntry +{ + public static final int TYPE = 8; + private Certificate[] path; + + public CertPathEntry(Certificate[] path, Date creationDate, + Properties properties) + { + super(TYPE, creationDate, properties); + if (path == null || path.length == 0) + throw new IllegalArgumentException("no certificate path"); + this.path = (Certificate[]) path.clone(); + } + + private CertPathEntry() + { + super(TYPE); + } + + public static CertPathEntry decode(DataInputStream in) throws IOException + { + CertPathEntry entry = new CertPathEntry(); + entry.properties.decode(in); + entry.makeCreationDate(); + int len = in.readInt(); + MeteredInputStream in2 = new MeteredInputStream(in, len); + try + { + CertificateFactory fact = CertificateFactory.getInstance("X.509"); + entry.path = (Certificate[]) fact.generateCertificates(in2).toArray(new Certificate[0]); + } + catch (CertificateException ce) + { + throw new MalformedKeyringException(ce.toString()); + } + return entry; + } + + public Certificate[] getCertPath() + { + return path; + } + + protected void encodePayload() throws IOException + { + ByteArrayOutputStream bout = new ByteArrayOutputStream(1024); + byte[] enc = null; + try + { + for (int i = 0; i < path.length; i++) + bout.write(path[i].getEncoded()); + } + catch (CertificateEncodingException cee) + { + throw new IOException(cee.toString()); + } + payload = bout.toByteArray(); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/keyring/CertificateEntry.java b/libjava/classpath/gnu/javax/crypto/keyring/CertificateEntry.java new file mode 100644 index 000000000..f574a4fe4 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/keyring/CertificateEntry.java @@ -0,0 +1,128 @@ +/* CertificateEntry.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.keyring; + +import java.io.DataInputStream; +import java.io.IOException; +import java.security.cert.Certificate; +import java.security.cert.CertificateEncodingException; +import java.security.cert.CertificateException; +import java.security.cert.CertificateFactory; +import java.util.Date; + +/** + * An immutable class representing a trusted certificate entry. + */ +public final class CertificateEntry + extends PrimitiveEntry +{ + public static final int TYPE = 5; + /** The certificate. */ + private Certificate certificate; + + /** + * Creates a new certificate entry. + * + * @param certificate The certificate. + * @param creationDate The creation date. + * @param properties The alias. + * @throws IllegalArgumentException If any argument is null, or if the alias + * is empty. + */ + public CertificateEntry(Certificate certificate, Date creationDate, + Properties properties) + { + super(TYPE, creationDate, properties); + if (certificate == null) + throw new IllegalArgumentException("no certificate"); + this.certificate = certificate; + this.properties.put("type", certificate.getType()); + } + + private CertificateEntry() + { + super(TYPE); + } + + public static CertificateEntry decode(DataInputStream in) throws IOException + { + CertificateEntry entry = new CertificateEntry(); + entry.properties.decode(in); + entry.makeCreationDate(); + String type = entry.properties.get("type"); + if (type == null) + throw new MalformedKeyringException("no certificate type"); + int len = in.readInt(); + MeteredInputStream in2 = new MeteredInputStream(in, len); + try + { + CertificateFactory fact = CertificateFactory.getInstance(type); + entry.certificate = fact.generateCertificate(in2); + } + catch (CertificateException ce) + { + throw new MalformedKeyringException(ce.toString()); + } + if (! in2.limitReached()) + throw new MalformedKeyringException("extra data at end of payload"); + return entry; + } + + /** + * Returns this entry's certificate. + * + * @return The certificate. + */ + public Certificate getCertificate() + { + return certificate; + } + + protected void encodePayload() throws IOException + { + try + { + payload = certificate.getEncoded(); + } + catch (CertificateEncodingException cee) + { + throw new IOException(cee.toString()); + } + } +} diff --git a/libjava/classpath/gnu/javax/crypto/keyring/CompressedEntry.java b/libjava/classpath/gnu/javax/crypto/keyring/CompressedEntry.java new file mode 100644 index 000000000..8949a41e9 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/keyring/CompressedEntry.java @@ -0,0 +1,93 @@ +/* CompressedEntry.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.keyring; + +import java.io.ByteArrayOutputStream; +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.util.Iterator; +import java.util.zip.DeflaterOutputStream; +import java.util.zip.InflaterInputStream; + +public class CompressedEntry + extends EnvelopeEntry +{ + public static final int TYPE = 4; + + public CompressedEntry(Properties properties) + { + super(TYPE, properties); + this.properties.put("algorithm", "DEFLATE"); + } + + private CompressedEntry() + { + this(new Properties()); + } + + public static CompressedEntry decode(DataInputStream in) throws IOException + { + CompressedEntry entry = new CompressedEntry(); + entry.properties.decode(in); + String alg = entry.properties.get("algorithm"); + if (alg == null) + throw new MalformedKeyringException("no compression algorithm"); + if (! alg.equalsIgnoreCase("DEFLATE")) + throw new MalformedKeyringException("unsupported compression algorithm: " + + alg); + int len = in.readInt(); + MeteredInputStream min = new MeteredInputStream(in, len); + InflaterInputStream infin = new InflaterInputStream(min); + DataInputStream in2 = new DataInputStream(infin); + entry.decodeEnvelope(in2); + return entry; + } + + protected void encodePayload() throws IOException + { + ByteArrayOutputStream buf = new ByteArrayOutputStream(1024); + DeflaterOutputStream dout = new DeflaterOutputStream(buf); + DataOutputStream out2 = new DataOutputStream(dout); + for (Iterator it = entries.iterator(); it.hasNext();) + ((Entry) it.next()).encode(out2); + dout.finish(); + payload = buf.toByteArray(); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/keyring/EncryptedEntry.java b/libjava/classpath/gnu/javax/crypto/keyring/EncryptedEntry.java new file mode 100644 index 000000000..68a6c2c8a --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/keyring/EncryptedEntry.java @@ -0,0 +1,191 @@ +/* EncryptedEntry.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.keyring; + +import gnu.java.security.Registry; +import gnu.javax.crypto.cipher.CipherFactory; +import gnu.javax.crypto.cipher.IBlockCipher; +import gnu.javax.crypto.mode.IMode; +import gnu.javax.crypto.mode.ModeFactory; +import gnu.javax.crypto.pad.IPad; +import gnu.javax.crypto.pad.PadFactory; +import gnu.javax.crypto.pad.WrongPaddingException; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.security.InvalidKeyException; +import java.util.HashMap; +import java.util.Iterator; + +public class EncryptedEntry extends MaskableEnvelopeEntry implements Registry +{ + public static final int TYPE = 0; + + public EncryptedEntry(String cipher, String mode, Properties properties) + { + super(TYPE, properties); + if (cipher == null || mode == null) + throw new IllegalArgumentException("neither cipher nor mode can be null"); + properties.put("cipher", cipher); + properties.put("mode", mode); + setMasked(false); + } + + private EncryptedEntry() + { + super(TYPE, new Properties()); + setMasked(true); + } + + public static EncryptedEntry decode(DataInputStream in) throws IOException + { + EncryptedEntry entry = new EncryptedEntry(); + entry.defaultDecode(in); + if (! entry.properties.containsKey("cipher")) + throw new MalformedKeyringException("no cipher"); + if (! entry.properties.containsKey("cipher")) + throw new MalformedKeyringException("no cipher"); + return entry; + } + + public void decrypt(byte[] key, byte[] iv) throws IllegalArgumentException, + WrongPaddingException + { + if (! isMasked() || payload == null) + return; + IMode mode = getMode(key, iv, IMode.DECRYPTION); + IPad padding = null; + padding = PadFactory.getInstance("PKCS7"); + padding.init(mode.currentBlockSize()); + byte[] buf = new byte[payload.length]; + int count = 0; + for (int i = 0; i < payload.length; i++) + { + mode.update(payload, count, buf, count); + count += mode.currentBlockSize(); + } + int padlen = padding.unpad(buf, 0, buf.length); + int len = buf.length - padlen; + DataInputStream in = new DataInputStream(new ByteArrayInputStream(buf, 0, len)); + try + { + decodeEnvelope(in); + } + catch (IOException ioe) + { + throw new IllegalArgumentException("decryption failed"); + } + setMasked(false); + payload = null; + } + + public void encrypt(byte[] key, byte[] iv) throws IOException + { + IMode mode = getMode(key, iv, IMode.ENCRYPTION); + IPad pad = PadFactory.getInstance("PKCS7"); + pad.init(mode.currentBlockSize()); + ByteArrayOutputStream bout = new ByteArrayOutputStream(1024); + DataOutputStream out2 = new DataOutputStream(bout); + for (Iterator it = entries.iterator(); it.hasNext();) + { + Entry entry = (Entry) it.next(); + entry.encode(out2); + } + byte[] plaintext = bout.toByteArray(); + byte[] padding = pad.pad(plaintext, 0, plaintext.length); + payload = new byte[plaintext.length + padding.length]; + byte[] lastBlock = new byte[mode.currentBlockSize()]; + int l = mode.currentBlockSize() - padding.length; + System.arraycopy(plaintext, plaintext.length - l, lastBlock, 0, l); + System.arraycopy(padding, 0, lastBlock, l, padding.length); + int count = 0; + while (count + mode.currentBlockSize() < plaintext.length) + { + mode.update(plaintext, count, payload, count); + count += mode.currentBlockSize(); + } + mode.update(lastBlock, 0, payload, count); + } + + public void encodePayload() throws IOException + { + if (payload == null) + throw new IOException("not encrypted"); + } + + private IMode getMode(byte[] key, byte[] iv, int state) + { + IBlockCipher cipher = CipherFactory.getInstance(properties.get("cipher")); + if (cipher == null) + throw new IllegalArgumentException("no such cipher: " + properties.get("cipher")); + int blockSize = cipher.defaultBlockSize(); + if (properties.containsKey("block-size")) + { + try + { + blockSize = Integer.parseInt(properties.get("block-size")); + } + catch (NumberFormatException nfe) + { + throw new IllegalArgumentException("bad block size: " + + nfe.getMessage()); + } + } + IMode mode = ModeFactory.getInstance(properties.get("mode"), cipher, blockSize); + if (mode == null) + throw new IllegalArgumentException("no such mode: " + properties.get("mode")); + + HashMap modeAttr = new HashMap(); + modeAttr.put(IMode.KEY_MATERIAL, key); + modeAttr.put(IMode.STATE, Integer.valueOf(state)); + modeAttr.put(IMode.IV, iv); + try + { + mode.init(modeAttr); + } + catch (InvalidKeyException ike) + { + throw new IllegalArgumentException(ike.toString()); + } + return mode; + } +} diff --git a/libjava/classpath/gnu/javax/crypto/keyring/Entry.java b/libjava/classpath/gnu/javax/crypto/keyring/Entry.java new file mode 100644 index 000000000..d45924940 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/keyring/Entry.java @@ -0,0 +1,179 @@ +/* Entry.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.keyring; + +import gnu.java.security.Configuration; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.util.logging.Logger; + +/** + * An immutable class representing a single entry in a keyring. + */ +public abstract class Entry +{ + private static final Logger log = Logger.getLogger(Entry.class.getName()); + private static final String[] TYPES = new String[] { + "Encrypted", + "PasswordEncrypted", + "Authenticated", + "PasswordAuthenticated", + "Compressed", + "Certificate", + "PublicKey", + "PrivateKey", + "CertPath", + "BinaryData" }; + /** This entry's type identifier. */ + protected int type; + /** This entry's property set. */ + protected Properties properties; + /** This entry's payload. */ + protected byte[] payload; + + /** + * Creates a new Entry. + * + * @param type This entry's type. + * @param properties This entry's properties. + * @throws IllegalArgumentException If the properties argument is null, or if + * the type is out of range. + */ + protected Entry(int type, Properties properties) + { + if (type < 0 || type > 255) + throw new IllegalArgumentException("invalid packet type"); + if (properties == null) + throw new IllegalArgumentException("no properties"); + this.type = type; + this.properties = (Properties) properties.clone(); + } + + /** + * Constructor for use by subclasses. + */ + protected Entry(final int type) + { + if (type < 0 || type > 255) + throw new IllegalArgumentException("invalid packet type"); + this.type = type; + properties = new Properties(); + } + + /** + * Returns this entry's properties object. The properties are cloned before + * being returned. + * + * @return The properties. + */ + public Properties getProperties() + { + return (Properties) properties.clone(); + } + + /** + * Returns this entry's payload data, or null if + */ + public byte[] getPayload() + { + if (payload == null) + return null; + return (byte[]) payload.clone(); + } + + /** + * This method is called when this entry needs to be written to an output + * stream. + * + * @param out The stream to write to. + * @throws IOException If an I/O exception occurs. + */ + public void encode(DataOutputStream out) throws IOException + { + if (payload == null) + encodePayload(); + if (out == null) + return; + out.write(type); + properties.encode(out); + out.writeInt(payload.length); + out.write(payload); + } + + public String toString() + { + return new StringBuilder("Entry{") + .append("type=").append(TYPES[type]) + .append(", properties=").append(properties) + .append(", payload=") + .append(payload == null ? "-" : "byte[" + payload.length + "]") + .append( "}") + .toString(); + } + + /** + * Generic decoding method, which simply decodes the properties field + * and reads the payload field. + * + * @param in The input data stream. + * @throws IOException If an I/O error occurs. + */ + protected void defaultDecode(DataInputStream in) throws IOException + { + properties = new Properties(); + properties.decode(in); + int len = in.readInt(); + if (len < 0) + throw new IOException("corrupt length"); + if (Configuration.DEBUG) + log.fine("About to instantiate new payload byte array for " + this); + payload = new byte[len]; + in.readFully(payload); + } + + /** + * This method is called of subclasses when the payload data needs to be + * created. + * + * @throws IOException If an encoding error occurs. + */ + protected abstract void encodePayload() throws IOException; +} diff --git a/libjava/classpath/gnu/javax/crypto/keyring/EnvelopeEntry.java b/libjava/classpath/gnu/javax/crypto/keyring/EnvelopeEntry.java new file mode 100644 index 000000000..76aba7d7b --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/keyring/EnvelopeEntry.java @@ -0,0 +1,439 @@ +/* EnvelopeEntry.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.keyring; + +import gnu.java.security.Configuration; + +import java.io.ByteArrayOutputStream; +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.StringTokenizer; +import java.util.logging.Logger; + +/** + * An envelope entry is a generic container for some number of primitive and + * other envelope entries. + */ +public abstract class EnvelopeEntry + extends Entry +{ + private static final Logger log = Logger.getLogger(EnvelopeEntry.class.getName()); + /** The envelope that contains this one (if any). */ + protected EnvelopeEntry containingEnvelope; + /** The contained entries. */ + protected List entries; + + public EnvelopeEntry(int type, Properties properties) + { + super(type, properties); + entries = new LinkedList(); + if (this.properties.get("alias-list") != null) + this.properties.remove("alias-list"); + } + + protected EnvelopeEntry(int type) + { + super(type); + entries = new LinkedList(); + } + + /** + * Adds an entry to this envelope. + * + * @param entry The entry to add. + */ + public void add(Entry entry) + { + if (Configuration.DEBUG) + log.entering(this.getClass().getName(), "add", entry); + if (! containsEntry(entry)) + { + if (entry instanceof EnvelopeEntry) + ((EnvelopeEntry) entry).setContainingEnvelope(this); + entries.add(entry); + if (Configuration.DEBUG) + log.fine("Payload is " + (payload == null ? "" : "not ") + "null"); + makeAliasList(); + } + if (Configuration.DEBUG) + log.exiting(this.getClass().getName(), "add"); + } + + /** + * Tests if this envelope contains a primitive entry with the given alias. + * + * @param alias The alias to test. + * @return True if this envelope (or one of the contained envelopes) contains + * a primitive entry with the given alias. + */ + public boolean containsAlias(String alias) + { + if (Configuration.DEBUG) + log.entering(this.getClass().getName(), "containsAlias", alias); + String aliases = getAliasList(); + if (Configuration.DEBUG) + log.fine("aliases = [" + aliases + "]"); + boolean result = false; + if (aliases != null) + { + StringTokenizer tok = new StringTokenizer(aliases, ";"); + while (tok.hasMoreTokens()) + if (tok.nextToken().equals(alias)) + { + result = true; + break; + } + } + if (Configuration.DEBUG) + log.exiting(this.getClass().getName(), "containsAlias", + Boolean.valueOf(result)); + return result; + } + + /** + * Tests if this envelope contains the given entry. + * + * @param entry The entry to test. + * @return True if this envelope contains the given entry. + */ + public boolean containsEntry(Entry entry) + { + if (entry instanceof EnvelopeEntry) + return entries.contains(entry); + if (entry instanceof PrimitiveEntry) + for (Iterator it = entries.iterator(); it.hasNext();) + { + Entry e = (Entry) it.next(); + if (e.equals(entry)) + return true; + if ((e instanceof EnvelopeEntry) + && ((EnvelopeEntry) e).containsEntry(entry)) + return true; + } + return false; + } + + /** + * Returns a copy of all entries this envelope contains. + * + * @return All contained entries. + */ + public List getEntries() + { + return new ArrayList(entries); + } + + /** + * Gets all primitive entries that have the given alias. If there are any + * masked entries that contain the given alias, they will be returned as well. + * + * @param alias The alias of the entries to get. + * @return A list of all primitive entries that have the given alias. + */ + public List get(String alias) + { + if (Configuration.DEBUG) + log.entering(this.getClass().getName(), "get", alias); + List result = new LinkedList(); + for (Iterator it = entries.iterator(); it.hasNext();) + { + Entry e = (Entry) it.next(); + if (e instanceof EnvelopeEntry) + { + EnvelopeEntry ee = (EnvelopeEntry) e; + if (! ee.containsAlias(alias)) + continue; + if (ee instanceof MaskableEnvelopeEntry) + { + MaskableEnvelopeEntry mee = (MaskableEnvelopeEntry) ee; + if (mee.isMasked()) + { + if (Configuration.DEBUG) + log.fine("Processing masked entry: " + mee); + result.add(mee); + continue; + } + } + if (Configuration.DEBUG) + log.fine("Processing unmasked entry: " + ee); + result.addAll(ee.get(alias)); + } + else if (e instanceof PrimitiveEntry) + { + PrimitiveEntry pe = (PrimitiveEntry) e; + if (pe.getAlias().equals(alias)) + result.add(e); + } + } + if (Configuration.DEBUG) + log.exiting(this.getClass().getName(), "get", result); + return result; + } + + /** + * Returns the list of all aliases contained by this envelope, separated by a + * semicolon (';'). + * + * @return The list of aliases. + */ + public String getAliasList() + { + String list = properties.get("alias-list"); + if (list == null) + return ""; + else + return list; + } + + /** + * Removes the specified entry. + * + * @param entry The entry. + * @return True if an entry was removed. + */ + public boolean remove(Entry entry) + { + if (Configuration.DEBUG) + log.entering(this.getClass().getName(), "remove", entry); + boolean ret = false; + for (Iterator it = entries.iterator(); it.hasNext();) + { + Entry e = (Entry) it.next(); + if (e instanceof EnvelopeEntry) + { + if (e == entry) + { + it.remove(); + ret = true; + break; + } + if (((EnvelopeEntry) e).remove(entry)) + { + ret = true; + break; + } + } + else if (e instanceof PrimitiveEntry) + { + if (((PrimitiveEntry) e).equals(entry)) + { + it.remove(); + ret = true; + break; + } + } + } + if (ret) + { + if (Configuration.DEBUG) + log.fine("State before: " + this); + payload = null; + makeAliasList(); + if (Configuration.DEBUG) + log.fine("State after: " + this); + } + if (Configuration.DEBUG) + log.exiting(this.getClass().getName(), "remove", Boolean.valueOf(ret)); + return ret; + } + + /** + * Removes all primitive entries that have the specified alias. + * + * @param alias The alias of the entries to remove. + * @return <code>true</code> if <code>alias</code> was present and was + * successfully trmoved. Returns <code>false</code> if + * <code>alias</code> was not present in the list of aliases in this + * envelope. + */ + public boolean remove(String alias) + { + if (Configuration.DEBUG) + log.entering(this.getClass().getName(), "remove", alias); + boolean result = false; + for (Iterator it = entries.iterator(); it.hasNext();) + { + Entry e = (Entry) it.next(); + if (e instanceof EnvelopeEntry) + { + EnvelopeEntry ee = (EnvelopeEntry) e; + result = ee.remove(alias) || result; + } + else if (e instanceof PrimitiveEntry) + { + PrimitiveEntry pe = (PrimitiveEntry) e; + if (pe.getAlias().equals(alias)) + { + it.remove(); + result = true; + } + } + } + if (result) + { + if (Configuration.DEBUG) + log.fine("State before: " + this); + payload = null; + makeAliasList(); + if (Configuration.DEBUG) + log.fine("State after: " + this); + } + if (Configuration.DEBUG) + log.exiting(this.getClass().getName(), "remove", Boolean.valueOf(result)); + return result; + } + + public String toString() + { + return new StringBuilder("Envelope{") + .append(super.toString()) + .append(", entries=").append(entries) + .append("}") + .toString(); + } + + // Protected methods. + // ------------------------------------------------------------------------ + + protected void encodePayload() throws IOException + { + ByteArrayOutputStream bout = new ByteArrayOutputStream(1024); + DataOutputStream out = new DataOutputStream(bout); + for (Iterator it = entries.iterator(); it.hasNext();) + ((Entry) it.next()).encode(out); + } + + protected void setContainingEnvelope(EnvelopeEntry e) + { + if (containingEnvelope != null) + throw new IllegalArgumentException("envelopes may not be shared"); + containingEnvelope = e; + } + + protected void decodeEnvelope(DataInputStream in) throws IOException + { + this.entries.clear(); + while (true) + { + int type = in.read(); + switch (type) + { + case EncryptedEntry.TYPE: + add(EncryptedEntry.decode(in)); + break; + case PasswordEncryptedEntry.TYPE: + add(PasswordEncryptedEntry.decode(in)); + break; + case PasswordAuthenticatedEntry.TYPE: + add(PasswordAuthenticatedEntry.decode(in)); + break; + case AuthenticatedEntry.TYPE: + add(AuthenticatedEntry.decode(in)); + break; + case CompressedEntry.TYPE: + add(CompressedEntry.decode(in)); + break; + case CertificateEntry.TYPE: + add(CertificateEntry.decode(in)); + break; + case PublicKeyEntry.TYPE: + add(PublicKeyEntry.decode(in)); + break; + case PrivateKeyEntry.TYPE: + add(PrivateKeyEntry.decode(in)); + break; + case CertPathEntry.TYPE: + add(CertPathEntry.decode(in)); + break; + case BinaryDataEntry.TYPE: + add(BinaryDataEntry.decode(in)); + break; + case -1: + return; + default: + throw new MalformedKeyringException("unknown type " + type); + } + } + } + + private void makeAliasList() + { + if (Configuration.DEBUG) + log.entering(this.getClass().getName(), "makeAliasList"); + if (! entries.isEmpty()) + { + StringBuilder buf = new StringBuilder(); + String aliasOrList; + for (Iterator it = entries.iterator(); it.hasNext();) + { + Entry entry = (Entry) it.next(); + aliasOrList = null; + if (entry instanceof EnvelopeEntry) + aliasOrList = ((EnvelopeEntry) entry).getAliasList(); + else if (entry instanceof PrimitiveEntry) + aliasOrList = ((PrimitiveEntry) entry).getAlias(); + else if (Configuration.DEBUG) + log.fine("Entry with no Alias. Ignored: " + entry); + if (aliasOrList != null) + { + aliasOrList = aliasOrList.trim(); + if (aliasOrList.trim().length() > 0) + { + buf.append(aliasOrList); + if (it.hasNext()) + buf.append(';'); + } + } + } + String aliasList = buf.toString(); + properties.put("alias-list", aliasList); + if (Configuration.DEBUG) + log.fine("alias-list=[" + aliasList + "]"); + if (containingEnvelope != null) + containingEnvelope.makeAliasList(); + } + if (Configuration.DEBUG) + log.exiting(this.getClass().getName(), "makeAliasList"); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/keyring/GnuPrivateKeyring.java b/libjava/classpath/gnu/javax/crypto/keyring/GnuPrivateKeyring.java new file mode 100644 index 000000000..ab3933972 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/keyring/GnuPrivateKeyring.java @@ -0,0 +1,368 @@ +/* GnuPrivateKeyring.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.keyring; + +import gnu.java.security.Configuration; +import gnu.java.security.Registry; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.security.Key; +import java.security.PublicKey; +import java.security.UnrecoverableKeyException; +import java.security.cert.Certificate; +import java.util.Date; +import java.util.Iterator; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * + */ +public class GnuPrivateKeyring + extends BaseKeyring + implements IPrivateKeyring +{ + private static final Logger log = Logger.getLogger(GnuPrivateKeyring.class.getName()); + public static final int USAGE = Registry.GKR_PRIVATE_KEYS + | Registry.GKR_PUBLIC_CREDENTIALS; + protected String mac; + protected int maclen; + protected String cipher; + protected String mode; + protected int keylen; + + public GnuPrivateKeyring(String mac, int maclen, String cipher, String mode, + int keylen) + { + keyring = new PasswordAuthenticatedEntry(mac, maclen, new Properties()); + keyring2 = new CompressedEntry(new Properties()); + keyring.add(keyring2); + this.mac = mac; + this.maclen = maclen; + this.cipher = cipher; + this.mode = mode; + this.keylen = keylen; + } + + public GnuPrivateKeyring() + { + this("HMAC-SHA-1", 20, "AES", "OFB", 16); + } + + public boolean containsPrivateKey(String alias) + { + if (Configuration.DEBUG) + log.entering(this.getClass().getName(), "containsPrivateKey", alias); + boolean result = false; + if (containsAlias(alias)) + for (Iterator it = get(alias).iterator(); it.hasNext();) + if (it.next() instanceof PasswordAuthenticatedEntry) + { + result = true; + break; + } + if (Configuration.DEBUG) + log.exiting(this.getClass().getName(), "containsPrivateKey", + Boolean.valueOf(result)); + return result; + } + + public Key getPrivateKey(String alias, char[] password) + throws UnrecoverableKeyException + { + if (Configuration.DEBUG) + log.entering(this.getClass().getName(), "getPrivateKey", alias); + Key result = null; + if (containsAlias(alias)) + { + PasswordAuthenticatedEntry e1 = null; + for (Iterator it = get(alias).iterator(); it.hasNext();) + { + Entry e = (Entry) it.next(); + if (Configuration.DEBUG) + log.finest("Entry: " + e); + if (e instanceof PasswordAuthenticatedEntry) + { + e1 = (PasswordAuthenticatedEntry) e; + break; + } + } + if (Configuration.DEBUG) + log.fine("e1 = " + e1); + if (e1 != null) + { + try + { + e1.verify(password); + } + catch (Exception e) + { + if (Configuration.DEBUG) + log.throwing(this.getClass().getName(), "getPrivateKey", e); + throw new UnrecoverableKeyException("authentication failed"); + } + PasswordEncryptedEntry e2 = null; + for (Iterator it = e1.getEntries().iterator(); it.hasNext();) + { + Entry e = (Entry) it.next(); + if (e instanceof PasswordEncryptedEntry) + { + e2 = (PasswordEncryptedEntry) e; + break; + } + } + if (e2 != null) + { + try + { + e2.decrypt(password); + } + catch (Exception e) + { + log.throwing(this.getClass().getName(), "getPrivateKey", e); + throw new UnrecoverableKeyException("decryption failed"); + } + for (Iterator it = e2.get(alias).iterator(); it.hasNext();) + { + Entry e = (Entry) it.next(); + if (e instanceof PrivateKeyEntry) + { + result = ((PrivateKeyEntry) e).getKey(); + break; + } + } + } + } + } + if (Configuration.DEBUG) + log.exiting(this.getClass().getName(), "getPrivateKey", + result == null ? "null" : result.getClass().getName()); + return result; + } + + public void putPrivateKey(String alias, Key key, char[] password) + { + if (Configuration.DEBUG) + log.entering(this.getClass().getName(), "putPrivateKey", + new Object[] { alias, key.getClass().getName() }); + if (! containsPrivateKey(alias)) + { + alias = fixAlias(alias); + Properties p = new Properties(); + p.put("alias", alias); + PrivateKeyEntry pke = new PrivateKeyEntry(key, new Date(), p); + if (Configuration.DEBUG) + log.fine("About to encrypt the key..."); + PasswordEncryptedEntry enc; + enc = new PasswordEncryptedEntry(cipher, mode, keylen, new Properties()); + enc.add(pke); + try + { + enc.encode(null, password); + } + catch (IOException x) + { + if (Configuration.DEBUG) + log.log(Level.FINE, "Exception while encrypting the key. " + + "Rethrow as IllegalArgumentException", x); + throw new IllegalArgumentException(x.toString()); + } + if (Configuration.DEBUG) + log.fine("About to authenticate the encrypted key..."); + PasswordAuthenticatedEntry auth; + auth = new PasswordAuthenticatedEntry(mac, maclen, new Properties()); + auth.add(enc); + try + { + auth.encode(null, password); + } + catch (IOException x) + { + if (Configuration.DEBUG) + log.log(Level.FINE, "Exception while authenticating the encrypted " + + "key. Rethrow as IllegalArgumentException", x); + throw new IllegalArgumentException(x.toString()); + } + keyring.add(auth); + } + else if (Configuration.DEBUG) + log.fine("Keyring already contains alias: " + alias); + if (Configuration.DEBUG) + log.exiting(this.getClass().getName(), "putPrivateKey"); + } + + public boolean containsPublicKey(String alias) + { + if (Configuration.DEBUG) + log.entering(this.getClass().getName(), "containsPublicKey", alias); + boolean result = false; + if (containsAlias(alias)) + for (Iterator it = get(alias).iterator(); it.hasNext();) + if (it.next() instanceof PublicKeyEntry) + { + result = true; + break; + } + if (Configuration.DEBUG) + log.exiting(this.getClass().getName(), "containsPublicKey", + Boolean.valueOf(result)); + return result; + } + + public PublicKey getPublicKey(String alias) + { + if (Configuration.DEBUG) + log.entering(this.getClass().getName(), "getPublicKey", alias); + PublicKey result = null; + if (containsAlias(alias)) + for (Iterator it = get(alias).iterator(); it.hasNext();) + { + Entry e = (Entry) it.next(); + if (e instanceof PublicKeyEntry) + { + result = ((PublicKeyEntry) e).getKey(); + break; + } + } + if (Configuration.DEBUG) + log.exiting(this.getClass().getName(), "getPublicKey", + result == null ? "null" : result.getClass().getName()); + return result; + } + + public void putPublicKey(String alias, PublicKey key) + { + if (Configuration.DEBUG) + log.entering(this.getClass().getName(), "putPublicKey", + new Object[] { alias, key.getClass().getName() }); + if (! containsPublicKey(alias)) + { + Properties p = new Properties(); + p.put("alias", fixAlias(alias)); + add(new PublicKeyEntry(key, new Date(), p)); + } + else if (Configuration.DEBUG) + log.fine("Keyring already contains alias: " + alias); + if (Configuration.DEBUG) + log.exiting(this.getClass().getName(), "putPublicKey"); + } + + public boolean containsCertPath(String alias) + { + if (Configuration.DEBUG) + log.entering(this.getClass().getName(), "containsCertPath", alias); + boolean result = false; + if (containsAlias(alias)) + for (Iterator it = get(alias).iterator(); it.hasNext();) + if (it.next() instanceof CertPathEntry) + { + result = true; + break; + } + if (Configuration.DEBUG) + log.exiting(this.getClass().getName(), "containsCertPath", + Boolean.valueOf(result)); + return result; + } + + public Certificate[] getCertPath(String alias) + { + if (Configuration.DEBUG) + log.entering(this.getClass().getName(), "getCertPath", alias); + Certificate[] result = null; + if (containsAlias(alias)) + for (Iterator it = get(alias).iterator(); it.hasNext();) + { + Entry e = (Entry) it.next(); + if (e instanceof CertPathEntry) + { + result = ((CertPathEntry) e).getCertPath(); + break; + } + } + if (Configuration.DEBUG) + log.exiting(this.getClass().getName(), "getCertPath", result); + return result; + } + + public void putCertPath(String alias, Certificate[] path) + { + if (Configuration.DEBUG) + log.entering(this.getClass().getName(), "putCertPath", + new Object[] { alias, path }); + if (! containsCertPath(alias)) + { + Properties p = new Properties(); + p.put("alias", fixAlias(alias)); + add(new CertPathEntry(path, new Date(), p)); + } + else if (Configuration.DEBUG) + log.fine("Keyring already contains alias: " + alias); + if (Configuration.DEBUG) + log.exiting(this.getClass().getName(), "putCertPath"); + } + + protected void load(InputStream in, char[] password) throws IOException + { + if (Configuration.DEBUG) + log.entering(this.getClass().getName(), "load"); + if (in.read() != USAGE) + throw new MalformedKeyringException("incompatible keyring usage"); + if (in.read() != PasswordAuthenticatedEntry.TYPE) + throw new MalformedKeyringException( + "expecting password-authenticated entry tag"); + keyring = PasswordAuthenticatedEntry.decode(new DataInputStream(in), password); + if (Configuration.DEBUG) + log.exiting(this.getClass().getName(), "load"); + } + + protected void store(OutputStream out, char[] password) throws IOException + { + if (Configuration.DEBUG) + log.entering(this.getClass().getName(), "store"); + out.write(USAGE); + keyring.encode(new DataOutputStream(out), password); + if (Configuration.DEBUG) + log.exiting(this.getClass().getName(), "store"); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/keyring/GnuPublicKeyring.java b/libjava/classpath/gnu/javax/crypto/keyring/GnuPublicKeyring.java new file mode 100644 index 000000000..d7387f892 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/keyring/GnuPublicKeyring.java @@ -0,0 +1,151 @@ +/* GnuPublicKeyring.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.keyring; + +import gnu.java.security.Configuration; +import gnu.java.security.Registry; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.security.cert.Certificate; +import java.util.Date; +import java.util.Iterator; +import java.util.logging.Logger; + +public class GnuPublicKeyring + extends BaseKeyring + implements IPublicKeyring +{ + private static final Logger log = Logger.getLogger(GnuPublicKeyring.class.getName()); + public static final int USAGE = Registry.GKR_CERTIFICATES; + + public GnuPublicKeyring(String mac, int macLen) + { + keyring = new PasswordAuthenticatedEntry(mac, macLen, new Properties()); + keyring2 = new CompressedEntry(new Properties()); + keyring.add(keyring2); + } + + public GnuPublicKeyring() + { + } + + public boolean containsCertificate(String alias) + { + if (Configuration.DEBUG) + log.entering(this.getClass().getName(), "containsCertificate", alias); + boolean result = false; + if (containsAlias(alias)) + for (Iterator it = get(alias).iterator(); it.hasNext();) + if (it.next() instanceof CertificateEntry) + { + result = true; + break; + } + if (Configuration.DEBUG) + log.exiting(this.getClass().getName(), "containsCertificate", + Boolean.valueOf(result)); + return result; + } + + public Certificate getCertificate(String alias) + { + if (Configuration.DEBUG) + log.entering(this.getClass().getName(), "getCertificate", alias); + Certificate result = null; + if (containsAlias(alias)) + for (Iterator it = get(alias).iterator(); it.hasNext();) + { + Entry e = (Entry) it.next(); + if (e instanceof CertificateEntry) + { + result = ((CertificateEntry) e).getCertificate(); + break; + } + } + if (Configuration.DEBUG) + log.exiting(this.getClass().getName(), "getCertificate", result); + return result; + } + + public void putCertificate(String alias, Certificate cert) + { + if (Configuration.DEBUG) + log.entering(this.getClass().getName(), "putCertificate", + new Object[] { alias, cert }); + if (! containsCertificate(alias)) + { + Properties p = new Properties(); + p.put("alias", fixAlias(alias)); + add(new CertificateEntry(cert, new Date(), p)); + } + else if (Configuration.DEBUG) + log.fine("Keyring already contains alias: " + alias); + if (Configuration.DEBUG) + log.exiting(this.getClass().getName(), "putCertificate"); + } + + protected void load(InputStream in, char[] password) throws IOException + { + if (Configuration.DEBUG) + log.entering(this.getClass().getName(), "load"); + if (in.read() != USAGE) + throw new MalformedKeyringException("incompatible keyring usage"); + if (in.read() != PasswordAuthenticatedEntry.TYPE) + throw new MalformedKeyringException( + "expecting password-authenticated entry tag"); + DataInputStream dis = new DataInputStream(in); + keyring = PasswordAuthenticatedEntry.decode(dis, password); + if (Configuration.DEBUG) + log.exiting(this.getClass().getName(), "load"); + } + + protected void store(OutputStream out, char[] password) throws IOException + { + if (Configuration.DEBUG) + log.entering(this.getClass().getName(), "store"); + out.write(USAGE); + keyring.encode(new DataOutputStream(out), password); + if (Configuration.DEBUG) + log.exiting(this.getClass().getName(), "store"); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/keyring/IKeyring.java b/libjava/classpath/gnu/javax/crypto/keyring/IKeyring.java new file mode 100644 index 000000000..141f2dcd4 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/keyring/IKeyring.java @@ -0,0 +1,162 @@ +/* IKeyring.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.keyring; + +import java.io.IOException; +import java.util.Enumeration; +import java.util.List; +import java.util.Map; + +/** + * The top-level interface to a <i>keyring:</i> a file that is used to store + * and protect public and private cryptographic keys. + * <p> + * A <i>keyring</i> is modelled as a mapping of one <i>alias</i> to one or + * more <i>entries</i> (optionally of different types). + * <p> + * See also the sub-interfaces {@link IPublicKeyring} and + * {@link IPrivateKeyring} for special types of <i>keyrings</i> --the + * difference being in the type of entries they contain. + */ +public interface IKeyring +{ + /** + * Property name for the source of data to load the keyring from. The value + * mapped must be a {@link java.io.InputStream}. + */ + public static final String KEYRING_DATA_IN = "gnu.crypto.keyring.data.in"; + + /** + * Property name for the data sink to store the keyring to. The value mapped + * must be a {@link java.io.OutputStream}. + */ + public static final String KEYRING_DATA_OUT = "gun.crypto.keyring.data.out"; + + /** + * Property name for the keyring's top-level password, used to authenticate + * and/or transform the store itself. The mapped value must be a char array. + */ + public static final String KEYRING_PASSWORD = "gnu.crypto.keyring.password"; + + /** + * Loads a keyring into memory. + * <p> + * What happens to the current contents of this keyring? are the new ones + * merged with the current ones or do they simply replace them? + * + * @param attributes The attributes that designate the source where the store + * is to be loaded from. What happens + * @throws IllegalArgumentException If the attributes are inappropriate. + * @throws IOException If the keyring file cannot be read. + * @throws SecurityException If the given password is incorrect, or if the + * top-level authentication or decryption fails. + */ + void load(Map attributes) throws IOException; + + /** + * Stores the contents of this keyring to persistent storage as specified by + * the designated <code>attributes</code>. + * + * @param attributes the attributes that define where the contents of this + * keyring will be stored. + * @throws IOException if an exception occurs during the process. + */ + void store(Map attributes) throws IOException; + + /** + * Resets this keyring, clearing all sensitive data. This method always + * suceeds. + */ + void reset(); + + /** + * Returns the number of entries in this keyring. + * + * @return The number of current entries in this keyring. + */ + int size(); + + /** + * Returns an {@link Enumeration} of all aliases (instances of {@link String}) + * in this keyring. + * + * @return The enumeration of {@link String}s each representing an <i>alias</i> + * found in this keyring. + */ + Enumeration aliases(); + + /** + * Tests whether or not this keyring contains the given alias. + * + * @param alias The alias to check. + * @return true if this keyring contains the alias. + */ + boolean containsAlias(String alias); + + /** + * Returns a {@link List} of entries (instances of {@link Entry}) for the + * given <code>alias</code>, or <code>null</code> if there no such entry + * exists. + * + * @param alias The alias of the entry(ies) to return. + * @return A list of all entries (instances of {@link Entry} that have the + * given <code>alias</code>, or <code>null</code> if no one + * {@link Entry} can be found with the designated <code>alias</code>. + */ + List get(String alias); + + /** + * Adds a designated {@link Entry} to this keyring. + * <p> + * What happens if there is already an entry with the same alias? + * + * @param entry The entry to put in this keyring. + */ + void add(Entry entry); + + /** + * Removes an entry with the designated <code>alias</code> from this + * keyring. Does nothing if there was no such entry. + * <p> + * What happens if there are more than one? + * + * @param alias The alias of the entry to remove. + */ + void remove(String alias); +} diff --git a/libjava/classpath/gnu/javax/crypto/keyring/IPrivateKeyring.java b/libjava/classpath/gnu/javax/crypto/keyring/IPrivateKeyring.java new file mode 100644 index 000000000..3bfa10098 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/keyring/IPrivateKeyring.java @@ -0,0 +1,144 @@ +/* IPrivateKeyring.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.keyring; + +import java.security.Key; +import java.security.PublicKey; +import java.security.UnrecoverableKeyException; +import java.security.cert.Certificate; + +/** + * An interface to private, or "personal", keyrings, which contain private + * credentials. The contract is that each such entry is known by a unique + * <i>alias</i>. + * <p> + * What about public keys? and certificate-path? + */ +public interface IPrivateKeyring + extends IKeyring +{ + /** + * Tests if this keyring contains a private key entry with the given + * <code>alias</code>. + * + * @param alias The alias to check. + * @return <code>true</code> if this keyring contains a private key with the + * given <code>alias</code>; <code>false</code> otherwise. + */ + boolean containsPrivateKey(String alias); + + /** + * Returns the private key with the given <code>alias</code>. + * + * @param alias The alias of the private key to find. + * @param password The password of the private key. + * @return The private, or secret, key if one is found; <code>null</code> if + * none were found. + * @throws UnrecoverableKeyException If the private key could not be + * recovered, possibly due to a bad password. + */ + Key getPrivateKey(String alias, char[] password) + throws UnrecoverableKeyException; + + /** + * Adds a private key to this keyring. + * + * @param alias The alias of the private key. + * @param key The private key. + * @param password The password used to protect this private key. + */ + void putPrivateKey(String alias, Key key, char[] password); + + /** + * Checks if this keyring contains a public key with the given + * <code>alias</code>. + * + * @param alias The alias to test. + * @return <code>true</code> if this keyring contains a public key entry + * with the given <code>alias</code>; <code>false</code> + * otherwise. + */ + boolean containsPublicKey(String alias); + + /** + * Returns the public key with the given <code>alias</code>, or + * <code>null</code> if there is no such entry. + * + * @param alias The alias of the public key to find. + * @return The public key; or <code>null</code> if none were found. + */ + PublicKey getPublicKey(String alias); + + /** + * Sets a public key entry. + * + * @param alias The alias for this public key. + * @param key The public key. + */ + void putPublicKey(String alias, PublicKey key); + + /** + * Checks if this keyring contains a certificate path with the given + * <code>alias</code>. + * + * @param alias The alias to check. + * @return <code>true</code> if this keyring contains a certificate path + * with the given <code>alias</code>; <code>false</code> + * otherwise. + */ + boolean containsCertPath(String alias); + + /** + * Returns the certificate path with the given <code>alias</code>, or + * <code>null</code> if there is no such entry. + * + * @param alias The alias of the certificate path to find. + * @return The certificate path for the designated <code>alias</code>; or + * <code>null</code> if none were found. + */ + Certificate[] getCertPath(String alias); + + /** + * Sets a certificate path entry. + * + * @param alias The alias for this certificate path. + * @param path The certificate path. + */ + void putCertPath(String alias, Certificate[] path); +} diff --git a/libjava/classpath/gnu/javax/crypto/keyring/IPublicKeyring.java b/libjava/classpath/gnu/javax/crypto/keyring/IPublicKeyring.java new file mode 100644 index 000000000..d723f5ae9 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/keyring/IPublicKeyring.java @@ -0,0 +1,82 @@ +/* IPublicKeyring.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.keyring; + +import java.security.cert.Certificate; + +/** + * An interface for keyrings that contain trusted (by the owner) public + * credentials (incl. certificates). + * + * @see IKeyring + */ +public interface IPublicKeyring + extends IKeyring +{ + /** + * Tests if this keyring contains a certificate entry with the specified + * <code>alias</code>. + * + * @param alias The alias of the certificate to check. + * @return <code>true</code> if this keyring contains a certificate entry + * that has the given <code>alias</code>; <code>false</code> + * otherwise. + */ + boolean containsCertificate(String alias); + + /** + * Returns a certificate that has the given <code>alias</code>, or + * <code>null</code> if this keyring has no such entry. + * + * @param alias The alias of the certificate to find. + * @return The certificate with the designated <code>alias</code>, or + * <code>null</code> if none found. + */ + Certificate getCertificate(String alias); + + /** + * Adds a certificate in this keyring, with the given <code>alias</code>. + * <p> + * What happens if there is already a certificate entry with this alias? + * + * @param alias The alias of this certificate entry. + * @param cert The certificate. + */ + void putCertificate(String alias, Certificate cert); +} diff --git a/libjava/classpath/gnu/javax/crypto/keyring/MalformedKeyringException.java b/libjava/classpath/gnu/javax/crypto/keyring/MalformedKeyringException.java new file mode 100644 index 000000000..f6b9d189b --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/keyring/MalformedKeyringException.java @@ -0,0 +1,55 @@ +/* MalformedKeyringException.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.keyring; + +import java.io.IOException; + +public class MalformedKeyringException + extends IOException +{ + public MalformedKeyringException() + { + super(); + } + + public MalformedKeyringException(String msg) + { + super(msg); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/keyring/MaskableEnvelopeEntry.java b/libjava/classpath/gnu/javax/crypto/keyring/MaskableEnvelopeEntry.java new file mode 100644 index 000000000..58254a437 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/keyring/MaskableEnvelopeEntry.java @@ -0,0 +1,135 @@ +/* MaskableEnvelopeEntry.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.keyring; + +import java.util.ArrayList; +import java.util.List; + +/** + * An envelope entry that can be "masked" -- placed in a state where the + * envelope's contents cannot be accessed, due to the envelope not being fully + * decoded, for example. + */ +public abstract class MaskableEnvelopeEntry + extends EnvelopeEntry +{ + /** The masked state. */ + protected boolean masked; + + public MaskableEnvelopeEntry(int type, Properties properties) + { + super(type, properties); + } + + protected MaskableEnvelopeEntry(int type) + { + super(type); + } + + /** + * Sets the masked state to the specified value. + * + * @param masked The new masked state. + */ + protected final void setMasked(boolean masked) + { + this.masked = masked; + } + + /** + * Gets the masked state of this object. Certain operations on this object + * will fail if it is masked. + * + * @return The current masked state. + */ + public boolean isMasked() + { + return masked; + } + + public void add(Entry entry) + { + if (isMasked()) + throw new IllegalStateException("masked envelope"); + super.add(entry); + } + + public boolean containsEntry(Entry entry) + { + if (isMasked()) + throw new IllegalStateException("masked envelope"); + return super.containsEntry(entry); + } + + public List getEntries() + { + if (isMasked()) + throw new IllegalStateException("masked envelope"); + return new ArrayList(entries); + } + + public List get(String alias) + { + if (isMasked()) + throw new IllegalStateException("masked envelope"); + return super.get(alias); + } + + public boolean remove(Entry entry) + { + if (isMasked()) + throw new IllegalStateException("masked envelope"); + return super.remove(entry); + } + + public boolean remove(String alias) + { + if (isMasked()) + throw new IllegalStateException("masked envelope"); + return super.remove(alias); + } + + public String toString() + { + return new StringBuilder("MaskableEnvelope{") + .append(super.toString()) + .append(", masked=").append(masked) + .append("}").toString(); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/keyring/MeteredInputStream.java b/libjava/classpath/gnu/javax/crypto/keyring/MeteredInputStream.java new file mode 100644 index 000000000..65f263359 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/keyring/MeteredInputStream.java @@ -0,0 +1,127 @@ +/* MeteredInputStream.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.keyring; + +import java.io.FilterInputStream; +import java.io.IOException; +import java.io.InputStream; + +final class MeteredInputStream + extends FilterInputStream +{ + private int count; + private final int limit; + + MeteredInputStream(InputStream in, int limit) + { + super(in); + if (limit < 0) + throw new IllegalArgumentException("limit must be nonnegative"); + this.limit = limit; + count = 0; + } + + /** + * Tests if the number of bytes read has reached the limit. + * + * @return True if the limit has been reached. + */ + public boolean limitReached() + { + return count == limit; + } + + public int available() throws IOException + { + return Math.min(in.available(), limit - count); + } + + public void close() throws IOException + { + in.close(); + } + + public void mark(int readLimit) + { + } + + public boolean markSupported() + { + return false; + } + + public int read() throws IOException + { + if (limitReached()) + return -1; + int i = in.read(); + if (i != -1) + count++; + return i; + } + + public int read(byte[] buf) throws IOException + { + return read(buf, 0, buf.length); + } + + public int read(byte[] buf, int off, int len) throws IOException + { + if (limitReached()) + return -1; + int i = in.read(buf, off, Math.min(len, limit - count)); + if (i != -1) + count += i; + return i; + } + + public void reset() throws IOException + { + } + + public long skip(long len) throws IOException + { + if (limitReached()) + return 0L; + len = Math.min(len, limit - count); + len = in.skip(len); + count += (int) len; + return len; + } +} diff --git a/libjava/classpath/gnu/javax/crypto/keyring/PasswordAuthenticatedEntry.java b/libjava/classpath/gnu/javax/crypto/keyring/PasswordAuthenticatedEntry.java new file mode 100644 index 000000000..d67300442 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/keyring/PasswordAuthenticatedEntry.java @@ -0,0 +1,286 @@ +/* PasswordAuthenticatedEntry.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.keyring; + +import gnu.java.security.Configuration; +import gnu.java.security.Registry; +import gnu.java.security.prng.IRandom; +import gnu.java.security.prng.LimitReachedException; +import gnu.java.security.util.PRNG; +import gnu.java.security.util.Util; +import gnu.javax.crypto.mac.IMac; +import gnu.javax.crypto.mac.MacFactory; +import gnu.javax.crypto.mac.MacInputStream; +import gnu.javax.crypto.mac.MacOutputStream; +import gnu.javax.crypto.prng.IPBE; +import gnu.javax.crypto.prng.PRNGFactory; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.security.InvalidKeyException; +import java.util.Arrays; +import java.util.HashMap; +import java.util.Iterator; +import java.util.logging.Logger; + +/** + * An entry authenticated with a password-based MAC. + */ +public final class PasswordAuthenticatedEntry + extends MaskableEnvelopeEntry + implements PasswordProtectedEntry, Registry +{ + private static final Logger log = Logger.getLogger(PasswordAuthenticatedEntry.class.getName()); + public static final int TYPE = 3; + + public PasswordAuthenticatedEntry(String mac, int maclen, + Properties properties) + { + super(TYPE, properties); + if (mac == null || mac.length() == 0) + throw new IllegalArgumentException("no MAC specified"); + this.properties.put("mac", mac); + this.properties.put("maclen", String.valueOf(maclen)); + setMasked(false); + } + + private PasswordAuthenticatedEntry() + { + super(TYPE); + setMasked(true); + } + + public static PasswordAuthenticatedEntry decode(DataInputStream in, + char[] password) + throws IOException + { + PasswordAuthenticatedEntry entry = new PasswordAuthenticatedEntry(); + entry.properties.decode(in); + IMac mac = entry.getMac(password); + int len = in.readInt() - mac.macSize(); + MeteredInputStream min = new MeteredInputStream(in, len); + MacInputStream macin = new MacInputStream(min, mac); + DataInputStream in2 = new DataInputStream(macin); + entry.setMasked(false); + entry.decodeEnvelope(in2); + byte[] macValue = new byte[mac.macSize()]; + in.readFully(macValue); + if (! Arrays.equals(macValue, mac.digest())) + throw new MalformedKeyringException("MAC verification failed"); + return entry; + } + + public static PasswordAuthenticatedEntry decode(DataInputStream in) + throws IOException + { + PasswordAuthenticatedEntry entry = new PasswordAuthenticatedEntry(); + entry.defaultDecode(in); + if (! entry.properties.containsKey("mac")) + throw new MalformedKeyringException("no MAC"); + if (! entry.properties.containsKey("maclen")) + throw new MalformedKeyringException("no MAC length"); + if (! entry.properties.containsKey("salt")) + throw new MalformedKeyringException("no salt"); + return entry; + } + + public void verify(char[] password) + { + if (Configuration.DEBUG) + log.entering(this.getClass().getName(), "verify"); + if (isMasked() && payload != null) + { + if (Configuration.DEBUG) + log.fine("payload to verify: " + Util.dumpString(payload)); + long tt = -System.currentTimeMillis(); + IMac m = null; + try + { + m = getMac(password); + } + catch (Exception x) + { + throw new IllegalArgumentException(x.toString(), x); + } + int limit = payload.length - m.macSize(); + m.update(payload, 0, limit); + byte[] macValue = new byte[m.macSize()]; + System.arraycopy(payload, payload.length - macValue.length, macValue, + 0, macValue.length); + if (! Arrays.equals(macValue, m.digest())) + throw new IllegalArgumentException("MAC verification failed"); + setMasked(false); + ByteArrayInputStream bais; + try + { + bais = new ByteArrayInputStream(payload, 0, limit); + DataInputStream in = new DataInputStream(bais); + decodeEnvelope(in); + } + catch (IOException ioe) + { + throw new IllegalArgumentException("malformed keyring fragment"); + } + tt += System.currentTimeMillis(); + if (Configuration.DEBUG) + log.fine("Verified in " + tt + "ms."); + } + else if (Configuration.DEBUG) + log.fine("Skip verification; " + + (isMasked() ? "null payload" : "unmasked")); + if (Configuration.DEBUG) + log.exiting(this.getClass().getName(), "verify"); + } + + public void authenticate(char[] password) throws IOException + { + if (Configuration.DEBUG) + log.entering(this.getClass().getName(), "authenticate"); + long tt = -System.currentTimeMillis(); + long t1 = -System.currentTimeMillis(); + if (isMasked()) + throw new IllegalStateException("entry is masked"); + byte[] salt = new byte[8]; + PRNG.getInstance().nextBytes(salt); + t1 += System.currentTimeMillis(); + if (Configuration.DEBUG) + log.fine("-- Generated salt in " + t1 + "ms."); + properties.put("salt", Util.toString(salt)); + IMac m = getMac(password); + ByteArrayOutputStream bout = new ByteArrayOutputStream(1024); + MacOutputStream macout = new MacOutputStream(bout, m); + DataOutputStream out2 = new DataOutputStream(macout); + for (Iterator it = entries.iterator(); it.hasNext();) + { + Entry entry = (Entry) it.next(); + if (Configuration.DEBUG) + log.fine("-- About to authenticate one " + entry); + t1 = -System.currentTimeMillis(); + entry.encode(out2); + t1 += System.currentTimeMillis(); + if (Configuration.DEBUG) + log.fine("-- Authenticated an Entry in " + t1 + "ms."); + } + bout.write(m.digest()); + payload = bout.toByteArray(); + if (Configuration.DEBUG) + log.fine("authenticated payload: " + Util.dumpString(payload)); + setMasked(true); + tt += System.currentTimeMillis(); + if (Configuration.DEBUG) + { + log.fine("Authenticated in " + tt + "ms."); + log.exiting(this.getClass().getName(), "authenticate"); + } + } + + public void encode(DataOutputStream out, char[] password) throws IOException + { + authenticate(password); + encode(out); + } + + protected void encodePayload(DataOutputStream out) throws IOException + { + if (payload == null) + { + log.fine("Null payload: " + this); + throw new IllegalStateException("mac not computed"); + } + } + + private IMac getMac(char[] password) throws MalformedKeyringException + { + if (Configuration.DEBUG) + log.entering(this.getClass().getName(), "getMac"); + String saltString = properties.get("salt"); + if (saltString == null) + throw new MalformedKeyringException("no salt"); + byte[] salt = Util.toBytesFromString(saltString); + String macAlgorithm = properties.get("mac"); + IMac mac = MacFactory.getInstance(macAlgorithm); + if (mac == null) + throw new MalformedKeyringException("no such mac: " + macAlgorithm); + String macLenString = properties.get("maclen"); + if (macLenString == null) + throw new MalformedKeyringException("no MAC length"); + int maclen; + try + { + maclen = Integer.parseInt(macLenString); + } + catch (NumberFormatException nfe) + { + throw new MalformedKeyringException("bad MAC length"); + } + HashMap pbAttr = new HashMap(); + pbAttr.put(IPBE.PASSWORD, password); + pbAttr.put(IPBE.SALT, salt); + pbAttr.put(IPBE.ITERATION_COUNT, ITERATION_COUNT); + IRandom kdf = PRNGFactory.getInstance("PBKDF2-HMAC-SHA"); + kdf.init(pbAttr); + int keylen = mac.macSize(); + byte[] dk = new byte[keylen]; + try + { + kdf.nextBytes(dk, 0, keylen); + } + catch (LimitReachedException shouldNotHappen) + { + throw new Error(shouldNotHappen.toString()); + } + HashMap macAttr = new HashMap(); + macAttr.put(IMac.MAC_KEY_MATERIAL, dk); + macAttr.put(IMac.TRUNCATED_SIZE, Integer.valueOf(maclen)); + try + { + mac.init(macAttr); + } + catch (InvalidKeyException shouldNotHappen) + { + throw new Error(shouldNotHappen.toString()); + } + if (Configuration.DEBUG) + log.exiting(this.getClass().getName(), "getMac"); + return mac; + } +} diff --git a/libjava/classpath/gnu/javax/crypto/keyring/PasswordEncryptedEntry.java b/libjava/classpath/gnu/javax/crypto/keyring/PasswordEncryptedEntry.java new file mode 100644 index 000000000..0fa7431a8 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/keyring/PasswordEncryptedEntry.java @@ -0,0 +1,293 @@ +/* PasswordEncryptedEntry.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.keyring; + +import gnu.java.security.Configuration; +import gnu.java.security.Registry; +import gnu.java.security.prng.IRandom; +import gnu.java.security.prng.LimitReachedException; +import gnu.java.security.util.PRNG; +import gnu.java.security.util.Util; +import gnu.javax.crypto.cipher.CipherFactory; +import gnu.javax.crypto.cipher.IBlockCipher; +import gnu.javax.crypto.mode.IMode; +import gnu.javax.crypto.mode.ModeFactory; +import gnu.javax.crypto.pad.IPad; +import gnu.javax.crypto.pad.PadFactory; +import gnu.javax.crypto.pad.WrongPaddingException; +import gnu.javax.crypto.prng.IPBE; +import gnu.javax.crypto.prng.PRNGFactory; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.security.InvalidKeyException; +import java.util.HashMap; +import java.util.Iterator; +import java.util.logging.Logger; + +/** + * An envelope that is encrypted with a password-derived key. + */ +public class PasswordEncryptedEntry + extends MaskableEnvelopeEntry + implements PasswordProtectedEntry, Registry +{ + private static final Logger log = Logger.getLogger(PasswordEncryptedEntry.class.getName()); + public static final int TYPE = 1; + + public PasswordEncryptedEntry(String cipher, String mode, int keylen, + Properties properties) + { + super(TYPE, properties); + if ((cipher == null || cipher.length() == 0) + || (mode == null || mode.length() == 0)) + throw new IllegalArgumentException("cipher nor mode can be empty"); + this.properties.put("cipher", cipher); + this.properties.put("mode", mode); + this.properties.put("keylen", String.valueOf(keylen)); + setMasked(false); + } + + private PasswordEncryptedEntry() + { + super(TYPE); + setMasked(true); + } + + public static PasswordEncryptedEntry decode(DataInputStream in, + char[] password) + throws IOException + { + PasswordEncryptedEntry entry = decode(in); + try + { + entry.decrypt(password); + } + catch (WrongPaddingException wpe) + { + throw new MalformedKeyringException("wrong padding in decrypted data"); + } + return entry; + } + + public static PasswordEncryptedEntry decode(DataInputStream in) + throws IOException + { + PasswordEncryptedEntry entry = new PasswordEncryptedEntry(); + entry.defaultDecode(in); + return entry; + } + + public void decrypt(char[] password) throws IllegalArgumentException, + WrongPaddingException + { + if (Configuration.DEBUG) + log.entering(this.getClass().getName(), "decrypt"); + if (isMasked() && payload != null) + { + long tt = -System.currentTimeMillis(); + IMode mode = getMode(password, IMode.DECRYPTION); + IPad padding = PadFactory.getInstance("PKCS7"); + padding.init(mode.currentBlockSize()); + byte[] buf = new byte[payload.length]; + int count = 0; + while (count + mode.currentBlockSize() <= payload.length) + { + mode.update(payload, count, buf, count); + count += mode.currentBlockSize(); + } + int padlen = padding.unpad(buf, 0, buf.length); + setMasked(false); + int len = buf.length - padlen; + ByteArrayInputStream baos = new ByteArrayInputStream(buf, 0, len); + DataInputStream in = new DataInputStream(baos); + try + { + decodeEnvelope(in); + } + catch (IOException ioe) + { + throw new IllegalArgumentException("decryption failed"); + } + tt += System.currentTimeMillis(); + log.fine("Decrypted in " + tt + "ms."); + } + else if (Configuration.DEBUG) + log.fine("Skip decryption; " + (isMasked() ? "null payload" : "unmasked")); + if (Configuration.DEBUG) + log.exiting(this.getClass().getName(), "decrypt"); + } + + public void encrypt(char[] password) throws IOException + { + if (Configuration.DEBUG) + log.entering(this.getClass().getName(), "encrypt", String.valueOf(password)); + long tt = -System.currentTimeMillis(); + long t1 = -System.currentTimeMillis(); + byte[] salt = new byte[8]; + PRNG.getInstance().nextBytes(salt); + t1 += System.currentTimeMillis(); + if (Configuration.DEBUG) + log.fine("-- Generated salt in " + t1 + "ms."); + properties.put("salt", Util.toString(salt)); + IMode mode = getMode(password, IMode.ENCRYPTION); + IPad pad = PadFactory.getInstance("PKCS7"); + pad.init(mode.currentBlockSize()); + ByteArrayOutputStream bout = new ByteArrayOutputStream(1024); + DataOutputStream out2 = new DataOutputStream(bout); + for (Iterator it = entries.iterator(); it.hasNext();) + { + Entry entry = (Entry) it.next(); + if (Configuration.DEBUG) + log.fine("-- About to encode one " + entry); + t1 = -System.currentTimeMillis(); + entry.encode(out2); + t1 += System.currentTimeMillis(); + if (Configuration.DEBUG) + log.fine("-- Encoded an Entry in " + t1 + "ms."); + } + byte[] plaintext = bout.toByteArray(); + byte[] padding = pad.pad(plaintext, 0, plaintext.length); + payload = new byte[plaintext.length + padding.length]; + byte[] lastBlock = new byte[mode.currentBlockSize()]; + int l = mode.currentBlockSize() - padding.length; + System.arraycopy(plaintext, plaintext.length - l, lastBlock, 0, l); + System.arraycopy(padding, 0, lastBlock, l, padding.length); + int count = 0; + while (count + mode.currentBlockSize() < plaintext.length) + { + mode.update(plaintext, count, payload, count); + count += mode.currentBlockSize(); + } + mode.update(lastBlock, 0, payload, count); + setMasked(true); + tt += System.currentTimeMillis(); + if (Configuration.DEBUG) + { + log.fine("Encrypted in " + tt + "ms."); + log.exiting(this.getClass().getName(), "encrypt"); + } + } + + public void encode(DataOutputStream out, char[] password) throws IOException + { + encrypt(password); + encode(out); + } + + protected void encodePayload() throws IOException + { + if (payload == null) + { + if (Configuration.DEBUG) + log.fine("Null payload: " + this); + throw new IllegalStateException("not encrypted"); + } + } + + private IMode getMode(char[] password, int state) + { + String s = properties.get("salt"); + if (s == null) + throw new IllegalArgumentException("no salt"); + byte[] salt = Util.toBytesFromString(s); + IBlockCipher cipher = CipherFactory.getInstance(properties.get("cipher")); + if (cipher == null) + throw new IllegalArgumentException("no such cipher: " + + properties.get("cipher")); + int blockSize = cipher.defaultBlockSize(); + if (properties.containsKey("block-size")) + try + { + blockSize = Integer.parseInt(properties.get("block-size")); + } + catch (NumberFormatException nfe) + { + throw new IllegalArgumentException("bad block size: " + + nfe.getMessage()); + } + String modeName = properties.get("mode"); + IMode mode = ModeFactory.getInstance(modeName, cipher, blockSize); + if (mode == null) + throw new IllegalArgumentException("no such mode: " + modeName); + HashMap pbAttr = new HashMap(); + pbAttr.put(IPBE.PASSWORD, password); + pbAttr.put(IPBE.SALT, salt); + pbAttr.put(IPBE.ITERATION_COUNT, ITERATION_COUNT); + IRandom kdf = PRNGFactory.getInstance("PBKDF2-HMAC-SHA"); + kdf.init(pbAttr); + int keylen = 0; + if (! properties.containsKey("keylen")) + throw new IllegalArgumentException("no key length"); + try + { + keylen = Integer.parseInt(properties.get("keylen")); + } + catch (NumberFormatException nfe) + { + } + byte[] dk = new byte[keylen]; + byte[] iv = new byte[blockSize]; + try + { + kdf.nextBytes(dk, 0, keylen); + kdf.nextBytes(iv, 0, blockSize); + } + catch (LimitReachedException shouldNotHappen) + { + throw new Error(shouldNotHappen.toString()); + } + HashMap modeAttr = new HashMap(); + modeAttr.put(IMode.KEY_MATERIAL, dk); + modeAttr.put(IMode.STATE, Integer.valueOf(state)); + modeAttr.put(IMode.IV, iv); + try + { + mode.init(modeAttr); + } + catch (InvalidKeyException ike) + { + throw new IllegalArgumentException(ike.toString()); + } + return mode; + } +} diff --git a/libjava/classpath/gnu/javax/crypto/keyring/PasswordProtectedEntry.java b/libjava/classpath/gnu/javax/crypto/keyring/PasswordProtectedEntry.java new file mode 100644 index 000000000..a95f2e4a4 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/keyring/PasswordProtectedEntry.java @@ -0,0 +1,57 @@ +/* PasswordProtectedEntry.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.keyring; + +import java.io.DataOutputStream; +import java.io.IOException; + +public interface PasswordProtectedEntry +{ + /** The iteration count for password-based KDFs. */ + Integer ITERATION_COUNT = Integer.valueOf(1000); + + /** + * Encodes this entry, protected by a password. + * + * @param out The output stream to encode to. + * @param password The password. + * @throws IOException If an I/O error occurs. + */ + void encode(DataOutputStream out, char[] password) throws IOException; +} diff --git a/libjava/classpath/gnu/javax/crypto/keyring/PrimitiveEntry.java b/libjava/classpath/gnu/javax/crypto/keyring/PrimitiveEntry.java new file mode 100644 index 000000000..8993de716 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/keyring/PrimitiveEntry.java @@ -0,0 +1,112 @@ +/* PrimitiveEntry.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.keyring; + +import java.util.Date; + +/** + * A primitive entry is an entry that contains a single cryptographic entity. + */ +public abstract class PrimitiveEntry + extends Entry +{ + /** The creation date. */ + protected Date creationDate; + + protected PrimitiveEntry(int type, Date creationDate, Properties properties) + { + super(type, properties); + if (creationDate == null) + this.creationDate = new Date(); + else + this.creationDate = (Date) creationDate.clone(); + if (! this.properties.containsKey("alias") + || this.properties.get("alias").length() == 0) + throw new IllegalArgumentException("primitive entries MUST have an alias"); + this.properties.put("creation-date", + String.valueOf(this.creationDate.getTime())); + } + + protected PrimitiveEntry(int type) + { + super(type); + } + + /** + * Returns the alias of this primitive entry. + * + * @return The alias. + */ + public String getAlias() + { + return properties.get("alias"); + } + + /** + * Returns the creation date of this primitive entry. + * + * @return The creation date. + */ + public Date getCreationDate() + { + return (Date) creationDate.clone(); + } + + public boolean equals(Object object) + { + if (! getClass().equals(object.getClass())) + return false; + return getAlias().equals(((PrimitiveEntry) object).getAlias()); + } + + protected final void makeCreationDate() throws MalformedKeyringException + { + String s = properties.get("creation-date"); + if (s == null) + throw new MalformedKeyringException("no creation date"); + try + { + creationDate = new Date(Long.parseLong(s)); + } + catch (NumberFormatException nfe) + { + throw new MalformedKeyringException("invalid creation date"); + } + } +} diff --git a/libjava/classpath/gnu/javax/crypto/keyring/PrivateKeyEntry.java b/libjava/classpath/gnu/javax/crypto/keyring/PrivateKeyEntry.java new file mode 100644 index 000000000..b2637316e --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/keyring/PrivateKeyEntry.java @@ -0,0 +1,194 @@ +/* PrivateKeyEntry.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.keyring; + +import gnu.java.security.key.IKeyPairCodec; +import gnu.java.security.key.KeyPairCodecFactory; +import gnu.java.security.key.dss.DSSPrivateKey; +import gnu.java.security.key.rsa.GnuRSAPrivateKey; +import gnu.javax.crypto.key.GnuSecretKey; +import gnu.javax.crypto.key.dh.GnuDHPrivateKey; + +import java.io.DataInputStream; +import java.io.IOException; +import java.security.Key; +import java.security.KeyFactory; +import java.security.PrivateKey; +import java.security.spec.PKCS8EncodedKeySpec; +import java.util.Date; + +/** + * An immutable class representing a private or secret key entry. + */ +public final class PrivateKeyEntry + extends PrimitiveEntry +{ + public static final int TYPE = 7; + /** The key. */ + private Key key; + + /** + * Creates a new key entry. + * + * @param key The key. + * @param creationDate The entry creation date. + * @param properties The entry properties. + * @throws IllegalArgumentException If any parameter is null. + */ + public PrivateKeyEntry(Key key, Date creationDate, Properties properties) + { + super(TYPE, creationDate, properties); + if (key == null) + throw new IllegalArgumentException("no private key"); + if (! (key instanceof PrivateKey) && ! (key instanceof GnuSecretKey)) + throw new IllegalArgumentException("not a private or secret key"); + this.key = key; + } + + private PrivateKeyEntry() + { + super(TYPE); + } + + public static PrivateKeyEntry decode(DataInputStream in) throws IOException + { + PrivateKeyEntry entry = new PrivateKeyEntry(); + entry.defaultDecode(in); + String type = entry.properties.get("type"); + if (type == null) + throw new MalformedKeyringException("no key type"); + if (type.equalsIgnoreCase("RAW-DSS")) + { + IKeyPairCodec coder = KeyPairCodecFactory.getInstance("dss"); + entry.key = coder.decodePrivateKey(entry.payload); + } + else if (type.equalsIgnoreCase("RAW-RSA")) + { + IKeyPairCodec coder = KeyPairCodecFactory.getInstance("rsa"); + entry.key = coder.decodePrivateKey(entry.payload); + } + else if (type.equalsIgnoreCase("RAW-DH")) + { + IKeyPairCodec coder = KeyPairCodecFactory.getInstance("dh"); + entry.key = coder.decodePrivateKey(entry.payload); + } + else if (type.equalsIgnoreCase("RAW")) + entry.key = new GnuSecretKey(entry.payload, null); + else if (type.equalsIgnoreCase("PKCS8")) + { + try + { + KeyFactory kf = KeyFactory.getInstance("RSA"); + PKCS8EncodedKeySpec ks = new PKCS8EncodedKeySpec(entry.payload); + entry.key = kf.generatePrivate(ks); + } + catch (Exception ignored) + { + } + if (entry.key == null) + { + try + { + KeyFactory kf = KeyFactory.getInstance("DSA"); + PKCS8EncodedKeySpec ks = new PKCS8EncodedKeySpec(entry.payload); + entry.key = kf.generatePrivate(ks); + } + catch (Exception ignored) + { + } + if (entry.key == null) + throw new MalformedKeyringException("could not decode PKCS#8 key"); + } + } + else + throw new MalformedKeyringException("unsupported key type " + type); + return entry; + } + + /** + * Returns this entry's key. + * + * @return The key. + */ + public Key getKey() + { + return key; + } + + protected void encodePayload() throws IOException + { + String format = key.getFormat(); + if (key instanceof DSSPrivateKey) + { + properties.put("type", "RAW-DSS"); + IKeyPairCodec coder = KeyPairCodecFactory.getInstance("dss"); + payload = coder.encodePrivateKey((PrivateKey) key); + } + else if (key instanceof GnuRSAPrivateKey) + { + properties.put("type", "RAW-RSA"); + IKeyPairCodec coder = KeyPairCodecFactory.getInstance("rsa"); + payload = coder.encodePrivateKey((PrivateKey) key); + } + else if (key instanceof GnuDHPrivateKey) + { + properties.put("type", "RAW-DH"); + IKeyPairCodec coder = KeyPairCodecFactory.getInstance("dh"); + payload = coder.encodePrivateKey((PrivateKey) key); + } + else if (key instanceof GnuSecretKey) + { + properties.put("type", "RAW"); + payload = key.getEncoded(); + } + else if (format != null && format.equals("PKCS#8")) + { + properties.put("type", "PKCS8"); + payload = key.getEncoded(); + } + else + throw new IllegalArgumentException("unsupported private key"); + } + + public String toString() + { + return "PrivateKeyEntry{key=" + + (key == null ? "-" : key.getClass().getName()) + "}"; + } +} diff --git a/libjava/classpath/gnu/javax/crypto/keyring/Properties.java b/libjava/classpath/gnu/javax/crypto/keyring/Properties.java new file mode 100644 index 000000000..f25c82e36 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/keyring/Properties.java @@ -0,0 +1,203 @@ +/* Properties.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.keyring; + +import java.io.ByteArrayOutputStream; +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; + +/** + * A set of <code>(name => value)</code> pairs used in keyring entries. + * Keys and values are simple strings, with the key never being empty and always + * treated case-insensitively. + */ +public class Properties + implements Cloneable +{ + private HashMap props; + + /** + * Creates a new properties object. + */ + public Properties() + { + props = new HashMap(); + } + + /** + * Removes all properties from this object. + */ + public void clear() + { + props.clear(); + } + + /** + * Creates a copy of this properties object. + * + * @return The copy. + */ + public Object clone() + { + Properties result = new Properties(); + result.props.putAll(props); + return result; + } + + /** + * Tests if this object contains a given property name. + * + * @param key The key to test. + * @return True if this object contains the given key. + */ + public boolean containsKey(String key) + { + if (key == null || key.length() == 0) + return false; + return props.containsKey(canonicalize(key)); + } + + /** + * Tests if this object contains a given property value. + * + * @param value The value to test. + * @return True if this object contains the given value. + */ + public boolean containsValue(String value) + { + if (value == null) + return false; + return props.containsValue(value); + } + + /** + * Adds a new property to this object. + * + * @param key The key, which can neither be null nor empty. + * @param value The value, which cannot be null. + * @return The old value mapped by the key, if any. + * @throws IllegalArgumentException If either the key or value parameter is + * null, or if the key is empty. + */ + public String put(String key, String value) + { + if (key == null || value == null || key.length() == 0) + throw new IllegalArgumentException("key nor value can be null"); + return (String) props.put(canonicalize(key), value); + } + + /** + * Returns the value mapped by the given key, or null if there is no such + * mapping. + * + * @param key + */ + public String get(String key) + { + if (key == null || key.length() == 0) + return null; + return (String) props.get(canonicalize(key)); + } + + /** + * Removes a key and its value from this object. + * + * @param key The key of the property to remove. + * @return The old value mapped by the key, if any. + */ + public String remove(String key) + { + if (key == null || key.length() == 0) + return null; + return (String) props.remove(canonicalize(key)); + } + + /** + * Decodes a set of properties from the given input stream. + * + * @param in The input stream. + * @throws IOException If an I/O error occurs. + */ + public void decode(DataInputStream in) throws IOException + { + int len = in.readInt(); + MeteredInputStream min = new MeteredInputStream(in, len); + DataInputStream in2 = new DataInputStream(min); + while (! min.limitReached()) + { + String name = in2.readUTF(); + String value = in2.readUTF(); + put(name, value); + } + } + + /** + * Encodes this set of properties to the given output stream. + * + * @param out The output stream to encode to. + * @throws IOException If an I/O error occurs. + */ + public void encode(DataOutputStream out) throws IOException + { + ByteArrayOutputStream buf = new ByteArrayOutputStream(); + DataOutputStream out2 = new DataOutputStream(buf); + for (Iterator it = props.entrySet().iterator(); it.hasNext();) + { + Map.Entry entry = (Map.Entry) it.next(); + out2.writeUTF((String) entry.getKey()); + out2.writeUTF((String) entry.getValue()); + } + out.writeInt(buf.size()); + buf.writeTo(out); + } + + public String toString() + { + return props.toString(); + } + + private String canonicalize(String key) + { + return key.toLowerCase(); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/keyring/PublicKeyEntry.java b/libjava/classpath/gnu/javax/crypto/keyring/PublicKeyEntry.java new file mode 100644 index 000000000..837706d19 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/keyring/PublicKeyEntry.java @@ -0,0 +1,162 @@ +/* PublicKeyEntry.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.keyring; + +import gnu.java.security.key.IKeyPairCodec; +import gnu.java.security.key.KeyPairCodecFactory; +import gnu.java.security.key.dss.DSSPublicKey; +import gnu.java.security.key.rsa.GnuRSAPublicKey; +import gnu.javax.crypto.key.dh.GnuDHPublicKey; + +import java.io.DataInputStream; +import java.io.IOException; +import java.security.KeyFactory; +import java.security.PublicKey; +import java.security.spec.X509EncodedKeySpec; +import java.util.Date; + +public final class PublicKeyEntry + extends PrimitiveEntry +{ + public static final int TYPE = 6; + private PublicKey key; + + public PublicKeyEntry(PublicKey key, Date creationDate, Properties properties) + { + super(TYPE, creationDate, properties); + if (key == null) + throw new IllegalArgumentException("no key specified"); + this.key = key; + } + + private PublicKeyEntry() + { + super(TYPE); + } + + public static PublicKeyEntry decode(DataInputStream in) throws IOException + { + PublicKeyEntry entry = new PublicKeyEntry(); + entry.defaultDecode(in); + String type = entry.properties.get("type"); + if (type == null) + throw new MalformedKeyringException("no key type"); + if (type.equalsIgnoreCase("RAW-DSS")) + { + IKeyPairCodec coder = KeyPairCodecFactory.getInstance("dss"); + entry.key = coder.decodePublicKey(entry.payload); + } + else if (type.equalsIgnoreCase("RAW-RSA")) + { + IKeyPairCodec coder = KeyPairCodecFactory.getInstance("rsa"); + entry.key = coder.decodePublicKey(entry.payload); + } + else if (type.equalsIgnoreCase("RAW-DH")) + { + IKeyPairCodec coder = KeyPairCodecFactory.getInstance("dh"); + entry.key = coder.decodePublicKey(entry.payload); + } + else if (type.equalsIgnoreCase("X.509")) + { + try + { + KeyFactory kf = KeyFactory.getInstance("RSA"); + entry.key = kf.generatePublic(new X509EncodedKeySpec(entry.payload)); + } + catch (Exception x) + { + } + if (entry.key == null) + { + try + { + KeyFactory kf = KeyFactory.getInstance("DSA"); + entry.key = kf.generatePublic(new X509EncodedKeySpec(entry.payload)); + } + catch (Exception x) + { + } + if (entry.key == null) + throw new MalformedKeyringException("could not decode X.509 key"); + } + } + else + throw new MalformedKeyringException("unsupported public key type: " + type); + return entry; + } + + /** + * Returns the public key. + * + * @return The public key. + */ + public PublicKey getKey() + { + return key; + } + + protected void encodePayload() throws IOException + { + if (key instanceof DSSPublicKey) + { + properties.put("type", "RAW-DSS"); + IKeyPairCodec coder = KeyPairCodecFactory.getInstance("dss"); + payload = coder.encodePublicKey(key); + } + else if (key instanceof GnuRSAPublicKey) + { + properties.put("type", "RAW-RSA"); + IKeyPairCodec coder = KeyPairCodecFactory.getInstance("rsa"); + payload = coder.encodePublicKey(key); + } + else if (key instanceof GnuDHPublicKey) + { + properties.put("type", "RAW-DH"); + IKeyPairCodec coder = KeyPairCodecFactory.getInstance("dh"); + payload = coder.encodePublicKey(key); + } + else if (key.getFormat() != null && key.getFormat().equals("X.509")) + { + properties.put("type", "X.509"); + payload = key.getEncoded(); + } + else + throw new IllegalArgumentException("cannot encode public key"); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/kwa/AESKeyWrap.java b/libjava/classpath/gnu/javax/crypto/kwa/AESKeyWrap.java new file mode 100644 index 000000000..bb86c5477 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/kwa/AESKeyWrap.java @@ -0,0 +1,168 @@ +/* AESWrap.java -- An implementation of RFC-3394 AES Key Wrap Algorithm + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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; either version 2, or (at your option) +any later version. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.kwa; + +import gnu.java.security.Registry; +import gnu.javax.crypto.cipher.IBlockCipher; +import gnu.javax.crypto.cipher.Rijndael; + +import java.security.InvalidKeyException; +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; + +/** + * The GNU implementation of the AES Key Wrap Algorithm as described in [1]. + * <p> + * References: + * <ol> + * <li><a href="http://csrc.nist.gov/encryption/kms/key-wrap.pdf"></a>.</li> + * <li><a href="http://www.rfc-archive.org/getrfc.php?rfc=3394">Advanced + * Encryption Standard (AES) Key Wrap Algorithm</a>.</li> + * <li><a href="http://www.w3.org/TR/xmlenc-core/">XML Encryption Syntax and + * Processing</a>.</li> + * </ol> + */ +public class AESKeyWrap + extends BaseKeyWrappingAlgorithm +{ + private static final byte[] DEFAULT_IV = new byte[] { + (byte) 0xA6, (byte) 0xA6, (byte) 0xA6, (byte) 0xA6, + (byte) 0xA6, (byte) 0xA6, (byte) 0xA6, (byte) 0xA6 }; + + private Rijndael aes; + private byte[] iv; + + public AESKeyWrap() + { + super(Registry.AES_KWA); + + aes = new Rijndael(); + } + + protected void engineInit(Map attributes) throws InvalidKeyException + { + Map cipherAttributes = new HashMap(); + cipherAttributes.put(IBlockCipher.CIPHER_BLOCK_SIZE, Integer.valueOf(16)); + cipherAttributes.put(IBlockCipher.KEY_MATERIAL, + attributes.get(KEY_ENCRYPTION_KEY_MATERIAL)); + aes.reset(); + aes.init(cipherAttributes); + byte[] initialValue = (byte[]) attributes.get(INITIAL_VALUE); + iv = initialValue == null ? DEFAULT_IV : (byte[]) initialValue.clone(); + } + + protected byte[] engineWrap(byte[] in, int inOffset, int length) + { + // TODO: handle input length which is not a multiple of 8 as suggested by + // section 2.2.3.2 of RFC-3394 + if (length % 8 != 0) + throw new IllegalArgumentException("Input length MUST be a multiple of 8"); + int n = length / 8; + // output is always one block larger than input + byte[] result = new byte[length + 8]; + + // 1. init variables: we'll use out buffer for our work buffer; + // A will be the first block in out, while R will be the rest + System.arraycopy(iv, 0, result, 0, 8); + System.arraycopy(in, inOffset, result, 8, length); + byte[] B = new byte[2 * 8]; + // 2. compute intermediate values + long t; + for (int j = 0; j < 6; j++) + for (int i = 1; i <= n; i++) + { + System.arraycopy(result, 0, B, 0, 8); + System.arraycopy(result, i * 8, B, 8, 8); + aes.encryptBlock(B, 0, B, 0); + t = (n * j) + i; + result[0] = (byte)(B[0] ^ (t >>> 56)); + result[1] = (byte)(B[1] ^ (t >>> 48)); + result[2] = (byte)(B[2] ^ (t >>> 40)); + result[3] = (byte)(B[3] ^ (t >>> 32)); + result[4] = (byte)(B[4] ^ (t >>> 24)); + result[5] = (byte)(B[5] ^ (t >>> 16)); + result[6] = (byte)(B[6] ^ (t >>> 8)); + result[7] = (byte)(B[7] ^ t ); + System.arraycopy(B, 8, result, i * 8, 8); + } + return result; + } + + protected byte[] engineUnwrap(byte[] in, int inOffset, int length) + throws KeyUnwrappingException + { + // TODO: handle input length which is not a multiple of 8 as suggested by + // section 2.2.3.2 of RFC-3394 + if (length % 8 != 0) + throw new IllegalArgumentException("Input length MUST be a multiple of 8"); + // output is always one block shorter than input + byte[] result = new byte[length - 8]; + + // 1. init variables: we'll use out buffer for our R work buffer + byte[] A = new byte[8]; + System.arraycopy(in, inOffset, A, 0, 8); + System.arraycopy(in, inOffset + 8, result, 0, result.length); + byte[] B = new byte[2 * 8]; + // 2. compute intermediate values + int n = length / 8 - 1; + long t; + for (int j = 5; j >= 0; j--) + for (int i = n; i >= 1; i--) + { + t = (n * j) + i; + B[0] = (byte)(A[0] ^ (t >>> 56)); + B[1] = (byte)(A[1] ^ (t >>> 48)); + B[2] = (byte)(A[2] ^ (t >>> 40)); + B[3] = (byte)(A[3] ^ (t >>> 32)); + B[4] = (byte)(A[4] ^ (t >>> 24)); + B[5] = (byte)(A[5] ^ (t >>> 16)); + B[6] = (byte)(A[6] ^ (t >>> 8)); + B[7] = (byte)(A[7] ^ t ); + System.arraycopy(result, (i - 1) * 8, B, 8, 8); + aes.decryptBlock(B, 0, B, 0); + System.arraycopy(B, 0, A, 0, 8); + System.arraycopy(B, 8, result, (i - 1) * 8, 8); + } + if (! Arrays.equals(A, iv)) + throw new KeyUnwrappingException(); + + return result; + } +} diff --git a/libjava/classpath/gnu/javax/crypto/kwa/BaseKeyWrappingAlgorithm.java b/libjava/classpath/gnu/javax/crypto/kwa/BaseKeyWrappingAlgorithm.java new file mode 100644 index 000000000..80b114a02 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/kwa/BaseKeyWrappingAlgorithm.java @@ -0,0 +1,145 @@ +/* BaseKeyWrappingAlgorithm.java -- FIXME: briefly describe file purpose + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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; either version 2, or (at your option) +any later version. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.kwa; + +import gnu.java.security.util.PRNG; + +import java.security.InvalidKeyException; +import java.util.Collections; +import java.util.Map; + +import javax.crypto.ShortBufferException; + +/** + * A base class to facilitate implementation of concrete Key Wrapping + * Algorithms. + */ +public abstract class BaseKeyWrappingAlgorithm + implements IKeyWrappingAlgorithm +{ + /** The canonical name of the key wrapping algorithm. */ + protected String name; + /** A source of randomness if/when needed by concrete implementations. */ + private PRNG prng; + + /** + * Protected constructor. + * + * @param name the key wrapping algorithm canonical name. + */ + protected BaseKeyWrappingAlgorithm(String name) + { + super(); + } + + public String name() + { + return this.name; + } + + public void init(Map attributes) throws InvalidKeyException + { + if (attributes == null) + attributes = Collections.EMPTY_MAP; + + engineInit(attributes); + } + + public int wrap(byte[] in, int inOffset, int length, byte[] out, int outOffset) + throws ShortBufferException + { + if (outOffset < 0) + throw new IllegalArgumentException("Output offset MUST NOT be negative"); + byte[] result = wrap(in, inOffset, length); + if (outOffset + result.length > out.length) + throw new ShortBufferException(); + System.arraycopy(result, 0, out, outOffset, result.length); + return result.length; + } + + public byte[] wrap(byte[] in, int inOffset, int length) + { + if (inOffset < 0) + throw new IllegalArgumentException("Input offset MUST NOT be negative"); + if (length < 0) + throw new IllegalArgumentException("Input length MUST NOT be negative"); + + return engineWrap(in, inOffset, length); + } + + public int unwrap(byte[] in, int inOffset, int length, + byte[] out, int outOffset) + throws ShortBufferException, KeyUnwrappingException + { + if (outOffset < 0) + throw new IllegalArgumentException("Output offset MUST NOT be negative"); + byte[] result = engineUnwrap(in, inOffset, length); + if (outOffset + result.length > out.length) + throw new ShortBufferException(); + System.arraycopy(result, 0, out, outOffset, result.length); + return result.length; + } + + public byte[] unwrap(byte[] in, int inOffset, int length) + throws KeyUnwrappingException + { + if (inOffset < 0) + throw new IllegalArgumentException("Input offset MUST NOT be negative"); + if (length < 0) + throw new IllegalArgumentException("Input length MUST NOT be negative"); + + return engineUnwrap(in, inOffset, length); + } + + protected abstract void engineInit(Map attributes) throws InvalidKeyException; + + protected abstract byte[] engineWrap(byte[] in, int inOffset, int length); + + protected abstract byte[] engineUnwrap(byte[] in, int inOffset, int length) + throws KeyUnwrappingException; + + /** @return a strong pseudo-random number generator if/when needed. */ + protected PRNG getDefaultPRNG() + { + if (prng == null) + prng = PRNG.getInstance(); + + return prng; + } +} diff --git a/libjava/classpath/gnu/javax/crypto/kwa/IKeyWrappingAlgorithm.java b/libjava/classpath/gnu/javax/crypto/kwa/IKeyWrappingAlgorithm.java new file mode 100644 index 000000000..271ec5c1b --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/kwa/IKeyWrappingAlgorithm.java @@ -0,0 +1,160 @@ +/* IKeyWrappingAlgorithm.java -- FIXME: briefly describe file purpose + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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; either version 2, or (at your option) +any later version. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.kwa; + +import java.security.InvalidKeyException; +import java.security.SecureRandom; +import java.util.Map; + +import javax.crypto.ShortBufferException; + +/** + * Constants and visible methods available to all GNU Key Wrapping Algorithm + * implementations. + */ +public interface IKeyWrappingAlgorithm +{ + /** + * Name of the property, in the attributes map, that references the Key + * Wrapping Algorithm KEK (Key Encryption Key) material. The object referenced + * by this property is a byte array containing the keying material for the + * underlying block cipher. + */ + String KEY_ENCRYPTION_KEY_MATERIAL = "gnu.crypto.kwa.kek"; + /** + * Name of the property, in the attributes map, that references the Initial + * Value (IV) material. The object referenced by this property is a byte array + * containing the initial integrity check register value. + */ + String INITIAL_VALUE = "gnu.crypto.kwa.iv"; + /** + * Property name of an optional {@link SecureRandom} instance to use. The + * default is to use a {@link gnu.java.security.util.PRNG} instance. + */ + String SOURCE_OF_RANDOMNESS = "gnu.crypto.kwa.prng"; + + /** + * Returns the canonical name of this Key Wrapping Algorithm. + * + * @return the canonical name of this Key Wrapping Algorithm. + */ + String name(); + + /** + * Initializes this instance with the designated algorithm specific + * attributes. + * + * @param attributes a map of name-to-value pairs the Key Wrapping Algorithm + * must use for its setup. + * @throws InvalidKeyException if an exception is encountered while seting up + * the Key Wrapping Algorithm keying material (KEK). + */ + void init(Map attributes) throws InvalidKeyException; + + /** + * Wraps the designated plain text bytes. + * + * @param in the input byte array containing the plain text. + * @param inOffset the offset into <code>in</code> where the first byte of + * the plain text (key material) to wrap is located. + * @param length the number of bytes to wrap. + * @param out the output byte array where the wrapped key material will be + * stored. + * @param outOffset the offset into <code>out</code> of the first wrapped + * byte. + * @return the number of bytes of the wrapped key material; i.e. the length, + * in <code>out</code>, starting from <code>outOffset</code> + * where the cipher text (wrapped key material) are stored. + * @throws ShortBufferException if the output buffer is not long enough to + * accomodate the number of bytes resulting from wrapping the plain + * text. + */ + int wrap(byte[] in, int inOffset, int length, byte[] out, int outOffset) + throws ShortBufferException; + + /** + * Wraps the designated plain text bytes. + * + * @param in the input byte array containing the plain text. + * @param inOffset the offset into <code>in</code> where the first byte of + * the plain text (key material) to wrap is located. + * @param length the number of bytes to wrap. + * @return a newly allocated byte array containing the cipher text. + */ + byte[] wrap(byte[] in, int inOffset, int length); + + /** + * Unwraps the designated cipher text bytes. + * + * @param in the input byte array containing the cipher text. + * @param inOffset the offset into <code>in</code> where the first byte of + * the cipher text (already wrapped key material) to unwrap is + * located. + * @param length the number of bytes to unwrap. + * @param out the output byte array where the unwrapped key material will be + * stored. + * @param outOffset the offset into <code>out</code> of the first unwrapped + * byte. + * @return the number of bytes of the unwrapped key material; i.e. the length, + * in <code>out</code>, starting from <code>outOffset</code> + * where the plain text (unwrapped key material) are stored. + * @throws ShortBufferException if the output buffer is not long enough to + * accomodate the number of bytes resulting from unwrapping the + * cipher text. + * @throws KeyUnwrappingException if after unwrapping the cipher text, the + * bytes at the begining did not match the initial value. + */ + int unwrap(byte[] in, int inOffset, int length, byte[] out, int outOffset) + throws ShortBufferException, KeyUnwrappingException; + + /** + * Unwraps the designated cipher text bytes. + * + * @param in the input byte array containing the cipher text. + * @param inOffset the offset into <code>in</code> where the first byte of + * the cipher text (already wrapped key material) to unwrap is + * located. + * @param length the number of bytes to unwrap. + * @return a newly allocated byte array containing the plain text. + * @throws KeyUnwrappingException if after unwrapping the cipher text, the + * bytes at the begining did not match the initial value. + */ + byte[] unwrap(byte[] in, int inOffset, int length) + throws KeyUnwrappingException; +} diff --git a/libjava/classpath/gnu/javax/crypto/kwa/KeyUnwrappingException.java b/libjava/classpath/gnu/javax/crypto/kwa/KeyUnwrappingException.java new file mode 100644 index 000000000..54b4aff0a --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/kwa/KeyUnwrappingException.java @@ -0,0 +1,67 @@ +/* KeyUnwrappingException.java -- FIXME: briefly describe file purpose + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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; either version 2, or (at your option) +any later version. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.kwa; + +import java.security.GeneralSecurityException; + +/** + * A checked security exception to denote an unexpected problem while unwrapping + * key material with a Key Wrapping Algorithm. + */ +public class KeyUnwrappingException + extends GeneralSecurityException +{ + /** + * Create a new instance with no descriptive error message. + */ + public KeyUnwrappingException() + { + super(); + } + + /** + * Create a new instance with a descriptive error message. + * + * @param msg the descriptive error message + */ + public KeyUnwrappingException(String msg) + { + super(msg); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/kwa/KeyWrappingAlgorithmFactory.java b/libjava/classpath/gnu/javax/crypto/kwa/KeyWrappingAlgorithmFactory.java new file mode 100644 index 000000000..abd208c07 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/kwa/KeyWrappingAlgorithmFactory.java @@ -0,0 +1,110 @@ +/* KeyWrappingAlgorithmFactory.java -- FIXME: briefly describe file purpose + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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; either version 2, or (at your option) +any later version. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.kwa; + +import gnu.java.security.Registry; + +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; + +/** + * A Factory class for the Key Wrapping Algorithm implementations. + */ +public class KeyWrappingAlgorithmFactory +{ + /** Names of Key Wrapping Algorihms cached for speed. */ + private static Set names; + + /** Trivial constructor to enforce Singleton pattern. */ + private KeyWrappingAlgorithmFactory() + { + super(); + } + + /** + * Returns an instance of a key-wrapping algorithm given its name. + * + * @param name the case-insensitive name of the key-wrapping algorithm. + * @return an instance of the designated key-wrapping algorithm, or + * <code>null</code> if none was found. + * @exception InternalError if the implementation does not pass its self-test. + */ + public static final IKeyWrappingAlgorithm getInstance(String name) + { + if (name == null) + return null; + name = name.trim(); + IKeyWrappingAlgorithm result = null; + if (name.equalsIgnoreCase(Registry.AES_KWA) + || name.equalsIgnoreCase(Registry.AES128_KWA) + || name.equalsIgnoreCase(Registry.AES192_KWA) + || name.equalsIgnoreCase(Registry.AES256_KWA) + || name.equalsIgnoreCase(Registry.RIJNDAEL_KWA)) + result = new AESKeyWrap(); + else if (name.equalsIgnoreCase(Registry.TRIPLEDES_KWA) + || name.equalsIgnoreCase(Registry.DESEDE_KWA)) + result = new TripleDESKeyWrap(); + + return result; + } + + /** + * Returns a {@link Set} of key wrapping algorithm names supported by this + * <i>Factory</i>. + * + * @return a {@link Set} of key wrapping algorithm names (Strings). + */ + public static synchronized final Set getNames() + { + if (names == null) + { + HashSet hs = new HashSet(); + hs.add(Registry.AES_KWA); + hs.add(Registry.AES128_KWA); + hs.add(Registry.AES192_KWA); + hs.add(Registry.AES256_KWA); + hs.add(Registry.RIJNDAEL_KWA); + hs.add(Registry.TRIPLEDES_KWA); + hs.add(Registry.DESEDE_KWA); + names = Collections.unmodifiableSet(hs); + } + return names; + } +} diff --git a/libjava/classpath/gnu/javax/crypto/kwa/TripleDESKeyWrap.java b/libjava/classpath/gnu/javax/crypto/kwa/TripleDESKeyWrap.java new file mode 100644 index 000000000..28b16cf31 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/kwa/TripleDESKeyWrap.java @@ -0,0 +1,292 @@ +/* TripleDESKeyWrap.java -- FIXME: briefly describe file purpose + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath 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; either version 2, or (at your option) +any later version. + +GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.kwa; + +import gnu.java.security.Registry; +import gnu.java.security.hash.Sha160; +import gnu.javax.crypto.assembly.Assembly; +import gnu.javax.crypto.assembly.Cascade; +import gnu.javax.crypto.assembly.Direction; +import gnu.javax.crypto.assembly.Stage; +import gnu.javax.crypto.assembly.Transformer; +import gnu.javax.crypto.assembly.TransformerException; +import gnu.javax.crypto.cipher.IBlockCipher; +import gnu.javax.crypto.cipher.TripleDES; +import gnu.javax.crypto.mode.IMode; +import gnu.javax.crypto.mode.ModeFactory; + +import java.security.InvalidKeyException; +import java.security.SecureRandom; +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; + +/** + * The GNU implementation of the Triple DES Key Wrap Algorithm as described in + * [1]. + * <p> + * <b>IMPORTANT</b>: This class is NOT thread safe. + * <p> + * References: + * <ol> + * <li><a href="http://www.rfc-archive.org/getrfc.php?rfc=3217">Triple-DES and + * RC2 Key Wrapping</a>.</li> + * <li><a href="http://www.w3.org/TR/xmlenc-core/">XML Encryption Syntax and + * Processing</a>.</li> + * </ol> + */ +public class TripleDESKeyWrap + extends BaseKeyWrappingAlgorithm +{ + private static final byte[] DEFAULT_IV = new byte[] { + (byte) 0x4A, (byte) 0xDD, (byte) 0xA2, (byte) 0x2C, + (byte) 0x79, (byte) 0xE8, (byte) 0x21, (byte) 0x05 }; + + private Assembly asm; + private HashMap asmAttributes = new HashMap(); + private HashMap modeAttributes = new HashMap(); + private Sha160 sha = new Sha160(); + private SecureRandom rnd; + + public TripleDESKeyWrap() + { + super(Registry.TRIPLEDES_KWA); + } + + protected void engineInit(Map attributes) throws InvalidKeyException + { + rnd = (SecureRandom) attributes.get(IKeyWrappingAlgorithm.SOURCE_OF_RANDOMNESS); + IMode des3CBC = ModeFactory.getInstance(Registry.CBC_MODE, new TripleDES(), 8); + Stage des3CBCStage = Stage.getInstance(des3CBC, Direction.FORWARD); + Cascade cascade = new Cascade(); + Object modeNdx = cascade.append(des3CBCStage); + + asmAttributes.put(modeNdx, modeAttributes); + + asm = new Assembly(); + asm.addPreTransformer(Transformer.getCascadeTransformer(cascade)); + + modeAttributes.put(IBlockCipher.KEY_MATERIAL, + attributes.get(KEY_ENCRYPTION_KEY_MATERIAL)); + asmAttributes.put(Assembly.DIRECTION, Direction.FORWARD); + } + + protected byte[] engineWrap(byte[] in, int inOffset, int length) + { + // The same key wrap algorithm is used for both Two-key Triple-DES and + // Three-key Triple-DES keys. When a Two-key Triple-DES key is to be + // wrapped, a third DES key with the same value as the first DES key is + // created. Thus, all wrapped Triple-DES keys include three DES keys. + if (length != 16 && length != 24) + throw new IllegalArgumentException("Only 2- and 3-key Triple DES keys are alowed"); + + byte[] CEK = new byte[24]; + if (length == 16) + { + System.arraycopy(in, inOffset, CEK, 0, 16); + System.arraycopy(in, inOffset, CEK, 16, 8); + } + else + System.arraycopy(in, inOffset, CEK, 0, 24); + + // TODO: check for the following: + // However, a Two-key Triple-DES key MUST NOT be used to wrap a Three- + // key Triple-DES key that is comprised of three unique DES keys. + + // 1. Set odd parity for each of the DES key octets comprising the + // Three-Key Triple-DES key that is to be wrapped, call the result + // CEK. + TripleDES.adjustParity(CEK, 0); + + // 2. Compute an 8 octet key checksum value on CEK as described above in + // Section 2, call the result ICV. + sha.update(CEK); + byte[] hash = sha.digest(); + byte[] ICV = new byte[8]; + System.arraycopy(hash, 0, ICV, 0, 8); + + // 3. Let CEKICV = CEK || ICV. + byte[] CEKICV = new byte[CEK.length + ICV.length]; + System.arraycopy(CEK, 0, CEKICV, 0, CEK.length); + System.arraycopy(ICV, 0, CEKICV, CEK.length, ICV.length); + + // 4. Generate 8 octets at random, call the result IV. + byte[] IV = new byte[8]; + nextRandomBytes(IV); + + // 5. Encrypt CEKICV in CBC mode using the key-encryption key. Use the + // random value generated in the previous step as the initialization + // vector (IV). Call the ciphertext TEMP1. + modeAttributes.put(IMode.IV, IV); + asmAttributes.put(Assembly.DIRECTION, Direction.FORWARD); + byte[] TEMP1; + try + { + asm.init(asmAttributes); + TEMP1 = asm.lastUpdate(CEKICV); + } + catch (TransformerException x) + { + throw new RuntimeException(x); + } + + // 6. Let TEMP2 = IV || TEMP1. + byte[] TEMP2 = new byte[IV.length + TEMP1.length]; + System.arraycopy(IV, 0, TEMP2, 0, IV.length); + System.arraycopy(TEMP1, 0, TEMP2, IV.length, TEMP1.length); + + // 7. Reverse the order of the octets in TEMP2. That is, the most + // significant (first) octet is swapped with the least significant + // (last) octet, and so on. Call the result TEMP3. + byte[] TEMP3 = new byte[TEMP2.length]; + for (int i = 0, j = TEMP2.length - 1; i < TEMP2.length; i++, j--) + TEMP3[j] = TEMP2[i]; + + // 8. Encrypt TEMP3 in CBC mode using the key-encryption key. Use an + // initialization vector (IV) of 0x4adda22c79e82105. The ciphertext + // is 40 octets long. + modeAttributes.put(IMode.IV, DEFAULT_IV); + asmAttributes.put(Assembly.DIRECTION, Direction.FORWARD); + byte[] result; + try + { + asm.init(asmAttributes); + result = asm.lastUpdate(TEMP3); + } + catch (TransformerException x) + { + throw new RuntimeException(x); + } + return result; + } + + protected byte[] engineUnwrap(byte[] in, int inOffset, int length) + throws KeyUnwrappingException + { + // 1. If the wrapped key is not 40 octets, then error. + if (length != 40) + throw new IllegalArgumentException("length MUST be 40"); + + // 2. Decrypt the wrapped key in CBC mode using the key-encryption key. + // Use an initialization vector (IV) of 0x4adda22c79e82105. Call the + // output TEMP3. + modeAttributes.put(IMode.IV, DEFAULT_IV); + asmAttributes.put(Assembly.DIRECTION, Direction.REVERSED); + byte[] TEMP3; + try + { + asm.init(asmAttributes); + TEMP3 = asm.lastUpdate(in, inOffset, 40); + } + catch (TransformerException x) + { + throw new RuntimeException(x); + } + + // 3. Reverse the order of the octets in TEMP3. That is, the most + // significant (first) octet is swapped with the least significant + // (last) octet, and so on. Call the result TEMP2. + byte[] TEMP2 = new byte[40]; + for (int i = 0, j = 40 - 1; i < 40; i++, j--) + TEMP2[j] = TEMP3[i]; + + // 4. Decompose TEMP2 into IV and TEMP1. IV is the most significant + // (first) 8 octets, and TEMP1 is the least significant (last) 32 + // octets. + byte[] IV = new byte[8]; + byte[] TEMP1 = new byte[32]; + System.arraycopy(TEMP2, 0, IV, 0, 8); + System.arraycopy(TEMP2, 8, TEMP1, 0, 32); + + // 5. Decrypt TEMP1 in CBC mode using the key-encryption key. Use the + // IV value from the previous step as the initialization vector. + // Call the ciphertext CEKICV. + modeAttributes.put(IMode.IV, IV); + asmAttributes.put(Assembly.DIRECTION, Direction.REVERSED); + byte[] CEKICV; + try + { + asm.init(asmAttributes); + CEKICV = asm.lastUpdate(TEMP1, 0, 32); + } + catch (TransformerException x) + { + throw new RuntimeException(x); + } + + // 6. Decompose CEKICV into CEK and ICV. CEK is the most significant + // (first) 24 octets, and ICV is the least significant (last) 8 + // octets. + byte[] CEK = new byte[24]; + byte[] ICV = new byte[8]; + System.arraycopy(CEKICV, 0, CEK, 0, 24); + System.arraycopy(CEKICV, 24, ICV, 0, 8); + + // 7. Compute an 8 octet key checksum value on CEK as described above in + // Section 2. If the computed key checksum value does not match the + // decrypted key checksum value, ICV, then error. + sha.update(CEK); + byte[] hash = sha.digest(); + byte[] computedICV = new byte[8]; + System.arraycopy(hash, 0, computedICV, 0, 8); + if (! Arrays.equals(ICV, computedICV)) + throw new KeyUnwrappingException("ICV and computed ICV MUST match"); + + // 8. Check for odd parity each of the DES key octets comprising CEK. + // If parity is incorrect, then error. + if (! TripleDES.isParityAdjusted(CEK, 0)) + throw new KeyUnwrappingException("Triple-DES key parity MUST be adjusted"); + + // 9. Use CEK as a Triple-DES key. + return CEK; + } + + /** + * Fills the designated byte array with random data. + * + * @param buffer the byte array to fill with random data. + */ + private void nextRandomBytes(byte[] buffer) + { + if (rnd != null) + rnd.nextBytes(buffer); + else + getDefaultPRNG().nextBytes(buffer); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/mac/BaseMac.java b/libjava/classpath/gnu/javax/crypto/mac/BaseMac.java new file mode 100644 index 000000000..4c524e905 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/mac/BaseMac.java @@ -0,0 +1,127 @@ +/* BaseMac.java -- + Copyright (C) 2001, 2002, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.mac; + +import gnu.java.security.hash.IMessageDigest; + +import java.security.InvalidKeyException; +import java.util.Map; + +/** + * A base abstract class to facilitate <i>MAC</i> (Message Authentication Code) + * implementations. + */ +public abstract class BaseMac + implements IMac +{ + /** The canonical name prefix of the <i>MAC</i>. */ + protected String name; + /** Reference to the underlying hash algorithm instance. */ + protected IMessageDigest underlyingHash; + /** The length of the truncated output in bytes. */ + protected int truncatedSize; + + /** + * Trivial constructor for use by concrete subclasses. + * + * @param name the canonical name of this instance. + */ + protected BaseMac(String name) + { + super(); + + this.name = name; + } + + /** + * Trivial constructor for use by concrete subclasses. + * + * @param name the canonical name of this instance. + * @param underlyingHash the underlying message digest algorithm instance. + */ + protected BaseMac(String name, IMessageDigest underlyingHash) + { + this(name); + + if (underlyingHash != null) + truncatedSize = underlyingHash.hashSize(); + this.underlyingHash = underlyingHash; + } + + public String name() + { + return name; + } + + public int macSize() + { + return truncatedSize; + } + + public void update(byte b) + { + underlyingHash.update(b); + } + + public void update(byte[] b, int offset, int len) + { + underlyingHash.update(b, offset, len); + } + + public void reset() + { + underlyingHash.reset(); + } + + public Object clone() throws CloneNotSupportedException + { + BaseMac result = (BaseMac) super.clone(); + if (this.underlyingHash != null) + result.underlyingHash = (IMessageDigest) this.underlyingHash.clone(); + + return result; + } + + public abstract void init(Map attributes) throws InvalidKeyException, + IllegalStateException; + + public abstract byte[] digest(); + + public abstract boolean selfTest(); +} diff --git a/libjava/classpath/gnu/javax/crypto/mac/HMac.java b/libjava/classpath/gnu/javax/crypto/mac/HMac.java new file mode 100644 index 000000000..ae2cd3ce2 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/mac/HMac.java @@ -0,0 +1,263 @@ +/* HMac.java -- + Copyright (C) 2001, 2002, 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.mac; + +import gnu.java.security.Registry; +import gnu.java.security.hash.IMessageDigest; +import gnu.java.security.hash.MD5; +import gnu.java.security.util.Util; + +import java.security.InvalidKeyException; +import java.util.HashMap; +import java.util.Map; + +/** + * The implementation of the <i>HMAC</i> (Keyed-Hash Message Authentication + * Code). + * <p> + * <i>HMAC</i> can be used in combination with any iterated cryptographic hash + * function. <i>HMAC</i> also uses a <i>secret key</i> for calculation and + * verification of the message authentication values. The main goals behind this + * construction are: + * <ul> + * <li>To use, without modifications, available hash functions. In particular, + * hash functions that perform well in software, and for which code is freely + * and widely available.</li> + * <li>To preserve the original performance of the hash function without + * incurring a significant degradation.</li> + * <li>To use and handle keys in a simple way.</li> + * <li>To have a well understood cryptographic analysis of the strength of the + * authentication mechanism based on reasonable assumptions on the underlying + * hash function.</li> + * <li>To allow for easy replaceability of the underlying hash function in case + * that faster or more secure hash functions are found or required.</li> + * </ul> + * <p> + * References: + * <ol> + * <li><a href="http://www.ietf.org/rfc/rfc-2104.txt">RFC 2104</a>HMAC: + * Keyed-Hashing for Message Authentication.<br> + * H. Krawczyk, M. Bellare, and R. Canetti.</li> + * </ol> + */ +public class HMac + extends BaseMac + implements Cloneable +{ + public static final String USE_WITH_PKCS5_V2 = "gnu.crypto.hmac.pkcs5"; + private static final byte IPAD_BYTE = 0x36; + private static final byte OPAD_BYTE = 0x5C; + /** caches the result of the correctness test, once executed. */ + private static Boolean valid; + protected int macSize; + protected int blockSize; + protected IMessageDigest ipadHash; + protected IMessageDigest opadHash; + protected byte[] ipad; + + /** + * Trivial constructor for use by concrete subclasses. + * + * @param underlyingHash the underlying hash algorithm instance. + */ + protected HMac(IMessageDigest underlyingHash) + { + super(Registry.HMAC_NAME_PREFIX + underlyingHash.name(), underlyingHash); + + this.blockSize = underlyingHash.blockSize(); + this.macSize = underlyingHash.hashSize(); + ipadHash = opadHash = null; + } + + public Object clone() throws CloneNotSupportedException + { + HMac result = (HMac) super.clone(); + if (this.ipadHash != null) + result.ipadHash = (IMessageDigest) this.ipadHash.clone(); + if (this.opadHash != null) + result.opadHash = (IMessageDigest) this.opadHash.clone(); + if (this.ipad != null) + result.ipad = (byte[]) this.ipad.clone(); + + return result; + } + + public void init(Map attributes) throws InvalidKeyException, + IllegalStateException + { + Integer ts = (Integer) attributes.get(TRUNCATED_SIZE); + truncatedSize = (ts == null ? macSize : ts.intValue()); + if (truncatedSize < (macSize / 2)) + throw new IllegalArgumentException("Truncated size too small"); + else if (truncatedSize < 10) + throw new IllegalArgumentException("Truncated size less than 80 bits"); + + // we dont use/save the key outside this method + byte[] K = (byte[]) attributes.get(MAC_KEY_MATERIAL); + if (K == null) + { // take it as an indication to re-use previous key if set + if (ipadHash == null) + throw new InvalidKeyException("Null key"); + // we already went through the motions; ie. up to step #4. re-use + underlyingHash = (IMessageDigest) ipadHash.clone(); + return; + } + + // for HMACs used in key-derivation functions (e.g. PBKDF2) the key material + // need not be >= the (output) block size of the underlying algorithm + Boolean pkcs5 = (Boolean) attributes.get(USE_WITH_PKCS5_V2); + if (pkcs5 == null) + pkcs5 = Boolean.FALSE; + if (K.length < macSize && ! pkcs5.booleanValue()) + throw new InvalidKeyException("Key too short"); + + if (K.length > blockSize) + { + // (0) replace K with HASH(K) if K is larger than the hash's block size. + // Then pad with zeros until it is the correct size (the next `if'). + underlyingHash.update(K, 0, K.length); + K = underlyingHash.digest(); + } + if (K.length < blockSize) + { + // (1) append zeros to the end of K to create a B byte string (e.g., if + // K is of length 20 bytes and B=64, then K will be appended with 44 + // zero bytes 0x00) + int limit = (K.length > blockSize) ? blockSize : K.length; + byte[] newK = new byte[blockSize]; + System.arraycopy(K, 0, newK, 0, limit); + K = newK; + } + underlyingHash.reset(); + opadHash = (IMessageDigest) underlyingHash.clone(); + if (ipad == null) + ipad = new byte[blockSize]; + // (2) XOR (bitwise exclusive-OR) the B byte string computed in step (1) + // with ipad + // (3) append the stream of data 'text' to the B byte string resulting from + // step (2) + // (4) apply H to the stream generated in step (3) + for (int i = 0; i < blockSize; i++) + ipad[i] = (byte)(K[i] ^ IPAD_BYTE); + for (int i = 0; i < blockSize; i++) + opadHash.update((byte)(K[i] ^ OPAD_BYTE)); + underlyingHash.update(ipad, 0, blockSize); + ipadHash = (IMessageDigest) underlyingHash.clone(); + K = null; + } + + public void reset() + { + super.reset(); + if (ipad != null) + { + underlyingHash.update(ipad, 0, blockSize); + ipadHash = (IMessageDigest) underlyingHash.clone(); + } + } + + public byte[] digest() + { + if (ipadHash == null) + throw new IllegalStateException("HMAC not initialised"); + byte[] out = underlyingHash.digest(); + // (5) XOR (bitwise exclusive-OR) the B byte string computed in step (1) + // with opad + underlyingHash = (IMessageDigest) opadHash.clone(); + // (6) append the H result from step (4) to the B byte string resulting from + // step (5) + underlyingHash.update(out, 0, macSize); + // (7) apply H to the stream generated in step (6) and output the result + out = underlyingHash.digest(); // which also resets the underlying hash + // truncate and return + if (truncatedSize == macSize) + return out; + byte[] result = new byte[truncatedSize]; + System.arraycopy(out, 0, result, 0, truncatedSize); + return result; + } + + public boolean selfTest() + { + if (valid == null) + { + try + { + IMac mac = new HMac(new MD5()); // use rfc-2104 test vectors + String tv1 = "9294727A3638BB1C13F48EF8158BFC9D"; + String tv3 = "56BE34521D144C88DBB8C733F0E8B3F6"; + byte[] k1 = new byte[] { + 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, + 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B }; + byte[] k3 = new byte[] { + (byte) 0xAA, (byte) 0xAA, (byte) 0xAA, (byte) 0xAA, + (byte) 0xAA, (byte) 0xAA, (byte) 0xAA, (byte) 0xAA, + (byte) 0xAA, (byte) 0xAA, (byte) 0xAA, (byte) 0xAA, + (byte) 0xAA, (byte) 0xAA, (byte) 0xAA, (byte) 0xAA }; + byte[] data = new byte[50]; + for (int i = 0; i < 50;) + data[i++] = (byte) 0xDD; + + HashMap map = new HashMap(); + // test vector #1 + map.put(MAC_KEY_MATERIAL, k1); + mac.init(map); + mac.update("Hi There".getBytes("ASCII"), 0, 8); + if (! tv1.equals(Util.toString(mac.digest()))) + valid = Boolean.FALSE; + + // test #2 is not used since it causes a "Key too short" exception + + // test vector #3 + map.put(MAC_KEY_MATERIAL, k3); + mac.init(map); + mac.update(data, 0, 50); + if (! tv3.equals(Util.toString(mac.digest()))) + valid = Boolean.FALSE; + valid = Boolean.TRUE; + } + catch (Exception x) + { + x.printStackTrace(System.err); + valid = Boolean.FALSE; + } + } + return valid.booleanValue(); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/mac/HMacFactory.java b/libjava/classpath/gnu/javax/crypto/mac/HMacFactory.java new file mode 100644 index 000000000..0afd8c6ac --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/mac/HMacFactory.java @@ -0,0 +1,111 @@ +/* HMacFactory.java -- + Copyright (C) 2001, 2002, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.mac; + +import gnu.java.security.Registry; +import gnu.java.security.hash.HashFactory; + +import java.util.Collections; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Set; + +/** + * A <i>Factory</i> to instantiate Keyed-Hash Message Authentication Code + * (HMAC) algorithm instances. + */ +public class HMacFactory + implements Registry +{ + /** Trivial constructor to enforce <i>Singleton</i> pattern. */ + private HMacFactory() + { + super(); + } + + /** + * Return an instance of a <i>HMAC</i> algorithm given the name of its + * underlying hash function, prefixed with the literal defined in + * {@link Registry#HMAC_NAME_PREFIX}. + * + * @param name the fully qualified name of the underlying algorithm: composed + * as the concatenation of a literal prefix (see + * {@link Registry#HMAC_NAME_PREFIX}) and the name of the underlying + * hash algorithm. + * @return an instance of the <i>HMAC</i> algorithm, or <code>null</code> + * if none can be constructed. + * @exception InternalError if the implementation does not pass its self-test. + */ + public static IMac getInstance(String name) + { + if (name == null) + return null; + + name = name.trim(); + name = name.toLowerCase(); + if (! name.startsWith(HMAC_NAME_PREFIX)) + return null; + + // strip the prefix + name = name.substring(HMAC_NAME_PREFIX.length()).trim(); + IMac result = new HMac(HashFactory.getInstance(name)); + if (result != null && ! result.selfTest()) + throw new InternalError(result.name()); + + return result; + } + + /** + * <p> + * Returns a {@link java.util.Set} of names of <i>HMAC</i> algorithms + * supported by this <i>Factory</i>. + * </p> + * + * @return a {@link java.util.Set} of HMAC algorithm names (Strings). + */ + public static final Set getNames() + { + Set hashNames = HashFactory.getNames(); + HashSet hs = new HashSet(); + for (Iterator it = hashNames.iterator(); it.hasNext();) + hs.add(HMAC_NAME_PREFIX + ((String) it.next())); + + return Collections.unmodifiableSet(hs); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/mac/IMac.java b/libjava/classpath/gnu/javax/crypto/mac/IMac.java new file mode 100644 index 000000000..a9582564d --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/mac/IMac.java @@ -0,0 +1,181 @@ +/* IMac.java -- + Copyright (C) 2001, 2002, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.mac; + +import java.security.InvalidKeyException; +import java.util.Map; + +/** + * The basic visible methods of any MAC (Message Authentication Code) algorithm. + * <p> + * A <i>MAC</i> provides a way to check the integrity of information + * transmitted over, or stored in, an unreliable medium, based on a secret key. + * Typically, <i>MAC</i>s are used between two parties, that share a common + * secret key, in order to validate information transmitted between them. + * <p> + * When a <i>MAC</i> algorithm is based on a cryptographic hash function, it is + * then called to a <i>HMAC</i> (Hashed Message Authentication Code) --see <a + * href="http://www.ietf.org/rfc/rfc-2104.txt">RFC-2104</a>. + * <p> + * Another type of <i>MAC</i> algorithms exist: UMAC or <i>Universal Message + * Authentication Code</i>, described in <a + * href="http://www.ietf.org/internet-drafts/draft-krovetz-umac-01.txt"> + * draft-krovetz-umac-01.txt</a>. + * <p> + * With <i>UMAC</i>s, the sender and receiver share a common secret key (the + * <i>MAC</i> key) which determines: + * <ul> + * <li>The key for a <i>universal hash function</i>. This hash function is + * <i>non-cryptographic</i>, in the sense that it does not need to have any + * cryptographic <i>hardness</i> property. Rather, it needs to satisfy some + * combinatorial property, which can be proven to hold without relying on + * unproven hardness assumptions.</li> + * <li>The key for a <i>pseudorandom function</i>. This is where one needs a + * cryptographic hardness assumption. The pseudorandom function may be obtained + * from a <i>block cipher</i> or a <i>cryptographic hash function</i>. </li> + * </ul> + * <p> + * References: + * <ol> + * <li><a href="http://www.ietf.org/rfc/rfc-2104.txt">RFC 2104</a>HMAC: + * Keyed-Hashing for Message Authentication.<br> + * H. Krawczyk, M. Bellare, and R. Canetti.</li> + * <li><a href="http://www.ietf.org/internet-drafts/draft-krovetz-umac-01.txt"> + * UMAC</a>: Message Authentication Code using Universal Hashing.<br> + * T. Krovetz, J. Black, S. Halevi, A. Hevia, H. Krawczyk, and P. Rogaway.</li> + * </ol> + */ +public interface IMac +{ + /** + * Property name of the user-supplied key material. The value associated to + * this property name is taken to be a byte array. + */ + String MAC_KEY_MATERIAL = "gnu.crypto.mac.key.material"; + /** + * Property name of the desired truncated output size in bytes. The value + * associated to this property name is taken to be an integer. If no value is + * specified in the attributes map at initialisation time, then all bytes of + * the underlying hash algorithm's output are emitted. + * <p> + * This implementation, follows the recommendation of the <i>RFC 2104</i> + * authors; specifically: + * <pre> + * We recommend that the output length t be not less than half the + * length of the hash output (to match the birthday attack bound) + * and not less than 80 bits (a suitable lower bound on the number + * of bits that need to be predicted by an attacker). + * </pre> + */ + String TRUNCATED_SIZE = "gnu.crypto.mac.truncated.size"; + + /** + * Returns the canonical name of this algorithm. + * + * @return the canonical name of this algorithm. + */ + String name(); + + /** + * Returns the output length in bytes of this <i>MAC</i> algorithm. + * + * @return the output length in bytes of this <i>MAC</i> algorithm. + */ + int macSize(); + + /** + * Initialises the algorithm with designated attributes. Permissible names and + * values are described in the class documentation above. + * + * @param attributes a set of name-value pairs that describe the desired + * future instance behaviour. + * @exception InvalidKeyException if the key data is invalid. + * @exception IllegalStateException if the instance is already initialised. + * @see #MAC_KEY_MATERIAL + */ + void init(Map attributes) throws InvalidKeyException, IllegalStateException; + + /** + * Continues a <i>MAC</i> operation using the input byte. + * + * @param b the input byte to digest. + */ + void update(byte b); + + /** + * Continues a <i>MAC</i> operation, by filling the buffer, processing data + * in the algorithm's MAC_SIZE-bit block(s), updating the context and count, + * and buffering the remaining bytes in buffer for the next operation. + * + * @param in the input block. + * @param offset start of meaningful bytes in input block. + * @param length number of bytes, in input block, to consider. + */ + void update(byte[] in, int offset, int length); + + /** + * Completes the <i>MAC</i> by performing final operations such as padding + * and resetting the instance. + * + * @return the array of bytes representing the <i>MAC</i> value. + */ + byte[] digest(); + + /** + * Resets the algorithm instance for re-initialisation and use with other + * characteristics. This method always succeeds. + */ + void reset(); + + /** + * A basic test. Ensures that the MAC of a pre-determined message is equal to + * a known pre-computed value. + * + * @return <code>true</code> if the implementation passes a basic self-test. + * Returns <code>false</code> otherwise. + */ + boolean selfTest(); + + /** + * Returns a clone copy of this instance. + * + * @return a clone copy of this instance. + */ + Object clone() throws CloneNotSupportedException; +} diff --git a/libjava/classpath/gnu/javax/crypto/mac/MacFactory.java b/libjava/classpath/gnu/javax/crypto/mac/MacFactory.java new file mode 100644 index 000000000..5e3b50f7f --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/mac/MacFactory.java @@ -0,0 +1,130 @@ +/* MacFactory.java -- + Copyright (C) 2001, 2002, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.mac; + +import gnu.java.security.Registry; +import gnu.javax.crypto.cipher.CipherFactory; +import gnu.javax.crypto.cipher.IBlockCipher; + +import java.util.Collections; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Set; + +/** + * A <i>Factory</i> that instantiates instances of every supported Message + * Authentication Code algorithms, including all <i>HMAC</i> algorithms. + */ +public class MacFactory + implements Registry +{ + private static Set names; + + /** Trivial constructor to enforce <i>Singleton</i> pattern. */ + private MacFactory() + { + super(); + } + + /** + * Returns an instance of a <i>MAC</i> algorithm given its name. + * + * @param name the name of the MAC algorithm. + * @return an instance of the <i>MAC</i> algorithm, or <code>null</code> if + * none can be constructed. + * @exception InternalError if the implementation does not pass its self-test. + */ + public static IMac getInstance(String name) + { + if (name == null) + return null; + + name = name.trim(); + name = name.toLowerCase(); + if (name.startsWith(HMAC_NAME_PREFIX)) + return HMacFactory.getInstance(name); + + if (name.startsWith(OMAC_PREFIX)) + { + name = name.substring(OMAC_PREFIX.length()); + IBlockCipher cipher = CipherFactory.getInstance(name); + if (cipher == null) + return null; + return new OMAC(cipher); + } + IMac result = null; + if (name.equalsIgnoreCase(UHASH32)) + result = new UHash32(); + else if (name.equalsIgnoreCase(UMAC32)) + result = new UMac32(); + else if (name.equalsIgnoreCase(TMMH16)) + result = new TMMH16(); + + if (result != null && ! result.selfTest()) + throw new InternalError(result.name()); + + return result; + } + + /** + * Returns a {@link Set} of names of <i>MAC</i> algorithms supported by this + * <i>Factory</i>. + * + * @return a {@link Set} of MAC names (Strings). + */ + public static final Set getNames() + { + synchronized (MacFactory.class) + { + if (names == null) + { + HashSet hs = new HashSet(); + hs.addAll(HMacFactory.getNames()); + hs.add(UHASH32); + hs.add(UMAC32); + hs.add(TMMH16); + for (Iterator it = CipherFactory.getNames().iterator(); it.hasNext();) + hs.add(OMAC_PREFIX + it.next()); + + names = Collections.unmodifiableSet(hs); + } + } + return names; + } +} diff --git a/libjava/classpath/gnu/javax/crypto/mac/MacInputStream.java b/libjava/classpath/gnu/javax/crypto/mac/MacInputStream.java new file mode 100644 index 000000000..7ea808aa9 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/mac/MacInputStream.java @@ -0,0 +1,124 @@ +/* MacInputStream.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.mac; + +import java.io.FilterInputStream; +import java.io.InputStream; +import java.io.IOException; + +/** + * A filtering input stream that computes a MAC (message authentication code) + * over all data read from the stream. + */ +public class MacInputStream + extends FilterInputStream +{ + /** The digesting state. The MAC is updated only if this flag is true. */ + private boolean digesting; + /** The MAC being updated. */ + private IMac mac; + + /** + * Creates a new MacInputStream. The stream is initially set to digest data + * written, the <i>mac</i> argument must have already been initialized, and + * the <i>mac</i> argument is <b>not</b> cloned. + * + * @param in The underlying input stream. + * @param mac The mac instance to use. + */ + public MacInputStream(InputStream in, IMac mac) + { + super(in); + if (mac == null) + throw new NullPointerException(); + this.mac = mac; + digesting = true; + } + + /** + * Returns the MAC this stream is updating. + * + * @return The MAC. + */ + public IMac getMac() + { + return mac; + } + + /** + * Sets the MAC this stream is updating, which must have already been + * initialized. The argument is not cloned by this method. + * + * @param mac The new MAC. + * @throws NullPointerException If the argument is null. + */ + public void setMac(IMac mac) + { + if (mac == null) + throw new NullPointerException(); + this.mac = mac; + } + + /** + * Turns the digesting state on or off. When off, the MAC will not be updated + * when data is written to the stream. + * + * @param flag The new digesting state. + */ + public void on(boolean flag) + { + digesting = flag; + } + + public int read() throws IOException + { + int i = in.read(); + if (digesting && i != -1) + mac.update((byte) i); + return i; + } + + public int read(byte[] buf, int off, int len) throws IOException + { + int i = in.read(buf, off, len); + if (digesting && i != -1) + mac.update(buf, off, i); + return i; + } +} diff --git a/libjava/classpath/gnu/javax/crypto/mac/MacOutputStream.java b/libjava/classpath/gnu/javax/crypto/mac/MacOutputStream.java new file mode 100644 index 000000000..2aa352d75 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/mac/MacOutputStream.java @@ -0,0 +1,123 @@ +/* MacOutputStream.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.mac; + +import java.io.FilterOutputStream; +import java.io.IOException; +import java.io.OutputStream; + +/** + * A filtering output stream that computes a MAC (message authentication code) + * over all data written to the stream. + */ +public class MacOutputStream + extends FilterOutputStream +{ + /** The digesting state. The MAC is updated only if this flag is true. */ + private boolean digesting; + /** The MAC being updated. */ + private IMac mac; + + /** + * Creates a new <code>MacOutputStream</code>. The stream is initially set + * to digest data written, the <code>mac</code> argument must have already + * been initialized, and the <code>mac</code> argument is <b>not</b> + * cloned. + * + * @param out The underlying output stream. + * @param mac The mac instance to use. + */ + public MacOutputStream(OutputStream out, IMac mac) + { + super(out); + if (mac == null) + throw new NullPointerException(); + this.mac = mac; + digesting = true; + } + + /** + * Returns the MAC this stream is updating. + * + * @return The MAC. + */ + public IMac getMac() + { + return mac; + } + + /** + * Sets the MAC this stream is updating, which must have already been + * initialized. The argument is not cloned by this method. + * + * @param mac The non-null new MAC. + * @throws NullPointerException If the argument is null. + */ + public void setMac(IMac mac) + { + if (mac == null) + throw new NullPointerException(); + this.mac = mac; + } + + /** + * Turns the digesting state on or off. When off, the MAC will not be updated + * when data is written to the stream. + * + * @param flag The new digesting state. + */ + public void on(boolean flag) + { + digesting = flag; + } + + public void write(int b) throws IOException + { + if (digesting) + mac.update((byte) b); + out.write(b); + } + + public void write(byte[] buf, int off, int len) throws IOException + { + if (digesting) + mac.update(buf, off, len); + out.write(buf, off, len); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/mac/OMAC.java b/libjava/classpath/gnu/javax/crypto/mac/OMAC.java new file mode 100644 index 000000000..6758b314f --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/mac/OMAC.java @@ -0,0 +1,303 @@ +/* OMAC.java -- + Copyright (C) 2004, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.mac; + +import gnu.java.security.Configuration; +import gnu.java.security.Registry; +import gnu.java.security.util.Util; +import gnu.javax.crypto.cipher.CipherFactory; +import gnu.javax.crypto.cipher.IBlockCipher; +import gnu.javax.crypto.mode.IMode; + +import java.security.InvalidKeyException; +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; +import java.util.logging.Logger; + +/** + * The One-Key CBC MAC, OMAC. This message authentication code is based on a + * block cipher in CBC mode. + * <p> + * References: + * <ol> + * <li>Tetsu Iwata and Kaoru Kurosawa, <i><a + * href="http://crypt.cis.ibaraki.ac.jp/omac/docs/omac.pdf">OMAC: One-Key CBC + * MAC</a></i>.</li> + * </ol> + */ +public class OMAC + implements IMac +{ + private static final Logger log = Logger.getLogger(OMAC.class.getName()); + private static final byte C1 = (byte) 0x87; + private static final byte C2 = 0x1b; + // Test key for OMAC-AES-128 + private static final byte[] KEY0 = + Util.toBytesFromString("2b7e151628aed2a6abf7158809cf4f3c"); + // Test MAC for zero-length input. + private static final byte[] DIGEST0 = + Util.toBytesFromString("bb1d6929e95937287fa37d129b756746"); + private static Boolean valid; + private final IBlockCipher cipher; + private final String name; + private IMode mode; + private int blockSize; + private int outputSize; + private byte[] Lu, Lu2; + private byte[] M; + private byte[] Y; + private boolean init; + private int index; + + public OMAC(IBlockCipher cipher) + { + this.cipher = cipher; + this.name = "OMAC-" + cipher.name(); + } + + public Object clone() + { + return new OMAC(cipher); + } + + public String name() + { + return name; + } + + public int macSize() + { + return outputSize; + } + + public void init(Map attrib) throws InvalidKeyException + { + HashMap attrib2 = new HashMap(); + attrib2.put(IBlockCipher.KEY_MATERIAL, attrib.get(MAC_KEY_MATERIAL)); + cipher.reset(); + cipher.init(attrib2); + blockSize = cipher.currentBlockSize(); + Integer os = (Integer) attrib.get(TRUNCATED_SIZE); + if (os != null) + { + outputSize = os.intValue(); + if (outputSize < 0 || outputSize > blockSize) + throw new IllegalArgumentException("truncated size out of range"); + } + else + outputSize = blockSize; + + byte[] L = new byte[blockSize]; + cipher.encryptBlock(L, 0, L, 0); + if (Configuration.DEBUG) + log.fine("L = " + Util.toString(L).toLowerCase()); + if (Lu != null) + { + Arrays.fill(Lu, (byte) 0); + if (Lu.length != blockSize) + Lu = new byte[blockSize]; + } + else + Lu = new byte[blockSize]; + if (Lu2 != null) + { + Arrays.fill(Lu2, (byte) 0); + if (Lu2.length != blockSize) + Lu2 = new byte[blockSize]; + } + else + Lu2 = new byte[blockSize]; + + boolean msb = (L[0] & 0x80) != 0; + for (int i = 0; i < blockSize; i++) + { + Lu[i] = (byte)(L[i] << 1 & 0xFF); + if (i + 1 < blockSize) + Lu[i] |= (byte)((L[i + 1] & 0x80) >> 7); + } + if (msb) + { + if (blockSize == 16) + Lu[Lu.length - 1] ^= C1; + else if (blockSize == 8) + Lu[Lu.length - 1] ^= C2; + else + throw new IllegalArgumentException("unsupported cipher block size: " + + blockSize); + } + if (Configuration.DEBUG) + log.fine("Lu = " + Util.toString(Lu).toLowerCase()); + msb = (Lu[0] & 0x80) != 0; + for (int i = 0; i < blockSize; i++) + { + Lu2[i] = (byte)(Lu[i] << 1 & 0xFF); + if (i + 1 < blockSize) + Lu2[i] |= (byte)((Lu[i + 1] & 0x80) >> 7); + } + if (msb) + { + if (blockSize == 16) + Lu2[Lu2.length - 1] ^= C1; + else + Lu2[Lu2.length - 1] ^= C2; + } + if (Configuration.DEBUG) + log.fine("Lu2 = " + Util.toString(Lu2).toLowerCase()); + if (M != null) + { + Arrays.fill(M, (byte) 0); + if (M.length != blockSize) + M = new byte[blockSize]; + } + else + M = new byte[blockSize]; + if (Y != null) + { + Arrays.fill(Y, (byte) 0); + if (Y.length != blockSize) + Y = new byte[blockSize]; + } + else + Y = new byte[blockSize]; + + index = 0; + init = true; + } + + public void update(byte b) + { + if (! init) + throw new IllegalStateException("not initialized"); + if (index == M.length) + { + process(); + index = 0; + } + M[index++] = b; + } + + public void update(byte[] buf, int off, int len) + { + if (! init) + throw new IllegalStateException("not initialized"); + if (off < 0 || len < 0 || off + len > buf.length) + throw new IndexOutOfBoundsException("size=" + buf.length + "; off=" + off + + "; len=" + len); + for (int i = 0; i < len;) + { + if (index == blockSize) + { + process(); + index = 0; + } + int count = Math.min(blockSize - index, len - i); + System.arraycopy(buf, off + i, M, index, count); + index += count; + i += count; + } + } + + public byte[] digest() + { + byte[] b = new byte[outputSize]; + digest(b, 0); + return b; + } + + public void digest(byte[] out, int off) + { + if (! init) + throw new IllegalStateException("not initialized"); + if (off < 0 || off + outputSize > out.length) + throw new IndexOutOfBoundsException("size=" + out.length + "; off=" + off + + "; len=" + outputSize); + byte[] T = new byte[blockSize]; + byte[] L = Lu; + if (index < blockSize) + { + M[index++] = (byte) 0x80; + while (index < blockSize) + M[index++] = 0; + L = Lu2; + } + for (int i = 0; i < blockSize; i++) + T[i] = (byte)(M[i] ^ Y[i] ^ L[i]); + cipher.encryptBlock(T, 0, T, 0); + System.arraycopy(T, 0, out, off, outputSize); + reset(); + } + + public void reset() + { + index = 0; + if (Y != null) + Arrays.fill(Y, (byte) 0); + if (M != null) + Arrays.fill(M, (byte) 0); + } + + public boolean selfTest() + { + OMAC mac = new OMAC(CipherFactory.getInstance(Registry.AES_CIPHER)); + mac.reset(); + Map attr = new HashMap(); + attr.put(MAC_KEY_MATERIAL, KEY0); + byte[] digest = null; + try + { + mac.init(attr); + digest = mac.digest(); + } + catch (Exception x) + { + return false; + } + if (digest == null) + return false; + return Arrays.equals(DIGEST0, digest); + } + + private void process() + { + for (int i = 0; i < blockSize; i++) + M[i] = (byte)(M[i] ^ Y[i]); + cipher.encryptBlock(M, 0, Y, 0); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/mac/TMMH16.java b/libjava/classpath/gnu/javax/crypto/mac/TMMH16.java new file mode 100644 index 000000000..3427317ab --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/mac/TMMH16.java @@ -0,0 +1,339 @@ +/* TMMH16.java -- + Copyright (C) 2001, 2002, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.mac; + +import gnu.java.security.Registry; +import gnu.java.security.prng.IRandom; +import gnu.java.security.prng.LimitReachedException; + +import java.security.InvalidKeyException; +import java.util.Map; + +/** + * <i>TMMH</i> is a <i>universal</i> hash function suitable for message + * authentication in the Wegman-Carter paradigm, as in the Stream Cipher + * Security Transform. It is simple, quick, and especially appropriate for + * Digital Signal Processors and other processors with a fast multiply + * operation, though a straightforward implementation requires storage equal in + * length to the largest message to be hashed. + * <p> + * <i>TMMH</i> is a simple hash function which maps a key and a message to a + * hash value. There are two versions of TMMH: TMMH/16 and TMMH/32. <i>TMMH</i> + * can be used as a message authentication code, as described in Section 5 (see + * References). + * <p> + * The key, message, and hash value are all octet strings, and the lengths of + * these quantities are denoted as <code>KEY_LENGTH</code>, + * <code>MESSAGE_LENGTH</code>, and <code>TAG_LENGTH</code>, respectively. + * The values of <code>KEY_LENGTH</code> and <code>TAG_LENGTH</code> + * <bold>MUST</bold> be fixed for any particular fixed value of the key, and + * must obey the alignment restrictions described below. + * <p> + * The parameter <code>MAX_HASH_LENGTH</code>, which denotes the maximum + * value which <code>MESSAGE_LENGTH</code> may take, is equal to + * <code>KEY_LENGTH - TAG_LENGTH</code>. + * <p> + * References: + * <ol> + * <li><a + * href="http://www.ietf.org/internet-drafts/draft-mcgrew-saag-tmmh-01.txt"> The + * Truncated Multi-Modular Hash Function (TMMH)</a>, David A. McGrew.</li> + * </ol> + */ +public class TMMH16 + extends BaseMac + implements Cloneable +{ + public static final String TAG_LENGTH = "gnu.crypto.mac.tmmh.tag.length"; + public static final String KEYSTREAM = "gnu.crypto.mac.tmmh.keystream"; + public static final String PREFIX = "gnu.crypto.mac.tmmh.prefix"; + private static final int P = (1 << 16) + 1; // the TMMH/16 prime + /** caches the result of the correctness test, once executed. */ + private static Boolean valid; + private int tagWords = 0; // the tagLength expressed in words + private IRandom keystream = null; // the keystream generator + private byte[] prefix; // mask to use when operating as an authentication f. + private long keyWords; // key words counter + private long msgLength; // in bytes + private long msgWords; // should be = msgLength * WORD_LENGTH + private int[] context; // the tmmh running context; length == TAG_WORDS + private int[] K0; // the first TAG_WORDS words of the keystream + private int[] Ki; // the sliding TAG_WORDS words of the keystream + private int Mi; // current message word being constructed + + /** Trivial 0-arguments constructor. */ + public TMMH16() + { + super(Registry.TMMH16); + } + + public int macSize() + { + return tagWords * 2; + } + + public void init(Map attributes) throws InvalidKeyException, + IllegalStateException + { + int wantTagLength = 0; + Integer tagLength = (Integer) attributes.get(TAG_LENGTH); // get tag length + if (tagLength == null) + { + if (tagWords == 0) // was never set + throw new IllegalArgumentException(TAG_LENGTH); + // else re-use + } + else // check if positive and is divisible by WORD_LENGTH + { + wantTagLength = tagLength.intValue(); + if (wantTagLength < 2 || (wantTagLength % 2 != 0)) + throw new IllegalArgumentException(TAG_LENGTH); + else if (wantTagLength > (512 / 8)) // 512-bits is our maximum + throw new IllegalArgumentException(TAG_LENGTH); + + tagWords = wantTagLength / 2; // init local vars + K0 = new int[tagWords]; + Ki = new int[tagWords]; + context = new int[tagWords]; + } + + prefix = (byte[]) attributes.get(PREFIX); + if (prefix == null) // default to all-zeroes + prefix = new byte[tagWords * 2]; + else // ensure it's as long as it should + { + if (prefix.length != tagWords * 2) + throw new IllegalArgumentException(PREFIX); + } + + IRandom prng = (IRandom) attributes.get(KEYSTREAM); // get keystream + if (prng == null) + { + if (keystream == null) + throw new IllegalArgumentException(KEYSTREAM); + // else reuse + } + else + keystream = prng; + + reset(); // reset context variables + for (int i = 0; i < tagWords; i++) // init starting key words + Ki[i] = K0[i] = getNextKeyWord(keystream); + } + + // The words of the key are denoted as K[1], K[2], ..., K[KEY_WORDS], and the + // words of the message (after zero padding, if needed) are denoted as M[1], + // M[2], ..., M[MSG_WORDS], where MSG_WORDS is the smallest number such that + // 2 * MSG_WORDS is at least MESSAGE_LENGTH, and KEY_WORDS is KEY_LENGTH / 2. + // + // If MESSAGE_LENGTH is greater than MAX_HASH_LENGTH, then the value of + // TMMH/16 is undefined. Implementations MUST indicate an error if asked to + // hash a message with such a length. Otherwise, the hash value is defined + // to be the length TAG_WORDS sequence of words in which the j-th word in the + // sequence is defined as + // + // [ [ K[j] * MESSAGE_LENGTH +32 K[j+1] * M[1] +32 K[j+2] * M[2] + // +32 ... K[j+MSG_WORDS] * M[MSG_WORDS] ] modulo p ] modulo 2^16 + // + // where j ranges from 1 to TAG_WORDS. + public void update(byte b) + { + this.update(b, keystream); + } + + public void update(byte[] b, int offset, int len) + { + for (int i = 0; i < len; i++) + this.update(b[offset + i], keystream); + } + + // For TMMH/16, KEY_LENGTH and TAG_LENGTH MUST be a multiple of two. The key, + // message, and hash value are treated as a sequence of unsigned sixteen bit + // integers in network byte order. (In this section, we call such an integer + // a word.) If MESSAGE_LENGTH is odd, then a zero byte is appended to the + // message to align it on a word boundary, though this process does not + // change the value of MESSAGE_LENGTH. + // + // ... Otherwise, the hash value is defined to be the length TAG_WORDS + // sequence of words in which the j-th word in the sequence is defined as + // + // [ [ K[j] * MESSAGE_LENGTH +32 K[j+1] * M[1] +32 K[j+2] * M[2] + // +32 ... K[j+MSG_WORDS] * M[MSG_WORDS] ] modulo p ] modulo 2^16 + // + // where j ranges from 1 to TAG_WORDS. + // + // Here, TAG_WORDS is equal to TAG_LENGTH / 2, and p is equal to 2^16 + 1. + // The symbol * denotes multiplication and the symbol +32 denotes addition + // modulo 2^32. + public byte[] digest() + { + return this.digest(keystream); + } + + public void reset() + { + msgLength = msgWords = keyWords = 0L; + Mi = 0; + for (int i = 0; i < tagWords; i++) + context[i] = 0; + } + + public boolean selfTest() + { + if (valid == null) + { + // TODO: compute and test equality with one known vector + valid = Boolean.TRUE; + } + return valid.booleanValue(); + } + + public Object clone() throws CloneNotSupportedException + { + TMMH16 result = (TMMH16) super.clone(); + if (this.keystream != null) + result.keystream = (IRandom) this.keystream.clone(); + if (this.prefix != null) + result.prefix = (byte[]) this.prefix.clone(); + if (this.context != null) + result.context = (int[]) this.context.clone(); + if (this.K0 != null) + result.K0 = (int[]) this.K0.clone(); + if (this.Ki != null) + result.Ki = (int[]) this.Ki.clone(); + return result; + } + + /** + * Similar to the same method with one argument, but uses the designated + * random number generator to compute needed keying material. + * + * @param b the byte to process. + * @param prng the source of randomness to use. + */ + public void update(byte b, IRandom prng) + { + Mi <<= 8; // update message buffer + Mi |= b & 0xFF; + msgLength++; // update message length (bytes) + if (msgLength % 2 == 0) // got a full word + { + msgWords++; // update message words counter + System.arraycopy(Ki, 1, Ki, 0, tagWords - 1); // 1. shift Ki up by 1 + Ki[tagWords - 1] = getNextKeyWord(prng); // 2. fill last box of Ki + long t; // temp var to allow working in modulo 2^32 + for (int i = 0; i < tagWords; i++) // 3. update context + { + t = context[i] & 0xFFFFFFFFL; + t += Ki[i] * Mi; + context[i] = (int) t; + } + Mi = 0; // reset message buffer + } + } + + /** + * Similar to the same method with three arguments, but uses the designated + * random number generator to compute needed keying material. + * + * @param b the byte array to process. + * @param offset the starting offset in <code>b</code> to start considering + * the bytes to process. + * @param len the number of bytes in <code>b</code> starting from + * <code>offset</code> to process. + * @param prng the source of randomness to use. + */ + public void update(byte[] b, int offset, int len, IRandom prng) + { + for (int i = 0; i < len; i++) + this.update(b[offset + i], prng); + } + + /** + * Similar to the same method with no arguments, but uses the designated + * random number generator to compute needed keying material. + * + * @param prng the source of randomness to use. + * @return the final result of the algorithm. + */ + public byte[] digest(IRandom prng) + { + doFinalRound(prng); + byte[] result = new byte[tagWords * 2]; + for (int i = 0, j = 0; i < tagWords; i++) + { + result[j] = (byte)((context[i] >>> 8) ^ prefix[j]); + j++; + result[j] = (byte)(context[i] ^ prefix[j]); + j++; + } + reset(); + return result; + } + + private int getNextKeyWord(IRandom prng) + { + int result = 0; + try + { + result = (prng.nextByte() & 0xFF) << 8 | (prng.nextByte() & 0xFF); + } + catch (LimitReachedException x) + { + throw new RuntimeException(String.valueOf(x)); + } + keyWords++; // update key words counter + return result; + } + + private void doFinalRound(IRandom prng) + { + long limit = msgLength; // formula works on real message length + while (msgLength % 2 != 0) + update((byte) 0x00, prng); + long t; + for (int i = 0; i < tagWords; i++) + { + t = context[i] & 0xFFFFFFFFL; + t += K0[i] * limit; + t %= P; + context[i] = (int) t; + } + } +} diff --git a/libjava/classpath/gnu/javax/crypto/mac/UHash32.java b/libjava/classpath/gnu/javax/crypto/mac/UHash32.java new file mode 100644 index 000000000..53513eda9 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/mac/UHash32.java @@ -0,0 +1,758 @@ +/* UHash32.java -- + Copyright (C) 2001, 2002, 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.mac; + +import gnu.java.security.prng.IRandom; +import gnu.java.security.prng.LimitReachedException; +import gnu.javax.crypto.cipher.IBlockCipher; +import gnu.javax.crypto.prng.UMacGenerator; + +import java.io.ByteArrayOutputStream; +import java.math.BigInteger; +import java.security.InvalidKeyException; +import java.util.HashMap; +import java.util.Map; + +/** + * <i>UHASH</i> is a keyed hash function, which takes as input a string of + * arbitrary length, and produces as output a string of fixed length (such as 8 + * bytes). The actual output length depends on the parameter UMAC-OUTPUT-LEN. + * <p> + * <i>UHASH</i> has been shown to be <i>epsilon-ASU</i> ("Almost Strongly + * Universal"), where epsilon is a small (parameter-dependent) real number. + * Informally, saying that a keyed hash function is <i>epsilon-ASU</i> means + * that for any two distinct fixed input strings, the two outputs of the hash + * function with a random key "look almost like a pair of random strings". The + * number epsilon measures how non-random the output strings may be. + * <p> + * <i>UHASH</i> has been designed to be fast by exploiting several + * architectural features of modern commodity processors. It was specifically + * designed for use in <i>UMAC</i>. But <i>UHASH</i> is useful beyond that + * domain, and can be easily adopted for other purposes. + * <p> + * <i>UHASH</i> does its work in three layers. First, a hash function called + * <code>NH</code> is used to compress input messages into strings which are + * typically many times smaller than the input message. Second, the compressed + * message is hashed with an optimized <i>polynomial hash function</i> into a + * fixed-length 16-byte string. Finally, the 16-byte string is hashed using an + * <i>inner-product hash</i> into a string of length WORD-LEN bytes. These + * three layers are repeated (with a modified key) until the outputs total + * UMAC-OUTPUT-LEN bytes. + * <p> + * References: + * <ol> + * <li><a href="http://www.ietf.org/internet-drafts/draft-krovetz-umac-01.txt"> + * UMAC</a>: Message Authentication Code using Universal Hashing.<br> + * T. Krovetz, J. Black, S. Halevi, A. Hevia, H. Krawczyk, and P. Rogaway.</li> + * </ol> + */ +public class UHash32 + extends BaseMac +{ + // UMAC prime values + private static final BigInteger PRIME_19 = BigInteger.valueOf(0x7FFFFL); + private static final BigInteger PRIME_32 = BigInteger.valueOf(0xFFFFFFFBL); + private static final BigInteger PRIME_36 = BigInteger.valueOf(0xFFFFFFFFBL); + private static final BigInteger PRIME_64 = new BigInteger(1, new byte[] { + (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, + (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xC5 }); + private static final BigInteger PRIME_128 = new BigInteger(1, new byte[] { + (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, + (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, + (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, + (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0x61 }); + static final BigInteger TWO = BigInteger.valueOf(2L); + static final long BOUNDARY = TWO.shiftLeft(17).longValue(); + // 2**64 - 2**32 + static final BigInteger LOWER_RANGE = TWO.pow(64).subtract(TWO.pow(32)); + // 2**128 - 2**96 + static final BigInteger UPPER_RANGE = TWO.pow(128).subtract(TWO.pow(96)); + static final byte[] ALL_ZEROES = new byte[32]; + int streams; + L1Hash32[] l1hash; + + /** Trivial 0-arguments constructor. */ + public UHash32() + { + super("uhash32"); + } + + /** + * Private constructor for cloning purposes. + * + * @param that the instance to clone. + */ + private UHash32(UHash32 that) + { + this(); + + this.streams = that.streams; + if (that.l1hash != null) + { + this.l1hash = new L1Hash32[that.streams]; + for (int i = 0; i < that.streams; i++) + if (that.l1hash[i] != null) + this.l1hash[i] = (L1Hash32) that.l1hash[i].clone(); + } + } + + /** + * The prime numbers used in UMAC are: + * <pre> + * +-----+--------------------+---------------------------------------+ + * | x | prime(x) [Decimal] | prime(x) [Hexadecimal] | + * +-----+--------------------+---------------------------------------+ + * | 19 | 2^19 - 1 | 0x0007FFFF | + * | 32 | 2^32 - 5 | 0xFFFFFFFB | + * | 36 | 2^36 - 5 | 0x0000000F FFFFFFFB | + * | 64 | 2^64 - 59 | 0xFFFFFFFF FFFFFFC5 | + * | 128 | 2^128 - 159 | 0xFFFFFFFF FFFFFFFF FFFFFFFF FFFFFF61 | + * +-----+--------------------+---------------------------------------+ + *</pre> + * + * @param n a number of bits. + * @return the largest prime number less than 2**n. + */ + static final BigInteger prime(int n) + { + switch (n) + { + case 19: + return PRIME_19; + case 32: + return PRIME_32; + case 36: + return PRIME_36; + case 64: + return PRIME_64; + case 128: + return PRIME_128; + default: + throw new IllegalArgumentException("Undefined prime(" + + String.valueOf(n) + ")"); + } + } + + public Object clone() + { + return new UHash32(this); + } + + public int macSize() + { + return UMac32.OUTPUT_LEN; + } + + public void init(Map attributes) throws InvalidKeyException, + IllegalStateException + { + byte[] K = (byte[]) attributes.get(MAC_KEY_MATERIAL); + if (K == null) + throw new InvalidKeyException("Null Key"); + if (K.length != UMac32.KEY_LEN) + throw new InvalidKeyException("Invalid Key length: " + + String.valueOf(K.length)); + // Calculate iterations needed to make UMAC-OUTPUT-LEN bytes + streams = (UMac32.OUTPUT_LEN + 3) / 4; + // Define total key needed for all iterations using UMacGenerator. + // L1Key and L3Key1 both reuse most key between iterations. + IRandom kdf1 = new UMacGenerator(); + IRandom kdf2 = new UMacGenerator(); + IRandom kdf3 = new UMacGenerator(); + IRandom kdf4 = new UMacGenerator(); + Map map = new HashMap(); + map.put(IBlockCipher.KEY_MATERIAL, K); + map.put(UMacGenerator.INDEX, Integer.valueOf(0)); + kdf1.init(map); + map.put(UMacGenerator.INDEX, Integer.valueOf(1)); + kdf2.init(map); + map.put(UMacGenerator.INDEX, Integer.valueOf(2)); + kdf3.init(map); + map.put(UMacGenerator.INDEX, Integer.valueOf(3)); + kdf4.init(map); + // need to generate all bytes for use later in a Toepliz construction + byte[] L1Key = new byte[UMac32.L1_KEY_LEN + (streams - 1) * 16]; + try + { + kdf1.nextBytes(L1Key, 0, L1Key.length); + } + catch (LimitReachedException x) + { + x.printStackTrace(System.err); + throw new RuntimeException("KDF for L1Key reached limit"); + } + + l1hash = new L1Hash32[streams]; + for (int i = 0; i < streams; i++) + { + byte[] k1 = new byte[UMac32.L1_KEY_LEN]; + System.arraycopy(L1Key, i * 16, k1, 0, UMac32.L1_KEY_LEN); + byte[] k2 = new byte[24]; + try + { + kdf2.nextBytes(k2, 0, 24); + } + catch (LimitReachedException x) + { + x.printStackTrace(System.err); + throw new RuntimeException("KDF for L2Key reached limit"); + } + byte[] k31 = new byte[64]; + try + { + kdf3.nextBytes(k31, 0, 64); + } + catch (LimitReachedException x) + { + x.printStackTrace(System.err); + throw new RuntimeException("KDF for L3Key1 reached limit"); + } + byte[] k32 = new byte[4]; + try + { + kdf4.nextBytes(k32, 0, 4); + } + catch (LimitReachedException x) + { + x.printStackTrace(System.err); + throw new RuntimeException("KDF for L3Key2 reached limit"); + } + L1Hash32 mac = new L1Hash32(); + mac.init(k1, k2, k31, k32); + l1hash[i] = mac; + } + } + + public void update(byte b) + { + for (int i = 0; i < streams; i++) + l1hash[i].update(b); + } + + public void update(byte[] b, int offset, int len) + { + for (int i = 0; i < len; i++) + this.update(b[offset + i]); + } + + public byte[] digest() + { + byte[] result = new byte[UMac32.OUTPUT_LEN]; + for (int i = 0; i < streams; i++) + { + byte[] partialResult = l1hash[i].digest(); + System.arraycopy(partialResult, 0, result, 4 * i, 4); + } + reset(); + return result; + } + + public void reset() + { + for (int i = 0; i < streams; i++) + l1hash[i].reset(); + } + + public boolean selfTest() + { + return true; + } + + /** + * First hash stage of the UHash32 algorithm. + */ + class L1Hash32 + implements Cloneable + { + private int[] key; // key material as an array of 32-bit ints + private byte[] buffer; // work buffer L1_KEY_LEN long + private int count; // meaningful bytes in buffer + private ByteArrayOutputStream Y; + private long totalCount; + private L2Hash32 l2hash; + private L3Hash32 l3hash; + + /** Trivial 0-arguments constructor. */ + L1Hash32() + { + super(); + + key = new int[UMac32.L1_KEY_LEN / 4]; + buffer = new byte[UMac32.L1_KEY_LEN]; + count = 0; + Y = new ByteArrayOutputStream(); + totalCount = 0L; + } + + /** + * Private constructor for cloning purposes. + * + * @param that the instance to clone. + */ + private L1Hash32(L1Hash32 that) + { + this(); + + System.arraycopy(that.key, 0, this.key, 0, that.key.length); + System.arraycopy(that.buffer, 0, this.buffer, 0, that.count); + this.count = that.count; + byte[] otherY = that.Y.toByteArray(); + this.Y.write(otherY, 0, otherY.length); + this.totalCount = that.totalCount; + if (that.l2hash != null) + this.l2hash = (L2Hash32) that.l2hash.clone(); + if (that.l3hash != null) + this.l3hash = (L3Hash32) that.l3hash.clone(); + } + + public Object clone() + { + return new L1Hash32(this); + } + + public void init(byte[] k1, byte[] k2, byte[] k31, byte[] k32) + { + for (int i = 0, j = 0; i < (UMac32.L1_KEY_LEN / 4); i++) + key[i] = k1[j++] << 24 + | (k1[j++] & 0xFF) << 16 + | (k1[j++] & 0xFF) << 8 + | (k1[j++] & 0xFF); + l2hash = new L2Hash32(k2); + l3hash = new L3Hash32(k31, k32); + } + + public void update(byte b) + { + // Break M into L1_KEY_LEN byte chunks (final chunk may be shorter) + + // Let M_1, M_2, ..., M_t be strings so that M = M_1 || M_2 || .. || + // M_t, and length(M_i) = L1_KEY_LEN for all 0 < i < t. + + // For each chunk, except the last: endian-adjust, NH hash + // and add bit-length. Use results to build Y. + buffer[count] = b; + count++; + totalCount++; + if (count >= UMac32.L1_KEY_LEN) + { + byte[] y = nh32(UMac32.L1_KEY_LEN); + Y.write(y, 0, 8); + + count = 0; + + // For each iteration, extract key and three-layer hash. + // If length(M) <= L1_KEY_LEN, then skip L2-HASH. + if (Y.size() == 16) // we already hashed twice L1_KEY_LEN + { + byte[] A = Y.toByteArray(); + Y.reset(); + l2hash.update(A, 0, 16); + } + } + } + + public byte[] digest() + { + // For the last chunk: pad to 32-byte boundary, endian-adjust, + // NH hash and add bit-length. Concatenate the result to Y. + if (count != 0) + { + if (count % 32 != 0) + { + int limit = 32 * ((count + 31) / 32); + System.arraycopy(ALL_ZEROES, 0, buffer, count, limit - count); + count += limit - count; + } + byte[] y = nh32(count); + Y.write(y, 0, 8); + } + byte[] A = Y.toByteArray(); + Y.reset(); + byte[] B; + if (totalCount <= UMac32.L1_KEY_LEN) + { + // we might have 'update'd the bytes already. check + if (A.length == 0) // we did + B = l2hash.digest(); + else // did not + { + B = new byte[16]; + System.arraycopy(A, 0, B, 8, 8); + } + } + else + { + if (A.length != 0) + l2hash.update(A, 0, A.length); + B = l2hash.digest(); + } + byte[] result = l3hash.digest(B); + reset(); + return result; + } + + public void reset() + { + count = 0; + Y.reset(); + totalCount = 0L; + if (l2hash != null) + l2hash.reset(); + } + + /** + * 5.1 NH-32: NH hashing with a 32-bit word size. + * + * @param len count of bytes, divisible by 32, in buffer to process + * @return Y, string of length 8 bytes. + */ + private byte[] nh32(int len) + { + // Break M and K into 4-byte chunks + int t = len / 4; + // Let M_1, M_2, ..., M_t be 4-byte strings + // so that M = M_1 || M_2 || .. || M_t. + // Let K_1, K_2, ..., K_t be 4-byte strings + // so that K_1 || K_2 || .. || K_t is a prefix of K. + int[] m = new int[t]; + int i; + int j = 0; + for (i = 0, j = 0; i < t; i++) + m[i] = buffer[j++] << 24 + | (buffer[j++] & 0xFF) << 16 + | (buffer[j++] & 0xFF) << 8 + | (buffer[j++] & 0xFF); + // Perform NH hash on the chunks, pairing words for multiplication + // which are 4 apart to accommodate vector-parallelism. + long result = len * 8L; + for (i = 0; i < t; i += 8) + { + result += ((m[i + 0] + key[i + 0]) & 0xFFFFFFFFL) + * ((m[i + 4] + key[i + 4]) & 0xFFFFFFFFL); + result += ((m[i + 1] + key[i + 1]) & 0xFFFFFFFFL) + * ((m[i + 5] + key[i + 5]) & 0xFFFFFFFFL); + result += ((m[i + 2] + key[i + 2]) & 0xFFFFFFFFL) + * ((m[i + 6] + key[i + 6]) & 0xFFFFFFFFL); + result += ((m[i + 3] + key[i + 3]) & 0xFFFFFFFFL) + * ((m[i + 7] + key[i + 7]) & 0xFFFFFFFFL); + } + return new byte[] { + (byte)(result >>> 56), (byte)(result >>> 48), + (byte)(result >>> 40), (byte)(result >>> 32), + (byte)(result >>> 24), (byte)(result >>> 16), + (byte)(result >>> 8), (byte) result }; + } + } + + /** + * Second hash stage of the UHash32 algorithm. + * <p> + * 5.4 L2-HASH-32: Second-layer hash. + * <ul> + * <li>Input:<br> + * K string of length 24 bytes.<br> + * M string of length less than 2^64 bytes.</li> + * <li>Returns:<br> + * Y, string of length 16 bytes.</li> + * </ul> + */ + class L2Hash32 + implements Cloneable + { + private BigInteger k64, k128; + private BigInteger y; + private boolean highBound; + private long bytesSoFar; + private ByteArrayOutputStream buffer; + + L2Hash32(byte[] K) + { + super(); + + if (K.length != 24) + throw new ExceptionInInitializerError("K length is not 24"); + // Extract keys and restrict to special key-sets + // Mask64 = uint2str(0x01FFFFFF01FFFFFF, 8); + // Mask128 = uint2str(0x01FFFFFF01FFFFFF01FFFFFF01FFFFFF, 16); + // k64 = str2uint(K[1..8] and Mask64); + // k128 = str2uint(K[9..24] and Mask128); + int i = 0; + k64 = new BigInteger(1, new byte[] { + (byte)(K[i++] & 0x01), (byte)(K[i++] & 0xFF), + (byte)(K[i++] & 0xFF), (byte)(K[i++] & 0xFF), + (byte)(K[i++] & 0x01), (byte)(K[i++] & 0xFF), + (byte)(K[i++] & 0xFF), (byte)(K[i++] & 0xFF) }); + k128 = new BigInteger(1, new byte[] { + (byte)(K[i++] & 0x01), (byte)(K[i++] & 0xFF), + (byte)(K[i++] & 0xFF), (byte)(K[i++] & 0xFF), + (byte)(K[i++] & 0x01), (byte)(K[i++] & 0xFF), + (byte)(K[i++] & 0xFF), (byte)(K[i++] & 0xFF), + (byte)(K[i++] & 0x01), (byte)(K[i++] & 0xFF), + (byte)(K[i++] & 0xFF), (byte)(K[i++] & 0xFF), + (byte)(K[i++] & 0x01), (byte)(K[i++] & 0xFF), + (byte)(K[i++] & 0xFF), (byte)(K[i++] & 0xFF) }); + y = BigInteger.ONE; + highBound = false; + bytesSoFar = 0L; + } + + private L2Hash32(L2Hash32 that) + { + super(); + + this.k64 = that.k64; + this.k128 = that.k128; + this.y = that.y; + this.highBound = that.highBound; + this.bytesSoFar = that.bytesSoFar; + if (that.buffer != null) + { + byte[] thatbuffer = that.buffer.toByteArray(); + this.buffer = new ByteArrayOutputStream(); + this.buffer.write(thatbuffer, 0, thatbuffer.length); + } + } + + public Object clone() + { + return new L2Hash32(this); + } + + // this is called with either 8-bytes or 16-bytes + void update(byte[] b, int offset, int len) + { + if (len == 0) + return; + + if (! highBound) // do the first (only?) 8-bytes + { + poly(64, LOWER_RANGE, k64, b, offset, 8); + bytesSoFar += 8L; + highBound = (bytesSoFar > BOUNDARY); + if (highBound) // if we just crossed the limit then process y + { + poly(128, UPPER_RANGE, k128, yTo16bytes(), 0, 16); + buffer = new ByteArrayOutputStream(); + } + // do the rest if any + update(b, offset + 8, len - 8); + } + else + { // we're already beyond the 2**17 bytes size limit + // process in chuncks of 16 + buffer.write(b, offset, len); + if (buffer.size() > 16) + { + byte[] bb = buffer.toByteArray(); + poly(128, UPPER_RANGE, k128, bb, 0, 16); + if (bb.length > 16) + buffer.write(bb, 16, bb.length - 16); + } + } + } + + byte[] digest() + { + // If M no more than 2^17 bytes, hash under 64-bit prime, + // otherwise, hash first 2^17 bytes under 64-bit prime and + // remainder under 128-bit prime. + if (! highBound) // y is up-to-date + { + // do nothing + } + else // we may have some bytes in buffer + { + byte[] bb = buffer.toByteArray(); + byte[] lastBlock = new byte[16]; + System.arraycopy(bb, 0, lastBlock, 0, bb.length); + lastBlock[bb.length] = (byte) 0x80; + poly(128, UPPER_RANGE, k128, lastBlock, 0, 16); + } + byte[] result = yTo16bytes(); + reset(); + return result; + } + + void reset() + { + y = BigInteger.ONE; + highBound = false; + bytesSoFar = 0L; + if (buffer != null) + buffer.reset(); + } + + private byte[] yTo16bytes() + { + byte[] yy = y.toByteArray(); + byte[] result = new byte[16]; + if (yy.length > 16) + System.arraycopy(yy, yy.length - 16, result, 0, 16); + else + System.arraycopy(yy, 0, result, 16 - yy.length, yy.length); + + return result; + } + + /** + * 5.3 POLY: Polynomial hash Function Name: POLY + * + * @param wordbits positive integer divisible by 8: called with 64 or 128. + * @param maxwordrange positive integer less than 2**wordbits. + * @param k integer in the range 0 .. prime(wordbits) - 1. + * @param M string with length divisible by (wordbits / 8) bytes. return y, + * integer in the range 0 .. prime(wordbits) - 1. + */ + private void poly(int wordbits, BigInteger maxwordrange, BigInteger k, + byte[] M, int off, int len) + { + byte[] mag = new byte[len]; + System.arraycopy(M, off, mag, 0, len); + // Define constants used for fixing out-of-range words + BigInteger p = prime(wordbits); + BigInteger offset = TWO.pow(wordbits).subtract(p); // 2^wordbits - p; + BigInteger marker = p.subtract(BigInteger.ONE); + // Break M into chunks of length wordbytes bytes + // long n = M.length / wordbytes; + // Let M_1, M_2, ..., M_n be strings of length wordbytes bytes + // so that M = M_1 || M_2 || .. || M_n + + // For each input word, compare it with maxwordrange. If larger + // then hash the words 'marker' and (m - offset), both in range. + // for (int i = 0; i < n; i++) { + BigInteger m = new BigInteger(1, mag); + if (m.compareTo(maxwordrange) >= 0) // m >= maxwordrange + { + y = y.multiply(k).add(marker).mod(p); // (k * y + marker) % p; + y = y.multiply(k).add(m.subtract(offset)).mod(p); // (k * y + (m - offset)) % p; + } + else + y = y.multiply(k).add(m).mod(p); // (k * y + m) % p; + } + } + + /** + * Third hash stage of the UHash32 algorithm. + * <ul> + * <li>Input:<br/> + * K1 string of length 64 bytes.<br/> + * K2 string of length 4 bytes.<br/> + * M string of length 16 bytes.</li> + * <li>Returns:<br/> + * Y, string of length 4 bytes.</li> + * </ul> + */ + class L3Hash32 + implements Cloneable + { + private static final long PRIME_36 = 0x0000000FFFFFFFFBL; + private int[] k = new int[9]; + + /** + * @param K1 string of length 64 bytes. + * @param K2 string of length 4 bytes. + */ + L3Hash32(byte[] K1, byte[] K2) + { + super(); + + // pre-conditions + if (K1.length != 64) + throw new ExceptionInInitializerError("K1 length is not 64"); + if (K2.length != 4) + throw new ExceptionInInitializerError("K2 length is not 4"); + // Break K1 into 8 chunks and convert to integers + for (int i = 0, j = 0; i < 8; i++) + { + long kk = (K1[j++] & 0xFFL) << 56 + | (K1[j++] & 0xFFL) << 48 + | (K1[j++] & 0xFFL) << 40 + | (K1[j++] & 0xFFL) << 32 + | (K1[j++] & 0xFFL) << 24 + | (K1[j++] & 0xFFL) << 16 + | (K1[j++] & 0xFFL) << 8 + | (K1[j++] & 0xFFL); + k[i] = (int)(kk % PRIME_36); + } + k[8] = K2[0] << 24 + | (K2[1] & 0xFF) << 16 + | (K2[2] & 0xFF) << 8 + | (K2[3] & 0xFF); + } + + private L3Hash32(int[] k) + { + super(); + + this.k = k; + } + + public Object clone() + { + return new L3Hash32((int[]) k.clone()); + } + + /** + * @param M string of length 16 bytes. + * @return Y, string of length 4 bytes. + */ + byte[] digest(byte[] M) + { + if (M.length != 16) + throw new IllegalArgumentException("M length is not 16"); + + long m, y = 0L; + for (int i = 0, j = 0; i < 8; i++) + { + // Break M into 8 chunks and convert to integers + m = (M[j++] & 0xFFL) << 8 | (M[j++] & 0xFFL); + // Inner-product hash, extract last 32 bits and affine-translate + // y = (m_1 * k_1 + ... + m_8 * k_8) mod prime(36); + // y = y mod 2^32; + y += (m * (k[i] & 0xFFFFFFFFL)) % PRIME_36; + } + int Y = ((int) y) ^ k[8]; + return new byte[] { + (byte)(Y >>> 24), + (byte)(Y >>> 16), + (byte)(Y >>> 8), + (byte) Y }; + } + } +} diff --git a/libjava/classpath/gnu/javax/crypto/mac/UMac32.java b/libjava/classpath/gnu/javax/crypto/mac/UMac32.java new file mode 100644 index 000000000..6f53424ea --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/mac/UMac32.java @@ -0,0 +1,418 @@ +/* UMac32.java -- + Copyright (C) 2001, 2002, 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.mac; + +import gnu.java.security.Registry; +import gnu.java.security.prng.IRandom; +import gnu.java.security.prng.LimitReachedException; +import gnu.java.security.util.Util; +import gnu.javax.crypto.cipher.CipherFactory; +import gnu.javax.crypto.cipher.IBlockCipher; +import gnu.javax.crypto.prng.UMacGenerator; + +import java.io.UnsupportedEncodingException; +import java.math.BigInteger; +import java.security.InvalidKeyException; +import java.util.HashMap; +import java.util.Map; + +/** + * The implementation of the <i>UMAC</i> (Universal Message Authentication + * Code). + * <p> + * The <i>UMAC</i> algorithms described are <i>parameterized</i>. This means + * that various low-level choices, like the endian convention and the underlying + * cryptographic primitive, have not been fixed. One must choose values for + * these parameters before the authentication tag generated by <i>UMAC</i> (for + * a given message, key, and nonce) becomes fully-defined. In this document we + * provide two collections of parameter settings, and have named the sets + * <i>UMAC16</i> and <i>UMAC32</i>. The parameter sets have been chosen based + * on experimentation and provide good performance on a wide variety of + * processors. <i>UMAC16</i> is designed to excel on processors which provide + * small-scale SIMD parallelism of the type found in Intel's MMX and Motorola's + * AltiVec instruction sets, while <i>UMAC32</i> is designed to do well on + * processors with good 32- and 64- bit support. <i>UMAC32</i> may take + * advantage of SIMD parallelism in future processors. + * <p> + * <i>UMAC</i> has been designed to allow implementations which accommodate + * <i>on-line</i> authentication. This means that pieces of the message may be + * presented to <i>UMAC</i> at different times (but in correct order) and an + * on-line implementation will be able to process the message correctly without + * the need to buffer more than a few dozen bytes of the message. For + * simplicity, the algorithms in this specification are presented as if the + * entire message being authenticated were available at once. + * <p> + * To authenticate a message, <code>Msg</code>, one first applies the + * universal hash function, resulting in a string which is typically much + * shorter than the original message. The pseudorandom function is applied to a + * nonce, and the result is used in the manner of a Vernam cipher: the + * authentication tag is the xor of the output from the hash function and the + * output from the pseudorandom function. Thus, an authentication tag is + * generated as + * <pre> + * AuthTag = f(Nonce) xor h(Msg) + * </pre> + * <p> + * Here <code>f</code> is the pseudorandom function shared between the sender + * and the receiver, and h is a universal hash function shared by the sender and + * the receiver. In <i>UMAC</i>, a shared key is used to key the pseudorandom + * function <code>f</code>, and then <code>f</code> is used for both tag + * generation and internally to generate all of the bits needed by the universal + * hash function. + * <p> + * The universal hash function that we use is called <code>UHASH</code>. It + * combines several software-optimized algorithms into a multi-layered + * structure. The algorithm is moderately complex. Some of this complexity comes + * from extensive speed optimizations. + * <p> + * For the pseudorandom function we use the block cipher of the <i>Advanced + * Encryption Standard</i> (AES). + * <p> + * The UMAC32 parameters, considered in this implementation are: + * <pre> + * UMAC32 + * ------ + * WORD-LEN 4 + * UMAC-OUTPUT-LEN 8 + * L1-KEY-LEN 1024 + * UMAC-KEY-LEN 16 + * ENDIAN-FAVORITE BIG * + * L1-OPERATIONS-SIGN UNSIGNED + * </pre> + * <p> + * Please note that this UMAC32 differs from the one described in the paper by + * the <i>ENDIAN-FAVORITE</i> value. + * <p> + * References: + * <ol> + * <li><a href="http://www.ietf.org/internet-drafts/draft-krovetz-umac-01.txt"> + * UMAC</a>: Message Authentication Code using Universal Hashing.<br> + * T. Krovetz, J. Black, S. Halevi, A. Hevia, H. Krawczyk, and P. Rogaway.</li> + * </ol> + */ +public class UMac32 + extends BaseMac +{ + /** + * Property name of the user-supplied <i>Nonce</i>. The value associated to + * this property name is taken to be a byte array. + */ + public static final String NONCE_MATERIAL = "gnu.crypto.umac.nonce.material"; + /** Known test vector. */ + // private static final String TV1 = "3E5A0E09198B0F94"; + // private static final String TV1 = "5FD764A6D3A9FD9D"; + // private static final String TV1 = "48658DE1D9A70304"; + private static final String TV1 = "455ED214A6909F20"; + private static final BigInteger MAX_NONCE_ITERATIONS = BigInteger.ONE.shiftLeft(16 * 8); + // UMAC32 parameters + static final int OUTPUT_LEN = 8; + static final int L1_KEY_LEN = 1024; + static final int KEY_LEN = 16; + /** caches the result of the correctness test, once executed. */ + private static Boolean valid; + private byte[] nonce; + private UHash32 uhash32; + private BigInteger nonceReuseCount; + /** The authentication key for this instance. */ + private transient byte[] K; + + /** Trivial 0-arguments constructor. */ + public UMac32() + { + super("umac32"); + } + + /** + * Private constructor for cloning purposes. + * + * @param that the instance to clone. + */ + private UMac32(UMac32 that) + { + this(); + + if (that.K != null) + this.K = (byte[]) that.K.clone(); + if (that.nonce != null) + this.nonce = (byte[]) that.nonce.clone(); + if (that.uhash32 != null) + this.uhash32 = (UHash32) that.uhash32.clone(); + this.nonceReuseCount = that.nonceReuseCount; + } + + public Object clone() + { + return new UMac32(this); + } + + public int macSize() + { + return OUTPUT_LEN; + } + + /** + * Initialising a <i>UMAC</i> instance consists of defining values for the + * following parameters: + * <ol> + * <li>Key Material: as the value of the attribute entry keyed by + * {@link #MAC_KEY_MATERIAL}. The value is taken to be a byte array + * containing the user-specified key material. The length of this array, + * if/when defined SHOULD be exactly equal to {@link #KEY_LEN}.</li> + * <li>Nonce Material: as the value of the attribute entry keyed by + * {@link #NONCE_MATERIAL}. The value is taken to be a byte array containing + * the user-specified nonce material. The length of this array, if/when + * defined SHOULD be (a) greater than zero, and (b) less or equal to 16 (the + * size of the AES block).</li> + * </ol> + * <p> + * For convenience, this implementation accepts that not both parameters be + * always specified. + * <ul> + * <li>If the <i>Key Material</i> is specified, but the <i>Nonce Material</i> + * is not, then this implementation, re-uses the previously set <i>Nonce + * Material</i> after (a) converting the bytes to an unsigned integer, (b) + * incrementing the number by one, and (c) converting it back to 16 bytes.</li> + * <li>If the <i>Nonce Material</i> is specified, but the <i>Key Material</i> + * is not, then this implementation re-uses the previously set <i>Key Material</i>. + * </li> + * </ul> + * <p> + * This method throws an exception if no <i>Key Material</i> is specified in + * the input map, and there is no previously set/defined <i>Key Material</i> + * (from an earlier invocation of this method). If a <i>Key Material</i> can + * be used, but no <i>Nonce Material</i> is defined or previously + * set/defined, then a default value of all-zeroes shall be used. + * + * @param attributes one or both of required parameters. + * @throws InvalidKeyException the key material specified is not of the + * correct length. + */ + public void init(Map attributes) throws InvalidKeyException, + IllegalStateException + { + byte[] key = (byte[]) attributes.get(MAC_KEY_MATERIAL); + byte[] n = (byte[]) attributes.get(NONCE_MATERIAL); + boolean newKey = (key != null); + boolean newNonce = (n != null); + if (newKey) + { + if (key.length != KEY_LEN) + throw new InvalidKeyException("Key length: " + + String.valueOf(key.length)); + K = key; + } + else + { + if (K == null) + throw new InvalidKeyException("Null Key"); + } + if (newNonce) + { + if (n.length < 1 || n.length > 16) + throw new IllegalArgumentException("Invalid Nonce length: " + + String.valueOf(n.length)); + if (n.length < 16) // pad with zeroes + { + byte[] newN = new byte[16]; + System.arraycopy(n, 0, newN, 0, n.length); + nonce = newN; + } + else + nonce = n; + + nonceReuseCount = BigInteger.ZERO; + } + else if (nonce == null) // use all-0 nonce if 1st time + { + nonce = new byte[16]; + nonceReuseCount = BigInteger.ZERO; + } + else if (! newKey) // increment nonce if still below max count + { + nonceReuseCount = nonceReuseCount.add(BigInteger.ONE); + if (nonceReuseCount.compareTo(MAX_NONCE_ITERATIONS) >= 0) + { + // limit reached. we SHOULD have a key + throw new InvalidKeyException("Null Key and unusable old Nonce"); + } + BigInteger N = new BigInteger(1, nonce); + N = N.add(BigInteger.ONE).mod(MAX_NONCE_ITERATIONS); + n = N.toByteArray(); + if (n.length == 16) + nonce = n; + else if (n.length < 16) + { + nonce = new byte[16]; + System.arraycopy(n, 0, nonce, 16 - n.length, n.length); + } + else + { + nonce = new byte[16]; + System.arraycopy(n, n.length - 16, nonce, 0, 16); + } + } + else // do nothing, re-use old nonce value + nonceReuseCount = BigInteger.ZERO; + + if (uhash32 == null) + uhash32 = new UHash32(); + + Map map = new HashMap(); + map.put(MAC_KEY_MATERIAL, K); + uhash32.init(map); + } + + public void update(byte b) + { + uhash32.update(b); + } + + public void update(byte[] b, int offset, int len) + { + uhash32.update(b, offset, len); + } + + public byte[] digest() + { + byte[] result = uhash32.digest(); + byte[] pad = pdf(); // pdf(K, nonce); + for (int i = 0; i < OUTPUT_LEN; i++) + result[i] = (byte)(result[i] ^ pad[i]); + + return result; + } + + public void reset() + { + if (uhash32 != null) + uhash32.reset(); + } + + public boolean selfTest() + { + if (valid == null) + { + byte[] key; + try + { + key = "abcdefghijklmnop".getBytes("ASCII"); + } + catch (UnsupportedEncodingException x) + { + throw new RuntimeException("ASCII not supported"); + } + byte[] nonce = new byte[] { 0, 1, 2, 3, 4, 5, 6, 7 }; + UMac32 mac = new UMac32(); + Map attributes = new HashMap(); + attributes.put(MAC_KEY_MATERIAL, key); + attributes.put(NONCE_MATERIAL, nonce); + try + { + mac.init(attributes); + } + catch (InvalidKeyException x) + { + x.printStackTrace(System.err); + return false; + } + byte[] data = new byte[128]; + data[0] = (byte) 0x80; + mac.update(data, 0, 128); + byte[] result = mac.digest(); + valid = Boolean.valueOf(TV1.equals(Util.toString(result))); + } + return valid.booleanValue(); + } + + /** + * @return byte array of length 8 (or OUTPUT_LEN) bytes. + */ + private byte[] pdf() + { + // Make Nonce 16 bytes by prepending zeroes. done (see init()) + // one AES invocation is enough for more than one PDF invocation + // number of index bits needed = 1 + // Extract index bits and zero low bits of Nonce + BigInteger Nonce = new BigInteger(1, nonce); + int nlowbitsnum = Nonce.testBit(0) ? 1 : 0; + Nonce = Nonce.clearBit(0); + // Generate subkey, AES and extract indexed substring + IRandom kdf = new UMacGenerator(); + Map map = new HashMap(); + map.put(IBlockCipher.KEY_MATERIAL, K); + map.put(UMacGenerator.INDEX, Integer.valueOf(128)); + kdf.init(map); + byte[] Kp = new byte[KEY_LEN]; + try + { + kdf.nextBytes(Kp, 0, KEY_LEN); + } + catch (IllegalStateException x) + { + x.printStackTrace(System.err); + throw new RuntimeException(String.valueOf(x)); + } + catch (LimitReachedException x) + { + x.printStackTrace(System.err); + throw new RuntimeException(String.valueOf(x)); + } + IBlockCipher aes = CipherFactory.getInstance(Registry.AES_CIPHER); + map.put(IBlockCipher.KEY_MATERIAL, Kp); + try + { + aes.init(map); + } + catch (InvalidKeyException x) + { + x.printStackTrace(System.err); + throw new RuntimeException(String.valueOf(x)); + } + catch (IllegalStateException x) + { + x.printStackTrace(System.err); + throw new RuntimeException(String.valueOf(x)); + } + byte[] T = new byte[16]; + aes.encryptBlock(nonce, 0, T, 0); + byte[] result = new byte[OUTPUT_LEN]; + System.arraycopy(T, nlowbitsnum, result, 0, OUTPUT_LEN); + return result; + } +} diff --git a/libjava/classpath/gnu/javax/crypto/mode/BaseMode.java b/libjava/classpath/gnu/javax/crypto/mode/BaseMode.java new file mode 100644 index 000000000..831dd9664 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/mode/BaseMode.java @@ -0,0 +1,295 @@ +/* BaseMode.java -- + Copyright (C) 2001, 2002, 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.mode; + +import gnu.java.lang.CPStringBuilder; + +import gnu.javax.crypto.cipher.IBlockCipher; + +import java.security.InvalidKeyException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; + +/** + * A basic abstract class to facilitate implementing block cipher modes of + * operations. + */ +public abstract class BaseMode + implements IMode +{ + /** The canonical name prefix of this mode. */ + protected String name; + /** The state indicator of this instance. */ + protected int state; + /** The underlying block cipher implementation. */ + protected IBlockCipher cipher; + /** The block size, in bytes, to operate the underlying block cipher in. */ + protected int cipherBlockSize; + /** The block size, in bytes, in which to operate the mode instance. */ + protected int modeBlockSize; + /** The initialisation vector value. */ + protected byte[] iv; + /** The instance lock. */ + protected Object lock = new Object(); + + /** + * Trivial constructor for use by concrete subclasses. + * + * @param name the canonical name prefix of this mode. + * @param underlyingCipher the implementation of the underlying cipher. + * @param cipherBlockSize the block size, in bytes, in which to operate the + * underlying cipher. + */ + protected BaseMode(String name, IBlockCipher underlyingCipher, + int cipherBlockSize) + { + super(); + + this.name = name; + this.cipher = underlyingCipher; + this.cipherBlockSize = cipherBlockSize; + state = -1; + } + + public void update(byte[] in, int inOffset, byte[] out, int outOffset) + throws IllegalStateException + { + synchronized (lock) + { + switch (state) + { + case ENCRYPTION: + encryptBlock(in, inOffset, out, outOffset); + break; + case DECRYPTION: + decryptBlock(in, inOffset, out, outOffset); + break; + default: + throw new IllegalStateException(); + } + } + } + + public String name() + { + return new CPStringBuilder(name).append('(').append(cipher.name()).append(')') + .toString(); + } + + /** + * Returns the default value, in bytes, of the mode's block size. This value + * is part of the construction arguments passed to the Factory methods in + * {@link ModeFactory}. Unless changed by an invocation of any of the + * <code>init()</code> methods, a <i>Mode</i> instance would operate with + * the same block size as its underlying block cipher. As mentioned earlier, + * the block size of the underlying block cipher itself is specified in one of + * the method(s) available in the factory class. + * + * @return the default value, in bytes, of the mode's block size. + * @see ModeFactory + */ + public int defaultBlockSize() + { + return cipherBlockSize; + } + + /** + * Returns the default value, in bytes, of the underlying block cipher key + * size. + * + * @return the default value, in bytes, of the underlying cipher's key size. + */ + public int defaultKeySize() + { + return cipher.defaultKeySize(); + } + + /** + * Returns an {@link Iterator} over the supported block sizes. Each element + * returned by this object is an {@link Integer}. + * <p> + * The default behaviour is to return an iterator with just one value, which + * is that currently configured for the underlying block cipher. Concrete + * implementations may override this behaviour to signal their ability to + * support other values. + * + * @return an {@link Iterator} over the supported block sizes. + */ + public Iterator blockSizes() + { + ArrayList al = new ArrayList(); + al.add(Integer.valueOf(cipherBlockSize)); + return Collections.unmodifiableList(al).iterator(); + } + + /** + * Returns an {@link Iterator} over the supported underlying block cipher key + * sizes. Each element returned by this object is an instance of + * {@link Integer}. + * + * @return an {@link Iterator} over the supported key sizes. + */ + public Iterator keySizes() + { + return cipher.keySizes(); + } + + public void init(Map attributes) throws InvalidKeyException, + IllegalStateException + { + synchronized (lock) + { + if (state != -1) + throw new IllegalStateException(); + Integer want = (Integer) attributes.get(STATE); + if (want != null) + { + switch (want.intValue()) + { + case ENCRYPTION: + state = ENCRYPTION; + break; + case DECRYPTION: + state = DECRYPTION; + break; + default: + throw new IllegalArgumentException(); + } + } + Integer bs = (Integer) attributes.get(MODE_BLOCK_SIZE); + modeBlockSize = (bs == null ? cipherBlockSize : bs.intValue()); + byte[] iv = (byte[]) attributes.get(IV); + if (iv != null) + this.iv = (byte[]) iv.clone(); + else + this.iv = new byte[modeBlockSize]; + cipher.init(attributes); + setup(); + } + } + + public int currentBlockSize() + { + if (state == -1) + throw new IllegalStateException(); + return modeBlockSize; + } + + public void reset() + { + synchronized (lock) + { + state = -1; + iv = null; + cipher.reset(); + teardown(); + } + } + + public boolean selfTest() + { + int ks; + Iterator bit; + for (Iterator kit = keySizes(); kit.hasNext();) + { + ks = ((Integer) kit.next()).intValue(); + for (bit = blockSizes(); bit.hasNext();) + if (! testSymmetry(ks, ((Integer) bit.next()).intValue())) + return false; + } + return true; + } + + public abstract Object clone(); + + /** The initialisation phase of the concrete mode implementation. */ + public abstract void setup(); + + /** The termination phase of the concrete mode implementation. */ + public abstract void teardown(); + + public abstract void encryptBlock(byte[] in, int i, byte[] out, int o); + + public abstract void decryptBlock(byte[] in, int i, byte[] out, int o); + + private boolean testSymmetry(int ks, int bs) + { + try + { + IMode mode = (IMode) this.clone(); + byte[] iv = new byte[cipherBlockSize]; // all zeroes + byte[] k = new byte[ks]; + int i; + for (i = 0; i < ks; i++) + k[i] = (byte) i; + int blockCount = 5; + int limit = blockCount * bs; + byte[] pt = new byte[limit]; + for (i = 0; i < limit; i++) + pt[i] = (byte) i; + byte[] ct = new byte[limit]; + byte[] cpt = new byte[limit]; + Map map = new HashMap(); + map.put(KEY_MATERIAL, k); + map.put(CIPHER_BLOCK_SIZE, Integer.valueOf(cipherBlockSize)); + map.put(STATE, Integer.valueOf(ENCRYPTION)); + map.put(IV, iv); + map.put(MODE_BLOCK_SIZE, Integer.valueOf(bs)); + mode.reset(); + mode.init(map); + for (i = 0; i < blockCount; i++) + mode.update(pt, i * bs, ct, i * bs); + mode.reset(); + map.put(STATE, Integer.valueOf(DECRYPTION)); + mode.init(map); + for (i = 0; i < blockCount; i++) + mode.update(ct, i * bs, cpt, i * bs); + return Arrays.equals(pt, cpt); + } + catch (Exception x) + { + x.printStackTrace(System.err); + return false; + } + } +} diff --git a/libjava/classpath/gnu/javax/crypto/mode/CBC.java b/libjava/classpath/gnu/javax/crypto/mode/CBC.java new file mode 100644 index 000000000..31c445f4e --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/mode/CBC.java @@ -0,0 +1,123 @@ +/* CBC.java -- + Copyright (C) 2002, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.mode; + +import gnu.java.security.Registry; +import gnu.javax.crypto.cipher.IBlockCipher; + +/** + * The Cipher Block Chaining mode. This mode introduces feedback into the cipher + * by XORing the previous ciphertext block with the plaintext block before + * encipherment. That is, encrypting looks like this: + * + * <pre> + * C<sub>i</sub> = E<sub>K</sub>(P<sub>i</sub>ˆ C<sub>i-1</sub>) + * </pre> + * <p> + * Similarly, decrypting is: + * <pre> + * P<sub>i</sub> = C<sub>i-1</sub> ˆ D<sub>K</sub>(C<sub>i</sub>) + * </pre> + */ +public class CBC + extends BaseMode + implements Cloneable +{ + /** The last (de|en)crypted block */ + private byte[] lastBlock; + /** An intermediate buffer. */ + private byte[] scratch; + + /** + * Package-private constructor for the factory class. + * + * @param underlyingCipher The cipher implementation. + * @param cipherBlockSize The cipher's block size. + */ + CBC(IBlockCipher underlyingCipher, int cipherBlockSize) + { + super(Registry.CBC_MODE, underlyingCipher, cipherBlockSize); + } + + /** Our constructor for cloning. */ + private CBC(CBC that) + { + this((IBlockCipher) that.cipher.clone(), that.cipherBlockSize); + } + + public Object clone() + { + return new CBC(this); + } + + public void setup() + { + if (modeBlockSize != cipherBlockSize) + throw new IllegalArgumentException(); + scratch = new byte[cipherBlockSize]; + lastBlock = new byte[cipherBlockSize]; + // lastBlock gets initialized to the initialization vector. + for (int i = 0; i < lastBlock.length && i < iv.length; i++) + lastBlock[i] = iv[i]; + } + + public void teardown() + { + lastBlock = null; + scratch = null; + } + + public void encryptBlock(byte[] in, int i, byte[] out, int o) + { + for (int k = 0; k < scratch.length; k++) + scratch[k] = (byte)(lastBlock[k] ^ in[k + i]); + cipher.encryptBlock(scratch, 0, out, o); + System.arraycopy(out, o, lastBlock, 0, cipherBlockSize); + } + + public void decryptBlock(byte[] in, int i, byte[] out, int o) + { + byte[] buf = new byte[cipherBlockSize]; + System.arraycopy(in, i, buf, 0, cipherBlockSize); + cipher.decryptBlock(in, i, scratch, 0); + for (int k = 0; k < scratch.length; k++) + out[o + k] = (byte)(lastBlock[k] ^ scratch[k]); + System.arraycopy(buf, 0, lastBlock, 0, cipherBlockSize); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/mode/CFB.java b/libjava/classpath/gnu/javax/crypto/mode/CFB.java new file mode 100644 index 000000000..c5f06e11c --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/mode/CFB.java @@ -0,0 +1,155 @@ +/* CFB.java -- + Copyright (C) 2002, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.mode; + +import gnu.java.security.Registry; +import gnu.javax.crypto.cipher.IBlockCipher; + +/** + * The cipher feedback mode. CFB mode is a stream mode that operates on <i>s</i> + * bit blocks, where 1 <= <i>s</i> <= <i>b</i>, if <i>b</i> is the + * underlying cipher's block size. Encryption is: + * <pre> + * I[1] = IV + * I[j] = LSB(b-s, I[j-1]) | C[j-1] for j = 2...n + * O[j] = CIPH(K, I[j]) for j = 1,2...n + * C[j] = P[j] ˆ MSB(s, O[j]) for j = 1,2...n + * </pre> + * <p> + * And decryption is: + * <pre> + * I[1] = IV + * I[j] = LSB(b-s, I[j-1]) | C[j-1] for j = 2...n + * O[j] = CIPH(K, I[j]) for j = 1,2...n + * P[j] = C[j] ˆ MSB(s, O[j]) for j = 1,2...n + * </pre> + * <p> + * CFB mode requires an initialization vector, which need not be kept secret. + * <p> + * References: + * <ol> + * <li>Bruce Schneier, <i>Applied Cryptography: Protocols, Algorithms, and + * Source Code in C, Second Edition</i>. (1996 John Wiley and Sons) ISBN + * 0-471-11709-9.</li> + * <li><a + * href="http://csrc.nist.gov/encryption/modes/Recommendation/Modes01.pdf"> + * Recommendation for Block Cipher Modes of Operation Methods and Techniques</a>, + * Morris Dworkin.</li> + * </ol> + */ +public class CFB + extends BaseMode +{ + /** The shift register, the input block to the block cipher. */ + private byte[] shiftRegister; + /** The output block from the block cipher. */ + private byte[] scratch; + + /** + * Package-private constructor for the factory class. + * + * @param underlyingCipher The cipher implementation. + * @param cipherBlockSize The cipher's block size. + */ + CFB(IBlockCipher underlyingCipher, int cipherBlockSize) + { + super(Registry.CFB_MODE, underlyingCipher, cipherBlockSize); + } + + /** + * Cloneing constructor. + * + * @param that The instance being cloned. + */ + private CFB(CFB that) + { + this((IBlockCipher) that.cipher.clone(), that.cipherBlockSize); + } + + public Object clone() + { + return new CFB(this); + } + + public void setup() + { + if (modeBlockSize > cipherBlockSize) + throw new IllegalArgumentException( + "CFB block size cannot be larger than the cipher block size"); + shiftRegister = new byte[cipherBlockSize]; + scratch = new byte[cipherBlockSize]; + System.arraycopy(iv, 0, + shiftRegister, 0, + Math.min(iv.length, cipherBlockSize)); + } + + public void teardown() + { + if (shiftRegister != null) + for (int i = 0; i < shiftRegister.length; i++) + shiftRegister[i] = 0; + shiftRegister = null; + } + + public void encryptBlock(byte[] in, int inOffset, byte[] out, int outOffset) + { + cipher.encryptBlock(shiftRegister, 0, scratch, 0); + for (int i = 0; i < modeBlockSize; i++) + out[outOffset + i] = (byte)(in[inOffset + i] ^ scratch[i]); + System.arraycopy(shiftRegister, modeBlockSize, + shiftRegister, 0, + cipherBlockSize - modeBlockSize); + System.arraycopy(out, outOffset, + shiftRegister, cipherBlockSize - modeBlockSize, + modeBlockSize); + } + + public void decryptBlock(byte[] in, int inOffset, byte[] out, int outOffset) + { + cipher.encryptBlock(shiftRegister, 0, scratch, 0); + for (int i = 0; i < modeBlockSize; i++) + out[outOffset + i] = (byte)(in[inOffset + i] ^ scratch[i]); + System.arraycopy(shiftRegister, modeBlockSize, + shiftRegister, 0, + cipherBlockSize - modeBlockSize); + System.arraycopy(in, inOffset, + shiftRegister, cipherBlockSize - modeBlockSize, + modeBlockSize); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/mode/CTR.java b/libjava/classpath/gnu/javax/crypto/mode/CTR.java new file mode 100644 index 000000000..56ea58c25 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/mode/CTR.java @@ -0,0 +1,168 @@ +/* CTR.java -- + Copyright (C) 2001, 2002, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.mode; + +import gnu.java.security.Registry; +import gnu.java.security.util.Sequence; +import gnu.javax.crypto.cipher.IBlockCipher; + +import java.util.Arrays; +import java.util.Iterator; + +/** + * The implementation of the Counter Mode. + * <p> + * The algorithm steps are formally described as follows: + * + * <pre> + * CTR Encryption: O[j] = E(K)(T[j]); for j = 1, 2...n; + * C[j] = P[j] ˆ O[j]; for j = 1, 2...n. + * CTR Decryption: O[j] = E(K)(T[j]); for j = 1, 2...n; + * P[j] = C[j] ˆ O[j]; for j = 1, 2...n. + * </pre> + * + * <p> + * where <code>P</code> is the plaintext, <code>C</code> is the ciphertext, + * <code>E(K)</code> is the underlying block cipher encryption function + * parametrised with the session key <code>K</code>, and <code>T</code> is + * the <i>Counter</i>. + * <p> + * This implementation, uses a standard incrementing function with a step of 1, + * and an initial value similar to that described in the NIST document. + * <p> + * References: + * <ol> + * <li><a + * href="http://csrc.nist.gov/encryption/modes/Recommendation/Modes01.pdf"> + * Recommendation for Block Cipher Modes of Operation Methods and Techniques</a>, + * Morris Dworkin.</li> + * </ol> + */ +public class CTR + extends BaseMode + implements Cloneable +{ + private int off; + private byte[] counter, enc; + + /** + * Trivial package-private constructor for use by the Factory class. + * + * @param underlyingCipher the underlying cipher implementation. + * @param cipherBlockSize the underlying cipher block size to use. + */ + CTR(IBlockCipher underlyingCipher, int cipherBlockSize) + { + super(Registry.CTR_MODE, underlyingCipher, cipherBlockSize); + } + + /** + * Private constructor for cloning purposes. + * + * @param that the instance to clone. + */ + private CTR(CTR that) + { + this((IBlockCipher) that.cipher.clone(), that.cipherBlockSize); + } + + public Object clone() + { + return new CTR(this); + } + + public void setup() + { + if (modeBlockSize > cipherBlockSize) + throw new IllegalArgumentException("mode size exceeds cipher block size"); + off = 0; + counter = new byte[cipherBlockSize]; + int i = cipherBlockSize - 1; + int j = iv.length - 1; + while (i >= 0 && j >= 0) + counter[i--] = iv[j--]; + enc = new byte[cipherBlockSize]; + cipher.encryptBlock(counter, 0, enc, 0); + } + + public void teardown() + { + if (counter != null) + Arrays.fill(counter, (byte) 0); + if (enc != null) + Arrays.fill(enc, (byte) 0); + } + + public void encryptBlock(byte[] in, int i, byte[] out, int o) + { + ctr(in, i, out, o); + } + + public void decryptBlock(byte[] in, int i, byte[] out, int o) + { + ctr(in, i, out, o); + } + + public Iterator blockSizes() + { + return new Sequence(1, cipherBlockSize).iterator(); + } + + private void ctr(byte[] in, int inOffset, byte[] out, int outOffset) + { + for (int i = 0; i < modeBlockSize; i++) + { + out[outOffset++] = (byte)(in[inOffset++] ^ enc[off++]); + if (off == cipherBlockSize) + { + int j; + for (j = cipherBlockSize - 1; j >= 0; j--) + { + counter[j]++; + if ((counter[j] & 0xFF) != 0) + break; + } + if (j == 0) + counter[cipherBlockSize - 1]++; + off = 0; + cipher.encryptBlock(counter, 0, enc, 0); + } + } + } +} diff --git a/libjava/classpath/gnu/javax/crypto/mode/EAX.java b/libjava/classpath/gnu/javax/crypto/mode/EAX.java new file mode 100644 index 000000000..b3e4a6a4e --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/mode/EAX.java @@ -0,0 +1,289 @@ +/* EAX.java -- + Copyright (C) 2004, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.mode; + +import gnu.java.security.Registry; +import gnu.javax.crypto.cipher.IBlockCipher; +import gnu.javax.crypto.mac.IMac; +import gnu.javax.crypto.mac.MacFactory; + +import java.security.InvalidKeyException; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; + +/** + * A conventional two-pass authenticated-encrypted mode, EAX. EAX is a + * <i>Authenticated Encryption with Additional Data</i> (<b>AEAD</b>) scheme, + * which provides protection and authentication for the message, and provides + * authentication of an (optional) header. EAX is composed of the counter mode + * (CTR) and the one-key CBC MAC (OMAC). + * <p> + * This class makes full use of the {@link IAuthenticatedMode} interface, that + * is, all methods of both {@link IMode} and {@link IMac} can be used as + * specified in the {@link IAuthenticatedMode} interface. + * <p> + * References: + * <ol> + * <li>M. Bellare, P. Rogaway, and D. Wagner; <a + * href="http://www.cs.berkeley.edu/~daw/papers/eprint-short-ae.pdf">A + * Conventional Authenticated-Encryption Mode</a>.</li> + * </ol> + */ +public class EAX + implements IAuthenticatedMode +{ + /** The tag size, in bytes. */ + private int tagSize; + /** The nonce OMAC instance. */ + private IMac nonceOmac; + /** The header OMAC instance. */ + private IMac headerOmac; + /** The message OMAC instance. */ + private IMac msgOmac; + /** The CTR instance. */ + private IMode ctr; + /** The direction state (encrypting or decrypting). */ + private int state; + /** Whether we're initialized or not. */ + private boolean init; + /** The cipher block size. */ + private int cipherBlockSize; + /** The cipher. */ + private IBlockCipher cipher; + /** The [t]_n array. */ + private byte[] t_n; + private static boolean valid = false; + + public EAX(IBlockCipher cipher, int cipherBlockSize) + { + this.cipher = cipher; + this.cipherBlockSize = cipherBlockSize; + String name = cipher.name(); + int i = name.indexOf('-'); + if (i >= 0) + name = name.substring(0, i); + String omacname = Registry.OMAC_PREFIX + name; + nonceOmac = MacFactory.getInstance(omacname); + headerOmac = MacFactory.getInstance(omacname); + msgOmac = MacFactory.getInstance(omacname); + ctr = ModeFactory.getInstance(Registry.CTR_MODE, cipher, cipherBlockSize); + t_n = new byte[cipherBlockSize]; + init = false; + } + + public Object clone() + { + return new EAX((IBlockCipher) cipher.clone(), cipherBlockSize); + } + + public String name() + { + return Registry.EAX_MODE + "(" + cipher.name() + ")"; + } + + public int defaultBlockSize() + { + return ctr.defaultBlockSize(); + } + + public int defaultKeySize() + { + return ctr.defaultKeySize(); + } + + public Iterator blockSizes() + { + return ctr.blockSizes(); + } + + public Iterator keySizes() + { + return ctr.keySizes(); + } + + public void init(Map attrib) throws InvalidKeyException + { + byte[] nonce = (byte[]) attrib.get(IV); + if (nonce == null) + throw new IllegalArgumentException("no nonce provided"); + byte[] key = (byte[]) attrib.get(KEY_MATERIAL); + if (key == null) + throw new IllegalArgumentException("no key provided"); + + Arrays.fill(t_n, (byte) 0); + nonceOmac.reset(); + nonceOmac.init(Collections.singletonMap(MAC_KEY_MATERIAL, key)); + nonceOmac.update(t_n, 0, t_n.length); + nonceOmac.update(nonce, 0, nonce.length); + byte[] N = nonceOmac.digest(); + nonceOmac.reset(); + nonceOmac.update(t_n, 0, t_n.length); + nonceOmac.update(nonce, 0, nonce.length); + t_n[t_n.length - 1] = 1; + headerOmac.reset(); + headerOmac.init(Collections.singletonMap(MAC_KEY_MATERIAL, key)); + headerOmac.update(t_n, 0, t_n.length); + t_n[t_n.length - 1] = 2; + msgOmac.reset(); + msgOmac.init(Collections.singletonMap(MAC_KEY_MATERIAL, key)); + msgOmac.update(t_n, 0, t_n.length); + Integer modeSize = (Integer) attrib.get(MODE_BLOCK_SIZE); + if (modeSize == null) + modeSize = Integer.valueOf(cipherBlockSize); + HashMap ctrAttr = new HashMap(); + ctrAttr.put(KEY_MATERIAL, key); + ctrAttr.put(IV, N); + ctrAttr.put(STATE, Integer.valueOf(ENCRYPTION)); + ctrAttr.put(MODE_BLOCK_SIZE, modeSize); + ctr.reset(); + ctr.init(ctrAttr); + Integer st = (Integer) attrib.get(STATE); + if (st != null) + { + state = st.intValue(); + if (state != ENCRYPTION && state != DECRYPTION) + throw new IllegalArgumentException("invalid state"); + } + else + state = ENCRYPTION; + + Integer ts = (Integer) attrib.get(TRUNCATED_SIZE); + if (ts != null) + tagSize = ts.intValue(); + else + tagSize = cipherBlockSize; + if (tagSize < 0 || tagSize > cipherBlockSize) + throw new IllegalArgumentException("tag size out of range"); + init = true; + } + + public int currentBlockSize() + { + return ctr.currentBlockSize(); + } + + public void encryptBlock(byte[] in, int inOff, byte[] out, int outOff) + { + if (! init) + throw new IllegalStateException("not initialized"); + if (state != ENCRYPTION) + throw new IllegalStateException("not encrypting"); + ctr.update(in, inOff, out, outOff); + msgOmac.update(out, outOff, ctr.currentBlockSize()); + } + + public void decryptBlock(byte[] in, int inOff, byte[] out, int outOff) + { + if (! init) + throw new IllegalStateException("not initialized"); + if (state != DECRYPTION) + throw new IllegalStateException("not decrypting"); + msgOmac.update(in, inOff, ctr.currentBlockSize()); + ctr.update(in, inOff, out, outOff); + } + + public void update(byte[] in, int inOff, byte[] out, int outOff) + { + switch (state) + { + case ENCRYPTION: + encryptBlock(in, inOff, out, outOff); + break; + case DECRYPTION: + decryptBlock(in, inOff, out, outOff); + break; + default: + throw new IllegalStateException("impossible state " + state); + } + } + + public void reset() + { + nonceOmac.reset(); + headerOmac.reset(); + msgOmac.reset(); + ctr.reset(); + } + + public boolean selfTest() + { + return true; // XXX + } + + public int macSize() + { + return tagSize; + } + + public byte[] digest() + { + byte[] tag = new byte[tagSize]; + digest(tag, 0); + return tag; + } + + public void digest(byte[] out, int outOffset) + { + if (outOffset < 0 || outOffset + tagSize > out.length) + throw new IndexOutOfBoundsException(); + byte[] N = nonceOmac.digest(); + byte[] H = headerOmac.digest(); + byte[] M = msgOmac.digest(); + for (int i = 0; i < tagSize; i++) + out[outOffset + i] = (byte)(N[i] ^ H[i] ^ M[i]); + reset(); + } + + public void update(byte b) + { + if (! init) + throw new IllegalStateException("not initialized"); + headerOmac.update(b); + } + + public void update(byte[] buf, int off, int len) + { + if (! init) + throw new IllegalStateException("not initialized"); + headerOmac.update(buf, off, len); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/mode/ECB.java b/libjava/classpath/gnu/javax/crypto/mode/ECB.java new file mode 100644 index 000000000..7e02b0187 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/mode/ECB.java @@ -0,0 +1,121 @@ +/* ECB.java -- + Copyright (C) 2001, 2002, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.mode; + +import gnu.java.security.Registry; +import gnu.javax.crypto.cipher.IBlockCipher; + +/** + * The implementation of the Electronic Codebook mode. + * <p> + * The Electronic Codebook (ECB) mode is a confidentiality mode that is defined + * as follows: + * <ul> + * <li>ECB Encryption: C<sub>j</sub> = CIPH<sub>K</sub>(P<sub>j</sub>) + * for j = 1...n</li> + * <li>ECB Decryption: P<sub>j</sub> = CIPH<sup>-1</sup><sub>K</sub>(C<sub>j</sub>) + * for j = 1...n</li> + * </ul> + * <p> + * In ECB encryption, the forward cipher function is applied directly, and + * independently, to each block of the plaintext. The resulting sequence of + * output blocks is the ciphertext. + * <p> + * In ECB decryption, the inverse cipher function is applied directly, and + * independently, to each block of the ciphertext. The resulting sequence of + * output blocks is the plaintext. + * <p> + * References: + * <ol> + * <li><a + * href="http://csrc.nist.gov/encryption/modes/Recommendation/Modes01.pdf"> + * Recommendation for Block Cipher Modes of Operation Methods and Techniques</a>, + * Morris Dworkin.</li> + * </ol> + */ +public class ECB + extends BaseMode + implements Cloneable +{ + /** + * Trivial package-private constructor for use by the Factory class. + * + * @param underlyingCipher the underlying cipher implementation. + * @param cipherBlockSize the underlying cipher block size to use. + */ + ECB(IBlockCipher underlyingCipher, int cipherBlockSize) + { + super(Registry.ECB_MODE, underlyingCipher, cipherBlockSize); + } + + /** + * Private constructor for cloning purposes. + * + * @param that the mode to clone. + */ + private ECB(ECB that) + { + this((IBlockCipher) that.cipher.clone(), that.cipherBlockSize); + } + + public Object clone() + { + return new ECB(this); + } + + public void setup() + { + if (modeBlockSize != cipherBlockSize) + throw new IllegalArgumentException(IMode.MODE_BLOCK_SIZE); + } + + public void teardown() + { + } + + public void encryptBlock(byte[] in, int i, byte[] out, int o) + { + cipher.encryptBlock(in, i, out, o); + } + + public void decryptBlock(byte[] in, int i, byte[] out, int o) + { + cipher.decryptBlock(in, i, out, o); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/mode/IAuthenticatedMode.java b/libjava/classpath/gnu/javax/crypto/mode/IAuthenticatedMode.java new file mode 100644 index 000000000..51a5547f2 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/mode/IAuthenticatedMode.java @@ -0,0 +1,56 @@ +/* IAuthenticatedMode.java -- + Copyright (C) 2004, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.mode; + +import gnu.javax.crypto.mac.IMac; + +/** + * The interface for encryption modes that also produce a message authentication + * tag. + * <p> + * This interface is merely the conjuction of the {@link IMode} and {@link IMac} + * interfaces. Encryption and decryption is done via the + * {@link IMode#update(byte[],int,byte[],int)} method, tag generation is done + * via the {@link IMac#digest()} method, and header updating (if supported by + * the mode) is done via the {@link IMac#update(byte[],int,int)} method. + */ +public interface IAuthenticatedMode + extends IMode, IMac +{ +} diff --git a/libjava/classpath/gnu/javax/crypto/mode/ICM.java b/libjava/classpath/gnu/javax/crypto/mode/ICM.java new file mode 100644 index 000000000..a4737bcdf --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/mode/ICM.java @@ -0,0 +1,181 @@ +/* ICM.java -- + Copyright (C) 2001, 2002, 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.mode; + +import gnu.java.security.Registry; +import gnu.javax.crypto.cipher.IBlockCipher; + +import java.math.BigInteger; + +/** + * An implementation of <i>David McGrew</i> Integer Counter Mode (ICM) as an + * {@link IMode}. + * <p> + * ICM is a way to define a pseudorandom keystream generator using a block + * cipher. The keystream can be used for additive encryption, key derivation, or + * any other application requiring pseudorandom data. In the case of this class, + * it is used as additive encryption, XOR-ing the keystream with the input text + * --for both encryption and decryption. + * <p> + * In ICM, the keystream is logically broken into segments. Each segment is + * identified with a segment index, and the segments have equal lengths. This + * segmentation makes ICM especially appropriate for securing packet-based + * protocols. ICM also allows a variety of configurations based, among other + * things, on two parameters: the <i>block index length</i> and the <i>segment + * index length</i>. A constraint on those two values exists: The sum of + * <i>segment index length</i> and <i>block index length</i> <b>must not</b> + * half the <i>block size</i> of the underlying cipher. This requirement + * protects the ICM keystream generator from potentially failing to be + * pseudorandom. + * <p> + * For simplicity, this implementation, fixes these two values to the following: + * <ul> + * <li>block index length: is half the underlying cipher block size, and</li> + * <li>segment index length: is zero.</li> + * </ul> + * <p> + * For a 128-bit block cipher, the above values imply a maximum keystream length + * of 295,147,905,179,352,825,856 octets, since in ICM, each segment must not + * exceed the value + * <code>(256 ^ <i>block index length</i>) * <i>block length</i></code> + * octets. + * <p> + * Finally, for this implementation of the ICM, the IV placeholder will be used + * to pass the value of the <i>Offset</i> in the keystream segment. + * <p> + * References: + * <ol> + * <li><a + * href="http://www.ietf.org/internet-drafts/draft-mcgrew-saag-icm-00.txt"> + * Integer Counter Mode</a>, David A. McGrew.</li> + * </ol> + */ +public class ICM + extends BaseMode + implements Cloneable +{ + /** The integer value 256 as a BigInteger. */ + private static final BigInteger TWO_FIFTY_SIX = new BigInteger("256"); + /** Maximum number of blocks per segment. */ + private BigInteger maxBlocksPerSegment; + /** A work constant. */ + private BigInteger counterRange; + /** The initial counter for a given keystream segment. */ + private BigInteger C0; + /** The index of the next block for a given keystream segment. */ + private BigInteger blockNdx; + + /** + * Trivial package-private constructor for use by the Factory class. + * + * @param underlyingCipher the underlying cipher implementation. + * @param cipherBlockSize the underlying cipher block size to use. + */ + ICM(IBlockCipher underlyingCipher, int cipherBlockSize) + { + super(Registry.ICM_MODE, underlyingCipher, cipherBlockSize); + } + + /** + * Private constructor for cloning purposes. + * + * @param that the instance to clone. + */ + private ICM(ICM that) + { + this((IBlockCipher) that.cipher.clone(), that.cipherBlockSize); + } + + public Object clone() + { + return new ICM(this); + } + + public void setup() + { + if (modeBlockSize != cipherBlockSize) + throw new IllegalArgumentException(); + counterRange = TWO_FIFTY_SIX.pow(cipherBlockSize); + maxBlocksPerSegment = TWO_FIFTY_SIX.pow(cipherBlockSize / 2); + BigInteger r = new BigInteger(1, iv); + C0 = maxBlocksPerSegment.add(r).modPow(BigInteger.ONE, counterRange); + blockNdx = BigInteger.ZERO; + } + + public void teardown() + { + counterRange = null; + maxBlocksPerSegment = null; + C0 = null; + blockNdx = null; + } + + public void encryptBlock(byte[] in, int i, byte[] out, int o) + { + icm(in, i, out, o); + } + + public void decryptBlock(byte[] in, int i, byte[] out, int o) + { + icm(in, i, out, o); + } + + private void icm(byte[] in, int inOffset, byte[] out, int outOffset) + { + if (blockNdx.compareTo(maxBlocksPerSegment) >= 0) + throw new RuntimeException("Maximum blocks for segment reached"); + BigInteger Ci = C0.add(blockNdx).modPow(BigInteger.ONE, counterRange); + byte[] result = Ci.toByteArray(); + int limit = result.length; + int ndx = 0; + if (limit < cipherBlockSize) + { + byte[] data = new byte[cipherBlockSize]; + System.arraycopy(result, 0, data, cipherBlockSize - limit, limit); + result = data; + } + else if (limit > cipherBlockSize) + ndx = limit - cipherBlockSize; + + cipher.encryptBlock(result, ndx, result, ndx); + blockNdx = blockNdx.add(BigInteger.ONE); // increment blockNdx + for (int i = 0; i < modeBlockSize; i++) // xor result with input block + out[outOffset++] = (byte)(in[inOffset++] ^ result[ndx++]); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/mode/IMode.java b/libjava/classpath/gnu/javax/crypto/mode/IMode.java new file mode 100644 index 000000000..72c99ba73 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/mode/IMode.java @@ -0,0 +1,123 @@ +/* IMode.java -- + Copyright (C) 2001, 2002, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.mode; + +import gnu.javax.crypto.cipher.IBlockCipher; + +/** + * The basic visible methods of any block cipher mode. + * <p> + * Block ciphers encrypt plaintext in fixed size n-bit blocks. For messages + * larger than n bits, the simplest approach is to segment the message into + * n-bit blocks and process (encrypt and/or decrypt) each one separately + * (Electronic Codebook or ECB mode). But this approach has disadvantages in + * most applications. The block cipher modes of operations are one way of + * working around those disadvantages. + * <p> + * A <i>Mode</i> always employs an underlying block cipher for processing its + * input. For all intents and purposes, a <i>Mode</i> appears to behave as any + * other block cipher with the following differences: + * <ul> + * <li>Depending on the specifications of the mode, the block size may be + * different that that of the underlying cipher.</li> + * <li>While some modes of operations allow operations on block sizes that can + * be 1-bit long, this library will only deal with sizes that are multiple of 8 + * bits. This is because the <tt>byte</tt> is the smallest, easy to handle, + * primitive type in Java.</li> + * <li>Some modes need an <i>Initialisation Vector</i> (IV) to be properly + * initialised.</li> + * </ul> + * <p> + * Possible additional initialisation values for an instance of that type are: + * <ul> + * <li>The block size in which to operate this mode instance. This value is + * <b>optional</b>, if unspecified, the underlying block cipher's configured + * block size shall be used.</li> + * <li>Whether this mode will be used for encryption or decryption. This value + * is <b>mandatory</b> and should be included in the initialisation parameters. + * If it isn't, a {@link java.lang.IllegalStateException} will be thrown if any + * method, other than <code>reset()</code> is invoked on the instance.</li> + * <li>The byte array containing the <i>initialisation vector</i>, if required + * by this type of mode.</li> + * </ul> + */ +public interface IMode + extends IBlockCipher +{ + /** + * Property name of the state in which to operate this mode. The value + * associated to this property name is taken to be an {@link Integer} which + * value is either <code>ENCRYPTION</code> or <code>DECRYPTION</code>. + */ + String STATE = "gnu.crypto.mode.state"; + /** + * Property name of the block size in which to operate this mode. The value + * associated with this property name is taken to be an {@link Integer}. If + * it is not specified, the value of the block size of the underlying block + * cipher, used to construct the mode instance, shall be used. + */ + String MODE_BLOCK_SIZE = "gnu.crypto.mode.block.size"; + /** + * Property name of the initialisation vector to use, if required, with this + * instance. The value associated with this property name is taken to be a + * byte array. If the concrete instance needs such a parameter, and it has not + * been specified as part of the initialissation parameters, an all-zero byte + * array of the appropriate size shall be used. + */ + String IV = "gnu.crypto.mode.iv"; + /** Constant indicating the instance is being used for <i>encryption</i>. */ + int ENCRYPTION = 1; + /** Constant indicating the instance is being used for <i>decryption</i>. */ + int DECRYPTION = 2; + + /** + * A convenience method. Effectively invokes the <code>encryptBlock()</code> + * or <code>decryptBlock()</code> method depending on the operational state + * of the instance. + * + * @param in the plaintext. + * @param inOffset index of <code>in</code> from which to start considering + * data. + * @param out the ciphertext. + * @param outOffset index of <code>out</code> from which to store result. + * @exception IllegalStateException if the instance is not initialised. + */ + void update(byte[] in, int inOffset, byte[] out, int outOffset) + throws IllegalStateException; +} diff --git a/libjava/classpath/gnu/javax/crypto/mode/ModeFactory.java b/libjava/classpath/gnu/javax/crypto/mode/ModeFactory.java new file mode 100644 index 000000000..c1108ea11 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/mode/ModeFactory.java @@ -0,0 +1,151 @@ +/* ModeFactory.java -- + Copyright (C) 2001, 2002, 2004, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.mode; + +import gnu.java.security.Registry; + +import gnu.javax.crypto.cipher.CipherFactory; +import gnu.javax.crypto.cipher.IBlockCipher; + +import java.util.Collections; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Set; + +/** + * A <i>Factory</i> to instantiate block cipher modes of operations. + */ +public class ModeFactory + implements Registry +{ + private static Set names; + + /** Trivial constructor to enforce Singleton pattern. */ + private ModeFactory() + { + super(); + } + + /** + * Returns an instance of a block cipher mode of operations given its name and + * characteristics of the underlying block cipher. + * + * @param mode the case-insensitive name of the mode of operations. + * @param cipher the case-insensitive name of the block cipher. + * @param cipherBlockSize the block size, in bytes, of the underlying cipher. + * @return an instance of the block cipher algorithm, operating in a given + * mode of operations, or <code>null</code> if none found. + * @exception InternalError if either the mode or the underlying block cipher + * implementation does not pass its self-test. + */ + public static IMode getInstance(String mode, String cipher, + int cipherBlockSize) + { + if (mode == null || cipher == null) + return null; + + mode = mode.trim(); + cipher = cipher.trim(); + IBlockCipher cipherImpl = CipherFactory.getInstance(cipher); + if (cipherImpl == null) + return null; + + return getInstance(mode, cipherImpl, cipherBlockSize); + } + + public static IMode getInstance(String mode, IBlockCipher cipher, + int cipherBlockSize) + { + // ensure that cipherBlockSize is valid for the chosen underlying cipher + boolean ok = false; + for (Iterator it = cipher.blockSizes(); it.hasNext();) + { + ok = (cipherBlockSize == ((Integer) it.next()).intValue()); + if (ok) + break; + } + if (! ok) + throw new IllegalArgumentException("cipherBlockSize"); + IMode result = null; + if (mode.equalsIgnoreCase(ECB_MODE)) + result = new ECB(cipher, cipherBlockSize); + else if (mode.equalsIgnoreCase(CTR_MODE)) + result = new CTR(cipher, cipherBlockSize); + else if (mode.equalsIgnoreCase(ICM_MODE)) + result = new ICM(cipher, cipherBlockSize); + else if (mode.equalsIgnoreCase(OFB_MODE)) + result = new OFB(cipher, cipherBlockSize); + else if (mode.equalsIgnoreCase(CBC_MODE)) + result = new CBC(cipher, cipherBlockSize); + else if (mode.equalsIgnoreCase(CFB_MODE)) + result = new CFB(cipher, cipherBlockSize); + else if (mode.equalsIgnoreCase(EAX_MODE)) + result = new EAX(cipher, cipherBlockSize); + + if (result != null && ! result.selfTest()) + throw new InternalError(result.name()); + + return result; + } + + /** + * Returns a {@link Set} of names of mode supported by this <i>Factory</i>. + * + * @return a {@link Set} of mode names (Strings). + */ + public static final Set getNames() + { + synchronized (ModeFactory.class) + { + if (names == null) + { + HashSet hs = new HashSet(); + hs.add(ECB_MODE); + hs.add(CTR_MODE); + hs.add(ICM_MODE); + hs.add(OFB_MODE); + hs.add(CBC_MODE); + hs.add(CFB_MODE); + hs.add(EAX_MODE); + names = Collections.unmodifiableSet(hs); + } + } + return names; + } +} diff --git a/libjava/classpath/gnu/javax/crypto/mode/OFB.java b/libjava/classpath/gnu/javax/crypto/mode/OFB.java new file mode 100644 index 000000000..087f99132 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/mode/OFB.java @@ -0,0 +1,174 @@ +/* OFB.java -- + Copyright (C) 2001, 2002, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.mode; + +import gnu.java.security.Registry; +import gnu.javax.crypto.cipher.IBlockCipher; + +/** + * The Output Feedback (OFB) mode is a confidentiality mode that requires a + * unique <code>IV</code> for every message that is ever encrypted under the + * given key. The OFB mode is defined as follows: + * <ul> + * <li>OFB Encryption: + * <ul> + * <li>I<sub>1</sub> = IV;</li> + * <li>I<sub>j</sub> = O<sub>j -1</sub> for j = 2...n;</li> + * <li>O<sub>j</sub> = CIPH<sub>K</sub>(I<sub>j</sub>) for j = 1, 2...n;</li> + * <li>C<sub>j</sub> = P<sub>j</sub> XOR O<sub>j</sub> for j = 1, 2...n.</li> + * </ul> + * </li> + * <li>OFB Decryption: + * <ul> + * <li>I<sub>1</sub> = IV;</li> + * <li>I<sub>j</sub> = O<sub>j -1</sub> for j = 2...n;</li> + * <li>O<sub>j</sub> = CIPH<sub>K</sub>(I<sub>j</sub>) for j = 1, 2...n;</li> + * <li>P<sub>j</sub> = C<sub>j</sub> XOR O<sub>j</sub> for j = 1, 2...n.</li> + * </ul> + * </li> + * </ul> + * <p> + * In OFB encryption, the <code>IV</code> is transformed by the forward cipher + * function to produce the first output block. The first output block is + * exclusive-ORed with the first plaintext block to produce the first ciphertext + * block. The first output block is then transformed by the forward cipher + * function to produce the second output block. The second output block is + * exclusive-ORed with the second plaintext block to produce the second + * ciphertext block, and the second output block is transformed by the forward + * cipher function to produce the third output block. Thus, the successive + * output blocks are produced from enciphering the previous output blocks, and + * the output blocks are exclusive-ORed with the corresponding plaintext blocks + * to produce the ciphertext blocks. + * <p> + * In OFB decryption, the <code>IV</code> is transformed by the forward cipher + * function to produce the first output block. The first output block is + * exclusive-ORed with the first ciphertext block to recover the first plaintext + * block. The first output block is then transformed by the forward cipher + * function to produce the second output block. The second output block is + * exclusive-ORed with the second ciphertext block to produce the second + * plaintext block, and the second output block is also transformed by the + * forward cipher function to produce the third output block. Thus, the + * successive output blocks are produced from enciphering the previous output + * blocks, and the output blocks are exclusive-ORed with the corresponding + * ciphertext blocks to recover the plaintext blocks. + * <p> + * In both OFB encryption and OFB decryption, each forward cipher function + * (except the first) depends on the results of the previous forward cipher + * function; therefore, multiple forward cipher functions cannot be performed in + * parallel. However, if the <code>IV</code> is known, the output blocks can + * be generated prior to the availability of the plaintext or ciphertext data. + * <p> + * The OFB mode requires a unique <code>IV</code> for every message that is + * ever encrypted under the given key. If, contrary to this requirement, the + * same <code>IV</code> is used for the encryption of more than one message, + * then the confidentiality of those messages may be compromised. In particular, + * if a plaintext block of any of these messages is known, say, the j<sup>th</sup> + * plaintext block, then the j<sup>th</sup> output of the forward cipher + * function can be determined easily from the j<sup>th</sup> ciphertext block + * of the message. This information allows the j<sup>th</sup> plaintext block + * of any other message that is encrypted using the same <code>IV</code> to be + * easily recovered from the jth ciphertext block of that message. + * <p> + * Confidentiality may similarly be compromised if any of the input blocks to + * the forward cipher function for the encryption of a message is used as the + * <code>IV</code> for the encryption of another message under the given key. + * <p> + * References: + * <ol> + * <li><a + * href="http://csrc.nist.gov/encryption/modes/Recommendation/Modes01.pdf"> + * Recommendation for Block Cipher Modes of Operation Methods and Techniques</a>, + * Morris Dworkin.</li> + * </ol> + */ +public class OFB + extends BaseMode + implements Cloneable +{ + private byte[] outputBlock; + + /** + * Trivial package-private constructor for use by the Factory class. + * + * @param underlyingCipher the underlying cipher implementation. + * @param cipherBlockSize the underlying cipher block size to use. + */ + OFB(IBlockCipher underlyingCipher, int cipherBlockSize) + { + super(Registry.OFB_MODE, underlyingCipher, cipherBlockSize); + } + + /** + * Private constructor for cloning purposes. + * + * @param that the mode to clone. + */ + private OFB(OFB that) + { + this((IBlockCipher) that.cipher.clone(), that.cipherBlockSize); + } + + public Object clone() + { + return new OFB(this); + } + + public void setup() + { + if (modeBlockSize != cipherBlockSize) + throw new IllegalArgumentException(IMode.MODE_BLOCK_SIZE); + outputBlock = (byte[]) iv.clone(); + } + + public void teardown() + { + } + + public void encryptBlock(byte[] in, int i, byte[] out, int o) + { + cipher.encryptBlock(outputBlock, 0, outputBlock, 0); + for (int j = 0; j < cipherBlockSize;) + out[o++] = (byte)(in[i++] ^ outputBlock[j++]); + } + + public void decryptBlock(byte[] in, int i, byte[] out, int o) + { + this.encryptBlock(in, i, out, o); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/pad/BasePad.java b/libjava/classpath/gnu/javax/crypto/pad/BasePad.java new file mode 100644 index 000000000..feeaca2f0 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/pad/BasePad.java @@ -0,0 +1,193 @@ +/* BasePad.java -- + Copyright (C) 2001, 2002, 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.pad; + +import gnu.java.lang.CPStringBuilder; + +import gnu.java.security.Configuration; + +import java.util.Map; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * An abstract class to facilitate implementing padding algorithms. + */ +public abstract class BasePad + implements IPad +{ + private static final Logger log = Logger.getLogger(BasePad.class.getName()); + /** The canonical name prefix of the padding algorithm. */ + protected String name; + /** The block size, in bytes, for this instance. */ + protected int blockSize; + + /** Trivial constructor for use by concrete subclasses. */ + protected BasePad(final String name) + { + super(); + + this.name = name; + blockSize = -1; + } + + public String name() + { + final CPStringBuilder sb = new CPStringBuilder(name); + if (blockSize != -1) + sb.append('-').append(String.valueOf(8 * blockSize)); + return sb.toString(); + } + + public void init(final int bs) throws IllegalStateException + { + if (blockSize != -1) + throw new IllegalStateException(); + blockSize = bs; + setup(); + } + + /** + * Initialises the algorithm with designated attributes. Names, valid and/or + * recognisable by all concrete implementations are described in {@link IPad} + * class documentation. Other algorithm-specific attributes MUST be documented + * in the implementation class of that padding algorithm. + * <p> + * For compatibility reasons, this method is not declared <i>abstract</i>. + * Furthermore, and unless overridden, the default implementation will throw + * an {@link UnsupportedOperationException}. Concrete padding algorithms MUST + * override this method if they wish to offer an initialisation method that + * allows for other than the padding block size parameter to be specified. + * + * @param attributes a set of name-value pairs that describes the desired + * future behaviour of this instance. + * @exception IllegalStateException if the instance is already initialised. + * @exception IllegalArgumentException if the block size value is invalid. + */ + public void init(Map attributes) throws IllegalStateException + { + throw new UnsupportedOperationException(); + } + + public void reset() + { + blockSize = -1; + } + + /** + * A default implementation of a correctness test that exercises the padder + * implementation, using block sizes varying from 2 to 256 bytes. + * + * @return <code>true</code> if the concrete implementation correctly unpads + * what it pads for all tested block sizes. Returns <code>false</code> + * if the test fails for any block size. + */ + public boolean selfTest() + { + final byte[] in = new byte[1024]; + for (int bs = 2; bs < 256; bs++) + if (! test1BlockSize(bs, in)) + return false; + return true; + } + + /** + * The basic symmetric test for a padder given a specific block size. + * <p> + * The code ensures that the implementation is capable of unpadding what it + * pads. + * + * @param size the block size to test. + * @param buffer a work buffer. It is exposed as an argument for this method + * to reduce un-necessary object allocations. + * @return <code>true</code> if the test passes; <code>false</code> + * otherwise. + */ + protected boolean test1BlockSize(int size, byte[] buffer) + { + byte[] padBytes; + final int offset = 5; + final int limit = buffer.length; + this.init(size); + for (int i = 0; i < limit - offset - blockSize; i++) + { + padBytes = pad(buffer, offset, i); + if (((i + padBytes.length) % blockSize) != 0) + { + if (Configuration.DEBUG) + log.log(Level.SEVERE, + "Length of padded text MUST be a multiple of " + + blockSize, new RuntimeException(name())); + return false; + } + System.arraycopy(padBytes, 0, buffer, offset + i, padBytes.length); + try + { + if (padBytes.length != unpad(buffer, offset, i + padBytes.length)) + { + if (Configuration.DEBUG) + log.log(Level.SEVERE, + "IPad [" + name() + "] failed symmetric operation", + new RuntimeException(name())); + return false; + } + } + catch (WrongPaddingException x) + { + if (Configuration.DEBUG) + log.throwing(this.getClass().getName(), "test1BlockSize", x); + return false; + } + } + this.reset(); + return true; + } + + /** + * If any additional checks or resource setup must be done by the subclass, + * then this is the hook for it. This method will be called before the + * {@link #init(int)} method returns. + */ + public abstract void setup(); + + public abstract byte[] pad(byte[] in, int off, int len); + + public abstract int unpad(byte[] in, int off, int len) + throws WrongPaddingException; +} diff --git a/libjava/classpath/gnu/javax/crypto/pad/IPad.java b/libjava/classpath/gnu/javax/crypto/pad/IPad.java new file mode 100644 index 000000000..f5160e078 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/pad/IPad.java @@ -0,0 +1,127 @@ +/* IPad.java -- + Copyright (C) 2001, 2002, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.pad; + +import java.util.Map; + +/** + * The basic visible methods, and attribute names, of every padding algorithm. + * <p> + * Padding algorithms serve to <i>pad</i> and <i>unpad</i> byte arrays usually + * as the last step in an <i>encryption</i> or respectively a <i>decryption</i> + * operation. Their input buffers are usually those processed by instances of + * {@link gnu.javax.crypto.mode.IMode} and/or + * {@link gnu.javax.crypto.cipher.IBlockCipher}. + */ +public interface IPad +{ + /** + * Property name of the block size in which to operate the padding algorithm. + * The value associated with this property name is taken to be a positive + * {@link Integer} greater than zero. + */ + String PADDING_BLOCK_SIZE = "gnu.crypto.pad.block.size"; + + /** @return the canonical name of this instance. */ + String name(); + + /** + * Initialises the padding scheme with a designated block size. + * + * @param bs the designated block size. + * @exception IllegalStateException if the instance is already initialised. + * @exception IllegalArgumentException if the block size value is invalid. + */ + void init(int bs) throws IllegalStateException; + + /** + * Initialises the algorithm with designated attributes. Names, valid and/or + * recognisable by all concrete implementations are described in the class + * documentation above. Other algorithm-specific attributes MUST be documented + * in the implementation class of that padding algorithm. + * + * @param attributes a set of name-value pairs that describes the desired + * future behaviour of this instance. + * @exception IllegalStateException if the instance is already initialised. + * @exception IllegalArgumentException if the block size value is invalid. + */ + void init(Map attributes) throws IllegalStateException; + + /** + * Returns the byte sequence that should be appended to the designated input. + * + * @param in the input buffer containing the bytes to pad. + * @param offset the starting index of meaningful data in <i>in</i>. + * @param length the number of meaningful bytes in <i>in</i>. + * @return the possibly 0-byte long sequence to be appended to the designated + * input. + */ + byte[] pad(byte[] in, int offset, int length); + + /** + * Returns the number of bytes to discard from a designated input buffer. + * + * @param in the input buffer containing the bytes to unpad. + * @param offset the starting index of meaningful data in <i>in</i>. + * @param length the number of meaningful bytes in <i>in</i>. + * @return the number of bytes to discard, to the left of index position + * <code>offset + length</code> in <i>in</i>. In other words, if + * the return value of a successful invocation of this method is + * <code>result</code>, then the unpadded byte sequence will be + * <code>offset + length - result</code> bytes in <i>in</i>, + * starting from index position <code>offset</code>. + * @exception WrongPaddingException if the data is not terminated with the + * expected padding bytes. + */ + int unpad(byte[] in, int offset, int length) throws WrongPaddingException; + + /** + * Resets the scheme instance for re-initialisation and use with other + * characteristics. This method always succeeds. + */ + void reset(); + + /** + * A basic symmetric pad/unpad test. + * + * @return <code>true</code> if the implementation passes a basic symmetric + * self-test. Returns <code>false</code> otherwise. + */ + boolean selfTest(); +} diff --git a/libjava/classpath/gnu/javax/crypto/pad/ISO10126.java b/libjava/classpath/gnu/javax/crypto/pad/ISO10126.java new file mode 100644 index 000000000..8e8c59254 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/pad/ISO10126.java @@ -0,0 +1,109 @@ +/* ISO10126.java -- An implementation of the ISO 10126-2 padding scheme + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.pad; + +import gnu.java.security.Registry; +import gnu.java.security.util.PRNG; + +/** + * The implementation of the ISO 10126-2 padding algorithm. + * <p> + * The last byte of the padding block is the number of padding bytes, all other + * padding bytes are random. + * <p> + * References: + * <ol> + * <li><a href="http://www.w3.org/TR/xmlenc-core/">XML Encryption Syntax and + * Processing</a> Section "5.2 Block Encryption Algorithms"; "Padding".</li> + * </ol> + */ +public final class ISO10126 + extends BasePad +{ + /** Used to generate random numbers for padding bytes. */ + private PRNG prng; + + ISO10126() + { + super(Registry.ISO10126_PAD); + prng = PRNG.getInstance(); + } + + public void setup() + { + // Nothing to do here + } + + public byte[] pad(byte[] in, int offset, int length) + { + int padLength = blockSize - (length % blockSize); + final byte[] pad = new byte[padLength]; + + // generate random numbers for the padding bytes except for the last byte + prng.nextBytes(pad, 0, padLength - 1); + // the last byte contains the number of padding bytes + pad[padLength - 1] = (byte) padLength; + + return pad; + } + + public int unpad(byte[] in, int offset, int length) + throws WrongPaddingException + { + // the last byte contains the number of padding bytes + int padLength = in[offset + length - 1] & 0xFF; + if (padLength > length) + throw new WrongPaddingException(); + + return padLength; + } + + /** + * The default self-test in the super-class would take too long to finish + * with this type of padder --due to the large amount of random data needed. + * We override the default test and replace it with a simple one for a 16-byte + * block-size (default AES block-size). The Mauve test TestOfISO10126 will + * exercise all block-sizes that the default self-test uses for the other + * padders. + */ + public boolean selfTest() + { + return test1BlockSize(16, new byte[1024]); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/pad/PKCS1_V1_5.java b/libjava/classpath/gnu/javax/crypto/pad/PKCS1_V1_5.java new file mode 100644 index 000000000..e303264ae --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/pad/PKCS1_V1_5.java @@ -0,0 +1,156 @@ +/* PKCS1_V1_5.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.pad; + +import gnu.java.security.Configuration; +import gnu.java.security.Registry; +import gnu.java.security.sig.rsa.EME_PKCS1_V1_5; +import gnu.java.security.util.PRNG; +import gnu.java.security.util.Util; + +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * A padding algorithm implementation of the EME-PKCS1-V1.5 encoding/decoding + * algorithm as described in section 7.2 of RFC-3447. This is effectively an + * <i>Adapter</i> over an instance of {@link EME_PKCS1_V1_5} initialised with + * the RSA public shared modulus length (in bytes). + * <p> + * References: + * <ol> + * <li><a href="http://www.ietf.org/rfc/rfc3447.txt">Public-Key Cryptography + * Standards (PKCS) #1:</a><br> + * RSA Cryptography Specifications Version 2.1.<br> + * Jakob Jonsson and Burt Kaliski.</li> + * </ol> + * + * @see EME_PKCS1_V1_5 + */ +public class PKCS1_V1_5 + extends BasePad +{ + private static final Logger log = Logger.getLogger(PKCS1_V1_5.class.getName()); + private EME_PKCS1_V1_5 codec; + + /** + * Trivial package-private constructor for use by the <i>Factory</i> class. + * + * @see PadFactory + */ + PKCS1_V1_5() + { + super(Registry.EME_PKCS1_V1_5_PAD); + } + + public void setup() + { + codec = EME_PKCS1_V1_5.getInstance(blockSize); + } + + public byte[] pad(final byte[] in, final int offset, final int length) + { + final byte[] M = new byte[length]; + System.arraycopy(in, offset, M, 0, length); + final byte[] EM = codec.encode(M); + final byte[] result = new byte[blockSize - length]; + System.arraycopy(EM, 0, result, 0, result.length); + if (Configuration.DEBUG) + log.fine("padding: 0x" + Util.toString(result)); + return result; + } + + public int unpad(final byte[] in, final int offset, final int length) + throws WrongPaddingException + { + final byte[] EM = new byte[length]; + System.arraycopy(in, offset, EM, 0, length); + final int result = length - codec.decode(EM).length; + if (Configuration.DEBUG) + log.fine("padding length: " + String.valueOf(result)); + return result; + } + + public boolean selfTest() + { + final int[] mLen = new int[] { 16, 20, 32, 48, 64 }; + final byte[] M = new byte[mLen[mLen.length - 1]]; + PRNG.getInstance().nextBytes(M); + final byte[] EM = new byte[1024]; + byte[] p; + int bs, i, j; + for (bs = 256; bs < 1025; bs += 256) + { + init(bs); + for (i = 0; i < mLen.length; i++) + { + j = mLen[i]; + p = pad(M, 0, j); + if (j + p.length != blockSize) + { + if (Configuration.DEBUG) + log.log(Level.SEVERE, + "Length of padded text MUST be a multiple of " + + blockSize, new RuntimeException(name())); + return false; + } + System.arraycopy(p, 0, EM, 0, p.length); + System.arraycopy(M, 0, EM, p.length, j); + try + { + if (p.length != unpad(EM, 0, blockSize)) + { + if (Configuration.DEBUG) + log.log(Level.SEVERE, "Failed symmetric operation", + new RuntimeException(name())); + return false; + } + } + catch (WrongPaddingException x) + { + if (Configuration.DEBUG) + log.throwing(this.getClass().getName(), "selfTest", x); + return false; + } + } + reset(); + } + return true; + } +} diff --git a/libjava/classpath/gnu/javax/crypto/pad/PKCS7.java b/libjava/classpath/gnu/javax/crypto/pad/PKCS7.java new file mode 100644 index 000000000..9dd67fc81 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/pad/PKCS7.java @@ -0,0 +1,111 @@ +/* PKCS7.java -- + Copyright (C) 2001, 2002, 2006 Free Software Foundation, Inc. + + This file is a part of GNU Classpath. + + GNU Classpath 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; either version 2 of the License, or (at + your option) any later version. + + GNU Classpath 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 GNU Classpath; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 + USA + + Linking this library statically or dynamically with other modules is + making a combined work based on this library. Thus, the terms and + conditions of the GNU General Public License cover the whole + combination. + + As a special exception, the copyright holders of this library give you + permission to link this library with independent modules to produce an + executable, regardless of the license terms of these independent + modules, and to copy and distribute the resulting executable under + terms of your choice, provided that you also meet, for each linked + independent module, the terms and conditions of the license of that + module. An independent module is a module which is not derived from + or based on this library. If you modify this library, you may extend + this exception to your version of the library, but you are not + obligated to do so. If you do not wish to do so, delete this + exception statement from your version. */ + + +package gnu.javax.crypto.pad; + +import gnu.java.security.Configuration; +import gnu.java.security.Registry; +import gnu.java.security.util.Util; + +import java.util.logging.Logger; + +/** + * The implementation of the PKCS7 padding algorithm. + * <p> + * This algorithm is described for 8-byte blocks in [RFC-1423] and extended to + * block sizes of up to 256 bytes in [PKCS-7]. + * <p> + * References: + * <ol> + * <li><a href="http://www.ietf.org/rfc/rfc1423.txt">RFC-1423</a>: Privacy + * Enhancement for Internet Electronic Mail: Part III: Algorithms, Modes, and + * Identifiers.</li> + * <li><a href="http://www.ietf.org/">IETF</a>.</li> + * <li><a href="http://www.rsasecurity.com/rsalabs/pkcs/pkcs-7/">[PKCS-7]</a> + * PKCS #7: Cryptographic Message Syntax Standard - An RSA Laboratories + * Technical Note.</li> + * <li><a href="http://www.rsasecurity.com/">RSA Security</a>.</li> + * </ol> + */ +public final class PKCS7 + extends BasePad +{ + private static final Logger log = Logger.getLogger(PKCS7.class.getName()); + + /** + * Trivial package-private constructor for use by the <i>Factory</i> class. + * + * @see PadFactory + */ + PKCS7() + { + super(Registry.PKCS7_PAD); + } + + public void setup() + { + if (blockSize < 2 || blockSize > 256) + throw new IllegalArgumentException(); + } + + public byte[] pad(byte[] in, int offset, int length) + { + int padLength = blockSize; + if (length % blockSize != 0) + padLength = blockSize - length % blockSize; + byte[] result = new byte[padLength]; + for (int i = 0; i < padLength;) + result[i++] = (byte) padLength; + if (Configuration.DEBUG) + log.fine("padding: 0x" + Util.toString(result)); + return result; + } + + public int unpad(byte[] in, int offset, int length) + throws WrongPaddingException + { + int limit = offset + length; + int result = in[--limit] & 0xFF; + for (int i = 0; i < result - 1; i++) + if (result != (in[--limit] & 0xFF)) + throw new WrongPaddingException(); + if (Configuration.DEBUG) + log.fine("padding length: " + result); + return result; + } +} diff --git a/libjava/classpath/gnu/javax/crypto/pad/PadFactory.java b/libjava/classpath/gnu/javax/crypto/pad/PadFactory.java new file mode 100644 index 000000000..2df2029fa --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/pad/PadFactory.java @@ -0,0 +1,120 @@ +/* PadFactory.java -- + Copyright (C) 2001, 2002, 2003, 2004, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.pad; + +import gnu.java.security.Registry; + +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; + +/** + * A Factory to instantiate padding schemes. + */ +public class PadFactory + implements Registry +{ + /** Collection of padding algorithm names --cached for speed. */ + private static Set names; + + /** Trivial constructor to enforce Singleton pattern. */ + private PadFactory() + { + super(); + } + + /** + * Returns an instance of a padding algorithm given its name. + * + * @param pad the case-insensitive name of the padding algorithm. + * @return an instance of the padding algorithm, operating with a given block + * size, or <code>null</code> if none found. + * @throws InternalError if the implementation does not pass its self-test. + */ + public static final IPad getInstance(String pad) + { + if (pad == null) + return null; + + pad = pad.trim().toLowerCase(); + if (pad.endsWith("padding")) + pad = pad.substring(0, pad.length() - "padding".length()); + IPad result = null; + if (pad.equals(PKCS7_PAD) || pad.equals(PKCS5_PAD)) + result = new PKCS7(); + else if (pad.equals(TBC_PAD)) + result = new TBC(); + else if (pad.equals(EME_PKCS1_V1_5_PAD)) + result = new PKCS1_V1_5(); + else if (pad.equals(SSL3_PAD)) + result = new SSL3(); + else if (pad.equals(TLS1_PAD)) + result = new TLS1(); + else if (pad.equals(ISO10126_PAD)) + result = new ISO10126(); + + if (result != null && ! result.selfTest()) + throw new InternalError(result.name()); + + return result; + } + + /** + * Returns a {@link Set} of names of padding algorithms supported by this + * <i>Factory</i>. + * + * @return a {@link Set} of padding algorithm names (Strings). + */ + public static final Set getNames() + { + if (names == null) + { + HashSet hs = new HashSet(); + hs.add(PKCS5_PAD); + hs.add(PKCS7_PAD); + hs.add(TBC_PAD); + hs.add(EME_PKCS1_V1_5_PAD); + hs.add(SSL3_PAD); + hs.add(TLS1_PAD); + hs.add(ISO10126_PAD); + names = Collections.unmodifiableSet(hs); + } + return names; + } +} diff --git a/libjava/classpath/gnu/javax/crypto/pad/SSL3.java b/libjava/classpath/gnu/javax/crypto/pad/SSL3.java new file mode 100644 index 000000000..78964d619 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/pad/SSL3.java @@ -0,0 +1,90 @@ +/* SSL3.java -- SSLv3 padding scheme. + Copyright (C) 2004, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.pad; + +/** + * The padding scheme used by the Secure Sockets Layer, version 3. This padding + * scheme is used in the block-ciphered struct, e.g.: + * <pre> + * block-ciphered struct { + * opaque content[SSLCompressed.length]; + * opaque MAC[CipherSpec.hash_size]; + * uint8 padding[GenericBlockCipher.padding_length]; + * uint8 padding_length; + * } GenericBlockCipher; + * </pre> + * <p> + * Where <i>padding_length</i> is <i>cipher_block_size</i> - + * ((<i>SSLCompressed.length</i> + <i>CipherSpec.hash_size</i>) % + * <i>cipher_block_size</i>) - 1. That is, the padding is enough bytes to make + * the plaintext a multiple of the block size minus one, plus one additional + * byte for the padding length. The padding can be any arbitrary data. + */ +public class SSL3 + extends BasePad +{ + public SSL3() + { + super("ssl3"); + } + + public void setup() + { + if (blockSize <= 0 || blockSize > 255) + throw new IllegalArgumentException("invalid block size: " + blockSize); + } + + public byte[] pad(final byte[] in, final int off, final int len) + { + int padlen = blockSize - (len % blockSize); + byte[] pad = new byte[padlen]; + for (int i = 0; i < padlen; i++) + pad[i] = (byte)(padlen - 1); + return pad; + } + + public int unpad(final byte[] in, final int off, final int len) + throws WrongPaddingException + { + int padlen = in[off + len - 1] & 0xFF; + if (padlen >= blockSize) + throw new WrongPaddingException(); + return padlen + 1; + } +} diff --git a/libjava/classpath/gnu/javax/crypto/pad/TBC.java b/libjava/classpath/gnu/javax/crypto/pad/TBC.java new file mode 100644 index 000000000..5cd177058 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/pad/TBC.java @@ -0,0 +1,118 @@ +/* TBC.java -- + Copyright (C) 2001, 2002, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.pad; + +import gnu.java.security.Configuration; +import gnu.java.security.Registry; +import gnu.java.security.util.Util; + +import java.util.logging.Logger; + +/** + * The implementation of the Trailing Bit Complement (TBC) padding algorithm. + * <p> + * In this mode, "...the data string is padded at the trailing end with the + * complement of the trailing bit of the unpadded message: if the trailing bit + * is <tt>1</tt>, then <tt>0</tt> bits are appended, and if the trailing + * bit is <tt>0</tt>, then <tt>1</tt> bits are appended. As few bits are + * added as are necessary to meet the formatting size requirement." + * <p> + * References: + * <ol> + * <li><a + * href="http://csrc.nist.gov/encryption/modes/Recommendation/Modes01.pdf"> + * Recommendation for Block Cipher Modes of Operation Methods and + * Techniques</a>, Morris Dworkin.</li> + * </ol> + */ +public final class TBC + extends BasePad +{ + private static final Logger log = Logger.getLogger(TBC.class.getName()); + + /** + * Trivial package-private constructor for use by the <i>Factory</i> class. + * + * @see PadFactory + */ + TBC() + { + super(Registry.TBC_PAD); + } + + public void setup() + { + if (blockSize < 1 || blockSize > 256) + throw new IllegalArgumentException(); + } + + public byte[] pad(byte[] in, int offset, int length) + { + int padLength = blockSize; + if (length % blockSize != 0) + padLength = blockSize - length % blockSize; + byte[] result = new byte[padLength]; + int lastBit = in[offset + length - 1] & 0x01; + if (lastBit == 0) + for (int i = 0; i < padLength;) + result[i++] = 0x01; + // else it's already set to zeroes by virtue of initialisation + if (Configuration.DEBUG) + log.fine("padding: 0x" + Util.toString(result)); + return result; + } + + public int unpad(byte[] in, int offset, int length) + throws WrongPaddingException + { + int limit = offset + length - 1; + int lastBit = in[limit] & 0xFF; + int result = 0; + while (lastBit == (in[limit] & 0xFF)) + { + result++; + limit--; + } + if (result > length) + throw new WrongPaddingException(); + if (Configuration.DEBUG) + log.fine("padding length: " + result); + return result; + } +} diff --git a/libjava/classpath/gnu/javax/crypto/pad/TLS1.java b/libjava/classpath/gnu/javax/crypto/pad/TLS1.java new file mode 100644 index 000000000..1d690dd59 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/pad/TLS1.java @@ -0,0 +1,91 @@ +/* TLS1.java -- TLSv1 padding scheme. + Copyright (C) 2004, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.pad; + +/** + * The padding scheme used by the Transport Layer Security protocol, version 1. + * This padding scheme is used in the block-ciphered struct, e.g.: + * <pre> + * block-ciphered struct { + * opaque content[TLSCompressed.length]; + * opaque MAC[CipherSpec.hash_size]; + * uint8 padding[GenericBlockCipher.padding_length]; + * uint8 padding_length; + * } GenericBlockCipher; + * </pre> + * <p> + * Where <i>padding_length</i> is any multiple of <i>cipher_block_size</i> - + * ((<i>SSLCompressed.length</i> + <i>CipherSpec.hash_size</i>) % + * <i>cipher_block_size</i>) - 1 that is less than 255. Every byte of the + * padding must be equal to <i>padding_length</i>. That is, the end of the + * plaintext is <i>n</i> + 1 copies of the unsigned byte <i>n</i>. + */ +public class TLS1 + extends BasePad +{ + public TLS1() + { + super("tls1"); + } + + public void setup() + { + if (blockSize <= 0 || blockSize > 255) + throw new IllegalArgumentException("invalid block size: " + blockSize); + } + + public byte[] pad(final byte[] in, final int off, final int len) + { + int padlen = blockSize - (len % blockSize); + byte[] pad = new byte[padlen]; + for (int i = 0; i < padlen; i++) + pad[i] = (byte)(padlen - 1); + return pad; + } + + public int unpad(final byte[] in, final int off, final int len) + throws WrongPaddingException + { + int padlen = in[off + len - 1] & 0xFF; + for (int i = off + (len - padlen - 1); i < off + len - 1; i++) + if ((in[i] & 0xFF) != padlen) + throw new WrongPaddingException(); + return padlen + 1; + } +} diff --git a/libjava/classpath/gnu/javax/crypto/pad/WrongPaddingException.java b/libjava/classpath/gnu/javax/crypto/pad/WrongPaddingException.java new file mode 100644 index 000000000..d15723faf --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/pad/WrongPaddingException.java @@ -0,0 +1,48 @@ +/* WrongPaddingException.java -- + Copyright (C) 2001, 2002, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.pad; + +/** + * A checked exception that indicates that a padding algorithm did not find the + * expected padding bytes when unpadding some data. + */ +public class WrongPaddingException + extends Exception +{ +} diff --git a/libjava/classpath/gnu/javax/crypto/prng/ARCFour.java b/libjava/classpath/gnu/javax/crypto/prng/ARCFour.java new file mode 100644 index 000000000..60464d5ba --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/prng/ARCFour.java @@ -0,0 +1,137 @@ +/* ARCFour.java -- + Copyright (C) 2002, 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.prng; + +import gnu.java.security.Registry; +import gnu.java.security.prng.BasePRNG; +import gnu.java.security.prng.LimitReachedException; + +import java.util.Map; + +/** + * RC4 is a stream cipher developed by Ron Rivest. Until 1994 RC4 was a trade + * secret of RSA Data Security, Inc., when it was released anonymously to a + * mailing list. This version is a descendent of that code, and since there is + * no proof that the leaked version was in fact RC4 and because "RC4" is a + * trademark, it is called "ARCFOUR", short for "Allegedly RC4". + * <p> + * This class only implements the <i>keystream</i> of ARCFOUR. To use this as a + * stream cipher, one would say: + * <pre> + * out = in ˆ arcfour.nextByte(); + * </pre> + * <p> + * This operation works for encryption and decryption. + * <p> + * References: + * <ol> + * <li>Schneier, Bruce: <i>Applied Cryptography: Protocols, Algorithms, and + * Source Code in C, Second Edition.</i> (1996 John Wiley and Sons), pp. + * 397--398. ISBN 0-471-11709-9</li> + * <li>K. Kaukonen and R. Thayer, "A Stream Cipher Encryption Algorithm + * 'Arcfour'", Internet Draft (expired), <a + * href="http://www.mozilla.org/projects/security/pki/nss/draft-kaukonen-cipher-arcfour-03.txt">draft-kaukonen-cipher-arcfour-03.txt</a></li> + * </ol> + */ +public class ARCFour + extends BasePRNG + implements Cloneable +{ + /** The attributes property name for the key bytes. */ + public static final String ARCFOUR_KEY_MATERIAL = "gnu.crypto.prng.arcfour.key-material"; + /** The size of the internal S-box. */ + public static final int ARCFOUR_SBOX_SIZE = 256; + /** The S-box. */ + private byte[] s; + private byte m, n; + + /** Default 0-arguments constructor. */ + public ARCFour() + { + super(Registry.ARCFOUR_PRNG); + } + + public void setup(Map attributes) + { + byte[] kb = (byte[]) attributes.get(ARCFOUR_KEY_MATERIAL); + if (kb == null) + throw new IllegalArgumentException("ARCFOUR needs a key"); + s = new byte[ARCFOUR_SBOX_SIZE]; + m = n = 0; + byte[] k = new byte[ARCFOUR_SBOX_SIZE]; + for (int i = 0; i < ARCFOUR_SBOX_SIZE; i++) + s[i] = (byte) i; + if (kb.length > 0) + for (int i = 0, j = 0; i < ARCFOUR_SBOX_SIZE; i++) + { + k[i] = kb[j++]; + if (j >= kb.length) + j = 0; + } + for (int i = 0, j = 0; i < ARCFOUR_SBOX_SIZE; i++) + { + j = j + s[i] + k[i]; + byte temp = s[i]; + s[i] = s[j & 0xff]; + s[j & 0xff] = temp; + } + buffer = new byte[ARCFOUR_SBOX_SIZE]; + try + { + fillBlock(); + } + catch (LimitReachedException wontHappen) + { + } + } + + public void fillBlock() throws LimitReachedException + { + for (int i = 0; i < buffer.length; i++) + { + m++; + n = (byte)(n + s[m & 0xff]); + byte temp = s[m & 0xff]; + s[m & 0xff] = s[n & 0xff]; + s[n & 0xff] = temp; + temp = (byte)(s[m & 0xff] + s[n & 0xff]); + buffer[i] = s[temp & 0xff]; + } + } +} diff --git a/libjava/classpath/gnu/javax/crypto/prng/CSPRNG.java b/libjava/classpath/gnu/javax/crypto/prng/CSPRNG.java new file mode 100644 index 000000000..ecea2f469 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/prng/CSPRNG.java @@ -0,0 +1,985 @@ +/* CSPRNG.java -- continuously-seeded pseudo-random number generator. + Copyright (C) 2004, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.prng; + +import gnu.java.security.Configuration; +import gnu.java.security.Properties; +import gnu.java.security.Registry; +import gnu.java.security.hash.HashFactory; +import gnu.java.security.hash.IMessageDigest; +import gnu.java.security.prng.BasePRNG; +import gnu.java.security.prng.EntropySource; +import gnu.java.security.prng.IRandom; +import gnu.java.security.prng.LimitReachedException; +import gnu.java.security.util.SimpleList; +import gnu.java.security.util.Util; +import gnu.javax.crypto.cipher.CipherFactory; +import gnu.javax.crypto.cipher.IBlockCipher; + +import java.io.ByteArrayOutputStream; +import java.io.FileInputStream; +import java.io.InputStream; +import java.io.PrintStream; +import java.net.MalformedURLException; +import java.net.URL; +import java.security.AccessController; +import java.security.InvalidKeyException; +import java.security.PrivilegedAction; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.StringTokenizer; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * An entropy pool-based pseudo-random number generator based on the PRNG in + * Peter Gutmann's cryptlib (<a + * href="http://www.cs.auckland.ac.nz/~pgut001/cryptlib/">http://www.cs.auckland.ac.nz/~pgut001/cryptlib/</a>). + * <p> + * The basic properties of this generator are: + * <ol> + * <li>The internal state cannot be determined by knowledge of the input.</li> + * <li>It is resistant to bias introduced by specific inputs.</li> + * <li>The output does not reveal the state of the generator.</li> + * </ol> + */ +public class CSPRNG + extends BasePRNG +{ + private static final Logger log = Logger.getLogger(CSPRNG.class.getName()); + /** + * Property name for the list of files to read for random values. The mapped + * value is a list with the following values: + * <ol> + * <li>A {@link Double}, indicating the suggested <i>quality</i> of this + * source. This value must be between 0 and 100.</li> + * <li>An {@link Integer}, indicating the number of bytes to skip in the + * file before reading bytes. This can be any nonnegative value.</li> + * <li>An {@link Integer}, indicating the number of bytes to read.</li> + * <li>A {@link String}, indicating the path to the file.</li> + * </ol> + * + * @see gnu.java.security.util.SimpleList + */ + public static final String FILE_SOURCES = "gnu.crypto.prng.pool.files"; + /** + * Property name for the list of URLs to poll for random values. The mapped + * value is a list formatted similarly as in {@link #FILE_SOURCES}, but the + * fourth member is a {@link URL}. + */ + public static final String URL_SOURCES = "gnu.crypto.prng.pool.urls"; + /** + * Property name for the list of programs to execute, and use the output as + * new random bytes. The mapped property is formatted similarly an in + * {@link #FILE_SOURCES} and {@link #URL_SOURCES}, except the fourth member + * is a {@link String} of the program to execute. + */ + public static final String PROGRAM_SOURCES = "gnu.crypto.prng.pool.programs"; + /** + * Property name for a list of other sources of entropy. The mapped value must + * be a list of {@link EntropySource} objects. + */ + public static final String OTHER_SOURCES = "gnu.crypto.prng.pool.other"; + /** + * Property name for whether or not to wait for the slow poll to complete, + * passed as a {@link Boolean}. The default value is true. + */ + public static final String BLOCKING = "gnu.crypto.prng.pool.blocking"; + private static final String FILES = "gnu.crypto.csprng.file."; + private static final String URLS = "gnu.crypto.csprng.url."; + private static final String PROGS = "gnu.crypto.csprng.program."; + private static final String OTHER = "gnu.crypto.csprng.other."; + private static final String BLOCK = "gnu.crypto.csprng.blocking"; + private static final int POOL_SIZE = 256; + private static final int ALLOC_SIZE = 260; + private static final int OUTPUT_SIZE = POOL_SIZE / 2; + private static final int X917_POOL_SIZE = 16; + private static final String HASH_FUNCTION = Registry.SHA160_HASH; + private static final String CIPHER = Registry.AES_CIPHER; + private static final int MIX_COUNT = 10; + private static final int X917_LIFETIME = 8192; + // FIXME this should be configurable. + private static final int SPINNER_COUNT = 8; + /** + * The spinner group singleton. We use this to add a small amount of + * randomness (in addition to the current time and the amount of free memory) + * based on the randomness (if any) present due to system load and thread + * scheduling. + */ + private static final Spinner[] SPINNERS = new Spinner[SPINNER_COUNT]; + private static final Thread[] SPINNER_THREADS = new Thread[SPINNER_COUNT]; + static + { + for (int i = 0; i < SPINNER_COUNT; i++) + { + SPINNER_THREADS[i] = new Thread(SPINNERS[i] = new Spinner(), + "spinner-" + i); + SPINNER_THREADS[i].setDaemon(true); + SPINNER_THREADS[i].setPriority(Thread.MIN_PRIORITY); + SPINNER_THREADS[i].start(); + } + } + /** The message digest (SHA-1) used in the mixing function. */ + private final IMessageDigest hash; + /** The cipher (AES) used in the output masking function. */ + private final IBlockCipher cipher; + /** The number of times the pool has been mixed. */ + private int mixCount; + /** The entropy pool. */ + private final byte[] pool; + /** The quality of the random pool (percentage). */ + private double quality; + /** The index of the next byte in the entropy pool. */ + private int index; + /** The pool for the X9.17-like generator. */ + private byte[] x917pool; + /** The number of iterations of the X9.17-like generators. */ + private int x917count; + /** Whether or not the X9.17-like generator is initialized. */ + private boolean x917init; + /** The list of file soures. */ + private final List files; + /** The list of URL sources. */ + private final List urls; + /** The list of program sources. */ + private final List progs; + /** The list of other sources. */ + private final List other; + /** Whether or not to wait for the slow poll to complete. */ + private boolean blocking; + /** The thread that polls for random data. */ + private Poller poller; + private Thread pollerThread; + + public CSPRNG() + { + super("CSPRNG"); + pool = new byte[ALLOC_SIZE]; + x917pool = new byte[X917_POOL_SIZE]; + x917count = 0; + x917init = false; + quality = 0.0; + hash = HashFactory.getInstance(HASH_FUNCTION); + cipher = CipherFactory.getInstance(CIPHER); + buffer = new byte[OUTPUT_SIZE]; + ndx = 0; + initialised = false; + files = new LinkedList(); + urls = new LinkedList(); + progs = new LinkedList(); + other = new LinkedList(); + } + + /** + * Create and initialize a CSPRNG instance with the "system" parameters; the + * files, URLs, programs, and {@link EntropySource} sources used by the + * instance are derived from properties set in the system {@link Properties}. + * <p> + * All properties are of the from <i>name</i>.</i>N</i>, where <i>name</i> + * is the name of the source, and <i>N</i> is an integer (staring at 1) that + * indicates the preference number for that source. + * <p> + * The following vales for <i>name</i> are used here: + * <dl> + * <dt>gnu.crypto.csprng.file</dt> + * <dd> + * <p> + * These properties are file sources, passed as the {@link #FILE_SOURCES} + * parameter of the instance. The property value is a 4-tuple formatted as: + * </p> + * <blockquote><i>quality</i> ; <i>offset</i> ; <i>count</i> ; <i>path</i></blockquote> + * <p> + * The parameters are mapped to the parameters defined for {@link + * #FILE_SOURCES}. Leading or trailing spaces on any item are trimmed off. + * </p> + * </dd> + * <dt>gnu.crypto.csprng.url</dt> + * <dd> + * <p> + * These properties are URL sources, passed as the {@link #URL_SOURCES} + * parameter of the instance. The property is formatted the same way as file + * sources, but the <i>path</i> argument must be a valid URL. + * </p> + * </dd> + * <dt>gnu.crypto.csprng.program</dt> + * <dd> + * <p> + * These properties are program sources, passed as the {@link + * #PROGRAM_SOURCES} parameter of the instance. This property is formatted the + * same way as file and URL sources, but the last argument is a program and + * its arguments. + * </p> + * </dd> + * <dt>gnu.crypto.cspring.other</dt> + * <dd> + * <p> + * These properties are other sources, passed as the {@link #OTHER_SOURCES} + * parameter of the instance. The property value must be the full name of a + * class that implements the {@link EntropySource} interface and has a public + * no-argument constructor. + * </p> + * </dd> + * </dl> + * <p> + * Finally, a boolean property "gnu.crypto.csprng.blocking" can be set to the + * desired value of {@link #BLOCKING}. + * <p> + * An example of valid properties would be: + * <pre> + * gnu.crypto.csprng.blocking=true + * + * gnu.crypto.csprng.file.1=75.0;0;256;/dev/random + * gnu.crypto.csprng.file.2=10.0;0;100;/home/user/file + * + * gnu.crypto.csprng.url.1=5.0;0;256;http://www.random.org/cgi-bin/randbyte?nbytes=256 + * gnu.crypto.csprng.url.2=0;256;256;http://slashdot.org/ + * + * gnu.crypto.csprng.program.1=0.5;0;10;last -n 50 + * gnu.crypto.csprng.program.2=0.5;0;10;tcpdump -c 5 + * + * gnu.crypto.csprng.other.1=foo.bar.MyEntropySource + * gnu.crypto.csprng.other.2=com.company.OtherEntropySource + * </pre> + */ + public static IRandom getSystemInstance() throws ClassNotFoundException, + MalformedURLException, NumberFormatException + { + CSPRNG instance = new CSPRNG(); + HashMap attrib = new HashMap(); + attrib.put(BLOCKING, Boolean.valueOf(getProperty(BLOCK))); + String s = null; + // Get each file source "gnu.crypto.csprng.file.N". + List l = new LinkedList(); + for (int i = 0; (s = getProperty(FILES + i)) != null; i++) + try + { + l.add(parseString(s.trim())); + } + catch (NumberFormatException nfe) + { + } + attrib.put(FILE_SOURCES, l); + l = new LinkedList(); + for (int i = 0; (s = getProperty(URLS + i)) != null; i++) + try + { + l.add(parseURL(s.trim())); + } + catch (NumberFormatException nfe) + { + } + catch (MalformedURLException mue) + { + } + attrib.put(URL_SOURCES, l); + l = new LinkedList(); + for (int i = 0; (s = getProperty(PROGS + i)) != null; i++) + try + { + l.add(parseString(s.trim())); + } + catch (NumberFormatException nfe) + { + } + attrib.put(PROGRAM_SOURCES, l); + l = new LinkedList(); + for (int i = 0; (s = getProperty(OTHER + i)) != null; i++) + try + { + Class c = Class.forName(s.trim()); + l.add(c.newInstance()); + } + catch (ClassNotFoundException cnfe) + { + } + catch (InstantiationException ie) + { + } + catch (IllegalAccessException iae) + { + } + attrib.put(OTHER_SOURCES, l); + instance.init(attrib); + return instance; + } + + private static String getProperty(final String name) + { + return (String) AccessController.doPrivileged(new PrivilegedAction() + { + public Object run() + { + return Properties.getProperty(name); + } + }); + } + + private static List parseString(String s) throws NumberFormatException + { + StringTokenizer tok = new StringTokenizer(s, ";"); + if (tok.countTokens() != 4) + throw new IllegalArgumentException("malformed property"); + Double quality = new Double(tok.nextToken()); + Integer offset = new Integer(tok.nextToken()); + Integer length = new Integer(tok.nextToken()); + String str = tok.nextToken(); + return new SimpleList(quality, offset, length, str); + } + + private static List parseURL(String s) throws MalformedURLException, + NumberFormatException + { + StringTokenizer tok = new StringTokenizer(s, ";"); + if (tok.countTokens() != 4) + throw new IllegalArgumentException("malformed property"); + Double quality = new Double(tok.nextToken()); + Integer offset = new Integer(tok.nextToken()); + Integer length = new Integer(tok.nextToken()); + URL url = new URL(tok.nextToken()); + return new SimpleList(quality, offset, length, url); + } + + public Object clone() + { + return new CSPRNG(); + } + + public void setup(Map attrib) + { + List list = null; + if (Configuration.DEBUG) + log.fine("attrib=" + String.valueOf(attrib)); + try + { + list = (List) attrib.get(FILE_SOURCES); + if (Configuration.DEBUG) + log.fine("list=" + String.valueOf(list)); + if (list != null) + { + files.clear(); + for (Iterator it = list.iterator(); it.hasNext();) + { + List l = (List) it.next(); + if (Configuration.DEBUG) + log.fine("l=" + l); + if (l.size() != 4) + { + if (Configuration.DEBUG) + log.fine("file list too small: " + l.size()); + throw new IllegalArgumentException("invalid file list"); + } + Double quality = (Double) l.get(0); + Integer offset = (Integer) l.get(1); + Integer length = (Integer) l.get(2); + String source = (String) l.get(3); + files.add(new SimpleList(quality, offset, length, source)); + } + } + } + catch (ClassCastException cce) + { + if (Configuration.DEBUG) + log.log(Level.FINE, "bad file list", cce); + throw new IllegalArgumentException("invalid file list"); + } + try + { + list = (List) attrib.get(URL_SOURCES); + if (Configuration.DEBUG) + log.fine("list=" + String.valueOf(list)); + if (list != null) + { + urls.clear(); + for (Iterator it = list.iterator(); it.hasNext();) + { + List l = (List) it.next(); + if (Configuration.DEBUG) + log.fine("l=" + l); + if (l.size() != 4) + { + if (Configuration.DEBUG) + log.fine("URL list too small: " + l.size()); + throw new IllegalArgumentException("invalid URL list"); + } + Double quality = (Double) l.get(0); + Integer offset = (Integer) l.get(1); + Integer length = (Integer) l.get(2); + URL source = (URL) l.get(3); + urls.add(new SimpleList(quality, offset, length, source)); + } + } + } + catch (ClassCastException cce) + { + if (Configuration.DEBUG) + log.log(Level.FINE, "bad URL list", cce); + throw new IllegalArgumentException("invalid URL list"); + } + try + { + list = (List) attrib.get(PROGRAM_SOURCES); + if (Configuration.DEBUG) + log.fine("list=" + String.valueOf(list)); + if (list != null) + { + progs.clear(); + for (Iterator it = list.iterator(); it.hasNext();) + { + List l = (List) it.next(); + if (Configuration.DEBUG) + log.fine("l=" + l); + if (l.size() != 4) + { + if (Configuration.DEBUG) + log.fine("program list too small: " + l.size()); + throw new IllegalArgumentException("invalid program list"); + } + Double quality = (Double) l.get(0); + Integer offset = (Integer) l.get(1); + Integer length = (Integer) l.get(2); + String source = (String) l.get(3); + progs.add(new SimpleList(quality, offset, length, source)); + } + } + } + catch (ClassCastException cce) + { + if (Configuration.DEBUG) + log.log(Level.FINE, "bad program list", cce); + throw new IllegalArgumentException("invalid program list"); + } + try + { + list = (List) attrib.get(OTHER_SOURCES); + if (Configuration.DEBUG) + log.fine("list=" + String.valueOf(list)); + if (list != null) + { + other.clear(); + for (Iterator it = list.iterator(); it.hasNext();) + { + EntropySource src = (EntropySource) it.next(); + if (Configuration.DEBUG) + log.fine("src=" + src); + if (src == null) + throw new NullPointerException("null source in source list"); + other.add(src); + } + } + } + catch (ClassCastException cce) + { + throw new IllegalArgumentException("invalid source list"); + } + + try + { + Boolean block = (Boolean) attrib.get(BLOCKING); + if (block != null) + blocking = block.booleanValue(); + else + blocking = true; + } + catch (ClassCastException cce) + { + throw new IllegalArgumentException("invalid blocking parameter"); + } + poller = new Poller(files, urls, progs, other, this); + try + { + fillBlock(); + } + catch (LimitReachedException lre) + { + throw new RuntimeException("bootstrapping CSPRNG failed"); + } + } + + public void fillBlock() throws LimitReachedException + { + if (Configuration.DEBUG) + log.fine("fillBlock"); + if (getQuality() < 100.0) + { + if (Configuration.DEBUG) + log.fine("doing slow poll"); + slowPoll(); + } + do + { + fastPoll(); + mixRandomPool(); + } + while (mixCount < MIX_COUNT); + if (! x917init || x917count >= X917_LIFETIME) + { + mixRandomPool(pool); + Map attr = new HashMap(); + byte[] key = new byte[32]; + System.arraycopy(pool, 0, key, 0, 32); + cipher.reset(); + attr.put(IBlockCipher.KEY_MATERIAL, key); + try + { + cipher.init(attr); + } + catch (InvalidKeyException ike) + { + throw new Error(ike.toString()); + } + mixRandomPool(pool); + generateX917(pool); + mixRandomPool(pool); + generateX917(pool); + if (x917init) + quality = 0.0; + x917init = true; + x917count = 0; + } + byte[] export = new byte[ALLOC_SIZE]; + for (int i = 0; i < ALLOC_SIZE; i++) + export[i] = (byte)(pool[i] ^ 0xFF); + mixRandomPool(); + mixRandomPool(export); + generateX917(export); + for (int i = 0; i < OUTPUT_SIZE; i++) + buffer[i] = (byte)(export[i] ^ export[i + OUTPUT_SIZE]); + Arrays.fill(export, (byte) 0); + } + + /** + * Add an array of bytes into the randomness pool. Note that this method will + * <i>not</i> increment the pool's quality counter (this can only be done via + * a source provided to the setup method). + * + * @param buf The byte array. + * @param off The offset from whence to start reading bytes. + * @param len The number of bytes to add. + * @throws ArrayIndexOutOfBoundsException If <i>off</i> or <i>len</i> are + * out of the range of <i>buf</i>. + */ + public synchronized void addRandomBytes(byte[] buf, int off, int len) + { + if (off < 0 || len < 0 || off + len > buf.length) + throw new ArrayIndexOutOfBoundsException(); + if (Configuration.DEBUG) + { + log.fine("adding random bytes:"); + log.fine(Util.toString(buf, off, len)); + } + final int count = off + len; + for (int i = off; i < count; i++) + { + pool[index++] ^= buf[i]; + if (index == pool.length) + { + mixRandomPool(); + index = 0; + } + } + } + + /** + * Add a single random byte to the randomness pool. Note that this method will + * <i>not</i> increment the pool's quality counter (this can only be done via + * a source provided to the setup method). + * + * @param b The byte to add. + */ + public synchronized void addRandomByte(byte b) + { + if (Configuration.DEBUG) + log.fine("adding byte " + Integer.toHexString(b)); + pool[index++] ^= b; + if (index >= pool.length) + { + mixRandomPool(); + index = 0; + } + } + + synchronized void addQuality(double quality) + { + if (Configuration.DEBUG) + log.fine("adding quality " + quality); + if (this.quality < 100) + this.quality += quality; + if (Configuration.DEBUG) + log.fine("quality now " + this.quality); + } + + synchronized double getQuality() + { + return quality; + } + + /** + * The mix operation. This method will, for every 20-byte block in the random + * pool, hash that block, the previous 20 bytes, and the next 44 bytes with + * SHA-1, writing the result back into that block. + */ + private void mixRandomPool(byte[] buf) + { + int hashSize = hash.hashSize(); + for (int i = 0; i < buf.length; i += hashSize) + { + // First update the bytes [p-19..p-1]. + if (i == 0) + hash.update(buf, buf.length - hashSize, hashSize); + else + hash.update(buf, i - hashSize, hashSize); + // Now the next 64 bytes. + if (i + 64 < buf.length) + hash.update(buf, i, 64); + else + { + hash.update(buf, i, buf.length - i); + hash.update(buf, 0, 64 - (buf.length - i)); + } + byte[] digest = hash.digest(); + System.arraycopy(digest, 0, buf, i, hashSize); + } + } + + private void mixRandomPool() + { + mixRandomPool(pool); + mixCount++; + } + + private void generateX917(byte[] buf) + { + int off = 0; + for (int i = 0; i < buf.length; i += X917_POOL_SIZE) + { + int copy = Math.min(buf.length - i, X917_POOL_SIZE); + for (int j = 0; j < copy; j++) + x917pool[j] ^= pool[off + j]; + cipher.encryptBlock(x917pool, 0, x917pool, 0); + System.arraycopy(x917pool, 0, buf, off, copy); + cipher.encryptBlock(x917pool, 0, x917pool, 0); + off += copy; + x917count++; + } + } + + /** + * Add random data always immediately available into the random pool, such as + * the values of the eight asynchronous counters, the current time, the + * current memory usage, the calling thread name, and the current stack trace. + * <p> + * This method does not alter the quality counter, and is provided more to + * maintain randomness, not to seriously improve the current random state. + */ + private void fastPoll() + { + byte b = 0; + for (int i = 0; i < SPINNER_COUNT; i++) + b ^= SPINNERS[i].counter; + addRandomByte(b); + addRandomByte((byte) System.currentTimeMillis()); + addRandomByte((byte) Runtime.getRuntime().freeMemory()); + String s = Thread.currentThread().getName(); + if (s != null) + { + byte[] buf = s.getBytes(); + addRandomBytes(buf, 0, buf.length); + } + ByteArrayOutputStream bout = new ByteArrayOutputStream(1024); + PrintStream pout = new PrintStream(bout); + Throwable t = new Throwable(); + t.printStackTrace(pout); + pout.flush(); + byte[] buf = bout.toByteArray(); + addRandomBytes(buf, 0, buf.length); + } + + private void slowPoll() throws LimitReachedException + { + if (Configuration.DEBUG) + log.fine("poller is alive? " + + (pollerThread == null ? false : pollerThread.isAlive())); + if (pollerThread == null || ! pollerThread.isAlive()) + { + boolean interrupted = false; + pollerThread = new Thread(poller); + pollerThread.setDaemon(true); + pollerThread.setPriority(Thread.NORM_PRIORITY - 1); + pollerThread.start(); + if (blocking) + try + { + pollerThread.join(); + } + catch (InterruptedException ie) + { + interrupted = true; + } + // If the full slow poll has completed after we waited for it, + // and there in insufficient randomness, throw an exception. + if (! interrupted && blocking && quality < 100.0) + { + if (Configuration.DEBUG) + log.fine("insufficient quality: " + quality); + throw new LimitReachedException("insufficient randomness was polled"); + } + } + } + + protected void finalize() throws Throwable + { + if (poller != null && pollerThread != null && pollerThread.isAlive()) + { + pollerThread.interrupt(); + poller.stopUpdating(); + pollerThread.interrupt(); + } + Arrays.fill(pool, (byte) 0); + Arrays.fill(x917pool, (byte) 0); + Arrays.fill(buffer, (byte) 0); + } + + /** + * A simple thread that constantly updates a byte counter. This class is used + * in a group of lowest-priority threads and the values of their counters + * (updated in competition with all other threads) is used as a source of + * entropy bits. + */ + private static class Spinner + implements Runnable + { + protected byte counter; + + private Spinner() + { + } + + public void run() + { + while (true) + { + counter++; + try + { + Thread.sleep(100); + } + catch (InterruptedException ie) + { + } + } + } + } + + private final class Poller + implements Runnable + { + private final List files; + private final List urls; + private final List progs; + private final List other; + private final CSPRNG pool; + private boolean running; + + Poller(List files, List urls, List progs, List other, CSPRNG pool) + { + super(); + this.files = Collections.unmodifiableList(files); + this.urls = Collections.unmodifiableList(urls); + this.progs = Collections.unmodifiableList(progs); + this.other = Collections.unmodifiableList(other); + this.pool = pool; + } + + public void run() + { + running = true; + if (Configuration.DEBUG) + { + log.fine("files: " + files); + log.fine("URLs: " + urls); + log.fine("progs: " + progs); + } + Iterator files_it = files.iterator(); + Iterator urls_it = urls.iterator(); + Iterator prog_it = progs.iterator(); + Iterator other_it = other.iterator(); + + while (files_it.hasNext() || urls_it.hasNext() || prog_it.hasNext() + || other_it.hasNext()) + { + // There is enough random data. Go away. + if (pool.getQuality() >= 100.0 || ! running) + return; + if (files_it.hasNext()) + try + { + List l = (List) files_it.next(); + if (Configuration.DEBUG) + log.fine(l.toString()); + double qual = ((Double) l.get(0)).doubleValue(); + int offset = ((Integer) l.get(1)).intValue(); + int count = ((Integer) l.get(2)).intValue(); + String src = (String) l.get(3); + InputStream in = new FileInputStream(src); + byte[] buf = new byte[count]; + if (offset > 0) + in.skip(offset); + int len = in.read(buf); + if (len >= 0) + { + pool.addRandomBytes(buf, 0, len); + pool.addQuality(qual * ((double) len / (double) count)); + } + if (Configuration.DEBUG) + log.fine("got " + len + " bytes from " + src); + } + catch (Exception x) + { + if (Configuration.DEBUG) + log.throwing(this.getClass().getName(), "run", x); + } + if (pool.getQuality() >= 100.0 || ! running) + return; + if (urls_it.hasNext()) + try + { + List l = (List) urls_it.next(); + if (Configuration.DEBUG) + log.fine(l.toString()); + double qual = ((Double) l.get(0)).doubleValue(); + int offset = ((Integer) l.get(1)).intValue(); + int count = ((Integer) l.get(2)).intValue(); + URL src = (URL) l.get(3); + InputStream in = src.openStream(); + byte[] buf = new byte[count]; + if (offset > 0) + in.skip(offset); + int len = in.read(buf); + if (len >= 0) + { + pool.addRandomBytes(buf, 0, len); + pool.addQuality(qual * ((double) len / (double) count)); + } + if (Configuration.DEBUG) + log.fine("got " + len + " bytes from " + src); + } + catch (Exception x) + { + if (Configuration.DEBUG) + log.throwing(this.getClass().getName(), "run", x); + } + if (pool.getQuality() >= 100.0 || ! running) + return; + Process proc = null; + if (prog_it.hasNext()) + try + { + List l = (List) prog_it.next(); + if (Configuration.DEBUG) + log.finer(l.toString()); + double qual = ((Double) l.get(0)).doubleValue(); + int offset = ((Integer) l.get(1)).intValue(); + int count = ((Integer) l.get(2)).intValue(); + String src = (String) l.get(3); + proc = null; + proc = Runtime.getRuntime().exec(src); + InputStream in = proc.getInputStream(); + byte[] buf = new byte[count]; + if (offset > 0) + in.skip(offset); + int len = in.read(buf); + if (len >= 0) + { + pool.addRandomBytes(buf, 0, len); + pool.addQuality(qual * ((double) len / (double) count)); + } + proc.destroy(); + proc.waitFor(); + if (Configuration.DEBUG) + log.fine("got " + len + " bytes from " + src); + } + catch (Exception x) + { + if (Configuration.DEBUG) + log.throwing(this.getClass().getName(), "run", x); + try + { + if (proc != null) + { + proc.destroy(); + proc.waitFor(); + } + } + catch (Exception ignored) + { + } + } + if (pool.getQuality() >= 100.0 || ! running) + return; + if (other_it.hasNext()) + try + { + EntropySource src = (EntropySource) other_it.next(); + byte[] buf = src.nextBytes(); + if (pool == null) + return; + pool.addRandomBytes(buf, 0, buf.length); + pool.addQuality(src.quality()); + if (Configuration.DEBUG) + log.fine("got " + buf.length + " bytes from " + src); + } + catch (Exception x) + { + if (Configuration.DEBUG) + log.throwing(this.getClass().getName(), "run", x); + } + } + } + + public void stopUpdating() + { + running = false; + } + } +} diff --git a/libjava/classpath/gnu/javax/crypto/prng/Fortuna.java b/libjava/classpath/gnu/javax/crypto/prng/Fortuna.java new file mode 100644 index 000000000..8aec9ab7d --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/prng/Fortuna.java @@ -0,0 +1,349 @@ +/* Fortuna.java -- The Fortuna PRNG. + Copyright (C) 2004, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.prng; + +import gnu.java.security.Registry; +import gnu.java.security.hash.HashFactory; +import gnu.java.security.hash.IMessageDigest; +import gnu.java.security.prng.BasePRNG; +import gnu.java.security.prng.LimitReachedException; +import gnu.java.security.prng.RandomEvent; +import gnu.java.security.prng.RandomEventListener; +import gnu.javax.crypto.cipher.CipherFactory; +import gnu.javax.crypto.cipher.IBlockCipher; + +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.Serializable; +import java.security.InvalidKeyException; +import java.util.Arrays; +import java.util.Collections; +import java.util.Iterator; +import java.util.Map; + +/** + * The Fortuna continuously-seeded pseudo-random number generator. This + * generator is composed of two major pieces: the entropy accumulator and the + * generator function. The former takes in random bits and incorporates them + * into the generator's state. The latter takes this base entropy and generates + * pseudo-random bits from it. + * <p> + * There are some things users of this class <em>must</em> be aware of: + * <dl> + * <dt>Adding Random Data</dt> + * <dd>This class does not do any polling of random sources, but rather + * provides an interface for adding random events. Applications that use this + * code <em>must</em> provide this mechanism. We use this design because an + * application writer who knows the system he is targeting is in a better + * position to judge what random data is available.</dd> + * <dt>Storing the Seed</dt> + * <dd>This class implements {@link Serializable} in such a way that it writes + * a 64 byte seed to the stream, and reads it back again when being + * deserialized. This is the extent of seed file management, however, and those + * using this class are encouraged to think deeply about when, how often, and + * where to store the seed.</dd> + * </dl> + * <p> + * <b>References:</b> + * <ul> + * <li>Niels Ferguson and Bruce Schneier, <i>Practical Cryptography</i>, pp. + * 155--184. Wiley Publishing, Indianapolis. (2003 Niels Ferguson and Bruce + * Schneier). ISBN 0-471-22357-3.</li> + * </ul> + */ +public class Fortuna + extends BasePRNG + implements Serializable, RandomEventListener +{ + private static final long serialVersionUID = 0xFACADE; + private static final int SEED_FILE_SIZE = 64; + private static final int NUM_POOLS = 32; + private static final int MIN_POOL_SIZE = 64; + private final Generator generator; + private final IMessageDigest[] pools; + private long lastReseed; + private int pool; + private int pool0Count; + private int reseedCount; + public static final String SEED = "gnu.crypto.prng.fortuna.seed"; + + public Fortuna() + { + super(Registry.FORTUNA_PRNG); + generator = new Generator(CipherFactory.getInstance(Registry.RIJNDAEL_CIPHER), + HashFactory.getInstance(Registry.SHA256_HASH)); + pools = new IMessageDigest[NUM_POOLS]; + for (int i = 0; i < NUM_POOLS; i++) + pools[i] = HashFactory.getInstance(Registry.SHA256_HASH); + lastReseed = 0; + pool = 0; + pool0Count = 0; + buffer = new byte[256]; + } + + public void setup(Map attributes) + { + lastReseed = 0; + reseedCount = 0; + pool = 0; + pool0Count = 0; + generator.init(attributes); + try + { + fillBlock(); + } + catch (LimitReachedException shouldNotHappen) + { + throw new RuntimeException(shouldNotHappen); + } + } + + public void fillBlock() throws LimitReachedException + { + if (pool0Count >= MIN_POOL_SIZE + && System.currentTimeMillis() - lastReseed > 100) + { + reseedCount++; + byte[] seed = new byte[0]; + for (int i = 0; i < NUM_POOLS; i++) + if (reseedCount % (1 << i) == 0) + generator.addRandomBytes(pools[i].digest()); + lastReseed = System.currentTimeMillis(); + pool0Count = 0; + } + generator.nextBytes(buffer); + } + + public void addRandomByte(byte b) + { + pools[pool].update(b); + if (pool == 0) + pool0Count++; + pool = (pool + 1) % NUM_POOLS; + } + + public void addRandomBytes(byte[] buf, int offset, int length) + { + pools[pool].update(buf, offset, length); + if (pool == 0) + pool0Count += length; + pool = (pool + 1) % NUM_POOLS; + } + + public void addRandomEvent(RandomEvent event) + { + if (event.getPoolNumber() < 0 || event.getPoolNumber() >= pools.length) + throw new IllegalArgumentException("pool number out of range: " + + event.getPoolNumber()); + pools[event.getPoolNumber()].update(event.getSourceNumber()); + pools[event.getPoolNumber()].update((byte) event.getData().length); + pools[event.getPoolNumber()].update(event.getData()); + if (event.getPoolNumber() == 0) + pool0Count += event.getData().length; + } + + // Reading and writing this object is equivalent to storing and retrieving + // the seed. + + private void writeObject(ObjectOutputStream out) throws IOException + { + byte[] seed = new byte[SEED_FILE_SIZE]; + try + { + generator.nextBytes(seed); + } + catch (LimitReachedException shouldNeverHappen) + { + throw new Error(shouldNeverHappen); + } + out.write(seed); + } + + private void readObject(ObjectInputStream in) throws IOException + { + byte[] seed = new byte[SEED_FILE_SIZE]; + in.readFully(seed); + generator.addRandomBytes(seed); + } + + /** + * The Fortuna generator function. The generator is a PRNG in its own right; + * Fortuna itself is basically a wrapper around this generator that manages + * reseeding in a secure way. + */ + public static class Generator + extends BasePRNG + implements Cloneable + { + private static final int LIMIT = 1 << 20; + private final IBlockCipher cipher; + private final IMessageDigest hash; + private final byte[] counter; + private final byte[] key; + private boolean seeded; + + public Generator(final IBlockCipher cipher, final IMessageDigest hash) + { + super(Registry.FORTUNA_GENERATOR_PRNG); + this.cipher = cipher; + this.hash = hash; + counter = new byte[cipher.defaultBlockSize()]; + buffer = new byte[cipher.defaultBlockSize()]; + int keysize = 0; + for (Iterator it = cipher.keySizes(); it.hasNext();) + { + int ks = ((Integer) it.next()).intValue(); + if (ks > keysize) + keysize = ks; + if (keysize >= 32) + break; + } + key = new byte[keysize]; + } + + public byte nextByte() + { + byte[] b = new byte[1]; + nextBytes(b, 0, 1); + return b[0]; + } + + public void nextBytes(byte[] out, int offset, int length) + { + if (! seeded) + throw new IllegalStateException("generator not seeded"); + int count = 0; + do + { + int amount = Math.min(LIMIT, length - count); + try + { + super.nextBytes(out, offset + count, amount); + } + catch (LimitReachedException shouldNeverHappen) + { + throw new Error(shouldNeverHappen); + } + count += amount; + for (int i = 0; i < key.length; i += counter.length) + { + fillBlock(); + int l = Math.min(key.length - i, cipher.currentBlockSize()); + System.arraycopy(buffer, 0, key, i, l); + } + resetKey(); + } + while (count < length); + fillBlock(); + ndx = 0; + } + + public void addRandomByte(byte b) + { + addRandomBytes(new byte[] { b }); + } + + public void addRandomBytes(byte[] seed, int offset, int length) + { + hash.update(key); + hash.update(seed, offset, length); + byte[] newkey = hash.digest(); + System.arraycopy(newkey, 0, key, 0, Math.min(key.length, newkey.length)); + resetKey(); + incrementCounter(); + seeded = true; + } + + public void fillBlock() + { + if (! seeded) + throw new IllegalStateException("generator not seeded"); + cipher.encryptBlock(counter, 0, buffer, 0); + incrementCounter(); + } + + public void setup(Map attributes) + { + seeded = false; + Arrays.fill(key, (byte) 0); + Arrays.fill(counter, (byte) 0); + byte[] seed = (byte[]) attributes.get(SEED); + if (seed != null) + addRandomBytes(seed); + fillBlock(); + } + + /** + * Resets the cipher's key. This is done after every reseed, which combines + * the old key and the seed, and processes that throigh the hash function. + */ + private void resetKey() + { + try + { + cipher.reset(); + cipher.init(Collections.singletonMap(IBlockCipher.KEY_MATERIAL, key)); + } + // We expect to never get an exception here. + catch (InvalidKeyException ike) + { + throw new Error(ike); + } + catch (IllegalArgumentException iae) + { + throw new Error(iae); + } + } + + /** + * Increment `counter' as a sixteen-byte little-endian unsigned integer by + * one. + */ + private void incrementCounter() + { + for (int i = 0; i < counter.length; i++) + { + counter[i]++; + if (counter[i] != 0) + break; + } + } + } +} diff --git a/libjava/classpath/gnu/javax/crypto/prng/ICMGenerator.java b/libjava/classpath/gnu/javax/crypto/prng/ICMGenerator.java new file mode 100644 index 000000000..a4df5b964 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/prng/ICMGenerator.java @@ -0,0 +1,306 @@ +/* ICMGenerator.java -- + Copyright (C) 2001, 2002, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.prng; + +import gnu.java.security.Registry; +import gnu.java.security.prng.BasePRNG; +import gnu.java.security.prng.LimitReachedException; +import gnu.javax.crypto.cipher.CipherFactory; +import gnu.javax.crypto.cipher.IBlockCipher; + +import java.math.BigInteger; +import java.security.InvalidKeyException; +import java.util.HashMap; +import java.util.Map; + +/** + * Counter Mode is a way to define a pseudorandom keystream generator using a + * block cipher. The keystream can be used for additive encryption, key + * derivation, or any other application requiring pseudorandom data. + * <p> + * In ICM, the keystream is logically broken into segments. Each segment is + * identified with a segment index, and the segments have equal lengths. This + * segmentation makes ICM especially appropriate for securing packet-based + * protocols. + * <p> + * This implementation adheres to the definition of the ICM keystream generation + * function that allows for any symetric key block cipher algorithm + * (initialisation parameter <code>gnu.crypto.prng.icm.cipher.name</code> + * taken to be an instance of {@link java.lang.String}) to be used. If such a + * parameter is not defined/included in the initialisation <code>Map</code>, + * then the "Rijndael" algorithm is used. Furthermore, if the initialisation + * parameter <code>gnu.crypto.cipher.block.size</code> (taken to be a instance + * of {@link java.lang.Integer}) is missing or undefined in the initialisation + * <code>Map</code>, then the cipher's <em>default</em> block size is used. + * <p> + * The practical limits and constraints of such generator are: + * <ul> + * <li>The number of blocks in any segment <b>MUST NOT</b> exceed <code> + * 256 ** BLOCK_INDEX_LENGTH</code>. + * The number of segments <b>MUST NOT</b> exceed + * <code>256 ** SEGMENT_INDEX_LENGTH</code>. These restrictions ensure the + * uniqueness of each block cipher input.</li> + * <li>Each segment contains <code>SEGMENT_LENGTH</code> octets; this value + * <b>MUST NOT</b> exceed the value <code>(256 ** BLOCK_INDEX_LENGTH) * + * BLOCK_LENGTH</code>.</li> + * <li>The sum of <code>SEGMENT_INDEX_LENGTH</code> and + * <code>BLOCK_INDEX_LENGTH</code> <b>MUST NOT</b> exceed <code>BLOCK_LENGTH + * / 2</code>. + * This requirement protects the ICM keystream generator from potentially + * failing to be pseudorandom.</li> + * </ul> + * <p> + * <b>NOTE</b>: Rijndael is used as the default symmetric key block cipher + * algorithm because, with its default block and key sizes, it is the AES. Yet + * being Rijndael, the algorithm offers more versatile block and key sizes which + * may prove to be useful for generating <em>longer</em> key streams. + * <p> + * References: + * <ol> + * <li><a + * href="http://www.ietf.org/internet-drafts/draft-mcgrew-saag-icm-00.txt"> + * Integer Counter Mode</a>, David A. McGrew.</li> + * </ol> + */ +public class ICMGenerator + extends BasePRNG + implements Cloneable +{ + /** Property name of underlying block cipher for this ICM generator. */ + public static final String CIPHER = "gnu.crypto.prng.icm.cipher.name"; + /** Property name of ICM's block index length. */ + public static final String BLOCK_INDEX_LENGTH = + "gnu.crypto.prng.icm.block.index.length"; + /** Property name of ICM's segment index length. */ + public static final String SEGMENT_INDEX_LENGTH = + "gnu.crypto.prng.icm.segment.index.length"; + /** Property name of ICM's offset. */ + public static final String OFFSET = "gnu.crypto.prng.icm.offset"; + /** Property name of ICM's segment index. */ + public static final String SEGMENT_INDEX = "gnu.crypto.prng.icm.segment.index"; + /** The integer value 256 as a BigInteger. */ + private static final BigInteger TWO_FIFTY_SIX = new BigInteger("256"); + /** The underlying cipher implementation. */ + private IBlockCipher cipher; + /** This keystream block index length in bytes. */ + private int blockNdxLength = -1; + /** This keystream segment index length in bytes. */ + private int segmentNdxLength = -1; + /** The index of the next block for a given keystream segment. */ + private BigInteger blockNdx = BigInteger.ZERO; + /** The segment index for this keystream. */ + private BigInteger segmentNdx; + /** The initial counter for a given keystream segment. */ + private BigInteger C0; + + /** Trivial 0-arguments constructor. */ + public ICMGenerator() + { + super(Registry.ICM_PRNG); + } + + // Conceptually, ICM is a keystream generator that takes a secret key and a + // segment index as an input and then outputs a keystream segment. The + // segmentation lends itself to packet encryption, as each keystream segment + // can be used to encrypt a distinct packet. + // + // An ICM key consists of the block cipher key and an Offset. The Offset is + // an integer with BLOCK_LENGTH octets... + public void setup(Map attributes) + { + // find out which cipher algorithm to use + boolean newCipher = true; + String underlyingCipher = (String) attributes.get(CIPHER); + if (underlyingCipher == null) + if (cipher == null) // happy birthday + // ensure we have a reliable implementation of this cipher + cipher = CipherFactory.getInstance(Registry.RIJNDAEL_CIPHER); + else + // we already have one. use it as is + newCipher = false; + else // ensure we have a reliable implementation of this cipher + cipher = CipherFactory.getInstance(underlyingCipher); + + // find out what block size we should use it in + int cipherBlockSize = 0; + Integer bs = (Integer) attributes.get(IBlockCipher.CIPHER_BLOCK_SIZE); + if (bs != null) + cipherBlockSize = bs.intValue(); + else + { + if (newCipher) // assume we'll use its default block size + cipherBlockSize = cipher.defaultBlockSize(); + // else use as is + } + // get the key material + byte[] key = (byte[]) attributes.get(IBlockCipher.KEY_MATERIAL); + if (key == null) + throw new IllegalArgumentException(IBlockCipher.KEY_MATERIAL); + // now initialise the cipher + HashMap map = new HashMap(); + if (cipherBlockSize != 0) // only needed if new or changed + map.put(IBlockCipher.CIPHER_BLOCK_SIZE, Integer.valueOf(cipherBlockSize)); + map.put(IBlockCipher.KEY_MATERIAL, key); + try + { + cipher.init(map); + } + catch (InvalidKeyException x) + { + throw new IllegalArgumentException(IBlockCipher.KEY_MATERIAL); + } + // at this point we have an initialised (new or otherwise) cipher + // ensure that remaining params make sense + cipherBlockSize = cipher.currentBlockSize(); + BigInteger counterRange = TWO_FIFTY_SIX.pow(cipherBlockSize); + // offset, like the underlying cipher key is not cloneable + // always look for it and throw an exception if it's not there + Object obj = attributes.get(OFFSET); + // allow either a byte[] or a BigInteger + BigInteger r; + if (obj instanceof BigInteger) + r = (BigInteger) obj; + else // assume byte[]. should be same length as cipher block size + { + byte[] offset = (byte[]) obj; + if (offset.length != cipherBlockSize) + throw new IllegalArgumentException(OFFSET); + r = new BigInteger(1, offset); + } + int wantBlockNdxLength = -1; // number of octets in the block index + Integer i = (Integer) attributes.get(BLOCK_INDEX_LENGTH); + if (i != null) + { + wantBlockNdxLength = i.intValue(); + if (wantBlockNdxLength < 1) + throw new IllegalArgumentException(BLOCK_INDEX_LENGTH); + } + int wantSegmentNdxLength = -1; // number of octets in the segment index + i = (Integer) attributes.get(SEGMENT_INDEX_LENGTH); + if (i != null) + { + wantSegmentNdxLength = i.intValue(); + if (wantSegmentNdxLength < 1) + throw new IllegalArgumentException(SEGMENT_INDEX_LENGTH); + } + // if both are undefined check if it's a reuse + if ((wantBlockNdxLength == -1) && (wantSegmentNdxLength == -1)) + { + if (blockNdxLength == -1) // new instance + throw new IllegalArgumentException(BLOCK_INDEX_LENGTH + ", " + + SEGMENT_INDEX_LENGTH); + // else reuse old values + } + else // only one is undefined, set it to BLOCK_LENGTH/2 minus the other + { + int limit = cipherBlockSize / 2; + if (wantBlockNdxLength == -1) + wantBlockNdxLength = limit - wantSegmentNdxLength; + else if (wantSegmentNdxLength == -1) + wantSegmentNdxLength = limit - wantBlockNdxLength; + else if ((wantSegmentNdxLength + wantBlockNdxLength) > limit) + throw new IllegalArgumentException(BLOCK_INDEX_LENGTH + ", " + + SEGMENT_INDEX_LENGTH); + // save new values + blockNdxLength = wantBlockNdxLength; + segmentNdxLength = wantSegmentNdxLength; + } + // get the segment index as a BigInteger + BigInteger s = (BigInteger) attributes.get(SEGMENT_INDEX); + if (s == null) + { + if (segmentNdx == null) // segment index was never set + throw new IllegalArgumentException(SEGMENT_INDEX); + // reuse; check if still valid + if (segmentNdx.compareTo(TWO_FIFTY_SIX.pow(segmentNdxLength)) > 0) + throw new IllegalArgumentException(SEGMENT_INDEX); + } + else + { + if (s.compareTo(TWO_FIFTY_SIX.pow(segmentNdxLength)) > 0) + throw new IllegalArgumentException(SEGMENT_INDEX); + segmentNdx = s; + } + // The initial counter of the keystream segment with segment index s is + // defined as follows, where r denotes the Offset: + // + // C[0] = (s * (256^BLOCK_INDEX_LENGTH) + r) modulo (256^BLOCK_LENGTH) + C0 = segmentNdx.multiply(TWO_FIFTY_SIX.pow(blockNdxLength)) + .add(r).modPow(BigInteger.ONE, counterRange); + try + { + fillBlock(); + } + catch (LimitReachedException impossible) + { + throw (InternalError) + new InternalError().initCause(impossible); + } + } + + public void fillBlock() throws LimitReachedException + { + if (C0 == null) + throw new IllegalStateException(); + if (blockNdx.compareTo(TWO_FIFTY_SIX.pow(blockNdxLength)) >= 0) + throw new LimitReachedException(); + int cipherBlockSize = cipher.currentBlockSize(); + BigInteger counterRange = TWO_FIFTY_SIX.pow(cipherBlockSize); + // encrypt the counter for the current blockNdx + // C[i] = (C[0] + i) modulo (256^BLOCK_LENGTH). + BigInteger Ci = C0.add(blockNdx).modPow(BigInteger.ONE, counterRange); + buffer = Ci.toByteArray(); + int limit = buffer.length; + if (limit < cipherBlockSize) + { + byte[] data = new byte[cipherBlockSize]; + System.arraycopy(buffer, 0, data, cipherBlockSize - limit, limit); + buffer = data; + } + else if (limit > cipherBlockSize) + { + byte[] data = new byte[cipherBlockSize]; + System.arraycopy(buffer, limit - cipherBlockSize, data, 0, + cipherBlockSize); + buffer = data; + } + cipher.encryptBlock(buffer, 0, buffer, 0); + blockNdx = blockNdx.add(BigInteger.ONE); // increment blockNdx + } +} diff --git a/libjava/classpath/gnu/javax/crypto/prng/IPBE.java b/libjava/classpath/gnu/javax/crypto/prng/IPBE.java new file mode 100644 index 000000000..8138b7b9a --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/prng/IPBE.java @@ -0,0 +1,81 @@ +/* IPBE.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.prng; + +/** + * Trivial interface to group Password-based encryption property names and + * constants. + */ +public interface IPBE +{ + /** + * Property name for the iteration count in a PBE algorithm. The property + * associated with this is expected to be an {@link Integer}. + */ + String ITERATION_COUNT = "gnu.crypto.pbe.iteration.count"; + + /** + * Property name for the password in a PBE algorithm. The property associated + * with this is expected to be a char array. + */ + String PASSWORD = "gnu.crypto.pbe.password"; + + /** + * Property name for the password character encoding in a PBE algorithm. The + * property associated with this is expected to be a String denoting a valid + * character-encoding name. If this property is not set, and a password is + * used, then {@link #DEFAULT_PASSWORD_ENCODING} will be used when converting + * the password character(s) to bytes. + */ + String PASSWORD_ENCODING = "gnu.crypto.pbe.password.encoding"; + + /** + * Property name for the salt in a PBE algorithm. The property associated + * with this is expected to be a byte array. + */ + String SALT = "gnu.crypto.pbe.salt"; + + /** + * The default character set encoding name to be used if (a) a password is + * to be used as the source for a PBE-based Key Derivation Function (KDF) and + * (b) no character set encoding name was specified among the attributes used + * to initialize the instance. + */ + String DEFAULT_PASSWORD_ENCODING = "UTF-8"; +} diff --git a/libjava/classpath/gnu/javax/crypto/prng/PBKDF2.java b/libjava/classpath/gnu/javax/crypto/prng/PBKDF2.java new file mode 100644 index 000000000..22fcd5504 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/prng/PBKDF2.java @@ -0,0 +1,184 @@ +/* PBKDF2.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.prng; + +import gnu.java.security.prng.BasePRNG; +import gnu.java.security.prng.LimitReachedException; +import gnu.javax.crypto.mac.HMac; +import gnu.javax.crypto.mac.IMac; + +import java.io.UnsupportedEncodingException; +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; + +/** + * An implementation of the <i>key derivation function</i> KDF2 from PKCS #5: + * Password-Based Cryptography (<b>PBE</b>). This KDF is essentially a way to + * transform a password and a salt into a stream of random bytes, which may then + * be used to initialize a cipher or a MAC. + * <p> + * This version uses a MAC as its pseudo-random function, and the password is + * used as the key. + * <p> + * References: + * <ol> + * <li>B. Kaliski, <a href="http://www.ietf.org/rfc/rfc2898.txt">RFC 2898: + * Password-Based Cryptography Specification, Version 2.0</a></li> + * </ol> + */ +public class PBKDF2 + extends BasePRNG + implements Cloneable +{ + /** + * The bytes fed into the MAC. This is initially the concatenation of the salt + * and the block number. + */ + private byte[] in; + /** The iteration count. */ + private int iterationCount; + /** The salt. */ + private byte[] salt; + /** The MAC (the pseudo-random function we use). */ + private IMac mac; + /** The number of hLen-sized blocks generated. */ + private long count; + + /** + * Creates a new PBKDF2 object. The argument is the MAC that will serve as the + * pseudo-random function. The MAC does not need to be initialized. + * + * @param mac The pseudo-random function. + */ + public PBKDF2(IMac mac) + { + super("PBKDF2-" + mac.name()); + this.mac = mac; + iterationCount = -1; + } + + public void setup(Map attributes) + { + Map macAttrib = new HashMap(); + macAttrib.put(HMac.USE_WITH_PKCS5_V2, Boolean.TRUE); + byte[] s = (byte[]) attributes.get(IPBE.SALT); + if (s == null) + { + if (salt == null) + throw new IllegalArgumentException("no salt specified"); + // Otherwise re-use. + } + else + salt = s; + byte[] macKeyMaterial; + char[] password = (char[]) attributes.get(IPBE.PASSWORD); + if (password != null) + { + String encoding = (String) attributes.get(IPBE.PASSWORD_ENCODING); + if (encoding == null || encoding.trim().length() == 0) + encoding = IPBE.DEFAULT_PASSWORD_ENCODING; + else + encoding = encoding.trim(); + try + { + macKeyMaterial = new String(password).getBytes(encoding); + } + catch (UnsupportedEncodingException uee) + { + throw new IllegalArgumentException("Unknown or unsupported encoding: " + + encoding, uee); + } + } + else + macKeyMaterial = (byte[]) attributes.get(IMac.MAC_KEY_MATERIAL); + + if (macKeyMaterial != null) + macAttrib.put(IMac.MAC_KEY_MATERIAL, macKeyMaterial); + else if (! initialised) + throw new IllegalArgumentException( + "Neither password nor key-material were specified"); + // otherwise re-use previous password/key-material + try + { + mac.init(macAttrib); + } + catch (Exception x) + { + throw new IllegalArgumentException(x.getMessage()); + } + Integer ic = (Integer) attributes.get(IPBE.ITERATION_COUNT); + if (ic != null) + iterationCount = ic.intValue(); + if (iterationCount <= 0) + throw new IllegalArgumentException("bad iteration count"); + count = 0L; + buffer = new byte[mac.macSize()]; + try + { + fillBlock(); + } + catch (LimitReachedException x) + { + throw new Error(x.getMessage()); + } + } + + public void fillBlock() throws LimitReachedException + { + if (++count > ((1L << 32) - 1)) + throw new LimitReachedException(); + Arrays.fill(buffer, (byte) 0x00); + int limit = salt.length; + in = new byte[limit + 4]; + System.arraycopy(salt, 0, in, 0, salt.length); + in[limit++] = (byte)(count >>> 24); + in[limit++] = (byte)(count >>> 16); + in[limit++] = (byte)(count >>> 8); + in[limit ] = (byte) count; + for (int i = 0; i < iterationCount; i++) + { + mac.reset(); + mac.update(in, 0, in.length); + in = mac.digest(); + for (int j = 0; j < buffer.length; j++) + buffer[j] ^= in[j]; + } + } +} diff --git a/libjava/classpath/gnu/javax/crypto/prng/PRNGFactory.java b/libjava/classpath/gnu/javax/crypto/prng/PRNGFactory.java new file mode 100644 index 000000000..0a7c5e377 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/prng/PRNGFactory.java @@ -0,0 +1,115 @@ +/* PRNGFactory.java -- + Copyright (C) 2001, 2002, 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.prng; + +import gnu.java.security.Registry; +import gnu.java.security.prng.IRandom; +import gnu.javax.crypto.mac.HMacFactory; +import gnu.javax.crypto.mac.IMac; +import gnu.javax.crypto.mac.MacFactory; + +import java.util.Collections; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Set; + +/** + * A Factory to instantiate pseudo random number generators. + */ +public class PRNGFactory + implements Registry +{ + /** Trivial constructor to enforce <i>Singleton</i> pattern. */ + private PRNGFactory() + { + } + + /** + * Returns an instance of a padding algorithm given its name. + * + * @param prng the case-insensitive name of the PRNG. + * @return an instance of the pseudo-random number generator. + * @exception InternalError if the implementation does not pass its self- + * test. + */ + public static IRandom getInstance(String prng) + { + if (prng == null) + return null; + prng = prng.trim(); + IRandom result = null; + if (prng.equalsIgnoreCase(ARCFOUR_PRNG) || prng.equalsIgnoreCase(RC4_PRNG)) + result = new ARCFour(); + else if (prng.equalsIgnoreCase(ICM_PRNG)) + result = new ICMGenerator(); + else if (prng.equalsIgnoreCase(UMAC_PRNG)) + result = new UMacGenerator(); + else if (prng.toLowerCase().startsWith(PBKDF2_PRNG_PREFIX)) + { + String macName = prng.substring(PBKDF2_PRNG_PREFIX.length()); + IMac mac = MacFactory.getInstance(macName); + if (mac == null) + return null; + result = new PBKDF2(mac); + } + + if (result != null) + return result; + + return gnu.java.security.prng.PRNGFactory.getInstance(prng); + } + + /** + * Returns a {@link Set} of names of padding algorithms supported by this + * <i>Factory</i>. + * + * @return a {@link Set} of pseudo-random number generator algorithm names + * (Strings). + */ + public static Set getNames() + { + HashSet hs = new HashSet(gnu.java.security.prng.PRNGFactory.getNames()); + hs.add(ICM_PRNG); + hs.add(UMAC_PRNG); + // add all hmac implementations as candidate PBKDF2 ones too + for (Iterator it = HMacFactory.getNames().iterator(); it.hasNext();) + hs.add(PBKDF2_PRNG_PREFIX + ((String) it.next())); + return Collections.unmodifiableSet(hs); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/prng/UMacGenerator.java b/libjava/classpath/gnu/javax/crypto/prng/UMacGenerator.java new file mode 100644 index 000000000..1ee449223 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/prng/UMacGenerator.java @@ -0,0 +1,186 @@ +/* UMacGenerator.java -- + Copyright (C) 2001, 2002, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.prng; + +import gnu.java.security.Registry; +import gnu.java.security.prng.BasePRNG; +import gnu.java.security.prng.LimitReachedException; +import gnu.javax.crypto.cipher.CipherFactory; +import gnu.javax.crypto.cipher.IBlockCipher; + +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; +import java.security.InvalidKeyException; + +/** + * <i>KDF</i>s (Key Derivation Functions) are used to stretch user-supplied key + * material to specific size(s) required by high level cryptographic primitives. + * Described in the <A + * HREF="http://www.ietf.org/internet-drafts/draft-krovetz-umac-01.txt">UMAC</A> + * paper, this function basically operates an underlying <em>symmetric key block + * cipher</em> instance in output feedback mode (OFB), as a <b>strong</b> + * pseudo-random number generator. + * <p> + * <code>UMacGenerator</code> requires an <em>index</em> parameter + * (initialisation parameter <code>gnu.crypto.prng.umac.kdf.index</code> taken + * to be an instance of {@link Integer} with a value between <code>0</code> and + * <code>255</code>). Using the same key, but different indices, generates + * different pseudorandom outputs. + * <p> + * This implementation generalises the definition of the + * <code>UmacGenerator</code> algorithm to allow for other than the AES + * symetric key block cipher algorithm (initialisation parameter + * <code>gnu.crypto.prng.umac.cipher.name</code> taken to be an instance of + * {@link String}). If such a parameter is not defined/included in the + * initialisation <code>Map</code>, then the "Rijndael" algorithm is used. + * Furthermore, if the initialisation parameter + * <code>gnu.crypto.cipher.block.size</code> (taken to be a instance of + * {@link Integer}) is missing or undefined in the initialisation + * <code>Map</code>, then the cipher's <em>default</em> block size is used. + * <p> + * <b>NOTE</b>: Rijndael is used as the default symmetric key block cipher + * algorithm because, with its default block and key sizes, it is the AES. Yet + * being Rijndael, the algorithm offers more versatile block and key sizes which + * may prove to be useful for generating "longer" key streams. + * <p> + * References: + * <ol> + * <li><a href="http://www.ietf.org/internet-drafts/draft-krovetz-umac-01.txt"> + * UMAC</a>: Message Authentication Code using Universal Hashing.<br> + * T. Krovetz, J. Black, S. Halevi, A. Hevia, H. Krawczyk, and P. Rogaway.</li> + * </ol> + */ +public class UMacGenerator + extends BasePRNG + implements Cloneable +{ + /** + * Property name of the KDF <code>index</code> value to use in this + * instance. The value is taken to be an {@link Integer} less than + * <code>256</code>. + */ + public static final String INDEX = "gnu.crypto.prng.umac.index"; + /** The name of the underlying symmetric key block cipher algorithm. */ + public static final String CIPHER = "gnu.crypto.prng.umac.cipher.name"; + /** The generator's underlying block cipher. */ + private IBlockCipher cipher; + + /** Trivial 0-arguments constructor. */ + public UMacGenerator() + { + super(Registry.UMAC_PRNG); + } + + public void setup(Map attributes) + { + boolean newCipher = true; + String cipherName = (String) attributes.get(CIPHER); + if (cipherName == null) + if (cipher == null) // happy birthday + cipher = CipherFactory.getInstance(Registry.RIJNDAEL_CIPHER); + else // we already have one. use it as is + newCipher = false; + else + cipher = CipherFactory.getInstance(cipherName); + // find out what block size we should use it in + int cipherBlockSize = 0; + Integer bs = (Integer) attributes.get(IBlockCipher.CIPHER_BLOCK_SIZE); + if (bs != null) + cipherBlockSize = bs.intValue(); + else + { + if (newCipher) // assume we'll use its default block size + cipherBlockSize = cipher.defaultBlockSize(); + // else use as is + } + // get the key material + byte[] key = (byte[]) attributes.get(IBlockCipher.KEY_MATERIAL); + if (key == null) + throw new IllegalArgumentException(IBlockCipher.KEY_MATERIAL); + + int keyLength = key.length; + // ensure that keyLength is valid for the chosen underlying cipher + boolean ok = false; + for (Iterator it = cipher.keySizes(); it.hasNext();) + { + ok = (keyLength == ((Integer) it.next()).intValue()); + if (ok) + break; + } + if (! ok) + throw new IllegalArgumentException("key length"); + // ensure that remaining params make sense + int index = -1; + Integer i = (Integer) attributes.get(INDEX); + if (i != null) + { + index = i.intValue(); + if (index < 0 || index > 255) + throw new IllegalArgumentException(INDEX); + } + // now initialise the underlying cipher + Map map = new HashMap(); + if (cipherBlockSize != 0) // only needed if new or changed + map.put(IBlockCipher.CIPHER_BLOCK_SIZE, Integer.valueOf(cipherBlockSize)); + map.put(IBlockCipher.KEY_MATERIAL, key); + try + { + cipher.init(map); + } + catch (InvalidKeyException x) + { + throw new IllegalArgumentException(IBlockCipher.KEY_MATERIAL); + } + buffer = new byte[cipher.currentBlockSize()]; + buffer[cipher.currentBlockSize() - 1] = (byte) index; + try + { + fillBlock(); + } + catch (LimitReachedException impossible) + { + } + } + + public void fillBlock() throws LimitReachedException + { + cipher.encryptBlock(buffer, 0, buffer, 0); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/sasl/AuthInfo.java b/libjava/classpath/gnu/javax/crypto/sasl/AuthInfo.java new file mode 100644 index 000000000..37c1e0852 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/sasl/AuthInfo.java @@ -0,0 +1,129 @@ +/* AuthInfo.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.sasl; + +import gnu.java.security.Registry; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.StringTokenizer; + +/** + * A static class for creating {@link IAuthInfoProvider} providers. It + * transparently locates and uses any provider instances, based on the value + * assigned to the System property with the key + * <code>gnu.crypto.sasl.auth.info.provider.pkgs</code>. If more than one is + * specified they SHOULD be separated with a vertical bar character. Please note + * that the GNU provider is always added last to the list, disregarding whether + * it was mentioned or not in the value of that property, or if it that property + * was not defined. + */ +public class AuthInfo +{ + private static final ArrayList factories = new ArrayList(); + static + { + IAuthInfoProviderFactory ours = new AuthInfoProviderFactory(); + // if SASL_AUTH_INFO_PROVIDER_PKGS is defined then parse it + String clazz; + String pkgs = System.getProperty(Registry.SASL_AUTH_INFO_PROVIDER_PKGS, + null); + if (pkgs != null) + { + for (StringTokenizer st = new StringTokenizer(pkgs, "|"); st.hasMoreTokens();) + { + clazz = st.nextToken().trim(); + if (! "gnu.javax.crypto.sasl".equals(clazz)) + { + clazz += ".AuthInfoProviderFactory"; + try + { + IAuthInfoProviderFactory factory = + (IAuthInfoProviderFactory) Class.forName(clazz).newInstance(); + factories.add(factory); + } + catch (ClassCastException ignored) + { + } + catch (ClassNotFoundException ignored) + { + } + catch (InstantiationException ignored) + { + } + catch (IllegalAccessException ignored) + { + } + } + } + } + // always add ours last; unless it's already there + if (!factories.contains(ours)) + factories.add(ours); + } + + /** Trivial constructor to enforce Singleton pattern. */ + private AuthInfo() + { + super(); + } + + /** + * A convenience method to return the authentication information provider for + * a designated SASL mechnanism. It goes through all the installed provider + * factories, one at a time, and attempts to return a new instance of the + * provider for the designated mechanism. It stops at the first factory + * returning a non-null provider. + * + * @param mechanism the name of a SASL mechanism. + * @return an implementation that provides {@link IAuthInfoProvider} for that + * mechanism; or <code>null</code> if none found. + */ + public static IAuthInfoProvider getProvider(String mechanism) + { + for (Iterator it = factories.iterator(); it.hasNext();) + { + IAuthInfoProviderFactory factory = (IAuthInfoProviderFactory) it.next(); + IAuthInfoProvider result = factory.getInstance(mechanism); + if (result != null) + return result; + } + return null; + } +} diff --git a/libjava/classpath/gnu/javax/crypto/sasl/AuthInfoProviderFactory.java b/libjava/classpath/gnu/javax/crypto/sasl/AuthInfoProviderFactory.java new file mode 100644 index 000000000..f881e6e11 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/sasl/AuthInfoProviderFactory.java @@ -0,0 +1,67 @@ +/* AuthInfoProviderFactory.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.sasl; + +import gnu.java.security.Registry; +import gnu.javax.crypto.sasl.crammd5.CramMD5AuthInfoProvider; +import gnu.javax.crypto.sasl.plain.PlainAuthInfoProvider; +import gnu.javax.crypto.sasl.srp.SRPAuthInfoProvider; + +/** + * The concrete SASL authentication information provider factory. + */ +public class AuthInfoProviderFactory + implements IAuthInfoProviderFactory +{ + // implicit 0-args constructor + + public IAuthInfoProvider getInstance(String mechanism) + { + if (mechanism == null) + return null; + mechanism = mechanism.trim().toUpperCase(); + if (mechanism.startsWith(Registry.SASL_SRP_MECHANISM)) + return new SRPAuthInfoProvider(); + if (mechanism.equals(Registry.SASL_CRAM_MD5_MECHANISM)) + return new CramMD5AuthInfoProvider(); + if (mechanism.equals(Registry.SASL_PLAIN_MECHANISM)) + return new PlainAuthInfoProvider(); + return null; + } +} diff --git a/libjava/classpath/gnu/javax/crypto/sasl/ClientFactory.java b/libjava/classpath/gnu/javax/crypto/sasl/ClientFactory.java new file mode 100644 index 000000000..30309d2c7 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/sasl/ClientFactory.java @@ -0,0 +1,168 @@ +/* ClientFactory.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.sasl; + +import gnu.java.security.Registry; +import gnu.javax.crypto.sasl.anonymous.AnonymousClient; +import gnu.javax.crypto.sasl.crammd5.CramMD5Client; +import gnu.javax.crypto.sasl.plain.PlainClient; +import gnu.javax.crypto.sasl.srp.SRPClient; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import javax.security.auth.callback.CallbackHandler; +import javax.security.sasl.Sasl; +import javax.security.sasl.SaslClient; +import javax.security.sasl.SaslClientFactory; +import javax.security.sasl.SaslException; + +/** + * The implementation of {@link SaslClientFactory}. + */ +public class ClientFactory + implements SaslClientFactory +{ + // implicit 0-arguments constructor + + public static final Set getNames() + { + return Collections.unmodifiableSet(new HashSet(Arrays.asList(getNamesInternal(null)))); + } + + private static final String[] getNamesInternal(Map props) + { + String[] all = new String[] { + Registry.SASL_SRP_MECHANISM, + Registry.SASL_CRAM_MD5_MECHANISM, + Registry.SASL_PLAIN_MECHANISM, + Registry.SASL_ANONYMOUS_MECHANISM }; + if (props == null) + return all; + if (hasPolicy(Sasl.POLICY_PASS_CREDENTIALS, props)) + return new String[0]; + List result = new ArrayList(all.length); + for (int i = 0; i < all.length;) + result.add(all[i++]); + if (hasPolicy(Sasl.POLICY_NOPLAINTEXT, props)) + result.remove(Registry.SASL_PLAIN_MECHANISM); + if (hasPolicy(Sasl.POLICY_NOACTIVE, props)) + { + result.remove(Registry.SASL_CRAM_MD5_MECHANISM); + result.remove(Registry.SASL_PLAIN_MECHANISM); + } + if (hasPolicy(Sasl.POLICY_NODICTIONARY, props)) + { + result.remove(Registry.SASL_CRAM_MD5_MECHANISM); + result.remove(Registry.SASL_PLAIN_MECHANISM); + } + if (hasPolicy(Sasl.POLICY_NOANONYMOUS, props)) + { + result.remove(Registry.SASL_ANONYMOUS_MECHANISM); + } + if (hasPolicy(Sasl.POLICY_FORWARD_SECRECY, props)) + { + result.remove(Registry.SASL_CRAM_MD5_MECHANISM); + result.remove(Registry.SASL_ANONYMOUS_MECHANISM); + result.remove(Registry.SASL_PLAIN_MECHANISM); + } + return (String[]) result.toArray(new String[0]); + } + + public static final ClientMechanism getInstance(String mechanism) + { + if (mechanism == null) + return null; + mechanism = mechanism.trim().toUpperCase(); + if (mechanism.equals(Registry.SASL_SRP_MECHANISM)) + return new SRPClient(); + if (mechanism.equals(Registry.SASL_CRAM_MD5_MECHANISM)) + return new CramMD5Client(); + if (mechanism.equals(Registry.SASL_PLAIN_MECHANISM)) + return new PlainClient(); + if (mechanism.equals(Registry.SASL_ANONYMOUS_MECHANISM)) + return new AnonymousClient(); + return null; + } + + public SaslClient createSaslClient(String[] mechanisms, + String authorisationID, String protocol, + String serverName, Map props, + CallbackHandler cbh) throws SaslException + { + ClientMechanism result = null; + String mechanism; + for (int i = 0; i < mechanisms.length; i++) + { + mechanism = mechanisms[i]; + result = getInstance(mechanism); + if (result != null) + break; + } + if (result != null) + { + HashMap attributes = new HashMap(); + if (props != null) + attributes.putAll(props); + attributes.put(Registry.SASL_AUTHORISATION_ID, authorisationID); + attributes.put(Registry.SASL_PROTOCOL, protocol); + attributes.put(Registry.SASL_SERVER_NAME, serverName); + attributes.put(Registry.SASL_CALLBACK_HANDLER, cbh); + result.init(attributes); + return result; + } + throw new SaslException("No supported mechanism found in given mechanism list"); + } + + public String[] getMechanismNames(Map props) + { + return getNamesInternal(props); + } + + private static boolean hasPolicy(String propertyName, Map props) + { + return "true".equalsIgnoreCase(String.valueOf(props.get(propertyName))); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/sasl/ClientMechanism.java b/libjava/classpath/gnu/javax/crypto/sasl/ClientMechanism.java new file mode 100644 index 000000000..5e0dcd096 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/sasl/ClientMechanism.java @@ -0,0 +1,293 @@ +/* ClientMechanism.java -- + Copyright (C) 2003, 2005, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.sasl; + +import gnu.java.security.Registry; + +import java.util.HashMap; +import java.util.Map; + +import javax.security.auth.callback.CallbackHandler; +import javax.security.sasl.Sasl; +import javax.security.sasl.SaslClient; +import javax.security.sasl.SaslException; + +/** + * A base class to facilitate implementing SASL client-side mechanisms. + */ +public abstract class ClientMechanism + implements SaslClient +{ + /** Name of this mechanism. */ + protected String mechanism; + /** The authorisation identity. */ + protected String authorizationID; + /** Name of protocol using this mechanism. */ + protected String protocol; + /** Name of server to authenticate to. */ + protected String serverName; + /** Properties of qualities desired for this mechanism. */ + protected Map properties; + /** Callback handler to use with this mechanism instance. */ + protected CallbackHandler handler; + /** Channel binding data to use with this mechanism instance. */ + protected byte[] channelBinding; + /** Whether authentication phase is completed (true) or not (false). */ + protected boolean complete = false; + /** The state of the authentication automaton. */ + protected int state = -1; + + protected ClientMechanism(final String mechanism) + { + super(); + + this.mechanism = mechanism; + this.state = -1; + } + + protected abstract void initMechanism() throws SaslException; + + protected abstract void resetMechanism() throws SaslException; + + public abstract byte[] evaluateChallenge(byte[] challenge) + throws SaslException; + + public abstract boolean hasInitialResponse(); + + public boolean isComplete() + { + return complete; + } + + public byte[] unwrap(final byte[] incoming, final int offset, final int len) + throws SaslException + { + if (! isComplete()) + throw new IllegalMechanismStateException(); + return this.engineUnwrap(incoming, offset, len); + } + + public byte[] wrap(final byte[] outgoing, final int offset, final int len) + throws SaslException + { + if (! isComplete()) + throw new IllegalMechanismStateException(); + return this.engineWrap(outgoing, offset, len); + } + + public String getMechanismName() + { + return mechanism; + } + + public Object getNegotiatedProperty(final String propName) + { + if (! isComplete()) + throw new IllegalStateException(); + if (Sasl.QOP.equals(propName)) + return getNegotiatedQOP(); + if (Sasl.STRENGTH.equals(propName)) + return getNegotiatedStrength(); + if (Sasl.SERVER_AUTH.equals(propName)) + return getNegotiatedServerAuth(); + if (Sasl.MAX_BUFFER.equals(propName)) + return getNegotiatedMaxBuffer(); + if (Sasl.RAW_SEND_SIZE.equals(propName)) + return getNegotiatedRawSendSize(); + if (Sasl.POLICY_NOPLAINTEXT.equals(propName)) + return getNegotiatedPolicyNoPlainText(); + if (Sasl.POLICY_NOACTIVE.equals(propName)) + return getNegotiatedPolicyNoActive(); + if (Sasl.POLICY_NODICTIONARY.equals(propName)) + return getNegotiatedPolicyNoDictionary(); + if (Sasl.POLICY_NOANONYMOUS.equals(propName)) + return getNegotiatedPolicyNoAnonymous(); + if (Sasl.POLICY_FORWARD_SECRECY.equals(propName)) + return getNegotiatedPolicyForwardSecrecy(); + if (Sasl.POLICY_PASS_CREDENTIALS.equals(propName)) + return getNegotiatedPolicyPassCredentials(); + if (Sasl.REUSE.equals(propName)) + return getReuse(); + return null; + } + + public void dispose() throws SaslException + { + } + + public String getAuthorizationID() + { + return authorizationID; + } + + protected String getNegotiatedQOP() + { + return Registry.QOP_AUTH; + } + + protected String getNegotiatedStrength() + { + return Registry.STRENGTH_LOW; + } + + protected String getNegotiatedServerAuth() + { + return Registry.SERVER_AUTH_FALSE; + } + + protected String getNegotiatedMaxBuffer() + { + return null; + } + + protected String getNegotiatedRawSendSize() + { + return String.valueOf(Registry.SASL_BUFFER_MAX_LIMIT); + } + + protected String getNegotiatedPolicyNoPlainText() + { + return null; + } + + protected String getNegotiatedPolicyNoActive() + { + return null; + } + + protected String getNegotiatedPolicyNoDictionary() + { + return null; + } + + protected String getNegotiatedPolicyNoAnonymous() + { + return null; + } + + protected String getNegotiatedPolicyForwardSecrecy() + { + return null; + } + + protected String getNegotiatedPolicyPassCredentials() + { + return null; + } + + protected String getReuse() + { + return Registry.REUSE_FALSE; + } + + protected byte[] engineUnwrap(final byte[] incoming, final int offset, + final int len) throws SaslException + { + final byte[] result = new byte[len]; + System.arraycopy(incoming, offset, result, 0, len); + return result; + } + + protected byte[] engineWrap(final byte[] outgoing, final int offset, + final int len) throws SaslException + { + final byte[] result = new byte[len]; + System.arraycopy(outgoing, offset, result, 0, len); + return result; + } + + /** + * Initialises the mechanism with designated attributes. Permissible names and + * values are mechanism specific. + * + * @param attributes a set of name-value pairs that describes the desired + * future behaviour of this instance. + * @throws IllegalMechanismStateException if the instance is already + * initialised. + * @throws SaslException if an exception occurs during the process. + */ + public void init(final Map attributes) throws SaslException + { + if (state != -1) + throw new IllegalMechanismStateException("init()"); + if (properties == null) + properties = new HashMap(); + else + properties.clear(); + if (attributes != null) + { + authorizationID = (String) attributes.get(Registry.SASL_AUTHORISATION_ID); + protocol = (String) attributes.get(Registry.SASL_PROTOCOL); + serverName = (String) attributes.get(Registry.SASL_SERVER_NAME); + handler = (CallbackHandler) attributes.get(Registry.SASL_CALLBACK_HANDLER); + channelBinding = (byte[]) attributes.get(Registry.SASL_CHANNEL_BINDING); + properties.putAll(attributes); + } + else + handler = null; + + if (authorizationID == null) + authorizationID = ""; + if (protocol == null) + protocol = ""; + if (serverName == null) + serverName = ""; + if (channelBinding == null) + channelBinding = new byte[0]; + initMechanism(); + complete = false; + state = 0; + } + + /** + * Resets the mechanism instance for re-initialisation and use with other + * characteristics. + * + * @throws SaslException if an exception occurs during the process. + */ + public void reset() throws SaslException + { + resetMechanism(); + properties.clear(); + authorizationID = protocol = serverName = null; + channelBinding = null; + complete = false; + state = -1; + } +} diff --git a/libjava/classpath/gnu/javax/crypto/sasl/ConfidentialityException.java b/libjava/classpath/gnu/javax/crypto/sasl/ConfidentialityException.java new file mode 100644 index 000000000..85bd2ae18 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/sasl/ConfidentialityException.java @@ -0,0 +1,82 @@ +/* ConfidentialityException.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.sasl; + +import javax.security.sasl.SaslException; + +/** + * Used by mechanisms that offer a security services layer, this checked + * exception is thrown to indicate that a violation has occured during the + * processing of a <i>confidentiality</i> protection filter. + */ +public class ConfidentialityException + extends SaslException +{ + /** + * Constructs a new instance of <code>ConfidentialityException</code> with + * no detail message. + */ + public ConfidentialityException() + { + super(); + } + + /** + * Constructs a new instance of <code>ConfidentialityException</code> with + * the specified detail message. + * + * @param s the detail message. + */ + public ConfidentialityException(String s) + { + super(s); + } + + /** + * Constructs a new instance of <code>ConfidentialityException</code> with a + * detailed message and a root exception. + * + * @param s possibly null additional detail about the exception. + * @param x a possibly null root exception that caused this one. + */ + public ConfidentialityException(String s, Throwable x) + { + super(s, x); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/sasl/IAuthInfoProvider.java b/libjava/classpath/gnu/javax/crypto/sasl/IAuthInfoProvider.java new file mode 100644 index 000000000..88acc2d0a --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/sasl/IAuthInfoProvider.java @@ -0,0 +1,116 @@ +/* IAuthInfoProvider.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.sasl; + +import java.util.Map; + +import javax.security.sasl.AuthenticationException; + +/** + * The visible methods of any authentication information provider. + */ +public interface IAuthInfoProvider +{ + /** + * Activates (initialises) this provider instance. SHOULD be the first method + * invoked on the provider. + * + * @param context a collection of name-value bindings describing the + * activation context. + * @throws AuthenticationException if an exception occurs during the + * operation. + */ + void activate(Map context) throws AuthenticationException; + + /** + * Passivates (releases) this provider instance. SHOULD be the last method + * invoked on the provider. Once it is done, no other method may be invoked on + * the same instance before it is <i>activated</i> agains. + * + * @throws AuthenticationException if an exception occurs during the + * operation. + */ + void passivate() throws AuthenticationException; + + /** + * Checks if a user with a designated name is known to this provider. + * + * @param userName the name of a user to check. + * @return <code>true</code> if the user with the designated name is known + * to this provider; <code>false</code> otherwise. + * @throws AuthenticationException if an exception occurs during the + * operation. + */ + boolean contains(String userName) throws AuthenticationException; + + /** + * Returns a collection of information about a designated user. The contents + * of the returned map is provider-specific of name-to-value mappings. + * + * @param userID a map of name-to-value bindings that fully describe a user. + * @return a collection of information about the designated user. + * @throws AuthenticationException if an exception occurs during the + * operation. + */ + Map lookup(Map userID) throws AuthenticationException; + + /** + * Updates the credentials of a designated user. + * + * @param userCredentials a map of name-to-value bindings that fully describe + * a user, including per new credentials. + * @throws AuthenticationException if an exception occurs during the + * operation. + */ + void update(Map userCredentials) throws AuthenticationException; + + /** + * A provider may operate in more than mode; e.g. SRP-II caters for user + * credentials computed in more than one message digest algorithm. This method + * returns the set of name-to-value bindings describing the mode of the + * provider. + * + * @param mode a unique identifier describing the operational mode. + * @return a collection of name-to-value bindings describing the designated + * mode. + * @throws AuthenticationException if an exception occurs during the + * operation. + */ + Map getConfiguration(String mode) throws AuthenticationException; +} diff --git a/libjava/classpath/gnu/javax/crypto/sasl/IAuthInfoProviderFactory.java b/libjava/classpath/gnu/javax/crypto/sasl/IAuthInfoProviderFactory.java new file mode 100644 index 000000000..2a0b5bfec --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/sasl/IAuthInfoProviderFactory.java @@ -0,0 +1,55 @@ +/* IAuthInfoProviderFactory.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.sasl; + +/** + * The visible method of every authentication information provider factory. + */ +public interface IAuthInfoProviderFactory +{ + /** + * Returns an implementation of a provider for a designated mechanism capable + * of honouring {@link IAuthInfoProvider} requests. + * + * @param mechanism the unique name of a mechanism. + * @return an implementation of {@link IAuthInfoProvider} for that mechanism + * or <code>null</code> if none found. + */ + IAuthInfoProvider getInstance(String mechanism); +} diff --git a/libjava/classpath/gnu/javax/crypto/sasl/IllegalMechanismStateException.java b/libjava/classpath/gnu/javax/crypto/sasl/IllegalMechanismStateException.java new file mode 100644 index 000000000..fade7792c --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/sasl/IllegalMechanismStateException.java @@ -0,0 +1,84 @@ +/* IllegalMechanismStateException.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.sasl; + +import javax.security.sasl.AuthenticationException; + +/** + * A checked exception thrown to indicate that an operation that should be + * invoked on a completed mechanism was invoked but the authentication phase of + * that mechanism was not completed yet, or that an operation that should be + * invoked on incomplete mechanisms was invoked but the authentication phase of + * that mechanism was already completed. + */ +public class IllegalMechanismStateException + extends AuthenticationException +{ + /** + * Constructs a new instance of <code>IllegalMechanismStateException</code> + * with no detail message. + */ + public IllegalMechanismStateException() + { + super(); + } + + /** + * Constructs a new instance of <code>IllegalMechanismStateException</code> + * with the specified detail message. + * + * @param detail the detail message. + */ + public IllegalMechanismStateException(String detail) + { + super(detail); + } + + /** + * Constructs a new instance of <code>IllegalMechanismStateException</code> + * with the specified detail message, and cause. + * + * @param detail the detail message. + * @param ex the original cause. + */ + public IllegalMechanismStateException(String detail, Throwable ex) + { + super(detail, ex); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/sasl/InputBuffer.java b/libjava/classpath/gnu/javax/crypto/sasl/InputBuffer.java new file mode 100644 index 000000000..f15205765 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/sasl/InputBuffer.java @@ -0,0 +1,272 @@ +/* InputBuffer.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.sasl; + +import gnu.java.security.Registry; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.math.BigInteger; + +/** + * The implementation of an incoming SASL buffer. + * <p> + * The data elements this class caters for are described in [1]. + * <p> + * References: + * <ol> + * <li><a + * href="http://www.ietf.org/internet-drafts/draft-burdis-cat-srp-sasl-09.txt"> + * Secure Remote Password Authentication Mechanism</a>;<br/> + * draft-burdis-cat-srp-sasl-09,<br/> <a + * href="mailto:keith@rucus.ru.ac.za">Keith Burdis</a> and <a + * href="mailto:raif@forge.com.au">Raïf S. Naffah</a>.</li> + * </ol> + */ +public class InputBuffer +{ + /** The internal buffer stream containing the buffer's contents. */ + protected ByteArrayInputStream in; + /** The length of the buffer, according to its header. */ + protected int length; + + /** + * Constructs a SASL buffer given the buffer's encoded form, including its + * header bytes. + * + * @param frame the encoded form, including the header bytes, of a SASL + * buffer. + * @throws SaslEncodingException if the buffer is malformed. + */ + public InputBuffer(byte[] frame) throws SaslEncodingException + { + this(); + + if (frame.length < 4) + throw new SaslEncodingException("SASL buffer header too short"); + length = (frame[0] & 0xFF) << 24 + | (frame[1] & 0xFF) << 16 + | (frame[2] & 0xFF) << 8 + | (frame[3] & 0xFF); + if (length > Registry.SASL_BUFFER_MAX_LIMIT || length < 0) + throw new SaslEncodingException("SASL buffer size limit exceeded"); + in = new ByteArrayInputStream(frame, 4, length); + } + + /** Trivial private constructor for use by the class method. */ + private InputBuffer() + { + super(); + } + + /** + * Returns an instance of a SASL buffer given the buffer's encoded contents, + * excluding the buffer's header bytes. + * <p> + * Calls the method with the same name and three arguments as: + * <code>getInstance(raw, 0, raw.length)</code>. + * + * @param raw the encoded form, excluding the header bytes, of a SASL buffer. + * @return a new instance of {@link InputBuffer}. + */ + public static InputBuffer getInstance(byte[] raw) + { + return getInstance(raw, 0, raw.length); + } + + /** + * Returns an instance of a SASL buffer given the buffer's encoded contents, + * excluding the buffer's header bytes. + * + * @param raw the encoded form, excluding the header bytes, of a SASL buffer. + * @param offset offset where to start using raw bytes from. + * @param len number of bytes to use. + * @return a new instance of {@link InputBuffer}. + */ + public static InputBuffer getInstance(byte[] raw, int offset, int len) + { + InputBuffer result = new InputBuffer(); + result.in = new ByteArrayInputStream(raw, offset, len); + return result; + } + + /** + * Converts two octets into the number that they represent. + * + * @param b the two octets. + * @return the length. + */ + public static int twoBytesToLength(byte[] b) throws SaslEncodingException + { + final int result = (b[0] & 0xFF) << 8 | (b[1] & 0xFF); + if (result > Registry.SASL_TWO_BYTE_MAX_LIMIT) + throw new SaslEncodingException("SASL MPI/Text size limit exceeded"); + return result; + } + + public boolean hasMoreElements() + { + return (in.available() > 0); + } + + /** + * Decodes a SASL scalar quantity, <code>count</code>-octet long, from the + * current buffer. + * + * @param count the number of octets of this scalar quantity. + * @return a native representation of a SASL scalar (unsigned integer) + * quantity. + * @throws SaslEncodingException if an encoding exception occurs during the + * operation. + * @throws IOException if any other I/O exception occurs during the operation. + */ + public long getScalar(int count) throws IOException + { + if (count < 0 || count > 4) + throw new SaslEncodingException("Invalid SASL scalar octet count: " + + String.valueOf(count)); + if (! hasMoreElements()) + throw new SaslEncodingException("Not enough bytes for a scalar in buffer"); + if (in.available() < count) + throw new SaslEncodingException("Illegal SASL scalar encoding"); + byte[] element = new byte[count]; + in.read(element); + long result = 0L; + for (int i = 0; i < count; i++) + { + result <<= 8; + result |= element[i] & 0xFFL; + } + return result; + } + + /** + * Decodes a SASL OS from the current buffer. + * + * @return a native representation of a SASL OS. + * @throws SaslEncodingException if an encoding exception occurs during the + * operation. + * @throws IOException if any other I/O exception occurs during the operation. + */ + public byte[] getOS() throws IOException + { + if (! hasMoreElements()) + throw new SaslEncodingException( + "Not enough bytes for an octet-sequence in buffer"); + final int elementLength = in.read(); + if (elementLength > Registry.SASL_ONE_BYTE_MAX_LIMIT) + throw new SaslEncodingException("SASL octet-sequence size limit exceeded"); + if (in.available() < elementLength) + throw new SaslEncodingException("Illegal SASL octet-sequence encoding"); + byte[] result = new byte[elementLength]; + in.read(result); + return result; + } + + /** + * Decodes a SASL EOS from the current buffer. + * + * @return a native representation of a SASL EOS. + * @throws SaslEncodingException if an encoding exception occurs during the + * operation. + * @throws IOException if any other I/O exception occurs during the operation. + */ + public byte[] getEOS() throws IOException + { + if (in.available() < 2) + throw new SaslEncodingException( + "Not enough bytes for an extended octet-sequence in buffer"); + byte[] elementLengthBytes = new byte[2]; + in.read(elementLengthBytes); + final int elementLength = twoBytesToLength(elementLengthBytes); + if (in.available() < elementLength) + throw new SaslEncodingException( + "Illegal SASL extended octet-sequence encoding"); + byte[] result = new byte[elementLength]; + in.read(result); + return result; + } + + /** + * Decodes a SASL MPI from the current buffer. + * + * @return a native representation of a SASL MPI. + * @throws SaslEncodingException if an encoding exception occurs during the + * operation. + * @throws IOException if any other I/O exception occurs during the operation. + */ + public BigInteger getMPI() throws IOException + { + if (in.available() < 2) + throw new SaslEncodingException("Not enough bytes for an MPI in buffer"); + byte[] elementLengthBytes = new byte[2]; + in.read(elementLengthBytes); + final int elementLength = twoBytesToLength(elementLengthBytes); + if (in.available() < elementLength) + throw new SaslEncodingException( + "Illegal SASL multi-precision integer encoding"); + byte[] element = new byte[elementLength]; + in.read(element); + return new BigInteger(1, element); + } + + /** + * Decodes a SASL Text from the current buffer. + * + * @return a native representation of a SASL Text. + * @throws SaslEncodingException if an encoding exception occurs during the + * operation. + * @throws SaslEncodingException if the UTF-8 character encoding is not + * supported on this platform. + * @throws IOException if any other I/O exception occurs during the operation. + */ + public String getText() throws IOException + { + if (in.available() < 2) + throw new SaslEncodingException("Not enough bytes for a text in buffer"); + byte[] elementLengthBytes = new byte[2]; + in.read(elementLengthBytes); + final int elementLength = twoBytesToLength(elementLengthBytes); + if (in.available() < elementLength) + throw new SaslEncodingException("Illegal SASL text encoding"); + byte[] element = new byte[elementLength]; + in.read(element); + return new String(element, "UTF8"); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/sasl/IntegrityException.java b/libjava/classpath/gnu/javax/crypto/sasl/IntegrityException.java new file mode 100644 index 000000000..ce1b359de --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/sasl/IntegrityException.java @@ -0,0 +1,83 @@ +/* IntegrityException.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.sasl; + +import javax.security.sasl.SaslException; + +/** + * Used by mechanisms that offer a security services layer, this checked + * exception is thrown to indicate that a violation has occured during the + * processing of an <i>integrity</i> protection filter, including <i>replay + * detection</i>. + */ +public class IntegrityException + extends SaslException +{ + /** + * Constructs a new instance of <code>IntegrityException</code> with no + * detail message. + */ + public IntegrityException() + { + super(); + } + + /** + * Constructs a new instance of <code>IntegrityException</code> with the + * specified detail message. + * + * @param s the detail message. + */ + public IntegrityException(String s) + { + super(s); + } + + /** + * Constructs a new instance of <code>IntegrityException</code> with a + * detailed message and a root exception. + * + * @param s possibly null additional detail about the exception. + * @param x a possibly null root exception that caused this one. + */ + public IntegrityException(String s, Throwable x) + { + super(s, x); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/sasl/NoSuchMechanismException.java b/libjava/classpath/gnu/javax/crypto/sasl/NoSuchMechanismException.java new file mode 100644 index 000000000..d22bff894 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/sasl/NoSuchMechanismException.java @@ -0,0 +1,62 @@ +/* NoSuchMechanismException.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.sasl; + +import javax.security.sasl.SaslException; + +/** + * A checked exception thrown to indicate that a designated SASL mechanism + * implementation was not found. + */ +public class NoSuchMechanismException + extends SaslException +{ + /** + * Constructs a <code>NoSuchMechanismException</code> with the specified + * detail message. In the case of this exception, the detail message + * designates the offending mechanism name. + * + * @param arg the detail message, which in this case is the offending + * mechanism name. + */ + public NoSuchMechanismException(String arg) + { + super(arg); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/sasl/NoSuchUserException.java b/libjava/classpath/gnu/javax/crypto/sasl/NoSuchUserException.java new file mode 100644 index 000000000..447c7b919 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/sasl/NoSuchUserException.java @@ -0,0 +1,67 @@ +/* NoSuchUserException.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.sasl; + +import javax.security.sasl.AuthenticationException; + +/** + * A checked exception thrown to indicate that a designated user is unknown to + * the authentication layer. + */ +public class NoSuchUserException + extends AuthenticationException +{ + /** Constructs a <code>NoSuchUserException</code> with no detail message. */ + public NoSuchUserException() + { + super(); + } + + /** + * Constructs a <code>NoSuchUserException</code> with the specified detail + * message. In the case of this exception, the detail message designates the + * offending username. + * + * @param arg the detail message, which in this case is the username. + */ + public NoSuchUserException(String arg) + { + super(arg); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/sasl/OutputBuffer.java b/libjava/classpath/gnu/javax/crypto/sasl/OutputBuffer.java new file mode 100644 index 000000000..4bb3b0ec2 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/sasl/OutputBuffer.java @@ -0,0 +1,198 @@ +/* OutputBuffer.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.sasl; + +import gnu.java.security.Registry; +import gnu.java.security.util.Util; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.math.BigInteger; + +/** + * The implementation of an outgoing SASL buffer. + * <p> + * The data elements this class caters for are described in [1]. + * <p> + * References: + * <ol> + * <li><a + * href="http://www.ietf.org/internet-drafts/draft-burdis-cat-srp-sasl-09.txt"> + * Secure Remote Password Authentication Mechanism</a>;<br/> + * draft-burdis-cat-srp-sasl-09,<br/> <a + * href="mailto:keith@rucus.ru.ac.za">Keith Burdis</a> and <a + * href="mailto:raif@forge.com.au">Raïf S. Naffah</a>.</li> + * </ol> + */ +public class OutputBuffer +{ + /** The internal output stream. */ + private ByteArrayOutputStream out; + + public OutputBuffer() + { + super(); + + out = new ByteArrayOutputStream(); + } + + /** + * Encodes a SASL scalar quantity, <code>count</code>-octet long, to the + * current buffer. + * + * @param count number of octets to encode <code>b</code> with. + * @param b the scalar quantity. + * @throws SaslEncodingException if an encoding size constraint is violated. + * @throws IOException if any other I/O exception occurs during the operation. + */ + public void setScalar(int count, int b) throws IOException + { + if (count < 0 || count > 4) + throw new SaslEncodingException("Invalid SASL scalar octet count: " + + String.valueOf(count)); + byte[] element = new byte[count]; + for (int i = count; --i >= 0; b >>>= 8) + element[i] = (byte) b; + out.write(element); + } + + /** + * Encodes a SASL OS to the current buffer. + * + * @param b the OS element. + * @throws SaslEncodingException if an encoding size constraint is violated. + * @throws IOException if any other I/O exception occurs during the operation. + */ + public void setOS(byte[] b) throws IOException + { + final int length = b.length; + if (length > Registry.SASL_ONE_BYTE_MAX_LIMIT) + throw new SaslEncodingException("SASL octet-sequence too long"); + out.write(length & 0xFF); + out.write(b); + } + + /** + * Encodes a SASL EOS to the current buffer. + * + * @param b the EOS element. + * @throws SaslEncodingException if an encoding size constraint is violated. + * @throws IOException if any other I/O exception occurs during the operation. + */ + public void setEOS(byte[] b) throws IOException + { + final int length = b.length; + if (length > Registry.SASL_TWO_BYTE_MAX_LIMIT) + throw new SaslEncodingException("SASL extended octet-sequence too long"); + byte[] lengthBytes = { (byte)(length >>> 8), (byte) length }; + out.write(lengthBytes); + out.write(b); + } + + /** + * Encodes a SASL MPI to the current buffer. + * + * @param val the MPI element. + * @throws SaslEncodingException if an encoding size constraint is violated. + * @throws IOException if any other I/O exception occurs during the operation. + */ + public void setMPI(BigInteger val) throws IOException + { + byte[] b = Util.trim(val); + final int length = b.length; + if (length > Registry.SASL_TWO_BYTE_MAX_LIMIT) + throw new SaslEncodingException("SASL multi-precision integer too long"); + byte[] lengthBytes = { (byte)(length >>> 8), (byte) length }; + out.write(lengthBytes); + out.write(b); + } + + /** + * Encodes a SASL Text to the current buffer. + * + * @param str the Text element. + * @throws SaslEncodingException if an encoding size constraint is violated. + * @throws SaslEncodingException if the UTF-8 encoding is not supported on + * this platform. + * @throws IOException if any other I/O exception occurs during the operation. + */ + public void setText(String str) throws IOException + { + byte[] b = str.getBytes("UTF8"); + final int length = b.length; + if (length > Registry.SASL_TWO_BYTE_MAX_LIMIT) + throw new SaslEncodingException("SASL text too long"); + byte[] lengthBytes = { (byte)(length >>> 8), (byte) length }; + out.write(lengthBytes); + out.write(b); + } + + /** + * Returns the encoded form of the current buffer including the 4-byte length + * header. + * + * @throws SaslEncodingException if an encoding size constraint is violated. + */ + public byte[] encode() throws SaslEncodingException + { + byte[] buffer = wrap(); + final int length = buffer.length; + byte[] result = new byte[length + 4]; + result[0] = (byte)(length >>> 24); + result[1] = (byte)(length >>> 16); + result[2] = (byte)(length >>> 8); + result[3] = (byte) length; + System.arraycopy(buffer, 0, result, 4, length); + return result; + } + + /** + * Returns the encoded form of the current buffer excluding the 4-byte length + * header. + * + * @throws SaslEncodingException if an encoding size constraint is violated. + */ + public byte[] wrap() throws SaslEncodingException + { + final int length = out.size(); + if (length > Registry.SASL_BUFFER_MAX_LIMIT || length < 0) + throw new SaslEncodingException("SASL buffer too long"); + return out.toByteArray(); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/sasl/SaslEncodingException.java b/libjava/classpath/gnu/javax/crypto/sasl/SaslEncodingException.java new file mode 100644 index 000000000..5836270ac --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/sasl/SaslEncodingException.java @@ -0,0 +1,66 @@ +/* SaslEncodingException.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.sasl; + +import javax.security.sasl.SaslException; + +/** + * A checked exception, thrown when an exception occurs while decoding a SASL + * buffer and/or a SASL data element from/to a buffer. + */ +public class SaslEncodingException + extends SaslException +{ + /** Constructs a <code>SaslEncodingException</code> with no detail message. */ + public SaslEncodingException() + { + super(); + } + + /** + * Constructs a <code>SaslEncodingException</code> with the specified detail + * message. + * + * @param s the detail message. + */ + public SaslEncodingException(String s) + { + super(s); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/sasl/SaslInputStream.java b/libjava/classpath/gnu/javax/crypto/sasl/SaslInputStream.java new file mode 100644 index 000000000..6a6c85751 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/sasl/SaslInputStream.java @@ -0,0 +1,393 @@ +/* SaslInputStream.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.sasl; + +import gnu.java.security.Configuration; +import gnu.java.security.util.Util; + +import java.io.IOException; +import java.io.InputStream; +import java.io.InterruptedIOException; +import java.util.logging.Logger; + +import javax.security.sasl.Sasl; +import javax.security.sasl.SaslClient; +import javax.security.sasl.SaslServer; + +/** + * An input stream that uses either a {@link SaslClient} or a {@link SaslServer} + * to process the data through these entities' security layer filter(s). + */ +public class SaslInputStream + extends InputStream +{ + private static final Logger log = Logger.getLogger(SaslInputStream.class.getName()); + private SaslClient client; + private SaslServer server; + private int maxRawSendSize; + private InputStream source; + private byte[] internalBuf; + + public SaslInputStream(SaslClient client, InputStream source) + throws IOException + { + super(); + + this.client = client; + String size = (String) client.getNegotiatedProperty(Sasl.RAW_SEND_SIZE); + maxRawSendSize = Integer.parseInt(size); + server = null; + this.source = source; + } + + public SaslInputStream(SaslServer server, InputStream source) + throws IOException + { + super(); + + this.server = server; + String size = (String) server.getNegotiatedProperty(Sasl.RAW_SEND_SIZE); + maxRawSendSize = Integer.parseInt(size); + client = null; + this.source = source; + } + + public int available() throws IOException + { + return (internalBuf == null) ? 0 : internalBuf.length; + } + + public void close() throws IOException + { + source.close(); + } + + /** + * Reads the next byte of data from the input stream. The value byte is + * returned as an <code>int</code> in the range <code>0</code> to + * <code>255</code>. If no byte is available because the end of the stream + * has been reached, the value <code>-1</code> is returned. This method + * blocks until input data is available, the end of the stream is detected, or + * an exception is thrown. + * <p> + * From a SASL mechanism provider's perspective, if a security layer has been + * negotiated, the underlying <i>source</i> is expected to contain SASL + * buffers, as defined in RFC 2222. Four octets in network byte order in the + * front of each buffer identify the length of the buffer. The provider is + * responsible for performing any integrity checking or other processing on + * the buffer before returning the data as a stream of octets. For example, + * the protocol driver's request for a single octet from the stream might; + * i.e. an invocation of this method, may result in an entire SASL buffer + * being read and processed before that single octet can be returned. + * + * @return the next byte of data, or <code>-1</code> if the end of the + * stream is reached. + * @throws IOException if an I/O error occurs. + */ + public int read() throws IOException + { + int result = -1; + if (internalBuf != null && internalBuf.length > 0) + { + result = internalBuf[0] & 0xFF; + if (internalBuf.length == 1) + internalBuf = new byte[0]; + else + { + byte[] tmp = new byte[internalBuf.length - 1]; + System.arraycopy(internalBuf, 1, tmp, 0, tmp.length); + internalBuf = tmp; + } + } + else + { + byte[] buf = new byte[1]; + int check = read(buf); + result = (check > 0) ? (buf[0] & 0xFF) : -1; + } + return result; + } + + /** + * Reads up to <code>len</code> bytes of data from the underlying <i>source</i> + * input stream into an array of bytes. An attempt is made to read as many as + * <code>len</code> bytes, but a smaller number may be read, possibly zero. + * The number of bytes actually read is returned as an integer. + * <p> + * This method blocks until input data is available, end of file is detected, + * or an exception is thrown. + * <p> + * If <code>b</code> is <code>null</code>, a {@link NullPointerException} + * is thrown. + * <p> + * If <code>off</code> is negative, or <code>len</code> is negative, or + * <code>off+len</code> is greater than the length of the array + * <code>b</code>, then an {@link IndexOutOfBoundsException} is thrown. + * <p> + * If <code>len</code> is zero, then no bytes are read and <code>0</code> + * is returned; otherwise, there is an attempt to read at least one byte. If + * no byte is available because the stream is at end of file, the value + * <code>-1</code> is returned; otherwise, at least one byte is read and + * stored into <code>b</code>. + * <p> + * The first byte read is stored into element <code>b[off]</code>, the next + * one into <code>b[off+1]</code>, and so on. The number of bytes read is, + * at most, equal to <code>len</code>. Let <code>k</code> be the number + * of bytes actually read; these bytes will be stored in elements + * <code>b[off]</code> through <code>b[off+k-1]</code>, leaving elements + * <code>b[off+k]</code> through <code>b[off+len-1]</code> unaffected. + * <p> + * In every case, elements <code>b[0]</code> through <code>b[off]</code> + * and elements <code>b[off+len]</code> through <code>b[b.length-1]</code> + * are unaffected. + * <p> + * If the first byte cannot be read for any reason other than end of file, + * then an {@link IOException} is thrown. In particular, an + * {@link IOException} is thrown if the input stream has been closed. + * <p> + * From the SASL mechanism provider's perspective, if a security layer has + * been negotiated, the underlying <i>source</i> is expected to contain SASL + * buffers, as defined in RFC 2222. Four octets in network byte order in the + * front of each buffer identify the length of the buffer. The provider is + * responsible for performing any integrity checking or other processing on + * the buffer before returning the data as a stream of octets. The protocol + * driver's request for a single octet from the stream might result in an + * entire SASL buffer being read and processed before that single octet can be + * returned. + * + * @param b the buffer into which the data is read. + * @param off the start offset in array <code>b</code> at which the data is + * wricodeen. + * @param len the maximum number of bytes to read. + * @return the total number of bytes read into the buffer, or <code>-1</code> + * if there is no more data because the end of the stream has been + * reached. + * @throws IOException if an I/O error occurs. + */ + public int read(byte[] b, int off, int len) throws IOException + { + if (Configuration.DEBUG) + log.entering(this.getClass().getName(), "read", new Object[] { + b, Integer.valueOf(off), Integer.valueOf(len) + }); + if ((off < 0) || (off > b.length) || (len < 0) || ((off + len) > b.length) + || ((off + len) < 0)) + throw new IndexOutOfBoundsException("off=" + off + ", len=" + len + + ", b.length=" + b.length); + if (len == 0) + { + if (Configuration.DEBUG) + log.exiting(this.getClass().getName(), "read", Integer.valueOf(0)); + return 0; + } + if (Configuration.DEBUG) + log.finer("Available: " + available()); + int result = 0; + if (internalBuf == null || internalBuf.length < 1) + try + { + internalBuf = readSaslBuffer(); + if (internalBuf == null) + { + if (Configuration.DEBUG) + { + log.finer("Underlying stream empty. Returning -1"); + log.exiting(this.getClass().getName(), "read", + Integer.valueOf(-1)); + } + return -1; + } + } + catch (InterruptedIOException x) + { + if (Configuration.DEBUG) + { + log.finer("Reading thread was interrupted. Returning -1"); + log.throwing(this.getClass().getName(), "read", x); + log.exiting(this.getClass().getName(), "read", + Integer.valueOf(-1)); + } + return -1; + } + if (len <= internalBuf.length) + { + result = len; + System.arraycopy(internalBuf, 0, b, off, len); + if (len == internalBuf.length) + internalBuf = null; + else + { + byte[] tmp = new byte[internalBuf.length - len]; + System.arraycopy(internalBuf, len, tmp, 0, tmp.length); + internalBuf = tmp; + } + } + else + { + // first copy the available bytes to b + result = internalBuf.length; + System.arraycopy(internalBuf, 0, b, off, result); + internalBuf = null; + off += result; + len -= result; + int remaining; // count of bytes remaining in buffer after an iteration + int delta; // count of bytes moved to b after an iteration + int datalen; + byte[] data; + while (len > 0) + // we need to read SASL buffers, as long as there are at least + // 4 bytes available at the source + if (source.available() > 3) + { + // process a buffer + data = readSaslBuffer(); + if (data == null) + { + if (Configuration.DEBUG) + log.finer("Underlying stream exhausted. Breaking..."); + break; + } + datalen = data.length; + // copy [part of] the result to b + remaining = (datalen <= len) ? 0 : datalen - len; + delta = datalen - remaining; + System.arraycopy(data, 0, b, off, delta); + if (remaining > 0) + { + internalBuf = new byte[remaining]; + System.arraycopy(data, delta, internalBuf, 0, remaining); + } + // update off, result and len + off += delta; + result += delta; + len -= delta; + } + else + { // nothing much we can do except return what we have + if (Configuration.DEBUG) + log.finer("Not enough bytes in source to read a buffer. Breaking..."); + break; + } + } + if (Configuration.DEBUG) + { + log.finer("Remaining: " + + (internalBuf == null ? 0 : internalBuf.length)); + log.exiting(this.getClass().getName(), "read()", String.valueOf(result)); + } + return result; + } + + /** + * Reads a SASL buffer from the underlying source if at least 4 bytes are + * available. + * + * @return the byte[] of decoded buffer contents, or null if the underlying + * source was exhausted. + * @throws IOException if an I/O exception occurs during the operation. + */ + private byte[] readSaslBuffer() throws IOException + { + if (Configuration.DEBUG) + log.entering(this.getClass().getName(), "readSaslBuffer()"); + int realLength; // check if we read as many bytes as we're supposed to + byte[] result = new byte[4]; + try + { + realLength = source.read(result); + if (realLength == -1) + { + if (Configuration.DEBUG) + log.exiting(this.getClass().getName(), "readSaslBuffer"); + return null; + } + } + catch (IOException x) + { + if (Configuration.DEBUG) + log.throwing(this.getClass().getName(), "readSaslBuffer", x); + throw x; + } + if (realLength != 4) + throw new IOException("Was expecting 4 but found " + realLength); + int bufferLength = result[0] << 24 + | (result[1] & 0xFF) << 16 + | (result[2] & 0xFF) << 8 + | (result[3] & 0xFF); + if (Configuration.DEBUG) + log.finer("SASL buffer size: " + bufferLength); + if (bufferLength > maxRawSendSize || bufferLength < 0) + throw new SaslEncodingException("SASL buffer (security layer) too long"); + + result = new byte[bufferLength]; + try + { + realLength = source.read(result); + } + catch (IOException x) + { + if (Configuration.DEBUG) + log.throwing(this.getClass().getName(), "readSaslBuffer", x); + throw x; + } + if (realLength != bufferLength) + throw new IOException("Was expecting " + bufferLength + " but found " + + realLength); + if (Configuration.DEBUG) + { + log.finer("Incoming buffer (before security) (hex): " + + Util.dumpString(result)); + log.finer("Incoming buffer (before security) (str): \"" + + new String(result) + "\""); + } + if (client != null) + result = client.unwrap(result, 0, realLength); + else + result = server.unwrap(result, 0, realLength); + if (Configuration.DEBUG) + { + log.finer("Incoming buffer (after security) (hex): " + + Util.dumpString(result)); + log.finer("Incoming buffer (after security) (str): \"" + + new String(result) + "\""); + log.exiting(this.getClass().getName(), "readSaslBuffer"); + } + return result; + } +} diff --git a/libjava/classpath/gnu/javax/crypto/sasl/SaslOutputStream.java b/libjava/classpath/gnu/javax/crypto/sasl/SaslOutputStream.java new file mode 100644 index 000000000..0de1ce850 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/sasl/SaslOutputStream.java @@ -0,0 +1,175 @@ +/* SaslOutputStream.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.sasl; + +import gnu.java.security.Configuration; +import gnu.java.security.util.Util; + +import java.io.IOException; +import java.io.OutputStream; +import java.util.logging.Logger; + +import javax.security.sasl.Sasl; +import javax.security.sasl.SaslClient; +import javax.security.sasl.SaslServer; + +/** + * An output stream that uses either a {@link SaslClient} or a {@link SaslServer} + * to process the data through these entities' security layer filter(s). + */ +public class SaslOutputStream + extends OutputStream +{ + private static final Logger log = Logger.getLogger(SaslOutputStream.class.getName()); + private SaslClient client; + private SaslServer server; + private int maxRawSendSize; + private OutputStream dest; + + public SaslOutputStream(SaslClient client, OutputStream dest) + throws IOException + { + super(); + + this.client = client; + String size = (String) client.getNegotiatedProperty(Sasl.RAW_SEND_SIZE); + maxRawSendSize = Integer.parseInt(size); + server = null; + this.dest = dest; + } + + public SaslOutputStream(SaslServer server, OutputStream dest) + throws IOException + { + super(); + + this.server = server; + String size = (String) server.getNegotiatedProperty(Sasl.RAW_SEND_SIZE); + maxRawSendSize = Integer.parseInt(size); + client = null; + this.dest = dest; + } + + public void close() throws IOException + { + dest.flush(); + dest.close(); + } + + public void flush() throws IOException + { + dest.flush(); + } + + /** + * When writing octets to the resulting stream, if a security layer has been + * negotiated, each piece of data written (by a single invocation of + * <code>write()</code>) will be encapsulated as a SASL buffer, as defined in + * RFC 2222, and then written to the underlying <i>dest</i> output stream. + */ + public void write(int b) throws IOException + { + write(new byte[] { (byte) b }); + } + + /** + * When writing octets to the resulting stream, if a security layer has been + * negotiated, each piece of data written (by a single invocation of + * <code>write()</code>) will be encapsulated as a SASL buffer, as defined in + * RFC 2222, and then written to the underlying <i>dest</i> output stream. + */ + public void write(byte[] b, int off, int len) throws IOException + { + if (Configuration.DEBUG) + log.entering(this.getClass().getName(), "write"); + if ((off < 0) || (off > b.length) || (len < 0) || ((off + len) > b.length) + || ((off + len) < 0)) + throw new IndexOutOfBoundsException("off=" + off + ", len=" + len + + ", b.length=" + b.length); + if (len == 0) + { + if (Configuration.DEBUG) + log.exiting(this.getClass().getName(), "write"); + return; + } + int chunckSize, length, chunck = 1; + byte[] output = null, result; + if (Configuration.DEBUG) + log.finer("About to wrap " + len + " byte(s)..."); + while (len > 0) + { + chunckSize = (len > maxRawSendSize ? maxRawSendSize : len); + if (Configuration.DEBUG) + { + log.finer("Outgoing buffer (before security) (hex): " + + Util.dumpString(b, off, chunckSize)); + log.finer("Outgoing buffer (before security) (str): \"" + + new String(b, off, chunckSize) + "\""); + } + if (client != null) + output = client.wrap(b, off, chunckSize); + else + output = server.wrap(b, off, chunckSize); + + if (Configuration.DEBUG) + { + log.finer("Outgoing buffer (after security) (hex): " + + Util.dumpString(output)); + log.finer("Outgoing buffer (after security) (str): \"" + + new String(output) + "\""); + } + length = output.length; + result = new byte[length + 4]; + result[0] = (byte)(length >>> 24); + result[1] = (byte)(length >>> 16); + result[2] = (byte)(length >>> 8); + result[3] = (byte) length; + System.arraycopy(output, 0, result, 4, length); + dest.write(result); + off += chunckSize; + len -= chunckSize; + if (Configuration.DEBUG) + log.finer("Wrapped chunck #" + chunck); + chunck++; + } + dest.flush(); + if (Configuration.DEBUG) + log.exiting(this.getClass().getName(), "write"); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/sasl/SaslUtil.java b/libjava/classpath/gnu/javax/crypto/sasl/SaslUtil.java new file mode 100644 index 000000000..b17d9536e --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/sasl/SaslUtil.java @@ -0,0 +1,75 @@ +/* SaslUtil.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.sasl; + +import gnu.java.security.util.Util; + +import java.security.MessageDigest; + +/** + * Utility methods for SASL-related classes. + */ +public class SaslUtil +{ + private SaslUtil() + { + super(); + } + + public static final boolean validEmailAddress(String address) + { + // need to do better than this + return (address.indexOf("@") != -1); + } + + /** Returns the context of the designated hash as a string. */ + public static final String dump(MessageDigest md) + { + String result; + try + { + result = Util.dumpString(((MessageDigest) md.clone()).digest()); + } + catch (Exception ignored) + { + result = "..."; + } + return result; + } +} diff --git a/libjava/classpath/gnu/javax/crypto/sasl/ServerFactory.java b/libjava/classpath/gnu/javax/crypto/sasl/ServerFactory.java new file mode 100644 index 000000000..6df44c08c --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/sasl/ServerFactory.java @@ -0,0 +1,158 @@ +/* ServerFactory.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.sasl; + +import gnu.java.security.Registry; +import gnu.javax.crypto.sasl.anonymous.AnonymousServer; +import gnu.javax.crypto.sasl.crammd5.CramMD5Server; +import gnu.javax.crypto.sasl.plain.PlainServer; +import gnu.javax.crypto.sasl.srp.SRPServer; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import javax.security.auth.callback.CallbackHandler; +import javax.security.sasl.Sasl; +import javax.security.sasl.SaslException; +import javax.security.sasl.SaslServer; +import javax.security.sasl.SaslServerFactory; + +/** + * The implementation of the {@link SaslServerFactory}. + */ +public class ServerFactory + implements SaslServerFactory +{ + // implicit 0-arguments constructor + + public static final Set getNames() + { + return Collections.unmodifiableSet(new HashSet(Arrays.asList(getNamesInternal(null)))); + } + + private static final String[] getNamesInternal(Map props) + { + String[] all = new String[] { + Registry.SASL_SRP_MECHANISM, + Registry.SASL_CRAM_MD5_MECHANISM, + Registry.SASL_PLAIN_MECHANISM, + Registry.SASL_ANONYMOUS_MECHANISM }; + List result = new ArrayList(4); + int i; + for (i = 0; i < all.length;) + result.add(all[i++]); + if (props == null) + return (String[]) result.toArray(new String[0]); // all + if (hasPolicy(Sasl.POLICY_PASS_CREDENTIALS, props)) // none + return new String[0]; + if (hasPolicy(Sasl.POLICY_NOPLAINTEXT, props)) + result.remove(Registry.SASL_PLAIN_MECHANISM); + if (hasPolicy(Sasl.POLICY_NOACTIVE, props)) + { + result.remove(Registry.SASL_CRAM_MD5_MECHANISM); + result.remove(Registry.SASL_PLAIN_MECHANISM); + } + if (hasPolicy(Sasl.POLICY_NODICTIONARY, props)) + { + result.remove(Registry.SASL_CRAM_MD5_MECHANISM); + result.remove(Registry.SASL_PLAIN_MECHANISM); + } + if (hasPolicy(Sasl.POLICY_NOANONYMOUS, props)) + { + result.remove(Registry.SASL_ANONYMOUS_MECHANISM); + } + if (hasPolicy(Sasl.POLICY_FORWARD_SECRECY, props)) + { + result.remove(Registry.SASL_CRAM_MD5_MECHANISM); + result.remove(Registry.SASL_ANONYMOUS_MECHANISM); + result.remove(Registry.SASL_PLAIN_MECHANISM); + } + return (String[]) result.toArray(new String[0]); + } + + public static final ServerMechanism getInstance(String mechanism) + { + if (mechanism == null) + return null; + mechanism = mechanism.trim().toUpperCase(); + if (mechanism.equals(Registry.SASL_SRP_MECHANISM)) + return new SRPServer(); + if (mechanism.equals(Registry.SASL_CRAM_MD5_MECHANISM)) + return new CramMD5Server(); + if (mechanism.equals(Registry.SASL_PLAIN_MECHANISM)) + return new PlainServer(); + if (mechanism.equals(Registry.SASL_ANONYMOUS_MECHANISM)) + return new AnonymousServer(); + return null; + } + + public SaslServer createSaslServer(String mechanism, String protocol, + String serverName, Map props, + CallbackHandler cbh) throws SaslException + { + ServerMechanism result = getInstance(mechanism); + if (result != null) + { + HashMap attributes = new HashMap(); + if (props != null) + attributes.putAll(props); + attributes.put(Registry.SASL_PROTOCOL, protocol); + attributes.put(Registry.SASL_SERVER_NAME, serverName); + attributes.put(Registry.SASL_CALLBACK_HANDLER, cbh); + result.init(attributes); + } + return result; + } + + public String[] getMechanismNames(Map props) + { + return getNamesInternal(props); + } + + private static boolean hasPolicy(String propertyName, Map props) + { + return "true".equalsIgnoreCase(String.valueOf(props.get(propertyName))); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/sasl/ServerMechanism.java b/libjava/classpath/gnu/javax/crypto/sasl/ServerMechanism.java new file mode 100644 index 000000000..71dfdd4e0 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/sasl/ServerMechanism.java @@ -0,0 +1,294 @@ +/* ServerMechanism.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.sasl; + +import gnu.java.security.Registry; + +import java.util.HashMap; +import java.util.Map; + +import javax.security.auth.callback.CallbackHandler; +import javax.security.sasl.Sasl; +import javax.security.sasl.SaslException; +import javax.security.sasl.SaslServer; + +/** + * A base class to facilitate implementing SASL server-side mechanisms. + */ +public abstract class ServerMechanism + implements SaslServer +{ + /** Name of this mechanism. */ + protected String mechanism; + /** Name of protocol using this mechanism. */ + protected String protocol; + /** Name of server to authenticate to. */ + protected String serverName; + /** Properties of qualities desired for this mechanism. */ + protected Map properties; + /** Callback handler to use with this mechanism instance. */ + protected CallbackHandler handler; + /** Whether authentication phase is completed (true) or not (false). */ + protected boolean complete = false; + /** The authorisation identity. */ + protected String authorizationID; + /** Channel binding data to use with this mechanism instance. */ + protected byte[] channelBinding; + /** The state of the authentication automaton. -1 means uninitialised. */ + protected int state = -1; + /** The provider for authentication information. */ + protected IAuthInfoProvider authenticator; + + protected ServerMechanism(final String mechanism) + { + super(); + + this.mechanism = mechanism; + this.authenticator = AuthInfo.getProvider(mechanism); + this.state = -1; + } + + protected abstract void initMechanism() throws SaslException; + + protected abstract void resetMechanism() throws SaslException; + + public abstract byte[] evaluateResponse(byte[] response) throws SaslException; + + public boolean isComplete() + { + return complete; + } + + public byte[] unwrap(final byte[] incoming, final int offset, final int len) + throws SaslException + { + if (! isComplete()) + throw new IllegalMechanismStateException(); + return this.engineUnwrap(incoming, offset, len); + } + + public byte[] wrap(final byte[] outgoing, final int offset, final int len) + throws SaslException + { + if (! isComplete()) + throw new IllegalMechanismStateException(); + return this.engineWrap(outgoing, offset, len); + } + + public String getMechanismName() + { + return this.mechanism; + } + + public String getAuthorizationID() + { + return this.authorizationID; + } + + public Object getNegotiatedProperty(final String propName) + { + if (! isComplete()) + throw new IllegalStateException(); + if (Sasl.QOP.equals(propName)) + return getNegotiatedQOP(); + if (Sasl.STRENGTH.equals(propName)) + return getNegotiatedStrength(); + if (Sasl.SERVER_AUTH.equals(propName)) + return getNegotiatedServerAuth(); + if (Sasl.MAX_BUFFER.equals(propName)) + return getNegotiatedMaxBuffer(); + if (Sasl.RAW_SEND_SIZE.equals(propName)) + return getNegotiatedRawSendSize(); + if (Sasl.POLICY_NOPLAINTEXT.equals(propName)) + return getNegotiatedPolicyNoPlainText(); + if (Sasl.POLICY_NOACTIVE.equals(propName)) + return getNegotiatedPolicyNoActive(); + if (Sasl.POLICY_NODICTIONARY.equals(propName)) + return getNegotiatedPolicyNoDictionary(); + if (Sasl.POLICY_NOANONYMOUS.equals(propName)) + return getNegotiatedPolicyNoAnonymous(); + if (Sasl.POLICY_FORWARD_SECRECY.equals(propName)) + return getNegotiatedPolicyForwardSecrecy(); + if (Sasl.POLICY_PASS_CREDENTIALS.equals(propName)) + return getNegotiatedPolicyPassCredentials(); + if (Sasl.REUSE.equals(propName)) + return getReuse(); + return null; + } + + public void dispose() throws SaslException + { + reset(); + } + + protected String getNegotiatedQOP() + { + return Registry.QOP_AUTH; + } + + protected String getNegotiatedStrength() + { + return Registry.STRENGTH_LOW; + } + + protected String getNegotiatedServerAuth() + { + return Registry.SERVER_AUTH_FALSE; + } + + protected String getNegotiatedMaxBuffer() + { + return null; + } + + protected String getNegotiatedPolicyNoPlainText() + { + return null; + } + + protected String getNegotiatedPolicyNoActive() + { + return null; + } + + protected String getNegotiatedPolicyNoDictionary() + { + return null; + } + + protected String getNegotiatedPolicyNoAnonymous() + { + return null; + } + + protected String getNegotiatedPolicyForwardSecrecy() + { + return null; + } + + protected String getNegotiatedPolicyPassCredentials() + { + return null; + } + + protected String getNegotiatedRawSendSize() + { + return String.valueOf(Registry.SASL_BUFFER_MAX_LIMIT); + } + + protected String getReuse() + { + return Registry.REUSE_FALSE; + } + + protected byte[] engineUnwrap(final byte[] incoming, final int offset, + final int len) throws SaslException + { + final byte[] result = new byte[len]; + System.arraycopy(incoming, offset, result, 0, len); + return result; + } + + protected byte[] engineWrap(final byte[] outgoing, final int offset, + final int len) throws SaslException + { + final byte[] result = new byte[len]; + System.arraycopy(outgoing, offset, result, 0, len); + return result; + } + + /** + * Initialises the mechanism with designated attributes. Permissible names and + * values are mechanism specific. + * + * @param attributes a set of name-value pairs that describes the desired + * future behaviour of this instance. + * @throws IllegalMechanismStateException if the instance is already + * initialised. + * @throws SaslException if an exception occurs during the process. + */ + public void init(final Map attributes) throws SaslException + { + if (state != -1) + throw new IllegalMechanismStateException("init()"); + if (properties == null) + properties = new HashMap(); + else + properties.clear(); + if (attributes != null) + { + protocol = (String) attributes.get(Registry.SASL_PROTOCOL); + serverName = (String) attributes.get(Registry.SASL_SERVER_NAME); + handler = (CallbackHandler) attributes.get(Registry.SASL_CALLBACK_HANDLER); + channelBinding = (byte[]) attributes.get(Registry.SASL_CHANNEL_BINDING); + properties.putAll(attributes); + } + else + handler = null; + if (protocol == null) + protocol = ""; + if (serverName == null) + serverName = ""; + if (authenticator != null) + authenticator.activate(properties); + if (channelBinding == null) + channelBinding = new byte[0]; + initMechanism(); + complete = false; + state = 0; + } + + /** + * Resets the mechanism instance for re-initialisation and use with other + * characteristics. + * + * @throws SaslException if an exception occurs during the process. + */ + public void reset() throws SaslException + { + resetMechanism(); + properties.clear(); + if (authenticator != null) + authenticator.passivate(); + protocol = serverName = null; + channelBinding = null; + complete = false; + state = -1; + } +} diff --git a/libjava/classpath/gnu/javax/crypto/sasl/UserAlreadyExistsException.java b/libjava/classpath/gnu/javax/crypto/sasl/UserAlreadyExistsException.java new file mode 100644 index 000000000..615fabb57 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/sasl/UserAlreadyExistsException.java @@ -0,0 +1,70 @@ +/* UserAlreadyExistsException.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.sasl; + +import javax.security.sasl.SaslException; + +/** + * A checked exception thrown to indicate that a designated user is already + * known to the the authentication layer. + */ +public class UserAlreadyExistsException + extends SaslException +{ + /** + * Constructs a <code>UserAlreadyExistsException</code> with no detail + * message. + */ + public UserAlreadyExistsException() + { + super(); + } + + /** + * Constructs a <code>UserAlreadyExistsException</code> with the specified + * detail message. In the case of this exception, the detail message + * designates the offending username. + * + * @param userName the detail message, which in this case is the username. + */ + public UserAlreadyExistsException(String userName) + { + super(userName); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/sasl/anonymous/AnonymousClient.java b/libjava/classpath/gnu/javax/crypto/sasl/anonymous/AnonymousClient.java new file mode 100644 index 000000000..860efb4f9 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/sasl/anonymous/AnonymousClient.java @@ -0,0 +1,102 @@ +/* AnonymousClient.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.sasl.anonymous; + +import gnu.java.security.Registry; +import gnu.javax.crypto.sasl.ClientMechanism; +import gnu.javax.crypto.sasl.IllegalMechanismStateException; + +import java.io.UnsupportedEncodingException; + +import javax.security.sasl.AuthenticationException; +import javax.security.sasl.SaslClient; +import javax.security.sasl.SaslException; + +/** + * The ANONYMOUS client-side mechanism. + */ +public class AnonymousClient + extends ClientMechanism + implements SaslClient +{ + public AnonymousClient() + { + super(Registry.SASL_ANONYMOUS_MECHANISM); + } + + protected void initMechanism() throws SaslException + { + } + + protected void resetMechanism() throws SaslException + { + } + + public boolean hasInitialResponse() + { + return true; + } + + public byte[] evaluateChallenge(final byte[] challenge) throws SaslException + { + if (complete) + { + throw new IllegalMechanismStateException("evaluateChallenge()"); + } + return response(); + } + + private byte[] response() throws SaslException + { + if (! AnonymousUtil.isValidTraceInformation(authorizationID)) + throw new AuthenticationException( + "Authorisation ID is not a valid email address"); + complete = true; + final byte[] result; + try + { + result = authorizationID.getBytes("UTF-8"); + } + catch (UnsupportedEncodingException x) + { + throw new AuthenticationException("response()", x); + } + return result; + } +} diff --git a/libjava/classpath/gnu/javax/crypto/sasl/anonymous/AnonymousServer.java b/libjava/classpath/gnu/javax/crypto/sasl/anonymous/AnonymousServer.java new file mode 100644 index 000000000..675194caa --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/sasl/anonymous/AnonymousServer.java @@ -0,0 +1,90 @@ +/* AnonymousServer.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.sasl.anonymous; + +import gnu.java.security.Registry; +import gnu.javax.crypto.sasl.ServerMechanism; + +import java.io.UnsupportedEncodingException; + +import javax.security.sasl.AuthenticationException; +import javax.security.sasl.SaslException; +import javax.security.sasl.SaslServer; + +/** + * The ANONYMOUS server-side mechanism. + */ +public class AnonymousServer + extends ServerMechanism + implements SaslServer +{ + public AnonymousServer() + { + super(Registry.SASL_ANONYMOUS_MECHANISM); + } + + protected void initMechanism() throws SaslException + { + } + + protected void resetMechanism() throws SaslException + { + } + + public byte[] evaluateResponse(final byte[] response) throws SaslException + { + if (response == null) + return null; + try + { + authorizationID = new String(response, "UTF-8"); + } + catch (UnsupportedEncodingException x) + { + throw new AuthenticationException("evaluateResponse()", x); + } + if (AnonymousUtil.isValidTraceInformation(authorizationID)) + { + this.complete = true; + return null; + } + authorizationID = null; + throw new AuthenticationException("Invalid email address"); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/sasl/anonymous/AnonymousUtil.java b/libjava/classpath/gnu/javax/crypto/sasl/anonymous/AnonymousUtil.java new file mode 100644 index 000000000..bb59779d6 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/sasl/anonymous/AnonymousUtil.java @@ -0,0 +1,83 @@ +/* AnonymousUtil.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.sasl.anonymous; + +import gnu.javax.crypto.sasl.SaslUtil; + +/** + * An ANONYMOUS-specific utility class. + */ +public class AnonymousUtil +{ + /** Trivial private constructor to enforce Singleton pattern. */ + private AnonymousUtil() + { + super(); + } + + static boolean isValidTraceInformation(String traceInformation) + { + if (traceInformation == null) + return false; + if (traceInformation.length() == 0) + return true; + if (SaslUtil.validEmailAddress(traceInformation)) + return true; + return isValidToken(traceInformation); + } + + static boolean isValidToken(String token) + { + if (token == null) + return false; + if (token.length() == 0) + return false; + if (token.length() > 255) + return false; + if (token.indexOf('@') != -1) + return false; + for (int i = 0; i < token.length(); i++) + { + char c = token.charAt(i); + if (c < 0x20 || c > 0x7E) + return false; + } + return true; + } +} diff --git a/libjava/classpath/gnu/javax/crypto/sasl/crammd5/CramMD5AuthInfoProvider.java b/libjava/classpath/gnu/javax/crypto/sasl/crammd5/CramMD5AuthInfoProvider.java new file mode 100644 index 000000000..e3d8b8f08 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/sasl/crammd5/CramMD5AuthInfoProvider.java @@ -0,0 +1,166 @@ +/* CramMD5AuthInfoProvider.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.sasl.crammd5; + +import gnu.java.security.Registry; +import gnu.javax.crypto.sasl.IAuthInfoProvider; +import gnu.javax.crypto.sasl.NoSuchUserException; + +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; + +import javax.security.sasl.AuthenticationException; + +/** + * The CRAM-MD5 mechanism authentication information provider implementation. + */ +public class CramMD5AuthInfoProvider + implements IAuthInfoProvider +{ + private PasswordFile passwordFile = null; + + // implicit 0-args constrcutor + + public void activate(Map context) throws AuthenticationException + { + try + { + if (context == null) + passwordFile = new PasswordFile(); + else + { + String pfn = (String) context.get(CramMD5Registry.PASSWORD_FILE); + if (pfn == null) + passwordFile = new PasswordFile(); + else + passwordFile = new PasswordFile(pfn); + } + } + catch (IOException x) + { + throw new AuthenticationException("activate()", x); + } + } + + public void passivate() throws AuthenticationException + { + passwordFile = null; + } + + public boolean contains(String userName) throws AuthenticationException + { + if (passwordFile == null) + throw new AuthenticationException("contains()", + new IllegalStateException()); + boolean result = false; + try + { + result = passwordFile.contains(userName); + } + catch (IOException x) + { + throw new AuthenticationException("contains()", x); + } + return result; + } + + public Map lookup(Map userID) throws AuthenticationException + { + if (passwordFile == null) + throw new AuthenticationException("lookup()", new IllegalStateException()); + Map result = new HashMap(); + try + { + String userName = (String) userID.get(Registry.SASL_USERNAME); + if (userName == null) + throw new NoSuchUserException(""); + String[] data = passwordFile.lookup(userName); + result.put(Registry.SASL_USERNAME, data[0]); + result.put(Registry.SASL_PASSWORD, data[1]); + result.put(CramMD5Registry.UID_FIELD, data[2]); + result.put(CramMD5Registry.GID_FIELD, data[3]); + result.put(CramMD5Registry.GECOS_FIELD, data[4]); + result.put(CramMD5Registry.DIR_FIELD, data[5]); + result.put(CramMD5Registry.SHELL_FIELD, data[6]); + } + catch (Exception x) + { + if (x instanceof AuthenticationException) + throw (AuthenticationException) x; + throw new AuthenticationException("lookup()", x); + } + return result; + } + + public void update(Map userCredentials) throws AuthenticationException + { + if (passwordFile == null) + throw new AuthenticationException("update()", new IllegalStateException()); + try + { + String userName = (String) userCredentials.get(Registry.SASL_USERNAME); + String password = (String) userCredentials.get(Registry.SASL_PASSWORD); + String uid = (String) userCredentials.get(CramMD5Registry.UID_FIELD); + String gid = (String) userCredentials.get(CramMD5Registry.GID_FIELD); + String gecos = (String) userCredentials.get(CramMD5Registry.GECOS_FIELD); + String dir = (String) userCredentials.get(CramMD5Registry.DIR_FIELD); + String shell = (String) userCredentials.get(CramMD5Registry.SHELL_FIELD); + if (uid == null || gid == null || gecos == null || dir == null + || shell == null) + passwordFile.changePasswd(userName, password); + else + { + String[] attributes = new String[] { uid, gid, gecos, dir, shell }; + passwordFile.add(userName, password, attributes); + } + } + catch (Exception x) + { + if (x instanceof AuthenticationException) + throw (AuthenticationException) x; + throw new AuthenticationException("update()", x); + } + } + + public Map getConfiguration(String mode) throws AuthenticationException + { + throw new AuthenticationException("", new UnsupportedOperationException()); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/sasl/crammd5/CramMD5Client.java b/libjava/classpath/gnu/javax/crypto/sasl/crammd5/CramMD5Client.java new file mode 100644 index 000000000..44f694e5c --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/sasl/crammd5/CramMD5Client.java @@ -0,0 +1,168 @@ +/* CramMD5Client.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.sasl.crammd5; + +import gnu.java.security.Registry; +import gnu.java.security.util.Util; +import gnu.javax.crypto.sasl.ClientMechanism; + +import java.io.IOException; +import java.security.InvalidKeyException; + +import javax.security.auth.callback.Callback; +import javax.security.auth.callback.NameCallback; +import javax.security.auth.callback.PasswordCallback; +import javax.security.auth.callback.UnsupportedCallbackException; +import javax.security.sasl.AuthenticationException; +import javax.security.sasl.SaslClient; +import javax.security.sasl.SaslException; + +/** + * The CRAM-MD5 SASL client-side mechanism. + */ +public class CramMD5Client + extends ClientMechanism + implements SaslClient +{ + public CramMD5Client() + { + super(Registry.SASL_CRAM_MD5_MECHANISM); + } + + protected void initMechanism() throws SaslException + { + } + + protected void resetMechanism() throws SaslException + { + } + + public boolean hasInitialResponse() + { + return false; + } + + public byte[] evaluateChallenge(final byte[] challenge) throws SaslException + { + if (challenge == null) + throw new SaslException("null challenge"); + try + { + final String username; + final char[] password; + Callback[] callbacks; + if ((! properties.containsKey(Registry.SASL_USERNAME)) + && (! properties.containsKey(Registry.SASL_PASSWORD))) + { + callbacks = new Callback[2]; + final NameCallback nameCB; + final String defaultName = System.getProperty("user.name"); + if (defaultName == null) + nameCB = new NameCallback("username: "); + else + nameCB = new NameCallback("username: ", defaultName); + final PasswordCallback pwdCB = new PasswordCallback("password: ", + false); + callbacks[0] = nameCB; + callbacks[1] = pwdCB; + this.handler.handle(callbacks); + username = nameCB.getName(); + password = pwdCB.getPassword(); + } + else + { + if (properties.containsKey(Registry.SASL_USERNAME)) + username = (String) properties.get(Registry.SASL_USERNAME); + else + { + callbacks = new Callback[1]; + final NameCallback nameCB; + final String defaultName = System.getProperty("user.name"); + if (defaultName == null) + nameCB = new NameCallback("username: "); + else + nameCB = new NameCallback("username: ", defaultName); + callbacks[0] = nameCB; + this.handler.handle(callbacks); + username = nameCB.getName(); + } + + if (properties.containsKey(Registry.SASL_PASSWORD)) + password = ((String) properties.get(Registry.SASL_PASSWORD)).toCharArray(); + else + { + callbacks = new Callback[1]; + final PasswordCallback pwdCB = new PasswordCallback("password: ", + false); + callbacks[0] = pwdCB; + this.handler.handle(callbacks); + password = pwdCB.getPassword(); + } + } + if (password == null) + throw new SaslException("null password supplied"); + final byte[] digest; + try + { + digest = CramMD5Util.createHMac(password, challenge); + } + catch (InvalidKeyException x) + { + throw new AuthenticationException("evaluateChallenge()", x); + } + final String response = username + " " + + Util.toString(digest).toLowerCase(); + this.complete = true; + return response.getBytes("UTF-8"); + } + catch (UnsupportedCallbackException x) + { + throw new AuthenticationException("evaluateChallenge()", x); + } + catch (IOException x) + { + throw new AuthenticationException("evaluateChallenge()", x); + } + } + + protected String getNegotiatedQOP() + { + return Registry.QOP_AUTH; + } +} diff --git a/libjava/classpath/gnu/javax/crypto/sasl/crammd5/CramMD5Registry.java b/libjava/classpath/gnu/javax/crypto/sasl/crammd5/CramMD5Registry.java new file mode 100644 index 000000000..560eb854e --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/sasl/crammd5/CramMD5Registry.java @@ -0,0 +1,60 @@ +/* CramMD5Registry.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.sasl.crammd5; + +/** + * A list of properties common to CRAM-MD5 classes. + */ +public interface CramMD5Registry +{ + /** Name of the password file (used by the server) property. */ + String PASSWORD_FILE = "gnu.crypto.sasl.crammd5.password.file"; + /** Default password file (used by the server) pathname. */ + String DEFAULT_PASSWORD_FILE = "/etc/passwd"; + /** Name of the UID field in the plain password file. */ + String UID_FIELD = "crammd5.uid"; + /** Name of the GID field in the plain password file. */ + String GID_FIELD = "crammd5.gid"; + /** Name of the GECOS field in the plain password file. */ + String GECOS_FIELD = "crammd5.gecos"; + /** Name of the DIR field in the plain password file. */ + String DIR_FIELD = "crammd5.dir"; + /** Name of the SHELL field in the plain password file. */ + String SHELL_FIELD = "crammd5.shell"; +} diff --git a/libjava/classpath/gnu/javax/crypto/sasl/crammd5/CramMD5Server.java b/libjava/classpath/gnu/javax/crypto/sasl/crammd5/CramMD5Server.java new file mode 100644 index 000000000..1522f6b35 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/sasl/crammd5/CramMD5Server.java @@ -0,0 +1,158 @@ +/* CramMD5Server.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.sasl.crammd5; + +import gnu.java.security.Registry; +import gnu.java.security.util.Util; +import gnu.javax.crypto.sasl.NoSuchUserException; +import gnu.javax.crypto.sasl.ServerMechanism; + +import java.io.IOException; +import java.io.UnsupportedEncodingException; +import java.security.InvalidKeyException; +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; + +import javax.security.sasl.AuthenticationException; +import javax.security.sasl.SaslException; +import javax.security.sasl.SaslServer; + +/** + * The CRAM-MD5 SASL server-side mechanism. + */ +public class CramMD5Server + extends ServerMechanism + implements SaslServer +{ + private byte[] msgID; + + public CramMD5Server() + { + super(Registry.SASL_CRAM_MD5_MECHANISM); + } + + protected void initMechanism() throws SaslException + { + } + + protected void resetMechanism() throws SaslException + { + } + + public byte[] evaluateResponse(final byte[] response) throws SaslException + { + if (state == 0) + { + msgID = CramMD5Util.createMsgID(); + state++; + return msgID; + } + final String responseStr = new String(response); + final int index = responseStr.lastIndexOf(" "); + final String username = responseStr.substring(0, index); + final byte[] responseDigest; + try + { + responseDigest = responseStr.substring(index + 1).getBytes("UTF-8"); + } + catch (UnsupportedEncodingException x) + { + throw new AuthenticationException("evaluateResponse()", x); + } + // Look up the password + final char[] password = lookupPassword(username); + // Compute the digest + byte[] digest; + try + { + digest = CramMD5Util.createHMac(password, msgID); + } + catch (InvalidKeyException x) + { + throw new AuthenticationException("evaluateResponse()", x); + } + try + { + digest = Util.toString(digest).toLowerCase().getBytes("UTF-8"); + } + catch (UnsupportedEncodingException x) + { + throw new AuthenticationException("evaluateResponse()", x); + } + // Compare the received and computed digests + if (! Arrays.equals(digest, responseDigest)) + throw new AuthenticationException("Digest mismatch"); + state++; + return null; + } + + public boolean isComplete() + { + return (state == 2); + } + + protected String getNegotiatedQOP() + { + return Registry.QOP_AUTH; + } + + private char[] lookupPassword(final String userName) throws SaslException + { + try + { + if (! authenticator.contains(userName)) + throw new NoSuchUserException(userName); + final Map userID = new HashMap(); + userID.put(Registry.SASL_USERNAME, userName); + final Map credentials = authenticator.lookup(userID); + final String password = (String) credentials.get(Registry.SASL_PASSWORD); + if (password == null) + throw new AuthenticationException("lookupPassword()", + new InternalError()); + return password.toCharArray(); + } + catch (IOException x) + { + if (x instanceof SaslException) + throw (SaslException) x; + throw new AuthenticationException("lookupPassword()", x); + } + } +} diff --git a/libjava/classpath/gnu/javax/crypto/sasl/crammd5/CramMD5Util.java b/libjava/classpath/gnu/javax/crypto/sasl/crammd5/CramMD5Util.java new file mode 100644 index 000000000..a85c4c721 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/sasl/crammd5/CramMD5Util.java @@ -0,0 +1,122 @@ +/* CramMD5Util.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.sasl.crammd5; + +import gnu.java.lang.CPStringBuilder; + +import gnu.java.security.Registry; +import gnu.java.security.util.Util; +import gnu.javax.crypto.mac.HMacFactory; +import gnu.javax.crypto.mac.IMac; + +import java.io.UnsupportedEncodingException; +import java.net.InetAddress; +import java.net.UnknownHostException; +import java.security.InvalidKeyException; +import java.util.HashMap; + +import javax.security.sasl.SaslException; + +/** + * A package-private CRAM-MD5-specific utility class. + */ +class CramMD5Util +{ + private CramMD5Util() + { + super(); + } + + static byte[] createMsgID() throws SaslException + { + final String encoded; + try + { + encoded = Util.toBase64(Thread.currentThread().getName().getBytes("UTF-8")); + } + catch (UnsupportedEncodingException x) + { + throw new SaslException("createMsgID()", x); + } + String hostname = "localhost"; + try + { + hostname = InetAddress.getLocalHost().getHostAddress(); + } + catch (UnknownHostException ignored) + { + } + final byte[] result; + try + { + result = new CPStringBuilder("<") + .append(encoded.substring(0,encoded.length())) + .append(".").append(String.valueOf(System.currentTimeMillis())) + .append("@").append(hostname).append(">") + .toString() + .getBytes("UTF-8"); + } + catch (UnsupportedEncodingException x) + { + throw new SaslException("createMsgID()", x); + } + return result; + } + + static byte[] createHMac(final char[] passwd, final byte[] data) + throws InvalidKeyException, SaslException + { + final IMac mac = HMacFactory.getInstance(Registry.HMAC_NAME_PREFIX + + Registry.MD5_HASH); + final HashMap map = new HashMap(); + final byte[] km; + try + { + km = new String(passwd).getBytes("UTF-8"); + } + catch (UnsupportedEncodingException x) + { + throw new SaslException("createHMac()", x); + } + map.put(IMac.MAC_KEY_MATERIAL, km); + mac.init(map); + mac.update(data, 0, data.length); + return mac.digest(); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/sasl/crammd5/PasswordFile.java b/libjava/classpath/gnu/javax/crypto/sasl/crammd5/PasswordFile.java new file mode 100644 index 000000000..65da4afdd --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/sasl/crammd5/PasswordFile.java @@ -0,0 +1,240 @@ +/* PasswordFile.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.sasl.crammd5; + +import gnu.java.lang.CPStringBuilder; + +import gnu.javax.crypto.sasl.NoSuchUserException; +import gnu.javax.crypto.sasl.UserAlreadyExistsException; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.IOException; +import java.io.PrintWriter; +import java.util.HashMap; +import java.util.Iterator; +import java.util.NoSuchElementException; +import java.util.StringTokenizer; + +/** + * The CRAM-MD5 password file representation. + */ +public class PasswordFile +{ + private static String DEFAULT_FILE; + static + { + DEFAULT_FILE = System.getProperty(CramMD5Registry.PASSWORD_FILE, + CramMD5Registry.DEFAULT_PASSWORD_FILE); + } + private HashMap entries; + private File passwdFile; + private long lastmod; + + public PasswordFile() throws IOException + { + this(DEFAULT_FILE); + } + + public PasswordFile(final File pwFile) throws IOException + { + this(pwFile.getAbsolutePath()); + } + + public PasswordFile(final String fileName) throws IOException + { + passwdFile = new File(fileName); + update(); + } + + public synchronized void add(final String user, final String passwd, + final String[] attributes) throws IOException + { + checkCurrent(); // check if the entry exists + if (entries.containsKey(user)) + throw new UserAlreadyExistsException(user); + if (attributes.length != 5) + throw new IllegalArgumentException("Wrong number of attributes"); + final String[] fields = new String[7]; // create the new entry + fields[0] = user; + fields[1] = passwd; + System.arraycopy(attributes, 0, fields, 2, 5); + entries.put(user, fields); + savePasswd(); + } + + public synchronized void changePasswd(final String user, final String passwd) + throws IOException + { + checkCurrent(); + if (! entries.containsKey(user)) + throw new NoSuchUserException(user); + final String[] fields = (String[]) entries.get(user); // get existing entry + fields[1] = passwd; // modify the password field + entries.remove(user); // delete the existing entry + entries.put(user, fields); // add the new entry + savePasswd(); + } + + public synchronized String[] lookup(final String user) throws IOException + { + checkCurrent(); + if (! entries.containsKey(user)) + throw new NoSuchUserException(user); + return (String[]) entries.get(user); + } + + public synchronized boolean contains(final String s) throws IOException + { + checkCurrent(); + return entries.containsKey(s); + } + + private synchronized void update() throws IOException + { + lastmod = passwdFile.lastModified(); + readPasswd(new FileInputStream(passwdFile)); + } + + private void checkCurrent() throws IOException + { + if (passwdFile.lastModified() > lastmod) + update(); + } + + private synchronized void readPasswd(final InputStream in) throws IOException + { + final BufferedReader din = new BufferedReader(new InputStreamReader(in)); + String line; + entries = new HashMap(); + while ((line = din.readLine()) != null) + { + final String[] fields = new String[7]; + final StringTokenizer st = new StringTokenizer(line, ":", true); + try + { + fields[0] = st.nextToken(); // username + st.nextToken(); + fields[1] = st.nextToken(); // passwd + if (fields[1].equals(":")) + fields[1] = ""; + else + st.nextToken(); + fields[2] = st.nextToken(); // uid + if (fields[2].equals(":")) + fields[2] = ""; + else + st.nextToken(); + fields[3] = st.nextToken(); // gid + if (fields[3].equals(":")) + fields[3] = ""; + else + st.nextToken(); + fields[4] = st.nextToken(); // gecos + if (fields[4].equals(":")) + fields[4] = ""; + else + st.nextToken(); + fields[5] = st.nextToken(); // dir + if (fields[5].equals(":")) + fields[5] = ""; + else + st.nextToken(); + fields[6] = st.nextToken(); // shell + if (fields[6].equals(":")) + fields[6] = ""; + } + catch (NoSuchElementException x) + { + continue; + } + entries.put(fields[0], fields); + } + } + + private synchronized void savePasswd() throws IOException + { + if (passwdFile != null) + { + final FileOutputStream fos = new FileOutputStream(passwdFile); + PrintWriter pw = null; + try + { + pw = new PrintWriter(fos); + String key; + String[] fields; + CPStringBuilder sb; + int i; + for (Iterator it = entries.keySet().iterator(); it.hasNext();) + { + key = (String) it.next(); + fields = (String[]) entries.get(key); + sb = new CPStringBuilder(fields[0]); + for (i = 1; i < fields.length; i++) + sb.append(":").append(fields[i]); + pw.println(sb.toString()); + } + } + finally + { + if (pw != null) + try + { + pw.flush(); + } + finally + { + pw.close(); + } + try + { + fos.close(); + } + catch (IOException ignored) + { + } + lastmod = passwdFile.lastModified(); + } + } + } +} diff --git a/libjava/classpath/gnu/javax/crypto/sasl/plain/PasswordFile.java b/libjava/classpath/gnu/javax/crypto/sasl/plain/PasswordFile.java new file mode 100644 index 000000000..51542d2b2 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/sasl/plain/PasswordFile.java @@ -0,0 +1,245 @@ +/* PasswordFile.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.sasl.plain; + +import gnu.java.lang.CPStringBuilder; + +import gnu.java.security.action.GetPropertyAction; +import gnu.javax.crypto.sasl.NoSuchUserException; +import gnu.javax.crypto.sasl.UserAlreadyExistsException; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.PrintWriter; +import java.security.AccessController; +import java.util.Enumeration; +import java.util.Hashtable; +import java.util.NoSuchElementException; +import java.util.StringTokenizer; + +/** + * A representation of a Plain password file. + */ +public class PasswordFile +{ + private static String DEFAULT_FILE; + static + { + DEFAULT_FILE = (String) AccessController.doPrivileged + (new GetPropertyAction(PlainRegistry.PASSWORD_FILE, + PlainRegistry.DEFAULT_PASSWORD_FILE)); + } + private Hashtable entries; + private File passwdFile; + private long lastmod; + + public PasswordFile() throws IOException + { + this(DEFAULT_FILE); + } + + public PasswordFile(File pwFile) throws IOException + { + this(pwFile.getAbsolutePath()); + } + + public PasswordFile(String fileName) throws IOException + { + passwdFile = new File(fileName); + update(); + } + + public synchronized void add(String user, String passwd, String[] attributes) + throws IOException + { + checkCurrent(); + if (entries.containsKey(user)) + throw new UserAlreadyExistsException(user); + if (attributes.length != 5) + throw new IllegalArgumentException("Wrong number of attributes"); + // create the new entry + String[] fields = new String[7]; + fields[0] = user; + fields[1] = passwd; + System.arraycopy(attributes, 0, fields, 2, 5); + entries.put(user, fields); + savePasswd(); + } + + public synchronized void changePasswd(String user, String passwd) + throws IOException + { + checkCurrent(); + if (! entries.containsKey(user)) + throw new NoSuchUserException(user); + String[] fields = (String[]) entries.get(user); // get the existing entry + fields[1] = passwd; // modify the password field + entries.remove(user); // delete the existing entry + entries.put(user, fields); // add the new entry + savePasswd(); + } + + public synchronized String[] lookup(String user) throws IOException + { + checkCurrent(); + if (! entries.containsKey(user)) + throw new NoSuchUserException(user); + return (String[]) entries.get(user); + } + + public synchronized boolean contains(String s) throws IOException + { + checkCurrent(); + return entries.containsKey(s); + } + + private synchronized void update() throws IOException + { + lastmod = passwdFile.lastModified(); + readPasswd(new FileInputStream(passwdFile)); + } + + private void checkCurrent() throws IOException + { + if (passwdFile.lastModified() > lastmod) + update(); + } + + private synchronized void readPasswd(InputStream in) throws IOException + { + BufferedReader din = new BufferedReader(new InputStreamReader(in)); + String line; + entries = new Hashtable(); + String[] fields = new String[7]; + while ((line = din.readLine()) != null) + { + StringTokenizer st = new StringTokenizer(line, ":", true); + try + { + fields[0] = st.nextToken(); // username + st.nextToken(); + fields[1] = st.nextToken(); // passwd + if (fields[1].equals(":")) + fields[1] = ""; + else + st.nextToken(); + fields[2] = st.nextToken(); // uid + if (fields[2].equals(":")) + fields[2] = ""; + else + st.nextToken(); + fields[3] = st.nextToken(); // gid + if (fields[3].equals(":")) + fields[3] = ""; + else + st.nextToken(); + fields[4] = st.nextToken(); // gecos + if (fields[4].equals(":")) + fields[4] = ""; + else + st.nextToken(); + fields[5] = st.nextToken(); // dir + if (fields[5].equals(":")) + fields[5] = ""; + else + st.nextToken(); + fields[6] = st.nextToken(); // shell + if (fields[6].equals(":")) + fields[6] = ""; + } + catch (NoSuchElementException ignored) + { + continue; + } + entries.put(fields[0], fields); + } + } + + private synchronized void savePasswd() throws IOException + { + if (passwdFile != null) + { + FileOutputStream fos = new FileOutputStream(passwdFile); + PrintWriter pw = null; + try + { + pw = new PrintWriter(fos); + String key; + String[] fields; + CPStringBuilder sb; + Enumeration keys = entries.keys(); + while (keys.hasMoreElements()) + { + key = (String) keys.nextElement(); + fields = (String[]) entries.get(key); + sb = new CPStringBuilder(fields[0]); + for (int i = 1; i < fields.length; i++) + sb.append(":" + fields[i]); + pw.println(sb.toString()); + } + } + finally + { + if (pw != null) + try + { + pw.flush(); + } + finally + { + pw.close(); + } + if (fos != null) + try + { + fos.close(); + } + catch (IOException ignored) + { + } + lastmod = passwdFile.lastModified(); + } + } + } +} diff --git a/libjava/classpath/gnu/javax/crypto/sasl/plain/PlainAuthInfoProvider.java b/libjava/classpath/gnu/javax/crypto/sasl/plain/PlainAuthInfoProvider.java new file mode 100644 index 000000000..5f35c455b --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/sasl/plain/PlainAuthInfoProvider.java @@ -0,0 +1,166 @@ +/* PlainAuthInfoProvider.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.sasl.plain; + +import gnu.java.security.Registry; +import gnu.javax.crypto.sasl.IAuthInfoProvider; +import gnu.javax.crypto.sasl.NoSuchUserException; + +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; + +import javax.security.sasl.AuthenticationException; + +/** + * The PLAIN mechanism authentication information provider implementation. + */ +public class PlainAuthInfoProvider + implements IAuthInfoProvider, PlainRegistry +{ + private PasswordFile passwordFile = null; + + // implicit 0-args constrcutor + + public void activate(Map context) throws AuthenticationException + { + try + { + if (context == null) + passwordFile = new PasswordFile(); + else + { + String pfn = (String) context.get(PASSWORD_FILE); + if (pfn == null) + passwordFile = new PasswordFile(); + else + passwordFile = new PasswordFile(pfn); + } + } + catch (IOException x) + { + throw new AuthenticationException("activate()", x); + } + } + + public void passivate() throws AuthenticationException + { + passwordFile = null; + } + + public boolean contains(String userName) throws AuthenticationException + { + if (passwordFile == null) + throw new AuthenticationException("contains()", + new IllegalStateException()); + boolean result = false; + try + { + result = passwordFile.contains(userName); + } + catch (IOException x) + { + throw new AuthenticationException("contains()", x); + } + return result; + } + + public Map lookup(Map userID) throws AuthenticationException + { + if (passwordFile == null) + throw new AuthenticationException("lookup()", new IllegalStateException()); + Map result = new HashMap(); + try + { + String userName = (String) userID.get(Registry.SASL_USERNAME); + if (userName == null) + throw new NoSuchUserException(""); + String[] data = passwordFile.lookup(userName); + result.put(Registry.SASL_USERNAME, data[0]); + result.put(Registry.SASL_PASSWORD, data[1]); + result.put(UID_FIELD, data[2]); + result.put(GID_FIELD, data[3]); + result.put(GECOS_FIELD, data[4]); + result.put(DIR_FIELD, data[5]); + result.put(SHELL_FIELD, data[6]); + } + catch (Exception x) + { + if (x instanceof AuthenticationException) + throw (AuthenticationException) x; + throw new AuthenticationException("lookup()", x); + } + return result; + } + + public void update(Map userCredentials) throws AuthenticationException + { + if (passwordFile == null) + throw new AuthenticationException("update()", new IllegalStateException()); + try + { + String userName = (String) userCredentials.get(Registry.SASL_USERNAME); + String password = (String) userCredentials.get(Registry.SASL_PASSWORD); + String uid = (String) userCredentials.get(UID_FIELD); + String gid = (String) userCredentials.get(GID_FIELD); + String gecos = (String) userCredentials.get(GECOS_FIELD); + String dir = (String) userCredentials.get(DIR_FIELD); + String shell = (String) userCredentials.get(SHELL_FIELD); + if (uid == null || gid == null || gecos == null || dir == null + || shell == null) + passwordFile.changePasswd(userName, password); + else + { + String[] attributes = new String[] { uid, gid, gecos, dir, shell }; + passwordFile.add(userName, password, attributes); + } + } + catch (Exception x) + { + if (x instanceof AuthenticationException) + throw (AuthenticationException) x; + throw new AuthenticationException("update()", x); + } + } + + public Map getConfiguration(String mode) throws AuthenticationException + { + throw new AuthenticationException("", new UnsupportedOperationException()); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/sasl/plain/PlainClient.java b/libjava/classpath/gnu/javax/crypto/sasl/plain/PlainClient.java new file mode 100644 index 000000000..f984ed13f --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/sasl/plain/PlainClient.java @@ -0,0 +1,156 @@ +/* PlainClient.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.sasl.plain; + +import gnu.java.lang.CPStringBuilder; + +import gnu.java.security.Registry; +import gnu.javax.crypto.sasl.ClientMechanism; + +import javax.security.sasl.SaslClient; +import javax.security.sasl.SaslException; +import javax.security.auth.callback.Callback; +import javax.security.auth.callback.NameCallback; +import javax.security.auth.callback.PasswordCallback; + +/** + * The PLAIN SASL client-side mechanism. + */ +public class PlainClient + extends ClientMechanism + implements SaslClient +{ + public PlainClient() + { + super(Registry.SASL_PLAIN_MECHANISM); + } + + protected void initMechanism() throws SaslException + { + } + + protected void resetMechanism() throws SaslException + { + } + + public boolean hasInitialResponse() + { + return true; + } + + public byte[] evaluateChallenge(final byte[] challenge) throws SaslException + { + try + { + final String username; + final char[] password; + Callback[] callbacks; + if ((! properties.containsKey(Registry.SASL_USERNAME)) + && (! properties.containsKey(Registry.SASL_PASSWORD))) + { + callbacks = new Callback[2]; + final NameCallback nameCB; + final String defaultName = System.getProperty("user.name"); + if (defaultName == null) + nameCB = new NameCallback("username: "); + else + nameCB = new NameCallback("username: ", defaultName); + final PasswordCallback pwdCB = new PasswordCallback("password: ", + false); + callbacks[0] = nameCB; + callbacks[1] = pwdCB; + this.handler.handle(callbacks); + username = nameCB.getName(); + password = pwdCB.getPassword(); + } + else + { + if (properties.containsKey(Registry.SASL_USERNAME)) + username = (String) properties.get(Registry.SASL_USERNAME); + else + { + callbacks = new Callback[1]; + final NameCallback nameCB; + final String defaultName = System.getProperty("user.name"); + if (defaultName == null) + nameCB = new NameCallback("username: "); + else + nameCB = new NameCallback("username: ", defaultName); + callbacks[0] = nameCB; + this.handler.handle(callbacks); + username = nameCB.getName(); + } + if (properties.containsKey(Registry.SASL_PASSWORD)) + password = ((String) properties.get(Registry.SASL_PASSWORD)).toCharArray(); + else + { + callbacks = new Callback[1]; + final PasswordCallback pwdCB = new PasswordCallback("password: ", + false); + callbacks[0] = pwdCB; + this.handler.handle(callbacks); + password = pwdCB.getPassword(); + } + } + if (password == null) + throw new SaslException("null password supplied"); + final CPStringBuilder sb = new CPStringBuilder(); + if (authorizationID != null) + sb.append(authorizationID); + sb.append('\0'); + sb.append(username); + sb.append('\0'); + sb.append(password); + this.complete = true; + final byte[] response = sb.toString().getBytes("UTF-8"); + return response; + } + catch (Exception x) + { + if (x instanceof SaslException) + throw (SaslException) x; + throw new SaslException("evaluateChallenge()", x); + } + } + + protected String getNegotiatedQOP() + { + return Registry.QOP_AUTH; + } +} diff --git a/libjava/classpath/gnu/javax/crypto/sasl/plain/PlainRegistry.java b/libjava/classpath/gnu/javax/crypto/sasl/plain/PlainRegistry.java new file mode 100644 index 000000000..68b121d96 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/sasl/plain/PlainRegistry.java @@ -0,0 +1,57 @@ +/* PlainRegistry.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.sasl.plain; + +public interface PlainRegistry +{ + /** Name of PLAIN password file property. */ + String PASSWORD_FILE = "gnu.crypto.sasl.plain.password.file"; + /** Default fully qualified pathname of the PLAIN password file. */ + String DEFAULT_PASSWORD_FILE = "/etc/tpasswd"; + /** Name of the UID field in the plain password file. */ + String UID_FIELD = "plain.uid"; + /** Name of the GID field in the plain password file. */ + String GID_FIELD = "plain.gid"; + /** Name of the GECOS field in the plain password file. */ + String GECOS_FIELD = "plain.gecos"; + /** Name of the DIR field in the plain password file. */ + String DIR_FIELD = "plain.dir"; + /** Name of the SHELL field in the plain password file. */ + String SHELL_FIELD = "plain.shell"; +} diff --git a/libjava/classpath/gnu/javax/crypto/sasl/plain/PlainServer.java b/libjava/classpath/gnu/javax/crypto/sasl/plain/PlainServer.java new file mode 100644 index 000000000..9d97bc029 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/sasl/plain/PlainServer.java @@ -0,0 +1,155 @@ +/* PlainServer.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.sasl.plain; + +import gnu.java.security.Registry; +import gnu.javax.crypto.sasl.NoSuchUserException; +import gnu.javax.crypto.sasl.ServerMechanism; + +import java.io.IOException; +import java.io.UnsupportedEncodingException; +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; +import java.util.NoSuchElementException; +import java.util.StringTokenizer; + +import javax.security.sasl.SaslException; +import javax.security.sasl.SaslServer; + +/** + * The PLAIN SASL server-side mechanism. + */ +public class PlainServer + extends ServerMechanism + implements SaslServer +{ + public PlainServer() + { + super(Registry.SASL_PLAIN_MECHANISM); + } + + protected void initMechanism() throws SaslException + { + } + + protected void resetMechanism() throws SaslException + { + } + + public byte[] evaluateResponse(final byte[] response) throws SaslException + { + if (response == null) + return null; + try + { + final String nullStr = new String("\0"); + final StringTokenizer strtok = new StringTokenizer(new String(response), + nullStr, true); + authorizationID = strtok.nextToken(); + if (! authorizationID.equals(nullStr)) + strtok.nextToken(); + else + authorizationID = null; + final String id = strtok.nextToken(); + if (id.equals(nullStr)) + throw new SaslException("No identity given"); + if (authorizationID == null) + authorizationID = id; + if ((! authorizationID.equals(nullStr)) && (! authorizationID.equals(id))) + throw new SaslException("Delegation not supported"); + strtok.nextToken(); + final byte[] pwd; + try + { + pwd = strtok.nextToken().getBytes("UTF-8"); + } + catch (UnsupportedEncodingException x) + { + throw new SaslException("evaluateResponse()", x); + } + if (pwd == null) + throw new SaslException("No password given"); + final byte[] password; + try + { + password = new String(lookupPassword(id)).getBytes("UTF-8"); + } + catch (UnsupportedEncodingException x) + { + throw new SaslException("evaluateResponse()", x); + } + if (! Arrays.equals(pwd, password)) + throw new SaslException("Password incorrect"); + this.complete = true; + return null; + } + catch (NoSuchElementException x) + { + throw new SaslException("evaluateResponse()", x); + } + } + + protected String getNegotiatedQOP() + { + return Registry.QOP_AUTH; + } + + private char[] lookupPassword(final String userName) throws SaslException + { + try + { + if (! authenticator.contains(userName)) + throw new NoSuchUserException(userName); + final Map userID = new HashMap(); + userID.put(Registry.SASL_USERNAME, userName); + final Map credentials = authenticator.lookup(userID); + final String password = (String) credentials.get(Registry.SASL_PASSWORD); + if (password == null) + throw new SaslException("lookupPassword()", new InternalError()); + return password.toCharArray(); + } + catch (IOException x) + { + if (x instanceof SaslException) + throw (SaslException) x; + throw new SaslException("lookupPassword()", x); + } + } +} diff --git a/libjava/classpath/gnu/javax/crypto/sasl/srp/CALG.java b/libjava/classpath/gnu/javax/crypto/sasl/srp/CALG.java new file mode 100644 index 000000000..22f9c9751 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/sasl/srp/CALG.java @@ -0,0 +1,221 @@ +/* CALG.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.sasl.srp; + +import gnu.java.security.Registry; +import gnu.javax.crypto.assembly.Assembly; +import gnu.javax.crypto.assembly.Cascade; +import gnu.javax.crypto.assembly.Direction; +import gnu.javax.crypto.assembly.Stage; +import gnu.javax.crypto.assembly.Transformer; +import gnu.javax.crypto.assembly.TransformerException; +import gnu.javax.crypto.cipher.CipherFactory; +import gnu.javax.crypto.cipher.IBlockCipher; +import gnu.javax.crypto.mode.IMode; +import gnu.javax.crypto.mode.ModeFactory; +import gnu.javax.crypto.pad.IPad; +import gnu.javax.crypto.pad.PadFactory; +import gnu.javax.crypto.sasl.ConfidentialityException; + +import java.util.HashMap; + +import javax.security.sasl.SaslException; + +/** + * A Factory class that returns CALG (Confidentiality Algorithm) instances that + * operate as described in the draft-burdis-cat-sasl-srp-08. + * <p> + * The designated CALG block cipher should be used in OFB (Output Feedback + * Block) mode in the ISO variant, as described in <i>The Handbook of Applied + * Cryptography</i>, algorithm 7.20. + * <p> + * Let <code>k</code> be the block size of the chosen symmetric key block + * cipher algorithm; e.g. for AES this is <code>128</code> bits or + * <code>16</code> octets. The OFB mode used shall be of length/size + * <code>k</code>. + * <p> + * It is recommended that block ciphers operating in OFB mode be used with an + * Initial Vector (the mode's IV). In such a mode of operation - OFB with key + * re-use - the IV need not be secret. For the mechanism in question the IVs + * shall be a random octet sequence of <code>k</code> bytes. + * <p> + * The input data to the confidentiality protection algorithm shall be a + * multiple of the symmetric cipher block size <code>k</code>. When the input + * length is not a multiple of <code>k</code> octets, the data shall be padded + * according to the following scheme: + * <p> + * Assuming the length of the input is <code>l</code> octets, + * <code>(k - (l mod k))</code> octets, all having the value + * <code>(k - (l mod k))</code>, shall be appended to the original data. In + * other words, the input is padded at the trailing end with one of the + * following sequences: + * <pre> + * + * 01 -- if l mod k = k-1 + * 02 02 -- if l mod k = k-2 + * ... + * ... + * ... + * k k ... k k -- if l mod k = 0 + * </pre> + * <p> + * The padding can be removed unambiguously since all input is padded and no + * padding sequence is a suffix of another. This padding method is well-defined + * if and only if <code>k < 256</code> octets, which is the case with + * symmetric key block ciphers today, and in the forseeable future. + */ +public final class CALG +{ + private Assembly assembly; + private Object modeNdx; // initialisation key of the cascade's attributes + private int blockSize; // the underlying cipher's blocksize == IV length + private int keySize; // the underlying cipher's key size (in bytes). + + /** Private constructor to enforce instantiation through Factory method. */ + private CALG(final int blockSize, final int keySize, final Object modeNdx, + final Assembly assembly) + { + super(); + + this.blockSize = blockSize; + this.keySize = keySize; + this.modeNdx = modeNdx; + this.assembly = assembly; + } + + /** + * Returns an instance of a SASL-SRP CALG implementation. + * + * @param algorithm the name of the symmetric cipher algorithm. + * @return an instance of this object. + */ + static synchronized CALG getInstance(final String algorithm) + { + final IBlockCipher cipher = CipherFactory.getInstance(algorithm); + final int blockSize = cipher.defaultBlockSize(); + final int keySize = cipher.defaultKeySize(); + final Cascade ofbCipher = new Cascade(); + IMode ofbMode = ModeFactory.getInstance(Registry.OFB_MODE, + cipher, + blockSize); + Stage modeStage = Stage.getInstance(ofbMode, Direction.FORWARD); + final Object modeNdx = ofbCipher.append(modeStage); + final IPad pkcs7 = PadFactory.getInstance(Registry.PKCS7_PAD); + final Assembly asm = new Assembly(); + asm.addPreTransformer(Transformer.getCascadeTransformer(ofbCipher)); + asm.addPreTransformer(Transformer.getPaddingTransformer(pkcs7)); + return new CALG(blockSize, keySize, modeNdx, asm); + } + + /** + * Initialises a SASL-SRP CALG implementation. + * + * @param kdf the key derivation function. + * @param iv the initial vector value to use. + * @param dir whether this CALG is used for encryption or decryption. + */ + public void init(final KDF kdf, final byte[] iv, final Direction dir) + throws SaslException + { + final byte[] realIV; + if (iv.length == blockSize) + realIV = iv; + else + { + realIV = new byte[blockSize]; + if (iv.length > blockSize) + System.arraycopy(iv, 0, realIV, 0, blockSize); + else // shouldnt happen + System.arraycopy(iv, 0, realIV, 0, iv.length); + } + final HashMap modeAttributes = new HashMap(); + final byte[] sk = kdf.derive(keySize); + modeAttributes.put(IBlockCipher.KEY_MATERIAL, sk); + modeAttributes.put(IMode.IV, realIV); + final HashMap attributes = new HashMap(); + attributes.put(Assembly.DIRECTION, dir); + attributes.put(modeNdx, modeAttributes); + try + { + assembly.init(attributes); + } + catch (TransformerException x) + { + throw new SaslException("getInstance()", x); + } + } + + /** + * Encrypts or decrypts, depending on the mode already set, a designated array + * of bytes and returns the result. + * + * @param data the data to encrypt/decrypt. + * @return the decrypted/encrypted result. + * @throws ConfidentialityException if an exception occurs duirng the process. + */ + public byte[] doFinal(final byte[] data) throws ConfidentialityException + { + return doFinal(data, 0, data.length); + } + + /** + * Encrypts or decrypts, depending on the mode already set, a designated array + * of bytes and returns the result. + * + * @param data the data to encrypt/decrypt. + * @param offset where to start in <code>data</code>. + * @param length how many bytes to consider in <code>data</code>. + * @return the decrypted/encrypted result. + * @throws ConfidentialityException if an exception occurs duirng the process. + */ + public byte[] doFinal(final byte[] data, final int offset, final int length) + throws ConfidentialityException + { + final byte[] result; + try + { + result = assembly.lastUpdate(data, offset, length); + } + catch (TransformerException x) + { + throw new ConfidentialityException("doFinal()", x); + } + return result; + } +} diff --git a/libjava/classpath/gnu/javax/crypto/sasl/srp/ClientStore.java b/libjava/classpath/gnu/javax/crypto/sasl/srp/ClientStore.java new file mode 100644 index 000000000..1d27137d1 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/sasl/srp/ClientStore.java @@ -0,0 +1,155 @@ +/* ClientStore.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.sasl.srp; + +import java.util.HashMap; + +/** + * The client-side implementation of the SRP security context store. + */ +public class ClientStore +{ + /** The underlying singleton. */ + private static ClientStore singleton = null; + /** The map of uid --> SASL Security Context record. */ + private static final HashMap uid2ssc = new HashMap(); + /** The map of sid --> Session timing record. */ + private static final HashMap uid2ttl = new HashMap(); + /** A synchronisation lock. */ + private static final Object lock = new Object(); + + /** Private constructor to enforce Singleton pattern. */ + private ClientStore() + { + super(); + + // TODO: add a cleaning timer thread + } + + /** + * Returns the classloader Singleton. + * + * @return the classloader Singleton instance. + */ + static synchronized final ClientStore instance() + { + if (singleton == null) + singleton = new ClientStore(); + return singleton; + } + + /** + * Returns a boolean flag indicating if the designated client's session is + * still alive or not. + * + * @param uid the identifier of the client whose session to check. + * @return <code>true</code> if the designated client's session is still + * alive. <code>false</code> otherwise. + */ + boolean isAlive(final String uid) + { + final boolean result; + synchronized (lock) + { + final Object obj = uid2ssc.get(uid); + result = (obj != null); + if (result) // is it still alive? + { + final StoreEntry sto = (StoreEntry) uid2ttl.get(uid); + if (! sto.isAlive()) // invalidate it + { + uid2ssc.remove(uid); + uid2ttl.remove(uid); + } + } + } + return result; + } + + /** + * Records a mapping between a client's unique identifier and its security + * context. + * + * @param uid the unique identifier of the SRP client for which the session is + * to be cached. + * @param ttl the session's Time-To-Live indicator (in seconds). + * @param ctx the client's security context. + */ + void cacheSession(final String uid, final int ttl, final SecurityContext ctx) + { + synchronized (lock) + { + uid2ssc.put(uid, ctx); + uid2ttl.put(uid, new StoreEntry(ttl)); + } + } + + /** + * Removes the mapping between the designated SRP client unique identifier and + * the its session security context (and other timing information). + * + * @param uid the identifier of the client whose session is to invalidate. + */ + void invalidateSession(final String uid) + { + synchronized (lock) + { + uid2ssc.remove(uid); + uid2ttl.remove(uid); + } + } + + /** + * Returns an SRP client's security context record mapped by that client's + * unique identifier. + * + * @param uid the identifier of the client whose session is to restore. + * @return the SRP client's security context. + */ + SecurityContext restoreSession(final String uid) + { + final SecurityContext result; + synchronized (lock) + { + result = (SecurityContext) uid2ssc.remove(uid); + uid2ttl.remove(uid); + } + return result; + } +} diff --git a/libjava/classpath/gnu/javax/crypto/sasl/srp/IALG.java b/libjava/classpath/gnu/javax/crypto/sasl/srp/IALG.java new file mode 100644 index 000000000..d0c92ea68 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/sasl/srp/IALG.java @@ -0,0 +1,128 @@ +/* IALG.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.sasl.srp; + +import gnu.javax.crypto.mac.IMac; +import gnu.javax.crypto.mac.MacFactory; + +import java.security.InvalidKeyException; +import java.security.NoSuchAlgorithmException; +import java.util.HashMap; + +import javax.security.sasl.SaslException; + +/** + * A Factory class that returns IALG (Integrity Algorithm) instances that + * operate as described in the draft-burdis-cat-sasl-srp-04 and later. + */ +public final class IALG + implements Cloneable +{ + private IMac hmac; + + /** Private constructor to enforce instantiation through Factory method. */ + private IALG(final IMac hmac) + { + super(); + + this.hmac = hmac; + } + + /** + * Returns an instance of a SASL-SRP IALG implementation. + * + * @param algorithm the name of the HMAC algorithm. + * @return an instance of this object. + */ + static synchronized IALG getInstance(final String algorithm) + throws SaslException + { + final IMac hmac; + hmac = MacFactory.getInstance(algorithm); + if (hmac == null) + throw new SaslException("getInstance()", + new NoSuchAlgorithmException(algorithm)); + return new IALG(hmac); + } + + public Object clone() throws CloneNotSupportedException + { + return new IALG((IMac) hmac.clone()); + } + + public void init(final KDF kdf) throws SaslException + { + try + { + final byte[] sk = kdf.derive(hmac.macSize()); + final HashMap map = new HashMap(); + map.put(IMac.MAC_KEY_MATERIAL, sk); + hmac.init(map); + } + catch (InvalidKeyException x) + { + throw new SaslException("getInstance()", x); + } + } + + public void update(final byte[] data) + { + hmac.update(data, 0, data.length); + } + + public void update(final byte[] data, final int offset, final int length) + { + hmac.update(data, offset, length); + } + + public byte[] doFinal() + { + return hmac.digest(); + } + + /** + * Returns the length (in bytes) of this SASL SRP Integrity Algorithm. + * + * @return the length, in bytes, of this integrity protection algorithm. + */ + public int length() + { + return hmac.macSize(); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/sasl/srp/KDF.java b/libjava/classpath/gnu/javax/crypto/sasl/srp/KDF.java new file mode 100644 index 000000000..513aafb94 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/sasl/srp/KDF.java @@ -0,0 +1,140 @@ +/* KDF.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.sasl.srp; + +import gnu.java.security.Registry; +import gnu.java.security.prng.LimitReachedException; +import gnu.java.security.util.PRNG; +import gnu.javax.crypto.cipher.IBlockCipher; +import gnu.javax.crypto.prng.UMacGenerator; + +import java.util.HashMap; + +/** + * The SASL-SRP KDF implementation, which is also used, depending on how it was + * instantiated, as a secure Pseudo Random Number Generator. + */ +public class KDF +{ + private static final int AES_BLOCK_SIZE = 16; // default block size for AES + private static final int AES_KEY_SIZE = 16; // default key size for the AES + private static final byte[] buffer = new byte[1]; + /** Our default source of randomness. */ + private static final PRNG prng = PRNG.getInstance(); + /** The underlying UMAC Generator instance. */ + private UMacGenerator umac = null; + + /** + * Constructs an instance of the <code>KDF</code> initialised with the + * designated shared secret bytes. + * + * @param keyMaterial the SASL SRP shared secret (K) bytes. + */ + private KDF(final byte[] keyMaterial, final int ndx) + { + super(); + + final HashMap map = new HashMap(); + map.put(UMacGenerator.CIPHER, Registry.AES_CIPHER); + map.put(UMacGenerator.INDEX, Integer.valueOf(ndx)); + map.put(IBlockCipher.CIPHER_BLOCK_SIZE, Integer.valueOf(AES_BLOCK_SIZE)); + final byte[] key = new byte[AES_KEY_SIZE]; + System.arraycopy(keyMaterial, 0, key, 0, AES_KEY_SIZE); + map.put(IBlockCipher.KEY_MATERIAL, key); + umac = new UMacGenerator(); + umac.init(map); + } + + /** + * A Factory mehod that returns an instance of a <code>KDF</code> based on + * supplied seed data. + * + * @param K the SASL SRP shared secret for a <code>KDF</code> to be used for + * <i>CALG</i> and <i>IALG</i> setup. <code>null</code> otherwise. + * @return an instance of a <code>KDF</code>. + */ + static final KDF getInstance(final byte[] K) + { + int ndx = -1; + final byte[] keyMaterial; + if (K != null) + { + keyMaterial = K; + ndx = 0; + } + else + { + keyMaterial = new byte[AES_BLOCK_SIZE]; + while (ndx < 1 || ndx > 255) + ndx = (byte) nextByte(); + } + return new KDF(keyMaterial, ndx); + } + + private static synchronized final int nextByte() + { + prng.nextBytes(buffer); + return (buffer[0] & 0xFF); + } + + /** + * Returns a designated number of bytes suitable for use in the SASL SRP + * mechanism. + * + * @param length the number of bytes needed. + * @return a byte array containing the generated/selected bytes. + */ + public synchronized byte[] derive(final int length) + { + final byte[] result = new byte[length]; + try + { + umac.nextBytes(result, 0, length); + } + catch (IllegalStateException x) // should not happen + { + x.printStackTrace(System.err); + } + catch (LimitReachedException x) // idem + { + x.printStackTrace(System.err); + } + return result; + } +} diff --git a/libjava/classpath/gnu/javax/crypto/sasl/srp/PasswordFile.java b/libjava/classpath/gnu/javax/crypto/sasl/srp/PasswordFile.java new file mode 100644 index 000000000..c13c2fa71 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/sasl/srp/PasswordFile.java @@ -0,0 +1,627 @@ +/* PasswordFile.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.sasl.srp; + +import gnu.java.lang.CPStringBuilder; + +import gnu.java.security.Registry; +import gnu.java.security.util.Util; +import gnu.javax.crypto.key.srp6.SRPAlgorithm; +import gnu.javax.crypto.sasl.NoSuchUserException; +import gnu.javax.crypto.sasl.UserAlreadyExistsException; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.PrintWriter; +import java.io.UnsupportedEncodingException; +import java.math.BigInteger; +import java.util.HashMap; +import java.util.Iterator; +import java.util.NoSuchElementException; +import java.util.StringTokenizer; + +/** + * The implementation of SRP password files. + * <p> + * For SRP, there are three (3) files: + * <ol> + * <li>The password configuration file: tpasswd.conf. It contains the pairs + * <N,g> indexed by a number for each pair used for a user. By default, this + * file's pathname is constructed from the base password file pathname by + * prepending it with the ".conf" suffix.</li> + * <li>The base password file: tpasswd. It contains the related password + * entries for all the users with values computed using SRP's default message + * digest algorithm: SHA-1 (with 160-bit output block size).</li> + * <li>The extended password file: tpasswd2. Its name, by default, is + * constructed by adding the suffix "2" to the fully qualified pathname of the + * base password file. It contains, in addition to the same fields as the base + * password file, albeit with a different verifier value, an extra field + * identifying the message digest algorithm used to compute this (verifier) + * value.</li> + * </ol> + * <p> + * This implementation assumes the following message digest algorithm codes: + * <ul> + * <li>0: the default hash algorithm, which is SHA-1 (or its alias SHA-160).</li> + * <li>1: MD5.</li> + * <li>2: RIPEMD-128.</li> + * <li>3: RIPEMD-160.</li> + * <li>4: SHA-256.</li> + * <li>5: SHA-384.</li> + * <li>6: SHA-512.</li> + * </ul> + * <p> + * <b>IMPORTANT:</b> This method computes the verifiers as described in + * RFC-2945, which differs from the description given on the web page for SRP-6. + * <p> + * Reference: + * <ol> + * <li><a href="http://srp.stanford.edu/design.html">SRP Protocol Design</a><br> + * Thomas J. Wu.</li> + * </ol> + */ +public class PasswordFile +{ + // names of property keys used in this class + private static final String USER_FIELD = "user"; + private static final String VERIFIERS_FIELD = "verifier"; + private static final String SALT_FIELD = "salt"; + private static final String CONFIG_FIELD = "config"; + private static String DEFAULT_FILE; + static + { + DEFAULT_FILE = System.getProperty(SRPRegistry.PASSWORD_FILE, + SRPRegistry.DEFAULT_PASSWORD_FILE); + } + /** The SRP algorithm instances used by this object. */ + private static final HashMap srps; + static + { + final HashMap map = new HashMap(SRPRegistry.SRP_ALGORITHMS.length); + // The first entry MUST exist. The others are optional. + map.put("0", SRP.instance(SRPRegistry.SRP_ALGORITHMS[0])); + for (int i = 1; i < SRPRegistry.SRP_ALGORITHMS.length; i++) + { + try + { + map.put(String.valueOf(i), + SRP.instance(SRPRegistry.SRP_ALGORITHMS[i])); + } + catch (Exception x) + { + System.err.println("Ignored: " + x); + x.printStackTrace(System.err); + } + } + srps = map; + } + + private String confName, pwName, pw2Name; + private File configFile, passwdFile, passwd2File; + private long lastmodPasswdFile, lastmodPasswd2File; + private HashMap entries = new HashMap(); + private HashMap configurations = new HashMap(); + // default N values to use when creating a new password.conf file + private static final BigInteger[] Nsrp = new BigInteger[] { + SRPAlgorithm.N_2048, + SRPAlgorithm.N_1536, + SRPAlgorithm.N_1280, + SRPAlgorithm.N_1024, + SRPAlgorithm.N_768, + SRPAlgorithm.N_640, + SRPAlgorithm.N_512 }; + + public PasswordFile() throws IOException + { + this(DEFAULT_FILE); + } + + public PasswordFile(final File pwFile) throws IOException + { + this(pwFile.getAbsolutePath()); + } + + public PasswordFile(final String pwName) throws IOException + { + this(pwName, pwName + "2", pwName + ".conf"); + } + + public PasswordFile(final String pwName, final String confName) + throws IOException + { + this(pwName, pwName + "2", confName); + } + + public PasswordFile(final String pwName, final String pw2Name, + final String confName) throws IOException + { + super(); + + this.pwName = pwName; + this.pw2Name = pw2Name; + this.confName = confName; + + readOrCreateConf(); + update(); + } + + /** + * Returns a string representing the decimal value of an integer identifying + * the message digest algorithm to use for the SRP computations. + * + * @param mdName the canonical name of a message digest algorithm. + * @return a string representing the decimal value of an ID for that + * algorithm. + */ + private static final String nameToID(final String mdName) + { + if (Registry.SHA_HASH.equalsIgnoreCase(mdName) + || Registry.SHA1_HASH.equalsIgnoreCase(mdName) + || Registry.SHA160_HASH.equalsIgnoreCase(mdName)) + return "0"; + else if (Registry.MD5_HASH.equalsIgnoreCase(mdName)) + return "1"; + else if (Registry.RIPEMD128_HASH.equalsIgnoreCase(mdName)) + return "2"; + else if (Registry.RIPEMD160_HASH.equalsIgnoreCase(mdName)) + return "3"; + else if (Registry.SHA256_HASH.equalsIgnoreCase(mdName)) + return "4"; + else if (Registry.SHA384_HASH.equalsIgnoreCase(mdName)) + return "5"; + else if (Registry.SHA512_HASH.equalsIgnoreCase(mdName)) + return "6"; + return "0"; + } + + /** + * Checks if the current configuration file contains the <N, g> pair for + * the designated <code>index</code>. + * + * @param index a string representing 1-digit identification of an <N, g> + * pair used. + * @return <code>true</code> if the designated <code>index</code> is that + * of a known <N, g> pair, and <code>false</code> otherwise. + * @throws IOException if an exception occurs during the process. + * @see SRPRegistry#N_2048_BITS + * @see SRPRegistry#N_1536_BITS + * @see SRPRegistry#N_1280_BITS + * @see SRPRegistry#N_1024_BITS + * @see SRPRegistry#N_768_BITS + * @see SRPRegistry#N_640_BITS + * @see SRPRegistry#N_512_BITS + */ + public synchronized boolean containsConfig(final String index) + throws IOException + { + checkCurrent(); + return configurations.containsKey(index); + } + + /** + * Returns a pair of strings representing the pair of <code>N</code> and + * <code>g</code> MPIs for the designated <code>index</code>. + * + * @param index a string representing 1-digit identification of an <N, g> + * pair to look up. + * @return a pair of strings, arranged in an array, where the first (at index + * position #0) is the repesentation of the MPI <code>N</code>, and + * the second (at index position #1) is the representation of the MPI + * <code>g</code>. If the <code>index</code> refers to an unknown + * pair, then an empty string array is returned. + * @throws IOException if an exception occurs during the process. + */ + public synchronized String[] lookupConfig(final String index) + throws IOException + { + checkCurrent(); + String[] result = null; + if (configurations.containsKey(index)) + result = (String[]) configurations.get(index); + return result; + } + + public synchronized boolean contains(final String user) throws IOException + { + checkCurrent(); + return entries.containsKey(user); + } + + public synchronized void add(final String user, final String passwd, + final byte[] salt, final String index) + throws IOException + { + checkCurrent(); + if (entries.containsKey(user)) + throw new UserAlreadyExistsException(user); + final HashMap fields = new HashMap(4); + fields.put(USER_FIELD, user); // 0 + fields.put(VERIFIERS_FIELD, newVerifiers(user, salt, passwd, index)); // 1 + fields.put(SALT_FIELD, Util.toBase64(salt)); // 2 + fields.put(CONFIG_FIELD, index); // 3 + entries.put(user, fields); + savePasswd(); + } + + public synchronized void changePasswd(final String user, final String passwd) + throws IOException + { + checkCurrent(); + if (! entries.containsKey(user)) + throw new NoSuchUserException(user); + final HashMap fields = (HashMap) entries.get(user); + final byte[] salt; + try + { + salt = Util.fromBase64((String) fields.get(SALT_FIELD)); + } + catch (NumberFormatException x) + { + throw new IOException("Password file corrupt"); + } + final String index = (String) fields.get(CONFIG_FIELD); + fields.put(VERIFIERS_FIELD, newVerifiers(user, salt, passwd, index)); + entries.put(user, fields); + savePasswd(); + } + + public synchronized void savePasswd() throws IOException + { + final FileOutputStream f1 = new FileOutputStream(passwdFile); + final FileOutputStream f2 = new FileOutputStream(passwd2File); + PrintWriter pw1 = null; + PrintWriter pw2 = null; + try + { + pw1 = new PrintWriter(f1, true); + pw2 = new PrintWriter(f2, true); + this.writePasswd(pw1, pw2); + } + finally + { + if (pw1 != null) + try + { + pw1.flush(); + } + finally + { + pw1.close(); + } + if (pw2 != null) + try + { + pw2.flush(); + } + finally + { + pw2.close(); + } + try + { + f1.close(); + } + catch (IOException ignored) + { + } + try + { + f2.close(); + } + catch (IOException ignored) + { + } + } + lastmodPasswdFile = passwdFile.lastModified(); + lastmodPasswd2File = passwd2File.lastModified(); + } + + /** + * Returns the triplet: verifier, salt and configuration file index, of a + * designated user, and a designated message digest algorithm name, as an + * array of strings. + * + * @param user the username. + * @param mdName the canonical name of the SRP's message digest algorithm. + * @return a string array containing, in this order, the BASE-64 encodings of + * the verifier, the salt and the index in the password configuration + * file of the MPIs N and g of the designated user. + */ + public synchronized String[] lookup(final String user, final String mdName) + throws IOException + { + checkCurrent(); + if (! entries.containsKey(user)) + throw new NoSuchUserException(user); + final HashMap fields = (HashMap) entries.get(user); + final HashMap verifiers = (HashMap) fields.get(VERIFIERS_FIELD); + final String salt = (String) fields.get(SALT_FIELD); + final String index = (String) fields.get(CONFIG_FIELD); + final String verifier = (String) verifiers.get(nameToID(mdName)); + return new String[] { verifier, salt, index }; + } + + private synchronized void readOrCreateConf() throws IOException + { + configurations.clear(); + final FileInputStream fis; + configFile = new File(confName); + try + { + fis = new FileInputStream(configFile); + readConf(fis); + } + catch (FileNotFoundException x) + { // create a default one + final String g = Util.toBase64(Util.trim(new BigInteger("2"))); + String index, N; + for (int i = 0; i < Nsrp.length; i++) + { + index = String.valueOf(i + 1); + N = Util.toBase64(Util.trim(Nsrp[i])); + configurations.put(index, new String[] { N, g }); + } + FileOutputStream f0 = null; + PrintWriter pw0 = null; + try + { + f0 = new FileOutputStream(configFile); + pw0 = new PrintWriter(f0, true); + this.writeConf(pw0); + } + finally + { + if (pw0 != null) + pw0.close(); + else if (f0 != null) + f0.close(); + } + } + } + + private void readConf(final InputStream in) throws IOException + { + final BufferedReader din = new BufferedReader(new InputStreamReader(in)); + String line, index, N, g; + StringTokenizer st; + while ((line = din.readLine()) != null) + { + st = new StringTokenizer(line, ":"); + try + { + index = st.nextToken(); + N = st.nextToken(); + g = st.nextToken(); + } + catch (NoSuchElementException x) + { + throw new IOException("SRP password configuration file corrupt"); + } + configurations.put(index, new String[] { N, g }); + } + } + + private void writeConf(final PrintWriter pw) + { + String ndx; + String[] mpi; + CPStringBuilder sb; + for (Iterator it = configurations.keySet().iterator(); it.hasNext();) + { + ndx = (String) it.next(); + mpi = (String[]) configurations.get(ndx); + sb = new CPStringBuilder(ndx) + .append(":").append(mpi[0]) + .append(":").append(mpi[1]); + pw.println(sb.toString()); + } + } + + /** + * Compute the new verifiers for the designated username and password. + * <p> + * <b>IMPORTANT:</b> This method computes the verifiers as described in + * RFC-2945, which differs from the description given on the web page for + * SRP-6. + * + * @param user the user's name. + * @param s the user's salt. + * @param password the user's password + * @param index the index of the <N, g> pair to use for this user. + * @return a {@link java.util.Map} of user verifiers. + * @throws UnsupportedEncodingException if the US-ASCII decoder is not + * available on this platform. + */ + private HashMap newVerifiers(final String user, final byte[] s, + final String password, final String index) + throws UnsupportedEncodingException + { + // to ensure inter-operability with non-java tools + final String[] mpi = (String[]) configurations.get(index); + final BigInteger N = new BigInteger(1, Util.fromBase64(mpi[0])); + final BigInteger g = new BigInteger(1, Util.fromBase64(mpi[1])); + final HashMap result = new HashMap(srps.size()); + BigInteger x, v; + SRP srp; + for (int i = 0; i < srps.size(); i++) + { + final String digestID = String.valueOf(i); + srp = (SRP) srps.get(digestID); + x = new BigInteger(1, srp.computeX(s, user, password)); + v = g.modPow(x, N); + final String verifier = Util.toBase64(v.toByteArray()); + result.put(digestID, verifier); + } + return result; + } + + private synchronized void update() throws IOException + { + entries.clear(); + FileInputStream fis; + passwdFile = new File(pwName); + lastmodPasswdFile = passwdFile.lastModified(); + try + { + fis = new FileInputStream(passwdFile); + readPasswd(fis); + } + catch (FileNotFoundException ignored) + { + } + passwd2File = new File(pw2Name); + lastmodPasswd2File = passwd2File.lastModified(); + try + { + fis = new FileInputStream(passwd2File); + readPasswd2(fis); + } + catch (FileNotFoundException ignored) + { + } + } + + private void checkCurrent() throws IOException + { + if (passwdFile.lastModified() > lastmodPasswdFile + || passwd2File.lastModified() > lastmodPasswd2File) + update(); + } + + private void readPasswd(final InputStream in) throws IOException + { + final BufferedReader din = new BufferedReader(new InputStreamReader(in)); + String line, user, verifier, salt, index; + StringTokenizer st; + while ((line = din.readLine()) != null) + { + st = new StringTokenizer(line, ":"); + try + { + user = st.nextToken(); + verifier = st.nextToken(); + salt = st.nextToken(); + index = st.nextToken(); + } + catch (NoSuchElementException x) + { + throw new IOException("SRP base password file corrupt"); + } + final HashMap verifiers = new HashMap(6); + verifiers.put("0", verifier); + final HashMap fields = new HashMap(4); + fields.put(USER_FIELD, user); + fields.put(VERIFIERS_FIELD, verifiers); + fields.put(SALT_FIELD, salt); + fields.put(CONFIG_FIELD, index); + entries.put(user, fields); + } + } + + private void readPasswd2(final InputStream in) throws IOException + { + final BufferedReader din = new BufferedReader(new InputStreamReader(in)); + String line, digestID, user, verifier; + StringTokenizer st; + HashMap fields, verifiers; + while ((line = din.readLine()) != null) + { + st = new StringTokenizer(line, ":"); + try + { + digestID = st.nextToken(); + user = st.nextToken(); + verifier = st.nextToken(); + } + catch (NoSuchElementException x) + { + throw new IOException("SRP extended password file corrupt"); + } + fields = (HashMap) entries.get(user); + if (fields != null) + { + verifiers = (HashMap) fields.get(VERIFIERS_FIELD); + verifiers.put(digestID, verifier); + } + } + } + + private void writePasswd(final PrintWriter pw1, final PrintWriter pw2) + throws IOException + { + String user, digestID; + HashMap fields, verifiers; + CPStringBuilder sb1, sb2; + Iterator j; + final Iterator i = entries.keySet().iterator(); + while (i.hasNext()) + { + user = (String) i.next(); + fields = (HashMap) entries.get(user); + if (! user.equals(fields.get(USER_FIELD))) + throw new IOException("Inconsistent SRP password data"); + verifiers = (HashMap) fields.get(VERIFIERS_FIELD); + sb1 = new CPStringBuilder(user) + .append(":").append((String) verifiers.get("0")) + .append(":").append((String) fields.get(SALT_FIELD)) + .append(":").append((String) fields.get(CONFIG_FIELD)); + pw1.println(sb1.toString()); + // write extended information + j = verifiers.keySet().iterator(); + while (j.hasNext()) + { + digestID = (String) j.next(); + if (! "0".equals(digestID)) + { + // #0 is the default digest, already present in tpasswd! + sb2 = new CPStringBuilder(digestID) + .append(":").append(user) + .append(":").append((String) verifiers.get(digestID)); + pw2.println(sb2.toString()); + } + } + } + } +} diff --git a/libjava/classpath/gnu/javax/crypto/sasl/srp/SRP.java b/libjava/classpath/gnu/javax/crypto/sasl/srp/SRP.java new file mode 100644 index 000000000..569855dd7 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/sasl/srp/SRP.java @@ -0,0 +1,255 @@ +/* SRP.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.sasl.srp; + +import gnu.java.security.hash.HashFactory; +import gnu.java.security.hash.IMessageDigest; +import gnu.java.security.util.Util; + +import java.io.UnsupportedEncodingException; +import java.math.BigInteger; +import java.util.HashMap; + +/** + * A Factory class that returns SRP Singletons that know all SRP-related + * mathematical computations and protocol-related operations for both the + * client- and server-sides. + */ +public final class SRP +{ + /** The map of already instantiated SRP algorithm instances. */ + private static final HashMap algorithms = new HashMap(); + private static final byte COLON = (byte) 0x3A; + /** The underlying message digest algorithm used for all SRP calculations. */ + private IMessageDigest mda; + + /** Trivial private constructor to enforce Singleton pattern. */ + private SRP(final IMessageDigest mda) + { + super(); + + this.mda = mda; + } + + /** + * Returns an instance of this object that uses the designated message digest + * algorithm as its digest function. + * + * @return an instance of this object for the designated digest name. + */ + public static synchronized SRP instance(String mdName) + { + if (mdName != null) + mdName = mdName.trim().toLowerCase(); + if (mdName == null || mdName.equals("")) + mdName = SRPRegistry.SRP_DEFAULT_DIGEST_NAME; + SRP result = (SRP) algorithms.get(mdName); + if (result == null) + { + final IMessageDigest mda = HashFactory.getInstance(mdName); + result = new SRP(mda); + algorithms.put(mdName, result); + } + return result; + } + + private static final byte[] xor(final byte[] b1, final byte[] b2, + final int length) + { + final byte[] result = new byte[length]; + for (int i = 0; i < length; ++i) + result[i] = (byte)(b1[i] ^ b2[i]); + return result; + } + + /** @return the message digest algorithm name used by this instance. */ + public String getAlgorithm() + { + return mda.name(); + } + + /** + * Returns a new instance of the SRP message digest algorithm --which is + * SHA-160 by default, but could be anything else provided the proper + * conditions as specified in the SRP specifications. + * + * @return a new instance of the underlying SRP message digest algorithm. + * @throws RuntimeException if the implementation of the message digest + * algorithm does not support cloning. + */ + public IMessageDigest newDigest() + { + return (IMessageDigest) mda.clone(); + } + + /** + * Convenience method to return the result of digesting the designated input + * with a new instance of the SRP message digest algorithm. + * + * @param src some bytes to digest. + * @return the bytes constituting the result of digesting the designated input + * with a new instance of the SRP message digest algorithm. + */ + public byte[] digest(final byte[] src) + { + final IMessageDigest hash = (IMessageDigest) mda.clone(); + hash.update(src, 0, src.length); + return hash.digest(); + } + + /** + * Convenience method to return the result of digesting the designated input + * with a new instance of the SRP message digest algorithm. + * + * @param src a String whose bytes (using US-ASCII encoding) are to be + * digested. + * @return the bytes constituting the result of digesting the designated input + * with a new instance of the SRP message digest algorithm. + * @throws UnsupportedEncodingException if US-ASCII charset is not found. + */ + public byte[] digest(final String src) throws UnsupportedEncodingException + { + return digest(src.getBytes("US-ASCII")); + } + + /** + * Convenience method to XOR N bytes from two arrays; N being the output size + * of the SRP message digest algorithm. + * + * @param a the first byte array. + * @param b the second one. + * @return N bytes which are the result of the XOR operations on the first N + * bytes from the designated arrays. N is the size of the SRP message + * digest algorithm; eg. 20 for SHA-160. + */ + public byte[] xor(final byte[] a, final byte[] b) + { + return xor(a, b, mda.hashSize()); + } + + public byte[] generateM1(final BigInteger N, final BigInteger g, + final String U, final byte[] s, final BigInteger A, + final BigInteger B, final byte[] K, final String I, + final String L, final byte[] cn, final byte[] cCB) + throws UnsupportedEncodingException + { + final IMessageDigest hash = (IMessageDigest) mda.clone(); + byte[] b; + b = xor(digest(Util.trim(N)), digest(Util.trim(g))); + hash.update(b, 0, b.length); + b = digest(U); + hash.update(b, 0, b.length); + hash.update(s, 0, s.length); + b = Util.trim(A); + hash.update(b, 0, b.length); + b = Util.trim(B); + hash.update(b, 0, b.length); + hash.update(K, 0, K.length); + b = digest(I); + hash.update(b, 0, b.length); + b = digest(L); + hash.update(b, 0, b.length); + hash.update(cn, 0, cn.length); + hash.update(cCB, 0, cCB.length); + return hash.digest(); + } + + public byte[] generateM2(final BigInteger A, final byte[] M1, final byte[] K, + final String U, final String I, final String o, + final byte[] sid, final int ttl, final byte[] cIV, + final byte[] sIV, final byte[] sCB) + throws UnsupportedEncodingException + { + final IMessageDigest hash = (IMessageDigest) mda.clone(); + byte[] b; + b = Util.trim(A); + hash.update(b, 0, b.length); + hash.update(M1, 0, M1.length); + hash.update(K, 0, K.length); + b = digest(U); + hash.update(b, 0, b.length); + b = digest(I); + hash.update(b, 0, b.length); + b = digest(o); + hash.update(b, 0, b.length); + hash.update(sid, 0, sid.length); + hash.update((byte)(ttl >>> 24)); + hash.update((byte)(ttl >>> 16)); + hash.update((byte)(ttl >>> 8)); + hash.update((byte) ttl); + hash.update(cIV, 0, cIV.length); + hash.update(sIV, 0, sIV.length); + hash.update(sCB, 0, sCB.length); + return hash.digest(); + } + + public byte[] generateKn(final byte[] K, final byte[] cn, final byte[] sn) + { + final IMessageDigest hash = (IMessageDigest) mda.clone(); + hash.update(K, 0, K.length); + hash.update(cn, 0, cn.length); + hash.update(sn, 0, sn.length); + return hash.digest(); + } + + public byte[] computeX(final byte[] s, final String user, + final String password) + throws UnsupportedEncodingException + { + return computeX(s, user.getBytes("US-ASCII"), password.getBytes("US-ASCII")); + } + + public byte[] computeX(final byte[] s, final String user, final byte[] p) + throws UnsupportedEncodingException + { + return computeX(s, user.getBytes("US-ASCII"), p); + } + + private byte[] computeX(final byte[] s, final byte[] user, final byte[] p) + { + final IMessageDigest hash = (IMessageDigest) mda.clone(); + hash.update(user, 0, user.length); + hash.update(COLON); + hash.update(p, 0, p.length); + final byte[] up = hash.digest(); + hash.update(s, 0, s.length); + hash.update(up, 0, up.length); + return hash.digest(); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/sasl/srp/SRPAuthInfoProvider.java b/libjava/classpath/gnu/javax/crypto/sasl/srp/SRPAuthInfoProvider.java new file mode 100644 index 000000000..e42cfffa9 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/sasl/srp/SRPAuthInfoProvider.java @@ -0,0 +1,177 @@ +/* SRPAuthInfoProvider.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.sasl.srp; + +import gnu.java.security.Registry; +import gnu.java.security.util.Util; +import gnu.javax.crypto.sasl.IAuthInfoProvider; +import gnu.javax.crypto.sasl.NoSuchUserException; + +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; + +import javax.security.sasl.AuthenticationException; + +/** + * The SRP mechanism authentication information provider implementation. + */ +public class SRPAuthInfoProvider + implements IAuthInfoProvider +{ + private PasswordFile passwordFile = null; + + // implicit 0-args constrcutor + + public void activate(Map context) throws AuthenticationException + { + try + { + if (context == null) + passwordFile = new PasswordFile(); + else + { + passwordFile = (PasswordFile) context.get(SRPRegistry.PASSWORD_DB); + if (passwordFile == null) + { + String pfn = (String) context.get(SRPRegistry.PASSWORD_FILE); + if (pfn == null) + passwordFile = new PasswordFile(); + else + passwordFile = new PasswordFile(pfn); + } + } + } + catch (IOException x) + { + throw new AuthenticationException("activate()", x); + } + } + + public void passivate() throws AuthenticationException + { + passwordFile = null; + } + + public boolean contains(String userName) throws AuthenticationException + { + if (passwordFile == null) + throw new AuthenticationException("contains()", + new IllegalStateException()); + boolean result = false; + try + { + result = passwordFile.contains(userName); + } + catch (IOException x) + { + throw new AuthenticationException("contains()", x); + } + return result; + } + + public Map lookup(Map userID) throws AuthenticationException + { + if (passwordFile == null) + throw new AuthenticationException("lookup()", new IllegalStateException()); + Map result = new HashMap(); + try + { + String userName = (String) userID.get(Registry.SASL_USERNAME); + if (userName == null) + throw new NoSuchUserException(""); + String mdName = (String) userID.get(SRPRegistry.MD_NAME_FIELD); + String[] data = passwordFile.lookup(userName, mdName); + result.put(SRPRegistry.USER_VERIFIER_FIELD, data[0]); + result.put(SRPRegistry.SALT_FIELD, data[1]); + result.put(SRPRegistry.CONFIG_NDX_FIELD, data[2]); + } + catch (Exception x) + { + if (x instanceof AuthenticationException) + throw (AuthenticationException) x; + throw new AuthenticationException("lookup()", x); + } + return result; + } + + public void update(Map userCredentials) throws AuthenticationException + { + if (passwordFile == null) + throw new AuthenticationException("update()", new IllegalStateException()); + try + { + String userName = (String) userCredentials.get(Registry.SASL_USERNAME); + String password = (String) userCredentials.get(Registry.SASL_PASSWORD); + String salt = (String) userCredentials.get(SRPRegistry.SALT_FIELD); + String config = (String) userCredentials.get(SRPRegistry.CONFIG_NDX_FIELD); + if (salt == null || config == null) + passwordFile.changePasswd(userName, password); + else + passwordFile.add(userName, password, Util.fromBase64(salt), config); + } + catch (Exception x) + { + if (x instanceof AuthenticationException) + throw (AuthenticationException) x; + throw new AuthenticationException("update()", x); + } + } + + public Map getConfiguration(String mode) throws AuthenticationException + { + if (passwordFile == null) + throw new AuthenticationException("getConfiguration()", + new IllegalStateException()); + Map result = new HashMap(); + try + { + String[] data = passwordFile.lookupConfig(mode); + result.put(SRPRegistry.SHARED_MODULUS, data[0]); + result.put(SRPRegistry.FIELD_GENERATOR, data[1]); + } + catch (Exception x) + { + if (x instanceof AuthenticationException) + throw (AuthenticationException) x; + throw new AuthenticationException("getConfiguration()", x); + } + return result; + } +} diff --git a/libjava/classpath/gnu/javax/crypto/sasl/srp/SRPClient.java b/libjava/classpath/gnu/javax/crypto/sasl/srp/SRPClient.java new file mode 100644 index 000000000..8e44e4ead --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/sasl/srp/SRPClient.java @@ -0,0 +1,954 @@ +/* SRPClient.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.sasl.srp; + +import gnu.java.lang.CPStringBuilder; + +import gnu.java.security.Configuration; +import gnu.java.security.Registry; +import gnu.java.security.hash.MD5; +import gnu.java.security.util.PRNG; +import gnu.java.security.util.Util; +import gnu.javax.crypto.assembly.Direction; +import gnu.javax.crypto.cipher.CipherFactory; +import gnu.javax.crypto.cipher.IBlockCipher; +import gnu.javax.crypto.key.IKeyAgreementParty; +import gnu.javax.crypto.key.IncomingMessage; +import gnu.javax.crypto.key.KeyAgreementException; +import gnu.javax.crypto.key.KeyAgreementFactory; +import gnu.javax.crypto.key.OutgoingMessage; +import gnu.javax.crypto.key.srp6.SRP6KeyAgreement; +import gnu.javax.crypto.sasl.ClientMechanism; +import gnu.javax.crypto.sasl.IllegalMechanismStateException; +import gnu.javax.crypto.sasl.InputBuffer; +import gnu.javax.crypto.sasl.IntegrityException; +import gnu.javax.crypto.sasl.OutputBuffer; +import gnu.javax.security.auth.Password; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.UnsupportedEncodingException; +import java.math.BigInteger; +import java.security.NoSuchAlgorithmException; +import java.util.Arrays; +import java.util.HashMap; +import java.util.StringTokenizer; +import java.util.logging.Logger; + +import javax.security.auth.DestroyFailedException; +import javax.security.auth.callback.Callback; +import javax.security.auth.callback.NameCallback; +import javax.security.auth.callback.PasswordCallback; +import javax.security.auth.callback.UnsupportedCallbackException; +import javax.security.sasl.AuthenticationException; +import javax.security.sasl.SaslClient; +import javax.security.sasl.SaslException; + +/** + * The SASL-SRP client-side mechanism. + */ +public class SRPClient + extends ClientMechanism + implements SaslClient +{ + private static final Logger log = Logger.getLogger(SRPClient.class.getName()); + private String uid; // the unique key for this type of client + private String U; // the authentication identity + BigInteger N, g, A, B; + private Password password; // the authentication credentials + private byte[] s; // the user's salt + private byte[] cIV, sIV; // client+server IVs, when confidentiality is on + private byte[] M1, M2; // client+server evidences + private byte[] cn, sn; // client's and server's nonce + private SRP srp; // SRP algorithm instance used by this client + private byte[] sid; // session ID when re-used + private int ttl; // session time-to-live in seconds + private byte[] sCB; // the peer's channel binding data + private String L; // available options + private String o; + private String chosenIntegrityAlgorithm; + private String chosenConfidentialityAlgorithm; + private int rawSendSize = Registry.SASL_BUFFER_MAX_LIMIT; + private byte[] K; // shared session key + private boolean replayDetection = true; // whether Replay Detection is on + private int inCounter = 0; // messages sequence numbers + private int outCounter = 0; + private IALG inMac, outMac; // if !null, use for integrity + private CALG inCipher, outCipher; // if !null, use for confidentiality + private IKeyAgreementParty clientHandler = + KeyAgreementFactory.getPartyAInstance(Registry.SRP_SASL_KA); + /** Our default source of randomness. */ + private PRNG prng = null; + + public SRPClient() + { + super(Registry.SASL_SRP_MECHANISM); + } + + protected void initMechanism() throws SaslException + { + // we shall keep track of the sid (and the security context of this SRP + // client) based on the initialisation parameters of an SRP session. + // we shall compute a unique key for those parameters and key the sid + // (and the security context) accordingly. + // 1. compute the mapping key. use MD5 (the fastest) for this purpose + final MD5 md = new MD5(); + byte[] b; + b = authorizationID.getBytes(); + md.update(b, 0, b.length); + b = serverName.getBytes(); + md.update(b, 0, b.length); + b = protocol.getBytes(); + md.update(b, 0, b.length); + if (channelBinding.length > 0) + md.update(channelBinding, 0, channelBinding.length); + + uid = Util.toBase64(md.digest()); + if (ClientStore.instance().isAlive(uid)) + { + final SecurityContext ctx = ClientStore.instance().restoreSession(uid); + srp = SRP.instance(ctx.getMdName()); + sid = ctx.getSID(); + K = ctx.getK(); + cIV = ctx.getClientIV(); + sIV = ctx.getServerIV(); + replayDetection = ctx.hasReplayDetection(); + inCounter = ctx.getInCounter(); + outCounter = ctx.getOutCounter(); + inMac = ctx.getInMac(); + outMac = ctx.getOutMac(); + inCipher = ctx.getInCipher(); + outCipher = ctx.getOutCipher(); + } + else + { + sid = new byte[0]; + ttl = 0; + K = null; + cIV = null; + sIV = null; + cn = null; + sn = null; + } + } + + protected void resetMechanism() throws SaslException + { + try + { + password.destroy(); + } + catch (DestroyFailedException dfe) + { + SaslException se = new SaslException("resetMechanism()"); + se.initCause(dfe); + throw se; + } + password = null; + M1 = null; + K = null; + cIV = null; + sIV = null; + inMac = outMac = null; + inCipher = outCipher = null; + sid = null; + ttl = 0; + cn = null; + sn = null; + } + + public boolean hasInitialResponse() + { + return true; + } + + public byte[] evaluateChallenge(final byte[] challenge) throws SaslException + { + switch (state) + { + case 0: + state++; + return sendIdentities(); + case 1: + state++; + final byte[] result = sendPublicKey(challenge); + try + { + password.destroy(); //don't need further this session + } + catch (DestroyFailedException x) + { + SaslException se = new SaslException("sendPublicKey()"); + se.initCause(se); + throw se; + } + return result; + case 2: // should only occur if session re-use was rejected + if (! complete) + { + state++; + return receiveEvidence(challenge); + } + // else fall through + default: + throw new IllegalMechanismStateException("evaluateChallenge()"); + } + } + + protected byte[] engineUnwrap(final byte[] incoming, final int offset, + final int len) throws SaslException + { + if (Configuration.DEBUG) + log.entering(this.getClass().getName(), "engineUnwrap"); + if (inMac == null && inCipher == null) + throw new IllegalStateException("connection is not protected"); + // at this point one, or both, of confidentiality and integrity protection + // services are active. + final byte[] result; + try + { + if (inMac != null) + { // integrity bytes are at the end of the stream + final int macBytesCount = inMac.length(); + final int payloadLength = len - macBytesCount; + final byte[] received_mac = new byte[macBytesCount]; + System.arraycopy(incoming, offset + payloadLength, received_mac, 0, + macBytesCount); + if (Configuration.DEBUG) + log.fine("Got C (received MAC): " + Util.dumpString(received_mac)); + inMac.update(incoming, offset, payloadLength); + if (replayDetection) + { + inCounter++; + if (Configuration.DEBUG) + log.fine("inCounter=" + inCounter); + inMac.update(new byte[] { + (byte)(inCounter >>> 24), + (byte)(inCounter >>> 16), + (byte)(inCounter >>> 8), + (byte) inCounter }); + } + final byte[] computed_mac = inMac.doFinal(); + if (Configuration.DEBUG) + log.fine("Computed MAC: " + Util.dumpString(computed_mac)); + if (! Arrays.equals(received_mac, computed_mac)) + throw new IntegrityException("engineUnwrap()"); + // deal with the payload, which can be either plain or encrypted + if (inCipher != null) + result = inCipher.doFinal(incoming, offset, payloadLength); + else + { + result = new byte[len - macBytesCount]; + System.arraycopy(incoming, offset, result, 0, result.length); + } + } + else // no integrity protection; just confidentiality + result = inCipher.doFinal(incoming, offset, len); + } + catch (IOException x) + { + if (x instanceof SaslException) + throw (SaslException) x; + throw new SaslException("engineUnwrap()", x); + } + if (Configuration.DEBUG) + log.exiting(this.getClass().getName(), "engineUnwrap"); + return result; + } + + protected byte[] engineWrap(final byte[] outgoing, final int offset, + final int len) throws SaslException + { + if (Configuration.DEBUG) + log.entering(this.getClass().getName(), "engineWrap"); + if (outMac == null && outCipher == null) + throw new IllegalStateException("connection is not protected"); + // at this point one, or both, of confidentiality and integrity protection + // services are active. + byte[] result; + try + { + final ByteArrayOutputStream out = new ByteArrayOutputStream(); + // Process the data + if (outCipher != null) + { + result = outCipher.doFinal(outgoing, offset, len); + if (Configuration.DEBUG) + log.fine("Encoding c (encrypted plaintext): " + + Util.dumpString(result)); + out.write(result); + if (outMac != null) + { + outMac.update(result); + if (replayDetection) + { + outCounter++; + if (Configuration.DEBUG) + log.fine("outCounter=" + outCounter); + outMac.update(new byte[] { + (byte)(outCounter >>> 24), + (byte)(outCounter >>> 16), + (byte)(outCounter >>> 8), + (byte) outCounter }); + } + final byte[] C = outMac.doFinal(); + out.write(C); + if (Configuration.DEBUG) + log.fine("Encoding C (integrity checksum): " + Util.dumpString(C)); + } + // else confidentiality only; do nothing + } + else // no confidentiality; just integrity [+ replay detection] + { + if (Configuration.DEBUG) + log.fine("Encoding p (plaintext): " + + Util.dumpString(outgoing, offset, len)); + out.write(outgoing, offset, len); + outMac.update(outgoing, offset, len); + if (replayDetection) + { + outCounter++; + if (Configuration.DEBUG) + log.fine("outCounter=" + outCounter); + outMac.update(new byte[] { + (byte)(outCounter >>> 24), + (byte)(outCounter >>> 16), + (byte)(outCounter >>> 8), + (byte) outCounter }); + } + final byte[] C = outMac.doFinal(); + out.write(C); + if (Configuration.DEBUG) + log.fine("Encoding C (integrity checksum): " + Util.dumpString(C)); + } + result = out.toByteArray(); + } + catch (IOException x) + { + if (x instanceof SaslException) + throw (SaslException) x; + throw new SaslException("engineWrap()", x); + } + if (Configuration.DEBUG) + log.exiting(this.getClass().getName(), "engineWrap"); + return result; + } + + protected String getNegotiatedQOP() + { + if (inMac != null) + { + if (inCipher != null) + return Registry.QOP_AUTH_CONF; + return Registry.QOP_AUTH_INT; + } + return Registry.QOP_AUTH; + } + + protected String getNegotiatedStrength() + { + if (inMac != null) + { + if (inCipher != null) + return Registry.STRENGTH_HIGH; + return Registry.STRENGTH_MEDIUM; + } + return Registry.STRENGTH_LOW; + } + + protected String getNegotiatedRawSendSize() + { + return String.valueOf(rawSendSize); + } + + protected String getReuse() + { + return Registry.REUSE_TRUE; + } + + private byte[] sendIdentities() throws SaslException + { + if (Configuration.DEBUG) + log.entering(this.getClass().getName(), "sendIdentities"); + // If necessary, prompt the client for the username and password + getUsernameAndPassword(); + if (Configuration.DEBUG) + { + log.fine("Password: \"" + new String(password.getPassword()) + "\""); + log.fine("Encoding U (username): \"" + U + "\""); + log.fine("Encoding I (userid): \"" + authorizationID + "\""); + } + // if session re-use generate new 16-byte nonce + if (sid.length != 0) + { + cn = new byte[16]; + getDefaultPRNG().nextBytes(cn); + } + else + cn = new byte[0]; + final OutputBuffer frameOut = new OutputBuffer(); + try + { + frameOut.setText(U); + frameOut.setText(authorizationID); + frameOut.setEOS(sid); // session ID to re-use + frameOut.setOS(cn); // client nonce + frameOut.setEOS(channelBinding); + } + catch (IOException x) + { + if (x instanceof SaslException) + throw (SaslException) x; + throw new AuthenticationException("sendIdentities()", x); + } + final byte[] result = frameOut.encode(); + if (Configuration.DEBUG) + { + log.fine("C: " + Util.dumpString(result)); + log.fine(" U = " + U); + log.fine(" I = " + authorizationID); + log.fine("sid = " + new String(sid)); + log.fine(" cn = " + Util.dumpString(cn)); + log.fine("cCB = " + Util.dumpString(channelBinding)); + log.exiting(this.getClass().getName(), "sendIdentities"); + } + return result; + } + + private byte[] sendPublicKey(final byte[] input) throws SaslException + { + if (Configuration.DEBUG) + { + log.entering(this.getClass().getName(), "sendPublicKey"); + log.fine("S: " + Util.dumpString(input)); + } + // Server sends [00], N, g, s, B, L + // or [FF], sn, sCB + final InputBuffer frameIn = new InputBuffer(input); + final int ack; + try + { + ack = (int) frameIn.getScalar(1); + if (ack == 0x00) // new session + { + N = frameIn.getMPI(); + if (Configuration.DEBUG) + log.fine("Got N (modulus): " + Util.dump(N)); + g = frameIn.getMPI(); + if (Configuration.DEBUG) + log.fine("Got g (generator): " + Util.dump(g)); + s = frameIn.getOS(); + if (Configuration.DEBUG) + log.fine("Got s (salt): " + Util.dumpString(s)); + B = frameIn.getMPI(); + if (Configuration.DEBUG) + log.fine("Got B (server ephermeral public key): " + Util.dump(B)); + L = frameIn.getText(); + if (Configuration.DEBUG) + log.fine("Got L (available options): \"" + L + "\""); + } + else if (ack == 0xFF) // session re-use + { + sn = frameIn.getOS(); + if (Configuration.DEBUG) + log.fine("Got sn (server nonce): " + Util.dumpString(sn)); + sCB = frameIn.getEOS(); + if (Configuration.DEBUG) + log.fine("Got sCB (server channel binding): " + Util.dumpString(sCB)); + } + else // unexpected scalar + throw new SaslException("sendPublicKey(): Invalid scalar (" + ack + + ") in server's request"); + } + catch (IOException x) + { + if (x instanceof SaslException) + throw (SaslException) x; + throw new SaslException("sendPublicKey()", x); + } + if (ack == 0x00) + { // new session --------------------------------------- + o = createO(L.toLowerCase()); // do this first to initialise the SRP hash + final byte[] pBytes; // use ASCII encoding to inter-operate w/ non-java + pBytes = password.getBytes(); + // ---------------------------------------------------------------------- + final HashMap mapA = new HashMap(); + mapA.put(SRP6KeyAgreement.HASH_FUNCTION, srp.getAlgorithm()); + mapA.put(SRP6KeyAgreement.USER_IDENTITY, U); + mapA.put(SRP6KeyAgreement.USER_PASSWORD, pBytes); + try + { + clientHandler.init(mapA); + clientHandler.processMessage(null); + } + catch (KeyAgreementException x) + { + throw new SaslException("sendPublicKey()", x); + } + // ------------------------------------------------------------------- + try + { + OutgoingMessage out = new OutgoingMessage(); + out.writeMPI(N); + out.writeMPI(g); + out.writeMPI(new BigInteger(1, s)); + out.writeMPI(B); + IncomingMessage in = new IncomingMessage(out.toByteArray()); + out = clientHandler.processMessage(in); + in = new IncomingMessage(out.toByteArray()); + A = in.readMPI(); + K = clientHandler.getSharedSecret(); + } + catch (KeyAgreementException x) + { + throw new SaslException("sendPublicKey()", x); + } + // ------------------------------------------------------------------- + if (Configuration.DEBUG) + { + log.fine("K: " + Util.dumpString(K)); + log.fine("Encoding A (client ephemeral public key): " + Util.dump(A)); + } + try + { + M1 = srp.generateM1(N, g, U, s, A, B, K, authorizationID, L, cn, + channelBinding); + } + catch (UnsupportedEncodingException x) + { + throw new AuthenticationException("sendPublicKey()", x); + } + if (Configuration.DEBUG) + { + log.fine("Encoding o (client chosen options): \"" + o + "\""); + log.fine("Encoding cIV (client IV): \"" + Util.dumpString(cIV) + "\""); + } + final OutputBuffer frameOut = new OutputBuffer(); + try + { + frameOut.setMPI(A); + frameOut.setOS(M1); + frameOut.setText(o); + frameOut.setOS(cIV); + } + catch (IOException x) + { + if (x instanceof SaslException) + throw (SaslException) x; + throw new AuthenticationException("sendPublicKey()", x); + } + final byte[] result = frameOut.encode(); + if (Configuration.DEBUG) + { + log.fine("New session, or session re-use rejected..."); + log.fine("C: " + Util.dumpString(result)); + log.fine(" A = 0x" + A.toString(16)); + log.fine(" M1 = " + Util.dumpString(M1)); + log.fine(" o = " + o); + log.fine("cIV = " + Util.dumpString(cIV)); + log.exiting(this.getClass().getName(), "sendPublicKey"); + } + return result; + } + else // session re-use accepted ------------------------------------------- + { + setupSecurityServices(true); + if (Configuration.DEBUG) + { + log.fine("Session re-use accepted..."); + log.exiting(this.getClass().getName(), "sendPublicKey"); + } + return null; + } + } + + private byte[] receiveEvidence(byte[] input) throws SaslException + { + if (Configuration.DEBUG) + { + log.entering(this.getClass().getName(), "receiveEvidence"); + log.fine("S: " + Util.dumpString(input)); + } + // Server send M2, sIV, sCB, sid, ttl + final InputBuffer frameIn = new InputBuffer(input); + try + { + M2 = frameIn.getOS(); + if (Configuration.DEBUG) + log.fine("Got M2 (server evidence): " + Util.dumpString(M2)); + sIV = frameIn.getOS(); + if (Configuration.DEBUG) + log.fine("Got sIV (server IV): " + Util.dumpString(sIV)); + sid = frameIn.getEOS(); + if (Configuration.DEBUG) + log.fine("Got sid (session ID): " + new String(sid)); + ttl = (int) frameIn.getScalar(4); + if (Configuration.DEBUG) + log.fine("Got ttl (session time-to-live): " + ttl + "sec."); + sCB = frameIn.getEOS(); + if (Configuration.DEBUG) + log.fine("Got sCB (server channel binding): " + Util.dumpString(sCB)); + } + catch (IOException x) + { + if (x instanceof SaslException) + throw (SaslException) x; + throw new AuthenticationException("receiveEvidence()", x); + } + + final byte[] expected; + try + { + expected = srp.generateM2(A, M1, K, U, authorizationID, o, sid, ttl, + cIV, sIV, sCB); + } + catch (UnsupportedEncodingException x) + { + throw new AuthenticationException("receiveEvidence()", x); + } + if (Configuration.DEBUG) + log.fine("Expected: " + Util.dumpString(expected)); + if (! Arrays.equals(M2, expected)) + throw new AuthenticationException("M2 mismatch"); + setupSecurityServices(false); + if (Configuration.DEBUG) + log.exiting(this.getClass().getName(), "receiveEvidence"); + return null; + } + + private void getUsernameAndPassword() throws AuthenticationException + { + try + { + if ((! properties.containsKey(Registry.SASL_USERNAME)) + && (! properties.containsKey(Registry.SASL_PASSWORD))) + { + final NameCallback nameCB; + final String defaultName = System.getProperty("user.name"); + if (defaultName == null) + nameCB = new NameCallback("username: "); + else + nameCB = new NameCallback("username: ", defaultName); + final PasswordCallback pwdCB = new PasswordCallback("password: ", + false); + handler.handle(new Callback[] { nameCB, pwdCB }); + U = nameCB.getName(); + password = new Password(pwdCB.getPassword()); + } + else + { + if (properties.containsKey(Registry.SASL_USERNAME)) + this.U = (String) properties.get(Registry.SASL_USERNAME); + else + { + final NameCallback nameCB; + final String defaultName = System.getProperty("user.name"); + if (defaultName == null) + nameCB = new NameCallback("username: "); + else + nameCB = new NameCallback("username: ", defaultName); + this.handler.handle(new Callback[] { nameCB }); + this.U = nameCB.getName(); + } + + if (properties.containsKey(Registry.SASL_PASSWORD)) + { + Object pw = properties.get(Registry.SASL_PASSWORD); + if (pw instanceof char[]) + password = new Password((char[]) pw); + else if (pw instanceof Password) + password = (Password) pw; + else if (pw instanceof String) + password = new Password(((String) pw).toCharArray()); + else + throw new IllegalArgumentException(pw.getClass().getName() + + "is not a valid password class"); + } + else + { + final PasswordCallback pwdCB = new PasswordCallback("password: ", + false); + this.handler.handle(new Callback[] { pwdCB }); + password = new Password(pwdCB.getPassword()); + } + } + + if (U == null) + throw new AuthenticationException("null username supplied"); + if (password == null) + throw new AuthenticationException("null password supplied"); + } + catch (UnsupportedCallbackException x) + { + throw new AuthenticationException("getUsernameAndPassword()", x); + } + catch (IOException x) + { + throw new AuthenticationException("getUsernameAndPassword()", x); + } + } + + // We go through the list of available services and for each available one + // we decide whether or not we want it enabled, based on properties passed + // to us by the client. + private String createO(final String aol) throws AuthenticationException + { + if (Configuration.DEBUG) + log.entering(this.getClass().getName(), "createO", aol); + boolean replaydetectionAvailable = false; + boolean integrityAvailable = false; + boolean confidentialityAvailable = false; + String option, mandatory = SRPRegistry.DEFAULT_MANDATORY; + int i; + + String mdName = SRPRegistry.SRP_DEFAULT_DIGEST_NAME; + final StringTokenizer st = new StringTokenizer(aol, ","); + while (st.hasMoreTokens()) + { + option = st.nextToken(); + if (option.startsWith(SRPRegistry.OPTION_SRP_DIGEST + "=")) + { + option = option.substring(option.indexOf('=') + 1); + if (Configuration.DEBUG) + log.fine("mda: <" + option + ">"); + for (i = 0; i < SRPRegistry.INTEGRITY_ALGORITHMS.length; i++) + if (SRPRegistry.SRP_ALGORITHMS[i].equals(option)) + { + mdName = option; + break; + } + } + else if (option.equals(SRPRegistry.OPTION_REPLAY_DETECTION)) + replaydetectionAvailable = true; + else if (option.startsWith(SRPRegistry.OPTION_INTEGRITY + "=")) + { + option = option.substring(option.indexOf('=') + 1); + if (Configuration.DEBUG) + log.fine("ialg: <" + option + ">"); + for (i = 0; i < SRPRegistry.INTEGRITY_ALGORITHMS.length; i++) + if (SRPRegistry.INTEGRITY_ALGORITHMS[i].equals(option)) + { + chosenIntegrityAlgorithm = option; + integrityAvailable = true; + break; + } + } + else if (option.startsWith(SRPRegistry.OPTION_CONFIDENTIALITY + "=")) + { + option = option.substring(option.indexOf('=') + 1); + if (Configuration.DEBUG) + log.fine("calg: <" + option + ">"); + for (i = 0; i < SRPRegistry.CONFIDENTIALITY_ALGORITHMS.length; i++) + if (SRPRegistry.CONFIDENTIALITY_ALGORITHMS[i].equals(option)) + { + chosenConfidentialityAlgorithm = option; + confidentialityAvailable = true; + break; + } + } + else if (option.startsWith(SRPRegistry.OPTION_MANDATORY + "=")) + mandatory = option.substring(option.indexOf('=') + 1); + else if (option.startsWith(SRPRegistry.OPTION_MAX_BUFFER_SIZE + "=")) + { + final String maxBufferSize = option.substring(option.indexOf('=') + 1); + try + { + rawSendSize = Integer.parseInt(maxBufferSize); + if (rawSendSize > Registry.SASL_BUFFER_MAX_LIMIT + || rawSendSize < 1) + throw new AuthenticationException( + "Illegal value for 'maxbuffersize' option"); + } + catch (NumberFormatException x) + { + throw new AuthenticationException( + SRPRegistry.OPTION_MAX_BUFFER_SIZE + "=" + maxBufferSize, x); + } + } + } + String s; + Boolean flag; + s = (String) properties.get(SRPRegistry.SRP_REPLAY_DETECTION); + flag = Boolean.valueOf(s); + replayDetection = replaydetectionAvailable && flag.booleanValue(); + s = (String) properties.get(SRPRegistry.SRP_INTEGRITY_PROTECTION); + flag = Boolean.valueOf(s); + boolean integrity = integrityAvailable && flag.booleanValue(); + s = (String) properties.get(SRPRegistry.SRP_CONFIDENTIALITY); + flag = Boolean.valueOf(s); + boolean confidentiality = confidentialityAvailable && flag.booleanValue(); + // make sure we do the right thing + if (SRPRegistry.OPTION_REPLAY_DETECTION.equals(mandatory)) + { + replayDetection = true; + integrity = true; + } + else if (SRPRegistry.OPTION_INTEGRITY.equals(mandatory)) + integrity = true; + else if (SRPRegistry.OPTION_CONFIDENTIALITY.equals(mandatory)) + confidentiality = true; + + if (replayDetection) + { + if (chosenIntegrityAlgorithm == null) + throw new AuthenticationException( + "Replay detection is required but no integrity protection " + + "algorithm was chosen"); + } + if (integrity) + { + if (chosenIntegrityAlgorithm == null) + throw new AuthenticationException( + "Integrity protection is required but no algorithm was chosen"); + } + if (confidentiality) + { + if (chosenConfidentialityAlgorithm == null) + throw new AuthenticationException( + "Confidentiality protection is required but no algorithm was chosen"); + } + // 1. check if we'll be using confidentiality; if not set IV to 0-byte + if (chosenConfidentialityAlgorithm == null) + cIV = new byte[0]; + else + { + // 2. get the block size of the cipher + final IBlockCipher cipher = CipherFactory.getInstance(chosenConfidentialityAlgorithm); + if (cipher == null) + throw new AuthenticationException("createO()", + new NoSuchAlgorithmException()); + final int blockSize = cipher.defaultBlockSize(); + // 3. generate random iv + cIV = new byte[blockSize]; + getDefaultPRNG().nextBytes(cIV); + } + srp = SRP.instance(mdName); + // Now create the options list specifying which of the available options + // we have chosen. + + // For now we just select the defaults. Later we need to add support for + // properties (perhaps in a file) where a user can specify the list of + // algorithms they would prefer to use. + final CPStringBuilder sb = new CPStringBuilder(); + sb.append(SRPRegistry.OPTION_SRP_DIGEST) + .append("=").append(mdName).append(","); + if (replayDetection) + sb.append(SRPRegistry.OPTION_REPLAY_DETECTION).append(","); + if (integrity) + sb.append(SRPRegistry.OPTION_INTEGRITY) + .append("=").append(chosenIntegrityAlgorithm).append(","); + if (confidentiality) + sb.append(SRPRegistry.OPTION_CONFIDENTIALITY) + .append("=").append(chosenConfidentialityAlgorithm).append(","); + + final String result = sb.append(SRPRegistry.OPTION_MAX_BUFFER_SIZE) + .append("=").append(Registry.SASL_BUFFER_MAX_LIMIT) + .toString(); + if (Configuration.DEBUG) + log.exiting(this.getClass().getName(), "createO", result); + return result; + } + + private void setupSecurityServices(final boolean sessionReUse) + throws SaslException + { + complete = true; // signal end of authentication phase + if (! sessionReUse) + { + outCounter = inCounter = 0; + // instantiate cipher if confidentiality protection filter is active + if (chosenConfidentialityAlgorithm != null) + { + if (Configuration.DEBUG) + log.fine("Activating confidentiality protection filter"); + inCipher = CALG.getInstance(chosenConfidentialityAlgorithm); + outCipher = CALG.getInstance(chosenConfidentialityAlgorithm); + } + // instantiate hmacs if integrity protection filter is active + if (chosenIntegrityAlgorithm != null) + { + if (Configuration.DEBUG) + log.fine("Activating integrity protection filter"); + inMac = IALG.getInstance(chosenIntegrityAlgorithm); + outMac = IALG.getInstance(chosenIntegrityAlgorithm); + } + } + else // same session new Keys + K = srp.generateKn(K, cn, sn); + + final KDF kdf = KDF.getInstance(K); + // initialise in/out ciphers if confidentiality protection is used + if (inCipher != null) + { + inCipher.init(kdf, sIV, Direction.REVERSED); + outCipher.init(kdf, cIV, Direction.FORWARD); + } + // initialise in/out macs if integrity protection is used + if (inMac != null) + { + inMac.init(kdf); + outMac.init(kdf); + } + if (sid != null && sid.length != 0) + { // update the security context and save in map + if (Configuration.DEBUG) + log.fine("Updating security context for UID = " + uid); + ClientStore.instance().cacheSession(uid, + ttl, + new SecurityContext(srp.getAlgorithm(), + sid, + K, + cIV, + sIV, + replayDetection, + inCounter, + outCounter, + inMac, outMac, + inCipher, + outCipher)); + } + } + + private PRNG getDefaultPRNG() + { + if (prng == null) + prng = PRNG.getInstance(); + return prng; + } +} diff --git a/libjava/classpath/gnu/javax/crypto/sasl/srp/SRPRegistry.java b/libjava/classpath/gnu/javax/crypto/sasl/srp/SRPRegistry.java new file mode 100644 index 000000000..b6d24cf14 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/sasl/srp/SRPRegistry.java @@ -0,0 +1,165 @@ +/* SRPRegistry.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.sasl.srp; + +import gnu.java.security.Registry; + +/** + * A list of key names designating the values exchanged between the server + * and client in an SRP communication authentication phase. + */ +public interface SRPRegistry +{ + /** Indices of (N, g) parameter values for SRP (.conf) password database. */ + String N_2048_BITS = "1"; + String N_1536_BITS = "2"; + String N_1280_BITS = "3"; + String N_1024_BITS = "4"; + String N_768_BITS = "5"; + String N_640_BITS = "6"; + String N_512_BITS = "7"; + /** Available hash algorithms for all SRP calculations. */ + String[] SRP_ALGORITHMS = { + Registry.SHA160_HASH, // the default one + Registry.MD5_HASH, + Registry.RIPEMD128_HASH, + Registry.RIPEMD160_HASH, + + Registry.SHA256_HASH, + Registry.SHA384_HASH, + Registry.SHA512_HASH }; + /** + * The name of the default message digest algorithm to use when no name is + * explicitely given. In this implementation it is the <b>first</b> among + * those supported; i.e. the algorithm at index position #0: SHA with + * 160-bit output. + */ + String SRP_DEFAULT_DIGEST_NAME = SRP_ALGORITHMS[0]; + /** + * The property name of the message digest algorithm name to use in a given + * SRP incarnation. + */ + String SRP_DIGEST_NAME = "srp.digest.name"; + /** The public shared modulus: n. */ + String SHARED_MODULUS = "srp.N"; + /** The GF generator used: g. */ + String FIELD_GENERATOR = "srp.g"; + /** The list of server's available security options. */ + String AVAILABLE_OPTIONS = "srp.L"; + /** The client's chosen security options. */ + String CHOSEN_OPTIONS = "srp.o"; + /** The client's username. */ + String USER_NAME = "srp.U"; + /** The client's authorization ID. */ + String USER_ROLE = "srp.I"; + /** The user's salt. */ + String USER_SALT = "srp.s"; + /** The user's password verifier. */ + String PASSWORD_VERIFIER = "srp.v"; + /** The client's public ephemeral exponent: A. */ + String CLIENT_PUBLIC_KEY = "srp.A"; + /** The server's public ephemeral exponent: B. */ + String SERVER_PUBLIC_KEY = "srp.B"; + /** The client's evidence: M1. */ + String CLIENT_EVIDENCE = "srp.M1"; + /** The server's evidence: M2. */ + String SERVER_EVIDENCE = "srp.M2"; + /** Name of underlying hash algorithm for use with all SRP calculations. */ + String SRP_HASH = "gnu.crypto.sasl.srp.hash"; + /** Name of SRP mandatory service property. */ + String SRP_MANDATORY = "gnu.crypto.sasl.srp.mandatory"; + /** Name of SRP replay detection property. */ + String SRP_REPLAY_DETECTION = "gnu.crypto.sasl.srp.replay.detection"; + /** Name of SRP integrity protection property. */ + String SRP_INTEGRITY_PROTECTION = "gnu.crypto.sasl.srp.integrity"; + /** Name of SRP confidentiality protection property. */ + String SRP_CONFIDENTIALITY = "gnu.crypto.sasl.srp.confidentiality"; + /** Name of the main SRP password file pathname property. */ + String PASSWORD_FILE = "gnu.crypto.sasl.srp.password.file"; + /** + * Name of the SRP password database property --a reference to + * {@link PasswordFile} object. + */ + String PASSWORD_DB = "gnu.crypto.sasl.srp.password.db"; + /** Default fully qualified pathname of the SRP password file. */ + String DEFAULT_PASSWORD_FILE = "/etc/tpasswd"; + /** Default value for replay detection security service. */ + boolean DEFAULT_REPLAY_DETECTION = true; + /** Default value for integrity protection security service. */ + boolean DEFAULT_INTEGRITY = true; // implied by the previous option + /** Default value for confidentiality protection security service. */ + boolean DEFAULT_CONFIDENTIALITY = false; + // constants defining HMAC names + String HMAC_SHA1 = "hmac-sha1"; + String HMAC_MD5 = "hmac-md5"; + String HMAC_RIPEMD_160 = "hmac-ripemd-160"; + /** Available HMAC algorithms for integrity protection. */ + String[] INTEGRITY_ALGORITHMS = { HMAC_SHA1, HMAC_MD5, HMAC_RIPEMD_160 }; + // constants defining Cipher names + String AES = "aes"; + String BLOWFISH = "blowfish"; + /** Available Cipher algorithms for confidentiality protection. */ + String[] CONFIDENTIALITY_ALGORITHMS = { AES, BLOWFISH }; + /** String for mandatory replay detection. */ + String OPTION_MANDATORY = "mandatory"; + /** String for mda: the SRP digest algorithm name. */ + String OPTION_SRP_DIGEST = "mda"; + /** String for mandatory replay detection. */ + String OPTION_REPLAY_DETECTION = "replay_detection"; + /** String for mandatory integrity protection. */ + String OPTION_INTEGRITY = "integrity"; + /** String for mandatory confidentiality protection. */ + String OPTION_CONFIDENTIALITY = "confidentiality"; + /** String for mandatory replay detection. */ + String OPTION_MAX_BUFFER_SIZE = "maxbuffersize"; + /** String for no mandatory security service. */ + String MANDATORY_NONE = "none"; + /** Default mandatory security service required. */ + String DEFAULT_MANDATORY = OPTION_REPLAY_DETECTION; + /** Name of the UID field in the plain password file. */ + String MD_NAME_FIELD = "srp.md.name"; + /** Name of the GID field in the plain password file. */ + String USER_VERIFIER_FIELD = "srp.user.verifier"; + /** Name of the GECOS field in the plain password file. */ + String SALT_FIELD = "srp.salt"; + /** Name of the SHELL field in the plain password file. */ + String CONFIG_NDX_FIELD = "srp.config.ndx"; + /** Minimum bitlength of the SRP public modulus. */ + int MINIMUM_MODULUS_BITLENGTH = 512; +} diff --git a/libjava/classpath/gnu/javax/crypto/sasl/srp/SRPServer.java b/libjava/classpath/gnu/javax/crypto/sasl/srp/SRPServer.java new file mode 100644 index 000000000..fca5c3bf3 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/sasl/srp/SRPServer.java @@ -0,0 +1,842 @@ +/* SRPServer.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.sasl.srp; + +import gnu.java.lang.CPStringBuilder; + +import gnu.java.security.Configuration; +import gnu.java.security.Registry; +import gnu.java.security.util.PRNG; +import gnu.java.security.util.Util; +import gnu.javax.crypto.assembly.Direction; +import gnu.javax.crypto.cipher.CipherFactory; +import gnu.javax.crypto.cipher.IBlockCipher; +import gnu.javax.crypto.key.IKeyAgreementParty; +import gnu.javax.crypto.key.IncomingMessage; +import gnu.javax.crypto.key.KeyAgreementException; +import gnu.javax.crypto.key.KeyAgreementFactory; +import gnu.javax.crypto.key.OutgoingMessage; +import gnu.javax.crypto.key.srp6.SRP6KeyAgreement; +import gnu.javax.crypto.sasl.IllegalMechanismStateException; +import gnu.javax.crypto.sasl.InputBuffer; +import gnu.javax.crypto.sasl.IntegrityException; +import gnu.javax.crypto.sasl.OutputBuffer; +import gnu.javax.crypto.sasl.ServerMechanism; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.UnsupportedEncodingException; +import java.math.BigInteger; +import java.util.Arrays; +import java.util.HashMap; +import java.util.StringTokenizer; +import java.util.logging.Logger; + +import javax.security.sasl.AuthenticationException; +import javax.security.sasl.SaslException; +import javax.security.sasl.SaslServer; + +/** + * The SASL-SRP server-side mechanism. + */ +public class SRPServer + extends ServerMechanism + implements SaslServer +{ + private static final Logger log = Logger.getLogger(SRPServer.class.getName()); + private String U = null; // client's username + private BigInteger N, g, A, B; + private byte[] s; // salt + private byte[] cIV, sIV; // client+server IVs, when confidentiality is on + private byte[] cn, sn; // client's and server's nonce + private SRP srp; // SRP algorithm instance used by this server + private byte[] sid; // session ID when re-used + private int ttl = 360; // session time-to-live in seconds + private byte[] cCB; // peer's channel binding' + private String mandatory; // List of available options + private String L = null; + private String o; + private String chosenIntegrityAlgorithm; + private String chosenConfidentialityAlgorithm; + private int rawSendSize = Registry.SASL_BUFFER_MAX_LIMIT; + private byte[] K; // shared session key + private boolean replayDetection = true; // whether Replay Detection is on + private int inCounter = 0; // messages sequence numbers + private int outCounter = 0; + private IALG inMac, outMac; // if !null, use for integrity + private CALG inCipher, outCipher; // if !null, use for confidentiality + private IKeyAgreementParty serverHandler = + KeyAgreementFactory.getPartyBInstance(Registry.SRP_SASL_KA); + /** Our default source of randomness. */ + private PRNG prng = null; + + public SRPServer() + { + super(Registry.SASL_SRP_MECHANISM); + } + + protected void initMechanism() throws SaslException + { + // TODO: + // we must have a means to map a given username to a preferred + // SRP hash algorithm; otherwise we end up using _always_ SHA. + // for the time being get it from the mechanism properties map + // and apply it for all users. + final String mda = (String) properties.get(SRPRegistry.SRP_HASH); + srp = SRP.instance(mda == null ? SRPRegistry.SRP_DEFAULT_DIGEST_NAME : mda); + } + + protected void resetMechanism() throws SaslException + { + s = null; + A = B = null; + K = null; + inMac = outMac = null; + inCipher = outCipher = null; + sid = null; + } + + public byte[] evaluateResponse(final byte[] response) throws SaslException + { + switch (state) + { + case 0: + if (response == null) + return null; + state++; + return sendProtocolElements(response); + case 1: + if (! complete) + { + state++; + return sendEvidence(response); + } + // else fall through + default: + throw new IllegalMechanismStateException("evaluateResponse()"); + } + } + + protected byte[] engineUnwrap(final byte[] incoming, final int offset, + final int len) throws SaslException + { + if (Configuration.DEBUG) + log.entering(this.getClass().getName(), "engineUnwrap"); + if (inMac == null && inCipher == null) + throw new IllegalStateException("connection is not protected"); + if (Configuration.DEBUG) + log.fine("Incoming buffer (before security): " + + Util.dumpString(incoming, offset, len)); + // at this point one, or both, of confidentiality and integrity protection + // services are active. + final byte[] result; + try + { + if (inMac != null) + { // integrity bytes are at the end of the stream + final int macBytesCount = inMac.length(); + final int payloadLength = len - macBytesCount; + final byte[] received_mac = new byte[macBytesCount]; + System.arraycopy(incoming, offset + payloadLength, received_mac, 0, + macBytesCount); + if (Configuration.DEBUG) + log.fine("Got C (received MAC): " + Util.dumpString(received_mac)); + inMac.update(incoming, offset, payloadLength); + if (replayDetection) + { + inCounter++; + if (Configuration.DEBUG) + log.fine("inCounter=" + String.valueOf(inCounter)); + inMac.update(new byte[] { + (byte)(inCounter >>> 24), + (byte)(inCounter >>> 16), + (byte)(inCounter >>> 8), + (byte) inCounter }); + } + final byte[] computed_mac = inMac.doFinal(); + if (Configuration.DEBUG) + log.fine("Computed MAC: " + Util.dumpString(computed_mac)); + if (! Arrays.equals(received_mac, computed_mac)) + throw new IntegrityException("engineUnwrap()"); + // deal with the payload, which can be either plain or encrypted + if (inCipher != null) + result = inCipher.doFinal(incoming, offset, payloadLength); + else + { + result = new byte[payloadLength]; + System.arraycopy(incoming, offset, result, 0, result.length); + } + } + else // no integrity protection; just confidentiality + result = inCipher.doFinal(incoming, offset, len); + } + catch (IOException x) + { + if (x instanceof SaslException) + throw (SaslException) x; + throw new SaslException("engineUnwrap()", x); + } + if (Configuration.DEBUG) + { + log.fine("Incoming buffer (after security): " + Util.dumpString(result)); + log.exiting(this.getClass().getName(), "engineUnwrap"); + } + return result; + } + + protected byte[] engineWrap(final byte[] outgoing, final int offset, + final int len) throws SaslException + { + if (Configuration.DEBUG) + log.entering(this.getClass().getName(), "engineWrap"); + if (outMac == null && outCipher == null) + throw new IllegalStateException("connection is not protected"); + if (Configuration.DEBUG) + { + log.fine("Outgoing buffer (before security) (hex): " + + Util.dumpString(outgoing, offset, len)); + log.fine("Outgoing buffer (before security) (str): \"" + + new String(outgoing, offset, len) + "\""); + } + // at this point one, or both, of confidentiality and integrity protection + // services are active. + byte[] result; + try + { + final ByteArrayOutputStream out = new ByteArrayOutputStream(); + if (outCipher != null) + { + result = outCipher.doFinal(outgoing, offset, len); + if (Configuration.DEBUG) + log.fine("Encoding c (encrypted plaintext): " + + Util.dumpString(result)); + out.write(result); + if (outMac != null) + { + outMac.update(result); + if (replayDetection) + { + outCounter++; + if (Configuration.DEBUG) + log.fine("outCounter=" + outCounter); + outMac.update(new byte[] { + (byte)(outCounter >>> 24), + (byte)(outCounter >>> 16), + (byte)(outCounter >>> 8), + (byte) outCounter }); + } + final byte[] C = outMac.doFinal(); + out.write(C); + if (Configuration.DEBUG) + log.fine("Encoding C (integrity checksum): " + Util.dumpString(C)); + } + // else ciphertext only; do nothing + } + else // no confidentiality; just integrity [+ replay detection] + { + if (Configuration.DEBUG) + log.fine("Encoding p (plaintext): " + + Util.dumpString(outgoing, offset, len)); + out.write(outgoing, offset, len); + outMac.update(outgoing, offset, len); + if (replayDetection) + { + outCounter++; + if (Configuration.DEBUG) + log.fine("outCounter=" + outCounter); + outMac.update(new byte[] { + (byte)(outCounter >>> 24), + (byte)(outCounter >>> 16), + (byte)(outCounter >>> 8), + (byte) outCounter }); + } + final byte[] C = outMac.doFinal(); + out.write(C); + if (Configuration.DEBUG) + log.fine("Encoding C (integrity checksum): " + Util.dumpString(C)); + } + result = out.toByteArray(); + } + catch (IOException x) + { + if (x instanceof SaslException) + throw (SaslException) x; + throw new SaslException("engineWrap()", x); + } + if (Configuration.DEBUG) + log.exiting(this.getClass().getName(), "engineWrap"); + return result; + } + + protected String getNegotiatedQOP() + { + if (inMac != null) + { + if (inCipher != null) + return Registry.QOP_AUTH_CONF; + return Registry.QOP_AUTH_INT; + } + return Registry.QOP_AUTH; + } + + protected String getNegotiatedStrength() + { + if (inMac != null) + { + if (inCipher != null) + return Registry.STRENGTH_HIGH; + return Registry.STRENGTH_MEDIUM; + } + return Registry.STRENGTH_LOW; + } + + protected String getNegotiatedRawSendSize() + { + return String.valueOf(rawSendSize); + } + + protected String getReuse() + { + return Registry.REUSE_TRUE; + } + + private byte[] sendProtocolElements(final byte[] input) throws SaslException + { + if (Configuration.DEBUG) + { + log.entering(this.getClass().getName(), "sendProtocolElements"); + log.fine("C: " + Util.dumpString(input)); + } + // Client send U, I, sid, cn + final InputBuffer frameIn = new InputBuffer(input); + try + { + U = frameIn.getText(); // Extract username + if (Configuration.DEBUG) + log.fine("Got U (username): \"" + U + "\""); + authorizationID = frameIn.getText(); // Extract authorisation ID + if (Configuration.DEBUG) + log.fine("Got I (userid): \"" + authorizationID + "\""); + sid = frameIn.getEOS(); + if (Configuration.DEBUG) + log.fine("Got sid (session ID): " + new String(sid)); + cn = frameIn.getOS(); + if (Configuration.DEBUG) + log.fine("Got cn (client nonce): " + Util.dumpString(cn)); + cCB = frameIn.getEOS(); + if (Configuration.DEBUG) + log.fine("Got cCB (client channel binding): " + Util.dumpString(cCB)); + } + catch (IOException x) + { + if (x instanceof SaslException) + throw (SaslException) x; + throw new AuthenticationException("sendProtocolElements()", x); + } + // do/can we re-use? + if (ServerStore.instance().isAlive(sid)) + { + final SecurityContext ctx = ServerStore.instance().restoreSession(sid); + srp = SRP.instance(ctx.getMdName()); + K = ctx.getK(); + cIV = ctx.getClientIV(); + sIV = ctx.getServerIV(); + replayDetection = ctx.hasReplayDetection(); + inCounter = ctx.getInCounter(); + outCounter = ctx.getOutCounter(); + inMac = ctx.getInMac(); + outMac = ctx.getOutMac(); + inCipher = ctx.getInCipher(); + outCipher = ctx.getOutCipher(); + if (sn == null || sn.length != 16) + sn = new byte[16]; + getDefaultPRNG().nextBytes(sn); + setupSecurityServices(false); + final OutputBuffer frameOut = new OutputBuffer(); + try + { + frameOut.setScalar(1, 0xFF); + frameOut.setOS(sn); + frameOut.setEOS(channelBinding); + } + catch (IOException x) + { + if (x instanceof SaslException) + throw (SaslException) x; + throw new AuthenticationException("sendProtocolElements()", x); + } + final byte[] result = frameOut.encode(); + if (Configuration.DEBUG) + { + log.fine("Old session..."); + log.fine("S: " + Util.dumpString(result)); + log.fine(" sn = " + Util.dumpString(sn)); + log.fine(" sCB = " + Util.dumpString(channelBinding)); + log.exiting(this.getClass().getName(), "sendProtocolElements"); + } + return result; + } + else + { // new session + authenticator.activate(properties); + // ------------------------------------------------------------------- + final HashMap mapB = new HashMap(); + mapB.put(SRP6KeyAgreement.HASH_FUNCTION, srp.getAlgorithm()); + mapB.put(SRP6KeyAgreement.HOST_PASSWORD_DB, authenticator); + try + { + serverHandler.init(mapB); + OutgoingMessage out = new OutgoingMessage(); + out.writeString(U); + IncomingMessage in = new IncomingMessage(out.toByteArray()); + out = serverHandler.processMessage(in); + in = new IncomingMessage(out.toByteArray()); + N = in.readMPI(); + g = in.readMPI(); + s = in.readMPI().toByteArray(); + B = in.readMPI(); + } + catch (KeyAgreementException x) + { + throw new SaslException("sendProtocolElements()", x); + } + // ------------------------------------------------------------------- + if (Configuration.DEBUG) + { + log.fine("Encoding N (modulus): " + Util.dump(N)); + log.fine("Encoding g (generator): " + Util.dump(g)); + log.fine("Encoding s (client's salt): " + Util.dumpString(s)); + log.fine("Encoding B (server ephemeral public key): " + Util.dump(B)); + } + // The server creates an options list (L), which consists of a + // comma-separated list of option strings that specify the security + // service options the server supports. + L = createL(); + if (Configuration.DEBUG) + { + log.fine("Encoding L (available options): \"" + L + "\""); + log.fine("Encoding sIV (server IV): " + Util.dumpString(sIV)); + } + final OutputBuffer frameOut = new OutputBuffer(); + try + { + frameOut.setScalar(1, 0x00); + frameOut.setMPI(N); + frameOut.setMPI(g); + frameOut.setOS(s); + frameOut.setMPI(B); + frameOut.setText(L); + } + catch (IOException x) + { + if (x instanceof SaslException) + throw (SaslException) x; + throw new AuthenticationException("sendProtocolElements()", x); + } + final byte[] result = frameOut.encode(); + if (Configuration.DEBUG) + { + log.fine("New session..."); + log.fine("S: " + Util.dumpString(result)); + log.fine(" N = 0x" + N.toString(16)); + log.fine(" g = 0x" + g.toString(16)); + log.fine(" s = " + Util.dumpString(s)); + log.fine(" B = 0x" + B.toString(16)); + log.fine(" L = " + L); + log.exiting(this.getClass().getName(), "sendProtocolElements"); + } + return result; + } + } + + private byte[] sendEvidence(final byte[] input) throws SaslException + { + if (Configuration.DEBUG) + { + log.entering(this.getClass().getName(), "sendEvidence"); + log.fine("C: " + Util.dumpString(input)); + } + // Client send A, M1, o, cIV + final InputBuffer frameIn = new InputBuffer(input); + final byte[] M1; + try + { + A = frameIn.getMPI(); // Extract client's ephemeral public key + if (Configuration.DEBUG) + log.fine("Got A (client ephemeral public key): " + Util.dump(A)); + M1 = frameIn.getOS(); // Extract evidence + if (Configuration.DEBUG) + log.fine("Got M1 (client evidence): " + Util.dumpString(M1)); + o = frameIn.getText(); // Extract client's options list + if (Configuration.DEBUG) + log.fine("Got o (client chosen options): \"" + o + "\""); + cIV = frameIn.getOS(); // Extract client's IV + if (Configuration.DEBUG) + log.fine("Got cIV (client IV): " + Util.dumpString(cIV)); + } + catch (IOException x) + { + if (x instanceof SaslException) + throw (SaslException) x; + throw new AuthenticationException("sendEvidence()", x); + } + // Parse client's options and set security layer variables + parseO(o); + // ---------------------------------------------------------------------- + try + { + final OutgoingMessage out = new OutgoingMessage(); + out.writeMPI(A); + final IncomingMessage in = new IncomingMessage(out.toByteArray()); + serverHandler.processMessage(in); + K = serverHandler.getSharedSecret(); + } + catch (KeyAgreementException x) + { + throw new SaslException("sendEvidence()", x); + } + // ---------------------------------------------------------------------- + if (Configuration.DEBUG) + log.fine("K: " + Util.dumpString(K)); + final byte[] expected; + try + { + expected = srp.generateM1(N, g, U, s, A, B, K, authorizationID, L, cn, + cCB); + } + catch (UnsupportedEncodingException x) + { + throw new AuthenticationException("sendEvidence()", x); + } + // Verify client evidence + if (! Arrays.equals(M1, expected)) + throw new AuthenticationException("M1 mismatch"); + setupSecurityServices(true); + final byte[] M2; + try + { + M2 = srp.generateM2(A, M1, K, U, authorizationID, o, sid, ttl, cIV, + sIV, channelBinding); + } + catch (UnsupportedEncodingException x) + { + throw new AuthenticationException("sendEvidence()", x); + } + final OutputBuffer frameOut = new OutputBuffer(); + try + { + frameOut.setOS(M2); + frameOut.setOS(sIV); + frameOut.setEOS(sid); + frameOut.setScalar(4, ttl); + frameOut.setEOS(channelBinding); + } + catch (IOException x) + { + if (x instanceof SaslException) + throw (SaslException) x; + throw new AuthenticationException("sendEvidence()", x); + } + final byte[] result = frameOut.encode(); + if (Configuration.DEBUG) + { + log.fine("S: " + Util.dumpString(result)); + log.fine(" M2 = " + Util.dumpString(M2)); + log.fine(" sIV = " + Util.dumpString(sIV)); + log.fine(" sid = " + new String(sid)); + log.fine(" ttl = " + ttl); + log.fine(" sCB = " + Util.dumpString(channelBinding)); + log.exiting(this.getClass().getName(), "sendEvidence"); + } + return result; + } + + private String createL() + { + if (Configuration.DEBUG) + log.entering(this.getClass().getName(), "createL()"); + String s = (String) properties.get(SRPRegistry.SRP_MANDATORY); + if (s == null) + s = SRPRegistry.DEFAULT_MANDATORY; + + if (! SRPRegistry.MANDATORY_NONE.equals(s) + && ! SRPRegistry.OPTION_REPLAY_DETECTION.equals(s) + && ! SRPRegistry.OPTION_INTEGRITY.equals(s) + && ! SRPRegistry.OPTION_CONFIDENTIALITY.equals(s)) + { + if (Configuration.DEBUG) + log.fine("Unrecognised mandatory option (" + s + "). Using default..."); + s = SRPRegistry.DEFAULT_MANDATORY; + } + mandatory = s; + s = (String) properties.get(SRPRegistry.SRP_CONFIDENTIALITY); + final boolean confidentiality = (s == null ? SRPRegistry.DEFAULT_CONFIDENTIALITY + : Boolean.valueOf(s).booleanValue()); + s = (String) properties.get(SRPRegistry.SRP_INTEGRITY_PROTECTION); + boolean integrity = (s == null ? SRPRegistry.DEFAULT_INTEGRITY + : Boolean.valueOf(s).booleanValue()); + s = (String) properties.get(SRPRegistry.SRP_REPLAY_DETECTION); + final boolean replayDetection = (s == null ? SRPRegistry.DEFAULT_REPLAY_DETECTION + : Boolean.valueOf(s).booleanValue()); + final CPStringBuilder sb = new CPStringBuilder(); + sb.append(SRPRegistry.OPTION_SRP_DIGEST).append("=") + .append(srp.getAlgorithm()).append(","); + + if (! SRPRegistry.MANDATORY_NONE.equals(mandatory)) + sb.append(SRPRegistry.OPTION_MANDATORY) + .append("=").append(mandatory).append(","); + + if (replayDetection) + { + sb.append(SRPRegistry.OPTION_REPLAY_DETECTION).append(","); + // if replay detection is on then force integrity protection + integrity = true; + } + int i; + if (integrity) + { + for (i = 0; i < SRPRegistry.INTEGRITY_ALGORITHMS.length; i++) + sb.append(SRPRegistry.OPTION_INTEGRITY).append("=") + .append(SRPRegistry.INTEGRITY_ALGORITHMS[i]).append(","); + } + if (confidentiality) + { + IBlockCipher cipher; + for (i = 0; i < SRPRegistry.CONFIDENTIALITY_ALGORITHMS.length; i++) + { + cipher = CipherFactory.getInstance(SRPRegistry.CONFIDENTIALITY_ALGORITHMS[i]); + if (cipher != null) + sb.append(SRPRegistry.OPTION_CONFIDENTIALITY).append("=") + .append(SRPRegistry.CONFIDENTIALITY_ALGORITHMS[i]).append(","); + } + } + final String result = sb.append(SRPRegistry.OPTION_MAX_BUFFER_SIZE) + .append("=").append(Registry.SASL_BUFFER_MAX_LIMIT) + .toString(); + if (Configuration.DEBUG) + log.exiting(this.getClass().getName(), "createL"); + return result; + } + + // Parse client's options and set security layer variables + private void parseO(final String o) throws AuthenticationException + { + this.replayDetection = false; + boolean integrity = false; + boolean confidentiality = false; + String option; + int i; + + final StringTokenizer st = new StringTokenizer(o.toLowerCase(), ","); + while (st.hasMoreTokens()) + { + option = st.nextToken(); + if (Configuration.DEBUG) + log.fine("option: <" + option + ">"); + if (option.equals(SRPRegistry.OPTION_REPLAY_DETECTION)) + replayDetection = true; + else if (option.startsWith(SRPRegistry.OPTION_INTEGRITY + "=")) + { + if (integrity) + throw new AuthenticationException( + "Only one integrity algorithm may be chosen"); + option = option.substring(option.indexOf('=') + 1); + if (Configuration.DEBUG) + log.fine("algorithm: <" + option + ">"); + for (i = 0; i < SRPRegistry.INTEGRITY_ALGORITHMS.length; i++) + { + if (SRPRegistry.INTEGRITY_ALGORITHMS[i].equals(option)) + { + chosenIntegrityAlgorithm = option; + integrity = true; + break; + } + } + if (! integrity) + throw new AuthenticationException("Unknown integrity algorithm: " + + option); + } + else if (option.startsWith(SRPRegistry.OPTION_CONFIDENTIALITY + "=")) + { + if (confidentiality) + throw new AuthenticationException( + "Only one confidentiality algorithm may be chosen"); + option = option.substring(option.indexOf('=') + 1); + if (Configuration.DEBUG) + log.fine("algorithm: <" + option + ">"); + for (i = 0; i < SRPRegistry.CONFIDENTIALITY_ALGORITHMS.length; i++) + { + if (SRPRegistry.CONFIDENTIALITY_ALGORITHMS[i].equals(option)) + { + chosenConfidentialityAlgorithm = option; + confidentiality = true; + break; + } + } + if (! confidentiality) + throw new AuthenticationException("Unknown confidentiality algorithm: " + + option); + } + else if (option.startsWith(SRPRegistry.OPTION_MAX_BUFFER_SIZE + "=")) + { + final String maxBufferSize = option.substring(option.indexOf('=') + 1); + try + { + rawSendSize = Integer.parseInt(maxBufferSize); + if (rawSendSize > Registry.SASL_BUFFER_MAX_LIMIT + || rawSendSize < 1) + throw new AuthenticationException( + "Illegal value for 'maxbuffersize' option"); + } + catch (NumberFormatException x) + { + throw new AuthenticationException( + SRPRegistry.OPTION_MAX_BUFFER_SIZE + "=" + maxBufferSize, x); + } + } + } + // check if client did the right thing + if (replayDetection) + { + if (! integrity) + throw new AuthenticationException( + "Missing integrity protection algorithm but replay detection is chosen"); + } + if (mandatory.equals(SRPRegistry.OPTION_REPLAY_DETECTION)) + { + if (! replayDetection) + throw new AuthenticationException( + "Replay detection is mandatory but was not chosen"); + } + if (mandatory.equals(SRPRegistry.OPTION_INTEGRITY)) + { + if (! integrity) + throw new AuthenticationException( + "Integrity protection is mandatory but was not chosen"); + } + if (mandatory.equals(SRPRegistry.OPTION_CONFIDENTIALITY)) + { + if (! confidentiality) + throw new AuthenticationException( + "Confidentiality is mandatory but was not chosen"); + } + int blockSize = 0; + if (chosenConfidentialityAlgorithm != null) + { + final IBlockCipher cipher = CipherFactory.getInstance(chosenConfidentialityAlgorithm); + if (cipher != null) + blockSize = cipher.defaultBlockSize(); + else // should not happen + throw new AuthenticationException("Confidentiality algorithm (" + + chosenConfidentialityAlgorithm + + ") not available"); + } + sIV = new byte[blockSize]; + if (blockSize > 0) + getDefaultPRNG().nextBytes(sIV); + } + + private void setupSecurityServices(final boolean newSession) + throws SaslException + { + complete = true; // signal end of authentication phase + if (newSession) + { + outCounter = inCounter = 0; + // instantiate cipher if confidentiality protection filter is active + if (chosenConfidentialityAlgorithm != null) + { + if (Configuration.DEBUG) + log.fine("Activating confidentiality protection filter"); + inCipher = CALG.getInstance(chosenConfidentialityAlgorithm); + outCipher = CALG.getInstance(chosenConfidentialityAlgorithm); + } + // instantiate hmacs if integrity protection filter is active + if (chosenIntegrityAlgorithm != null) + { + if (Configuration.DEBUG) + log.fine("Activating integrity protection filter"); + inMac = IALG.getInstance(chosenIntegrityAlgorithm); + outMac = IALG.getInstance(chosenIntegrityAlgorithm); + } + // generate a new sid if at least integrity is used + sid = (inMac != null ? ServerStore.getNewSessionID() : new byte[0]); + } + else // same session new keys + K = srp.generateKn(K, cn, sn); + + final KDF kdf = KDF.getInstance(K); + // initialise in/out ciphers if confidentaility protection is used + if (inCipher != null) + { + outCipher.init(kdf, sIV, Direction.FORWARD); + inCipher.init(kdf, cIV, Direction.REVERSED); + } + // initialise in/out macs if integrity protection is used + if (inMac != null) + { + outMac.init(kdf); + inMac.init(kdf); + } + if (sid != null && sid.length != 0) + { // update the security context and save in map + if (Configuration.DEBUG) + log.fine("Updating security context for sid = " + new String(sid)); + ServerStore.instance().cacheSession(ttl, + new SecurityContext(srp.getAlgorithm(), + sid, + K, + cIV, + sIV, + replayDetection, + inCounter, + outCounter, + inMac, outMac, + inCipher, + outCipher)); + } + } + + private PRNG getDefaultPRNG() + { + if (prng == null) + prng = PRNG.getInstance(); + return prng; + } +} diff --git a/libjava/classpath/gnu/javax/crypto/sasl/srp/SecurityContext.java b/libjava/classpath/gnu/javax/crypto/sasl/srp/SecurityContext.java new file mode 100644 index 000000000..41ec57c81 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/sasl/srp/SecurityContext.java @@ -0,0 +1,140 @@ +/* SecurityContext.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.sasl.srp; + +/** + * A package-private placeholder for an SRP security context. + */ +class SecurityContext +{ + private String mdName; + private byte[] sid; + private byte[] K; + private byte[] cIV; + private byte[] sIV; + private boolean replayDetection; + private int inCounter; + private int outCounter; + private IALG inMac; + private IALG outMac; + private CALG inCipher; + private CALG outCipher; + + SecurityContext(final String mdName, final byte[] sid, final byte[] K, + final byte[] cIV, final byte[] sIV, + final boolean replayDetection, final int inCounter, + final int outCounter, final IALG inMac, final IALG outMac, + final CALG inCipher, final CALG outCipher) + { + super(); + + this.mdName = mdName; + this.sid = sid; + this.K = K; + this.cIV = cIV; + this.sIV = sIV; + this.replayDetection = replayDetection; + this.inCounter = inCounter; + this.outCounter = outCounter; + this.inMac = inMac; + this.outMac = outMac; + this.inCipher = inCipher; + this.outCipher = outCipher; + } + + String getMdName() + { + return mdName; + } + + byte[] getSID() + { + return sid; + } + + byte[] getK() + { + return K; + } + + byte[] getClientIV() + { + return cIV; + } + + byte[] getServerIV() + { + return sIV; + } + + boolean hasReplayDetection() + { + return replayDetection; + } + + int getInCounter() + { + return inCounter; + } + + int getOutCounter() + { + return outCounter; + } + + IALG getInMac() + { + return inMac; + } + + IALG getOutMac() + { + return outMac; + } + + CALG getInCipher() + { + return inCipher; + } + + CALG getOutCipher() + { + return outCipher; + } +} diff --git a/libjava/classpath/gnu/javax/crypto/sasl/srp/ServerStore.java b/libjava/classpath/gnu/javax/crypto/sasl/srp/ServerStore.java new file mode 100644 index 000000000..d98747324 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/sasl/srp/ServerStore.java @@ -0,0 +1,177 @@ +/* ServerStore.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.sasl.srp; + +import gnu.java.lang.CPStringBuilder; + +import java.util.HashMap; + +/** + * The server-side implementation of the SRP security context store. + */ +public class ServerStore +{ + /** The underlying singleton. */ + private static ServerStore singleton = null; + /** The map of sid --> Security Context record. */ + private static final HashMap sid2ssc = new HashMap(); + /** The map of sid --> Session timing record. */ + private static final HashMap sid2ttl = new HashMap(); + /** A synchronisation lock. */ + private static final Object lock = new Object(); + /** A counter to generate legible SIDs. */ + private static int counter = 0; + + /** Private constructor to enforce Singleton pattern. */ + private ServerStore() + { + super(); + + // TODO: add a cleaning timer thread + } + + /** + * Returns the classloader Singleton. + * + * @return the classloader Singleton instance. + */ + static synchronized final ServerStore instance() + { + if (singleton == null) + singleton = new ServerStore(); + return singleton; + } + + /** + * Returns a legible new session identifier. + * + * @return a new session identifier. + */ + static synchronized final byte[] getNewSessionID() + { + final String sid = String.valueOf(++counter); + return new CPStringBuilder("SID-") + .append("0000000000".substring(0, 10 - sid.length())).append(sid) + .toString().getBytes(); + } + + /** + * Returns a boolean flag indicating if the designated session is still alive + * or not. + * + * @param sid the identifier of the session to check. + * @return <code>true</code> if the designated session is still alive. + * <code>false</code> otherwise. + */ + boolean isAlive(final byte[] sid) + { + boolean result = false; + if (sid != null && sid.length != 0) + { + synchronized (lock) + { + final String key = new String(sid); + final StoreEntry ctx = (StoreEntry) sid2ttl.get(key); + if (ctx != null) + { + result = ctx.isAlive(); + if (! result) // invalidate it en-passant + { + sid2ssc.remove(key); + sid2ttl.remove(key); + } + } + } + } + return result; + } + + /** + * Records a mapping between a session identifier and the Security Context of + * the designated SRP server mechanism instance. + * + * @param ttl the session's Time-To-Live indicator (in seconds). + * @param ctx the server's security context. + */ + void cacheSession(final int ttl, final SecurityContext ctx) + { + synchronized (lock) + { + final String key = new String(ctx.getSID()); + sid2ssc.put(key, ctx); + sid2ttl.put(key, new StoreEntry(ttl)); + } + } + + /** + * Updates the mapping between the designated session identifier and the + * designated server's SASL Security Context. In the process, computes and + * return the underlying mechanism server's evidence that shall be returned to + * the client in a session re-use exchange. + * + * @param sid the identifier of the session to restore. + * @return an SRP server's security context. + */ + SecurityContext restoreSession(final byte[] sid) + { + final String key = new String(sid); + final SecurityContext result; + synchronized (lock) + { + result = (SecurityContext) sid2ssc.remove(key); + sid2ttl.remove(key); + } + return result; + } + + /** + * Removes all information related to the designated session ID. + * + * @param sid the identifier of the seesion to invalidate. + */ + void invalidateSession(final byte[] sid) + { + final String key = new String(sid); + synchronized (lock) + { + sid2ssc.remove(key); + sid2ttl.remove(key); + } + } +} diff --git a/libjava/classpath/gnu/javax/crypto/sasl/srp/StoreEntry.java b/libjava/classpath/gnu/javax/crypto/sasl/srp/StoreEntry.java new file mode 100644 index 000000000..ae64fa774 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/sasl/srp/StoreEntry.java @@ -0,0 +1,75 @@ +/* StoreEntry.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath 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; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath 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 GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.sasl.srp; + +/** + * A simple timing-related object for use by SRP re-use code. + */ +class StoreEntry +{ + private boolean perenial; + private long timeToDie; + + StoreEntry(int ttl) + { + super(); + + if (ttl == 0) + { + perenial = true; + timeToDie = 0L; + } + else + { + perenial = false; + timeToDie = System.currentTimeMillis() + (ttl & 0xFFFFFFFFL) * 1000L; + } + } + + /** + * Returns <code>true</code> if the Time-To_live period has not elapsed. + * + * @return <code>true</code> if the Time-To-Live period (in seconds) has not + * elapsed yet; <code>false</code> otherwise. + */ + boolean isAlive() + { + return (perenial ? true : (System.currentTimeMillis() < timeToDie)); + } +} |