Save This Page
Home » openjdk-7 » com.sun.crypto » provider » [javadoc | source]
    1   /*
    2    * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
    3    * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
    4    *
    5    * This code is free software; you can redistribute it and/or modify it
    6    * under the terms of the GNU General Public License version 2 only, as
    7    * published by the Free Software Foundation.  Oracle designates this
    8    * particular file as subject to the "Classpath" exception as provided
    9    * by Oracle in the LICENSE file that accompanied this code.
   10    *
   11    * This code is distributed in the hope that it will be useful, but WITHOUT
   12    * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
   13    * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
   14    * version 2 for more details (a copy is included in the LICENSE file that
   15    * accompanied this code).
   16    *
   17    * You should have received a copy of the GNU General Public License version
   18    * 2 along with this work; if not, write to the Free Software Foundation,
   19    * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
   20    *
   21    * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
   22    * or visit www.oracle.com if you need additional information or have any
   23    * questions.
   24    */
   25   
   26   package com.sun.crypto.provider;
   27   
   28   import java.security;
   29   import java.security.spec.AlgorithmParameterSpec;
   30   
   31   import javax.crypto;
   32   
   33   /**
   34    * Implementation of the ARCFOUR cipher, an algorithm apparently compatible
   35    * with RSA Security's RC4(tm) cipher. The description of this algorithm was
   36    * taken from Bruce Schneier's book Applied Cryptography, 2nd ed.,
   37    * section 17.1.
   38    *
   39    * We support keys from 40 to 1024 bits. ARCFOUR would allow for keys shorter
   40    * than 40 bits, but that is too insecure for us to permit.
   41    *
   42    * Note that we subclass CipherSpi directly and do not use the CipherCore
   43    * framework. That was designed to simplify implementation of block ciphers
   44    * and does not offer any advantages for stream ciphers such as ARCFOUR.
   45    *
   46    * @since   1.5
   47    * @author  Andreas Sterbenz
   48    */
   49   public final class ARCFOURCipher extends CipherSpi {
   50   
   51       // state array S, 256 entries. The entries are 8-bit, but we use an int[]
   52       // because int arithmetic is much faster than in Java than bytes.
   53       private final int[] S;
   54   
   55       // state indices i and j. Called is and js to avoid collision with
   56       // local variables. 'is' is set to -1 after a call to doFinal()
   57       private int is, js;
   58   
   59       // the bytes of the last key used (if any)
   60       // we need this to re-initialize after a call to doFinal()
   61       private byte[] lastKey;
   62   
   63       // called by the JCE framework
   64       public ARCFOURCipher() {
   65           S = new int[256];
   66       }
   67   
   68       // core key setup code. initializes S, is, and js
   69       // assumes key is non-null and between 40 and 1024 bit
   70       private void init(byte[] key) {
   71           // initialize S[i] to i
   72           for (int i = 0; i < 256; i++) {
   73               S[i] = i;
   74           }
   75   
   76           // we avoid expanding key to 256 bytes and instead keep a separate
   77           // counter ki = i mod key.length.
   78           for (int i = 0, j = 0, ki = 0; i < 256; i++) {
   79               int Si = S[i];
   80               j = (j + Si + key[ki]) & 0xff;
   81               S[i] = S[j];
   82               S[j] = Si;
   83               ki++;
   84               if (ki == key.length) {
   85                   ki = 0;
   86               }
   87           }
   88   
   89           // set indices to 0
   90           is = 0;
   91           js = 0;
   92       }
   93   
   94       // core crypt code. OFB style, so works for both encryption and decryption
   95       private void crypt(byte[] in, int inOfs, int inLen, byte[] out,
   96               int outOfs) {
   97           if (is < 0) {
   98               // doFinal() was called, need to reset the cipher to initial state
   99               init(lastKey);
  100           }
  101           while (inLen-- > 0) {
  102               is = (is + 1) & 0xff;
  103               int Si = S[is];
  104               js = (js + Si) & 0xff;
  105               int Sj = S[js];
  106               S[is] = Sj;
  107               S[js] = Si;
  108               out[outOfs++] = (byte)(in[inOfs++] ^ S[(Si + Sj) & 0xff]);
  109           }
  110       }
  111   
  112       // Modes do not make sense with stream ciphers, but allow ECB
  113       // see JCE spec.
  114       protected void engineSetMode(String mode) throws NoSuchAlgorithmException {
  115           if (mode.equalsIgnoreCase("ECB") == false) {
  116               throw new NoSuchAlgorithmException("Unsupported mode " + mode);
  117           }
  118       }
  119   
  120       // Padding does not make sense with stream ciphers, but allow NoPadding
  121       // see JCE spec.
  122       protected void engineSetPadding(String padding)
  123               throws NoSuchPaddingException {
  124           if (padding.equalsIgnoreCase("NoPadding") == false) {
  125               throw new NoSuchPaddingException("Padding must be NoPadding");
  126           }
  127       }
  128   
  129       // Return 0 to indicate stream cipher
  130       // see JCE spec.
  131       protected int engineGetBlockSize() {
  132           return 0;
  133       }
  134   
  135       // output length is always the same as input length
  136       // see JCE spec
  137       protected int engineGetOutputSize(int inputLen) {
  138           return inputLen;
  139       }
  140   
  141       // no IV, return null
  142       // see JCE spec
  143       protected byte[] engineGetIV() {
  144           return null;
  145       }
  146   
  147       // no parameters
  148       // see JCE spec
  149       protected AlgorithmParameters engineGetParameters() {
  150           return null;
  151       }
  152   
  153       // see JCE spec
  154       protected void engineInit(int opmode, Key key, SecureRandom random)
  155               throws InvalidKeyException {
  156           init(opmode, key);
  157       }
  158   
  159       // see JCE spec
  160       protected void engineInit(int opmode, Key key,
  161               AlgorithmParameterSpec params, SecureRandom random)
  162               throws InvalidKeyException, InvalidAlgorithmParameterException {
  163           if (params != null) {
  164               throw new InvalidAlgorithmParameterException
  165                   ("Parameters not supported");
  166           }
  167           init(opmode, key);
  168       }
  169   
  170       // see JCE spec
  171       protected void engineInit(int opmode, Key key,
  172               AlgorithmParameters params, SecureRandom random)
  173               throws InvalidKeyException, InvalidAlgorithmParameterException {
  174           if (params != null) {
  175               throw new InvalidAlgorithmParameterException
  176                   ("Parameters not supported");
  177           }
  178           init(opmode, key);
  179       }
  180   
  181       // init method. Check opmode and key, then call init(byte[]).
  182       private void init(int opmode, Key key) throws InvalidKeyException {
  183           if ((opmode < Cipher.ENCRYPT_MODE) || (opmode > Cipher.UNWRAP_MODE)) {
  184               throw new InvalidKeyException("Unknown opmode: " + opmode);
  185           }
  186           lastKey = getEncodedKey(key);
  187           init(lastKey);
  188       }
  189   
  190       // return the encoding of key if key is a valid ARCFOUR key.
  191       // otherwise, throw an InvalidKeyException
  192       private static byte[] getEncodedKey(Key key) throws InvalidKeyException {
  193           String keyAlg = key.getAlgorithm();
  194           if (!keyAlg.equals("RC4") && !keyAlg.equals("ARCFOUR")) {
  195               throw new InvalidKeyException("Not an ARCFOUR key: " + keyAlg);
  196           }
  197           if ("RAW".equals(key.getFormat()) == false) {
  198               throw new InvalidKeyException("Key encoding format must be RAW");
  199           }
  200           byte[] encodedKey = key.getEncoded();
  201           if ((encodedKey.length < 5) || (encodedKey.length > 128)) {
  202               throw new InvalidKeyException
  203                   ("Key length must be between 40 and 1024 bit");
  204           }
  205           return encodedKey;
  206       }
  207   
  208       // see JCE spec
  209       protected byte[] engineUpdate(byte[] in, int inOfs, int inLen) {
  210           byte[] out = new byte[inLen];
  211           crypt(in, inOfs, inLen, out, 0);
  212           return out;
  213       }
  214   
  215       // see JCE spec
  216       protected int engineUpdate(byte[] in, int inOfs, int inLen,
  217               byte[] out, int outOfs) throws ShortBufferException {
  218           if (out.length - outOfs < inLen) {
  219               throw new ShortBufferException("Output buffer too small");
  220           }
  221           crypt(in, inOfs, inLen, out, outOfs);
  222           return inLen;
  223       }
  224   
  225       // see JCE spec
  226       protected byte[] engineDoFinal(byte[] in, int inOfs, int inLen) {
  227           byte[] out = engineUpdate(in, inOfs, inLen);
  228           is = -1;
  229           return out;
  230       }
  231   
  232       // see JCE spec
  233       protected int engineDoFinal(byte[] in, int inOfs, int inLen,
  234               byte[] out, int outOfs) throws ShortBufferException {
  235           int outLen = engineUpdate(in, inOfs, inLen, out, outOfs);
  236           is = -1;
  237           return outLen;
  238       }
  239   
  240       // see JCE spec
  241       protected byte[] engineWrap(Key key) throws IllegalBlockSizeException,
  242               InvalidKeyException {
  243           byte[] encoded = key.getEncoded();
  244           if ((encoded == null) || (encoded.length == 0)) {
  245               throw new InvalidKeyException("Could not obtain encoded key");
  246           }
  247           return engineDoFinal(encoded, 0, encoded.length);
  248       }
  249   
  250       // see JCE spec
  251       protected Key engineUnwrap(byte[] wrappedKey, String algorithm,
  252               int type) throws InvalidKeyException, NoSuchAlgorithmException {
  253           byte[] encoded = engineDoFinal(wrappedKey, 0, wrappedKey.length);
  254           return ConstructKeys.constructKey(encoded, algorithm, type);
  255       }
  256   
  257       // see JCE spec
  258       protected int engineGetKeySize(Key key) throws InvalidKeyException {
  259           byte[] encodedKey = getEncodedKey(key);
  260           return encodedKey.length << 3;
  261       }
  262   
  263   }

Save This Page
Home » openjdk-7 » com.sun.crypto » provider » [javadoc | source]