1 /* RSA.java -- RSA PKCS#1 signatures.
2    Copyright (C) 2004  Free Software Foundation, Inc.
3 
4 This file is part of GNU Classpath.
5 
6 GNU Classpath is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
9 any later version.
10 
11 GNU Classpath is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 General Public License for more details.
15 
16 You should have received a copy of the GNU General Public License
17 along with GNU Classpath; see the file COPYING.  If not, write to the
18 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 02110-1301 USA.
20 
21 Linking this library statically or dynamically with other modules is
22 making a combined work based on this library.  Thus, the terms and
23 conditions of the GNU General Public License cover the whole
24 combination.
25 
26 As a special exception, the copyright holders of this library give you
27 permission to link this library with independent modules to produce an
28 executable, regardless of the license terms of these independent
29 modules, and to copy and distribute the resulting executable under
30 terms of your choice, provided that you also meet, for each linked
31 independent module, the terms and conditions of the license of that
32 module.  An independent module is a module which is not derived from
33 or based on this library.  If you modify this library, you may extend
34 this exception to your version of the library, but you are not
35 obligated to do so.  If you do not wish to do so, delete this
36 exception statement from your version. */
37 
38 
39 package gnu.java.security.provider;
40 
41 import gnu.java.security.OID;
42 import gnu.java.security.der.DER;
43 import gnu.java.security.der.DERReader;
44 import gnu.java.security.der.DERValue;
45 import gnu.java.security.der.DERWriter;
46 
47 import java.io.ByteArrayOutputStream;
48 import java.io.IOException;
49 import java.math.BigInteger;
50 import java.security.InvalidKeyException;
51 import java.security.MessageDigest;
52 import java.security.PrivateKey;
53 import java.security.PublicKey;
54 import java.security.SecureRandom;
55 import java.security.SignatureException;
56 import java.security.SignatureSpi;
57 import java.security.interfaces.RSAPrivateKey;
58 import java.security.interfaces.RSAPublicKey;
59 import java.util.ArrayList;
60 
61 public abstract class RSA extends SignatureSpi implements Cloneable
62 {
63 
64   // Constants and fields.
65   // -------------------------------------------------------------------------
66 
67   /**
68    * digestAlgorithm OBJECT IDENTIFIER ::=
69    *   { iso(1) member-body(2) US(840) rsadsi(113549) digestAlgorithm(2) }
70    */
71   protected static final OID DIGEST_ALGORITHM = new OID("1.2.840.113549.2");
72 
73   protected final OID digestAlgorithm;
74   protected final MessageDigest md;
75   protected RSAPrivateKey signerKey;
76   protected RSAPublicKey verifierKey;
77 
78   // Constructor.
79   // -------------------------------------------------------------------------
80 
RSA(MessageDigest md, OID digestAlgorithm)81   protected RSA(MessageDigest md, OID digestAlgorithm)
82   {
83     super();
84     this.md = md;
85     this.digestAlgorithm = digestAlgorithm;
86   }
87 
88   // Instance methods.
89   // -------------------------------------------------------------------------
90 
clone()91   public Object clone() throws CloneNotSupportedException
92   {
93     return super.clone();
94   }
95 
engineGetParameter(String param)96   protected Object engineGetParameter(String param)
97   {
98     throw new UnsupportedOperationException("deprecated");
99   }
100 
engineSetParameter(String param, Object value)101   protected void engineSetParameter(String param, Object value)
102   {
103     throw new UnsupportedOperationException("deprecated");
104   }
105 
engineInitSign(PrivateKey privateKey)106   protected void engineInitSign(PrivateKey privateKey)
107     throws InvalidKeyException
108   {
109     if (!(privateKey instanceof RSAPrivateKey))
110       throw new InvalidKeyException();
111     verifierKey = null;
112     signerKey = (RSAPrivateKey) privateKey;
113   }
114 
engineInitSign(PrivateKey privateKey, SecureRandom random)115   protected void engineInitSign(PrivateKey privateKey, SecureRandom random)
116     throws InvalidKeyException
117   {
118     // This class does not need random bytes.
119     engineInitSign(privateKey);
120   }
121 
engineInitVerify(PublicKey publicKey)122   protected void engineInitVerify(PublicKey publicKey)
123     throws InvalidKeyException
124   {
125     if (!(publicKey instanceof RSAPublicKey))
126       throw new InvalidKeyException();
127     signerKey = null;
128     verifierKey = (RSAPublicKey) publicKey;
129   }
130 
engineUpdate(byte b)131   protected void engineUpdate(byte b) throws SignatureException
132   {
133     if (signerKey == null && verifierKey == null)
134       throw new SignatureException("not initialized");
135     md.update(b);
136   }
137 
engineUpdate(byte[] buf, int off, int len)138   protected void engineUpdate(byte[] buf, int off, int len)
139     throws SignatureException
140   {
141     if (signerKey == null && verifierKey == null)
142       throw new SignatureException("not initialized");
143     md.update(buf, off, len);
144   }
145 
engineSign()146   protected byte[] engineSign() throws SignatureException
147   {
148     if (signerKey == null)
149       throw new SignatureException("not initialized for signing");
150     //
151     // The signature will be the RSA encrypted BER representation of
152     // the following:
153     //
154     //   DigestInfo ::= SEQUENCE {
155     //     digestAlgorithm  DigestAlgorithmIdentifier,
156     //     digest           Digest }
157     //
158     //   DigestAlgorithmIdentifier ::= AlgorithmIdentifier
159     //
160     //   Digest ::= OCTET STRING
161     //
162     ArrayList digestAlg = new ArrayList(2);
163     digestAlg.add(new DERValue(DER.OBJECT_IDENTIFIER, digestAlgorithm));
164     digestAlg.add(new DERValue(DER.NULL, null));
165     ArrayList digestInfo = new ArrayList(2);
166     digestInfo.add(new DERValue(DER.SEQUENCE, digestAlg));
167     digestInfo.add(new DERValue(DER.OCTET_STRING, md.digest()));
168     ByteArrayOutputStream out = new ByteArrayOutputStream();
169     try
170       {
171         DERWriter.write(out, new DERValue(DER.SEQUENCE, digestInfo));
172       }
173     catch (IOException ioe)
174       {
175         throw new SignatureException(ioe.toString());
176       }
177     byte[] buf = out.toByteArray();
178     md.reset();
179 
180     // k = octect length of the modulus.
181     int k = signerKey.getModulus().bitLength();
182     k = (k >>> 3) + ((k & 7) == 0 ? 0 : 1);
183     if (buf.length < k - 3)
184       {
185         throw new SignatureException("RSA modulus too small");
186       }
187     byte[] d = new byte[k];
188 
189     // Padding type 1:
190     //     00 | 01 | FF | ... | FF | 00 | D
191     d[1] = 0x01;
192     for (int i = 2; i < k - buf.length - 1; i++)
193       d[i] = (byte) 0xFF;
194     System.arraycopy(buf, 0, d, k - buf.length, buf.length);
195 
196     BigInteger eb = new BigInteger(d);
197 
198     byte[] ed = eb.modPow(signerKey.getPrivateExponent(),
199                           signerKey.getModulus()).toByteArray();
200 
201     // Ensure output is k octets long.
202     if (ed.length < k)
203       {
204         byte[] b = new byte[k];
205         System.arraycopy(eb, 0, b, k - ed.length, ed.length);
206         ed = b;
207       }
208     else if (ed.length > k)
209       {
210         if (ed.length != k + 1)
211           {
212             throw new SignatureException("modPow result is larger than the modulus");
213           }
214         // Maybe an extra 00 octect.
215         byte[] b = new byte[k];
216         System.arraycopy(ed, 1, b, 0, k);
217         ed = b;
218       }
219 
220     return ed;
221   }
222 
engineSign(byte[] out, int off, int len)223   protected int engineSign(byte[] out, int off, int len)
224     throws SignatureException
225   {
226     if (out == null || off < 0 || len < 0 || off+len > out.length)
227       throw new SignatureException("illegal output argument");
228     byte[] result = engineSign();
229     if (result.length > len)
230       throw new SignatureException("not enough space for signature");
231     System.arraycopy(result, 0, out, off, result.length);
232     return result.length;
233   }
234 
engineVerify(byte[] sig)235   protected boolean engineVerify(byte[] sig) throws SignatureException
236   {
237     if (verifierKey == null)
238       throw new SignatureException("not initialized for verifying");
239     if (sig == null)
240       throw new SignatureException("no signature specified");
241     int k = verifierKey.getModulus().bitLength();
242     k = (k >>> 3) + ((k & 7) == 0 ? 0 : 1);
243     if (sig.length != k)
244       throw new SignatureException("signature is the wrong size (expecting "
245                                    + k + " bytes, got " + sig.length + ")");
246     BigInteger ed = new BigInteger(1, sig);
247     byte[] eb = ed.modPow(verifierKey.getPublicExponent(),
248                           verifierKey.getModulus()).toByteArray();
249 
250     int i = 0;
251     if (eb[0] == 0x00)
252       {
253         for (i = 1; i < eb.length && eb[i] == 0x00; i++);
254         if (i == 1)
255           throw new SignatureException("wrong RSA padding");
256         i--;
257       }
258     else if (eb[0] == 0x01)
259       {
260         for (i = 1; i < eb.length && eb[i] != 0x00; i++)
261           if (eb[i] != (byte) 0xFF)
262             throw new IllegalArgumentException("wrong RSA padding");
263       }
264     else
265       throw new SignatureException("wrong RSA padding type");
266 
267     byte[] d = new byte[eb.length-i-1];
268     System.arraycopy(eb, i+1, d, 0, eb.length-i-1);
269 
270     DERReader der = new DERReader(d);
271     try
272       {
273         DERValue val = der.read();
274         if (val.getTag() != DER.SEQUENCE)
275           throw new SignatureException("failed to parse DigestInfo");
276         val = der.read();
277         if (val.getTag() != DER.SEQUENCE)
278           throw new SignatureException("failed to parse DigestAlgorithmIdentifier");
279         boolean sequenceIsBer = val.getLength() == 0;
280         val = der.read();
281         if (val.getTag() != DER.OBJECT_IDENTIFIER)
282           throw new SignatureException("failed to parse object identifier");
283         if (!val.getValue().equals(digestAlgorithm))
284           throw new SignatureException("digest algorithms do not match");
285         val = der.read();
286         // We should never see parameters here, since they are never used.
287         if (val.getTag() != DER.NULL)
288           throw new SignatureException("cannot handle digest parameters");
289         if (sequenceIsBer)
290           der.skip(1); // end-of-sequence byte.
291         val = der.read();
292         if (val.getTag() != DER.OCTET_STRING)
293           throw new SignatureException("failed to parse Digest");
294         return MessageDigest.isEqual(md.digest(), (byte[]) val.getValue());
295       }
296     catch (IOException ioe)
297       {
298         throw new SignatureException(ioe.toString());
299       }
300   }
301 
engineVerify(byte[] sig, int off, int len)302   protected boolean engineVerify(byte[] sig, int off, int len)
303     throws SignatureException
304   {
305     if (sig == null || off < 0 || len < 0 || off+len > sig.length)
306       throw new SignatureException("illegal parameter");
307     byte[] buf = new byte[len];
308     System.arraycopy(sig, off, buf, 0, len);
309     return engineVerify(buf);
310   }
311 }
312