001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017:
018: /**
019: * @author Alexander Y. Kleymenov
020: * @version $Revision$
021: */package org.apache.harmony.xnet.provider.jsse;
022:
023: import org.apache.harmony.xnet.provider.jsse.AlertException;
024: import org.apache.harmony.xnet.provider.jsse.Logger;
025:
026: import java.security.GeneralSecurityException;
027: import java.security.MessageDigest;
028: import java.security.NoSuchAlgorithmException;
029: import java.util.Arrays;
030: import javax.net.ssl.SSLException;
031: import javax.crypto.Mac;
032: import javax.crypto.spec.SecretKeySpec;
033:
034: /**
035: * This class provides functionality for computation
036: * of PRF values for TLS (http://www.ietf.org/rfc/rfc2246.txt)
037: * and SSL v3 (http://wp.netscape.com/eng/ssl3) protocols.
038: */
039: public class PRF {
040: private static Logger.Stream logger = Logger.getStream("prf");
041:
042: private static Mac md5_mac;
043: private static Mac sha_mac;
044: protected static MessageDigest md5;
045: protected static MessageDigest sha;
046: private static int md5_mac_length;
047: private static int sha_mac_length;
048:
049: static private void init() {
050: try {
051: md5_mac = Mac.getInstance("HmacMD5");
052: sha_mac = Mac.getInstance("HmacSHA1");
053: } catch (NoSuchAlgorithmException e) {
054: throw new AlertException(
055: AlertProtocol.INTERNAL_ERROR,
056: new SSLException(
057: "There is no provider of HmacSHA1 or HmacMD5 "
058: + "algorithms installed in the system"));
059: }
060: md5_mac_length = md5_mac.getMacLength();
061: sha_mac_length = sha_mac.getMacLength();
062: try {
063: md5 = MessageDigest.getInstance("MD5");
064: sha = MessageDigest.getInstance("SHA-1");
065: } catch (Exception e) {
066: throw new AlertException(
067: AlertProtocol.INTERNAL_ERROR,
068: new SSLException(
069: "Could not initialize the Digest Algorithms."));
070: }
071: }
072:
073: /**
074: * Computes the value of SSLv3 pseudo random function.
075: * @param out: the buffer to fill up with the value of the function.
076: * @param secret: the buffer containing the secret value to generate prf.
077: * @param seed: the seed to be used.
078: */
079: static synchronized void computePRF_SSLv3(byte[] out,
080: byte[] secret, byte[] seed) {
081: if (sha == null) {
082: init();
083: }
084: int pos = 0;
085: int iteration = 1;
086: byte[] digest;
087: while (pos < out.length) {
088: byte[] pref = new byte[iteration];
089: Arrays.fill(pref, (byte) (64 + iteration++));
090: sha.update(pref);
091: sha.update(secret);
092: sha.update(seed);
093: md5.update(secret);
094: md5.update(sha.digest());
095: digest = md5.digest(); // length == 16
096: if (pos + 16 > out.length) {
097: System.arraycopy(digest, 0, out, pos, out.length - pos);
098: pos = out.length;
099: } else {
100: System.arraycopy(digest, 0, out, pos, 16);
101: pos += 16;
102: }
103: }
104: }
105:
106: /**
107: * Computes the value of TLS pseudo random function.
108: * @param out: the buffer to fill up with the value of the function.
109: * @param secret: the buffer containing the secret value to generate prf.
110: * @param str_bytes: the label bytes to be used.
111: * @param seed: the seed to be used.
112: */
113: synchronized static void computePRF(byte[] out, byte[] secret,
114: byte[] str_byts, byte[] seed)
115: throws GeneralSecurityException {
116: if (sha_mac == null) {
117: init();
118: }
119: // Do concatenation of the label with the seed:
120: // (metterings show that is is faster to concatenate the arrays
121: // and to call HMAC.update on cancatenation, than twice call for
122: // each of the part, i.e.:
123: // time(HMAC.update(label+seed))
124: // < time(HMAC.update(label)) + time(HMAC.update(seed))
125: // but it takes more memmory (approximaty on 4%)
126: /*
127: byte[] tmp_seed = new byte[seed.length + str_byts.length];
128: System.arraycopy(str_byts, 0, tmp_seed, 0, str_byts.length);
129: System.arraycopy(seed, 0, tmp_seed, str_byts.length, seed.length);
130: seed = tmp_seed;
131: */
132: SecretKeySpec keyMd5;
133: SecretKeySpec keySha1;
134: if ((secret == null) || (secret.length == 0)) {
135: secret = new byte[8];
136: keyMd5 = new SecretKeySpec(secret, "HmacMD5");
137: keySha1 = new SecretKeySpec(secret, "HmacSHA1");
138: } else {
139: int length = secret.length >> 1; // division by 2
140: int offset = secret.length & 1; // remainder
141: keyMd5 = new SecretKeySpec(secret, 0, length + offset,
142: "HmacMD5");
143: keySha1 = new SecretKeySpec(secret, length,
144: length + offset, "HmacSHA1");
145: }
146:
147: //byte[] str_byts = label.getBytes();
148:
149: if (logger != null) {
150: logger.println("secret[" + secret.length + "]: ");
151: logger.printAsHex(16, "", " ", secret);
152: logger.println("label[" + str_byts.length + "]: ");
153: logger.printAsHex(16, "", " ", str_byts);
154: logger.println("seed[" + seed.length + "]: ");
155: logger.printAsHex(16, "", " ", seed);
156: logger.println("MD5 key:");
157: logger.printAsHex(16, "", " ", keyMd5.getEncoded());
158: logger.println("SHA1 key:");
159: logger.printAsHex(16, "", " ", keySha1.getEncoded());
160: }
161:
162: md5_mac.init(keyMd5);
163: sha_mac.init(keySha1);
164:
165: int pos = 0;
166: md5_mac.update(str_byts);
167: byte[] hash = md5_mac.doFinal(seed); // A(1)
168: while (pos < out.length) {
169: md5_mac.update(hash);
170: md5_mac.update(str_byts);
171: md5_mac.update(seed);
172: if (pos + md5_mac_length < out.length) {
173: md5_mac.doFinal(out, pos);
174: pos += md5_mac_length;
175: } else {
176: System.arraycopy(md5_mac.doFinal(), 0, out, pos,
177: out.length - pos);
178: break;
179: }
180: // make A(i)
181: hash = md5_mac.doFinal(hash);
182: }
183: if (logger != null) {
184: logger.println("P_MD5:");
185: logger.printAsHex(md5_mac_length, "", " ", out);
186: }
187:
188: pos = 0;
189: sha_mac.update(str_byts);
190: hash = sha_mac.doFinal(seed); // A(1)
191: byte[] sha1hash;
192: while (pos < out.length) {
193: sha_mac.update(hash);
194: sha_mac.update(str_byts);
195: sha1hash = sha_mac.doFinal(seed);
196: for (int i = 0; (i < sha_mac_length) & (pos < out.length); i++) {
197: out[pos++] ^= sha1hash[i];
198: }
199: // make A(i)
200: hash = sha_mac.doFinal(hash);
201: }
202:
203: if (logger != null) {
204: logger.println("PRF:");
205: logger.printAsHex(sha_mac_length, "", " ", out);
206: }
207: }
208: }
|