> ## Documentation Index
> Fetch the complete documentation index at: https://docs.loremstock.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Data Encryption for Securing RESTful APIs

> Learn symmetric and asymmetric encryption, hash passwords with bcrypt, generate tokens with Node's crypto module, and understand why HTTPS protects data in transit.

Encryption is the foundation of API security. Without it, passwords stored in databases are readable if the server is compromised, and data sent over networks can be intercepted. This page covers the types of encryption you use in Node.js backend development, with complete working code for every technique.

## Key Concepts: Encryption Vocabulary

| Term               | Simple Definition                                                          |
| ------------------ | -------------------------------------------------------------------------- |
| **Plaintext**      | Original readable data before encryption                                   |
| **Ciphertext**     | Scrambled, unreadable version after encryption                             |
| **Encryption key** | The secret used to encrypt and decrypt data                                |
| **Hashing**        | One-way transformation: plaintext -> hash (cannot be reversed)             |
| **Salt**           | Random data added to input before hashing to prevent rainbow table attacks |
| **Symmetric**      | Same key used to encrypt and decrypt                                       |
| **Asymmetric**     | Public key encrypts, private key decrypts (or vice versa)                  |

## Hashing vs Encryption

These are often confused. Know the difference.

| Feature     | Hashing                   | Encryption                        |
| ----------- | ------------------------- | --------------------------------- |
| Reversible? | No (one-way)              | Yes (with the key)                |
| Use case    | Passwords, file integrity | Storing sensitive data, transport |
| Example     | bcrypt, SHA-256           | AES-256, RSA                      |
| Output      | Fixed-length hash         | Variable-length ciphertext        |

<Note>
  Passwords must be HASHED, not encrypted. If you encrypt passwords, the encryption key becomes the single point of failure. If hashed with bcrypt, even the server admin cannot read the original password.
</Note>

## Password Hashing with bcrypt

bcrypt is the industry-standard library for hashing passwords in Node.js.

```bash theme={null}
npm install bcrypt
```

### How bcrypt Works

1. Generates a random salt
2. Combines salt + password
3. Runs the combination through a slow hashing algorithm N times (controlled by `saltRounds`)
4. Returns a single string containing the algorithm, salt, and hash

### Hashing a Password

```javascript theme={null}
const bcrypt = require('bcrypt');

const hashPassword = async (plainTextPassword) => {
  const saltRounds = 10; // Recommended: 10-12. Higher = slower but more secure.
  const hash = await bcrypt.hash(plainTextPassword, saltRounds);
  return hash;
  // Example output: "$2b$10$N9qo8uLOickgx2ZMRZoMyeIjZAgcfl7p92ldGxad68LJZdL17lhWy"
};
```

### Comparing a Password

```javascript theme={null}
const verifyPassword = async (plainTextPassword, hashedPassword) => {
  const isMatch = await bcrypt.compare(plainTextPassword, hashedPassword);
  return isMatch; // true or false
};
```

### Complete Login Example

```javascript theme={null}
// controllers/authController.js
const bcrypt = require('bcrypt');
const User = require('../models/User');
const jwt = require('jsonwebtoken');

exports.login = async (req, res) => {
  try {
    const { email, password } = req.body;

    // Find user
    const user = await User.findOne({ email });
    if (!user) {
      return res.status(401).json({ message: 'Invalid credentials' });
    }

    // Compare password with stored hash
    const isMatch = await bcrypt.compare(password, user.password);
    if (!isMatch) {
      return res.status(401).json({ message: 'Invalid credentials' });
    }

    // Sign JWT
    const token = jwt.sign(
      { sub: user._id, role: user.role },
      process.env.JWT_SECRET,
      { expiresIn: '1d' }
    );

    res.status(200).json({ token });
  } catch (err) {
    res.status(500).json({ message: err.message });
  }
};
```

<Warning>
  Always return the same error message for "user not found" and "wrong password". Returning different messages reveals whether an email is registered, which attackers exploit for account enumeration.
</Warning>

### Salt Rounds: What They Mean

Salt rounds control how many times bcrypt iterates. Each increment roughly doubles the time.

| Salt Rounds | Approximate Time | Recommendation          |
| ----------- | ---------------- | ----------------------- |
| 8           | Very fast (ms)   | Too weak for production |
| 10          | \~100ms          | Minimum for production  |
| 12          | \~400ms          | Good default            |
| 14          | \~1.5 seconds    | Maximum practical       |

## Symmetric Encryption: AES-256 with crypto

Node.js has a built-in `crypto` module. Use it for encrypting sensitive data at rest (credit card numbers, PII, tokens to store in DB).

```javascript theme={null}
const crypto = require('crypto');

const ALGORITHM = 'aes-256-cbc';
const KEY = Buffer.from(process.env.ENCRYPTION_KEY, 'hex'); // 32 bytes = 64 hex chars
const IV_LENGTH = 16; // AES block size

// Encrypt a string
function encrypt(text) {
  const iv = crypto.randomBytes(IV_LENGTH);
  const cipher = crypto.createCipheriv(ALGORITHM, KEY, iv);
  let encrypted = cipher.update(text, 'utf8', 'hex');
  encrypted += cipher.final('hex');
  return iv.toString('hex') + ':' + encrypted;
}

// Decrypt a string
function decrypt(encryptedText) {
  const [ivHex, encrypted] = encryptedText.split(':');
  const iv = Buffer.from(ivHex, 'hex');
  const decipher = crypto.createDecipheriv(ALGORITHM, KEY, iv);
  let decrypted = decipher.update(encrypted, 'hex', 'utf8');
  decrypted += decipher.final('utf8');
  return decrypted;
}

module.exports = { encrypt, decrypt };
```

Generate a key for your .env:

```bash theme={null}
node -e "console.log(require('crypto').randomBytes(32).toString('hex'))"
```

## Asymmetric Encryption: Public/Private Keys

Used in HTTPS (TLS), JWT signing with RS256, and SSL certificates. The public key encrypts or verifies; the private key decrypts or signs.

```javascript theme={null}
const crypto = require('crypto');

// Generate an RSA key pair
const { publicKey, privateKey } = crypto.generateKeyPairSync('rsa', {
  modulusLength: 2048,
});

// Encrypt with public key (anyone can encrypt)
function encryptWithPublicKey(data) {
  return crypto.publicEncrypt(publicKey, Buffer.from(data)).toString('base64');
}

// Decrypt with private key (only the owner can decrypt)
function decryptWithPrivateKey(encryptedData) {
  return crypto.privateDecrypt(
    privateKey,
    Buffer.from(encryptedData, 'base64')
  ).toString('utf8');
}
```

<Note>
  In JWT with RS256 algorithm, the server signs tokens with the PRIVATE key and clients verify with the PUBLIC key. This allows clients to validate tokens without ever knowing the private key.
</Note>

## Generating Secure Random Tokens

Use `crypto.randomBytes()` for password reset tokens, email verification tokens, and API keys.

```javascript theme={null}
const crypto = require('crypto');

// Generate a secure random token
function generateToken(bytes = 32) {
  return crypto.randomBytes(bytes).toString('hex');
  // Returns a 64-character hex string for 32 bytes
}

// Usage: password reset
const resetToken = generateToken();
const resetTokenExpiry = Date.now() + 3600000; // 1 hour from now

// Store hash of token in DB (not the token itself!)
const hashedToken = crypto
  .createHash('sha256')
  .update(resetToken)
  .digest('hex');

// Send resetToken to user's email, store hashedToken in DB
```

## HTTPS/TLS: Encryption in Transit

HTTPS encrypts all data between client and server using TLS. Without HTTPS, passwords sent in login requests can be intercepted on public networks.

For development (self-signed cert):

```javascript theme={null}
const https = require('https');
const fs = require('fs');
const express = require('express');

const app = express();

const httpsOptions = {
  key: fs.readFileSync('./certs/server.key'),
  cert: fs.readFileSync('./certs/server.cert')
};

https.createServer(httpsOptions, app).listen(443, () => {
  console.log('HTTPS server running on port 443');
});
```

In production, use Certbot with Nginx (covered in LO4) rather than managing TLS in Node.js directly.

## Key Terms

| Term              | Definition                                                                            |
| ----------------- | ------------------------------------------------------------------------------------- |
| **bcrypt**        | Adaptive hashing algorithm designed specifically for passwords. Slow by design.       |
| **Salt**          | Random value added to a password before hashing. Prevents rainbow table attacks.      |
| **Salt rounds**   | The cost factor in bcrypt. Controls how many iterations run. Higher = slower + safer. |
| **AES-256**       | Advanced Encryption Standard with 256-bit key. Symmetric, very fast.                  |
| **RSA**           | Asymmetric algorithm using public/private key pairs. Slower but more flexible.        |
| **TLS/HTTPS**     | Transport Layer Security. Encrypts data between client and server.                    |
| **Rainbow table** | Pre-computed table of common password hashes used to crack them. Salt prevents this.  |

## Common Mistakes

<Accordion title="Using MD5 or SHA-1 for passwords">
  MD5 and SHA-1 are fast cryptographic hashes, not password hashing algorithms. Fast = bad for passwords. Always use bcrypt, Argon2, or scrypt for password storage.
</Accordion>

<Accordion title="Storing the encryption key in the same database as the encrypted data">
  If an attacker dumps your database and also finds the encryption key there, encryption provides no protection. Store keys in environment variables or a key management service.
</Accordion>

<Accordion title="Using the same IV for every encryption">
  AES requires a unique Initialization Vector for every encryption operation. Reusing IVs leaks information about the plaintext. Always generate a new IV with `crypto.randomBytes(16)`.
</Accordion>

<Accordion title="Not using HTTPS in production">
  Without HTTPS, credentials sent in login forms are plaintext on the network. Always configure SSL/TLS before going live.
</Accordion>
