<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Usama Farooq</title>
    <description>The latest articles on DEV Community by Usama Farooq (@usamafarooq).</description>
    <link>https://dev.to/usamafarooq</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4203906%2Ff50e9ec7-a9a6-4d52-869c-64d9b46d0c99.png</url>
      <title>DEV Community: Usama Farooq</title>
      <link>https://dev.to/usamafarooq</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/usamafarooq"/>
    <language>en</language>
    <item>
      <title>10 Free Online Tools Every Developer Needs (That Run Entirely in Your Browser)</title>
      <dc:creator>Usama Farooq</dc:creator>
      <pubDate>Sun, 25 Oct 2026 04:56:51 +0000</pubDate>
      <link>https://dev.to/usamafarooq/10-free-online-tools-every-developer-needs-that-run-entirely-in-your-browser-49m4</link>
      <guid>https://dev.to/usamafarooq/10-free-online-tools-every-developer-needs-that-run-entirely-in-your-browser-49m4</guid>
      <description>&lt;h1&gt;
  
  
  10 Free Online Tools Every Developer Needs (That Run Entirely in Your Browser)
&lt;/h1&gt;

&lt;p&gt;Every developer has a folder of bookmarked utility sites: the JSON formatter, the JWT decoder, the UUID generator. The problem is that most of them are ad-covered, slow, or — worse — they send your data to a server before showing you the result.&lt;/p&gt;

&lt;p&gt;I run &lt;a href="https://www.toolsofweb.com" rel="noopener noreferrer"&gt;toolsofweb.com&lt;/a&gt;, a free tools site, and every tool there runs 100% in your browser. Nothing uploads, nothing needs an account. Here are the ten developer tools I reach for most, what each one actually does, and a real example of when you'd use it.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. JSON Formatter
&lt;/h2&gt;

&lt;p&gt;Paste minified JSON, get it readable. Sounds trivial until you're staring at a 4,000-character API response on one line.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.toolsofweb.com/tools/dev/json-formatter" rel="noopener noreferrer"&gt;JSON Formatter&lt;/a&gt; validates your JSON as you type and pretty-prints it with collapsible structure. Real example: a webhook from Stripe fails with a vague error, you paste the raw payload in, and the formatter shows the &lt;code&gt;error.message&lt;/code&gt; field three levels deep that the one-line version hid. It also catches the classic mistakes — trailing commas, single quotes, unquoted keys — and points at the exact line.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. JWT Decoder
&lt;/h2&gt;

&lt;p&gt;A JWT is just three base64url segments separated by dots: header, payload, signature. You don't need a library to read one — you need to see what's inside it.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.toolsofweb.com/tools/dev/jwt-decoder" rel="noopener noreferrer"&gt;JWT Decoder&lt;/a&gt; decodes the header and payload instantly and shows the expiry (&lt;code&gt;exp&lt;/code&gt;) as a human-readable date. Real example: your API returns 401 and you're not sure why. Paste the token in and you see &lt;code&gt;exp&lt;/code&gt; was yesterday — the token expired, your refresh logic never ran, and it's not a permissions problem at all. Because it runs locally, your token never leaves the tab, which matters when it contains a live session.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. UUID Generator
&lt;/h2&gt;

&lt;p&gt;Every database row, every idempotency key, every test fixture needs a unique ID. &lt;code&gt;uuidgen&lt;/code&gt; works on the command line, but you're usually already in the browser.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.toolsofweb.com/tools/dev/uuid-generator" rel="noopener noreferrer"&gt;UUID Generator&lt;/a&gt; produces v4 UUIDs in bulk, and there's a &lt;a href="https://www.toolsofweb.com/tools/dev/uuid-v7-generator" rel="noopener noreferrer"&gt;UUID v7 generator&lt;/a&gt; too. Real example: you're seeding a test database and need 50 unique user IDs. Generate them in one click, copy, paste into your seed script. v7 is worth knowing about: it's time-ordered, so rows sort roughly by creation time, which keeps your database indexes happier than random v4 values.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Base64 Converter
&lt;/h2&gt;

&lt;p&gt;Base64 shows up everywhere: data URIs in CSS, basic auth headers, binary data stuffed into JSON.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.toolsofweb.com/tools/dev/base64-converter" rel="noopener noreferrer"&gt;Base64 Converter&lt;/a&gt; encodes text to base64 and decodes it back, and handles files too. Real example: you need to embed a small SVG logo directly in your HTML. Convert it, paste the &lt;code&gt;data:image/svg+xml;base64,...&lt;/code&gt; string into an &lt;code&gt;&amp;lt;img&amp;gt;&lt;/code&gt; tag, and there's one fewer HTTP request. Going the other way, paste a suspicious base64 string from a log file and read the original text — often it's a JSON error message in disguise.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Cron Generator
&lt;/h2&gt;

&lt;p&gt;Cron syntax is a language nobody fully memorizes: is &lt;code&gt;0 9 * * 1&lt;/code&gt; Monday at 9, or the 1st of the month at 9? (It's Monday.)&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.toolsofweb.com/tools/dev/cron-generator" rel="noopener noreferrer"&gt;Cron Generator&lt;/a&gt; builds the expression from plain-English choices — "every weekday at 9am" — and shows you the next few run times so you can sanity-check it before it goes into production. Real example: you're scheduling a nightly backup and want it at 2:30am, not 2:30pm. The preview of upcoming runs catches the AM/PM mistake before your backup silently runs in the middle of the working day.&lt;/p&gt;

&lt;h2&gt;
  
  
  6. URL Encoder / Decoder
&lt;/h2&gt;

&lt;p&gt;URLs can't contain spaces, ampersands, or most punctuation — they have to be percent-encoded. And when you see &lt;code&gt;%20&lt;/code&gt; and &lt;code&gt;%3F&lt;/code&gt; in a log, you need the reverse.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.toolsofweb.com/tools/dev/url-encoder-decoder" rel="noopener noreferrer"&gt;URL Encoder/Decoder&lt;/a&gt; handles both directions. Real example: you're building a search URL with a query like &lt;code&gt;q=shoes &amp;amp; bags&lt;/code&gt; and your API keeps splitting it into two parameters. Encode it and the &lt;code&gt;&amp;amp;&lt;/code&gt; becomes &lt;code&gt;%26&lt;/code&gt;, so the whole query arrives as one value. Decoding is just as useful when a redirect URL in your logs is triple-encoded and you need to see the original destination.&lt;/p&gt;

&lt;h2&gt;
  
  
  7. Unix Timestamp Converter
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;1698225600&lt;/code&gt; means nothing to a human. &lt;code&gt;2026-10-25 10:00:00&lt;/code&gt; means everything.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.toolsofweb.com/tools/dev/unix-timestamp-converter" rel="noopener noreferrer"&gt;Unix Timestamp Converter&lt;/a&gt; converts timestamps both ways — epoch to date, date to epoch — and shows the current time ticking live. Real example: a user reports a bug "around 3pm", your log shows event time &lt;code&gt;1761387600&lt;/code&gt;, and the converter tells you that's 3:00pm exactly, so you know which log lines matter. It handles seconds and milliseconds, which saves you from the classic bug of treating a 13-digit millisecond timestamp as seconds and landing in the year 56,000.&lt;/p&gt;

&lt;h2&gt;
  
  
  8. YAML to JSON Converter
&lt;/h2&gt;

&lt;p&gt;YAML is what humans write; JSON is what APIs eat. Kubernetes manifests, GitHub Actions workflows, Docker Compose files — all YAML, all eventually needing to become JSON for a tool that only speaks JSON.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.toolsofweb.com/tools/dev/yaml-json-converter" rel="noopener noreferrer"&gt;YAML to JSON Converter&lt;/a&gt; converts in both directions. Real example: your CI config is YAML, but a validation script expects JSON. Convert, validate, convert back. It catches indentation errors too — the number one YAML failure — and tells you which line is wrong instead of failing silently.&lt;/p&gt;

&lt;h2&gt;
  
  
  9. JSON to CSV Converter
&lt;/h2&gt;

&lt;p&gt;APIs return JSON. Spreadsheets and data tools want CSV. Someone has to translate.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.toolsofweb.com/tools/dev/json-csv-converter" rel="noopener noreferrer"&gt;JSON to CSV Converter&lt;/a&gt; flattens JSON arrays into CSV with headers, handling nested objects by flattening their keys. Real example: you pull 200 rows of analytics from an API and your manager wants them in a spreadsheet. Paste the JSON, download the CSV, done — no throwaway Python script, no pandas install. It works the other way too when you have a CSV export and need JSON for an import.&lt;/p&gt;

&lt;h2&gt;
  
  
  10. Hash Generator — the one I built last week
&lt;/h2&gt;

&lt;p&gt;I covered this in detail in &lt;a href="https://dev.to/usamafarooq/how-i-built-a-free-hash-generator-that-runs-100-in-your-browser-297a"&gt;yesterday's post&lt;/a&gt;, but it belongs on this list: MD5, SHA-1, SHA-256, SHA-384, SHA-512, HMAC, and file checksums, all computed locally. Real example: you download a Linux ISO and the mirror publishes a SHA-256 checksum. Hash the file in your browser, compare, and you know the download wasn't corrupted or tampered with — without uploading a 3 GB file to anyone's server.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why "runs in your browser" is the whole point
&lt;/h2&gt;

&lt;p&gt;Every tool above shares one design rule: your data never leaves your machine. That matters more for developer tools than for most others, because what you paste into them is often sensitive — API tokens, database dumps, config files with secrets, JWTs carrying live sessions.&lt;/p&gt;

&lt;p&gt;A server-side tool has to receive your data to process it. A client-side tool doesn't. The browser already has everything needed: the WebCrypto API for hashing, &lt;code&gt;atob&lt;/code&gt;/&lt;code&gt;btoa&lt;/code&gt; for base64, &lt;code&gt;JSON.parse&lt;/code&gt; for formatting. There's no technical reason for these utilities to phone home, and every reason for them not to.&lt;/p&gt;

&lt;p&gt;All ten are free, no signup, no ads on the tool pages themselves. If there's a developer tool you're missing, the site has a &lt;a href="https://www.toolsofweb.com/request-tool" rel="noopener noreferrer"&gt;request-a-tool form&lt;/a&gt; — every request gets read.&lt;/p&gt;

&lt;p&gt;What utility do you reach for most? I'd genuinely like to know what to build next.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>javascript</category>
      <category>tools</category>
      <category>productivity</category>
    </item>
    <item>
      <title>How I Built a Free Hash Generator That Runs 100% in Your Browser</title>
      <dc:creator>Usama Farooq</dc:creator>
      <pubDate>Sat, 24 Oct 2026 05:06:10 +0000</pubDate>
      <link>https://dev.to/usamafarooq/how-i-built-a-free-hash-generator-that-runs-100-in-your-browser-297a</link>
      <guid>https://dev.to/usamafarooq/how-i-built-a-free-hash-generator-that-runs-100-in-your-browser-297a</guid>
      <description>&lt;h1&gt;
  
  
  How I Built a Free Hash Generator That Runs 100% in Your Browser
&lt;/h1&gt;

&lt;p&gt;Every week I add a free tool to &lt;a href="https://www.toolsofweb.com" rel="noopener noreferrer"&gt;toolsofweb.com&lt;/a&gt;, and the newest one is a &lt;a href="https://www.toolsofweb.com/tools/dev/hash-generator" rel="noopener noreferrer"&gt;hash generator&lt;/a&gt;. It computes MD5, SHA-1, SHA-256, SHA-384 and SHA-512 — plus HMAC for all of them — without a server, an account, or a single byte of your data leaving the tab.&lt;/p&gt;

&lt;p&gt;This isn't a launch post. It's a build log: the decisions I made, the crypto API quirks I hit, and the code that shipped.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why client-side matters for this one
&lt;/h2&gt;

&lt;p&gt;Most free hash tools online paste your input into a form, POST it to a server, and return the digest. For a hash generator, that's backwards: people hash things precisely because the data is sensitive — passwords before storing them, file checksums before trusting a download, API secrets when debugging HMAC signatures.&lt;/p&gt;

&lt;p&gt;The site's rule is simple: anything you hash stays on your machine. The whole tool is a React component plus one TypeScript module, and the only "backend" is &lt;code&gt;crypto.subtle&lt;/code&gt; — the WebCrypto API already living in your browser.&lt;/p&gt;

&lt;h2&gt;
  
  
  MD5: hand-rolled, RFC 1321, streaming
&lt;/h2&gt;

&lt;p&gt;Here's the surprise: browsers no longer ship MD5 in WebCrypto. &lt;code&gt;crypto.subtle.digest()&lt;/code&gt; supports SHA-1, SHA-256, SHA-384 and SHA-512, but MD5 was left behind because it's not collision-resistant anymore.&lt;/p&gt;

&lt;p&gt;Still, people need MD5 constantly — legacy database fields, Gravatar URLs, &lt;code&gt;htpasswd&lt;/code&gt; files (our &lt;a href="https://www.toolsofweb.com/tools/dev/htpasswd-generator" rel="noopener noreferrer"&gt;htpasswd generator&lt;/a&gt; uses it). So I wrote an incremental MD5 implementation straight from RFC 1321:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Md5&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mh"&gt;0x67452301&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Initial state, straight from the RFC&lt;/span&gt;
  &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mh"&gt;0xefcdab89&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;c&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mh"&gt;0x98badcfe&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;d&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mh"&gt;0x10325476&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;buf&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Uint8Array&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;64&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// one 512-bit block&lt;/span&gt;
  &lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The round constants are derived the way the spec demands — &lt;code&gt;floor(abs(sin(i+1)) * 2^32)&lt;/code&gt; — no magic-number tables copied from the internet. And because the class is incremental (&lt;code&gt;update()&lt;/code&gt; keeps 64 bytes of internal buffering and processes full blocks as they arrive), I can hash a 100 MB file in chunks without loading it all into memory. That matters on phones.&lt;/p&gt;

&lt;p&gt;One detail I was careful about: I verified my implementation byte-for-byte against the MD5 function already powering the site's htpasswd generator. Two implementations agreeing on every test vector means a bug would have to exist identically in both — unlikely. &lt;code&gt;md5("hello")&lt;/code&gt; gives the famous &lt;code&gt;5d41402abc4b2a76b9719d911017c592&lt;/code&gt;, as expected.&lt;/p&gt;

&lt;h2&gt;
  
  
  SHA family: let the browser do the heavy lifting
&lt;/h2&gt;

&lt;p&gt;For SHA-1 through SHA-512, there was no reason to hand-roll anything. WebCrypto's &lt;code&gt;digest()&lt;/code&gt; is implemented in the browser's native crypto layer — it's faster and better reviewed than anything I'd write:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;digest&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;crypto&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;subtle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;digest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;SHA-256&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;One gotcha worth knowing: &lt;code&gt;crypto.subtle.digest()&lt;/code&gt; is &lt;strong&gt;async&lt;/strong&gt; and takes an &lt;code&gt;ArrayBuffer&lt;/code&gt; (a bare &lt;code&gt;Uint8Array&lt;/code&gt; needs a cast). The tool computes all five digests in parallel with &lt;code&gt;Promise.all&lt;/code&gt; for text input, so the UI updates essentially instantly — no loading spinner for normal text.&lt;/p&gt;

&lt;h2&gt;
  
  
  HMAC: half native, half by hand
&lt;/h2&gt;

&lt;p&gt;The tool has an HMAC tab — you supply a key and a message, it signs it. For HMAC-SHA-*, WebCrypto has you covered:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;cryptoKey&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;crypto&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;subtle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;importKey&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;raw&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;keyBuffer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;HMAC&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;hash&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;SHA-256&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;sign&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;sig&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;crypto&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;subtle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sign&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;HMAC&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;cryptoKey&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But HMAC-MD5 needs the hand-rolled MD5 again, built exactly per RFC 2104:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;HMAC(K, m) = H((K' ⊕ opad) || H((K' ⊕ ipad) || m))
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;with &lt;code&gt;ipad = 0x36&lt;/code&gt; and &lt;code&gt;opad = 0x5c&lt;/code&gt; repeated over a 64-byte block-sized key (hash the key first if it's longer than 64 bytes). Nothing exotic, but getting the padding exactly right is the whole game with HMAC, so I tested it against Python's &lt;code&gt;hmac&lt;/code&gt; module output before shipping.&lt;/p&gt;

&lt;h2&gt;
  
  
  Four tabs, each answering one real question
&lt;/h2&gt;

&lt;p&gt;The UI is four tabs, one per question people actually ask:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Text&lt;/strong&gt; — "What are the hashes of this string?" All five digests compute live as you type.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;File checksum&lt;/strong&gt; — "Is this download intact?" Drop a file (up to 100 MB) and it gets hashed locally — &lt;code&gt;FileReader&lt;/code&gt; reads the bytes, WebCrypto/MD5 digests them, nothing uploads. Then paste the checksum the publisher listed and use…&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Compare&lt;/strong&gt; — "Does this match?" Paste the expected hash and your input; the tool auto-detects the algorithm from the hex length (32 chars → MD5, 40 → SHA-1, 64 → SHA-256, 96 → SHA-384, 128 → SHA-512) and reports match/mismatch.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;HMAC&lt;/strong&gt; — "What's the signature for this webhook payload?" Key + message → signature.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Real example: after downloading a Linux ISO, the mirror usually publishes a SHA-256 checksum. Open the File checksum tab, drop the ISO, compare against the published value. If it matches, the file wasn't corrupted or tampered with in transit. Doing this without uploading a 3 GB file to someone's server is the entire point of building it client-side.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I learned shipping this
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;WebCrypto is async everywhere.&lt;/strong&gt; Mixing it with a synchronous hand-rolled MD5 meant making the MD5 path synchronous and the SHA path async, then joining results with &lt;code&gt;Promise.all&lt;/code&gt;. Fine, but plan the API boundary early.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Verify against independent implementations.&lt;/strong&gt; My MD5 cross-checks against the htpasswd generator's MD5; my HMAC-MD5 cross-checks against Python's &lt;code&gt;hmac&lt;/code&gt; module. One self-consistent implementation can be self-consistently wrong.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Streaming isn't optional for files.&lt;/strong&gt; A naive implementation reads the whole file into memory. The incremental MD5 processes 64-byte blocks as they arrive; WebCrypto handles its own chunking internally. Keep the memory footprint flat.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;MD5 is still everywhere.&lt;/strong&gt; People reach for it for checksums, cache keys, deduplication — non-security uses where collision resistance doesn't matter. A "SHA-only" tool would have missed half the use cases.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Try it
&lt;/h2&gt;

&lt;p&gt;The tool is free, no signup, no ads: &lt;a href="https://www.toolsofweb.com/tools/dev/hash-generator" rel="noopener noreferrer"&gt;toolsofweb.com/hash-generator&lt;/a&gt;. Paste some text, drop a file, or check an HMAC — everything happens in your browser, and I never see any of it.&lt;/p&gt;

&lt;p&gt;If there's a hash-related feature you'd want (bcrypt/argon2 wrappers, keccak, bulk file hashing), the site has a &lt;a href="https://www.toolsofweb.com/request-tool" rel="noopener noreferrer"&gt;request-a-tool form&lt;/a&gt; — every request gets read.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>javascript</category>
      <category>cryptography</category>
      <category>opensource</category>
    </item>
  </channel>
</rss>
