| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241 | 
							- /**
 
-  * Javascript implementation of PKCS#1 PSS signature padding.
 
-  *
 
-  * @author Stefan Siegl
 
-  *
 
-  * Copyright (c) 2012 Stefan Siegl <stesie@brokenpipe.de>
 
-  */
 
- var forge = require('./forge');
 
- require('./random');
 
- require('./util');
 
- // shortcut for PSS API
 
- var pss = module.exports = forge.pss = forge.pss || {};
 
- /**
 
-  * Creates a PSS signature scheme object.
 
-  *
 
-  * There are several ways to provide a salt for encoding:
 
-  *
 
-  * 1. Specify the saltLength only and the built-in PRNG will generate it.
 
-  * 2. Specify the saltLength and a custom PRNG with 'getBytesSync' defined that
 
-  *   will be used.
 
-  * 3. Specify the salt itself as a forge.util.ByteBuffer.
 
-  *
 
-  * @param options the options to use:
 
-  *          md the message digest object to use, a forge md instance.
 
-  *          mgf the mask generation function to use, a forge mgf instance.
 
-  *          [saltLength] the length of the salt in octets.
 
-  *          [prng] the pseudo-random number generator to use to produce a salt.
 
-  *          [salt] the salt to use when encoding.
 
-  *
 
-  * @return a signature scheme object.
 
-  */
 
- pss.create = function(options) {
 
-   // backwards compatibility w/legacy args: hash, mgf, sLen
 
-   if(arguments.length === 3) {
 
-     options = {
 
-       md: arguments[0],
 
-       mgf: arguments[1],
 
-       saltLength: arguments[2]
 
-     };
 
-   }
 
-   var hash = options.md;
 
-   var mgf = options.mgf;
 
-   var hLen = hash.digestLength;
 
-   var salt_ = options.salt || null;
 
-   if(typeof salt_ === 'string') {
 
-     // assume binary-encoded string
 
-     salt_ = forge.util.createBuffer(salt_);
 
-   }
 
-   var sLen;
 
-   if('saltLength' in options) {
 
-     sLen = options.saltLength;
 
-   } else if(salt_ !== null) {
 
-     sLen = salt_.length();
 
-   } else {
 
-     throw new Error('Salt length not specified or specific salt not given.');
 
-   }
 
-   if(salt_ !== null && salt_.length() !== sLen) {
 
-     throw new Error('Given salt length does not match length of given salt.');
 
-   }
 
-   var prng = options.prng || forge.random;
 
-   var pssobj = {};
 
-   /**
 
-    * Encodes a PSS signature.
 
-    *
 
-    * This function implements EMSA-PSS-ENCODE as per RFC 3447, section 9.1.1.
 
-    *
 
-    * @param md the message digest object with the hash to sign.
 
-    * @param modsBits the length of the RSA modulus in bits.
 
-    *
 
-    * @return the encoded message as a binary-encoded string of length
 
-    *           ceil((modBits - 1) / 8).
 
-    */
 
-   pssobj.encode = function(md, modBits) {
 
-     var i;
 
-     var emBits = modBits - 1;
 
-     var emLen = Math.ceil(emBits / 8);
 
-     /* 2. Let mHash = Hash(M), an octet string of length hLen. */
 
-     var mHash = md.digest().getBytes();
 
-     /* 3. If emLen < hLen + sLen + 2, output "encoding error" and stop. */
 
-     if(emLen < hLen + sLen + 2) {
 
-       throw new Error('Message is too long to encrypt.');
 
-     }
 
-     /* 4. Generate a random octet string salt of length sLen; if sLen = 0,
 
-      *    then salt is the empty string. */
 
-     var salt;
 
-     if(salt_ === null) {
 
-       salt = prng.getBytesSync(sLen);
 
-     } else {
 
-       salt = salt_.bytes();
 
-     }
 
-     /* 5. Let M' = (0x)00 00 00 00 00 00 00 00 || mHash || salt; */
 
-     var m_ = new forge.util.ByteBuffer();
 
-     m_.fillWithByte(0, 8);
 
-     m_.putBytes(mHash);
 
-     m_.putBytes(salt);
 
-     /* 6. Let H = Hash(M'), an octet string of length hLen. */
 
-     hash.start();
 
-     hash.update(m_.getBytes());
 
-     var h = hash.digest().getBytes();
 
-     /* 7. Generate an octet string PS consisting of emLen - sLen - hLen - 2
 
-      *    zero octets.  The length of PS may be 0. */
 
-     var ps = new forge.util.ByteBuffer();
 
-     ps.fillWithByte(0, emLen - sLen - hLen - 2);
 
-     /* 8. Let DB = PS || 0x01 || salt; DB is an octet string of length
 
-      *    emLen - hLen - 1. */
 
-     ps.putByte(0x01);
 
-     ps.putBytes(salt);
 
-     var db = ps.getBytes();
 
-     /* 9. Let dbMask = MGF(H, emLen - hLen - 1). */
 
-     var maskLen = emLen - hLen - 1;
 
-     var dbMask = mgf.generate(h, maskLen);
 
-     /* 10. Let maskedDB = DB \xor dbMask. */
 
-     var maskedDB = '';
 
-     for(i = 0; i < maskLen; i++) {
 
-       maskedDB += String.fromCharCode(db.charCodeAt(i) ^ dbMask.charCodeAt(i));
 
-     }
 
-     /* 11. Set the leftmost 8emLen - emBits bits of the leftmost octet in
 
-      *     maskedDB to zero. */
 
-     var mask = (0xFF00 >> (8 * emLen - emBits)) & 0xFF;
 
-     maskedDB = String.fromCharCode(maskedDB.charCodeAt(0) & ~mask) +
 
-       maskedDB.substr(1);
 
-     /* 12. Let EM = maskedDB || H || 0xbc.
 
-      * 13. Output EM. */
 
-     return maskedDB + h + String.fromCharCode(0xbc);
 
-   };
 
-   /**
 
-    * Verifies a PSS signature.
 
-    *
 
-    * This function implements EMSA-PSS-VERIFY as per RFC 3447, section 9.1.2.
 
-    *
 
-    * @param mHash the message digest hash, as a binary-encoded string, to
 
-    *         compare against the signature.
 
-    * @param em the encoded message, as a binary-encoded string
 
-    *          (RSA decryption result).
 
-    * @param modsBits the length of the RSA modulus in bits.
 
-    *
 
-    * @return true if the signature was verified, false if not.
 
-    */
 
-   pssobj.verify = function(mHash, em, modBits) {
 
-     var i;
 
-     var emBits = modBits - 1;
 
-     var emLen = Math.ceil(emBits / 8);
 
-     /* c. Convert the message representative m to an encoded message EM
 
-      *    of length emLen = ceil((modBits - 1) / 8) octets, where modBits
 
-      *    is the length in bits of the RSA modulus n */
 
-     em = em.substr(-emLen);
 
-     /* 3. If emLen < hLen + sLen + 2, output "inconsistent" and stop. */
 
-     if(emLen < hLen + sLen + 2) {
 
-       throw new Error('Inconsistent parameters to PSS signature verification.');
 
-     }
 
-     /* 4. If the rightmost octet of EM does not have hexadecimal value
 
-      *    0xbc, output "inconsistent" and stop. */
 
-     if(em.charCodeAt(emLen - 1) !== 0xbc) {
 
-       throw new Error('Encoded message does not end in 0xBC.');
 
-     }
 
-     /* 5. Let maskedDB be the leftmost emLen - hLen - 1 octets of EM, and
 
-      *    let H be the next hLen octets. */
 
-     var maskLen = emLen - hLen - 1;
 
-     var maskedDB = em.substr(0, maskLen);
 
-     var h = em.substr(maskLen, hLen);
 
-     /* 6. If the leftmost 8emLen - emBits bits of the leftmost octet in
 
-      *    maskedDB are not all equal to zero, output "inconsistent" and stop. */
 
-     var mask = (0xFF00 >> (8 * emLen - emBits)) & 0xFF;
 
-     if((maskedDB.charCodeAt(0) & mask) !== 0) {
 
-       throw new Error('Bits beyond keysize not zero as expected.');
 
-     }
 
-     /* 7. Let dbMask = MGF(H, emLen - hLen - 1). */
 
-     var dbMask = mgf.generate(h, maskLen);
 
-     /* 8. Let DB = maskedDB \xor dbMask. */
 
-     var db = '';
 
-     for(i = 0; i < maskLen; i++) {
 
-       db += String.fromCharCode(maskedDB.charCodeAt(i) ^ dbMask.charCodeAt(i));
 
-     }
 
-     /* 9. Set the leftmost 8emLen - emBits bits of the leftmost octet
 
-      * in DB to zero. */
 
-     db = String.fromCharCode(db.charCodeAt(0) & ~mask) + db.substr(1);
 
-     /* 10. If the emLen - hLen - sLen - 2 leftmost octets of DB are not zero
 
-      * or if the octet at position emLen - hLen - sLen - 1 (the leftmost
 
-      * position is "position 1") does not have hexadecimal value 0x01,
 
-      * output "inconsistent" and stop. */
 
-     var checkLen = emLen - hLen - sLen - 2;
 
-     for(i = 0; i < checkLen; i++) {
 
-       if(db.charCodeAt(i) !== 0x00) {
 
-         throw new Error('Leftmost octets not zero as expected');
 
-       }
 
-     }
 
-     if(db.charCodeAt(checkLen) !== 0x01) {
 
-       throw new Error('Inconsistent PSS signature, 0x01 marker not found');
 
-     }
 
-     /* 11. Let salt be the last sLen octets of DB. */
 
-     var salt = db.substr(-sLen);
 
-     /* 12.  Let M' = (0x)00 00 00 00 00 00 00 00 || mHash || salt */
 
-     var m_ = new forge.util.ByteBuffer();
 
-     m_.fillWithByte(0, 8);
 
-     m_.putBytes(mHash);
 
-     m_.putBytes(salt);
 
-     /* 13. Let H' = Hash(M'), an octet string of length hLen. */
 
-     hash.start();
 
-     hash.update(m_.getBytes());
 
-     var h_ = hash.digest().getBytes();
 
-     /* 14. If H = H', output "consistent." Otherwise, output "inconsistent." */
 
-     return h === h_;
 
-   };
 
-   return pssobj;
 
- };
 
 
  |