[{"data":1,"prerenderedAt":41},["ShallowReactive",2],{"$f9UJ7QMPpmRD5FLCC6ibjsX_I3i9xBhAwAIToQopFC2c":3},{"slug":4,"title":5,"description":6,"date":7,"tags":8,"tools":13,"draft":15,"html":16,"toc":17,"minutes":40},"md5-and-sha-hashes-in-the-browser","MD5 and SHA Hashes in the Browser, and Why I Wrote MD5 by Hand","Web Crypto has SHA but no MD5. How ToolOnTap's hash generator implements RFC 1321 itself, checks downloads against a checksum, and where MD5 still belongs.","2026-10-06",[9,10,11,12],"hashing","web crypto","algorithms","typescript",[14],"hash-generator",false,"\u003Cp>You download an installer or a Linux image, and the download page lists a long hex string next to it labelled “SHA-256”. Checking it means opening a terminal and remembering whether it’s \u003Ccode>shasum -a 256\u003C\u002Fcode> or \u003Ccode>certutil -hashfile\u003C\u002Fcode>. I wanted a page that does it in the browser, for MD5 and the SHA family at once. The browser already computes SHA hashes. MD5 it doesn’t, so ToolOnTap’s \u003Ca href=\"\u002Fhash-generator\">hash generator\u003C\u002Fa> carries its own MD5 implementation, about 45 lines of TypeScript.\u003C\u002Fp>\n\u003Ch2 id=\"what-a-hash-is-for\">What a hash is for\u003C\u002Fh2>\n\u003Cp>A hash function turns any amount of data into a short, fixed-size value. The same input always gives the same hash, and changing a single bit changes the result completely. That’s what makes it useful as a fingerprint: compare two 64-character strings instead of two 4 GB files.\u003C\u002Fp>\n\u003Cp>The five algorithms on the page differ mainly in length, which also helps you recognize a checksum you’ve been given:\u003C\u002Fp>\n\u003Cdiv class=\"table-wrap\">\u003Ctable>\u003Cthead>\n\u003Ctr>\n\u003Cth>Algorithm\u003C\u002Fth>\n\u003Cth>Bits\u003C\u002Fth>\n\u003Cth>Hex characters\u003C\u002Fth>\n\u003Cth>Still safe against deliberate forgery?\u003C\u002Fth>\n\u003C\u002Ftr>\n\u003C\u002Fthead>\n\u003Ctbody>\n\u003Ctr>\n\u003Ctd>MD5\u003C\u002Ftd>\n\u003Ctd>128\u003C\u002Ftd>\n\u003Ctd>32\u003C\u002Ftd>\n\u003Ctd>No, collisions have been practical since 2004\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>SHA-1\u003C\u002Ftd>\n\u003Ctd>160\u003C\u002Ftd>\n\u003Ctd>40\u003C\u002Ftd>\n\u003Ctd>No, a public collision was shown in 2017\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>SHA-256\u003C\u002Ftd>\n\u003Ctd>256\u003C\u002Ftd>\n\u003Ctd>64\u003C\u002Ftd>\n\u003Ctd>Yes\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>SHA-384\u003C\u002Ftd>\n\u003Ctd>384\u003C\u002Ftd>\n\u003Ctd>96\u003C\u002Ftd>\n\u003Ctd>Yes\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>SHA-512\u003C\u002Ftd>\n\u003Ctd>512\u003C\u002Ftd>\n\u003Ctd>128\u003C\u002Ftd>\n\u003Ctd>Yes\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003C\u002Ftbody>\n\u003C\u002Ftable>\u003C\u002Fdiv>\u003Ch2 id=\"sha-comes-free-with-web-crypto\">SHA comes free with Web Crypto\u003C\u002Fh2>\n\u003Cp>Browsers have a built-in hashing API, \u003Ccode>crypto.subtle.digest\u003C\u002Fcode>. The Web Crypto specification gives it four algorithms: SHA-1, SHA-256, SHA-384 and SHA-512. They run in the browser’s native code, so they’re fast, and they need no library at all. The page asks for all four in parallel and adds MD5 next to them:\u003C\u002Fp>\n\u003Cpre class=\"shiki shiki-themes github-light github-dark\" style=\"--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e\" tabindex=\"0\">\u003Ccode>\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#cb2431;--shiki-dark:#F97583\">export\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#cb2431;--shiki-dark:#F97583\"> async\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#cb2431;--shiki-dark:#F97583\"> function\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\"> hashAll\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">(\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#b35309;--shiki-dark:#FFAB70\">data\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#cb2431;--shiki-dark:#F97583\">:\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\"> Uint8Array\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">)\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#cb2431;--shiki-dark:#F97583\">:\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\"> Promise\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">&#x3C;\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\">Record\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">&#x3C;\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\">Algorithm\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">, \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">string\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">>> {\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#cb2431;--shiki-dark:#F97583\">  const\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\"> subtle\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#cb2431;--shiki-dark:#F97583\"> =\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> globalThis.crypto.subtle\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#cb2431;--shiki-dark:#F97583\">  const\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\"> sha\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#cb2431;--shiki-dark:#F97583\"> =\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#cb2431;--shiki-dark:#F97583\"> await\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\"> Promise\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">.\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\">all\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">(([\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#032F62;--shiki-dark:#9ECBFF\">'SHA-1'\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">, \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#032F62;--shiki-dark:#9ECBFF\">'SHA-256'\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">, \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#032F62;--shiki-dark:#9ECBFF\">'SHA-384'\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">, \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#032F62;--shiki-dark:#9ECBFF\">'SHA-512'\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">] \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#cb2431;--shiki-dark:#F97583\">as\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#cb2431;--shiki-dark:#F97583\"> const\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">).\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\">map\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">(\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#cb2431;--shiki-dark:#F97583\">async\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#b35309;--shiki-dark:#FFAB70\"> a\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#cb2431;--shiki-dark:#F97583\"> =>\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> [a, \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\">toHex\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">(\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#cb2431;--shiki-dark:#F97583\">new\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\"> Uint8Array\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">(\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#cb2431;--shiki-dark:#F97583\">await\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> subtle.\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\">digest\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">(a, data \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#cb2431;--shiki-dark:#F97583\">as\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\"> BufferSource\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">)))] \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#cb2431;--shiki-dark:#F97583\">as\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#cb2431;--shiki-dark:#F97583\"> const\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">))\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#cb2431;--shiki-dark:#F97583\">  return\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> { MD5: \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\">toHex\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">(\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\">md5\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">(data)), \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#cb2431;--shiki-dark:#F97583\">...\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">Object.\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\">fromEntries\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">(sha) } \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#cb2431;--shiki-dark:#F97583\">as\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\"> Record\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">&#x3C;\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\">Algorithm\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">, \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">string\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">>\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">}\u003C\u002Fspan>\u003C\u002Fspan>\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>Two browser rules shape the rest of the tool:\u003C\u002Fp>\n\u003Cul>\n\u003Cli>\u003Cstrong>\u003Ccode>crypto.subtle\u003C\u002Fcode> only exists on secure pages\u003C\u002Fstrong>, HTTPS or localhost. That’s fine for a public site, and worth knowing if you copy this code into a page you serve over plain HTTP on a local network.\u003C\u002Fli>\n\u003Cli>\u003Cstrong>\u003Ccode>digest\u003C\u002Fcode> takes the whole input at once.\u003C\u002Fstrong> There’s no streaming version, so a file is read fully into memory before it’s hashed. That’s why the page caps files at 512 MB and suggests your system’s own tools (\u003Ccode>shasum\u003C\u002Fcode>, \u003Ccode>certutil\u003C\u002Fcode>) for bigger disk images.\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Ch2 id=\"why-md5-is-missing-and-writing-it-anyway\">Why MD5 is missing, and writing it anyway\u003C\u002Fh2>\n\u003Cp>The Web Crypto specification doesn’t include MD5 at all, which makes sense for an API meant for security work. But MD5 is far from gone. Plenty of download pages, package mirrors and storage systems still publish MD5 checksums, so leaving it out would leave the tool unable to check them.\u003C\u002Fp>\n\u003Cp>MD5 is defined in RFC 1321, and it’s short enough to write from the description. It works on 64-byte blocks. Each block is read as sixteen 32-bit words in little-endian order and mixed into four 32-bit state values over 64 steps, in four rounds of 16 that each use a different bit function. Each step adds one constant from a table of 64. The RFC prints the table, but it also says where the numbers come from, so the code computes them instead of copying 64 hex values:\u003C\u002Fp>\n\u003Cpre class=\"shiki shiki-themes github-light github-dark\" style=\"--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e\" tabindex=\"0\">\u003Ccode>\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#cb2431;--shiki-dark:#F97583\">const\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\"> K\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#cb2431;--shiki-dark:#F97583\"> =\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> Array.\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\">from\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">({ length: \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">64\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> }, (\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#b35309;--shiki-dark:#FFAB70\">_\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">, \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#b35309;--shiki-dark:#FFAB70\">i\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">) \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#cb2431;--shiki-dark:#F97583\">=>\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> Math.\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\">floor\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">(Math.\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\">abs\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">(Math.\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\">sin\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">(i \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#cb2431;--shiki-dark:#F97583\">+\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\"> 1\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">)) \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#cb2431;--shiki-dark:#F97583\">*\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\"> 2\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#cb2431;--shiki-dark:#F97583\"> **\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\"> 32\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">) \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#cb2431;--shiki-dark:#F97583\">>>>\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\"> 0\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">)\u003C\u002Fspan>\u003C\u002Fspan>\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>Each constant is the integer part of |sin(i)| × 2³² for i from 1 to 64. A JavaScript number carries 53 bits of precision and only the top 32 are needed, so the computed values match the RFC’s table, and the tests would fail on any single wrong constant.\u003C\u002Fp>\n\u003Cp>JavaScript has no 32-bit unsigned integers, so the code ends every addition with \u003Ccode>&gt;&gt;&gt; 0\u003C\u002Fcode> to wrap it back into the range 0 to 2³² − 1, and the rotations are written with \u003Ccode>&lt;&lt;\u003C\u002Fcode> and \u003Ccode>&gt;&gt;&gt;\u003C\u002Fcode>.\u003C\u002Fp>\n\u003Cp>The fiddly part is the end. After the last full block, MD5 appends one \u003Ccode>0x80\u003C\u002Fcode> byte, pads with zeros, and finishes with the input’s length in bits as a 64-bit little-endian number. If the leftover bytes plus that marker and length don’t fit in one 64-byte block, padding takes two blocks. The code builds that tail separately, which also means it never copies the whole input: a 500 MB file is processed where it is, block by block.\u003C\u002Fp>\n\u003Ch2 id=\"how-i-know-it-s-right\">How I know it’s right\u003C\u002Fh2>\n\u003Cp>A hash function that’s wrong by one bit still produces a convincing hex string, so the tests had to be strict:\u003C\u002Fp>\n\u003Cul>\n\u003Cli>\u003Cstrong>The RFC 1321 test suite\u003C\u002Fstrong>: the seven inputs printed at the end of the RFC, from the empty string (\u003Ccode>d41d8cd98f00b204e9800998ecf8427e\u003C\u002Fcode>) to eighty digits.\u003C\u002Fli>\n\u003Cli>\u003Cstrong>Every length from 0 to 130 bytes\u003C\u002Fstrong>, compared with Node’s own MD5. This crosses the 56-byte and 64-byte boundaries where padding switches from one block to two, which is where hand-written MD5 usually breaks.\u003C\u002Fli>\n\u003Cli>\u003Cstrong>3,000,001 bytes\u003C\u002Fstrong>, to cover large input.\u003C\u002Fli>\n\u003Cli>\u003Cstrong>UTF-8 text\u003C\u002Fstrong> with accents, a coffee emoji and Arabic, through all five algorithms, compared with Node.\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Ch2 id=\"checking-a-download-against-its-checksum\">Checking a download against its checksum\u003C\u002Fh2>\n\u003Cp>The “Compare with an expected hash” box is the part I use most. You paste the checksum from the download page, and the tool compares it with all five results:\u003C\u002Fp>\n\u003Cpre class=\"shiki shiki-themes github-light github-dark\" style=\"--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e\" tabindex=\"0\">\u003Ccode>\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#cb2431;--shiki-dark:#F97583\">export\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#cb2431;--shiki-dark:#F97583\"> function\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\"> findMatch\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">(\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#b35309;--shiki-dark:#FFAB70\">hashes\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#cb2431;--shiki-dark:#F97583\">:\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\"> Record\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">&#x3C;\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\">Algorithm\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">, \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">string\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">>, \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#b35309;--shiki-dark:#FFAB70\">expected\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#cb2431;--shiki-dark:#F97583\">:\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\"> string\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">)\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#cb2431;--shiki-dark:#F97583\">:\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\"> Algorithm\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#cb2431;--shiki-dark:#F97583\"> |\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\"> null\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> {\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#cb2431;--shiki-dark:#F97583\">  const\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\"> want\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#cb2431;--shiki-dark:#F97583\"> =\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> expected.\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\">trim\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">().\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\">replace\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">(\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#032F62;--shiki-dark:#9ECBFF\">\u002F\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">\\s\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#cb2431;--shiki-dark:#F97583\">+\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#032F62;--shiki-dark:#9ECBFF\">\u002F\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#cb2431;--shiki-dark:#F97583\">g\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">, \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#032F62;--shiki-dark:#9ECBFF\">''\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">).\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\">toLowerCase\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">()\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#cb2431;--shiki-dark:#F97583\">  return\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\"> ALGORITHMS\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">.\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\">find\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">(\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#b35309;--shiki-dark:#FFAB70\">a\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#cb2431;--shiki-dark:#F97583\"> =>\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> hashes[a] \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#cb2431;--shiki-dark:#F97583\">===\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> want) \u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#cb2431;--shiki-dark:#F97583\">??\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\"> null\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">}\u003C\u002Fspan>\u003C\u002Fspan>\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>Removing whitespace and ignoring case means output copied from PowerShell’s \u003Ccode>Get-FileHash\u003C\u002Fcode> (uppercase) or from \u003Ccode>certutil\u003C\u002Fcode> (spaced on some Windows versions) matches without editing. And because it checks every algorithm, you don’t need to know which one the site used. If nothing matches, the file differs or the checksum is for a different file.\u003C\u002Fp>\n\u003Cp>A checksum is only as trustworthy as the place you got it. It reliably catches a cut-off download or a corrupted copy. Against someone who replaced the file on purpose, it only helps if the checksum came from a source they couldn’t change, such as the project’s official HTTPS site, and only with SHA-256 or stronger.\u003C\u002Fp>\n\u003Cp>For text, the tool hashes the exact UTF-8 bytes you typed, 120 ms after you stop typing. A trailing space or Windows line endings (CR LF instead of LF) give a different hash, which is the usual reason a hash of “the same text” doesn’t match.\u003C\u002Fp>\n\u003Ch2 id=\"what-hashes-aren-t-for\">What hashes aren’t for\u003C\u002Fh2>\n\u003Cp>Two things I’d tell anyone using this page at work:\u003C\u002Fp>\n\u003Cul>\n\u003Cli>\u003Cstrong>Don’t store passwords as MD5 or SHA hashes\u003C\u002Fstrong>, even SHA-512. These functions are designed to be fast, which helps an attacker try billions of guesses. Use a password hashing function built to be slow, such as Argon2, bcrypt or scrypt.\u003C\u002Fli>\n\u003Cli>\u003Cstrong>Don’t use MD5 or SHA-1 where someone might forge a match\u003C\u002Fstrong>, such as signatures or deduplication of files from untrusted users. For accidental damage, both still work fine.\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Ch2 id=\"try-it\">Try it\u003C\u002Fh2>\n\u003Cp>Open the \u003Ca href=\"\u002Fhash-generator\">hash generator\u003C\u002Fa>, choose “Text” or “File”, and all five hashes appear together. Paste a published checksum into the compare box to see which one matches. Other tools for developers are on the \u003Ca href=\"\u002Fdev-tools\">developer tools\u003C\u002Fa> page.\u003C\u002Fp>\n",[18,22,25,28,31,34,37],{"id":19,"text":20,"level":21},"what-a-hash-is-for","What a hash is for",2,{"id":23,"text":24,"level":21},"sha-comes-free-with-web-crypto","SHA comes free with Web Crypto",{"id":26,"text":27,"level":21},"why-md5-is-missing-and-writing-it-anyway","Why MD5 is missing, and writing it anyway",{"id":29,"text":30,"level":21},"how-i-know-it-s-right","How I know it’s right",{"id":32,"text":33,"level":21},"checking-a-download-against-its-checksum","Checking a download against its checksum",{"id":35,"text":36,"level":21},"what-hashes-aren-t-for","What hashes aren’t for",{"id":38,"text":39,"level":21},"try-it","Try it",5,1792325801077]