001: package org.bouncycastle.crypto.macs;
002:
003: import java.util.Hashtable;
004:
005: import org.bouncycastle.crypto.CipherParameters;
006: import org.bouncycastle.crypto.Digest;
007: import org.bouncycastle.crypto.ExtendedDigest;
008: import org.bouncycastle.crypto.Mac;
009: import org.bouncycastle.crypto.params.KeyParameter;
010:
011: /**
012: * HMAC implementation based on RFC2104
013: *
014: * H(K XOR opad, H(K XOR ipad, text))
015: */
016: public class HMac implements Mac {
017: private final static byte IPAD = (byte) 0x36;
018: private final static byte OPAD = (byte) 0x5C;
019:
020: private Digest digest;
021: private int digestSize;
022: private int blockLength;
023:
024: private byte[] inputPad;
025: private byte[] outputPad;
026:
027: private static Hashtable blockLengths;
028:
029: static {
030: blockLengths = new Hashtable();
031:
032: blockLengths.put("GOST3411", new Integer(32));
033:
034: blockLengths.put("MD2", new Integer(16));
035: blockLengths.put("MD4", new Integer(64));
036: blockLengths.put("MD5", new Integer(64));
037:
038: blockLengths.put("RIPEMD128", new Integer(64));
039: blockLengths.put("RIPEMD160", new Integer(64));
040:
041: blockLengths.put("SHA-1", new Integer(64));
042: blockLengths.put("SHA-224", new Integer(64));
043: blockLengths.put("SHA-256", new Integer(64));
044: blockLengths.put("SHA-384", new Integer(128));
045: blockLengths.put("SHA-512", new Integer(128));
046:
047: blockLengths.put("Tiger", new Integer(64));
048: blockLengths.put("Whirlpool", new Integer(64));
049: }
050:
051: private static int getByteLength(Digest digest) {
052: if (digest instanceof ExtendedDigest) {
053: return ((ExtendedDigest) digest).getByteLength();
054: }
055:
056: Integer b = (Integer) blockLengths.get(digest
057: .getAlgorithmName());
058:
059: if (b == null) {
060: throw new IllegalArgumentException(
061: "unknown digest passed: "
062: + digest.getAlgorithmName());
063: }
064:
065: return b.intValue();
066: }
067:
068: /**
069: * Base constructor for one of the standard digest algorithms that the
070: * byteLength of the algorithm is know for.
071: *
072: * @param digest the digest.
073: */
074: public HMac(Digest digest) {
075: this (digest, getByteLength(digest));
076: }
077:
078: private HMac(Digest digest, int byteLength) {
079: this .digest = digest;
080: digestSize = digest.getDigestSize();
081:
082: this .blockLength = byteLength;
083:
084: inputPad = new byte[blockLength];
085: outputPad = new byte[blockLength];
086: }
087:
088: public String getAlgorithmName() {
089: return digest.getAlgorithmName() + "/HMAC";
090: }
091:
092: public Digest getUnderlyingDigest() {
093: return digest;
094: }
095:
096: public void init(CipherParameters params) {
097: digest.reset();
098:
099: byte[] key = ((KeyParameter) params).getKey();
100:
101: if (key.length > blockLength) {
102: digest.update(key, 0, key.length);
103: digest.doFinal(inputPad, 0);
104: for (int i = digestSize; i < inputPad.length; i++) {
105: inputPad[i] = 0;
106: }
107: } else {
108: System.arraycopy(key, 0, inputPad, 0, key.length);
109: for (int i = key.length; i < inputPad.length; i++) {
110: inputPad[i] = 0;
111: }
112: }
113:
114: outputPad = new byte[inputPad.length];
115: System.arraycopy(inputPad, 0, outputPad, 0, inputPad.length);
116:
117: for (int i = 0; i < inputPad.length; i++) {
118: inputPad[i] ^= IPAD;
119: }
120:
121: for (int i = 0; i < outputPad.length; i++) {
122: outputPad[i] ^= OPAD;
123: }
124:
125: digest.update(inputPad, 0, inputPad.length);
126: }
127:
128: public int getMacSize() {
129: return digestSize;
130: }
131:
132: public void update(byte in) {
133: digest.update(in);
134: }
135:
136: public void update(byte[] in, int inOff, int len) {
137: digest.update(in, inOff, len);
138: }
139:
140: public int doFinal(byte[] out, int outOff) {
141: byte[] tmp = new byte[digestSize];
142: digest.doFinal(tmp, 0);
143:
144: digest.update(outputPad, 0, outputPad.length);
145: digest.update(tmp, 0, tmp.length);
146:
147: int len = digest.doFinal(out, outOff);
148:
149: reset();
150:
151: return len;
152: }
153:
154: /**
155: * Reset the mac generator.
156: */
157: public void reset() {
158: /*
159: * reset the underlying digest.
160: */
161: digest.reset();
162:
163: /*
164: * reinitialize the digest.
165: */
166: digest.update(inputPad, 0, inputPad.length);
167: }
168: }
|