001: /*
002: *
003: *
004: * Copyright 1990-2007 Sun Microsystems, Inc. All Rights Reserved.
005: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
006: *
007: * This program is free software; you can redistribute it and/or
008: * modify it under the terms of the GNU General Public License version
009: * 2 only, as published by the Free Software Foundation.
010: *
011: * This program is distributed in the hope that it will be useful, but
012: * WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014: * General Public License version 2 for more details (a copy is
015: * included at /legal/license.txt).
016: *
017: * You should have received a copy of the GNU General Public License
018: * version 2 along with this work; if not, write to the Free Software
019: * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
020: * 02110-1301 USA
021: *
022: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
023: * Clara, CA 95054 or visit www.sun.com if you need additional
024: * information or have any questions.
025: */
026:
027: package com.sun.midp.crypto;
028:
029: /**
030: * Implements RSA Signatures.
031: */
032: final class RSASig {
033:
034: /** Current algorithm. */
035: String alg;
036:
037: /** Current message digest. */
038: MessageDigest md = null;
039:
040: /** Current cipher. */
041: Cipher c = null;
042:
043: /** Current key. */
044: RSAKey k = null;
045:
046: /** Signature prefix. */
047: byte[] prefix;
048:
049: /**
050: * Constructs an RSA signature object that uses the specified
051: * signature algorithm.
052: *
053: * @param sigPrefix Prefix for the signature
054: * @param messageDigest Message digest for the signature
055: *
056: * @exception NoSuchAlgorithmException if RSA is
057: * not available in the caller's environment.
058: */
059: RSASig(byte[] sigPrefix, MessageDigest messageDigest)
060: throws NoSuchAlgorithmException {
061: prefix = sigPrefix;
062: md = messageDigest;
063:
064: try {
065: c = Cipher.getInstance("RSA");
066: } catch (NoSuchPaddingException e) {
067: // we used the default mode and padding this should not happen
068: throw new NoSuchAlgorithmException();
069: }
070: }
071:
072: /**
073: * Gets the byte-length of the signature.
074: *
075: * @return the byte-length of the signature produced by this object
076: */
077: public int getLength() {
078: if (k == null)
079: return (short) 0;
080: else
081: // return the modulus length in bytes
082: return (short) k.getModulusLen();
083: }
084:
085: /**
086: * Initializes the <CODE>RSASig</CODE> object with the appropriate
087: * <CODE>Key</CODE> for signature verification.
088: *
089: * @param theKey the key object to use for verification
090: *
091: * @exception InvalidKeyException if the key type is inconsistent
092: * with the mode or signature implementation.
093: */
094: public void initVerify(PublicKey theKey) throws InvalidKeyException {
095: if (!(theKey instanceof RSAPublicKey)) {
096: throw new InvalidKeyException();
097: }
098:
099: c.init(Cipher.DECRYPT_MODE, theKey);
100:
101: k = (RSAKey) theKey;
102: }
103:
104: /**
105: * Initializes the <CODE>RSASig</CODE> object with the appropriate
106: * <CODE>Key</CODE> for signature creation.
107: *
108: * @param theKey the key object to use for signing
109: *
110: * @exception InvalidKeyException if the key type is inconsistent
111: * with the mode or signature implementation.
112: */
113: public void initSign(PrivateKey theKey) throws InvalidKeyException {
114: if (!(theKey instanceof RSAPrivateKey)) {
115: throw new InvalidKeyException();
116: }
117:
118: c.init(Cipher.ENCRYPT_MODE, theKey);
119:
120: k = (RSAKey) theKey;
121: }
122:
123: /**
124: * Accumulates a signature of the input data. When this method is used,
125: * temporary storage of intermediate results is required. This method
126: * should only be used if all the input data required for the signature
127: * is not available in one byte array. The sign() or verify() method is
128: * recommended whenever possible.
129: *
130: * @param inBuf the input buffer of data to be signed
131: * @param inOff starting offset within the input buffer for data to
132: * be signed
133: * @param inLen the byte length of data to be signed
134: *
135: * @exception SignatureException if this signature object is not
136: * initialized properly.
137: */
138: public void update(byte[] inBuf, int inOff, int inLen)
139: throws SignatureException {
140: if (k == null) {
141: throw new SignatureException("Illegal State");
142: }
143:
144: md.update(inBuf, inOff, inLen);
145: }
146:
147: /**
148: * Generates the signature of all/last input data. A call to this
149: * method also resets this signature object to the state it was in
150: * when previously initialized via a call to init(). That is, the
151: * object is reset and available to sign another message.
152: *
153: * @param sigBuf the output buffer to store signature data
154: * @param sigOff starting offset within the output buffer at which
155: * to begin signature data
156: * @param sigLen max byte length of signature data
157: *
158: * @return number of bytes of signature output in sigBuf
159: *
160: * @exception SignatureException if this signature object is not
161: * initialized properly, or len is less than the actual signature
162: */
163: public int sign(byte[] sigBuf, int sigOff, int sigLen)
164: throws SignatureException {
165: if (k == null || !(k instanceof RSAPrivateKey)) {
166: throw new SignatureException("Illegal State");
167: }
168:
169: if (sigLen < k.getModulusLen()) {
170: throw new SignatureException("Buffer too short");
171: }
172:
173: byte[] data = new byte[prefix.length + md.getDigestLength()];
174:
175: // Include the OID of signing algorithm in padding
176: System.arraycopy(prefix, 0, data, 0, prefix.length);
177: try {
178: md.digest(data, prefix.length, md.getDigestLength());
179:
180: /*
181: * we can cast to a short because a private key encryption is
182: * is less than the key length, which is a short.
183: */
184: return c.doFinal(data, 0, data.length, sigBuf, sigOff);
185: } catch (GeneralSecurityException ce) {
186: throw new SignatureException(ce.getMessage());
187: }
188: };
189:
190: /**
191: * Verifies the signature of all/last input data against the passed
192: * in signature. A call to this method also resets this signature
193: * object to the state it was in when previously initialized via a
194: * call to init(). That is, the object is reset and available to
195: * verify another message.
196: *
197: * @param sigBuf the input buffer containing signature data
198: * @param sigOff starting offset within the sigBuf where signature
199: * data begins
200: * @param sigLen byte length of signature data
201: *
202: * @return true if signature verifies, false otherwise
203: *
204: * @exception SignatureException if this signature object is not
205: * initialized properly, or the passed-in signature is improperly
206: * encoded or of the wrong type, etc.
207: */
208: public boolean verify(byte[] sigBuf, int sigOff, int sigLen)
209: throws SignatureException {
210: if (k == null || !(k instanceof RSAPublicKey)) {
211: throw new SignatureException("Illegal State");
212: }
213:
214: byte[] res = null;
215: int val;
216: byte[] digest = new byte[md.getDigestLength()];
217:
218: try {
219: md.digest(digest, 0, digest.length);
220: res = new byte[k.getModulusLen()];
221: val = c.doFinal(sigBuf, sigOff, sigLen, res, 0);
222: } catch (IllegalArgumentException iae) {
223: throw new SignatureException(iae.getMessage());
224: } catch (GeneralSecurityException e) {
225: return false;
226: }
227:
228: int size = prefix.length + md.getDigestLength();
229:
230: if (val != size) {
231: return false;
232: }
233:
234: // Match the prefix corresponding to the signature algorithm
235: for (int i = 0; i < prefix.length; i++) {
236: if (res[i] != prefix[i]) {
237: return false;
238: }
239: }
240:
241: for (int i = prefix.length; i < size; i++) {
242: if (res[i] != digest[i - prefix.length]) {
243: return false;
244: }
245: }
246:
247: return true;
248: }
249: }
|