PHP
password security
cryptography
random number generation
salting

Help me understand pack, openssl_random_pseudo_bytes and mt_rand for salting passwords

System Design practice on Codemia

Work through 120+ system design problems with detailed solutions, from rate limiters to multi-region storage.

Practice system design

Introduction

These three PHP functions do very different jobs, and only one of them was historically relevant to secure salt generation. pack() formats bytes, openssl_random_pseudo_bytes() generates cryptographically strong random bytes, and mt_rand() is a general-purpose pseudorandom generator that should not be used for password salts.

What pack() Does

pack() is not a randomness function at all. It converts values into a binary string representation.

Example:

php
<?php
$bytes = pack("H*", "41424344");
echo $bytes;

This prints ABCD because the hexadecimal bytes were packed into their binary form.

So pack() might appear in old password code when someone is formatting data before hashing, but it is not generating entropy and it is not "a salt function."

What openssl_random_pseudo_bytes() Does

This function was used to ask OpenSSL for cryptographically strong random bytes:

php
1<?php
2$strong = false;
3$salt = openssl_random_pseudo_bytes(16, $strong);
4var_dump(strlen($salt), $strong);

Historically, this was the correct class of function for salts because salts need unpredictability and uniqueness. If the $strong flag was true, the output was considered suitable for cryptographic use.

In newer PHP code, random_bytes() is usually preferred because it gives a simpler modern API for secure randomness.

Why Salts Need Unpredictability

A salt does not need to be secret, but it does need to be unique and hard to predict ahead of time. That is why a cryptographic randomness source matters. The point of the salt is to ensure that two identical passwords do not produce the same stored hash and that precomputed rainbow tables become ineffective.

Why mt_rand() Is Wrong for Salts

mt_rand() is not designed for cryptographic security:

php
<?php
echo mt_rand();

It is fine for simulation, games, or non-security randomization, but not for password salting. An attacker should not be able to predict or reconstruct the salt source easily, and mt_rand() is not meant to provide that guarantee.

So the rule is simple:

  • 'mt_rand() for general randomness'
  • cryptographic byte generators for salts, tokens, and keys

Modern Best Practice: Let Password APIs Handle It

In modern PHP, you usually do not generate salts manually at all. Use password_hash():

php
<?php
$hash = password_hash("correct horse battery staple", PASSWORD_DEFAULT);
echo $hash;

This function handles:

  • Secure salt generation
  • Appropriate password hashing algorithms
  • Correct encoding and storage format

That is much safer than manually stitching together salts and hash functions.

It also means you do not need to decide how to store the salt separately. The password API handles the format for you, which removes an entire class of implementation mistakes.

If You Truly Need Random Bytes

If you need secure random bytes for a token or a non-password use case, use:

php
<?php
$token = bin2hex(random_bytes(16));
echo $token;

This gives you strong random data without relying on older APIs.

That is the modern replacement for older patterns built around OpenSSL-specific randomness functions.

Common Pitfalls

  • Thinking pack() creates randomness.
  • Using mt_rand() for salts or security tokens.
  • Generating salts manually when password_hash() already solves the password-storage problem.
  • Focusing on salt generation while ignoring the more important question of which password hashing API is being used.

Summary

  • 'pack() formats data; it does not generate secure random values.'
  • 'openssl_random_pseudo_bytes() was historically suitable for cryptographic randomness.'
  • 'mt_rand() is not appropriate for password salts.'
  • In modern PHP, prefer password_hash() for password storage and random_bytes() for secure random data.
  • The safest password-salting strategy today is usually not to manage salts manually at all.

Related reading
Course
Beginner
27 lessons
10 hours
System Design Fundamentals

Build a strong foundation in designing scalable, reliable distributed systems.

View the course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

System Design practice on Codemia

Work through 120+ system design problems with detailed solutions, from rate limiters to multi-region storage.

Practice system design