0N/A/*
2362N/A * Copyright (c) 2002, 2009, Oracle and/or its affiliates. All rights reserved.
0N/A * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
0N/A *
0N/A * This code is free software; you can redistribute it and/or modify it
0N/A * under the terms of the GNU General Public License version 2 only, as
2362N/A * published by the Free Software Foundation. Oracle designates this
0N/A * particular file as subject to the "Classpath" exception as provided
2362N/A * by Oracle in the LICENSE file that accompanied this code.
0N/A *
0N/A * This code is distributed in the hope that it will be useful, but WITHOUT
0N/A * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
0N/A * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
0N/A * version 2 for more details (a copy is included in the LICENSE file that
0N/A * accompanied this code).
0N/A *
0N/A * You should have received a copy of the GNU General Public License version
0N/A * 2 along with this work; if not, write to the Free Software Foundation,
0N/A * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
0N/A *
2362N/A * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
2362N/A * or visit www.oracle.com if you need additional information or have any
2362N/A * questions.
0N/A */
0N/A
0N/Apackage com.sun.crypto.provider;
0N/A
0N/Aimport java.util.Arrays;
0N/A
0N/Aimport java.nio.ByteBuffer;
0N/A
0N/Aimport javax.crypto.MacSpi;
0N/Aimport javax.crypto.SecretKey;
0N/Aimport java.security.*;
0N/Aimport java.security.spec.*;
0N/A
0N/A/**
0N/A * This class constitutes the core of HMAC-<MD> algorithms, where
1953N/A * <MD> can be SHA1 or MD5, etc. See RFC 2104 for spec.
0N/A *
0N/A * It also contains the implementation classes for the SHA-256,
0N/A * SHA-384, and SHA-512 HMACs.
0N/A *
0N/A * @author Jan Luehe
0N/A */
0N/Afinal class HmacCore implements Cloneable {
0N/A
0N/A private final MessageDigest md;
0N/A private final byte[] k_ipad; // inner padding - key XORd with ipad
0N/A private final byte[] k_opad; // outer padding - key XORd with opad
0N/A private boolean first; // Is this the first data to be processed?
0N/A
0N/A private final int blockLen;
0N/A
0N/A /**
0N/A * Standard constructor, creates a new HmacCore instance using the
0N/A * specified MessageDigest object.
0N/A */
0N/A HmacCore(MessageDigest md, int bl) {
0N/A this.md = md;
0N/A this.blockLen = bl;
0N/A this.k_ipad = new byte[blockLen];
0N/A this.k_opad = new byte[blockLen];
0N/A first = true;
0N/A }
0N/A
0N/A /**
0N/A * Standard constructor, creates a new HmacCore instance instantiating
0N/A * a MessageDigest of the specified name.
0N/A */
0N/A HmacCore(String digestAlgorithm, int bl) throws NoSuchAlgorithmException {
0N/A this(MessageDigest.getInstance(digestAlgorithm), bl);
0N/A }
0N/A
0N/A /**
0N/A * Constructor used for cloning.
0N/A */
0N/A private HmacCore(HmacCore other) throws CloneNotSupportedException {
0N/A this.md = (MessageDigest)other.md.clone();
0N/A this.blockLen = other.blockLen;
0N/A this.k_ipad = (byte[])other.k_ipad.clone();
0N/A this.k_opad = (byte[])other.k_opad.clone();
0N/A this.first = other.first;
0N/A }
0N/A
0N/A /**
0N/A * Returns the length of the HMAC in bytes.
0N/A *
0N/A * @return the HMAC length in bytes.
0N/A */
0N/A int getDigestLength() {
0N/A return this.md.getDigestLength();
0N/A }
0N/A
0N/A /**
0N/A * Initializes the HMAC with the given secret key and algorithm parameters.
0N/A *
0N/A * @param key the secret key.
0N/A * @param params the algorithm parameters.
0N/A *
0N/A * @exception InvalidKeyException if the given key is inappropriate for
0N/A * initializing this MAC.
0N/A * @exception InvalidAlgorithmParameterException if the given algorithm
0N/A * parameters are inappropriate for this MAC.
0N/A */
0N/A void init(Key key, AlgorithmParameterSpec params)
0N/A throws InvalidKeyException, InvalidAlgorithmParameterException {
0N/A
0N/A if (params != null) {
0N/A throw new InvalidAlgorithmParameterException
0N/A ("HMAC does not use parameters");
0N/A }
0N/A
0N/A if (!(key instanceof SecretKey)) {
0N/A throw new InvalidKeyException("Secret key expected");
0N/A }
0N/A
0N/A byte[] secret = key.getEncoded();
1953N/A if (secret == null) {
0N/A throw new InvalidKeyException("Missing key data");
0N/A }
0N/A
0N/A // if key is longer than the block length, reset it using
0N/A // the message digest object.
0N/A if (secret.length > blockLen) {
0N/A byte[] tmp = md.digest(secret);
0N/A // now erase the secret
0N/A Arrays.fill(secret, (byte)0);
0N/A secret = tmp;
0N/A }
0N/A
0N/A // XOR k with ipad and opad, respectively
0N/A for (int i = 0; i < blockLen; i++) {
0N/A int si = (i < secret.length) ? secret[i] : 0;
0N/A k_ipad[i] = (byte)(si ^ 0x36);
0N/A k_opad[i] = (byte)(si ^ 0x5c);
0N/A }
0N/A
0N/A // now erase the secret
0N/A Arrays.fill(secret, (byte)0);
0N/A secret = null;
0N/A
0N/A reset();
0N/A }
0N/A
0N/A /**
0N/A * Processes the given byte.
0N/A *
0N/A * @param input the input byte to be processed.
0N/A */
0N/A void update(byte input) {
0N/A if (first == true) {
0N/A // compute digest for 1st pass; start with inner pad
0N/A md.update(k_ipad);
0N/A first = false;
0N/A }
0N/A
0N/A // add the passed byte to the inner digest
0N/A md.update(input);
0N/A }
0N/A
0N/A /**
0N/A * Processes the first <code>len</code> bytes in <code>input</code>,
0N/A * starting at <code>offset</code>.
0N/A *
0N/A * @param input the input buffer.
0N/A * @param offset the offset in <code>input</code> where the input starts.
0N/A * @param len the number of bytes to process.
0N/A */
0N/A void update(byte input[], int offset, int len) {
0N/A if (first == true) {
0N/A // compute digest for 1st pass; start with inner pad
0N/A md.update(k_ipad);
0N/A first = false;
0N/A }
0N/A
0N/A // add the selected part of an array of bytes to the inner digest
0N/A md.update(input, offset, len);
0N/A }
0N/A
0N/A void update(ByteBuffer input) {
0N/A if (first == true) {
0N/A // compute digest for 1st pass; start with inner pad
0N/A md.update(k_ipad);
0N/A first = false;
0N/A }
0N/A
0N/A md.update(input);
0N/A }
0N/A
0N/A /**
0N/A * Completes the HMAC computation and resets the HMAC for further use,
0N/A * maintaining the secret key that the HMAC was initialized with.
0N/A *
0N/A * @return the HMAC result.
0N/A */
0N/A byte[] doFinal() {
0N/A if (first == true) {
0N/A // compute digest for 1st pass; start with inner pad
0N/A md.update(k_ipad);
0N/A } else {
0N/A first = true;
0N/A }
0N/A
0N/A try {
0N/A // finish the inner digest
0N/A byte[] tmp = md.digest();
0N/A
0N/A // compute digest for 2nd pass; start with outer pad
0N/A md.update(k_opad);
0N/A // add result of 1st hash
0N/A md.update(tmp);
0N/A
0N/A md.digest(tmp, 0, tmp.length);
0N/A return tmp;
0N/A } catch (DigestException e) {
0N/A // should never occur
0N/A throw new ProviderException(e);
0N/A }
0N/A }
0N/A
0N/A /**
0N/A * Resets the HMAC for further use, maintaining the secret key that the
0N/A * HMAC was initialized with.
0N/A */
0N/A void reset() {
0N/A if (first == false) {
0N/A md.reset();
0N/A first = true;
0N/A }
0N/A }
0N/A
0N/A /*
0N/A * Clones this object.
0N/A */
0N/A public Object clone() throws CloneNotSupportedException {
0N/A return new HmacCore(this);
0N/A }
0N/A
0N/A // nested static class for the HmacSHA256 implementation
0N/A public static final class HmacSHA256 extends MacSpi implements Cloneable {
0N/A private final HmacCore core;
0N/A public HmacSHA256() throws NoSuchAlgorithmException {
0N/A core = new HmacCore("SHA-256", 64);
0N/A }
0N/A private HmacSHA256(HmacSHA256 base) throws CloneNotSupportedException {
0N/A core = (HmacCore)base.core.clone();
0N/A }
0N/A protected int engineGetMacLength() {
0N/A return core.getDigestLength();
0N/A }
0N/A protected void engineInit(Key key, AlgorithmParameterSpec params)
0N/A throws InvalidKeyException, InvalidAlgorithmParameterException {
0N/A core.init(key, params);
0N/A }
0N/A protected void engineUpdate(byte input) {
0N/A core.update(input);
0N/A }
0N/A protected void engineUpdate(byte input[], int offset, int len) {
0N/A core.update(input, offset, len);
0N/A }
0N/A protected void engineUpdate(ByteBuffer input) {
0N/A core.update(input);
0N/A }
0N/A protected byte[] engineDoFinal() {
0N/A return core.doFinal();
0N/A }
0N/A protected void engineReset() {
0N/A core.reset();
0N/A }
0N/A public Object clone() throws CloneNotSupportedException {
0N/A return new HmacSHA256(this);
0N/A }
0N/A }
0N/A
0N/A // nested static class for the HmacSHA384 implementation
0N/A public static final class HmacSHA384 extends MacSpi implements Cloneable {
0N/A private final HmacCore core;
0N/A public HmacSHA384() throws NoSuchAlgorithmException {
0N/A core = new HmacCore("SHA-384", 128);
0N/A }
0N/A private HmacSHA384(HmacSHA384 base) throws CloneNotSupportedException {
0N/A core = (HmacCore)base.core.clone();
0N/A }
0N/A protected int engineGetMacLength() {
0N/A return core.getDigestLength();
0N/A }
0N/A protected void engineInit(Key key, AlgorithmParameterSpec params)
0N/A throws InvalidKeyException, InvalidAlgorithmParameterException {
0N/A core.init(key, params);
0N/A }
0N/A protected void engineUpdate(byte input) {
0N/A core.update(input);
0N/A }
0N/A protected void engineUpdate(byte input[], int offset, int len) {
0N/A core.update(input, offset, len);
0N/A }
0N/A protected void engineUpdate(ByteBuffer input) {
0N/A core.update(input);
0N/A }
0N/A protected byte[] engineDoFinal() {
0N/A return core.doFinal();
0N/A }
0N/A protected void engineReset() {
0N/A core.reset();
0N/A }
0N/A public Object clone() throws CloneNotSupportedException {
0N/A return new HmacSHA384(this);
0N/A }
0N/A }
0N/A
0N/A // nested static class for the HmacSHA512 implementation
0N/A public static final class HmacSHA512 extends MacSpi implements Cloneable {
0N/A private final HmacCore core;
0N/A public HmacSHA512() throws NoSuchAlgorithmException {
0N/A core = new HmacCore("SHA-512", 128);
0N/A }
0N/A private HmacSHA512(HmacSHA512 base) throws CloneNotSupportedException {
0N/A core = (HmacCore)base.core.clone();
0N/A }
0N/A protected int engineGetMacLength() {
0N/A return core.getDigestLength();
0N/A }
0N/A protected void engineInit(Key key, AlgorithmParameterSpec params)
0N/A throws InvalidKeyException, InvalidAlgorithmParameterException {
0N/A core.init(key, params);
0N/A }
0N/A protected void engineUpdate(byte input) {
0N/A core.update(input);
0N/A }
0N/A protected void engineUpdate(byte input[], int offset, int len) {
0N/A core.update(input, offset, len);
0N/A }
0N/A protected void engineUpdate(ByteBuffer input) {
0N/A core.update(input);
0N/A }
0N/A protected byte[] engineDoFinal() {
0N/A return core.doFinal();
0N/A }
0N/A protected void engineReset() {
0N/A core.reset();
0N/A }
0N/A public Object clone() throws CloneNotSupportedException {
0N/A return new HmacSHA512(this);
0N/A }
0N/A }
0N/A
0N/A}