35

I have tried for days to get bcrypt installed on my windows machine with no luck. One of the dependencies (Windows 7 SDK) does not want to be installed even though I have tried numerous suggestions from around the net it just refuses to cooperate.

I need a good alternative to bcrypt which does not have any dependencies.

Scott Arciszewski
  • 33,610
  • 16
  • 89
  • 206
Kory
  • 1,396
  • 3
  • 14
  • 31
  • 2
    What's wrong with node's [built-in crypto functions](http://nodejs.org/api/crypto.html)? – josh3736 Nov 06 '13 at 21:12
  • 2
    @josh3736 I don't have enough experience with encryption to answer that. But I've noticed that most projects and examples use bcrypt which seems odd if there are other solutions (mentioned below) that have zero dependencies. – Kory Nov 06 '13 at 22:48

6 Answers6

29

Check out https://npmjs.org/package/bcryptjs, it's fully compatible with bcrypt just without the dependencies.

Or https://npmjs.org/package/simplecrypt if you don't want the crypto boilerplate and just need to encrypt and decrypt strings.

enducat
  • 1,676
  • 3
  • 17
  • 16
  • 2
    I will likely use one of these but Im not sure what you mean by boilerplate. Are you referring to the fact that it makes some assumptions? Like how many bits the key should be, encryption type etc? Other than that are the two different in any other way in terms of being easier or harder to circumvent? – Kory Nov 06 '13 at 22:45
  • Right, the simplecrypt is really good at just doing simple string encodes and decodes without any configuration of salts, hashes, etc. bcryptjs has enterprise support from other modules such as https://npmjs.org/package/loopback, so I would definitely pick that over simplecrypt for anything more complex. – enducat Nov 06 '13 at 23:05
  • 1
    bcryptjs does it have same security features as bcrypt? – Amiga500 Jun 23 '16 at 07:20
22

As of 24th April 2020 There is a nice built in way of hashing passwords using scrypt in the crypto module

// Using the built in crypto module

const { scryptSync, randomBytes } = require("crypto");


// Any random string here (ideally should be atleast 16 bytes)

const salt = randomBytes(16).toString("hex")


// Pass the password string and get hashed password back
// ( and store only the hashed string along with the salt in your database)
// {hashedPassword}${salt}

const getHash = (password) => scryptSync(password, salt, 32).toString("hex");

Malik Bagwala
  • 2,695
  • 7
  • 23
  • 38
10

Here is an improved version of @malik-bagwala with JsDocs, types and a match password function.

import { randomBytes, scryptSync } from 'crypto';

// Pass the password string and get hashed password back
// ( and store only the hashed string in your database)
const encryptPassword = (password: string, salt: string) => {
  return scryptSync(password, salt, 32).toString('hex');
};

/**
 * Hash password with random salt
 * @return {string} password hash followed by salt
 *  XXXX till 64 XXXX till 32
 *
 */
export const hashPassword = (password: string): string => {
  // Any random string here (ideally should be at least 16 bytes)
  const salt = randomBytes(16).toString('hex');
  return encryptPassword(password, salt) + salt;
};

// fetch the user from your db and then use this function

/**
 * Match password against the stored hash
 */
export const matchPassword = (password: string, hash: string): Boolean => {
  // extract salt from the hashed string
  // our hex password length is 32*2 = 64
  const salt = hash.slice(64);
  const originalPassHash = hash.slice(0, 64);
  const currentPassHash = encryptPassword(password, salt);
  return originalPassHash === currentPassHash;
};

Zitoun
  • 446
  • 3
  • 13
Shivam
  • 652
  • 12
  • 14
  • 1
    Use [`crypto.timingSafeEqual`](https://nodejs.org/api/crypto.html#cryptotimingsafeequala-b) instead of `originalPassHash === currentPassHash` for comparing both hashes to prevent timing attacks. You can find an implementation [in this SO answer](https://stackoverflow.com/a/67038052/3673659) – Advena Jan 24 '23 at 07:28
  • 1
    Love this! Nice way of salting the password by appending the salt to the salted hash. Genius! Unless someone finds out the algorithm :D – Zilvinas Apr 04 '23 at 18:20
3

If someone faces similar issue, you can try bcryptjs which is optimized bcrypt written in JavaScript with zero dependencies and is also compatible to the C++ bcrypt.

Michael Johansen
  • 4,688
  • 5
  • 29
  • 47
Nux
  • 5,890
  • 13
  • 48
  • 74
  • 1
    Thank you! Helped. I was facing issues due to a build of bcrypt not existing for arm64-linux (was building a docker image using Alpine Linux on a M1 Mac) – Timotej Leginus Aug 02 '22 at 19:52
  • "Optimized" - [30% slower than bcrypt](https://github.com/dcodeIO/bcrypt.js#security-considerations). – Advena Jan 24 '23 at 07:29
  • @Advena, [slower is better](https://security.stackexchange.com/questions/150620/what-is-the-purpose-of-slowing-down-the-calculation-of-a-password-hash) when it comes to hash functions right? – Mat J May 13 '23 at 20:21
  • @MatJ That's good question! When you verify passwords from db hash you may want to make it a bit slower. But what about when you hash them to save them into db? That `30% slower` can be annoying. – Nux May 14 '23 at 13:10
  • @MatJ exactly as Nux said. Bcrypt is by design slow - no need to make it additionally slow by rewriting it in a high programming language (JavaScript). – Advena May 20 '23 at 14:24
0

You should really use the built-in crypto module for your encryption needs. It's basically a binding to OpenSSL, a fast, stable, secure, and well-vetted crypto library. Trying to implement your own crypto (or use someone else's unvalidated attempt at implementing crypto) is a recipe for disaster.

If you're looking to encrypt data, all you have to do is call crypto.createCipher, which returns a readable/writable Stream. Write data into the stream and it will emit data events with the encrypted data.

For example:

var stream = crypto.createCipher('aes192', 'mysecretpassword');
stream.on('data', function(enc) {
    // enc is a `Buffer` with a chunk of encrypted data
});

stream.write('some secret data');
stream.end();
josh3736
  • 139,160
  • 33
  • 216
  • 263
  • 11
    If you're storing passwords, this is not recommended. You need a salt or else all the passwords in your database could be compromised, e.g., with a rainbow table. Just a thought. Cheers! – Dave Jensen Dec 06 '16 at 22:49
0

It's possible to hash using either Argon2i, Argon2d or Argon2id (default), and verify if a password matches a hash.

https://www.npmjs.com/package/argon2

const password = 'password123';

async function hashPassword(password) {
  try {
    const hashedPassword = await argon2.hash(password);
    console.log('Hashed password:', hashedPassword);
  } catch (error) {
    console.error('Error hashing password:', error);
  }
}

hashPassword(password);
Peter
  • 1,124
  • 14
  • 17