summaryrefslogtreecommitdiffstats
path: root/pki/base/util/src/com/netscape/cmsutil/util/HMACDigest.java
blob: c1ab2003d652a606dc1be869fb8fa7da6d3fbf60 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
// --- BEGIN COPYRIGHT BLOCK ---
// This program 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; version 2 of the License.
//
// This program 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 this program; if not, write to the Free Software Foundation, Inc.,
// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
//
// (C) 2007 Red Hat, Inc.
// All rights reserved.
// --- END COPYRIGHT BLOCK ---
package com.netscape.cmsutil.util;


import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;


/**
 * This class implements the HMAC algorithm specified in RFC 2104 using
 * any MessageDigest.
 *
 * @author mikep
 * @version $Revision$, $Date$
 * @see java.security.MessageDigest
 */
public class HMACDigest implements Cloneable {
    public static final int PAD_BYTES = 64;
    public static final int IPAD = 0x36;
    public static final int OPAD = 0x5C;

    /**
     * inner padding - key XORd with ipad
     */
    private byte[] mKeyIpad = new byte[PAD_BYTES];

    /**
     * outer padding - key XORd with opad
     */
    private byte[] mKeyOpad = new byte[PAD_BYTES];

    /**
     * The real MessageDigest
     */
    private MessageDigest mMD = null;

    /**
     * Creates an HMACDigest
     *
     * @param md The MessageDigest to be used for the HMAC calculation.  It
     * must be clonable.
     */
    public HMACDigest(MessageDigest md) {
        mMD = md;
    }

    /**
     * Creates an HMACDigest and initializes the HMAC function
     * with the given key.
     *
     * @param md The MessageDigest to be used for the HMAC calculation.  It
     * must be clonable.
     * @param key The key value to be used in the HMAC calculation
     */
    public HMACDigest(MessageDigest md, byte[] key) {
        this(md);
        init(key);
    }

    /**
     * Return the MessageDigest used for this HMAC
     */
    public MessageDigest getMessageDigest() {
        return mMD;
    }

    /**
     * Initialize the HMAC function
     *
     * The HMAC transform looks like:
     *
     *      hash(key XOR opad, hash(key XOR ipad, text))
     *
     * where key is an n byte key
     * ipad is the byte 0x36 repeated 64 times
     * opad is the byte 0x5c repeated 64 times
     * and text is the data being protected
     *
     * This routine must be called after every reset.
     *
     * @param key The password used to protect the hash value
     */
    public void init(byte[] key) {
        int i;

        reset();

        // If the key is longer than 64 bytes, just hash it down
        if (key.length > 64) {
            key = mMD.digest(key);
            mMD.reset(); // Redundant?
        }

        // Copy the key.  Truncate if key is too long
        for (i = 0; i < key.length && i < PAD_BYTES; i++) {
            mKeyIpad[i] = key[i];
            mKeyOpad[i] = key[i];
        }

        // XOR in the pads
        for (i = 0; i < PAD_BYTES; i++) {
            mKeyIpad[i] ^= IPAD;
            mKeyOpad[i] ^= OPAD;
        }

        mMD.update(mKeyIpad);

        // Hmmm, we really shouldn't key Opad around in memory for so
        // long, but it would just force the user to key their key around
        // until digest() time. Oh well, at least clear the key and Ipad
        for (i = 0; i < PAD_BYTES; i++) {
            mKeyIpad[i] = 0;
        }
        for (i = 0; i < key.length; i++) {
            key[0] = 0;
        }
    }

    /**
     * Updates the digest using the specified array of bytes.
     *
     * @param input the array of bytes.
     */
    public void update(byte[] input) {
        mMD.update(input);
    }

    /**
     * Completes the HMAC computation with the outer pad
     * The digest is reset after this call is made.
     *
     * @return the array of bytes for the resulting hash value.
     */
    public byte[] digest() {
        byte[] finalDigest;
        byte[] innerDigest = mMD.digest();

        mMD.reset(); // Redundant?
        mMD.update(mKeyOpad);
        mMD.update(innerDigest);
        finalDigest = mMD.digest();
        reset(); // Clear pad arrays
        return finalDigest;
    }

    /**
     * Resets the digest for further use.
     */
    public void reset() {
        int i;

        mMD.reset();

        // Clear out the pads
        for (i = 0; i < PAD_BYTES; i++) {
            mKeyIpad[i] = 0;
            mKeyOpad[i] = 0;
        }
    }

    /**
     * Clone the HMACDigest
     *
     * @return a clone if the implementation is cloneable.
     * @exception CloneNotSupportedException if this is called on a 
     * MessageDigest implementation that does not support 
     * <code>Cloneable</code>.
     */
    public Object clone() throws CloneNotSupportedException {
        int i;

        HMACDigest hd = (HMACDigest) super.clone();	

        hd.mKeyOpad = new byte[PAD_BYTES];
        hd.mKeyIpad = new byte[PAD_BYTES];

        for (i = 0; i < PAD_BYTES; i++) {
            hd.mKeyOpad[i] = mKeyOpad[i];
            hd.mKeyIpad[i] = mKeyIpad[i];
        }

        hd.mMD = (MessageDigest) mMD.clone();
        return hd;
    }

}