/ node_modules / jwa / index.js
index.js
  1  var Buffer = require('safe-buffer').Buffer;
  2  var crypto = require('crypto');
  3  var formatEcdsa = require('ecdsa-sig-formatter');
  4  var util = require('util');
  5  
  6  var MSG_INVALID_ALGORITHM = '"%s" is not a valid algorithm.\n  Supported algorithms are:\n  "HS256", "HS384", "HS512", "RS256", "RS384", "RS512", "PS256", "PS384", "PS512", "ES256", "ES384", "ES512" and "none".'
  7  var MSG_INVALID_SECRET = 'secret must be a string or buffer';
  8  var MSG_INVALID_VERIFIER_KEY = 'key must be a string or a buffer';
  9  var MSG_INVALID_SIGNER_KEY = 'key must be a string, a buffer or an object';
 10  
 11  var supportsKeyObjects = typeof crypto.createPublicKey === 'function';
 12  if (supportsKeyObjects) {
 13    MSG_INVALID_VERIFIER_KEY += ' or a KeyObject';
 14    MSG_INVALID_SECRET += 'or a KeyObject';
 15  }
 16  
 17  function checkIsPublicKey(key) {
 18    if (Buffer.isBuffer(key)) {
 19      return;
 20    }
 21  
 22    if (typeof key === 'string') {
 23      return;
 24    }
 25  
 26    if (!supportsKeyObjects) {
 27      throw typeError(MSG_INVALID_VERIFIER_KEY);
 28    }
 29  
 30    if (typeof key !== 'object') {
 31      throw typeError(MSG_INVALID_VERIFIER_KEY);
 32    }
 33  
 34    if (typeof key.type !== 'string') {
 35      throw typeError(MSG_INVALID_VERIFIER_KEY);
 36    }
 37  
 38    if (typeof key.asymmetricKeyType !== 'string') {
 39      throw typeError(MSG_INVALID_VERIFIER_KEY);
 40    }
 41  
 42    if (typeof key.export !== 'function') {
 43      throw typeError(MSG_INVALID_VERIFIER_KEY);
 44    }
 45  };
 46  
 47  function checkIsPrivateKey(key) {
 48    if (Buffer.isBuffer(key)) {
 49      return;
 50    }
 51  
 52    if (typeof key === 'string') {
 53      return;
 54    }
 55  
 56    if (typeof key === 'object') {
 57      return;
 58    }
 59  
 60    throw typeError(MSG_INVALID_SIGNER_KEY);
 61  };
 62  
 63  function checkIsSecretKey(key) {
 64    if (Buffer.isBuffer(key)) {
 65      return;
 66    }
 67  
 68    if (typeof key === 'string') {
 69      return key;
 70    }
 71  
 72    if (!supportsKeyObjects) {
 73      throw typeError(MSG_INVALID_SECRET);
 74    }
 75  
 76    if (typeof key !== 'object') {
 77      throw typeError(MSG_INVALID_SECRET);
 78    }
 79  
 80    if (key.type !== 'secret') {
 81      throw typeError(MSG_INVALID_SECRET);
 82    }
 83  
 84    if (typeof key.export !== 'function') {
 85      throw typeError(MSG_INVALID_SECRET);
 86    }
 87  }
 88  
 89  function fromBase64(base64) {
 90    return base64
 91      .replace(/=/g, '')
 92      .replace(/\+/g, '-')
 93      .replace(/\//g, '_');
 94  }
 95  
 96  function toBase64(base64url) {
 97    base64url = base64url.toString();
 98  
 99    var padding = 4 - base64url.length % 4;
100    if (padding !== 4) {
101      for (var i = 0; i < padding; ++i) {
102        base64url += '=';
103      }
104    }
105  
106    return base64url
107      .replace(/\-/g, '+')
108      .replace(/_/g, '/');
109  }
110  
111  function typeError(template) {
112    var args = [].slice.call(arguments, 1);
113    var errMsg = util.format.bind(util, template).apply(null, args);
114    return new TypeError(errMsg);
115  }
116  
117  function bufferOrString(obj) {
118    return Buffer.isBuffer(obj) || typeof obj === 'string';
119  }
120  
121  function normalizeInput(thing) {
122    if (!bufferOrString(thing))
123      thing = JSON.stringify(thing);
124    return thing;
125  }
126  
127  function createHmacSigner(bits) {
128    return function sign(thing, secret) {
129      checkIsSecretKey(secret);
130      thing = normalizeInput(thing);
131      var hmac = crypto.createHmac('sha' + bits, secret);
132      var sig = (hmac.update(thing), hmac.digest('base64'))
133      return fromBase64(sig);
134    }
135  }
136  
137  var bufferEqual;
138  var timingSafeEqual = 'timingSafeEqual' in crypto ? function timingSafeEqual(a, b) {
139    if (a.byteLength !== b.byteLength) {
140      return false;
141    }
142  
143    return crypto.timingSafeEqual(a, b)
144  } : function timingSafeEqual(a, b) {
145    if (!bufferEqual) {
146      bufferEqual = require('buffer-equal-constant-time');
147    }
148  
149    return bufferEqual(a, b)
150  }
151  
152  function createHmacVerifier(bits) {
153    return function verify(thing, signature, secret) {
154      var computedSig = createHmacSigner(bits)(thing, secret);
155      return timingSafeEqual(Buffer.from(signature), Buffer.from(computedSig));
156    }
157  }
158  
159  function createKeySigner(bits) {
160   return function sign(thing, privateKey) {
161      checkIsPrivateKey(privateKey);
162      thing = normalizeInput(thing);
163      // Even though we are specifying "RSA" here, this works with ECDSA
164      // keys as well.
165      var signer = crypto.createSign('RSA-SHA' + bits);
166      var sig = (signer.update(thing), signer.sign(privateKey, 'base64'));
167      return fromBase64(sig);
168    }
169  }
170  
171  function createKeyVerifier(bits) {
172    return function verify(thing, signature, publicKey) {
173      checkIsPublicKey(publicKey);
174      thing = normalizeInput(thing);
175      signature = toBase64(signature);
176      var verifier = crypto.createVerify('RSA-SHA' + bits);
177      verifier.update(thing);
178      return verifier.verify(publicKey, signature, 'base64');
179    }
180  }
181  
182  function createPSSKeySigner(bits) {
183    return function sign(thing, privateKey) {
184      checkIsPrivateKey(privateKey);
185      thing = normalizeInput(thing);
186      var signer = crypto.createSign('RSA-SHA' + bits);
187      var sig = (signer.update(thing), signer.sign({
188        key: privateKey,
189        padding: crypto.constants.RSA_PKCS1_PSS_PADDING,
190        saltLength: crypto.constants.RSA_PSS_SALTLEN_DIGEST
191      }, 'base64'));
192      return fromBase64(sig);
193    }
194  }
195  
196  function createPSSKeyVerifier(bits) {
197    return function verify(thing, signature, publicKey) {
198      checkIsPublicKey(publicKey);
199      thing = normalizeInput(thing);
200      signature = toBase64(signature);
201      var verifier = crypto.createVerify('RSA-SHA' + bits);
202      verifier.update(thing);
203      return verifier.verify({
204        key: publicKey,
205        padding: crypto.constants.RSA_PKCS1_PSS_PADDING,
206        saltLength: crypto.constants.RSA_PSS_SALTLEN_DIGEST
207      }, signature, 'base64');
208    }
209  }
210  
211  function createECDSASigner(bits) {
212    var inner = createKeySigner(bits);
213    return function sign() {
214      var signature = inner.apply(null, arguments);
215      signature = formatEcdsa.derToJose(signature, 'ES' + bits);
216      return signature;
217    };
218  }
219  
220  function createECDSAVerifer(bits) {
221    var inner = createKeyVerifier(bits);
222    return function verify(thing, signature, publicKey) {
223      signature = formatEcdsa.joseToDer(signature, 'ES' + bits).toString('base64');
224      var result = inner(thing, signature, publicKey);
225      return result;
226    };
227  }
228  
229  function createNoneSigner() {
230    return function sign() {
231      return '';
232    }
233  }
234  
235  function createNoneVerifier() {
236    return function verify(thing, signature) {
237      return signature === '';
238    }
239  }
240  
241  module.exports = function jwa(algorithm) {
242    var signerFactories = {
243      hs: createHmacSigner,
244      rs: createKeySigner,
245      ps: createPSSKeySigner,
246      es: createECDSASigner,
247      none: createNoneSigner,
248    }
249    var verifierFactories = {
250      hs: createHmacVerifier,
251      rs: createKeyVerifier,
252      ps: createPSSKeyVerifier,
253      es: createECDSAVerifer,
254      none: createNoneVerifier,
255    }
256    var match = algorithm.match(/^(RS|PS|ES|HS)(256|384|512)$|^(none)$/i);
257    if (!match)
258      throw typeError(MSG_INVALID_ALGORITHM, algorithm);
259    var algo = (match[1] || match[3]).toLowerCase();
260    var bits = match[2];
261  
262    return {
263      sign: signerFactories[algo](bits),
264      verify: verifierFactories[algo](bits),
265    }
266  };