Skip to content

Commit 7e9641b

Browse files
committed
Add PKCS#1 PSS padding, with help from https://github.com/digitalbazaar/forge/blob/master/js/pss.js
1 parent b7e51bc commit 7e9641b

File tree

1 file changed

+190
-1
lines changed

1 file changed

+190
-1
lines changed

rsasign-1.2.js

Lines changed: 190 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,13 @@ _RSASIGN_HASHHEXFUNC['ripemd160'] = function(s){return hex_rmd160(s);}; // htt
4848
//_RSASIGN_HASHHEXFUNC['sha1'] = function(s){return sha1.hex(s);} // http://user1.matsumoto.ne.jp/~goma/js/hash.html
4949
//_RSASIGN_HASHHEXFUNC['sha256'] = function(s){return sha256.hex;} // http://user1.matsumoto.ne.jp/~goma/js/hash.html
5050

51+
var _RSASIGN_HASHRAWFUNC = [];
52+
_RSASIGN_HASHRAWFUNC['sha1'] = function(s){return rstr_sha1(s);}; // http://pajhome.org.uk/crypt/md5/md5.html
53+
_RSASIGN_HASHRAWFUNC['sha256'] = function(s){return rstr_sha256(s);} // http://pajhome.org.uk/crypt/md5/md5.html
54+
_RSASIGN_HASHRAWFUNC['sha512'] = function(s){return rstr_sha512(s);} // http://pajhome.org.uk/crypt/md5/md5.html
55+
_RSASIGN_HASHRAWFUNC['md5'] = function(s){return rstr_md5(s);}; // http://pajhome.org.uk/crypt/md5/md5.html
56+
_RSASIGN_HASHRAWFUNC['ripemd160'] = function(s){return rstr_rmd160(s);}; // http://pajhome.org.uk/crypt/md5/md5.html
57+
5158
var _RE_HEXDECONLY = new RegExp("");
5259
_RE_HEXDECONLY.compile("[^0-9a-f]", "gi");
5360

@@ -97,6 +104,92 @@ function _rsasign_signStringWithSHA256(s) {
97104
return _rsasign_signString.call(this, s, 'sha256');
98105
}
99106

107+
// PKCS#1 (PSS) mask generation function
108+
function pss_mgf1_str(seed, len, hash)
109+
{
110+
var mask = '', i = 0;
111+
112+
while (mask.length < len)
113+
{
114+
mask += hash(seed + String.fromCharCode.apply(String, [
115+
(i & 0xff000000) >> 24,
116+
(i & 0x00ff0000) >> 16,
117+
(i & 0x0000ff00) >> 8,
118+
i & 0x000000ff]));
119+
i += 1;
120+
}
121+
122+
return mask;
123+
}
124+
125+
function _rsasign_signStringPSS(s, hashAlg, sLen)
126+
{
127+
var hashFunc = _RSASIGN_HASHRAWFUNC[hashAlg];
128+
var mHash = hashFunc(s);
129+
var hLen = mHash.length;
130+
var emBits = this.n.bitLength() - 1;
131+
var emLen = Math.ceil(emBits / 8);
132+
var i;
133+
134+
if (sLen === -1)
135+
{
136+
sLen = hLen; // same has hash length
137+
}
138+
else if ((sLen === -2) || (sLen === undefined))
139+
{
140+
sLen = emLen - hLen - 2; // maximum
141+
}
142+
else if (sLen < -2)
143+
{
144+
throw "invalid salt length";
145+
}
146+
147+
if (emLen < (hLen + sLen + 2))
148+
{
149+
throw "data too long";
150+
}
151+
152+
var salt = '';
153+
154+
if (sLen > 0)
155+
{
156+
salt = new Array(sLen);
157+
new SecureRandom().nextBytes(salt);
158+
salt = String.fromCharCode.apply(String, salt);
159+
}
160+
161+
var H = hashFunc('\x00\x00\x00\x00\x00\x00\x00\x00' + mHash + salt);
162+
var PS = [];
163+
164+
for (i = 0; i < emLen - sLen - hLen - 2; i += 1)
165+
{
166+
PS[i] = 0x00;
167+
}
168+
169+
var DB = String.fromCharCode.apply(String, PS) + '\x01' + salt;
170+
var dbMask = pss_mgf1_str(H, DB.length, hashFunc);
171+
var maskedDB = [];
172+
173+
for (i = 0; i < DB.length; i += 1)
174+
{
175+
maskedDB[i] = DB.charCodeAt(i) ^ dbMask.charCodeAt(i);
176+
}
177+
178+
var mask = (0xff00 >> (8 * emLen - emBits)) & 0xff;
179+
maskedDB[0] &= ~mask;
180+
181+
for (i = 0; i < hLen; i++)
182+
{
183+
maskedDB.push(H.charCodeAt(i));
184+
}
185+
186+
maskedDB.push(0xbc);
187+
188+
return _zeroPaddingOfSignature(
189+
this.doPrivate(new BigInteger(maskedDB)).toString(16),
190+
this.n.bitLength());
191+
}
192+
100193
// ========================================================================
101194
// Signature Verification
102195
// ========================================================================
@@ -178,15 +271,111 @@ function _rsasign_verifyString(sMsg, hSig) {
178271
return (diHashValue == msgHashValue);
179272
}
180273

274+
function _rsasign_verifyStringPSS(sMsg, hSig, hashAlg, sLen)
275+
{
276+
if (hSig.length !== this.n.bitLength() / 4)
277+
{
278+
return false;
279+
}
280+
281+
var hashFunc = _RSASIGN_HASHRAWFUNC[hashAlg];
282+
var mHash = hashFunc(sMsg);
283+
var hLen = mHash.length;
284+
var emBits = this.n.bitLength() - 1;
285+
var emLen = Math.ceil(emBits / 8);
286+
var i;
287+
288+
if (sLen === -1)
289+
{
290+
sLen = hLen; // same has hash length
291+
}
292+
else if ((sLen === -2) || (sLen === undefined))
293+
{
294+
sLen = emLen - hLen - 2; // maximum
295+
}
296+
else if (sLen < -2)
297+
{
298+
throw "invalid salt length";
299+
}
300+
301+
if (emLen < (hLen + sLen + 2))
302+
{
303+
throw "data too long";
304+
}
305+
306+
var em = this.doPublic(parseBigInt(hSig, 16)).toByteArray();
307+
308+
for (i = 0; i < em.length; i += 1)
309+
{
310+
em[i] &= 0xff;
311+
}
312+
313+
while (em.length < emLen)
314+
{
315+
em.unshift(0);
316+
}
317+
318+
if (em[emLen -1] !== 0xbc)
319+
{
320+
throw "encoded message does not end in 0xbc";
321+
}
322+
323+
em = String.fromCharCode.apply(String, em);
324+
325+
var maskedDB = em.substr(0, emLen - hLen - 1);
326+
var H = em.substr(maskedDB.length, hLen);
327+
328+
var mask = (0xff00 >> (8 * emLen - emBits)) & 0xff;
329+
330+
if ((maskedDB.charCodeAt(0) & mask) !== 0)
331+
{
332+
throw "bits beyond keysize not zero";
333+
}
334+
335+
var dbMask = pss_mgf1_str(H, maskedDB.length, hashFunc);
336+
var DB = [];
337+
338+
for (i = 0; i < maskedDB.length; i += 1)
339+
{
340+
DB[i] = maskedDB.charCodeAt(i) ^ dbMask.charCodeAt(i);
341+
}
342+
343+
DB[0] &= ~mask;
344+
345+
var checkLen = emLen - hLen - sLen - 2;
346+
347+
for (i = 0; i < checkLen; i += 1)
348+
{
349+
if (DB[i] !== 0x00)
350+
{
351+
throw "leftmost octets not zero";
352+
}
353+
}
354+
355+
if (DB[checkLen] !== 0x01)
356+
{
357+
throw "0x01 marker not found";
358+
}
359+
360+
return H === hashFunc('\x00\x00\x00\x00\x00\x00\x00\x00' + mHash +
361+
String.fromCharCode.apply(String, DB.slice(-sLen)));
362+
}
363+
181364
RSAKey.prototype.signString = _rsasign_signString;
182365
RSAKey.prototype.signStringWithSHA1 = _rsasign_signStringWithSHA1;
183366
RSAKey.prototype.signStringWithSHA256 = _rsasign_signStringWithSHA256;
184367
RSAKey.prototype.sign = _rsasign_signString;
185368
RSAKey.prototype.signWithSHA1 = _rsasign_signStringWithSHA1;
186369
RSAKey.prototype.signWithSHA256 = _rsasign_signStringWithSHA256;
370+
RSAKey.prototype.signStringPSS = _rsasign_signStringPSS;
371+
RSAKey.prototype.signPSS = _rsasign_signStringPSS;
372+
RSAKey.SALT_LEN_HLEN = -1;
373+
RSAKey.SALT_LEN_MAX = -2;
187374

188375
RSAKey.prototype.verifyString = _rsasign_verifyString;
189376
RSAKey.prototype.verifyHexSignatureForMessage = _rsasign_verifyHexSignatureForMessage;
190377
RSAKey.prototype.verify = _rsasign_verifyString;
191378
RSAKey.prototype.verifyHexSignatureForByteArrayMessage = _rsasign_verifyHexSignatureForMessage;
192-
379+
RSAKey.prototype.verifyStringPSS = _rsasign_verifyStringPSS;
380+
RSAKey.prototype.verifyPSS = _rsasign_verifyStringPSS;
381+
RSAKey.SALT_LEN_RECOVER = -2;

0 commit comments

Comments
 (0)