001: /*
002: * ===========================================================================
003: *
004: * (C) Copyright IBM Corp. 2003 All Rights Reserved.
005: *
006: * ===========================================================================
007: */
008:
009: /*
010: * The contents of this file are subject to the terms
011: * of the Common Development and Distribution License
012: * (the License). You may not use this file except in
013: * compliance with the License.
014: *
015: * You can obtain a copy of the license at
016: * https://glassfish.dev.java.net/public/CDDLv1.0.html.
017: * See the License for the specific language governing
018: * permissions and limitations under the License.
019: *
020: * When distributing Covered Code, include this CDDL
021: * Header Notice in each file and include the License file
022: * at https://glassfish.dev.java.net/public/CDDLv1.0.html.
023: * If applicable, add the following below the CDDL Header,
024: * with the fields enclosed by brackets [] replaced by
025: * you own identifying information:
026: * "Portions Copyrighted [year] [name of copyright owner]"
027: *
028: * Copyright 2006 Sun Microsystems Inc. All Rights Reserved
029: */
030:
031: package com.sun.xml.ws.security.opt.crypto.dsig.internal;
032:
033: import java.security.Key;
034: import java.security.InvalidKeyException;
035: import java.security.MessageDigest;
036: import java.security.NoSuchAlgorithmException;
037: import java.security.SignatureException;
038: import java.util.logging.Level;
039: import java.util.logging.Logger;
040:
041: /**
042: * An implementation of the HMAC-SHA1 (RFC 2104)
043: *
044: * @author Joyce Leung
045: */
046:
047: public class HmacSHA1 {
048:
049: private static Logger log = Logger
050: .getLogger("org.jcp.xml.dsig.internal");
051:
052: private static final int SHA1_BLOCK = 64; // 512 bit block in SHA-1
053: private byte[] key_opad;
054:
055: //private boolean initialized = false;
056: //private Key key;
057: private MessageDigest digest;
058: private int byte_length;
059:
060: /**
061: * Initialize with the key
062: *
063: * @param key a Hmac key
064: * @param length output length in byte. length should be > 0 for a
065: * specified length or -1 for unspecified length (length of the signed output)
066: * @exception InvalidKeyException if key is null
067: */
068: public void init(Key key, int length) throws InvalidKeyException {
069: if (key == null) {
070: throw new InvalidKeyException("The key should not be null");
071: }
072: try {
073: this .digest = MessageDigest.getInstance("SHA1");
074: initialize(key);
075: } catch (NoSuchAlgorithmException nsae) {
076: // FIXME: should throw some other exception instead of
077: // InvalidKeyException
078: throw new InvalidKeyException("SHA1 not supported");
079: }
080: if (length > 0) {
081: this .byte_length = length / 8;
082: } else {
083: byte_length = -1;
084: }
085: if (log.isLoggable(Level.FINE)) {
086: log.log(Level.FINE, "byte_length: " + byte_length);
087: }
088: //initialized = true;
089: }
090:
091: /**
092: * update the engine with data
093: *
094: * @param data information to be signed or verified
095: */
096: public void update(byte[] data) {
097: this .digest.update(data);
098: }
099:
100: public void update(byte data) {
101: this .digest.update(data);
102: }
103:
104: public void update(byte[] data, int offset, int len) {
105: this .digest.update(data, offset, len);
106: }
107:
108: /**
109: * Signs the data
110: */
111: public byte[] sign() throws SignatureException {
112:
113: if (byte_length == 0) {
114: throw new SignatureException(
115: "length should be -1 or greater than zero, but is "
116: + byte_length);
117: }
118:
119: byte[] value = this .digest.digest();
120:
121: this .digest.reset();
122: this .digest.update(this .key_opad);
123: this .digest.update(value);
124: byte[] result = this .digest.digest();
125:
126: if (byte_length > 0 && result.length > byte_length) {
127: byte[] truncated = new byte[byte_length];
128: System.arraycopy(result, 0, truncated, 0, byte_length);
129: result = truncated;
130: }
131: return result;
132: }
133:
134: /**
135: * Verifies the signature
136: *
137: * @param siganture the signature to be verified
138: */
139: public boolean verify(byte[] signature) throws SignatureException {
140: return MessageDigest.isEqual(signature, this .sign());
141: }
142:
143: private void initialize(Key key) {
144: byte[] rawKey = key.getEncoded();
145: byte[] normalizedKey = new byte[SHA1_BLOCK];
146: if (rawKey.length > SHA1_BLOCK) {
147: this .digest.reset();
148: rawKey = this .digest.digest(rawKey);
149: }
150: System.arraycopy(rawKey, 0, normalizedKey, 0, rawKey.length);
151: for (int i = rawKey.length; i < SHA1_BLOCK; i++) {
152: normalizedKey[i] = 0;
153: }
154: byte[] key_ipad = new byte[SHA1_BLOCK];
155: key_opad = new byte[SHA1_BLOCK];
156: for (int i = 0; i < SHA1_BLOCK; i++) {
157: key_ipad[i] = (byte) (normalizedKey[i] ^ 0x36);
158: key_opad[i] = (byte) (normalizedKey[i] ^ 0x5c);
159: }
160:
161: this.digest.reset();
162: this.digest.update(key_ipad);
163: }
164: }
|