Пример #1
0
 static fixedTimeComparison(a, b) {
   try {
     return crypto.timingSafeEqual(Buffer.from(a), Buffer.from(b));
   } catch (err) {
     return false;
   }
 }
Пример #2
0
exports.fixedTimeComparison = function (a, b) {

    try {
        return Crypto.timingSafeEqual(Buffer.from(a), Buffer.from(b));
    }
    catch (err) {
        return false;
    }
};
Пример #3
0
function hashMatches(hash, secret) {
  const parts = hash.split(/:/g);
  if (parts[0] !== "shaHmac") {
    throw new Error("Unknown type of hash");
  }
  if (parts.length !== 3) {
    throw new Error("Bad hash format, should be type:nonce:data");
  }
  const expected = createHash(secret, parts[1]);
  return crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(hash));
}
Пример #4
0
function equalStrings(a, b) {
  if (!crypto.timeingSafeEqual) {
    return a === b;
  }
  var bufA = Buffer.from(`${a}`);
  var bufB = Buffer.from(`${b}`);
  // Funny way to force buffers to have same length
  return crypto.timingSafeEqual(
    Buffer.concat([a, b]),
    Buffer.concat([b, a])
  );
}
Пример #5
0
 ensureGithub: (req, res, next) => {
   if (!req.headers['user-agent'].includes('GitHub-Hookshot')) return res.redirect(301, '/');
   const hmac = crypto.createHmac('sha1', process.env.GITHUB_SECRET);
   if (
     crypto.timingSafeEqual(
       Buffer.from(`sha1=${hmac.update(JSON.stringify(req.body)).digest('hex')}`, 'utf8'),
       Buffer.from(req.get('X-Hub-Signature'), 'utf8'),
     )
   ) {
     return next();
   }
   return res.redirect(301, '/');
 },
Пример #6
0
 // Verifies if password is correct.
 validate (hash, password) {
     if (hash.substr(0, 5) === '{SHA}') {
         hash = hash.substr(5);
         return hash === utils.sha1(password);
     } else if (hash.substr(0, 6) === '$apr1$' || hash.substr(0, 3) === '$1$') {
         return hash === md5(password, hash);
     } else if (hash.substr(0, 4) === '$2y$' || hash.substr(0, 4) === '$2a$') {
         return bcrypt.compareSync(password, hash);
     } else if (hash === crypt(password, hash)) {
         return true;
     } else if (hash.length === password.length) {
         return crypto.timingSafeEqual ?
             crypto.timingSafeEqual(new Buffer(hash), new Buffer(password)) : hash === password;
     }
 }
Пример #7
0
function decryptFrontPageData(data) {
	data = Buffer.from(data, 'base64');

	var decipher = crypto.createDecipheriv('aes256', Buffer.from(nconf.get('tdwtf_front_e'), 'base64'), data.slice(32, 48));
	var decrypted = decipher.update(data.slice(48));
	decrypted = Buffer.concat([decrypted, decipher.final()]);

	var verify = crypto.createHmac('sha256', Buffer.from(nconf.get('tdwtf_front_s'), 'base64'));
	verify.update(decrypted);
	var hash = verify.digest();

	if (!crypto.timingSafeEqual(data.slice(0, 32), hash)) {
		throw new Error('invalid data');
	}

	return decrypted.toString('utf8');
}
Пример #8
0
module.exports = function scmp (a, b) {
  // check that both inputs are buffers
  if (!Buffer.isBuffer(a) || !Buffer.isBuffer(b)) {
    throw new Error('Both scmp args must be Buffers');
  }

  // return early here if buffer lengths are not equal since timingSafeEqual
  // will throw if buffer lengths are not equal
  if (a.length !== b.length) {
    return false;
  }

  // use crypto.timingSafeEqual if available (since Node.js v6.6.0),
  // otherwise use our own scmp-internal function.
  if (crypto.timingSafeEqual) {
    return crypto.timingSafeEqual(a, b);
  }

  return scmpCompare(a, b);
};
Пример #9
0
    /**
     * Get the list of devices discovered through the hub.
     * 
     * @param {bool} expand - True to include the current state of the resources.
     * @param {Buffer} payload - POST content for a subscribed notification
     * @param {Object} verification - Information used to authenticate that the post is valid
     * @param {Array} verification.header - Header information that came with the payload POST.
     *      Should include X-Hub-Signature
     * @param {verification} verification.key - Secret key used to hash the payload (provided to Wink on subscribe)
     */
    getPlatforms(expand, payload, verification) {

        // Payload can contain one or more platforms defined using the provider schema.  This should return those platforms
        // converted to the opent2t/ocf representation.
        if (payload !== undefined) {

            // The payload must be an object for translation, and a string/buffer for calculating
            // the HMAC. Ensure we have a copy in both formats
            var payloadAsString = typeof payload === 'object' ? JSON.stringify(payload) : payload;
            var payloadAsObject = typeof payload === 'object' ? payload : JSON.parse(payload);

            // Calculate the HMAC for the payload using the secret
            if (verification !== undefined && verification.key !== undefined) {
                // HTTP headers are case insensitive, while the JSON dictionary is case sensitive,
                // so the hub signature can be either x-hub-signature or X-Hub-Signature depending on
                // what server was used to capture the notification POST request.
                var hashFromWink = getDictionaryItemCaseInsensitive(verification.header, "x-hub-signature");
                var hashFromPayload = this._generateHmac(verification.key, payloadAsString);

                if (!Crypto.timingSafeEqual(hashFromWink, hashFromPayload)) {
                    throw new OpenT2TError(401, OpenT2TConstants.HMacSignatureVerificationFailed);
                }
            }

            // Payload may be a device graph update, in Wink's case, the body payload will contain an array of "objects"
            // {object_id: "...", object_type: "..."} but will not include state.  Without state, we can't even make non expanded platform schemas
            // as there is no way to know what resources would be supported where they are optional (a light_bulb object_type optionally supports access
            // colourRGB resource).
            // In the case of a device graph update, fall through to the _makeRequest/_providerSchemaToPlatformSchema combo below.
            if (!payloadAsObject.hasOwnProperty('objects')) {
                // Return the verified payload
                return this._providerSchemaToPlatformSchema(payloadAsObject, expand);
            }
        }

        return this._makeRequest(this._devicesPath, 'GET').then((response) => {
            return this._providerSchemaToPlatformSchema(response.data, expand);
        });
    }
Пример #10
0
    /**
      * Get the list of devices discovered through the hub.
     * 
     * @param {bool} expand - True to include the current state of the resources.
     * @param {Buffer} payload - POST content for a subscribed notification
     * @param {Object} verification - Information used to authenticate that the post is valid
     * @param {Array} verification.header - Header information that came with the payload POST.
     *                                      Includes hubSignature.
     * @param {verification} verification.key - Secret key used to hash the payload (provided to Wink on subscribe)
     */
    getPlatforms(expand, payload, verification) {
        if (payload === undefined) {
            return this._getEndpoints().then((endpoints) => {
                return this._getPlatformsByEndpointList(expand, endpoints);
            });
        } else {
            this.logger.verbose("Subscription Payload: " + JSON.stringify(payload, null, 2));
            
            //HMAC verification
            var payloadAsString = typeof payload === 'object' ? JSON.stringify(payload) : payload;

            // Calculate the HMAC for the payload using the secret
            if (verification !== undefined && verification.key !== undefined) {
                var hashFromSmartThings = verification.header.Signature;
                var hashFromPayload = this._generateHmac(verification.key, payloadAsString);

                if (!Crypto.timingSafeEqual(hashFromSmartThings, hashFromPayload)) {
                    throw new OpenT2TError(401, OpenT2TConstants.HMacSignatureVerificationFailed);
                }
            }
            
            if(payload.eventType){
                //SmartThings device graph event: device added/removed
                return this._getEndpointByLocationId(payload.locationId).then((endpoints) => {
                    return this._getPlatformsByEndpointList(expand, endpoints);
                });
            }else{
                //SmartThings device change event
                return this._getEndpointByLocationId(payload.locationId).then((endpoints) => {
                    if (endpoints.length === 0) return undefined;
                    
                    return this._providerSchemaToPlatformSchema(payload, expand, endpoints[0]);
                });
            }
        }
    }
Пример #11
0
 var compareSecure = function(a, b) {
   return a.length === b.length && crypto.timingSafeEqual(new Buffer(a), new Buffer(b));
 }
Пример #12
0
'use strict';
const common = require('../common');
if (!common.hasCrypto)
  common.skip('missing crypto');

const assert = require('assert');
const crypto = require('crypto');

assert.strictEqual(
  crypto.timingSafeEqual(Buffer.from('foo'), Buffer.from('foo')),
  true,
  'should consider equal strings to be equal'
);

assert.strictEqual(
  crypto.timingSafeEqual(Buffer.from('foo'), Buffer.from('bar')),
  false,
  'should consider unequal strings to be unequal'
);

assert.throws(function() {
  crypto.timingSafeEqual(Buffer.from([1, 2, 3]), Buffer.from([1, 2]));
}, /^TypeError: Input buffers must have the same length$/,
              'should throw when given buffers with different lengths');

assert.throws(function() {
  crypto.timingSafeEqual('not a buffer', Buffer.from([1, 2]));
}, /^TypeError: First argument must be a buffer$/,
              'should throw if the first argument is not a buffer');

assert.throws(function() {
Пример #13
0
assert.throws(function() {
  crypto.timingSafeEqual(Buffer.from([1, 2, 3]), Buffer.from([1, 2]));
}, /^TypeError: Input buffers must have the same length$/,
const limitClientWithExt = function(credentialName, issuingClientId, accessToken, scopes,
  expires, ext, expandScopes) {
  let issuingScopes = scopes;
  let res = {scopes, expires, accessToken};

  // Handle certificates
  if (ext.certificate) {
    let cert = ext.certificate;
    // Validate the certificate
    if (!(cert instanceof Object)) {
      throw new Error('ext.certificate must be a JSON object');
    }
    if (cert.version !== 1) {
      throw new Error('ext.certificate.version must be 1');
    }
    if (typeof cert.seed !== 'string') {
      throw new Error('ext.certificate.seed must be a string');
    }
    if (cert.seed.length !== 44) {
      throw new Error('ext.certificate.seed must be 44 characters');
    }
    if (typeof cert.start !== 'number') {
      throw new Error('ext.certificate.start must be a number');
    }
    if (typeof cert.expiry !== 'number') {
      throw new Error('ext.certificate.expiry must be a number');
    }
    if (!(cert.scopes instanceof Array)) {
      throw new Error('ext.certificate.scopes must be an array');
    }
    if (!cert.scopes.every(utils.validScope)) {
      throw new Error('ext.certificate.scopes must be an array of valid scopes');
    }

    // Check start and expiry
    let now = new Date().getTime();
    if (cert.start > now + 5 * 60 * 1000) {
      throw new Error('ext.certificate.start > now');
    }
    if (cert.expiry < now - 5 * 60 * 1000) {
      throw new Error('ext.certificate.expiry < now');
    }
    // Check max time between start and expiry
    if (cert.expiry - cert.start > 31 * 24 * 60 * 60 * 1000) {
      throw new Error('ext.certificate cannot last longer than 31 days!');
    }

    // Check clientId validity
    if (issuingClientId !== credentialName) {
      let createScope = 'auth:create-client:' + credentialName;
      if (!utils.scopeMatch(issuingScopes, [[createScope]])) {
        throw new Error('ext.certificate issuer `' + issuingClientId +
                        '` doesn\'t have `' + createScope + '` for supplied clientId.');
      }
    } else if (cert.hasOwnProperty('clientId')) {
      throw new Error('ext.certificate.clientId must only be used with ext.certificate.issuer');
    }

    // Validate certificate scopes are subset of client
    if (!utils.scopeMatch(scopes, [cert.scopes])) {
      throw new Error('ext.certificate issuer `' + issuingClientId +
                      '` doesn\'t satisfiy all certificate scopes ' +
                      cert.scopes.join(', ') + '.  The temporary ' +
                      'credentials were not generated correctly.');
    }

    // Generate certificate signature
    let sigContent = [];
    sigContent.push('version:'    + '1');
    if (cert.issuer) {
      sigContent.push('clientId:' + credentialName);
      sigContent.push('issuer:'   + cert.issuer);
    }
    sigContent.push('seed:'       + cert.seed);
    sigContent.push('start:'      + cert.start);
    sigContent.push('expiry:'     + cert.expiry);
    sigContent.push('scopes:');
    sigContent = sigContent.concat(cert.scopes);
    let signature = crypto.createHmac('sha256', accessToken)
      .update(sigContent.join('\n'))
      .digest('base64');

    // Validate signature
    if (typeof cert.signature !== 'string' ||
        !crypto.timingSafeEqual(Buffer.from(cert.signature), Buffer.from(signature))) {
      if (cert.issuer) {
        throw new Error('ext.certificate.signature is not valid, or wrong clientId provided');
      } else {
        throw new Error('ext.certificate.signature is not valid');
      }
    }

    // Regenerate temporary key
    let temporaryKey = crypto.createHmac('sha256', accessToken)
      .update(cert.seed)
      .digest('base64')
      .replace(/\+/g, '-')  // Replace + with - (see RFC 4648, sec. 5)
      .replace(/\//g, '_')  // Replace / with _ (see RFC 4648, sec. 5)
      .replace(/=/g,  '');  // Drop '==' padding

    // Update expiration, scopes and accessToken
    res.accessToken = temporaryKey;

    let cert_expires = new Date(cert.expiry);
    if (res.expires > cert_expires) {
      res.expires = cert_expires;
    }

    res.scopes = scopes = expandScopes(cert.scopes);
  }

  // Handle scope restriction with authorizedScopes
  if (ext.authorizedScopes) {
    // Validate input format
    if (!(ext.authorizedScopes instanceof Array)) {
      throw new Error('ext.authorizedScopes must be an array');
    }
    if (!ext.authorizedScopes.every(utils.validScope)) {
      throw new Error('ext.authorizedScopes must be an array of valid scopes');
    }

    // Validate authorizedScopes scopes are satisfied by client (or temp) scopes
    if (!utils.scopeMatch(res.scopes, [ext.authorizedScopes])) {
      throw new Error('Supplied credentials do not satisfy authorizedScopes; '
        + `credentials have scopes [${res.scopes}]; `
        + `authorizedScopes are [${[ext.authorizedScopes]}]`);
    }

    // Further limit scopes
    res.scopes = scopes = expandScopes(ext.authorizedScopes);
  }

  return res;
};
Пример #15
0
 Crypt._buffer_equal = function (b1, b2)
 {
     return (b1.length === b2.length) && crypto.timingSafeEqual(b1, b2);
 };
Пример #16
0
assert.throws(function() {
  crypto.timingSafeEqual(Buffer.from([1, 2]), 'not a buffer');
}, /^TypeError: Second argument must be a buffer$/,
Пример #17
0
assert.throws(function() {
  crypto.timingSafeEqual('not a buffer', Buffer.from([1, 2]));
}, /^TypeError: First argument must be a buffer$/,