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 Boris Kuznetsov
020: * @version $Revision$
021: */package org.apache.harmony.xnet.provider.jsse;
022:
023: import org.apache.harmony.xnet.provider.jsse.AlertException;
024:
025: import java.security.MessageDigest;
026: import java.security.PrivateKey;
027: import java.security.Signature;
028: import java.security.cert.Certificate;
029: import java.util.Arrays;
030:
031: import javax.crypto.Cipher;
032: import javax.net.ssl.SSLException;
033:
034: /**
035: * This class represents Signature type, as descrybed in TLS v 1.0 Protocol
036: * specification, 7.4.3. It allow to init, update and sign hash. Hash algorithm
037: * depends on SignatureAlgorithm.
038: *
039: * select (SignatureAlgorithm)
040: * { case anonymous: struct { };
041: * case rsa:
042: * digitally-signed struct {
043: * opaque md5_hash[16];
044: * opaque sha_hash[20];
045: * };
046: * case dsa:
047: * digitally-signed struct {
048: * opaque sha_hash[20];
049: * };
050: * } Signature;
051: *
052: * Digital signing description see in TLS spec., 4.7.
053: * (http://www.ietf.org/rfc/rfc2246.txt)
054: *
055: */
056: public class DigitalSignature {
057:
058: private MessageDigest md5 = null;
059: private MessageDigest sha = null;
060: private Signature signature = null;
061: private Cipher cipher = null;
062:
063: private byte[] md5_hash;
064: private byte[] sha_hash;
065:
066: /**
067: * Create Signature type
068: * @param keyExchange
069: */
070: public DigitalSignature(int keyExchange) {
071: try {
072: if (keyExchange == CipherSuite.KeyExchange_RSA_EXPORT
073: || keyExchange == CipherSuite.KeyExchange_RSA
074: || keyExchange == CipherSuite.KeyExchange_DHE_RSA
075: || keyExchange == CipherSuite.KeyExchange_DHE_RSA_EXPORT) {
076: // SignatureAlgorithm is rsa
077: md5 = MessageDigest.getInstance("MD5");
078: sha = MessageDigest.getInstance("SHA-1");
079: cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
080: } else if (keyExchange == CipherSuite.KeyExchange_DHE_DSS
081: || keyExchange == CipherSuite.KeyExchange_DHE_DSS_EXPORT) {
082: // SignatureAlgorithm is dsa
083: sha = MessageDigest.getInstance("SHA-1");
084: signature = Signature.getInstance("NONEwithDSA");
085: // The Signature should be empty in case of anonimous signature algorithm:
086: // } else if (keyExchange == CipherSuite.KeyExchange_DH_anon ||
087: // keyExchange == CipherSuite.KeyExchange_DH_anon_EXPORT) {
088: //
089: }
090: } catch (Exception e) {
091: throw new AlertException(
092: AlertProtocol.INTERNAL_ERROR,
093: new SSLException(
094: "INTERNAL ERROR: Unexpected exception on digital signature",
095: e));
096: }
097:
098: }
099:
100: /**
101: * Initiate Signature type by private key
102: * @param key
103: */
104: public void init(PrivateKey key) {
105: try {
106: if (signature != null) {
107: signature.initSign(key);
108: } else if (cipher != null) {
109: cipher.init(Cipher.ENCRYPT_MODE, key);
110: }
111: } catch (Exception e) {
112: e.printStackTrace();
113: }
114: }
115:
116: /**
117: * Initiate Signature type by certificate
118: * @param cert
119: */
120: public void init(Certificate cert) {
121: try {
122: if (signature != null) {
123: signature.initVerify(cert);
124: } else if (cipher != null) {
125: cipher.init(Cipher.DECRYPT_MODE, cert);
126: }
127: } catch (Exception e) {
128: e.printStackTrace();
129: }
130: }
131:
132: /**
133: * Update Signature hash
134: * @param data
135: */
136: public void update(byte[] data) {
137: try {
138: if (sha != null) {
139: sha.update(data);
140: }
141: if (md5 != null) {
142: md5.update(data);
143: }
144: } catch (Exception e) {
145: e.printStackTrace();
146: }
147: }
148:
149: /**
150: * Sets MD5 hash
151: * @param data
152: */
153: public void setMD5(byte[] data) {
154: md5_hash = data;
155: }
156:
157: /**
158: * Sets SHA hash
159: * @param data
160: */
161: public void setSHA(byte[] data) {
162: sha_hash = data;
163: }
164:
165: /**
166: * Sign hash
167: * @return Signature bytes
168: */
169: public byte[] sign() {
170: try {
171: if (md5 != null && md5_hash == null) {
172: md5_hash = new byte[16];
173: md5.digest(md5_hash, 0, md5_hash.length);
174: }
175: if (md5_hash != null) {
176: if (signature != null) {
177: signature.update(md5_hash);
178: } else if (cipher != null) {
179: cipher.update(md5_hash);
180: }
181: }
182: if (sha != null && sha_hash == null) {
183: sha_hash = new byte[20];
184: sha.digest(sha_hash, 0, sha_hash.length);
185: }
186: if (sha_hash != null) {
187: if (signature != null) {
188: signature.update(sha_hash);
189: } else if (cipher != null) {
190: cipher.update(sha_hash);
191: }
192: }
193: if (signature != null) {
194: return signature.sign();
195: } else if (cipher != null) {
196: return cipher.doFinal();
197: }
198: return new byte[0];
199: } catch (Exception e) {
200: e.printStackTrace();
201: return new byte[0];
202: }
203: }
204:
205: /**
206: * Verifies the signature data.
207: * @param data - the signature bytes
208: * @return true if verified
209: */
210: public boolean verifySignature(byte[] data) {
211: try {
212: if (signature != null) {
213: return signature.verify(data);
214: } else if (cipher != null) {
215: byte[] decrypt = cipher.doFinal(data);
216: byte[] md5_sha;
217: if (md5_hash != null && sha_hash != null) {
218: md5_sha = new byte[md5_hash.length
219: + sha_hash.length];
220: System.arraycopy(md5_hash, 0, md5_sha, 0,
221: md5_hash.length);
222: System.arraycopy(sha_hash, 0, md5_sha,
223: md5_hash.length, sha_hash.length);
224: } else if (md5_hash != null) {
225: md5_sha = md5_hash;
226: } else {
227: md5_sha = sha_hash;
228: }
229: if (Arrays.equals(decrypt, md5_sha)) {
230: return true;
231: } else {
232: return false;
233: }
234: } else if (data == null || data.length == 0) {
235: return true;
236: } else {
237: return false;
238: }
239: } catch (Exception e) {
240: e.printStackTrace();
241: return false;
242: }
243: }
244:
245: }
|