| /* 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; |
| } |
| } |