001: /*
002: * Copyright 2003-2006 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.rsa;
027:
028: import java.io.IOException;
029: import java.nio.ByteBuffer;
030: import java.math.BigInteger;
031: import java.util.Arrays;
032:
033: import java.security.*;
034: import java.security.interfaces.*;
035:
036: import sun.security.util.*;
037: import sun.security.x509.AlgorithmId;
038:
039: /**
040: * PKCS#1 RSA signatures with the various message digest algorithms.
041: * This file contains an abstract base class with all the logic plus
042: * a nested static class for each of the message digest algorithms
043: * (see end of the file). We support MD2, MD5, SHA-1, SHA-256, SHA-384,
044: * and SHA-512.
045: *
046: * @since 1.5
047: * @version 1.12, 05/05/07
048: * @author Andreas Sterbenz
049: */
050: public abstract class RSASignature extends SignatureSpi {
051:
052: // we sign an ASN.1 SEQUENCE of AlgorithmId and digest
053: // it has the form 30:xx:30:0c:[digestOID]:05:00:04:xx:[digest]
054: // this means the encoded length is (8 + digestOID.length + digest.length)
055: private static final int baseLength = 8;
056:
057: // object identifier for the message digest algorithm used
058: private final ObjectIdentifier digestOID;
059:
060: // length of the encoded signature blob
061: private final int encodedLength;
062:
063: // message digest implementation we use
064: private final MessageDigest md;
065: // flag indicating whether the digest is reset
066: private boolean digestReset;
067:
068: // private key, if initialized for signing
069: private RSAPrivateKey privateKey;
070: // public key, if initialized for verifying
071: private RSAPublicKey publicKey;
072:
073: // padding to use, set when the initSign/initVerify is called
074: private RSAPadding padding;
075:
076: /**
077: * Construct a new RSASignature. Used by subclasses.
078: */
079: RSASignature(String algorithm, ObjectIdentifier digestOID,
080: int oidLength) {
081: this .digestOID = digestOID;
082: try {
083: md = MessageDigest.getInstance(algorithm);
084: } catch (NoSuchAlgorithmException e) {
085: throw new ProviderException(e);
086: }
087: digestReset = true;
088: encodedLength = baseLength + oidLength + md.getDigestLength();
089: }
090:
091: // initialize for verification. See JCA doc
092: protected void engineInitVerify(PublicKey publicKey)
093: throws InvalidKeyException {
094: RSAPublicKey rsaKey = (RSAPublicKey) RSAKeyFactory
095: .toRSAKey(publicKey);
096: this .privateKey = null;
097: this .publicKey = rsaKey;
098: initCommon(rsaKey, null);
099: }
100:
101: // initialize for signing. See JCA doc
102: protected void engineInitSign(PrivateKey privateKey)
103: throws InvalidKeyException {
104: engineInitSign(privateKey, null);
105: }
106:
107: // initialize for signing. See JCA doc
108: protected void engineInitSign(PrivateKey privateKey,
109: SecureRandom random) throws InvalidKeyException {
110: RSAPrivateKey rsaKey = (RSAPrivateKey) RSAKeyFactory
111: .toRSAKey(privateKey);
112: this .privateKey = rsaKey;
113: this .publicKey = null;
114: initCommon(rsaKey, random);
115: }
116:
117: /**
118: * Init code common to sign and verify.
119: */
120: private void initCommon(RSAKey rsaKey, SecureRandom random)
121: throws InvalidKeyException {
122: resetDigest();
123: int keySize = RSACore.getByteLength(rsaKey);
124: try {
125: padding = RSAPadding.getInstance(
126: RSAPadding.PAD_BLOCKTYPE_1, keySize, random);
127: } catch (InvalidAlgorithmParameterException iape) {
128: throw new InvalidKeyException(iape.getMessage());
129: }
130: int maxDataSize = padding.getMaxDataSize();
131: if (encodedLength > maxDataSize) {
132: throw new InvalidKeyException(
133: "Key is too short for this signature algorithm");
134: }
135: }
136:
137: /**
138: * Reset the message digest if it is not already reset.
139: */
140: private void resetDigest() {
141: if (digestReset == false) {
142: md.reset();
143: digestReset = true;
144: }
145: }
146:
147: /**
148: * Return the message digest value.
149: */
150: private byte[] getDigestValue() {
151: digestReset = true;
152: return md.digest();
153: }
154:
155: // update the signature with the plaintext data. See JCA doc
156: protected void engineUpdate(byte b) throws SignatureException {
157: md.update(b);
158: digestReset = false;
159: }
160:
161: // update the signature with the plaintext data. See JCA doc
162: protected void engineUpdate(byte[] b, int off, int len)
163: throws SignatureException {
164: md.update(b, off, len);
165: digestReset = false;
166: }
167:
168: // update the signature with the plaintext data. See JCA doc
169: protected void engineUpdate(ByteBuffer b) {
170: md.update(b);
171: digestReset = false;
172: }
173:
174: // sign the data and return the signature. See JCA doc
175: protected byte[] engineSign() throws SignatureException {
176: byte[] digest = getDigestValue();
177: try {
178: byte[] encoded = encodeSignature(digestOID, digest);
179: byte[] padded = padding.pad(encoded);
180: byte[] encrypted = RSACore.rsa(padded, privateKey);
181: return encrypted;
182: } catch (GeneralSecurityException e) {
183: throw new SignatureException("Could not sign data", e);
184: } catch (IOException e) {
185: throw new SignatureException("Could not encode data", e);
186: }
187: }
188:
189: // verify the data and return the result. See JCA doc
190: protected boolean engineVerify(byte[] sigBytes)
191: throws SignatureException {
192: byte[] digest = getDigestValue();
193: try {
194: byte[] decrypted = RSACore.rsa(sigBytes, publicKey);
195: byte[] unpadded = padding.unpad(decrypted);
196: byte[] decodedDigest = decodeSignature(digestOID, unpadded);
197: return Arrays.equals(digest, decodedDigest);
198: } catch (javax.crypto.BadPaddingException e) {
199: // occurs if the app has used the wrong RSA public key
200: // or if sigBytes is invalid
201: // return false rather than propagating the exception for
202: // compatibility/ease of use
203: return false;
204: } catch (GeneralSecurityException e) {
205: throw new SignatureException(
206: "Signature verification failed", e);
207: } catch (IOException e) {
208: throw new SignatureException("Signature encoding error", e);
209: }
210: }
211:
212: /**
213: * Encode the digest, return the to-be-signed data.
214: * Also used by the PKCS#11 provider.
215: */
216: public static byte[] encodeSignature(ObjectIdentifier oid,
217: byte[] digest) throws IOException {
218: DerOutputStream out = new DerOutputStream();
219: new AlgorithmId(oid).encode(out);
220: out.putOctetString(digest);
221: DerValue result = new DerValue(DerValue.tag_Sequence, out
222: .toByteArray());
223: return result.toByteArray();
224: }
225:
226: /**
227: * Decode the signature data. Verify that the object identifier matches
228: * and return the message digest.
229: */
230: public static byte[] decodeSignature(ObjectIdentifier oid,
231: byte[] signature) throws IOException {
232: DerInputStream in = new DerInputStream(signature);
233: DerValue[] values = in.getSequence(2);
234: if ((values.length != 2) || (in.available() != 0)) {
235: throw new IOException("SEQUENCE length error");
236: }
237: AlgorithmId algId = AlgorithmId.parse(values[0]);
238: if (algId.getOID().equals(oid) == false) {
239: throw new IOException("ObjectIdentifier mismatch: "
240: + algId.getOID());
241: }
242: if (algId.getEncodedParams() != null) {
243: throw new IOException("Unexpected AlgorithmId parameters");
244: }
245: byte[] digest = values[1].getOctetString();
246: return digest;
247: }
248:
249: // set parameter, not supported. See JCA doc
250: protected void engineSetParameter(String param, Object value)
251: throws InvalidParameterException {
252: throw new UnsupportedOperationException(
253: "setParameter() not supported");
254: }
255:
256: // get parameter, not supported. See JCA doc
257: protected Object engineGetParameter(String param)
258: throws InvalidParameterException {
259: throw new UnsupportedOperationException(
260: "getParameter() not supported");
261: }
262:
263: // Nested class for MD2withRSA signatures
264: public static final class MD2withRSA extends RSASignature {
265: public MD2withRSA() {
266: super ("MD2", AlgorithmId.MD2_oid, 10);
267: }
268: }
269:
270: // Nested class for MD5withRSA signatures
271: public static final class MD5withRSA extends RSASignature {
272: public MD5withRSA() {
273: super ("MD5", AlgorithmId.MD5_oid, 10);
274: }
275: }
276:
277: // Nested class for SHA1withRSA signatures
278: public static final class SHA1withRSA extends RSASignature {
279: public SHA1withRSA() {
280: super ("SHA-1", AlgorithmId.SHA_oid, 7);
281: }
282: }
283:
284: // Nested class for SHA256withRSA signatures
285: public static final class SHA256withRSA extends RSASignature {
286: public SHA256withRSA() {
287: super ("SHA-256", AlgorithmId.SHA256_oid, 11);
288: }
289: }
290:
291: // Nested class for SHA384withRSA signatures
292: public static final class SHA384withRSA extends RSASignature {
293: public SHA384withRSA() {
294: super ("SHA-384", AlgorithmId.SHA384_oid, 11);
295: }
296: }
297:
298: // Nested class for SHA512withRSA signatures
299: public static final class SHA512withRSA extends RSASignature {
300: public SHA512withRSA() {
301: super ("SHA-512", AlgorithmId.SHA512_oid, 11);
302: }
303: }
304:
305: }
|