How to build a Password Manager with Node.js : Part - 1
Tags: webdev, tutorial, node, security
Published: 2021-10-15 19:50:00

A password manager is a computer program that allows users to store, generate, and manage their passwords for local applications and online services. A password manager assists in generating and retrieving complex passwords, storing such passwords in an encrypted database, or calculating them on demand. For the past seven years "**123456**" and "**password**" have been the two most commonly used passwords on the web. The problem is, most of us don't know what makes a good password and aren't able to remember hundreds of them anyway.

## Why Not Use Your Browser?

Most web browsers offer at least a rudimentary password manager. (This is where your passwords are stored when Google Chrome or Mozilla Firefox ask if you'd like to save a password.) This is better than reusing the same password everywhere, but browser-based password managers are limited. [Read More](https://www.avira.com/en/blog/browser-based-password-managers-vs-dedicated-password-managers)

## package.json

```json
"dependencies": {
  "apollo-server": "^3.1.2",
  "dotenv": "^10.0.0",
  "graphql": "^15.5.1",
  "mongoose": "^6.0.7"
},
```

`crypto` package is now a built-in Node module.

## Encryption

We are going to use the AES algorithm which is an iterative, symmetric-key block cipher that supports cryptographic keys **(secret keys)** of 128, 192, and 256 bits to encrypt and decrypt data in blocks of 128 bits. The below figure shows the high-level AES algorithm:

![JavaScript-AES-256-GCM-Encryption-and-Decryption-Example.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1634310985185/1zfLunEdl.png)

**Note** : `ENCRYPT_KEY` must be of 32 bytes

```js
const encrypt = (password) => {
  const iv = Buffer.from(randomBytes(16));
  // iv : initialization vector
  const cipher = createCipheriv(
    "aes-256-gcm",
    Buffer.from(process.env.ENCRYPT_KEY),
    iv
  );
  const encpass = Buffer.concat([cipher.update(password), cipher.final()]);
  return {
    iv: iv.toString("hex"),
    password: encpass.toString("hex"),
    tag: cipher.getAuthTag().toString("hex"),
  };
};
```

> Know more about [createCipheriv](https://nodejs.org/api/crypto.html#crypto_crypto_createcipheriv_algorithm_key_iv_options) function and [Buffer](https://nodejs.org/api/buffer.html#buffer_class_buffer) Class.

### What is IV?

In cryptography, an [initialization vector (IV)](https://en.wikipedia.org/wiki/Initialization_vector) or starting variable (SV) is an input to a cryptographic primitive being used to provide the initial state.

### What is `'aes-256-gcm'` ?

In cryptography, [Galois/Counter Mode (GCM)](https://en.wikipedia.org/wiki/Galois/Counter_Mode) is a mode of operation for symmetric-key cryptographic block ciphers which is widely adopted for its performance. GCM throughput rates for state-of-the-art, high-speed communication channels can be achieved with inexpensive hardware resources. The operation is an [authenticated encryption](https://en.wikipedia.org/wiki/Authenticated_encryption) algorithm designed to provide both data authenticity (integrity) and confidentiality. GCM is defined for block ciphers with a block size of 128 bits. Galois Message Authentication Code (GMAC) is an authentication-only variant of the GCM which can form an incremental message authentication code. Both GCM and GMAC can accept initialization vectors of arbitrary length.

### What is `tag` ?

The authentication tag is defined as an output parameter in GCM. In all the API's I've encountered it's appended to the ciphertext. Where it is actually placed is up to the protocol designer. The name "tag" of course kind of indicates that it should be tagged to the ciphertext and that may well mean direct concatenation. For the sake of clarity, we have placed it as a separate key.

## Decryption

```js
const decrypt = (encpass) => {
  const decipher = createDecipheriv(
    "aes-256-gcm",
    Buffer.from(process.env.ENCRYPT_KEY),
    Buffer.from(encpass.iv, "hex")
  );
  decipher.setAuthTag(Buffer.from(encpass.tag, "hex"));
  const decpass = Buffer.concat([
    decipher.update(Buffer.from(encpass.password, "hex")),
    decipher.final(),
  ]);
  return decpass.toString();
};
```

> Know more about [createDecipheriv](https://nodejs.org/api/crypto.html#crypto_crypto_createdecipheriv_algorithm_key_iv_options) function

## Moment of truth

![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1634322161113/Zwd8xKIsb.png)

### Success 🥳

The function is able to retrieve the original plain text password from the encrypted data, that means encryption and decryption are both working properly.

## Why apollo-server ?

Apollo Server is a community-maintained open-source GraphQL server. It works with many Node.js HTTP server frameworks, or can run on its own with a built-in Express server. [Read More](https://www.apollographql.com/docs/apollo-server/)

## Setup apollo-server

```js
const server = new ApolloServer({
  typeDefs,
  resolvers,
  context: ({ req }) => ({ req }),
});

connect(process.env.MONGODB, {
  useNewUrlParser: true,
  useUnifiedTopology: true,
})
  .then(() => {
    console.log(`Database Connected 🔥`);
    return server.listen({ port: process.env.PORT });
  })
  .then(({ url }) => {
    console.log(`${url} : Server Running 🔥`);
  });
```

> Know more about GraphQL [Schemas, TypeDefs & Resolvers](https://www.prisma.io/blog/graphql-server-basics-the-schema-ac5e2950214e)

![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1634323637765/yn78d5B37.png)

Now we can use any API client to quickly and easily send GraphQL requests at port `5555`. In the next part, we'll create a front-end for the same with proper user-authentication, login/signup mutations, create/retrive password query and a decent looking UI for the password manager.

This is all for this article. Hope you found it helpful :)

You can find me on [Twitter](https://twitter.com/r0hnx) where I'm also sharing my journey as a FullStack Developer.