Source for gnu.java.security.sig.rsa.RSAPSSSignature

   1: /* RSAPSSSignature.java -- 
   2:    Copyright (C) 2001, 2002, 2003, 2006 Free Software Foundation, Inc.
   3: 
   4: This file is a 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 of the License, or (at
   9: your option) 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; if not, write to the Free Software
  18: Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
  19: 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.sig.rsa;
  40: 
  41: import gnu.java.security.Configuration;
  42: import gnu.java.security.Registry;
  43: import gnu.java.security.hash.HashFactory;
  44: import gnu.java.security.hash.IMessageDigest;
  45: import gnu.java.security.sig.BaseSignature;
  46: import gnu.java.security.util.Util;
  47: 
  48: import java.math.BigInteger;
  49: import java.security.PrivateKey;
  50: import java.security.PublicKey;
  51: import java.security.interfaces.RSAPrivateKey;
  52: import java.security.interfaces.RSAPublicKey;
  53: import java.util.logging.Logger;
  54: 
  55: /**
  56:  * The RSA-PSS signature scheme is a public-key encryption scheme combining the
  57:  * RSA algorithm with the Probabilistic Signature Scheme (PSS) encoding method.
  58:  * <p>
  59:  * The inventors of RSA are Ronald L. Rivest, Adi Shamir, and Leonard Adleman,
  60:  * while the inventors of the PSS encoding method are Mihir Bellare and Phillip
  61:  * Rogaway. During efforts to adopt RSA-PSS into the P1363a standards effort,
  62:  * certain adaptations to the original version of RSA-PSS were made by Mihir
  63:  * Bellare and Phillip Rogaway and also by Burt Kaliski (the editor of IEEE
  64:  * P1363a) to facilitate implementation and integration into existing protocols.
  65:  * <p>
  66:  * References:
  67:  * <ol>
  68:  * <li><a
  69:  * href="http://www.cosic.esat.kuleuven.ac.be/nessie/workshop/submissions/rsa-pss.zip">
  70:  * RSA-PSS Signature Scheme with Appendix, part B.</a><br>
  71:  * Primitive specification and supporting documentation.<br>
  72:  * Jakob Jonsson and Burt Kaliski.</li>
  73:  * </ol>
  74:  */
  75: public class RSAPSSSignature
  76:     extends BaseSignature
  77: {
  78:   private static final Logger log = Logger.getLogger(RSAPSSSignature.class.getName());
  79: 
  80:   /** The underlying EMSA-PSS instance for this object. */
  81:   private EMSA_PSS pss;
  82: 
  83:   /** The desired length in octets of the EMSA-PSS salt. */
  84:   private int sLen;
  85: 
  86:   /**
  87:    * Default 0-arguments constructor. Uses SHA-1 as the default hash and a
  88:    * 0-octet <i>salt</i>.
  89:    */
  90:   public RSAPSSSignature()
  91:   {
  92:     this(Registry.SHA160_HASH, 0);
  93:   }
  94: 
  95:   /**
  96:    * Constructs an instance of this object using the designated message digest
  97:    * algorithm as its underlying hash function, and having 0-octet <i>salt</i>.
  98:    * 
  99:    * @param mdName the canonical name of the underlying hash function.
 100:    */
 101:   public RSAPSSSignature(String mdName)
 102:   {
 103:     this(mdName, 0);
 104:   }
 105: 
 106:   /**
 107:    * Constructs an instance of this object using the designated message digest
 108:    * algorithm as its underlying hash function.
 109:    * 
 110:    * @param mdName the canonical name of the underlying hash function.
 111:    * @param sLen the desired length in octets of the salt to use for encoding /
 112:    *          decoding signatures.
 113:    */
 114:   public RSAPSSSignature(String mdName, int sLen)
 115:   {
 116:     this(HashFactory.getInstance(mdName), sLen);
 117:   }
 118: 
 119:   public RSAPSSSignature(IMessageDigest md, int sLen)
 120:   {
 121:     super(Registry.RSA_PSS_SIG, md);
 122: 
 123:     pss = EMSA_PSS.getInstance(md.name());
 124:     this.sLen = sLen;
 125:   }
 126: 
 127:   /** Private constructor for cloning purposes. */
 128:   private RSAPSSSignature(RSAPSSSignature that)
 129:   {
 130:     this(that.md.name(), that.sLen);
 131: 
 132:     this.publicKey = that.publicKey;
 133:     this.privateKey = that.privateKey;
 134:     this.md = (IMessageDigest) that.md.clone();
 135:     this.pss = (EMSA_PSS) that.pss.clone();
 136:   }
 137: 
 138:   public Object clone()
 139:   {
 140:     return new RSAPSSSignature(this);
 141:   }
 142: 
 143:   protected void setupForVerification(PublicKey k)
 144:       throws IllegalArgumentException
 145:   {
 146:     if (! (k instanceof RSAPublicKey))
 147:       throw new IllegalArgumentException();
 148: 
 149:     publicKey = (RSAPublicKey) k;
 150:   }
 151: 
 152:   protected void setupForSigning(PrivateKey k) throws IllegalArgumentException
 153:   {
 154:     if (! (k instanceof RSAPrivateKey))
 155:       throw new IllegalArgumentException();
 156: 
 157:     privateKey = (RSAPrivateKey) k;
 158:   }
 159: 
 160:   protected Object generateSignature() throws IllegalStateException
 161:   {
 162:     // 1. Apply the EMSA-PSS encoding operation to the message M to produce an
 163:     // encoded message EM of length CEILING((modBits ? 1)/8) octets such
 164:     // that the bit length of the integer OS2IP(EM) is at most modBits ? 1:
 165:     // EM = EMSA-PSS-Encode(M,modBits ? 1).
 166:     // Note that the octet length of EM will be one less than k if
 167:     // modBits ? 1 is divisible by 8. If the encoding operation outputs
 168:     // 'message too long' or 'encoding error,' then output 'message too
 169:     // long' or 'encoding error' and stop.
 170:     int modBits = ((RSAPrivateKey) privateKey).getModulus().bitLength();
 171:     byte[] salt = new byte[sLen];
 172:     this.nextRandomBytes(salt);
 173:     byte[] EM = pss.encode(md.digest(), modBits - 1, salt);
 174:     if (Configuration.DEBUG)
 175:       log.fine("EM (sign): " + Util.toString(EM));
 176:     // 2. Convert the encoded message EM to an integer message representative
 177:     // m (see Section 1.2.2): m = OS2IP(EM).
 178:     BigInteger m = new BigInteger(1, EM);
 179:     // 3. Apply the RSASP signature primitive to the public key K and the
 180:     // message representative m to produce an integer signature
 181:     // representative s: s = RSASP(K,m).
 182:     BigInteger s = RSA.sign(privateKey, m);
 183:     // 4. Convert the signature representative s to a signature S of length k
 184:     // octets (see Section 1.2.1): S = I2OSP(s, k).
 185:     // 5. Output the signature S.
 186:     int k = (modBits + 7) / 8;
 187:     // return encodeSignature(s, k);
 188:     return RSA.I2OSP(s, k);
 189:   }
 190: 
 191:   protected boolean verifySignature(Object sig) throws IllegalStateException
 192:   {
 193:     if (publicKey == null)
 194:       throw new IllegalStateException();
 195:     // byte[] S = decodeSignature(sig);
 196:     byte[] S = (byte[]) sig;
 197:     // 1. If the length of the signature S is not k octets, output 'signature
 198:     // invalid' and stop.
 199:     int modBits = ((RSAPublicKey) publicKey).getModulus().bitLength();
 200:     int k = (modBits + 7) / 8;
 201:     if (S.length != k)
 202:       return false;
 203:     // 2. Convert the signature S to an integer signature representative s:
 204:     // s = OS2IP(S).
 205:     BigInteger s = new BigInteger(1, S);
 206:     // 3. Apply the RSAVP verification primitive to the public key (n, e) and
 207:     // the signature representative s to produce an integer message
 208:     // representative m: m = RSAVP((n, e), s).
 209:     // If RSAVP outputs 'signature representative out of range,' then
 210:     // output 'signature invalid' and stop.
 211:     BigInteger m = null;
 212:     try
 213:       {
 214:         m = RSA.verify(publicKey, s);
 215:       }
 216:     catch (IllegalArgumentException x)
 217:       {
 218:         return false;
 219:       }
 220:     // 4. Convert the message representative m to an encoded message EM of
 221:     // length emLen = CEILING((modBits - 1)/8) octets, where modBits is
 222:     // equal to the bit length of the modulus: EM = I2OSP(m, emLen).
 223:     // Note that emLen will be one less than k if modBits - 1 is divisible
 224:     // by 8. If I2OSP outputs 'integer too large,' then output 'signature
 225:     // invalid' and stop.
 226:     int emBits = modBits - 1;
 227:     int emLen = (emBits + 7) / 8;
 228:     byte[] EM = m.toByteArray();
 229:     if (Configuration.DEBUG)
 230:       log.fine("EM (verify): " + Util.toString(EM));
 231:     if (EM.length > emLen)
 232:       return false;
 233:     else if (EM.length < emLen)
 234:       {
 235:         byte[] newEM = new byte[emLen];
 236:         System.arraycopy(EM, 0, newEM, emLen - EM.length, EM.length);
 237:         EM = newEM;
 238:       }
 239:     // 5. Apply the EMSA-PSS decoding operation to the message M and the
 240:     // encoded message EM: Result = EMSA-PSS-Decode(M, EM, emBits). If
 241:     // Result = 'consistent,' output 'signature verified.' Otherwise,
 242:     // output 'signature invalid.'
 243:     byte[] mHash = md.digest();
 244:     boolean result = false;
 245:     try
 246:       {
 247:         result = pss.decode(mHash, EM, emBits, sLen);
 248:       }
 249:     catch (IllegalArgumentException x)
 250:       {
 251:         result = false;
 252:       }
 253:     return result;
 254:   }
 255: }