001: /*
002: * Copyright 2005 Sun Microsystems, Inc. All Rights Reserved.
003: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004: *
005: * This code is free software; you can redistribute it and/or modify it
006: * under the terms of the GNU General Public License version 2 only, as
007: * published by the Free Software Foundation. Sun designates this
008: * particular file as subject to the "Classpath" exception as provided
009: * by Sun in the LICENSE file that accompanied this code.
010: *
011: * This code is distributed in the hope that it will be useful, but WITHOUT
012: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
013: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
014: * version 2 for more details (a copy is included in the LICENSE file that
015: * accompanied this code).
016: *
017: * You should have received a copy of the GNU General Public License version
018: * 2 along with this work; if not, write to the Free Software Foundation,
019: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
020: *
021: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
022: * CA 95054 USA or visit www.sun.com if you need additional information or
023: * have any questions.
024: */
025:
026: package sun.security.mscapi;
027:
028: import java.nio.ByteBuffer;
029: import java.security.PublicKey;
030: import java.security.PrivateKey;
031: import java.security.InvalidKeyException;
032: import java.security.InvalidParameterException;
033: import java.security.InvalidAlgorithmParameterException;
034: import java.security.NoSuchAlgorithmException;
035: import java.security.ProviderException;
036: import java.security.MessageDigest;
037: import java.security.SecureRandom;
038: import java.security.Signature;
039: import java.security.SignatureSpi;
040: import java.security.SignatureException;
041:
042: /**
043: * RSA signature implementation. Supports RSA signing using PKCS#1 v1.5 padding.
044: *
045: * Objects should be instantiated by calling Signature.getInstance() using the
046: * following algorithm names:
047: *
048: * . "SHA1withRSA"
049: * . "MD5withRSA"
050: * . "MD2withRSA"
051: *
052: * Note: RSA keys must be at least 512 bits long
053: *
054: * @since 1.6
055: * @author Stanley Man-Kit Ho
056: */
057: abstract class RSASignature extends java.security.SignatureSpi {
058: // message digest implementation we use
059: private final MessageDigest messageDigest;
060:
061: // flag indicating whether the digest is reset
062: private boolean needsReset;
063:
064: // the signing key
065: private Key privateKey = null;
066:
067: // the verification key
068: private Key publicKey = null;
069:
070: RSASignature(String digestName) {
071:
072: try {
073: messageDigest = MessageDigest.getInstance(digestName);
074:
075: } catch (NoSuchAlgorithmException e) {
076: throw new ProviderException(e);
077: }
078:
079: needsReset = false;
080: }
081:
082: public static final class SHA1 extends RSASignature {
083: public SHA1() {
084: super ("SHA1");
085: }
086: }
087:
088: public static final class MD5 extends RSASignature {
089: public MD5() {
090: super ("MD5");
091: }
092: }
093:
094: public static final class MD2 extends RSASignature {
095: public MD2() {
096: super ("MD2");
097: }
098: }
099:
100: /**
101: * Initializes this signature object with the specified
102: * public key for verification operations.
103: *
104: * @param publicKey the public key of the identity whose signature is
105: * going to be verified.
106: *
107: * @exception InvalidKeyException if the key is improperly
108: * encoded, parameters are missing, and so on.
109: */
110: protected void engineInitVerify(PublicKey key)
111: throws InvalidKeyException {
112: // This signature accepts only RSAPublicKey
113: if ((key instanceof java.security.interfaces.RSAPublicKey) == false) {
114: throw new InvalidKeyException("Key type not supported");
115: }
116:
117: java.security.interfaces.RSAPublicKey rsaKey = (java.security.interfaces.RSAPublicKey) key;
118:
119: if ((key instanceof sun.security.mscapi.RSAPublicKey) == false) {
120:
121: // convert key to MSCAPI format
122:
123: byte[] modulusBytes = rsaKey.getModulus().toByteArray();
124:
125: // Adjust key length due to sign bit
126: int keyBitLength = (modulusBytes[0] == 0) ? (modulusBytes.length - 1) * 8
127: : modulusBytes.length * 8;
128:
129: byte[] keyBlob = generatePublicKeyBlob(keyBitLength,
130: modulusBytes, rsaKey.getPublicExponent()
131: .toByteArray());
132:
133: publicKey = importPublicKey(keyBlob, keyBitLength);
134:
135: } else {
136: publicKey = (sun.security.mscapi.RSAPublicKey) key;
137: }
138:
139: if (needsReset) {
140: messageDigest.reset();
141: needsReset = false;
142: }
143: }
144:
145: /**
146: * Initializes this signature object with the specified
147: * private key for signing operations.
148: *
149: * @param privateKey the private key of the identity whose signature
150: * will be generated.
151: *
152: * @exception InvalidKeyException if the key is improperly
153: * encoded, parameters are missing, and so on.
154: */
155: protected void engineInitSign(PrivateKey key)
156: throws InvalidKeyException {
157: // This signature accepts only RSAPrivateKey
158: if ((key instanceof sun.security.mscapi.RSAPrivateKey) == false) {
159: throw new InvalidKeyException("Key type not supported");
160: }
161: privateKey = (sun.security.mscapi.RSAPrivateKey) key;
162:
163: // Determine byte length from bit length
164: int keySize = (privateKey.bitLength() + 7) >> 3;
165:
166: if (keySize < 64)
167: throw new InvalidKeyException(
168: "RSA keys must be at least 512 bits long");
169:
170: if (needsReset) {
171: messageDigest.reset();
172: needsReset = false;
173: }
174: }
175:
176: /**
177: * Updates the data to be signed or verified
178: * using the specified byte.
179: *
180: * @param b the byte to use for the update.
181: *
182: * @exception SignatureException if the engine is not initialized
183: * properly.
184: */
185: protected void engineUpdate(byte b) throws SignatureException {
186: messageDigest.update(b);
187: needsReset = true;
188: }
189:
190: /**
191: * Updates the data to be signed or verified, using the
192: * specified array of bytes, starting at the specified offset.
193: *
194: * @param b the array of bytes
195: * @param off the offset to start from in the array of bytes
196: * @param len the number of bytes to use, starting at offset
197: *
198: * @exception SignatureException if the engine is not initialized
199: * properly
200: */
201: protected void engineUpdate(byte[] b, int off, int len)
202: throws SignatureException {
203: messageDigest.update(b, off, len);
204: needsReset = true;
205: }
206:
207: /**
208: * Updates the data to be signed or verified, using the
209: * specified ByteBuffer.
210: *
211: * @param input the ByteBuffer
212: */
213: protected void engineUpdate(ByteBuffer input) {
214: messageDigest.update(input);
215: needsReset = true;
216: }
217:
218: /**
219: * Returns the signature bytes of all the data
220: * updated so far.
221: * The format of the signature depends on the underlying
222: * signature scheme.
223: *
224: * @return the signature bytes of the signing operation's result.
225: *
226: * @exception SignatureException if the engine is not
227: * initialized properly or if this signature algorithm is unable to
228: * process the input data provided.
229: */
230: protected byte[] engineSign() throws SignatureException {
231:
232: byte[] hash = messageDigest.digest();
233: needsReset = false;
234:
235: // Sign hash using MS Crypto APIs
236:
237: byte[] result = signHash(hash, hash.length, messageDigest
238: .getAlgorithm(), privateKey.getHCryptProvider(),
239: privateKey.getHCryptKey());
240:
241: // Convert signature array from little endian to big endian
242: return convertEndianArray(result);
243: }
244:
245: /**
246: * Convert array from big endian to little endian, or vice versa.
247: */
248: private byte[] convertEndianArray(byte[] byteArray) {
249: if (byteArray == null || byteArray.length == 0)
250: return byteArray;
251:
252: byte[] retval = new byte[byteArray.length];
253:
254: // make it big endian
255: for (int i = 0; i < byteArray.length; i++)
256: retval[i] = byteArray[byteArray.length - i - 1];
257:
258: return retval;
259: }
260:
261: /**
262: * Sign hash using Microsoft Crypto API with HCRYPTKEY.
263: * The returned data is in little-endian.
264: */
265: private native static byte[] signHash(byte[] hash, int hashSize,
266: String hashAlgorithm, long hCryptProv, long hCryptKey)
267: throws SignatureException;
268:
269: /**
270: * Verify a signed hash using Microsoft Crypto API with HCRYPTKEY.
271: */
272: private native static boolean verifySignedHash(byte[] hash,
273: int hashSize, String hashAlgorithm, byte[] signature,
274: int signatureSize, long hCryptProv, long hCryptKey)
275: throws SignatureException;
276:
277: /**
278: * Verifies the passed-in signature.
279: *
280: * @param sigBytes the signature bytes to be verified.
281: *
282: * @return true if the signature was verified, false if not.
283: *
284: * @exception SignatureException if the engine is not
285: * initialized properly, the passed-in signature is improperly
286: * encoded or of the wrong type, if this signature algorithm is unable to
287: * process the input data provided, etc.
288: */
289: protected boolean engineVerify(byte[] sigBytes)
290: throws SignatureException {
291: byte[] hash = messageDigest.digest();
292: needsReset = false;
293:
294: return verifySignedHash(hash, hash.length, messageDigest
295: .getAlgorithm(), convertEndianArray(sigBytes),
296: sigBytes.length, publicKey.getHCryptProvider(),
297: publicKey.getHCryptKey());
298: }
299:
300: /**
301: * Sets the specified algorithm parameter to the specified
302: * value. This method supplies a general-purpose mechanism through
303: * which it is possible to set the various parameters of this object.
304: * A parameter may be any settable parameter for the algorithm, such as
305: * a parameter size, or a source of random bits for signature generation
306: * (if appropriate), or an indication of whether or not to perform
307: * a specific but optional computation. A uniform algorithm-specific
308: * naming scheme for each parameter is desirable but left unspecified
309: * at this time.
310: *
311: * @param param the string identifier of the parameter.
312: *
313: * @param value the parameter value.
314: *
315: * @exception InvalidParameterException if <code>param</code> is an
316: * invalid parameter for this signature algorithm engine,
317: * the parameter is already set
318: * and cannot be set again, a security exception occurs, and so on.
319: *
320: * @deprecated Replaced by {@link
321: * #engineSetParameter(java.security.spec.AlgorithmParameterSpec)
322: * engineSetParameter}.
323: */
324: protected void engineSetParameter(String param, Object value)
325: throws InvalidParameterException {
326: throw new InvalidParameterException("Parameter not supported");
327: }
328:
329: /**
330: * Gets the value of the specified algorithm parameter.
331: * This method supplies a general-purpose mechanism through which it
332: * is possible to get the various parameters of this object. A parameter
333: * may be any settable parameter for the algorithm, such as a parameter
334: * size, or a source of random bits for signature generation (if
335: * appropriate), or an indication of whether or not to perform a
336: * specific but optional computation. A uniform algorithm-specific
337: * naming scheme for each parameter is desirable but left unspecified
338: * at this time.
339: *
340: * @param param the string name of the parameter.
341: *
342: * @return the object that represents the parameter value, or null if
343: * there is none.
344: *
345: * @exception InvalidParameterException if <code>param</code> is an
346: * invalid parameter for this engine, or another exception occurs while
347: * trying to get this parameter.
348: *
349: * @deprecated
350: */
351: protected Object engineGetParameter(String param)
352: throws InvalidParameterException {
353: throw new InvalidParameterException("Parameter not supported");
354: }
355:
356: /**
357: * Generates a public-key BLOB from a key's components.
358: */
359: private native byte[] generatePublicKeyBlob(int keyBitLength,
360: byte[] modulus, byte[] publicExponent);
361:
362: /**
363: * Imports a public-key BLOB.
364: */
365: private native RSAPublicKey importPublicKey(byte[] keyBlob,
366: int keySize);
367: }
|