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

   1: /* RSAPSSSignature.java --
   2:    Copyright (C) 2001, 2002, 2003, 2006, 2010 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 = Configuration.DEBUG ?
  79:                 Logger.getLogger(RSAPSSSignature.class.getName()) : null;
  80: 
  81:   /** The underlying EMSA-PSS instance for this object. */
  82:   private EMSA_PSS pss;
  83: 
  84:   /** The desired length in octets of the EMSA-PSS salt. */
  85:   private int sLen;
  86: 
  87:   /**
  88:    * Default 0-arguments constructor. Uses SHA-1 as the default hash and a
  89:    * 0-octet <i>salt</i>.
  90:    */
  91:   public RSAPSSSignature()
  92:   {
  93:     this(Registry.SHA160_HASH, 0);
  94:   }
  95: 
  96:   /**
  97:    * Constructs an instance of this object using the designated message digest
  98:    * algorithm as its underlying hash function, and having 0-octet <i>salt</i>.
  99:    *
 100:    * @param mdName the canonical name of the underlying hash function.
 101:    */
 102:   public RSAPSSSignature(String mdName)
 103:   {
 104:     this(mdName, 0);
 105:   }
 106: 
 107:   /**
 108:    * Constructs an instance of this object using the designated message digest
 109:    * algorithm as its underlying hash function.
 110:    *
 111:    * @param mdName the canonical name of the underlying hash function.
 112:    * @param sLen the desired length in octets of the salt to use for encoding /
 113:    *          decoding signatures.
 114:    */
 115:   public RSAPSSSignature(String mdName, int sLen)
 116:   {
 117:     this(HashFactory.getInstance(mdName), sLen);
 118:   }
 119: 
 120:   public RSAPSSSignature(IMessageDigest md, int sLen)
 121:   {
 122:     super(Registry.RSA_PSS_SIG, md);
 123: 
 124:     pss = EMSA_PSS.getInstance(md.name());
 125:     this.sLen = sLen;
 126:   }
 127: 
 128:   /** Private constructor for cloning purposes. */
 129:   private RSAPSSSignature(RSAPSSSignature that)
 130:   {
 131:     this(that.md.name(), that.sLen);
 132: 
 133:     this.publicKey = that.publicKey;
 134:     this.privateKey = that.privateKey;
 135:     this.md = (IMessageDigest) that.md.clone();
 136:     this.pss = (EMSA_PSS) that.pss.clone();
 137:   }
 138: 
 139:   public Object clone()
 140:   {
 141:     return new RSAPSSSignature(this);
 142:   }
 143: 
 144:   protected void setupForVerification(PublicKey k)
 145:       throws IllegalArgumentException
 146:   {
 147:     if (! (k instanceof RSAPublicKey))
 148:       throw new IllegalArgumentException();
 149: 
 150:     publicKey = (RSAPublicKey) k;
 151:   }
 152: 
 153:   protected void setupForSigning(PrivateKey k) throws IllegalArgumentException
 154:   {
 155:     if (! (k instanceof RSAPrivateKey))
 156:       throw new IllegalArgumentException();
 157: 
 158:     privateKey = (RSAPrivateKey) k;
 159:   }
 160: 
 161:   protected Object generateSignature() throws IllegalStateException
 162:   {
 163:     // 1. Apply the EMSA-PSS encoding operation to the message M to produce an
 164:     // encoded message EM of length CEILING((modBits ? 1)/8) octets such
 165:     // that the bit length of the integer OS2IP(EM) is at most modBits ? 1:
 166:     // EM = EMSA-PSS-Encode(M,modBits ? 1).
 167:     // Note that the octet length of EM will be one less than k if
 168:     // modBits ? 1 is divisible by 8. If the encoding operation outputs
 169:     // 'message too long' or 'encoding error,' then output 'message too
 170:     // long' or 'encoding error' and stop.
 171:     int modBits = ((RSAPrivateKey) privateKey).getModulus().bitLength();
 172:     byte[] salt = new byte[sLen];
 173:     this.nextRandomBytes(salt);
 174:     byte[] EM = pss.encode(md.digest(), modBits - 1, salt);
 175:     if (Configuration.DEBUG)
 176:       log.fine("EM (sign): " + Util.toString(EM));
 177:     // 2. Convert the encoded message EM to an integer message representative
 178:     // m (see Section 1.2.2): m = OS2IP(EM).
 179:     BigInteger m = new BigInteger(1, EM);
 180:     // 3. Apply the RSASP signature primitive to the public key K and the
 181:     // message representative m to produce an integer signature
 182:     // representative s: s = RSASP(K,m).
 183:     BigInteger s = RSA.sign(privateKey, m);
 184:     // 4. Convert the signature representative s to a signature S of length k
 185:     // octets (see Section 1.2.1): S = I2OSP(s, k).
 186:     // 5. Output the signature S.
 187:     int k = (modBits + 7) / 8;
 188:     // return encodeSignature(s, k);
 189:     return RSA.I2OSP(s, k);
 190:   }
 191: 
 192:   protected boolean verifySignature(Object sig) throws IllegalStateException
 193:   {
 194:     if (publicKey == null)
 195:       throw new IllegalStateException();
 196:     // byte[] S = decodeSignature(sig);
 197:     byte[] S = (byte[]) sig;
 198:     // 1. If the length of the signature S is not k octets, output 'signature
 199:     // invalid' and stop.
 200:     int modBits = ((RSAPublicKey) publicKey).getModulus().bitLength();
 201:     int k = (modBits + 7) / 8;
 202:     if (S.length != k)
 203:       return false;
 204:     // 2. Convert the signature S to an integer signature representative s:
 205:     // s = OS2IP(S).
 206:     BigInteger s = new BigInteger(1, S);
 207:     // 3. Apply the RSAVP verification primitive to the public key (n, e) and
 208:     // the signature representative s to produce an integer message
 209:     // representative m: m = RSAVP((n, e), s).
 210:     // If RSAVP outputs 'signature representative out of range,' then
 211:     // output 'signature invalid' and stop.
 212:     BigInteger m = null;
 213:     try
 214:       {
 215:         m = RSA.verify(publicKey, s);
 216:       }
 217:     catch (IllegalArgumentException x)
 218:       {
 219:         return false;
 220:       }
 221:     // 4. Convert the message representative m to an encoded message EM of
 222:     // length emLen = CEILING((modBits - 1)/8) octets, where modBits is
 223:     // equal to the bit length of the modulus: EM = I2OSP(m, emLen).
 224:     // Note that emLen will be one less than k if modBits - 1 is divisible
 225:     // by 8. If I2OSP outputs 'integer too large,' then output 'signature
 226:     // invalid' and stop.
 227:     int emBits = modBits - 1;
 228:     int emLen = (emBits + 7) / 8;
 229:     byte[] EM = m.toByteArray();
 230:     if (Configuration.DEBUG)
 231:       log.fine("EM (verify): " + Util.toString(EM));
 232:     if (EM.length > emLen)
 233:       return false;
 234:     else if (EM.length < emLen)
 235:       {
 236:         byte[] newEM = new byte[emLen];
 237:         System.arraycopy(EM, 0, newEM, emLen - EM.length, EM.length);
 238:         EM = newEM;
 239:       }
 240:     // 5. Apply the EMSA-PSS decoding operation to the message M and the
 241:     // encoded message EM: Result = EMSA-PSS-Decode(M, EM, emBits). If
 242:     // Result = 'consistent,' output 'signature verified.' Otherwise,
 243:     // output 'signature invalid.'
 244:     byte[] mHash = md.digest();
 245:     boolean result = false;
 246:     try
 247:       {
 248:         result = pss.decode(mHash, EM, emBits, sLen);
 249:       }
 250:     catch (IllegalArgumentException x)
 251:       {
 252:         result = false;
 253:       }
 254:     return result;
 255:   }
 256: }