JavaScript-MD5
A zero-dependency JavaScript MD5 and HMAC-MD5 hashing implementation that runs identically in Node.js, browsers, and AMD module loaders.
Repository Health
Technical Analysis
blueimp-md5 is a small, self-contained JavaScript implementation of the MD5 message-digest algorithm, based on the classic RSA Data Security reference algorithm and Paul Johnston’s original JS port. It exposes a single md5() function that computes hex or raw MD5 and HMAC-MD5 digests of a string, with correct handling of UTF-8 input via encodeURIComponent/unescape normalization before hashing.
The library ships as a UMD module, so the same js/md5.js file works unmodified whether it’s loaded via require() in Node.js, wired up through an AMD loader like RequireJS, bundled with webpack/Browserify, or dropped in as a plain <script> tag that exposes window.md5. It has zero runtime dependencies, making it a lightweight drop-in for checksum, cache-key, and identicon-style hashing needs where a full crypto library would be overkill.
What You Get
- A single exported
md5(string, key, raw)function covering four modes: hex MD5, hex HMAC-MD5, raw MD5, and raw HMAC-MD5 - Correct UTF-8 string handling before hashing, verified against Unicode test fixtures
- Zero runtime dependencies — the entire implementation is one small file
- Universal module support: Node.js
require, AMD/RequireJSdefine, or a globalmd5when loaded via<script> - A prebuilt minified build (
js/md5.min.jsplus source map) alongside the readable source
Common Use Cases
- Generating cache-busting or dedupe keys from arbitrary string content
- Computing Gravatar-style avatar hashes (MD5 of a lowercased, trimmed email address)
- Producing HMAC-MD5 signatures for legacy APIs that still require that scheme
- Client-side checksums to detect whether form or file content has changed
- Non-cryptographic fingerprinting where MD5’s speed and ubiquity matter more than collision resistance
Under The Hood
Architecture
The entire library lives in one file, js/md5.js, wrapped in a single UMD IIFE that fans out to module.exports, AMD define, or a global $.md5 depending on the host environment. Internally it’s a straight-line functional pipeline with no classes or shared mutable state: str2rstrUTF8 normalizes input encoding, rstr2binl/binl2rstr convert between raw strings and the little-endian word arrays the MD5 round functions (md5ff/md5gg/md5hh/md5ii, all routed through md5cmn) operate on, and binlMD5 runs the four 16-step rounds per RFC 1321 before rstr2hex renders the final hex digest. rstrHMACMD5 layers the HMAC construction (ipad/opad XOR plus a second MD5 pass) on top of the same primitives. Because every function is a pure transform with an unambiguous single responsibility, the only thing that would break from a core-abstraction change is the word-array encoding contract between rstr2binl and binlMD5 — everything else composes around it cleanly.
Tech Stack
The runtime has zero dependencies — package.json declares no dependencies block at all, only devDependencies for tooling: mocha 9 and chai 4 for tests, eslint 7 with eslint-config-blueimp, eslint-plugin-jsdoc, and eslint-config-prettier/eslint-plugin-prettier for linting/formatting, and uglify-js 3 to produce the shipped md5.min.js plus its source map via the build npm script. GitHub Actions (.github/workflows/test.yml) runs npm install, the build, and the test suite on Node 14 and 16 for every push and pull request. The published npm package (blueimp-md5) ships only js/*.js and js/*.js.map per the files field in package.json.
Code Quality
test/test.js uses Mocha and Chai to assert hex and raw output for both plain MD5 and HMAC-MD5, explicitly covering ASCII and multi-byte UTF-8 (Japanese) input against known digest values — the UTF-8 cases exist specifically to pin down the encoding-normalization step, which is the part most implementations get wrong. Every function in md5.js carries a JSDoc block documenting parameters and return types, enforced by eslint-plugin-jsdoc, and the whole codebase is Prettier-formatted with a project-specific style config (no semicolons, single quotes, always-wrap arrow parens). There’s no TypeScript and no static type checking beyond what JSDoc/ESLint catch, but the combination of a real test suite, CI on two Node versions, and consistent linting is solid for a library of this scope.
API Design
The public surface is exactly one function, md5(string, key, raw), with the last two parameters optional and used to select HMAC mode and raw-vs-hex output — there’s no configuration object, no class to instantiate, and no setup step beyond require/import. That minimalism is the whole point: a developer needs zero context to call md5('value') and get a hex digest back, and the same function handles the HMAC and raw-output variants without a second API to learn. The tradeoff is that boolean/positional flags (raw) are slightly less self-documenting than named options would be, but for a four-mode utility with a decade of stable behavior, the terse signature stays easy to hold in your head.
Used by 5 apps in this directory
evidence
Analytics · Data Engineering
Turn SQL queries and markdown files into polished, interactive data apps and business intelligence reports — no drag-and-drop, no GUI, just code.
GDevelop
Developer Tools · Game Development · Design Tools
No-code, open-source game engine for building 2D, 3D and multiplayer games — publish to iOS, Android, Steam and the web.
Navidrome
File Storage
Run your own personal Spotify — stream your entire music collection from any device, anywhere, forever.
Notifuse
Marketing
Open-source, self-hosted alternative to Mailchimp, Brevo, and Klaviyo — send newsletters and transactional emails without per-email pricing or vendor lock-in.
Zulip
Team Chat
Topic-based team chat that brings the structure of email threads to real-time messaging, so distributed teams never lose context across hundreds of concurrent conversations.