001: /*
002: * @(#)RSASig.java 1.10 02/07/24 @(#)
003: *
004: * Copyright (c) 2000-2001 Sun Microsystems, Inc. All rights reserved.
005: * PROPRIETARY/CONFIDENTIAL
006: * Use is subject to license terms.
007: */
008:
009: package com.sun.portal.kssl;
010:
011: import com.sun.portal.ksecurity.CryptoException;
012: import com.sun.portal.ksecurity.MessageDigest;
013: import com.sun.portal.ksecurity.Key;
014: import com.sun.portal.ksecurity.KeyBuilder;
015:
016: /**
017: * Implements RSA Signatures.
018: */
019: final class RSASig extends Signature {
020: /** Current algorithm. */
021: byte alg;
022: /** Current message digest. */
023: MessageDigest md = null;
024: /** Current certificate mode. */
025: byte mode = Signature.MODE_UNKNOWN;
026: /** Current key. */
027: Key k = null;
028:
029: /**
030: * Expected prefix in the decrypted result when MD5 hashing is used
031: * with RSA signing. This prefix is followed by the MD5 hash.
032: * If you are interested, more details are in the comments around
033: * the verify method in X509Certificate.
034: */
035: private static final byte[] PREFIX_MD5 = { (byte) 0x30,
036: (byte) 0x20, (byte) 0x30, (byte) 0x0c, (byte) 0x06,
037: (byte) 0x08, (byte) 0x2a, (byte) 0x86, (byte) 0x48,
038: (byte) 0x86, (byte) 0xf7, (byte) 0x0d, (byte) 0x02,
039: (byte) 0x05, (byte) 0x05, (byte) 0x00, (byte) 0x04,
040: (byte) 0x10 };
041:
042: /**
043: * Expected prefix in decrypted value when SHA-1 hash is used
044: * with RSA signing. This prefix is followed by the SHA hash.
045: */
046: private static final byte[] PREFIX_SHA1 = { (byte) 0x30,
047: (byte) 0x21, (byte) 0x30, (byte) 0x09, (byte) 0x06,
048: (byte) 0x05, (byte) 0x2b, (byte) 0x0e, (byte) 0x03,
049: (byte) 0x02, (byte) 0x1a, (byte) 0x05, (byte) 0x00,
050: (byte) 0x04, (byte) 0x14 };
051:
052: /**
053: * Constructs an RSA signature object that uses the specified
054: * signature algorithm.
055: *
056: * @param a one of ALG_RSA_MD5_PKCS1 or ALG_RSA_SHA_PKCS1
057: */
058: RSASig(byte a) {
059: alg = a;
060: try {
061: if (alg == Signature.ALG_RSA_MD5_PKCS1)
062: md = MessageDigest.getInstance(MessageDigest.ALG_MD5,
063: false);
064: else if (alg == Signature.ALG_RSA_SHA_PKCS1)
065: md = MessageDigest.getInstance(MessageDigest.ALG_SHA,
066: false);
067: } catch (Exception e) {
068: md = null;
069: }
070: }
071:
072: /**
073: * Gets the signature algorithm.
074: *
075: * @return the algorithmimplemented by this signature object
076: */
077: public byte getAlgorithm() {
078: return alg;
079: }
080:
081: /**
082: * Gets the byte-length of the signature.
083: *
084: * @return the byte-length of the signature produced by this object
085: */
086: public short getLength() {
087: if (k == null)
088: return (short) 0;
089: else
090: // return the modulus length in bytes
091: return (short) (k.getSize() >>> 3);
092: }
093:
094: /**
095: * Initializes the <CODE>RSASig</CODE> object with the appropriate
096: * <CODE>Key</CODE> for signature creation or verification.
097: *
098: * @param theKey the key object to use for signing or verification
099: * @param theMode one of <CODE>MODE_SIGN</CODE> or
100: * <CODE>MODE_VERIFY</CODE>
101: * @exception CryptoException with reason code <CODE>ILLEGAL_VALUE</CODE>
102: * if an invalid mode is specified or if the key type is inconsistent
103: * with the mode or signature implementation.
104: */
105: public void init(Key theKey, byte theMode) throws CryptoException {
106: if (((theMode == Signature.MODE_SIGN) && (theKey.getType() == KeyBuilder.TYPE_RSA_PRIVATE))
107: || ((theMode == Signature.MODE_VERIFY) && (theKey
108: .getType() == KeyBuilder.TYPE_RSA_PUBLIC))) {
109: k = theKey;
110: mode = theMode;
111: } else {
112: throw new CryptoException(CryptoException.ILLEGAL_VALUE);
113: }
114: }
115:
116: /**
117: * Initializes the <CODE>RSASig</CODE> object with the appropriate
118: * <CODE>Key</CODE> and algorithm specific parameters for signature
119: * creation or verification.
120: *
121: * @param theKey the key object to use for signing or verification
122: * @param theMode one of <CODE>MODE_SIGN</CODE> or
123: * <CODE>MODE_VERIFY</CODE>
124: * @param b byte array containing algorithm specific parameters
125: * @param off starting offset of parameter data within the byte array
126: * @param len byte length of parameter data
127: * @exception CryptoException with reason code <CODE>ILLEGAL_VALUE</CODE>
128: * if an invalid mode is specified or if the key type is inconsistent
129: * with the mode or signature implementation or if this initialization mode
130: * is not supported by the signature algorithm
131: */
132: public void init(Key theKey, byte theMode, byte[] b, int off,
133: int len) throws CryptoException {
134: throw new CryptoException(CryptoException.ILLEGAL_VALUE);
135: }
136:
137: /**
138: * Accumulates a signature of the input data. When this method is used,
139: * temporary storage of intermediate results is required. This method
140: * should only be used if all the input data required for the signature
141: * is not available in one byte array. The sign() or verify() method is
142: * recommended whenever possible.
143: *
144: * @param inBuf the input buffer of data to be signed
145: * @param inOff starting offset within the input buffer for data to
146: * be signed
147: * @param inLen the byte length of data to be signed
148: * @exception CryptoException with <CODE>UNINITIALIZED_KEY</CODE>
149: * or <CODE>INVALID_INIT</CODE> if the signature object
150: * is not properly initialized
151: * @see #verify(byte[], int, int, byte[], int, short)
152: */
153: public void update(byte[] inBuf, int inOff, int inLen)
154: throws CryptoException {
155: if (k == null)
156: throw new CryptoException(CryptoException.UNINITIALIZED_KEY);
157: if ((md == null)
158: || ((mode != Signature.MODE_SIGN) && (mode != Signature.MODE_VERIFY)))
159: throw new CryptoException(CryptoException.INVALID_INIT);
160: md.update(inBuf, inOff, inLen);
161: }
162:
163: /**
164: * Generates the signature of all/last input data. A call to this
165: * method also resets this signature object to the state it was in
166: * when previously initialized via a call to init(). That is, the
167: * object is reset and available to sign another message.
168: *
169: * @param inBuf the input buffer of data to be signed
170: * @param inOff starting offset within the input buffer for data to
171: * be signed
172: * @param inLen the byte length of data to be signed
173: * @param sigBuf the output buffer to store signature data
174: * @param sigOff starting offset within the output buffer at which
175: * to begin signature data
176: * @return number of bytes of signature output in sigBuf
177: * @exception CryptoException with the following reason codes: (i)
178: * <CODE>UNINITIALIZED_KEY</CODE> if key is not initialized, (ii)
179: * <CODE>INVALID_INIT</CODE> if signature object wasn not
180: * properly initialized, for signing (iii) <CODE>ILLEGAL_USE</CODE>
181: * if the signature algorithm does not pad the message and the
182: * message is not block aligned
183: */
184: public short sign(byte[] inBuf, int inOff, int inLen,
185: byte[] sigBuf, int sigOff) throws CryptoException {
186: if (k == null)
187: throw new CryptoException(CryptoException.UNINITIALIZED_KEY);
188: if ((md == null) || (mode != Signature.MODE_SIGN))
189: throw new CryptoException(CryptoException.INVALID_INIT);
190: byte[] prefix = null;
191: if (alg == Signature.ALG_RSA_MD5_PKCS1) {
192: prefix = PREFIX_MD5;
193: } else {
194: prefix = PREFIX_SHA1;
195: }
196: byte[] data = new byte[prefix.length + md.getLength()];
197: // Include the OID of signing algorithm in padding
198: System.arraycopy(prefix, 0, data, 0, prefix.length);
199: md.doFinal(inBuf, inOff, inLen, data, prefix.length);
200:
201: Cipher c = Cipher.getInstance(Cipher.ALG_RSA_PKCS1, false);
202: c.init(k, Cipher.MODE_ENCRYPT);
203:
204: /*
205: * we can cast to a short because a private key encryption is
206: * is less than the key length, which is a short.
207: */
208: return (short) c.doFinal(data, 0, data.length, sigBuf, sigOff);
209: };
210:
211: /**
212: * Verifies the signature of all/last input data against the passed
213: * in signature. A call to this method also resets this signature
214: * object to the state it was in when previously initialized via a
215: * call to init(). That is, the object is reset and available to
216: * verify another message.
217: *
218: * @param inBuf the input buffer of data to be verified
219: * @param inOff starting offset within the input buffer for data to
220: * be verified
221: * @param inLen the byte length of data to be verified
222: * @param sigBuf the input buffer containing signature data
223: * @param sigOff starting offset within the sigBuf where signature
224: * data begins
225: * @param sigLen byte length of signature data
226: * @return true if signature verifies, false otherwise
227: * @exception CryptoException with the following reason codes: (i)
228: * <CODE>UNINITIALIZED_KEY</CODE> if key is not initialized, (ii)
229: * <CODE>INVALID_INIT</CODE> if signature object wasn not
230: * properly initialized, for verification (iii) <CODE>ILLEGAL_USE</CODE>
231: * if the signature algorithm does not pad the message and the
232: * message is not block aligned
233: */
234: public boolean verify(byte[] inBuf, int inOff, int inLen,
235: byte[] sigBuf, int sigOff, short sigLen)
236: throws CryptoException {
237: if (k == null)
238: throw new CryptoException(CryptoException.UNINITIALIZED_KEY);
239: if ((md == null) || (mode != Signature.MODE_VERIFY))
240: throw new CryptoException(CryptoException.INVALID_INIT);
241: byte[] res = null;
242: int val;
243: byte[] digest = new byte[md.getLength()];
244:
245: md.doFinal(inBuf, inOff, inLen, digest, 0);
246: try {
247: Cipher c = Cipher.getInstance(Cipher.ALG_RSA_PKCS1, false);
248: c.init(k, Cipher.MODE_DECRYPT);
249: res = new byte[k.getSize() >>> 3];
250: val = c.doFinal(sigBuf, sigOff, sigLen, res, 0);
251: } catch (Exception e) {
252: return false;
253: }
254: byte[] prefix = null;
255: int size = 0;
256: if (alg == Signature.ALG_RSA_MD5_PKCS1) {
257: prefix = PREFIX_MD5;
258: size = prefix.length + 16;
259: } else {
260: prefix = PREFIX_SHA1;
261: size = prefix.length + 20;
262: }
263: if (val != size)
264: return false;
265: // Match the prefix corresponding to the signature algorithm
266: for (int i = 0; i < prefix.length; i++) {
267: if (res[i] != prefix[i])
268: return false;
269: }
270: for (int i = prefix.length; i < size; i++) {
271: if (res[i] != digest[i - prefix.length])
272: return false;
273: }
274: return true;
275: }
276: }
|