Source for gnu.java.security.provider.RSA

   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: 
  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: 
  91:   public Object clone() throws CloneNotSupportedException
  92:   {
  93:     return super.clone();
  94:   }
  95: 
  96:   protected Object engineGetParameter(String param)
  97:   {
  98:     throw new UnsupportedOperationException("deprecated");
  99:   }
 100: 
 101:   protected void engineSetParameter(String param, Object value)
 102:   {
 103:     throw new UnsupportedOperationException("deprecated");
 104:   }
 105: 
 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: 
 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: 
 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: 
 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: 
 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: 
 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: 
 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: 
 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: 
 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: }