diff --git a/backend/controllers/key_controller.js b/backend/controllers/key_controller.js index 8e511df..5611704 100644 --- a/backend/controllers/key_controller.js +++ b/backend/controllers/key_controller.js @@ -1,4 +1,5 @@ const KeyLibrary = require("../models/KeyLibrary"); +const { randomBytes } = require("crypto"); const TRANSMISSION_LIMITS = [3, 6, 9, 12, 365]; // Keys retire after these limits @@ -87,5 +88,7 @@ exports.retryKeyValidation = async (req, res) => { // Function to generate McEliese keys function generateMcElieseKey() { - return Math.random().toString(36).substring(2, 15); + // 32 bytes of CSPRNG output; Math.random() is predictable and yielded + // only ~67 bits drawn from a non-cryptographic generator. + return randomBytes(32).toString("base64url"); } diff --git a/backend/controllers/user_controller.js b/backend/controllers/user_controller.js index cf95631..c334c42 100644 --- a/backend/controllers/user_controller.js +++ b/backend/controllers/user_controller.js @@ -1,6 +1,6 @@ const bcrypt = require("../utils/bcrypt"); const jwt = require("../utils/jwt"); -const { randomUUID } = require("crypto"); +const { randomUUID, randomInt } = require("crypto"); const docClient = require("../lib/dynamodbClient"); const { USER_TABLE_NAME, createUserItem } = require("../models/user"); @@ -8,7 +8,10 @@ exports.registerUser = async (req, res) => { try { const { name, email, location, role, password, phone } = req.body; const hashedPassword = await bcrypt.hash(password, 10); - const verificationCode = Math.floor(100000 + Math.random() * 900000).toString(); + // crypto.randomInt: Math.random() is predictable, and a guessable + // verification code lets an attacker verify an account they registered + // with someone else's email/phone. + const verificationCode = randomInt(100000, 1000000).toString(); const userItem = createUserItem({ id: randomUUID(), diff --git a/backend/utils/bcrypt.js b/backend/utils/bcrypt.js index 36de706..34c6c35 100644 --- a/backend/utils/bcrypt.js +++ b/backend/utils/bcrypt.js @@ -5,16 +5,14 @@ try { try { bcrypt = require('bcrypt'); } catch { - const crypto = require('crypto'); - bcrypt = { - async hash(password, _saltRounds) { - return crypto.createHash('sha256').update(password).digest('hex'); - }, - async compare(password, hashed) { - const digest = crypto.createHash('sha256').update(password).digest('hex'); - return digest === hashed; - } - }; + // No silent fallback: the previous unsalted single-round SHA-256 shim + // made every stored password crackable at billions of guesses/second. + // bcryptjs is a declared dependency, so this throw only fires on a + // broken install — which must fail loudly, not degrade silently. + throw new Error( + "No bcrypt implementation available: install 'bcryptjs' (declared in package.json). " + + 'Refusing to fall back to a fast unsalted hash for passwords.' + ); } } module.exports = bcrypt;