Save This Page
Home » openjdk-7 » com.sun.crypto » provider » [javadoc | source]
    1   /*
    2    * Copyright (c) 2002, 2009, 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.util.Arrays;
   29   
   30   import java.nio.ByteBuffer;
   31   
   32   import javax.crypto.MacSpi;
   33   import javax.crypto.SecretKey;
   34   import java.security;
   35   import java.security.spec;
   36   
   37   /**
   38    * This class constitutes the core of HMAC-<MD> algorithms, where
   39    * <MD> can be SHA1 or MD5, etc. See RFC 2104 for spec.
   40    *
   41    * It also contains the implementation classes for the SHA-256,
   42    * SHA-384, and SHA-512 HMACs.
   43    *
   44    * @author Jan Luehe
   45    */
   46   final class HmacCore implements Cloneable {
   47   
   48       private final MessageDigest md;
   49       private final byte[] k_ipad; // inner padding - key XORd with ipad
   50       private final byte[] k_opad; // outer padding - key XORd with opad
   51       private boolean first;       // Is this the first data to be processed?
   52   
   53       private final int blockLen;
   54   
   55       /**
   56        * Standard constructor, creates a new HmacCore instance using the
   57        * specified MessageDigest object.
   58        */
   59       HmacCore(MessageDigest md, int bl) {
   60           this.md = md;
   61           this.blockLen = bl;
   62           this.k_ipad = new byte[blockLen];
   63           this.k_opad = new byte[blockLen];
   64           first = true;
   65       }
   66   
   67       /**
   68        * Standard constructor, creates a new HmacCore instance instantiating
   69        * a MessageDigest of the specified name.
   70        */
   71       HmacCore(String digestAlgorithm, int bl) throws NoSuchAlgorithmException {
   72           this(MessageDigest.getInstance(digestAlgorithm), bl);
   73       }
   74   
   75       /**
   76        * Constructor used for cloning.
   77        */
   78       private HmacCore(HmacCore other) throws CloneNotSupportedException {
   79           this.md = (MessageDigest)other.md.clone();
   80           this.blockLen = other.blockLen;
   81           this.k_ipad = (byte[])other.k_ipad.clone();
   82           this.k_opad = (byte[])other.k_opad.clone();
   83           this.first = other.first;
   84       }
   85   
   86       /**
   87        * Returns the length of the HMAC in bytes.
   88        *
   89        * @return the HMAC length in bytes.
   90        */
   91       int getDigestLength() {
   92           return this.md.getDigestLength();
   93       }
   94   
   95       /**
   96        * Initializes the HMAC with the given secret key and algorithm parameters.
   97        *
   98        * @param key the secret key.
   99        * @param params the algorithm parameters.
  100        *
  101        * @exception InvalidKeyException if the given key is inappropriate for
  102        * initializing this MAC.
  103        * @exception InvalidAlgorithmParameterException if the given algorithm
  104        * parameters are inappropriate for this MAC.
  105        */
  106       void init(Key key, AlgorithmParameterSpec params)
  107               throws InvalidKeyException, InvalidAlgorithmParameterException {
  108   
  109           if (params != null) {
  110               throw new InvalidAlgorithmParameterException
  111                   ("HMAC does not use parameters");
  112           }
  113   
  114           if (!(key instanceof SecretKey)) {
  115               throw new InvalidKeyException("Secret key expected");
  116           }
  117   
  118           byte[] secret = key.getEncoded();
  119           if (secret == null) {
  120               throw new InvalidKeyException("Missing key data");
  121           }
  122   
  123           // if key is longer than the block length, reset it using
  124           // the message digest object.
  125           if (secret.length > blockLen) {
  126               byte[] tmp = md.digest(secret);
  127               // now erase the secret
  128               Arrays.fill(secret, (byte)0);
  129               secret = tmp;
  130           }
  131   
  132           // XOR k with ipad and opad, respectively
  133           for (int i = 0; i < blockLen; i++) {
  134               int si = (i < secret.length) ? secret[i] : 0;
  135               k_ipad[i] = (byte)(si ^ 0x36);
  136               k_opad[i] = (byte)(si ^ 0x5c);
  137           }
  138   
  139           // now erase the secret
  140           Arrays.fill(secret, (byte)0);
  141           secret = null;
  142   
  143           reset();
  144       }
  145   
  146       /**
  147        * Processes the given byte.
  148        *
  149        * @param input the input byte to be processed.
  150        */
  151       void update(byte input) {
  152           if (first == true) {
  153               // compute digest for 1st pass; start with inner pad
  154               md.update(k_ipad);
  155               first = false;
  156           }
  157   
  158           // add the passed byte to the inner digest
  159           md.update(input);
  160       }
  161   
  162       /**
  163        * Processes the first <code>len</code> bytes in <code>input</code>,
  164        * starting at <code>offset</code>.
  165        *
  166        * @param input the input buffer.
  167        * @param offset the offset in <code>input</code> where the input starts.
  168        * @param len the number of bytes to process.
  169        */
  170       void update(byte input[], int offset, int len) {
  171           if (first == true) {
  172               // compute digest for 1st pass; start with inner pad
  173               md.update(k_ipad);
  174               first = false;
  175           }
  176   
  177           // add the selected part of an array of bytes to the inner digest
  178           md.update(input, offset, len);
  179       }
  180   
  181       void update(ByteBuffer input) {
  182           if (first == true) {
  183               // compute digest for 1st pass; start with inner pad
  184               md.update(k_ipad);
  185               first = false;
  186           }
  187   
  188           md.update(input);
  189       }
  190   
  191       /**
  192        * Completes the HMAC computation and resets the HMAC for further use,
  193        * maintaining the secret key that the HMAC was initialized with.
  194        *
  195        * @return the HMAC result.
  196        */
  197       byte[] doFinal() {
  198           if (first == true) {
  199               // compute digest for 1st pass; start with inner pad
  200               md.update(k_ipad);
  201           } else {
  202               first = true;
  203           }
  204   
  205           try {
  206               // finish the inner digest
  207               byte[] tmp = md.digest();
  208   
  209               // compute digest for 2nd pass; start with outer pad
  210               md.update(k_opad);
  211               // add result of 1st hash
  212               md.update(tmp);
  213   
  214               md.digest(tmp, 0, tmp.length);
  215               return tmp;
  216           } catch (DigestException e) {
  217               // should never occur
  218               throw new ProviderException(e);
  219           }
  220       }
  221   
  222       /**
  223        * Resets the HMAC for further use, maintaining the secret key that the
  224        * HMAC was initialized with.
  225        */
  226       void reset() {
  227           if (first == false) {
  228               md.reset();
  229               first = true;
  230           }
  231       }
  232   
  233       /*
  234        * Clones this object.
  235        */
  236       public Object clone() throws CloneNotSupportedException {
  237           return new HmacCore(this);
  238       }
  239   
  240       // nested static class for the HmacSHA256 implementation
  241       public static final class HmacSHA256 extends MacSpi implements Cloneable {
  242           private final HmacCore core;
  243           public HmacSHA256() throws NoSuchAlgorithmException {
  244               core = new HmacCore("SHA-256", 64);
  245           }
  246           private HmacSHA256(HmacSHA256 base) throws CloneNotSupportedException {
  247               core = (HmacCore)base.core.clone();
  248           }
  249           protected int engineGetMacLength() {
  250               return core.getDigestLength();
  251           }
  252           protected void engineInit(Key key, AlgorithmParameterSpec params)
  253                   throws InvalidKeyException, InvalidAlgorithmParameterException {
  254               core.init(key, params);
  255           }
  256           protected void engineUpdate(byte input) {
  257               core.update(input);
  258           }
  259           protected void engineUpdate(byte input[], int offset, int len) {
  260               core.update(input, offset, len);
  261           }
  262           protected void engineUpdate(ByteBuffer input) {
  263               core.update(input);
  264           }
  265           protected byte[] engineDoFinal() {
  266               return core.doFinal();
  267           }
  268           protected void engineReset() {
  269               core.reset();
  270           }
  271           public Object clone() throws CloneNotSupportedException {
  272               return new HmacSHA256(this);
  273           }
  274       }
  275   
  276       // nested static class for the HmacSHA384 implementation
  277       public static final class HmacSHA384 extends MacSpi implements Cloneable {
  278           private final HmacCore core;
  279           public HmacSHA384() throws NoSuchAlgorithmException {
  280               core = new HmacCore("SHA-384", 128);
  281           }
  282           private HmacSHA384(HmacSHA384 base) throws CloneNotSupportedException {
  283               core = (HmacCore)base.core.clone();
  284           }
  285           protected int engineGetMacLength() {
  286               return core.getDigestLength();
  287           }
  288           protected void engineInit(Key key, AlgorithmParameterSpec params)
  289                   throws InvalidKeyException, InvalidAlgorithmParameterException {
  290               core.init(key, params);
  291           }
  292           protected void engineUpdate(byte input) {
  293               core.update(input);
  294           }
  295           protected void engineUpdate(byte input[], int offset, int len) {
  296               core.update(input, offset, len);
  297           }
  298           protected void engineUpdate(ByteBuffer input) {
  299               core.update(input);
  300           }
  301           protected byte[] engineDoFinal() {
  302               return core.doFinal();
  303           }
  304           protected void engineReset() {
  305               core.reset();
  306           }
  307           public Object clone() throws CloneNotSupportedException {
  308               return new HmacSHA384(this);
  309           }
  310       }
  311   
  312       // nested static class for the HmacSHA512 implementation
  313       public static final class HmacSHA512 extends MacSpi implements Cloneable {
  314           private final HmacCore core;
  315           public HmacSHA512() throws NoSuchAlgorithmException {
  316               core = new HmacCore("SHA-512", 128);
  317           }
  318           private HmacSHA512(HmacSHA512 base) throws CloneNotSupportedException {
  319               core = (HmacCore)base.core.clone();
  320           }
  321           protected int engineGetMacLength() {
  322               return core.getDigestLength();
  323           }
  324           protected void engineInit(Key key, AlgorithmParameterSpec params)
  325                   throws InvalidKeyException, InvalidAlgorithmParameterException {
  326               core.init(key, params);
  327           }
  328           protected void engineUpdate(byte input) {
  329               core.update(input);
  330           }
  331           protected void engineUpdate(byte input[], int offset, int len) {
  332               core.update(input, offset, len);
  333           }
  334           protected void engineUpdate(ByteBuffer input) {
  335               core.update(input);
  336           }
  337           protected byte[] engineDoFinal() {
  338               return core.doFinal();
  339           }
  340           protected void engineReset() {
  341               core.reset();
  342           }
  343           public Object clone() throws CloneNotSupportedException {
  344               return new HmacSHA512(this);
  345           }
  346       }
  347   
  348   }

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