source: trip-planner-front/node_modules/node-forge/lib/pss.js@ bdd6491

Last change on this file since bdd6491 was 6a3a178, checked in by Ema <ema_spirova@…>, 3 years ago

initial commit

  • Property mode set to 100644
File size: 7.7 KB
Line 
1/**
2 * Javascript implementation of PKCS#1 PSS signature padding.
3 *
4 * @author Stefan Siegl
5 *
6 * Copyright (c) 2012 Stefan Siegl <stesie@brokenpipe.de>
7 */
8var forge = require('./forge');
9require('./random');
10require('./util');
11
12// shortcut for PSS API
13var pss = module.exports = forge.pss = forge.pss || {};
14
15/**
16 * Creates a PSS signature scheme object.
17 *
18 * There are several ways to provide a salt for encoding:
19 *
20 * 1. Specify the saltLength only and the built-in PRNG will generate it.
21 * 2. Specify the saltLength and a custom PRNG with 'getBytesSync' defined that
22 * will be used.
23 * 3. Specify the salt itself as a forge.util.ByteBuffer.
24 *
25 * @param options the options to use:
26 * md the message digest object to use, a forge md instance.
27 * mgf the mask generation function to use, a forge mgf instance.
28 * [saltLength] the length of the salt in octets.
29 * [prng] the pseudo-random number generator to use to produce a salt.
30 * [salt] the salt to use when encoding.
31 *
32 * @return a signature scheme object.
33 */
34pss.create = function(options) {
35 // backwards compatibility w/legacy args: hash, mgf, sLen
36 if(arguments.length === 3) {
37 options = {
38 md: arguments[0],
39 mgf: arguments[1],
40 saltLength: arguments[2]
41 };
42 }
43
44 var hash = options.md;
45 var mgf = options.mgf;
46 var hLen = hash.digestLength;
47
48 var salt_ = options.salt || null;
49 if(typeof salt_ === 'string') {
50 // assume binary-encoded string
51 salt_ = forge.util.createBuffer(salt_);
52 }
53
54 var sLen;
55 if('saltLength' in options) {
56 sLen = options.saltLength;
57 } else if(salt_ !== null) {
58 sLen = salt_.length();
59 } else {
60 throw new Error('Salt length not specified or specific salt not given.');
61 }
62
63 if(salt_ !== null && salt_.length() !== sLen) {
64 throw new Error('Given salt length does not match length of given salt.');
65 }
66
67 var prng = options.prng || forge.random;
68
69 var pssobj = {};
70
71 /**
72 * Encodes a PSS signature.
73 *
74 * This function implements EMSA-PSS-ENCODE as per RFC 3447, section 9.1.1.
75 *
76 * @param md the message digest object with the hash to sign.
77 * @param modsBits the length of the RSA modulus in bits.
78 *
79 * @return the encoded message as a binary-encoded string of length
80 * ceil((modBits - 1) / 8).
81 */
82 pssobj.encode = function(md, modBits) {
83 var i;
84 var emBits = modBits - 1;
85 var emLen = Math.ceil(emBits / 8);
86
87 /* 2. Let mHash = Hash(M), an octet string of length hLen. */
88 var mHash = md.digest().getBytes();
89
90 /* 3. If emLen < hLen + sLen + 2, output "encoding error" and stop. */
91 if(emLen < hLen + sLen + 2) {
92 throw new Error('Message is too long to encrypt.');
93 }
94
95 /* 4. Generate a random octet string salt of length sLen; if sLen = 0,
96 * then salt is the empty string. */
97 var salt;
98 if(salt_ === null) {
99 salt = prng.getBytesSync(sLen);
100 } else {
101 salt = salt_.bytes();
102 }
103
104 /* 5. Let M' = (0x)00 00 00 00 00 00 00 00 || mHash || salt; */
105 var m_ = new forge.util.ByteBuffer();
106 m_.fillWithByte(0, 8);
107 m_.putBytes(mHash);
108 m_.putBytes(salt);
109
110 /* 6. Let H = Hash(M'), an octet string of length hLen. */
111 hash.start();
112 hash.update(m_.getBytes());
113 var h = hash.digest().getBytes();
114
115 /* 7. Generate an octet string PS consisting of emLen - sLen - hLen - 2
116 * zero octets. The length of PS may be 0. */
117 var ps = new forge.util.ByteBuffer();
118 ps.fillWithByte(0, emLen - sLen - hLen - 2);
119
120 /* 8. Let DB = PS || 0x01 || salt; DB is an octet string of length
121 * emLen - hLen - 1. */
122 ps.putByte(0x01);
123 ps.putBytes(salt);
124 var db = ps.getBytes();
125
126 /* 9. Let dbMask = MGF(H, emLen - hLen - 1). */
127 var maskLen = emLen - hLen - 1;
128 var dbMask = mgf.generate(h, maskLen);
129
130 /* 10. Let maskedDB = DB \xor dbMask. */
131 var maskedDB = '';
132 for(i = 0; i < maskLen; i++) {
133 maskedDB += String.fromCharCode(db.charCodeAt(i) ^ dbMask.charCodeAt(i));
134 }
135
136 /* 11. Set the leftmost 8emLen - emBits bits of the leftmost octet in
137 * maskedDB to zero. */
138 var mask = (0xFF00 >> (8 * emLen - emBits)) & 0xFF;
139 maskedDB = String.fromCharCode(maskedDB.charCodeAt(0) & ~mask) +
140 maskedDB.substr(1);
141
142 /* 12. Let EM = maskedDB || H || 0xbc.
143 * 13. Output EM. */
144 return maskedDB + h + String.fromCharCode(0xbc);
145 };
146
147 /**
148 * Verifies a PSS signature.
149 *
150 * This function implements EMSA-PSS-VERIFY as per RFC 3447, section 9.1.2.
151 *
152 * @param mHash the message digest hash, as a binary-encoded string, to
153 * compare against the signature.
154 * @param em the encoded message, as a binary-encoded string
155 * (RSA decryption result).
156 * @param modsBits the length of the RSA modulus in bits.
157 *
158 * @return true if the signature was verified, false if not.
159 */
160 pssobj.verify = function(mHash, em, modBits) {
161 var i;
162 var emBits = modBits - 1;
163 var emLen = Math.ceil(emBits / 8);
164
165 /* c. Convert the message representative m to an encoded message EM
166 * of length emLen = ceil((modBits - 1) / 8) octets, where modBits
167 * is the length in bits of the RSA modulus n */
168 em = em.substr(-emLen);
169
170 /* 3. If emLen < hLen + sLen + 2, output "inconsistent" and stop. */
171 if(emLen < hLen + sLen + 2) {
172 throw new Error('Inconsistent parameters to PSS signature verification.');
173 }
174
175 /* 4. If the rightmost octet of EM does not have hexadecimal value
176 * 0xbc, output "inconsistent" and stop. */
177 if(em.charCodeAt(emLen - 1) !== 0xbc) {
178 throw new Error('Encoded message does not end in 0xBC.');
179 }
180
181 /* 5. Let maskedDB be the leftmost emLen - hLen - 1 octets of EM, and
182 * let H be the next hLen octets. */
183 var maskLen = emLen - hLen - 1;
184 var maskedDB = em.substr(0, maskLen);
185 var h = em.substr(maskLen, hLen);
186
187 /* 6. If the leftmost 8emLen - emBits bits of the leftmost octet in
188 * maskedDB are not all equal to zero, output "inconsistent" and stop. */
189 var mask = (0xFF00 >> (8 * emLen - emBits)) & 0xFF;
190 if((maskedDB.charCodeAt(0) & mask) !== 0) {
191 throw new Error('Bits beyond keysize not zero as expected.');
192 }
193
194 /* 7. Let dbMask = MGF(H, emLen - hLen - 1). */
195 var dbMask = mgf.generate(h, maskLen);
196
197 /* 8. Let DB = maskedDB \xor dbMask. */
198 var db = '';
199 for(i = 0; i < maskLen; i++) {
200 db += String.fromCharCode(maskedDB.charCodeAt(i) ^ dbMask.charCodeAt(i));
201 }
202
203 /* 9. Set the leftmost 8emLen - emBits bits of the leftmost octet
204 * in DB to zero. */
205 db = String.fromCharCode(db.charCodeAt(0) & ~mask) + db.substr(1);
206
207 /* 10. If the emLen - hLen - sLen - 2 leftmost octets of DB are not zero
208 * or if the octet at position emLen - hLen - sLen - 1 (the leftmost
209 * position is "position 1") does not have hexadecimal value 0x01,
210 * output "inconsistent" and stop. */
211 var checkLen = emLen - hLen - sLen - 2;
212 for(i = 0; i < checkLen; i++) {
213 if(db.charCodeAt(i) !== 0x00) {
214 throw new Error('Leftmost octets not zero as expected');
215 }
216 }
217
218 if(db.charCodeAt(checkLen) !== 0x01) {
219 throw new Error('Inconsistent PSS signature, 0x01 marker not found');
220 }
221
222 /* 11. Let salt be the last sLen octets of DB. */
223 var salt = db.substr(-sLen);
224
225 /* 12. Let M' = (0x)00 00 00 00 00 00 00 00 || mHash || salt */
226 var m_ = new forge.util.ByteBuffer();
227 m_.fillWithByte(0, 8);
228 m_.putBytes(mHash);
229 m_.putBytes(salt);
230
231 /* 13. Let H' = Hash(M'), an octet string of length hLen. */
232 hash.start();
233 hash.update(m_.getBytes());
234 var h_ = hash.digest().getBytes();
235
236 /* 14. If H = H', output "consistent." Otherwise, output "inconsistent." */
237 return h === h_;
238 };
239
240 return pssobj;
241};
Note: See TracBrowser for help on using the repository browser.