Docjar: A Java Source and Docuemnt Enginecom.*    java.*    javax.*    org.*    all    new    plug-in

Quick Search    Search Deep

Source code: cryptix/sasl/srp/CALG.java


1   package cryptix.sasl.srp;
2   
3   // $Id: CALG.java,v 1.1 2001/06/25 21:04:56 raif Exp $
4   //
5   // Copyright (c) 2000-2001 The Cryptix Foundation Limited. All rights reserved.
6   //
7   // Use, modification, copying and distribution of this software is subject to
8   // the terms and conditions of the Cryptix General Licence. You should have
9   // received a copy of the Cryptix General License along with this library; if
10  // not, you can download a copy from <http://www.cryptix.org/>.
11  
12  import cryptix.sasl.ConfidentialityException;
13  import cryptix.sasl.SaslUtil;
14  import java.security.InvalidAlgorithmParameterException;
15  import java.security.InvalidKeyException;
16  import java.security.NoSuchAlgorithmException;
17  import java.util.Random;
18  import javax.crypto.BadPaddingException;
19  import javax.crypto.Cipher;
20  import javax.crypto.IllegalBlockSizeException;
21  import javax.crypto.NoSuchPaddingException;
22  import javax.crypto.SecretKey;
23  import javax.crypto.spec.IvParameterSpec;
24  import javax.crypto.spec.SecretKeySpec;
25  import javax.security.sasl.SaslException;
26  
27  import org.apache.log4j.Category;
28  
29  /**
30   * A Factory class that returns CALG (Confidentiality Algorithm) instances that
31   * operate as described in the draft-burdis-cat-sasl-srp-04. Specifically the
32   * following description, from the specs, is relevant:<p>
33   *
34   * <pre>
35   * The designated CALG block cipher should be used in OFB (Output
36   * Feedback Block) mode in the ISO variant, as described in [16],
37   * algorithm 7.20.
38   *
39   * Let k be the block size of the chosen symmetric cipher algorithm;
40   * e.g. for AES this is 128 bits or 16 octets.  The OFB mode used shall
41   * be of length/size k.
42   *
43   * It is recommended that Block ciphers operating in OFB mode be used
44   * with an Initial Vector (the mode's IV).  For the SASL mechanisms
45   * described in this document, the IV shall be an all-zero octet
46   * sequence of size k.
47   *
48   * In such a mode of operation - OFB with key re-use - the IV, which
49   * need not be secret, must be changed.  Otherwise an identical
50   * keystream results; and, by XORing corresponding ciphertexts, an
51   * adversary may reduce cryptanalysis to that of a running-key cipher
52   * with one plaintext as the running key.  To counter the effect of
53   * fixing the IV to an all-zero octet sequence, the sender should use a
54   * one k-octet sequence as the value of its first block, constructed as
55   * follows:
56   *
57   * o  the first (most significant) (k-2) octets are random,
58   *
59   * o  the octets at position #k-1 and #k, assuming the first octet is
60   *    at position #1, are exact copies of those at positions #1 and #2
61   *    respectively.
62   *
63   * The input data to the confidentiality protection algorithm shall be
64   * a multiple of the symmetric cipher block size k.  When the input
65   * length is not a multiple of k octets, the data shall be padded
66   * according to the following scheme (described in [17] which itself is
67   * based on RFC1423 [18]):
68  
69   *    Assuming the length of the input is l octets, (k - (l mod k))
70   *    octets, all having the value (k - (l mod k)), shall be appended
71   *    to the original data.  In other words, the input is padded at the
72   *    trailing end with one of the following sequences:
73   *
74   *                    01 -- if l mod k = k-1
75   *                   02 02 -- if l mod k = k-2
76   *                             ...
77   *                             ...
78   *                             ...
79   *                 k k ... k k -- if l mod k = 0
80   *
81   *    The padding can be removed unambiguously since all input is
82   *    padded and no padding sequence is a suffix of another.  This
83   *    padding method is well-defined if and only if k < 256 octets,
84   *    which is the case with symmetric block ciphers today, and in the
85   *    forseeable future.
86   *
87   * The output of this stage, when it is active, is:
88   *
89   *    at the sending side: CALG(K, ENCRYPT)( bytes(p1) )
90   *
91   *    at the receiving side: CALG(K, DECRYPT)( bytes(p1) )
92   *
93   * If the receiver, after decrypting the first block, finds that the
94   * last two octets do not match the value of the first two, it MUST
95   * signal an exception and abort the exchange.
96   * </pre>
97   *
98   * @version $Revision: 1.1 $
99   * @since draft-burdis-cat-sasl-srp-04
100  */
101 public final class CALG
102 {
103   // Constants and variables
104   // --------------------------------------------------------------------------
105 
106   private static Category cat = Category.getInstance(CALG.class);
107 
108   public static final int ENCRYPT = Cipher.ENCRYPT_MODE;
109   public static final int DECRYPT = Cipher.DECRYPT_MODE;
110 
111   private static final Random prng = new Random();
112 
113    private String algorithm;
114    private Cipher cipher;
115    private boolean encrypting;
116    private int blockSize;
117   private boolean firstBlock = true;
118   private byte[] iv;
119 
120   // Constructor(s)
121   // --------------------------------------------------------------------------
122 
123   /** Trivial private constructor to enforce Singleton pattern. */
124   private CALG(String algorithm, int blockSize, Cipher cipher, boolean encrypting)
125   throws SaslException {
126     super();
127 
128     this.algorithm = algorithm;
129     this.blockSize = blockSize;
130     this.cipher = cipher;
131     this.encrypting = encrypting;
132 
133     iv = new byte[blockSize];
134     if (encrypting) { // build first block
135        prng.nextBytes(iv);
136        iv[blockSize-2] = (byte) iv[0];
137        iv[blockSize-1] = (byte) iv[1];
138      }
139   }
140 
141   // Class methods
142   // -------------------------------------------------------------------------
143 
144    /**
145     * Returns an instance of a SASL-SRP CALG implementation.
146     *
147     * @param algorithm the name of the symmetric cipher algorithm.
148     * @param K the shared secret.
149     * @param mode whether this CALG is used for encryption or decryption.
150     * @return an instance of this object.
151     */
152    public static synchronized CALG
153    getInstance(String algorithm, SecretKey K, int mode)
154    throws SaslException {
155      String alias = SRPUtil.toProviderName(algorithm);
156      Cipher cipher;
157      int blockSize;
158       try {
159         cipher = Cipher.getInstance(alias+"/OFB/PKCS7");
160         blockSize = cipher.getBlockSize();
161       } catch (NoSuchAlgorithmException x) {
162        cat.error(x);
163         throw new SaslException("getInstance()", x);
164       } catch (NoSuchPaddingException x) {
165        cat.error(x);
166         throw new SaslException("getInstance()", x);
167       }
168 
169       try {
170          SecretKey sk = new SecretKeySpec(K.getEncoded(), alias);
171          IvParameterSpec iv = new IvParameterSpec(new byte[blockSize]);
172         cipher.init(mode, sk, iv);
173       } catch (InvalidKeyException x) {
174         throw new SaslException("getInstance()", x);
175       } catch (InvalidAlgorithmParameterException x) {
176         throw new SaslException("getInstance()", x);
177       }
178 
179       return new CALG(alias, blockSize, cipher, mode == ENCRYPT);
180    }
181 
182   // Instance methods
183   // -------------------------------------------------------------------------
184 
185   /**
186    * Encrypts or decrypts, depending on the mode already set, a designated
187    * array of bytes and returns the result.
188    *
189    * @param data the data to encrypt/decrypt
190    * @return the decrypted/encrypted result.
191    * @exception ConfidentialityException if an exception occurs duirng the
192    * process.
193    */
194   public byte[] doFinal(byte[] data) throws ConfidentialityException {
195     cat.debug("==> doFinal()");
196      cat.debug(encrypting ? "plaintext:  " : "ciphertext: "+SaslUtil.dumpString(data));
197 
198       byte[] t, result;
199     try {
200          if (encrypting && firstBlock) {
201             firstBlock = false;
202             t = new byte[data.length+blockSize];
203             System.arraycopy(iv,   0, t, 0,         blockSize);
204             System.arraycopy(data, 0, t, blockSize, data.length);
205          } else
206             t = data;
207 
208         t = cipher.doFinal(t);
209 
210          if (!encrypting && firstBlock) {
211             firstBlock = false;
212             result = new byte[t.length-blockSize];
213             System.arraycopy(t, 0,         iv,     0, blockSize);
214             System.arraycopy(t, blockSize, result, 0, t.length-blockSize);
215             if (iv[0] != iv[blockSize-2] || iv[1] != iv[blockSize-1])
216                throw new RuntimeException("Incorrect IV");
217          } else
218             result = t;
219 
220       } catch (IllegalBlockSizeException x) {
221         throw new ConfidentialityException("crypt()", x);
222       } catch (BadPaddingException x) {
223         throw new ConfidentialityException("crypt()", x);
224       } catch (Exception x) {
225         throw new ConfidentialityException("crypt()", x);
226       }
227 
228     cat.debug(encrypting ? "ciphertext: " : "plaintext:  "+SaslUtil.dumpString(result));
229     cat.debug("<== doFinal()");
230     return result;
231   }
232 }