blob: d54d02814d846d44030c4303ca48e2950a969f37 [file] [log] [blame]
J. Duke319a3b92007-12-01 00:00:00 +00001/*
2 * Copyright 2003-2006 Sun Microsystems, Inc. All Rights Reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Sun designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Sun in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
22 * CA 95054 USA or visit www.sun.com if you need additional information or
23 * have any questions.
24 */
25
26package sun.security.rsa;
27
28import java.io.IOException;
29import java.nio.ByteBuffer;
30import java.math.BigInteger;
31import java.util.Arrays;
32
33import java.security.*;
34import java.security.interfaces.*;
35
36import sun.security.util.*;
37import sun.security.x509.AlgorithmId;
38
39/**
40 * PKCS#1 RSA signatures with the various message digest algorithms.
41 * This file contains an abstract base class with all the logic plus
42 * a nested static class for each of the message digest algorithms
43 * (see end of the file). We support MD2, MD5, SHA-1, SHA-256, SHA-384,
44 * and SHA-512.
45 *
46 * @since 1.5
47 * @author Andreas Sterbenz
48 */
49public abstract class RSASignature extends SignatureSpi {
50
51 // we sign an ASN.1 SEQUENCE of AlgorithmId and digest
52 // it has the form 30:xx:30:0c:[digestOID]:05:00:04:xx:[digest]
53 // this means the encoded length is (8 + digestOID.length + digest.length)
54 private static final int baseLength = 8;
55
56 // object identifier for the message digest algorithm used
57 private final ObjectIdentifier digestOID;
58
59 // length of the encoded signature blob
60 private final int encodedLength;
61
62 // message digest implementation we use
63 private final MessageDigest md;
64 // flag indicating whether the digest is reset
65 private boolean digestReset;
66
67 // private key, if initialized for signing
68 private RSAPrivateKey privateKey;
69 // public key, if initialized for verifying
70 private RSAPublicKey publicKey;
71
72 // padding to use, set when the initSign/initVerify is called
73 private RSAPadding padding;
74
75 /**
76 * Construct a new RSASignature. Used by subclasses.
77 */
78 RSASignature(String algorithm, ObjectIdentifier digestOID, int oidLength) {
79 this.digestOID = digestOID;
80 try {
81 md = MessageDigest.getInstance(algorithm);
82 } catch (NoSuchAlgorithmException e) {
83 throw new ProviderException(e);
84 }
85 digestReset = true;
86 encodedLength = baseLength + oidLength + md.getDigestLength();
87 }
88
89 // initialize for verification. See JCA doc
90 protected void engineInitVerify(PublicKey publicKey)
91 throws InvalidKeyException {
92 RSAPublicKey rsaKey = (RSAPublicKey)RSAKeyFactory.toRSAKey(publicKey);
93 this.privateKey = null;
94 this.publicKey = rsaKey;
95 initCommon(rsaKey, null);
96 }
97
98 // initialize for signing. See JCA doc
99 protected void engineInitSign(PrivateKey privateKey)
100 throws InvalidKeyException {
101 engineInitSign(privateKey, null);
102 }
103
104 // initialize for signing. See JCA doc
105 protected void engineInitSign(PrivateKey privateKey, SecureRandom random)
106 throws InvalidKeyException {
107 RSAPrivateKey rsaKey = (RSAPrivateKey)RSAKeyFactory.toRSAKey(privateKey);
108 this.privateKey = rsaKey;
109 this.publicKey = null;
110 initCommon(rsaKey, random);
111 }
112
113 /**
114 * Init code common to sign and verify.
115 */
116 private void initCommon(RSAKey rsaKey, SecureRandom random)
117 throws InvalidKeyException {
118 resetDigest();
119 int keySize = RSACore.getByteLength(rsaKey);
120 try {
121 padding = RSAPadding.getInstance
122 (RSAPadding.PAD_BLOCKTYPE_1, keySize, random);
123 } catch (InvalidAlgorithmParameterException iape) {
124 throw new InvalidKeyException(iape.getMessage());
125 }
126 int maxDataSize = padding.getMaxDataSize();
127 if (encodedLength > maxDataSize) {
128 throw new InvalidKeyException
129 ("Key is too short for this signature algorithm");
130 }
131 }
132
133 /**
134 * Reset the message digest if it is not already reset.
135 */
136 private void resetDigest() {
137 if (digestReset == false) {
138 md.reset();
139 digestReset = true;
140 }
141 }
142
143 /**
144 * Return the message digest value.
145 */
146 private byte[] getDigestValue() {
147 digestReset = true;
148 return md.digest();
149 }
150
151 // update the signature with the plaintext data. See JCA doc
152 protected void engineUpdate(byte b) throws SignatureException {
153 md.update(b);
154 digestReset = false;
155 }
156
157 // update the signature with the plaintext data. See JCA doc
158 protected void engineUpdate(byte[] b, int off, int len)
159 throws SignatureException {
160 md.update(b, off, len);
161 digestReset = false;
162 }
163
164 // update the signature with the plaintext data. See JCA doc
165 protected void engineUpdate(ByteBuffer b) {
166 md.update(b);
167 digestReset = false;
168 }
169
170 // sign the data and return the signature. See JCA doc
171 protected byte[] engineSign() throws SignatureException {
172 byte[] digest = getDigestValue();
173 try {
174 byte[] encoded = encodeSignature(digestOID, digest);
175 byte[] padded = padding.pad(encoded);
176 byte[] encrypted = RSACore.rsa(padded, privateKey);
177 return encrypted;
178 } catch (GeneralSecurityException e) {
179 throw new SignatureException("Could not sign data", e);
180 } catch (IOException e) {
181 throw new SignatureException("Could not encode data", e);
182 }
183 }
184
185 // verify the data and return the result. See JCA doc
186 protected boolean engineVerify(byte[] sigBytes) throws SignatureException {
187 byte[] digest = getDigestValue();
188 try {
189 byte[] decrypted = RSACore.rsa(sigBytes, publicKey);
190 byte[] unpadded = padding.unpad(decrypted);
191 byte[] decodedDigest = decodeSignature(digestOID, unpadded);
192 return Arrays.equals(digest, decodedDigest);
193 } catch (javax.crypto.BadPaddingException e) {
194 // occurs if the app has used the wrong RSA public key
195 // or if sigBytes is invalid
196 // return false rather than propagating the exception for
197 // compatibility/ease of use
198 return false;
199 } catch (GeneralSecurityException e) {
200 throw new SignatureException("Signature verification failed", e);
201 } catch (IOException e) {
202 throw new SignatureException("Signature encoding error", e);
203 }
204 }
205
206 /**
207 * Encode the digest, return the to-be-signed data.
208 * Also used by the PKCS#11 provider.
209 */
210 public static byte[] encodeSignature(ObjectIdentifier oid, byte[] digest)
211 throws IOException {
212 DerOutputStream out = new DerOutputStream();
213 new AlgorithmId(oid).encode(out);
214 out.putOctetString(digest);
215 DerValue result = new DerValue(DerValue.tag_Sequence, out.toByteArray());
216 return result.toByteArray();
217 }
218
219 /**
220 * Decode the signature data. Verify that the object identifier matches
221 * and return the message digest.
222 */
223 public static byte[] decodeSignature(ObjectIdentifier oid, byte[] signature)
224 throws IOException {
225 DerInputStream in = new DerInputStream(signature);
226 DerValue[] values = in.getSequence(2);
227 if ((values.length != 2) || (in.available() != 0)) {
228 throw new IOException("SEQUENCE length error");
229 }
230 AlgorithmId algId = AlgorithmId.parse(values[0]);
231 if (algId.getOID().equals(oid) == false) {
232 throw new IOException("ObjectIdentifier mismatch: " + algId.getOID());
233 }
234 if (algId.getEncodedParams() != null) {
235 throw new IOException("Unexpected AlgorithmId parameters");
236 }
237 byte[] digest = values[1].getOctetString();
238 return digest;
239 }
240
241 // set parameter, not supported. See JCA doc
242 protected void engineSetParameter(String param, Object value)
243 throws InvalidParameterException {
244 throw new UnsupportedOperationException("setParameter() not supported");
245 }
246
247 // get parameter, not supported. See JCA doc
248 protected Object engineGetParameter(String param)
249 throws InvalidParameterException {
250 throw new UnsupportedOperationException("getParameter() not supported");
251 }
252
253 // Nested class for MD2withRSA signatures
254 public static final class MD2withRSA extends RSASignature {
255 public MD2withRSA() {
256 super("MD2", AlgorithmId.MD2_oid, 10);
257 }
258 }
259
260 // Nested class for MD5withRSA signatures
261 public static final class MD5withRSA extends RSASignature {
262 public MD5withRSA() {
263 super("MD5", AlgorithmId.MD5_oid, 10);
264 }
265 }
266
267 // Nested class for SHA1withRSA signatures
268 public static final class SHA1withRSA extends RSASignature {
269 public SHA1withRSA() {
270 super("SHA-1", AlgorithmId.SHA_oid, 7);
271 }
272 }
273
274 // Nested class for SHA256withRSA signatures
275 public static final class SHA256withRSA extends RSASignature {
276 public SHA256withRSA() {
277 super("SHA-256", AlgorithmId.SHA256_oid, 11);
278 }
279 }
280
281 // Nested class for SHA384withRSA signatures
282 public static final class SHA384withRSA extends RSASignature {
283 public SHA384withRSA() {
284 super("SHA-384", AlgorithmId.SHA384_oid, 11);
285 }
286 }
287
288 // Nested class for SHA512withRSA signatures
289 public static final class SHA512withRSA extends RSASignature {
290 public SHA512withRSA() {
291 super("SHA-512", AlgorithmId.SHA512_oid, 11);
292 }
293 }
294
295}