crypto-js, hash.js, sha.js, and sha1 are JavaScript libraries used to generate cryptographic hashes (like SHA-256, MD5, SHA-1) directly in the browser or Node.js environments. While the native Web Crypto API is now the standard for modern browsers, these libraries remain critical for legacy support, specific encoding needs, or environments where native APIs are unavailable. crypto-js is a comprehensive toolkit offering a wide range of algorithms and encoders. hash.js is a minimal, dependency-free implementation focused purely on hashing. sha.js provides a streaming interface compatible with Node.js core modules, ideal for large data processing. sha1 is a legacy, single-algorithm package that is no longer recommended for new development due to security vulnerabilities in the SHA-1 algorithm itself.
When building secure frontend applications, you often need to generate hashes for data integrity, password handling (with salt), or digital signatures. While modern browsers offer the native Web Crypto API, real-world architectures sometimes demand fallbacks for older browsers, specific encoding formats, or Node.js stream compatibility. The packages crypto-js, hash.js, sha.js, and sha1 address these needs differently. Let's break down their architectural fit.
The way you interact with these libraries defines how they fit into your data flow.
crypto-js uses a high-level, chainable API that handles encoding automatically. It is designed for ease of use with strings and WordArrays.
// crypto-js: High-level chainable API
import CryptoJS from 'crypto-js';
const message = 'Sensitive Data';
// Automatically handles UTF8 encoding and hex output
const hash = CryptoJS.SHA256(message).toString(CryptoJS.enc.Hex);
console.log(hash); // "8d969eef..."
hash.js offers a minimal, class-based API. You instantiate the hash object, update it, and digest it. It returns arrays or hex strings but requires manual handling if you need complex encodings.
// hash.js: Minimal class-based API
import hash from 'hash.js';
const sha256 = hash.sha256();
sha256.update('Sensitive Data');
const hashHex = sha256.digest('hex');
console.log(hashHex); // "8d969eef..."
sha.js mimics the Node.js native crypto module using a streaming interface (.update() and .digest()). This is critical for processing data chunks without loading everything into memory.
// sha.js: Streaming interface (Node-style)
import SHA256 from 'sha.js/sha256';
const hasher = new SHA256();
hasher.update('Sensitive ');
hasher.update('Data'); // Can accept Buffer or string
const hashBuffer = hasher.digest(); // Returns Buffer
console.log(hashBuffer.toString('hex')); // "8d969eef..."
sha1 provides a simple function-based API but is limited to the SHA-1 algorithm only. It lacks the flexibility of streams or advanced encoding options found in the others.
// sha1: Simple function call (Legacy)
import sha1 from 'sha1';
const hash = sha1('Sensitive Data');
console.log(hash); // "f4a6c..." (SHA-1 output)
In frontend architecture, every kilobyte counts. The choice here often depends on whether you need a Swiss Army knife or a scalpel.
crypto-js is the heaviest. It includes many algorithms (MD5, SHA-1, SHA-256, SHA-3, RIPEMD160, HMAC) and encoders. If you only need SHA-256, you are bundling unused code unless you use specific sub-imports (which can be tricky with its module structure).hash.js is extremely lightweight. It has no dependencies and focuses strictly on hashing. It is perfect for micro-frontends or widgets where bundle size is critical.sha.js is modular. You import only the algorithm you need (e.g., require('sha.js/sha256')). However, it often pulls in Buffer shims in browser environments if not configured correctly, which can bloat the bundle.sha1 is small but obsolete. Its size is irrelevant compared to the security risk it introduces.This is the most critical architectural differentiator. If you hash a 500MB video file in the browser, loading it all into a string will crash the tab.
crypto-js generally expects data to be available in memory. While it supports WordArrays, it does not offer a true streaming interface for incremental updates from a file reader loop in a simple way.
// crypto-js: Best for small, in-memory data
import CryptoJS from 'crypto-js';
// Not ideal for large files: must load 'fileContent' entirely first
const hash = CryptoJS.SHA256(fileContent);
hash.js allows incremental updates, making it suitable for looping through file chunks, but you must manage the loop yourself.
// hash.js: Incremental updates possible
import hash from 'hash.js';
const sha256 = hash.sha256();
// Simulating a file reader loop
for (const chunk of largeFileChunks) {
sha256.update(chunk);
}
const result = sha256.digest('hex');
sha.js shines here. Its API is explicitly designed for streams, making it the natural choice for Node.js backends or browser code using the Streams API.
// sha.js: Native stream support
import SHA256 from 'sha.js/sha256';
import { Readable } from 'stream'; // Node example
const hasher = new SHA256();
const stream = Readable.from(largeFileIterator);
stream.on('data', (chunk) => hasher.update(chunk));
stream.on('end', () => {
const finalHash = hasher.digest('hex');
});
Security is not just about the algorithm; it is about the library's maintenance and the algorithm's viability.
sha1: DO NOT USE. The SHA-1 algorithm is cryptographically broken. Collisions have been demonstrated in the wild. Using this for security signatures or passwords is a critical vulnerability. This package is effectively deprecated by the security community.crypto-js: Actively maintained and widely audited due to its popularity. It supports modern algorithms like SHA-3 and PBKDF2. However, ensure you are not using its MD5 or SHA-1 exports for security purposes.hash.js: Stable and minimal. Because it does less, there is less surface area for bugs. It is a safe choice for SHA-256 and SHA-512.sha.js: Highly respected in the Node.js ecosystem. It is used as a dependency by many major security libraries. It is reliable for streaming implementations of secure algorithms.You need to hash a password with PBKDF2 before sending it to the server, but you must support IE11.
crypto-jsimport CryptoJS from 'crypto-js';
const salt = CryptoJS.lib.WordArray.random(128/8);
const key = CryptoJS.PBKDF2(password, salt, { keySize: 8, iterations: 1000 });
You are embedding a script in a third-party site to verify a downloaded file's checksum. Bundle size is strictly limited.
hash.jsimport hash from 'hash.js';
function verifyFile(data, expectedHash) {
const actual = hash.sha256().update(data).digest('hex');
return actual === expectedHash;
}
Your Node.js server receives large file uploads and needs to compute the hash on the fly without buffering the whole file.
sha.jsimport SHA256 from 'sha.js/sha256';
// Inside an Express upload handler
const hasher = new SHA256();
req.pipe(hasher).on('finish', () => {
console.log('Hash:', hasher.digest('hex'));
});
You need to generate a checksum for a cache key where collision resistance is not a security concern, just a uniqueness check.
sha1 package. Use crypto-js or hash.js with SHA-1 if absolutely forced by legacy protocol, but prefer SHA-256.// Better than importing 'sha1' package
import CryptoJS from 'crypto-js';
// Using SHA-1 from a maintained library if legacy protocol demands it
const cacheKey = CryptoJS.SHA1(data).toString();
| Feature | crypto-js | hash.js | sha.js | sha1 |
|---|---|---|---|---|
| Primary Use | All-in-one crypto toolkit | Lightweight hashing | Streaming hashes | Legacy SHA-1 only |
| API Style | Chainable, High-level | Class-based, Minimal | Stream (Node-style) | Function call |
| Streaming | ❌ (Mostly in-memory) | ✅ (Manual loops) | ✅ (Native streams) | ❌ |
| Algorithms | Many (SHA-3, MD5, etc.) | Standard (SHA-1/2/3) | Modular (SHA-1/2/3) | SHA-1 Only |
| Security | ✅ (If using modern algos) | ✅ | ✅ | ❌ (Broken Algo) |
| Bundle Size | Large | Tiny | Medium (Modular) | Small |
For most modern frontend architectures, the native Web Crypto API (window.crypto.subtle) should be your first choice. It is faster, more secure, and requires no dependencies.
However, when you must choose a library:
sha1 entirely. The algorithm is broken, and the package offers no advantage over using SHA-1 from a maintained library if you are forced into a corner by legacy requirements.crypto-js if you need a "batteries included" solution for legacy browsers, need PBKDF2, or require easy encoding conversions (Hex/Base64) without extra setup.hash.js if you are building a lightweight component, a browser extension, or a widget where bundle size is the top priority and you only need standard hashing.sha.js if you are working in Node.js or need to hash large files via streams in the browser. Its API compatibility with Node's core crypto module makes it the professional choice for backend-heavy JavaScript stacks.Architectural Rule of Thumb: If you are starting a new project today, wrap the native Web Crypto API in a helper. Only reach for these libraries when the native API cannot meet your specific compatibility or streaming needs.
Choose crypto-js if you need a broad set of algorithms (MD5, SHA-3, RIPEMD160) and extensive encoding support (Base64, Hex, Latin1) without managing multiple dependencies. It is best suited for applications requiring quick implementation of various crypto primitives in a unified API, though it lacks streaming capabilities for large files.
Choose hash.js if your priority is a tiny footprint and zero dependencies for pure hashing tasks. It is ideal for embedded systems, lightweight frontend bundles, or scenarios where you only need standard hash functions (SHA-256, SHA-512) and want to avoid the overhead of a larger crypto toolkit.
Choose sha.js if you are processing large files or streams in Node.js or need an API that mimics Node's native crypto module (using .update() and .digest()). It is the architectural choice for backend-heavy JavaScript environments or when streaming data prevents loading entire payloads into memory.
Do NOT choose sha1 for any new project. This package implements the SHA-1 algorithm, which is cryptographically broken and deprecated for security-sensitive use cases. Only consider this if you are maintaining legacy code that strictly requires SHA-1 for non-security checksums, and even then, migrate to crypto-js or hash.js immediately.
JavaScript library of crypto standards.
Active development of CryptoJS has been discontinued. This library is no longer maintained.
Nowadays, NodeJS and modern browsers have a native Crypto module. The latest version of CryptoJS already uses the native Crypto module for random number generation, since Math.random() is not crypto-safe. Further development of CryptoJS would result in it only being a wrapper of native Crypto. Therefore, development and maintenance has been discontinued, it is time to go for the native crypto module.
Requirements:
npm install crypto-js
ES6 import for typical API call signing use case:
import sha256 from 'crypto-js/sha256';
import hmacSHA512 from 'crypto-js/hmac-sha512';
import Base64 from 'crypto-js/enc-base64';
const message, nonce, path, privateKey; // ...
const hashDigest = sha256(nonce + message);
const hmacDigest = Base64.stringify(hmacSHA512(path + hashDigest, privateKey));
Modular include:
var AES = require("crypto-js/aes");
var SHA256 = require("crypto-js/sha256");
...
console.log(SHA256("Message"));
Including all libraries, for access to extra methods:
var CryptoJS = require("crypto-js");
console.log(CryptoJS.HmacSHA1("Message", "Key"));
Requirements:
bower install crypto-js
Modular include:
require.config({
packages: [
{
name: 'crypto-js',
location: 'path-to/bower_components/crypto-js',
main: 'index'
}
]
});
require(["crypto-js/aes", "crypto-js/sha256"], function (AES, SHA256) {
console.log(SHA256("Message"));
});
Including all libraries, for access to extra methods:
// Above-mentioned will work or use this simple form
require.config({
paths: {
'crypto-js': 'path-to/bower_components/crypto-js/crypto-js'
}
});
require(["crypto-js"], function (CryptoJS) {
console.log(CryptoJS.HmacSHA1("Message", "Key"));
});
<script type="text/javascript" src="path-to/bower_components/crypto-js/crypto-js.js"></script>
<script type="text/javascript">
var encrypted = CryptoJS.AES(...);
var encrypted = CryptoJS.SHA256(...);
</script>
See: https://cryptojs.gitbook.io/docs/
var CryptoJS = require("crypto-js");
// Encrypt
var ciphertext = CryptoJS.AES.encrypt('my message', 'secret key 123').toString();
// Decrypt
var bytes = CryptoJS.AES.decrypt(ciphertext, 'secret key 123');
var originalText = bytes.toString(CryptoJS.enc.Utf8);
console.log(originalText); // 'my message'
var CryptoJS = require("crypto-js");
var data = [{id: 1}, {id: 2}]
// Encrypt
var ciphertext = CryptoJS.AES.encrypt(JSON.stringify(data), 'secret key 123').toString();
// Decrypt
var bytes = CryptoJS.AES.decrypt(ciphertext, 'secret key 123');
var decryptedData = JSON.parse(bytes.toString(CryptoJS.enc.Utf8));
console.log(decryptedData); // [{id: 1}, {id: 2}]
crypto-js/corecrypto-js/x64-corecrypto-js/lib-typedarrayscrypto-js/md5crypto-js/sha1crypto-js/sha256crypto-js/sha224crypto-js/sha512crypto-js/sha384crypto-js/sha3crypto-js/ripemd160crypto-js/hmac-md5crypto-js/hmac-sha1crypto-js/hmac-sha256crypto-js/hmac-sha224crypto-js/hmac-sha512crypto-js/hmac-sha384crypto-js/hmac-sha3crypto-js/hmac-ripemd160crypto-js/pbkdf2crypto-js/aescrypto-js/tripledescrypto-js/rc4crypto-js/rabbitcrypto-js/rabbit-legacycrypto-js/evpkdfcrypto-js/format-opensslcrypto-js/format-hexcrypto-js/enc-latin1crypto-js/enc-utf8crypto-js/enc-hexcrypto-js/enc-utf16crypto-js/enc-base64crypto-js/mode-cfbcrypto-js/mode-ctrcrypto-js/mode-ctr-gladmancrypto-js/mode-ofbcrypto-js/mode-ecbcrypto-js/pad-pkcs7crypto-js/pad-ansix923crypto-js/pad-iso10126crypto-js/pad-iso97971crypto-js/pad-zeropaddingcrypto-js/pad-nopaddingChange default hash algorithm and iteration's for PBKDF2 to prevent weak security by using the default configuration.
Custom KDF Hasher
Blowfish support
Fix module order in bundled release.
Include the browser field in the released package.json.
Added url safe variant of base64 encoding. 357
Avoid webpack to add crypto-browser package. 364
This is an update including breaking changes for some environments.
In this version Math.random() has been replaced by the random methods of the native crypto module.
For this reason CryptoJS might not run in some JavaScript environments without native crypto module. Such as IE 10 or before or React Native.
Rollback, 3.3.0 is the same as 3.1.9-1.
The move of using native secure crypto module will be shifted to a new 4.x.x version. As it is a breaking change the impact is too big for a minor release.
The usage of the native crypto module has been fixed. The import and access of the native crypto module has been improved.
In this version Math.random() has been replaced by the random methods of the native crypto module.
For this reason CryptoJS might does not run in some JavaScript environments without native crypto module. Such as IE 10 or before.
If it's absolute required to run CryptoJS in such an environment, stay with 3.1.x version. Encrypting and decrypting stays compatible. But keep in mind 3.1.x versions still use Math.random() which is cryptographically not secure, as it's not random enough.
This version came along with CRITICAL BUG.
DO NOT USE THIS VERSION! Please, go for a newer version!
The 3.1.x are based on the original CryptoJS, wrapped in CommonJS modules.