001: /*
002: * $Id: AnyMessageHash.java,v 1.20 2002/09/16 08:05:02 jkl Exp $
003: *
004: * Copyright (c) 2002 Njet Communications Ltd. All Rights Reserved.
005: *
006: * Use is subject to license terms, as defined in
007: * Anvil Sofware License, Version 1.1. See LICENSE
008: * file, or http://njet.org/license-1.1.txt
009: */
010: package anvil.core.crypto;
011:
012: import anvil.core.Any;
013: import anvil.core.AnyAbstractClass;
014: import anvil.core.io.AnyFile;
015: import anvil.core.net.AnyURL;
016: import anvil.script.Context;
017: import java.io.BufferedInputStream;
018: import java.io.File;
019: import java.io.FileInputStream;
020: import java.io.InputStream;
021: import java.io.IOException;
022: import java.net.URL;
023: import java.security.InvalidKeyException;
024: import java.security.MessageDigest;
025: import java.security.NoSuchAlgorithmException;
026: import javax.crypto.Mac;
027: import javax.crypto.SecretKey;
028: import javax.crypto.spec.SecretKeySpec;
029:
030: ///
031: /// @class MessageHash
032: /// This class is used for creating message hash codes:
033: /// <i>Message Digest</i> or <i>Message Authentication Code (MAC)</i>.
034: ///
035:
036: /**
037: * class AnyMessageHash
038: *
039: * Holds message hash codes
040: * (Message Digest or Message Authentication Code).
041: *
042: * Compatible with Test Cases for HMAC-MD5 and HMAC-SHA-1
043: * http://www.ietf.org/rfc/rfc2202.txt
044: *
045: * @author: Jaripekka Salminen
046: */
047: public class AnyMessageHash extends AnyAbstractClass {
048: public static final anvil.script.compiler.NativeClass __class__ = new anvil.script.compiler.NativeClass(
049: "MessageHash",
050: AnyMessageHash.class,
051: //DOC{{
052: ""
053: + "\n"
054: + " @class MessageHash\n"
055: + " This class is used for creating message hash codes:\n"
056: + " <i>Message Digest</i> or <i>Message Authentication Code (MAC)</i>.\n"
057: + "\n"
058: + " @method update\n"
059: + " @synopsis void update(object data [ , object data2, ... ]) ;\n"
060: + " Adds one or more data items (string or binary).\n"
061: + " @synopsis void update(File data [ , File data2, ...]) ;\n"
062: + " Adds the contents of one or more data files.\n"
063: + " @synopsis void update(URL data [, URL data2, ...]) ;\n"
064: + " Adds the contents from one or more URL:s.\n"
065: + " @param data one or more data items\n"
066: + " @method final\n"
067: + " @synopsis binary final() \n"
068: + " @return the message hash code.\n"
069: + " The code can be converted to a hex string using toHex() function.\n"
070: //}}DOC
071: );
072:
073: private MessageDigest _messageDigest;
074: private Mac _mac;
075:
076: /**
077: * @param algorithm "MD5" or "SHA"
078: */
079: /*package*/AnyMessageHash(String algorithm)
080: throws NoSuchAlgorithmException {
081: _messageDigest = MessageDigest.getInstance(algorithm);
082: }
083:
084: /**
085: *
086: */
087: /*package*/AnyMessageHash(String algorithm, Any anyKey)
088: throws NoSuchAlgorithmException, InvalidKeyException {
089: byte[] key;
090: int key_length;
091: if (anyKey.isBinary()) {
092: key = anyKey.toBinary();
093: key_length = anyKey.sizeOf();
094: } else {
095: key = anvil.util.Conversions.getBytes(anyKey.toString());
096: key_length = key.length;
097: }
098: SecretKey sk = new javax.crypto.spec.SecretKeySpec(key, 0,
099: key_length, algorithm);
100: _mac = Mac.getInstance(algorithm);
101: _mac.init(sk);
102: }
103:
104: /**
105: *
106: */
107: public AnyMessageHash update(byte[] data, int offset, int length) {
108: if (_messageDigest != null) {
109: _messageDigest.update(data, offset, length);
110: } else {
111: _mac.update(data, offset, length);
112: }
113: return this ;
114: }
115:
116: static final int _BUFSIZE = 2048;
117:
118: /**
119: *
120: */
121: private Any update(Context context, File file) throws IOException {
122: context.checkRead(file.getPath());
123: return update(new FileInputStream(file));
124: }
125:
126: /**
127: *
128: */
129: private Any update(URL url) throws IOException {
130: return update(url.openStream());
131: }
132:
133: /**
134: *
135: */
136: private Any update(InputStream inputs) throws IOException {
137: byte[] data = new byte[_BUFSIZE];
138: BufferedInputStream binputs = new BufferedInputStream(inputs);
139:
140: while (true) {
141: int nbytes = binputs.read(data, 0, _BUFSIZE);
142: if (nbytes < 1) {
143: break;
144: }
145: if (_messageDigest != null) {
146: _messageDigest.update(data, 0, nbytes);
147: } else {
148: _mac.update(data, 0, nbytes);
149: }
150: }
151: binputs.close();
152: return this ;
153: }
154:
155: /**
156: *
157: */
158:
159: public anvil.script.ClassType classOf() {
160: return __class__;
161: }
162:
163: /**
164: *
165: */
166: public Object toObject() {
167: if (_messageDigest != null) {
168: return _messageDigest;
169: } else {
170: return _mac;
171: }
172: }
173:
174: /**
175: *
176: */
177:
178: /// @method update
179: /// @synopsis void update(object data [ , object data2, ... ]) ;
180: /// Adds one or more data items (string or binary).
181: /// @synopsis void update(File data [ , File data2, ...]) ;
182: /// Adds the contents of one or more data files.
183: /// @synopsis void update(URL data [, URL data2, ...]) ;
184: /// Adds the contents from one or more URL:s.
185: /// @param data one or more data items
186: public Any m_update(Context context, Any[] parameters) {
187: if (parameters.length > 0) {
188:
189: try {
190: for (int i = 0; i < parameters.length; i++) {
191: Any param = parameters[i];
192:
193: if (param.isBinary()) {
194: update(param.toBinary(), 0, param.sizeOf());
195:
196: } else if (param instanceof AnyFile) {
197: update(context, (File) param.toObject());
198:
199: } else if (param instanceof AnyURL) {
200: update((URL) param.toObject());
201:
202: } else {
203: byte[] bytes = anvil.util.Conversions
204: .getBytes(param.toString());
205: update(bytes, 0, bytes.length);
206: }
207: }
208: } catch (IOException e) {
209: throw context.exception(e);
210: }
211: return this ;
212: } else {
213: throw parametersMissing(context, "update");
214: }
215: }
216:
217: /// @method final
218: /// @synopsis binary final()
219: /// @return the message hash code.
220: /// The code can be converted to a hex string using toHex() function.
221: public Any m_final(Context context, Any[] parameters) {
222: if (_messageDigest != null) {
223: return Any.create(_messageDigest.digest());
224: } else {
225: return Any.create(_mac.doFinal());
226: }
227: }
228:
229: }
|