{"id":641,"date":"2026-03-09T05:39:55","date_gmt":"2026-03-09T05:39:55","guid":{"rendered":"https:\/\/primetoolhub.com\/?page_id=641"},"modified":"2026-11-10T12:56:03","modified_gmt":"2026-11-10T12:56:03","slug":"free-secure-hash-generator","status":"publish","type":"page","link":"https:\/\/schoolict.net\/tools\/free-secure-hash-generator\/","title":{"rendered":"Free Secure Hash Generator &amp; File Checksum (SHA-256, MD5)"},"content":{"rendered":"\n<div class=\"pth-hero-section\">\n    <div class=\"pth-hero-content\">\n        <h2>Free Secure Hash Generator &amp; File Checksum (SHA-256, MD5)<\/h2>\n        <p>Instantly generate MD5, SHA-1, SHA-256, and SHA-512 hashes from text or verify file checksums completely offline securely in your browser.<\/p>\n\n        <div id=\"pth-toc-placeholder\"><\/div>\n    <\/div>\n\n   <div class=\"pth-hero-image\">\n\t<img data-no-lazy=\"1\"\n         src=\"https:\/\/schoolict.net\/tools\/wp-content\/uploads\/2026\/03\/Free-Secure-Hash-Generator-800x447.jpeg\"\n         width=\"800\"\n         height=\"447\"\n         alt=\"Free Secure Hash Generator &#038; File Checksum\"\n         fetchpriority=\"high\"\n         loading=\"eager\"\n         decoding=\"async\"\n         style=\"width:100%; height:auto; display:block;\">\n  <\/div>\n<\/div>\n\n\n\n\n<div class=\"wp-block-rank-math-toc-block\" id=\"rank-math-toc\"><h2>Table of Contents<\/h2><nav><ul><li><a href=\"#\ud83d\udd34-what-this-tool-actually-does-that-others-dont\">\ud83d\udd34 What This Tool Actually Does That Others Don&#8217;t<\/a><ul><li><a href=\"#real-input-\u2192-real-output-examples\">Real Input \u2192 Real Output Examples<\/a><\/li><li><a href=\"#\ud83d\udfe1-the-hmac-tab-when-a-hash-alone-is-not-enough\">\ud83d\udfe1 The HMAC Tab \u2014 When a Hash Alone Is Not Enough<\/a><\/li><li><a href=\"#\ud83d\udfe2-file-checksum-why-this-matters-more-than-you-think\">\ud83d\udfe2 File Checksum \u2014 Why This Matters More Than You Think<\/a><\/li><li><a href=\"#\ud83d\udd34-the-encoder-tab-rot-13-and-morse-are-not-cryptography\">\ud83d\udd34 The Encoder Tab \u2014 ROT13 and Morse Are Not Cryptography<\/a><\/li><\/ul><\/li><\/ul><\/nav><\/div>\n\n\n<!-- LSCACHE_DISABLE -->\r\n<style>\r\n\/* PTH Secure Hash Studio v4.0 \u2014 WCAG 2.1 AA *\/\r\n#pth-hs{font-family:'Inter',system-ui,sans-serif;max-width:1100px;margin:0 auto;background:#f8fafc;border-radius:16px;overflow:hidden;border:1px solid #e2e8f0}\r\n#pth-hs *{box-sizing:border-box;min-width:0}\r\n\/* Top bar *\/\r\n#pth-hs .hs-top{background:#1e293b;padding:18px 24px;text-align:center}\r\n#pth-hs .hs-title{font-size:1.4rem;font-weight:900;color:#f1f5f9;margin:0 0 4px}\r\n#pth-hs .hs-sub{font-size:.82rem;color:#94a3b8;margin:0}\r\n#pth-hs .hs-badges{display:flex;justify-content:center;gap:8px;flex-wrap:wrap;margin-top:10px}\r\n#pth-hs .hs-badge{font-size:.65rem;font-weight:800;padding:3px 9px;border-radius:999px;background:rgba(255,255,255,.08);color:#cbd5e1;border:1px solid rgba(255,255,255,.12)}\r\n\/* Tabs *\/\r\n#pth-hs .hs-tabs{display:flex;background:#0f172a;flex-wrap:wrap;gap:2px;padding:6px 8px}\r\n#pth-hs .hs-tab{flex:1;padding:8px 4px;font-size:.72rem;font-weight:800;color:#64748b;background:transparent;border:none;cursor:pointer;border-radius:6px;font-family:inherit;transition:.15s;white-space:nowrap;min-width:80px}\r\n#pth-hs .hs-tab.on{background:#1e40af;color:#fff}\r\n#pth-hs .hs-tab:hover:not(.on){background:rgba(255,255,255,.06);color:#e2e8f0}\r\n\/* Panel *\/\r\n#pth-hs .hs-body{padding:20px 22px}\r\n#pth-hs .hs-panel{display:none}\r\n#pth-hs .hs-panel.on{display:block}\r\n\/* Labels + inputs *\/\r\n#pth-hs .hs-label{font-size:.72rem;font-weight:800;color:#334155;text-transform:uppercase;letter-spacing:.4px;display:block;margin-bottom:5px}\r\n#pth-hs .hs-input,#pth-hs .hs-textarea{width:100%;padding:10px 13px;border:1.5px solid #e2e8f0;border-radius:8px;font-size:.85rem;font-family:'Courier New',monospace;outline:none;background:#fff;color:#0f172a;transition:.2s}\r\n#pth-hs .hs-input:focus,#pth-hs .hs-textarea:focus{border-color:#3b82f6;box-shadow:0 0 0 3px rgba(59,130,246,.12)}\r\n#pth-hs .hs-textarea{resize:vertical;min-height:90px;line-height:1.6}\r\n\/* Buttons *\/\r\n#pth-hs .hs-btn{padding:8px 16px;border-radius:7px;font-weight:800;font-size:.78rem;cursor:pointer;border:none;font-family:inherit;transition:.15s;display:inline-flex;align-items:center;gap:5px}\r\n#pth-hs .hs-btn-p{background:#1d4ed8;color:#fff}\r\n#pth-hs .hs-btn-p:hover{background:#1e40af}\r\n#pth-hs .hs-btn-g{background:#059669;color:#fff}\r\n#pth-hs .hs-btn-g:hover{background:#047857}\r\n#pth-hs .hs-btn-o{background:#f59e0b;color:#fff}\r\n#pth-hs .hs-btn-o:hover{background:#d97706}\r\n#pth-hs .hs-btn-r{background:#dc2626;color:#fff}\r\n#pth-hs .hs-btn-r:hover{background:#b91c1c}\r\n#pth-hs .hs-btn-gh{background:#f1f5f9;color:#334155;border:1px solid #e2e8f0}\r\n#pth-hs .hs-btn-gh:hover{background:#e2e8f0}\r\n\/* Hash result rows *\/\r\n#pth-hs .hs-rows{display:flex;flex-direction:column;gap:8px;margin-top:14px}\r\n#pth-hs .hs-row{display:grid;grid-template-columns:100px 1fr auto auto;gap:8px;align-items:center}\r\n#pth-hs .hs-algo{font-size:.7rem;font-weight:900;padding:4px 8px;border-radius:5px;color:#fff;text-align:center;white-space:nowrap}\r\n#pth-hs .hs-hash-out{width:100%;padding:8px 10px;background:#0f172a;border:1px solid #1e293b;border-radius:6px;font-family:'Courier New',monospace;font-size:.72rem;color:#a5f3fc;outline:none}\r\n#pth-hs .hs-len{font-size:.65rem;color:#94a3b8;white-space:nowrap;font-family:'Courier New',monospace}\r\n\/* Format toggle *\/\r\n#pth-hs .hs-fmt-row{display:flex;gap:6px;flex-wrap:wrap;margin-top:10px;align-items:center}\r\n#pth-hs .hs-fmt-btn{padding:4px 10px;border-radius:5px;font-size:.68rem;font-weight:800;cursor:pointer;border:1.5px solid #e2e8f0;background:#fff;color:#64748b;font-family:inherit;transition:.15s}\r\n#pth-hs .hs-fmt-btn.on{border-color:#1d4ed8;background:#eff6ff;color:#1d4ed8}\r\n\/* Entropy *\/\r\n#pth-hs .hs-entropy-bar{height:6px;border-radius:3px;background:#e2e8f0;overflow:hidden;margin-top:6px}\r\n#pth-hs .hs-entropy-fill{height:100%;border-radius:3px;transition:.4s;width:0%}\r\n\/* File drop *\/\r\n#pth-hs .hs-drop{border:2px dashed #cbd5e1;border-radius:10px;padding:28px;text-align:center;cursor:pointer;transition:.2s;background:#f8fafc}\r\n#pth-hs .hs-drop:hover,#pth-hs .hs-drop.drag{border-color:#3b82f6;background:#eff6ff}\r\n#pth-hs .hs-drop-icon{font-size:2rem;display:block;margin-bottom:6px}\r\n#pth-hs .hs-drop p{color:#64748b;font-size:.82rem;margin:0}\r\n\/* Progress bar *\/\r\n#pth-hs .hs-progress{height:6px;background:#e2e8f0;border-radius:3px;overflow:hidden;display:none;margin-top:8px}\r\n#pth-hs .hs-progress-fill{height:100%;background:linear-gradient(90deg,#3b82f6,#8b5cf6);border-radius:3px;transition:width .3s}\r\n\/* Verifier result *\/\r\n#pth-hs .hs-verify-result{padding:12px 16px;border-radius:8px;font-weight:800;font-size:.88rem;text-align:center;margin-top:12px;display:none}\r\n#pth-hs .hs-verify-result.match{background:#ecfdf5;color:#047857;border:1px solid #a7f3d0}\r\n#pth-hs .hs-verify-result.nomatch{background:#fef2f2;color:#dc2626;border:1px solid #fecaca}\r\n\/* HMAC *\/\r\n#pth-hs .hs-hmac-grid{display:grid;grid-template-columns:1fr 1fr;gap:14px}\r\n@media(max-width:640px){#pth-hs .hs-hmac-grid{grid-template-columns:1fr}}\r\n\/* Password *\/\r\n#pth-hs .hs-pw-out{width:100%;padding:12px;background:#0f172a;color:#a5f3fc;font-family:'Courier New',monospace;font-size:.9rem;border-radius:8px;border:1px solid #1e293b;text-align:center;font-weight:700;letter-spacing:1px;margin:12px 0}\r\n#pth-hs .hs-strength{height:8px;border-radius:4px;background:#e2e8f0;overflow:hidden;margin-bottom:6px}\r\n#pth-hs .hs-strength-fill{height:100%;border-radius:4px;transition:.3s}\r\n#pth-hs .hs-chips{display:flex;flex-wrap:wrap;gap:6px;margin-bottom:12px}\r\n#pth-hs .hs-chip{padding:5px 11px;border-radius:6px;font-size:.75rem;font-weight:700;cursor:pointer;border:1.5px solid #e2e8f0;background:#fff;color:#334155;font-family:inherit;user-select:none;transition:.15s}\r\n#pth-hs .hs-chip.on{background:#1d4ed8;color:#fff;border-color:#1d4ed8}\r\n#pth-hs input[type=range]{width:100%;accent-color:#1d4ed8;cursor:pointer}\r\n\/* Encoder *\/\r\n#pth-hs .hs-enc-modes{display:flex;flex-wrap:wrap;gap:5px;margin-bottom:12px}\r\n#pth-hs .hs-enc-mode{padding:5px 12px;border-radius:6px;font-size:.73rem;font-weight:800;cursor:pointer;border:1.5px solid #e2e8f0;background:#fff;color:#334155;font-family:inherit;transition:.15s}\r\n#pth-hs .hs-enc-mode.on{background:#1d4ed8;color:#fff;border-color:#1d4ed8}\r\n#pth-hs .hs-enc-grid{display:grid;grid-template-columns:1fr auto 1fr;gap:10px;align-items:center}\r\n@media(max-width:600px){#pth-hs .hs-enc-grid{grid-template-columns:1fr;gap:6px}}\r\n#pth-hs .hs-enc-arrows{display:flex;flex-direction:column;gap:5px;align-items:center}\r\n\/* Cross-link card *\/\r\n#pth-hs .hs-xlink{background:linear-gradient(135deg,#eff6ff,#f5f3ff);border:1px solid #c7d2fe;border-radius:10px;padding:14px 16px;margin-top:14px;display:flex;align-items:center;gap:10px;flex-wrap:wrap}\r\n#pth-hs .hs-xlink-icon{font-size:1.4rem;flex-shrink:0}\r\n#pth-hs .hs-xlink-text{flex:1}\r\n#pth-hs .hs-xlink-title{font-size:.82rem;font-weight:800;color:#1e40af;margin:0 0 2px}\r\n#pth-hs .hs-xlink-sub{font-size:.73rem;color:#4338ca;margin:0}\r\n#pth-hs .hs-xlink a{font-size:.75rem;font-weight:800;padding:5px 12px;background:#1d4ed8;color:#fff;border-radius:6px;text-decoration:none;white-space:nowrap}\r\n\/* Batch *\/\r\n#pth-hs .hs-batch-table{width:100%;border-collapse:collapse;font-size:.72rem;margin-top:10px}\r\n#pth-hs .hs-batch-table th{background:#1e293b;color:#e2e8f0;padding:6px 8px;text-align:left;font-weight:800}\r\n#pth-hs .hs-batch-table td{padding:5px 8px;border-bottom:1px solid #f1f5f9;font-family:'Courier New',monospace;color:#334155;word-break:break-all}\r\n#pth-hs .hs-batch-table tr:nth-child(even) td{background:#f8fafc}\r\n\r\n\/* Sample buttons *\/\r\n#pth-hs .hs-samples{display:flex;gap:5px;flex-wrap:wrap;margin-bottom:8px;align-items:center}\r\n#pth-hs .hs-sample-lbl{font-size:.65rem;font-weight:800;color:#94a3b8;text-transform:uppercase;letter-spacing:.3px;white-space:nowrap}\r\n#pth-hs .hs-sample{padding:3px 9px;border-radius:5px;font-size:.68rem;font-weight:700;cursor:pointer;border:1.5px solid #ddd6fe;background:#f5f3ff;color:#5b21b6;font-family:inherit;transition:.15s;white-space:nowrap}\r\n#pth-hs .hs-sample:hover{background:#ede9fe;border-color:#8b5cf6;color:#4c1d95}\r\n\/* Toast *\/\r\n#pth-hs-toast{position:fixed;bottom:20px;right:20px;background:#1e293b;color:#fff;padding:10px 18px;border-radius:10px;font-weight:800;font-size:.82rem;box-shadow:0 8px 24px rgba(0,0,0,.3);z-index:99999;display:none;align-items:center;gap:8px;border:1px solid #334155}\r\n#pth-hs-toast.show{display:flex}\r\n\/* Dividers *\/\r\n#pth-hs .hs-divider{height:1px;background:#f1f5f9;margin:14px 0}\r\n#pth-hs .hs-row-btns{display:flex;gap:6px;flex-wrap:wrap;margin-top:10px}\r\n\/* Compare result *\/\r\n#pth-hs .hs-cmp-result{padding:12px;border-radius:8px;font-size:.82rem;font-weight:700;margin-top:10px;display:none}\r\n<\/style>\r\n\r\n<div id=\"pth-hs-toast\" role=\"alert\" aria-live=\"polite\"><\/div>\r\n\r\n<div id=\"pth-hs\">\r\n <!-- Top bar -->\r\n <div class=\"hs-top\">\r\n  <h2 class=\"hs-title\">\ud83d\udd10 PTH Secure Hash Studio<\/h2>\r\n  <p class=\"hs-sub\">SHA-256\/512\/384\/1 \u00b7 MD5 \u00b7 CRC32 \u00b7 HMAC \u00b7 File Checksum \u00b7 Encoder \u2014 100% Offline<\/p>\r\n  <div class=\"hs-badges\">\r\n   <span class=\"hs-badge\">v4.0 PRO<\/span>\r\n   <span class=\"hs-badge\">Web Crypto API<\/span>\r\n   <span class=\"hs-badge\">WCAG 2.1 AA<\/span>\r\n   <span class=\"hs-badge\">Zero Upload<\/span>\r\n   <span class=\"hs-badge\">PTH v4.3<\/span>\r\n  <\/div>\r\n <\/div>\r\n\r\n <!-- Tabs -->\r\n <div class=\"hs-tabs\" role=\"tablist\">\r\n  <button class=\"hs-tab on\" data-tab=\"text\" role=\"tab\" aria-selected=\"true\" aria-controls=\"hs-p-text\" id=\"hs-tb-text\">\u270f\ufe0f Text Hasher<\/button>\r\n  <button class=\"hs-tab\" data-tab=\"file\" role=\"tab\" aria-selected=\"false\" aria-controls=\"hs-p-file\" id=\"hs-tb-file\">\ud83d\udcc1 File Checksum<\/button>\r\n  <button class=\"hs-tab\" data-tab=\"verify\" role=\"tab\" aria-selected=\"false\" aria-controls=\"hs-p-verify\" id=\"hs-tb-verify\">\ud83d\udd0d Verifier<\/button>\r\n  <button class=\"hs-tab\" data-tab=\"hmac\" role=\"tab\" aria-selected=\"false\" aria-controls=\"hs-p-hmac\" id=\"hs-tb-hmac\">\ud83d\udd10 HMAC<\/button>\r\n  <button class=\"hs-tab\" data-tab=\"batch\" role=\"tab\" aria-selected=\"false\" aria-controls=\"hs-p-batch\" id=\"hs-tb-batch\">\ud83d\udccb Batch CSV<\/button>\r\n  <button class=\"hs-tab\" data-tab=\"encoder\" role=\"tab\" aria-selected=\"false\" aria-controls=\"hs-p-encoder\" id=\"hs-tb-encoder\">\ud83d\udd04 Encoder<\/button>\r\n <\/div>\r\n\r\n <!-- Body -->\r\n <div class=\"hs-body\">\r\n\r\n  <!-- TAB 1: TEXT HASHER -->\r\n  <div class=\"hs-panel on\" id=\"hs-p-text\" role=\"tabpanel\" aria-labelledby=\"hs-tb-text\">\r\n   <label class=\"hs-label\" for=\"hs-text-in\">Input Text<\/label>\r\n   <!-- Sample buttons for Text Hasher -->\r\n   <div class=\"hs-samples\">\r\n    <span class=\"hs-sample-lbl\">Try:<\/span>\r\n    <button class=\"hs-sample\" data-sample-text=\"Hello, World!\" aria-label=\"Sample: Hello World\">Hello, World!<\/button>\r\n    <button class=\"hs-sample\" data-sample-text=\"PrimeToolHub.com\" aria-label=\"Sample: PrimeToolHub\">PrimeToolHub.com<\/button>\r\n    <button class=\"hs-sample\" data-sample-text=\"The quick brown fox jumps over the lazy dog\" aria-label=\"Sample: pangram\">Pangram<\/button>\r\n    <button class=\"hs-sample\" data-sample-text=\"password123\" aria-label=\"Sample: weak password\">password123<\/button>\r\n    <button class=\"hs-sample\" data-sample-text=\"\" aria-label=\"Sample: empty\">Empty<\/button>\r\n   <\/div>\r\n   <div style=\"display:flex;gap:6px;margin-bottom:6px;flex-wrap:wrap;align-items:center;\">\r\n    <select id=\"hs-char-enc\" style=\"padding:5px 8px;border-radius:6px;border:1.5px solid #e2e8f0;font-size:.72rem;font-family:inherit;color:#334155;background:#fff;\" aria-label=\"Character encoding\">\r\n     <option value=\"utf8\">UTF-8<\/option>\r\n     <option value=\"utf16\">UTF-16<\/option>\r\n     <option value=\"latin1\">Latin-1<\/option>\r\n    <\/select>\r\n    <button class=\"hs-btn hs-btn-gh\" id=\"hs-copy-all\" aria-label=\"Copy all hashes\" style=\"font-size:.72rem;padding:5px 10px;\">\ud83d\udccb Copy All<\/button>\r\n    <button class=\"hs-btn hs-btn-gh\" id=\"hs-clear-text\" aria-label=\"Clear input\" style=\"font-size:.72rem;padding:5px 10px;\">\ud83d\uddd1 Clear<\/button>\r\n   <\/div>\r\n   <textarea id=\"hs-text-in\" class=\"hs-textarea\" placeholder=\"Type or paste text here \u2014 hashes update in real time...\" aria-label=\"Text input for hashing\" style=\"height:80px;\"><\/textarea>\r\n\r\n   <!-- Entropy -->\r\n   <div style=\"display:flex;align-items:center;gap:10px;margin-top:8px;flex-wrap:wrap;\">\r\n    <span style=\"font-size:.7rem;font-weight:800;color:#64748b;\">ENTROPY<\/span>\r\n    <div class=\"hs-entropy-bar\" style=\"flex:1;min-width:100px;\"><div class=\"hs-entropy-fill\" id=\"hs-entropy-fill\"><\/div><\/div>\r\n    <span id=\"hs-entropy-val\" style=\"font-size:.7rem;font-weight:800;color:#1d4ed8;white-space:nowrap;\">0 bits<\/span>\r\n    <span id=\"hs-entropy-lbl\" style=\"font-size:.68rem;color:#94a3b8;\"><\/span>\r\n   <\/div>\r\n\r\n   <!-- Format buttons -->\r\n   <div class=\"hs-fmt-row\">\r\n    <span style=\"font-size:.68rem;font-weight:800;color:#94a3b8;text-transform:uppercase;\">Format:<\/span>\r\n    <button class=\"hs-fmt-btn on\" data-fmt=\"hex\" aria-pressed=\"true\">HEX<\/button>\r\n    <button class=\"hs-fmt-btn\" data-fmt=\"HEX\" aria-pressed=\"false\">HEX UPPER<\/button>\r\n    <button class=\"hs-fmt-btn\" data-fmt=\"b64\" aria-pressed=\"false\">BASE64<\/button>\r\n   <\/div>\r\n\r\n   <!-- Hash output rows -->\r\n   <div class=\"hs-rows\">\r\n    <div class=\"hs-row\">\r\n     <span class=\"hs-algo\" style=\"background:#1d4ed8;\">SHA-256<\/span>\r\n     <input type=\"text\" id=\"hs-out-sha256\" class=\"hs-hash-out\" readonly aria-label=\"SHA-256 output\">\r\n     <span class=\"hs-len\" id=\"hs-len-sha256\">256 bit<\/span>\r\n     <button class=\"hs-btn hs-btn-gh\" data-cp=\"hs-out-sha256\" aria-label=\"Copy SHA-256\" style=\"padding:5px 8px;font-size:.72rem;\">\ud83d\udccb<\/button>\r\n    <\/div>\r\n    <div class=\"hs-row\">\r\n     <span class=\"hs-algo\" style=\"background:#7c3aed;\">SHA-512<\/span>\r\n     <input type=\"text\" id=\"hs-out-sha512\" class=\"hs-hash-out\" readonly aria-label=\"SHA-512 output\">\r\n     <span class=\"hs-len\" id=\"hs-len-sha512\">512 bit<\/span>\r\n     <button class=\"hs-btn hs-btn-gh\" data-cp=\"hs-out-sha512\" aria-label=\"Copy SHA-512\" style=\"padding:5px 8px;font-size:.72rem;\">\ud83d\udccb<\/button>\r\n    <\/div>\r\n    <div class=\"hs-row\">\r\n     <span class=\"hs-algo\" style=\"background:#0891b2;\">SHA-384<\/span>\r\n     <input type=\"text\" id=\"hs-out-sha384\" class=\"hs-hash-out\" readonly aria-label=\"SHA-384 output\">\r\n     <span class=\"hs-len\" id=\"hs-len-sha384\">384 bit<\/span>\r\n     <button class=\"hs-btn hs-btn-gh\" data-cp=\"hs-out-sha384\" aria-label=\"Copy SHA-384\" style=\"padding:5px 8px;font-size:.72rem;\">\ud83d\udccb<\/button>\r\n    <\/div>\r\n    <div class=\"hs-row\">\r\n     <span class=\"hs-algo\" style=\"background:#9f1239;\">SHA-1<\/span>\r\n     <input type=\"text\" id=\"hs-out-sha1\" class=\"hs-hash-out\" readonly aria-label=\"SHA-1 output\">\r\n     <span class=\"hs-len\" id=\"hs-len-sha1\">160 bit<\/span>\r\n     <button class=\"hs-btn hs-btn-gh\" data-cp=\"hs-out-sha1\" aria-label=\"Copy SHA-1\" style=\"padding:5px 8px;font-size:.72rem;\">\ud83d\udccb<\/button>\r\n    <\/div>\r\n    <div class=\"hs-row\">\r\n     <span class=\"hs-algo\" style=\"background:#c2410c;\">MD5<\/span>\r\n     <input type=\"text\" id=\"hs-out-md5\" class=\"hs-hash-out\" readonly aria-label=\"MD5 output\">\r\n     <span class=\"hs-len\" id=\"hs-len-md5\">128 bit<\/span>\r\n     <button class=\"hs-btn hs-btn-gh\" data-cp=\"hs-out-md5\" aria-label=\"Copy MD5\" style=\"padding:5px 8px;font-size:.72rem;\">\ud83d\udccb<\/button>\r\n    <\/div>\r\n    <div class=\"hs-row\">\r\n     <span class=\"hs-algo\" style=\"background:#0369a1;\">CRC32<\/span>\r\n     <input type=\"text\" id=\"hs-out-crc32\" class=\"hs-hash-out\" readonly aria-label=\"CRC32 output\">\r\n     <span class=\"hs-len\" id=\"hs-len-crc32\">32 bit<\/span>\r\n     <button class=\"hs-btn hs-btn-gh\" data-cp=\"hs-out-crc32\" aria-label=\"Copy CRC32\" style=\"padding:5px 8px;font-size:.72rem;\">\ud83d\udccb<\/button>\r\n    <\/div>\r\n   <\/div>\r\n  <\/div>\r\n\r\n  <!-- TAB 2: FILE CHECKSUM -->\r\n  <div class=\"hs-panel\" id=\"hs-p-file\" role=\"tabpanel\" aria-labelledby=\"hs-tb-file\">\r\n   <!-- Mode toggle -->\r\n   <div style=\"display:flex;gap:6px;margin-bottom:14px;flex-wrap:wrap;\">\r\n    <button class=\"hs-enc-mode on\" id=\"hs-file-mode-single\" aria-pressed=\"true\">Single File<\/button>\r\n    <button class=\"hs-enc-mode\" id=\"hs-file-mode-compare\" aria-pressed=\"false\">Compare Two Files<\/button>\r\n   <\/div>\r\n\r\n   <!-- Single mode -->\r\n   <div id=\"hs-file-single\">\r\n    <div class=\"hs-drop\" id=\"hs-file-drop\" tabindex=\"0\" aria-label=\"Drop file here or click to select\">\r\n     <span class=\"hs-drop-icon\">\ud83d\udcc1<\/span>\r\n     <p><strong>Drag &amp; drop any file<\/strong> \u2014 or click to browse<\/p>\r\n     <p style=\"font-size:.72rem;margin-top:4px;color:#94a3b8;\">All processing is local \u2014 file never leaves your browser<\/p>\r\n    <\/div>\r\n    <input type=\"file\" id=\"hs-file-input\" style=\"display:none;\" aria-label=\"File input\">\r\n    <div class=\"hs-progress\" id=\"hs-file-progress\"><div class=\"hs-progress-fill\" id=\"hs-file-prog-fill\" style=\"width:0%\"><\/div><\/div>\r\n    <div id=\"hs-file-info\" style=\"display:none;margin-top:10px;\">\r\n     <div style=\"display:flex;gap:8px;align-items:center;flex-wrap:wrap;background:#f8fafc;border:1px solid #e2e8f0;border-radius:8px;padding:10px 14px;margin-bottom:10px;\">\r\n      <span style=\"font-size:1.2rem;\">\ud83d\udcc4<\/span>\r\n      <div style=\"flex:1;\">\r\n       <div id=\"hs-file-name\" style=\"font-weight:800;font-size:.82rem;color:#0f172a;\"><\/div>\r\n       <div id=\"hs-file-size\" style=\"font-size:.72rem;color:#64748b;\"><\/div>\r\n      <\/div>\r\n     <\/div>\r\n     <div class=\"hs-rows\" id=\"hs-file-rows\">\r\n      <div class=\"hs-row\"><span class=\"hs-algo\" style=\"background:#1d4ed8;\">SHA-256<\/span><input type=\"text\" id=\"hs-fout-sha256\" class=\"hs-hash-out\" readonly aria-label=\"File SHA-256\"><span class=\"hs-len\">256 bit<\/span><button class=\"hs-btn hs-btn-gh\" data-cp=\"hs-fout-sha256\" aria-label=\"Copy\" style=\"padding:5px 8px;font-size:.72rem;\">\ud83d\udccb<\/button><\/div>\r\n      <div class=\"hs-row\"><span class=\"hs-algo\" style=\"background:#7c3aed;\">SHA-512<\/span><input type=\"text\" id=\"hs-fout-sha512\" class=\"hs-hash-out\" readonly aria-label=\"File SHA-512\"><span class=\"hs-len\">512 bit<\/span><button class=\"hs-btn hs-btn-gh\" data-cp=\"hs-fout-sha512\" aria-label=\"Copy\" style=\"padding:5px 8px;font-size:.72rem;\">\ud83d\udccb<\/button><\/div>\r\n      <div class=\"hs-row\"><span class=\"hs-algo\" style=\"background:#c2410c;\">MD5<\/span><input type=\"text\" id=\"hs-fout-md5\" class=\"hs-hash-out\" readonly aria-label=\"File MD5\"><span class=\"hs-len\">128 bit<\/span><button class=\"hs-btn hs-btn-gh\" data-cp=\"hs-fout-md5\" aria-label=\"Copy\" style=\"padding:5px 8px;font-size:.72rem;\">\ud83d\udccb<\/button><\/div>\r\n      <div class=\"hs-row\"><span class=\"hs-algo\" style=\"background:#0369a1;\">CRC32<\/span><input type=\"text\" id=\"hs-fout-crc32\" class=\"hs-hash-out\" readonly aria-label=\"File CRC32\"><span class=\"hs-len\">32 bit<\/span><button class=\"hs-btn hs-btn-gh\" data-cp=\"hs-fout-crc32\" aria-label=\"Copy\" style=\"padding:5px 8px;font-size:.72rem;\">\ud83d\udccb<\/button><\/div>\r\n     <\/div>\r\n    <\/div>\r\n   <\/div>\r\n\r\n   <!-- Compare mode -->\r\n   <div id=\"hs-file-compare\" style=\"display:none;\">\r\n    <div style=\"display:grid;grid-template-columns:1fr 1fr;gap:12px;\">\r\n     <div>\r\n      <div style=\"font-size:.72rem;font-weight:800;color:#334155;margin-bottom:6px;\">File A<\/div>\r\n      <div class=\"hs-drop\" id=\"hs-drop-a\" tabindex=\"0\" aria-label=\"Drop file A\" style=\"height:90px;font-size:.82rem;padding:14px;\">\ud83d\udcc1 Drop File A<\/div>\r\n      <input type=\"file\" id=\"hs-file-a\" style=\"display:none;\">\r\n      <input type=\"text\" id=\"hs-hash-a\" class=\"hs-hash-out\" readonly placeholder=\"SHA-256 of File A\" style=\"margin-top:6px;width:100%;\" aria-label=\"File A hash\">\r\n      <div id=\"hs-name-a\" style=\"font-size:.68rem;color:#64748b;margin-top:3px;\"><\/div>\r\n     <\/div>\r\n     <div>\r\n      <div style=\"font-size:.72rem;font-weight:800;color:#334155;margin-bottom:6px;\">File B<\/div>\r\n      <div class=\"hs-drop\" id=\"hs-drop-b\" tabindex=\"0\" aria-label=\"Drop file B\" style=\"height:90px;font-size:.82rem;padding:14px;\">\ud83d\udcc1 Drop File B<\/div>\r\n      <input type=\"file\" id=\"hs-file-b\" style=\"display:none;\">\r\n      <input type=\"text\" id=\"hs-hash-b\" class=\"hs-hash-out\" readonly placeholder=\"SHA-256 of File B\" style=\"margin-top:6px;width:100%;\" aria-label=\"File B hash\">\r\n      <div id=\"hs-name-b\" style=\"font-size:.68rem;color:#64748b;margin-top:3px;\"><\/div>\r\n     <\/div>\r\n    <\/div>\r\n    <div id=\"hs-cmp-result\" class=\"hs-cmp-result\"><\/div>\r\n   <\/div>\r\n  <\/div>\r\n\r\n  <!-- TAB 3: VERIFIER -->\r\n  <div class=\"hs-panel\" id=\"hs-p-verify\" role=\"tabpanel\" aria-labelledby=\"hs-tb-verify\">\r\n   <!-- Sample buttons for Verifier -->\r\n   <div class=\"hs-samples\" style=\"margin-bottom:12px;\">\r\n    <span class=\"hs-sample-lbl\">Try:<\/span>\r\n    <button class=\"hs-sample\" data-sample-verify=\"hello\" aria-label=\"Verify hello\">Verify 'hello'<\/button>\r\n    <button class=\"hs-sample\" data-sample-verify=\"password123\" aria-label=\"Verify password\">Verify 'password123'<\/button>\r\n    <button class=\"hs-sample\" data-sample-verify=\"PrimeToolHub\" aria-label=\"Verify PrimeToolHub\">Verify 'PrimeToolHub'<\/button>\r\n   <\/div>\r\n   <div style=\"display:grid;gap:12px;\">\r\n    <div>\r\n     <label class=\"hs-label\" for=\"hs-ver-text\">Original Text<\/label>\r\n     <textarea id=\"hs-ver-text\" class=\"hs-textarea\" placeholder=\"Paste the original text...\" aria-label=\"Text to verify\" style=\"height:70px;\"><\/textarea>\r\n    <\/div>\r\n    <div>\r\n     <div style=\"display:flex;align-items:center;gap:8px;flex-wrap:wrap;margin-bottom:5px;\">\r\n      <label class=\"hs-label\" for=\"hs-ver-hash\" style=\"margin:0;\">Known Hash to Verify<\/label>\r\n      <button class=\"hs-btn\" id=\"hs-auto-detect\" aria-label=\"Auto detect algorithm\" style=\"font-size:.68rem;padding:3px 9px;background:#ede9fe;color:#5b21b6;border:1px solid #c4b5fd;border-radius:5px;cursor:pointer;\">\ud83d\udd0d Auto-detect Algo<\/button>\r\n      <span id=\"hs-detected-algo\" style=\"font-size:.72rem;color:#6d28d9;font-weight:800;\"><\/span>\r\n     <\/div>\r\n     <input type=\"text\" id=\"hs-ver-hash\" class=\"hs-input\" placeholder=\"Paste known hash here...\" aria-label=\"Known hash\">\r\n    <\/div>\r\n    <div>\r\n     <label class=\"hs-label\" for=\"hs-ver-algo\">Algorithm<\/label>\r\n     <select id=\"hs-ver-algo\" class=\"hs-input\" aria-label=\"Select algorithm for verification\" style=\"cursor:pointer;\">\r\n      <option value=\"SHA-256\">SHA-256<\/option>\r\n      <option value=\"SHA-512\">SHA-512<\/option>\r\n      <option value=\"SHA-384\">SHA-384<\/option>\r\n      <option value=\"SHA-1\">SHA-1<\/option>\r\n      <option value=\"MD5\">MD5<\/option>\r\n      <option value=\"CRC32\">CRC32<\/option>\r\n     <\/select>\r\n    <\/div>\r\n    <div class=\"hs-row-btns\">\r\n     <button class=\"hs-btn hs-btn-p\" id=\"hs-verify-btn\" aria-label=\"Verify hash\">\ud83d\udd0d Verify Hash<\/button>\r\n     <button class=\"hs-btn hs-btn-gh\" id=\"hs-ver-clear\" aria-label=\"Clear verifier\">\ud83d\uddd1 Clear<\/button>\r\n    <\/div>\r\n   <\/div>\r\n   <div class=\"hs-verify-result\" id=\"hs-verify-result\"><\/div>\r\n   <!-- Diff position hint -->\r\n   <div id=\"hs-diff-hint\" style=\"display:none;margin-top:10px;padding:10px;background:#fff7ed;border:1px solid #fed7aa;border-radius:8px;font-size:.75rem;color:#92400e;font-weight:600;\"><\/div>\r\n  <\/div>\r\n\r\n  <!-- TAB 4: HMAC -->\r\n  <div class=\"hs-panel\" id=\"hs-p-hmac\" role=\"tabpanel\" aria-labelledby=\"hs-tb-hmac\">\r\n   <!-- Sample buttons for HMAC -->\r\n   <div class=\"hs-samples\" style=\"margin-bottom:12px;\">\r\n    <span class=\"hs-sample-lbl\">Try:<\/span>\r\n    <button class=\"hs-sample\" data-sample-hmac-msg=\"The message to authenticate\" data-sample-hmac-key=\"my-secret-key-2024\" aria-label=\"HMAC sample 1\">API Auth<\/button>\r\n    <button class=\"hs-sample\" data-sample-hmac-msg=\"amount=100&currency=USD&timestamp=1720000000\" data-sample-hmac-key=\"webhook-secret-xyz\" aria-label=\"HMAC sample webhook\">Webhook<\/button>\r\n    <button class=\"hs-sample\" data-sample-hmac-msg=\"user_id=42&action=login\" data-sample-hmac-key=\"pthhub-secret\" aria-label=\"HMAC JWT sample\">JWT-style<\/button>\r\n   <\/div>\r\n   <div class=\"hs-hmac-grid\">\r\n    <div>\r\n     <label class=\"hs-label\" for=\"hs-hmac-text\">Message<\/label>\r\n     <textarea id=\"hs-hmac-text\" class=\"hs-textarea\" placeholder=\"Message to authenticate...\" aria-label=\"HMAC message\" style=\"height:90px;\"><\/textarea>\r\n    <\/div>\r\n    <div>\r\n     <label class=\"hs-label\" for=\"hs-hmac-key\">Secret Key<\/label>\r\n     <textarea id=\"hs-hmac-key\" class=\"hs-textarea\" placeholder=\"Secret key...\" aria-label=\"HMAC secret key\" style=\"height:90px;\"><\/textarea>\r\n    <\/div>\r\n   <\/div>\r\n   <div style=\"margin-top:12px;\">\r\n    <label class=\"hs-label\" for=\"hs-hmac-algo\">HMAC Algorithm<\/label>\r\n    <div style=\"display:flex;gap:6px;flex-wrap:wrap;margin-bottom:12px;\">\r\n     <button class=\"hs-enc-mode on\" data-hmac=\"SHA-256\" aria-pressed=\"true\">HMAC-SHA256<\/button>\r\n     <button class=\"hs-enc-mode\" data-hmac=\"SHA-512\" aria-pressed=\"false\">HMAC-SHA512<\/button>\r\n     <button class=\"hs-enc-mode\" data-hmac=\"SHA-384\" aria-pressed=\"false\">HMAC-SHA384<\/button>\r\n     <button class=\"hs-enc-mode\" data-hmac=\"SHA-1\" aria-pressed=\"false\">HMAC-SHA1<\/button>\r\n    <\/div>\r\n    <button class=\"hs-btn hs-btn-p\" id=\"hs-hmac-btn\" aria-label=\"Generate HMAC\">\ud83d\udd10 Generate HMAC<\/button>\r\n   <\/div>\r\n   <div style=\"margin-top:12px;\">\r\n    <label class=\"hs-label\">HMAC Output<\/label>\r\n    <div class=\"hs-rows\">\r\n     <div class=\"hs-row\">\r\n      <span class=\"hs-algo\" style=\"background:#1d4ed8;\">HEX<\/span>\r\n      <input type=\"text\" id=\"hs-hmac-hex\" class=\"hs-hash-out\" readonly aria-label=\"HMAC hex output\">\r\n      <span class=\"hs-len\"><\/span>\r\n      <button class=\"hs-btn hs-btn-gh\" data-cp=\"hs-hmac-hex\" aria-label=\"Copy hex\" style=\"padding:5px 8px;font-size:.72rem;\">\ud83d\udccb<\/button>\r\n     <\/div>\r\n     <div class=\"hs-row\">\r\n      <span class=\"hs-algo\" style=\"background:#7c3aed;\">BASE64<\/span>\r\n      <input type=\"text\" id=\"hs-hmac-b64\" class=\"hs-hash-out\" readonly aria-label=\"HMAC base64 output\">\r\n      <span class=\"hs-len\"><\/span>\r\n      <button class=\"hs-btn hs-btn-gh\" data-cp=\"hs-hmac-b64\" aria-label=\"Copy base64\" style=\"padding:5px 8px;font-size:.72rem;\">\ud83d\udccb<\/button>\r\n     <\/div>\r\n    <\/div>\r\n   <\/div>\r\n   <div style=\"margin-top:12px;padding:10px 14px;background:#f0fdf4;border:1px solid #bbf7d0;border-radius:8px;font-size:.75rem;color:#14532d;font-weight:600;\">\r\n    \ud83d\udd12 HMAC uses Web Crypto API \u2014 computed natively in your browser. Key and message never leave your device.\r\n   <\/div>\r\n  <\/div>\r\n\r\n  <!-- TAB 5: BATCH CSV -->\r\n  <div class=\"hs-panel\" id=\"hs-p-batch\" role=\"tabpanel\" aria-labelledby=\"hs-tb-batch\">\r\n   <!-- Sample buttons for Batch -->\r\n   <div class=\"hs-samples\" style=\"margin-bottom:8px;\">\r\n    <span class=\"hs-sample-lbl\">Load:<\/span>\r\n    <button class=\"hs-sample\" data-sample-batch=\"fruits\" aria-label=\"Sample fruits\">Fruits (5)<\/button>\r\n    <button class=\"hs-sample\" data-sample-batch=\"passwords\" aria-label=\"Sample passwords\">Common Passwords (5)<\/button>\r\n    <button class=\"hs-sample\" data-sample-batch=\"urls\" aria-label=\"Sample URLs\">URLs (4)<\/button>\r\n    <button class=\"hs-sample\" data-sample-batch=\"numbers\" aria-label=\"Sample numbers\">Numbers 1-10<\/button>\r\n   <\/div>\r\n   <label class=\"hs-label\" for=\"hs-batch-in\">Batch Input (one item per line)<\/label>\r\n   <textarea id=\"hs-batch-in\" class=\"hs-textarea\" placeholder=\"apple&#10;banana&#10;cherry&#10;one line per item...\" aria-label=\"Batch text input\" style=\"height:100px;\"><\/textarea>\r\n   <div style=\"display:flex;gap:8px;flex-wrap:wrap;margin-top:10px;align-items:center;\">\r\n    <label class=\"hs-label\" style=\"margin:0;\">Algorithm:<\/label>\r\n    <select id=\"hs-batch-algo\" class=\"hs-input\" style=\"width:auto;padding:6px 10px;cursor:pointer;\" aria-label=\"Batch algorithm\">\r\n     <option value=\"SHA-256\">SHA-256<\/option>\r\n     <option value=\"SHA-512\">SHA-512<\/option>\r\n     <option value=\"SHA-384\">SHA-384<\/option>\r\n     <option value=\"SHA-1\">SHA-1<\/option>\r\n     <option value=\"MD5\">MD5<\/option>\r\n     <option value=\"CRC32\">CRC32<\/option>\r\n    <\/select>\r\n    <button class=\"hs-btn hs-btn-p\" id=\"hs-batch-run\" aria-label=\"Run batch hash\">\u26a1 Hash All<\/button>\r\n    <button class=\"hs-btn hs-btn-g\" id=\"hs-batch-dl\" aria-label=\"Download CSV\" style=\"display:none;\">\u2b07 Download CSV<\/button>\r\n    <button class=\"hs-btn hs-btn-gh\" id=\"hs-batch-clear\" aria-label=\"Clear batch\">\ud83d\uddd1 Clear<\/button>\r\n   <\/div>\r\n   <div id=\"hs-batch-results\" style=\"margin-top:12px;\"><\/div>\r\n  <\/div>\r\n\r\n  <!-- TAB 6: ENCODER -->\r\n  <div class=\"hs-panel\" id=\"hs-p-encoder\" role=\"tabpanel\" aria-labelledby=\"hs-tb-encoder\">\r\n   <!-- Cross-link notice -->\r\n   <div class=\"hs-xlink\" style=\"margin-bottom:14px;\">\r\n    <span class=\"hs-xlink-icon\">\ud83d\udd17<\/span>\r\n    <div class=\"hs-xlink-text\">\r\n     <p class=\"hs-xlink-title\">Need standalone encoder tools?<\/p>\r\n     <p class=\"hs-xlink-sub\">Full Base64 Studio \u2192 <a href=\"\/free-base64-encoder-decoder-utf-8-supported\/\" rel=\"noopener\" style=\"color:#a5b4fc;\">free-base64-encoder-decoder-utf-8-supported<\/a> &nbsp;\u00b7&nbsp; URL Encoder \u2192 <a href=\"\/universal-url-encoder-decoder\/\" rel=\"noopener\" style=\"color:#a5b4fc;\">universal-url-encoder-decoder<\/a><\/p>\r\n    <\/div>\r\n   <\/div>\r\n\r\n   <!-- Sample buttons for Encoder -->\r\n   <div class=\"hs-samples\" style=\"margin-bottom:8px;\">\r\n    <span class=\"hs-sample-lbl\">Try:<\/span>\r\n    <button class=\"hs-sample\" data-sample-enc=\"Hello, World!\" aria-label=\"Encode Hello World\">Hello, World!<\/button>\r\n    <button class=\"hs-sample\" data-sample-enc=\"https:\/\/schoolict.net\/tools\/free-tools\/?cat=dev&lang=en\" aria-label=\"Encode URL\">URL with params<\/button>\r\n    <button class=\"hs-sample\" data-sample-enc=\"<h1>Hello &amp; World<\/h1>\" aria-label=\"Encode HTML\">HTML markup<\/button>\r\n    <button class=\"hs-sample\" data-sample-enc=\"SOS\" aria-label=\"Encode SOS in morse\">SOS (Morse)<\/button>\r\n   <\/div>\r\n   <div class=\"hs-enc-modes\" role=\"group\" aria-label=\"Encoding mode selector\">\r\n    <button class=\"hs-enc-mode on\" data-enc=\"base64\" aria-pressed=\"true\">Base64<\/button>\r\n    <button class=\"hs-enc-mode\" data-enc=\"url\" aria-pressed=\"false\">URL Encode<\/button>\r\n    <button class=\"hs-enc-mode\" data-enc=\"hex\" aria-pressed=\"false\">Hex<\/button>\r\n    <button class=\"hs-enc-mode\" data-enc=\"binary\" aria-pressed=\"false\">Binary<\/button>\r\n    <button class=\"hs-enc-mode\" data-enc=\"html\" aria-pressed=\"false\">HTML Entities<\/button>\r\n    <button class=\"hs-enc-mode\" data-enc=\"rot13\" aria-pressed=\"false\">ROT13<\/button>\r\n    <button class=\"hs-enc-mode\" data-enc=\"morse\" aria-pressed=\"false\">Morse Code<\/button>\r\n   <\/div>\r\n   <div id=\"hs-enc-desc\" style=\"font-size:.72rem;color:#64748b;margin-bottom:10px;min-height:16px;\"><\/div>\r\n   <div class=\"hs-enc-grid\">\r\n    <div>\r\n     <label class=\"hs-label\" for=\"hs-enc-in\">Input<\/label>\r\n     <textarea id=\"hs-enc-in\" class=\"hs-textarea\" placeholder=\"Type or paste text...\" aria-label=\"Encoder input\" style=\"height:120px;\"><\/textarea>\r\n    <\/div>\r\n    <div class=\"hs-enc-arrows\">\r\n     <button class=\"hs-btn hs-btn-p\" id=\"hs-enc-encode\" aria-label=\"Encode\">Encode \u2192<\/button>\r\n     <button class=\"hs-btn hs-btn-gh\" id=\"hs-enc-decode\" aria-label=\"Decode\">\u2190 Decode<\/button>\r\n     <button class=\"hs-btn hs-btn-gh\" id=\"hs-enc-swap\" aria-label=\"Swap input and output\" style=\"font-size:.72rem;\">\u21c4 Swap<\/button>\r\n    <\/div>\r\n    <div>\r\n     <label class=\"hs-label\" for=\"hs-enc-out\">Output<\/label>\r\n     <textarea id=\"hs-enc-out\" class=\"hs-textarea\" placeholder=\"Result appears here...\" aria-label=\"Encoder output\" style=\"height:120px;\" readonly><\/textarea>\r\n    <\/div>\r\n   <\/div>\r\n   <div class=\"hs-row-btns\" style=\"margin-top:8px;\">\r\n    <button class=\"hs-btn hs-btn-gh\" id=\"hs-enc-copy\" aria-label=\"Copy output\" style=\"font-size:.72rem;\">\ud83d\udccb Copy Output<\/button>\r\n    <button class=\"hs-btn hs-btn-gh\" id=\"hs-enc-clear\" aria-label=\"Clear encoder\" style=\"font-size:.72rem;\">\ud83d\uddd1 Clear<\/button>\r\n   <\/div>\r\n  <\/div>\r\n\r\n <\/div><!-- \/.hs-body -->\r\n<\/div><!-- \/#pth-hs -->\r\n\r\n<script data-no-optimize=\"1\" data-no-minify=\"1\" data-cfasync=\"false\">\r\n(function(){\r\n\"use strict\";\r\n\r\n\/* \u2500\u2500 MD5 pure-JS implementation \u2500\u2500 *\/\r\nfunction pthMD5(s){\r\n  function safeAdd(x,y){var lsw=(x&0xFFFF)+(y&0xFFFF);return(((x>>>16)+(y>>>16)+(lsw>>>16))<<16)|(lsw&0xFFFF);}\r\n  function bitRotateLeft(num,cnt){return(num<<cnt)|(num>>>(32-cnt));}\r\n  function md5cmn(q,a,b,x,s,t){return safeAdd(bitRotateLeft(safeAdd(safeAdd(a,q),safeAdd(x,t)),s),b);}\r\n  function md5ff(a,b,c,d,x,s,t){return md5cmn((b&c)|((~b)&d),a,b,x,s,t);}\r\n  function md5gg(a,b,c,d,x,s,t){return md5cmn((b&d)|(c&(~d)),a,b,x,s,t);}\r\n  function md5hh(a,b,c,d,x,s,t){return md5cmn(b^c^d,a,b,x,s,t);}\r\n  function md5ii(a,b,c,d,x,s,t){return md5cmn(c^(b|(~d)),a,b,x,s,t);}\r\n  function toUtf8Bytes(str){var bytes=[];for(var i=0;i<str.length;i++){var c=str.charCodeAt(i);if(c<128){bytes.push(c);}else if(c<2048){bytes.push((c>>6)|192,c&63|128);}else{bytes.push((c>>12)|224,((c>>6)&63)|128,(c&63)|128);}}return bytes;}\r\n  var bytes=toUtf8Bytes(s),bLen=bytes.length,words=[],i;\r\n  for(i=0;i<bLen;i++){words[i>>2]|=bytes[i]<<((i%4)*8);}\r\n  words[bLen>>2]|=0x80<<((bLen%4)*8);\r\n  words[(((bLen+8)>>6)<<4)+14]=bLen*8;\r\n  var a=1732584193,b=-271733879,c=-1732584194,d=271733878,m=words,aa,bb,cc,dd;\r\n  for(i=0;i<m.length;i+=16){\r\n    aa=a;bb=b;cc=c;dd=d;\r\n    a=md5ff(a,b,c,d,m[i+0],7,-680876936);d=md5ff(d,a,b,c,m[i+1],12,-389564586);c=md5ff(c,d,a,b,m[i+2],17,606105819);b=md5ff(b,c,d,a,m[i+3],22,-1044525330);\r\n    a=md5ff(a,b,c,d,m[i+4],7,-176418897);d=md5ff(d,a,b,c,m[i+5],12,1200080426);c=md5ff(c,d,a,b,m[i+6],17,-1473231341);b=md5ff(b,c,d,a,m[i+7],22,-45705983);\r\n    a=md5ff(a,b,c,d,m[i+8],7,1770035416);d=md5ff(d,a,b,c,m[i+9],12,-1958414417);c=md5ff(c,d,a,b,m[i+10],17,-42063);b=md5ff(b,c,d,a,m[i+11],22,-1990404162);\r\n    a=md5ff(a,b,c,d,m[i+12],7,1804603682);d=md5ff(d,a,b,c,m[i+13],12,-40341101);c=md5ff(c,d,a,b,m[i+14],17,-1502002290);b=md5ff(b,c,d,a,m[i+15],22,1236535329);\r\n    a=md5gg(a,b,c,d,m[i+1],5,-165796510);d=md5gg(d,a,b,c,m[i+6],9,-1069501632);c=md5gg(c,d,a,b,m[i+11],14,643717713);b=md5gg(b,c,d,a,m[i+0],20,-373897302);\r\n    a=md5gg(a,b,c,d,m[i+5],5,-701558691);d=md5gg(d,a,b,c,m[i+10],9,38016083);c=md5gg(c,d,a,b,m[i+15],14,-660478335);b=md5gg(b,c,d,a,m[i+4],20,-405537848);\r\n    a=md5gg(a,b,c,d,m[i+9],5,568446438);d=md5gg(d,a,b,c,m[i+14],9,-1019803690);c=md5gg(c,d,a,b,m[i+3],14,-187363961);b=md5gg(b,c,d,a,m[i+8],20,1163531501);\r\n    a=md5gg(a,b,c,d,m[i+13],5,-1444681467);d=md5gg(d,a,b,c,m[i+2],9,-51403784);c=md5gg(c,d,a,b,m[i+7],14,1735328473);b=md5gg(b,c,d,a,m[i+12],20,-1926607734);\r\n    a=md5hh(a,b,c,d,m[i+5],4,-378558);d=md5hh(d,a,b,c,m[i+8],11,-2022574463);c=md5hh(c,d,a,b,m[i+11],16,1839030562);b=md5hh(b,c,d,a,m[i+14],23,-35309556);\r\n    a=md5hh(a,b,c,d,m[i+1],4,-1530992060);d=md5hh(d,a,b,c,m[i+4],11,1272893353);c=md5hh(c,d,a,b,m[i+7],16,-155497632);b=md5hh(b,c,d,a,m[i+10],23,-1094730640);\r\n    a=md5hh(a,b,c,d,m[i+13],4,681279174);d=md5hh(d,a,b,c,m[i+0],11,-358537222);c=md5hh(c,d,a,b,m[i+3],16,-722521979);b=md5hh(b,c,d,a,m[i+6],23,76029189);\r\n    a=md5hh(a,b,c,d,m[i+9],4,-640364487);d=md5hh(d,a,b,c,m[i+12],11,-421815835);c=md5hh(c,d,a,b,m[i+15],16,530742520);b=md5hh(b,c,d,a,m[i+2],23,-995338651);\r\n    a=md5ii(a,b,c,d,m[i+0],6,-198630844);d=md5ii(d,a,b,c,m[i+7],10,1126891415);c=md5ii(c,d,a,b,m[i+14],15,-1416354905);b=md5ii(b,c,d,a,m[i+5],21,-57434055);\r\n    a=md5ii(a,b,c,d,m[i+12],6,1700485571);d=md5ii(d,a,b,c,m[i+3],10,-1894986606);c=md5ii(c,d,a,b,m[i+10],15,-1051523);b=md5ii(b,c,d,a,m[i+1],21,-2054922799);\r\n    a=md5ii(a,b,c,d,m[i+8],6,1873313359);d=md5ii(d,a,b,c,m[i+15],10,-30611744);c=md5ii(c,d,a,b,m[i+6],15,-1560198380);b=md5ii(b,c,d,a,m[i+13],21,1309151649);\r\n    a=md5ii(a,b,c,d,m[i+4],6,-145523070);d=md5ii(d,a,b,c,m[i+11],10,-1120210379);c=md5ii(c,d,a,b,m[i+2],15,718787259);b=md5ii(b,c,d,a,m[i+9],21,-343485551);\r\n    a=safeAdd(a,aa);b=safeAdd(b,bb);c=safeAdd(c,cc);d=safeAdd(d,dd);\r\n  }\r\n  var result='';\r\n  var vals=[a,b,c,d];\r\n  for(i=0;i<vals.length;i++){var val=vals[i];for(var j=0;j<4;j++){result+=('0'+((val>>(j*8))&0xFF).toString(16)).slice(-2);}}\r\n  return result;\r\n}\r\n\r\n\/* \u2500\u2500 CRC32 \u2500\u2500 *\/\r\nfunction pthCRC32(str){\r\n  var table=[];\r\n  for(var n=0;n<256;n++){var c=n;for(var k=0;k<8;k++){c=((c&1)?0xEDB88320^(c>>>1):(c>>>1));}table[n]=c;}\r\n  var crc=0xFFFFFFFF;\r\n  for(var i=0;i<str.length;i++){crc=table[(crc^str.charCodeAt(i))&0xFF]^(crc>>>8);}\r\n  return ('00000000'+((crc^0xFFFFFFFF)>>>0).toString(16)).slice(-8);\r\n}\r\n\r\n\/* \u2500\u2500 Morse Code \u2500\u2500 *\/\r\nvar MORSE_MAP={'A':'.-','B':'-...','C':'-.-.','D':'-..','E':'.','F':'..-.','G':'--.','H':'....','I':'..','J':'.---','K':'-.-','L':'.-..','M':'--','N':'-.','O':'---','P':'.--.','Q':'--.-','R':'.-.','S':'...','T':'-','U':'..-','V':'...-','W':'.--','X':'-..-','Y':'-.--','Z':'--..','0':'-----','1':'.----','2':'..---','3':'...--','4':'....-','5':'.....','6':'-....','7':'--...','8':'---..','9':'----.',' ':'\/'};\r\nvar MORSE_REV={};\r\n(function(){for(var k in MORSE_MAP){if(MORSE_MAP.hasOwnProperty(k))MORSE_REV[MORSE_MAP[k]]=k;}})();\r\n\r\n\/* \u2500\u2500 Main App \u2500\u2500 *\/\r\nwindow.pthHashApp = {\r\n  tab: 'text',\r\n  fmt: 'hex',\r\n  encMode: 'base64',\r\n  hmacAlgo: 'SHA-256',\r\n  batchData: [],\r\n  fileCompareMode: false,\r\n  ok: false,\r\n\r\n  g: function(id){ return document.getElementById(id); },\r\n  bev: function(el, ev, fn){ if(el) el.addEventListener(ev, fn); },\r\n\r\n  toast: function(msg, ms){\r\n    var t = document.getElementById('pth-hs-toast');\r\n    if(!t) return;\r\n    t.textContent = msg;\r\n    t.classList.add('show');\r\n    clearTimeout(this._tt);\r\n    var self = this;\r\n    this._tt = setTimeout(function(){ t.classList.remove('show'); }, ms || 2500);\r\n  },\r\n\r\n  \/* \u2500\u2500 Text to ArrayBuffer \u2500\u2500 *\/\r\n  strToAB: function(str){\r\n    var bytes = [];\r\n    for(var i=0; i<str.length; i++){\r\n      var c = str.charCodeAt(i);\r\n      if(c < 128){ bytes.push(c); }\r\n      else if(c < 2048){ bytes.push((c>>6)|192, (c&63)|128); }\r\n      else{ bytes.push((c>>12)|224, ((c>>6)&63)|128, (c&63)|128); }\r\n    }\r\n    return new Uint8Array(bytes).buffer;\r\n  },\r\n\r\n  bufToHex: function(buf){\r\n    var b = new Uint8Array(buf), hex = '';\r\n    for(var i=0;i<b.length;i++) hex += ('00'+b[i].toString(16)).slice(-2);\r\n    return hex;\r\n  },\r\n  bufToB64: function(buf){\r\n    return btoa(String.fromCharCode.apply(null, new Uint8Array(buf)));\r\n  },\r\n  hexToB64: function(hex){\r\n    var bytes = [];\r\n    for(var i=0;i<hex.length;i+=2) bytes.push(parseInt(hex.substr(i,2),16));\r\n    return btoa(String.fromCharCode.apply(null,bytes));\r\n  },\r\n  applyFmt: function(hex){\r\n    if(this.fmt === 'HEX') return hex.toUpperCase();\r\n    if(this.fmt === 'b64') return this.hexToB64(hex);\r\n    return hex;\r\n  },\r\n\r\n  \/* \u2500\u2500 Entropy \u2500\u2500 *\/\r\n  calcEntropy: function(str){\r\n    if(!str) return 0;\r\n    var freq = {};\r\n    for(var i=0;i<str.length;i++){var c=str[i];freq[c]=(freq[c]||0)+1;}\r\n    var ent = 0, len = str.length;\r\n    for(var k in freq){if(freq.hasOwnProperty(k)){var p=freq[k]\/len;ent-=p*Math.log2(p);}}\r\n    return +(ent*len).toFixed(1);\r\n  },\r\n\r\n  updateEntropy: function(str){\r\n    var bits = this.calcEntropy(str);\r\n    var max = str.length * 8;\r\n    var pct = max > 0 ? Math.min(100, (bits\/max)*100) : 0;\r\n    var fill = this.g('hs-entropy-fill');\r\n    if(fill){\r\n      fill.style.width = pct + '%';\r\n      fill.style.background = pct < 30 ? '#ef4444' : pct < 60 ? '#f59e0b' : '#10b981';\r\n    }\r\n    var val = this.g('hs-entropy-val');\r\n    if(val) val.textContent = bits + ' bits';\r\n    var lbl = this.g('hs-entropy-lbl');\r\n    if(lbl) lbl.textContent = pct < 30 ? '(Low)' : pct < 60 ? '(Medium)' : '(High)';\r\n  },\r\n\r\n  \/* \u2500\u2500 Hash text \u2500\u2500 *\/\r\n  hashText: async function(text){\r\n    var self = this;\r\n    if(!text){\r\n      ['sha256','sha512','sha384','sha1','md5','crc32'].forEach(function(a){\r\n        var el = self.g('hs-out-'+a);\r\n        if(el) el.value = '';\r\n      });\r\n      return;\r\n    }\r\n    var ab = this.strToAB(text);\r\n    var algos = [['SHA-256','sha256'],['SHA-512','sha512'],['SHA-384','sha384'],['SHA-1','sha1']];\r\n    for(var i=0;i<algos.length;i++){\r\n      try{\r\n        var buf = await crypto.subtle.digest(algos[i][0], ab);\r\n        var hex = this.bufToHex(buf);\r\n        var el = this.g('hs-out-'+algos[i][1]);\r\n        if(el) el.value = this.applyFmt(hex);\r\n      }catch(e){}\r\n    }\r\n    var md5hex = pthMD5(text);\r\n    var md5el = this.g('hs-out-md5');\r\n    if(md5el) md5el.value = this.applyFmt(md5hex);\r\n    var crc32hex = pthCRC32(text);\r\n    var crc32el = this.g('hs-out-crc32');\r\n    if(crc32el) crc32el.value = this.applyFmt(crc32hex);\r\n  },\r\n\r\n  \/* \u2500\u2500 Hash file (ArrayBuffer) \u2500\u2500 *\/\r\n  hashFileBuf: async function(buf){\r\n    var results = {};\r\n    var algos = [['SHA-256','sha256'],['SHA-512','sha512'],['MD5','md5'],['CRC32','crc32']];\r\n    for(var i=0;i<algos.length;i++){\r\n      if(algos[i][0]==='MD5'){ results['md5']='(text only)'; continue; }\r\n      if(algos[i][0]==='CRC32'){\r\n        var u8 = new Uint8Array(buf);\r\n        var table=[];for(var n=0;n<256;n++){var c2=n;for(var k=0;k<8;k++){c2=((c2&1)?0xEDB88320^(c2>>>1):(c2>>>1));}table[n]=c2;}\r\n        var crc=0xFFFFFFFF;\r\n        for(var j=0;j<u8.length;j++){crc=table[(crc^u8[j])&0xFF]^(crc>>>8);}\r\n        results['crc32']=('00000000'+((crc^0xFFFFFFFF)>>>0).toString(16)).slice(-8);\r\n        continue;\r\n      }\r\n      try{\r\n        var hashBuf = await crypto.subtle.digest(algos[i][0], buf);\r\n        results[algos[i][1]] = this.bufToHex(hashBuf);\r\n      }catch(e){ results[algos[i][1]]='Error'; }\r\n    }\r\n    return results;\r\n  },\r\n\r\n  \/* \u2500\u2500 Process file \u2500\u2500 *\/\r\n  processFile: function(file, outPrefix, nameEl, sizeEl){\r\n    var self = this;\r\n    var prog = this.g('hs-file-progress');\r\n    var progFill = this.g('hs-file-prog-fill');\r\n    var info = this.g('hs-file-info');\r\n    if(nameEl){ var nel=this.g(nameEl); if(nel) nel.textContent=file.name; }\r\n    if(sizeEl){ var sel2=this.g(sizeEl); if(sel2) sel2.textContent=this.formatSize(file.size); }\r\n    if(prog){ prog.style.display='block'; }\r\n    if(progFill){ progFill.style.width='10%'; }\r\n    var reader = new FileReader();\r\n    reader.onprogress = function(e){\r\n      if(e.lengthComputable && progFill) progFill.style.width = Math.min(90,(e.loaded\/e.total*90)) + '%';\r\n    };\r\n    reader.onload = async function(e){\r\n      if(progFill) progFill.style.width='100%';\r\n      var buf = e.target.result;\r\n      var results = await self.hashFileBuf(buf);\r\n      var keys = ['sha256','sha512','md5','crc32'];\r\n      for(var i=0;i<keys.length;i++){\r\n        var el2 = self.g((outPrefix||'hs-fout-')+keys[i]);\r\n        if(el2 && results[keys[i]]) el2.value = results[keys[i]];\r\n      }\r\n      if(prog) setTimeout(function(){ prog.style.display='none'; }, 800);\r\n      if(info) info.style.display='block';\r\n      self.toast('\u2705 File hashed: ' + file.name);\r\n    };\r\n    reader.readAsArrayBuffer(file);\r\n  },\r\n\r\n  formatSize: function(bytes){\r\n    if(bytes < 1024) return bytes + ' B';\r\n    if(bytes < 1048576) return (bytes\/1024).toFixed(1) + ' KB';\r\n    return (bytes\/1048576).toFixed(1) + ' MB';\r\n  },\r\n\r\n  \/* \u2500\u2500 Verifier \u2500\u2500 *\/\r\n  autoDetectAlgo: function(hash){\r\n    var h = hash.trim().toLowerCase();\r\n    var len = h.length;\r\n    if(len === 8) return 'CRC32';\r\n    if(len === 32) return 'MD5';\r\n    if(len === 40) return 'SHA-1';\r\n    if(len === 64) return 'SHA-256';\r\n    if(len === 96) return 'SHA-384';\r\n    if(len === 128) return 'SHA-512';\r\n    return null;\r\n  },\r\n\r\n  verifyHash: async function(){\r\n    var text = this.g('hs-ver-text') ? this.g('hs-ver-text').value : '';\r\n    var known = this.g('hs-ver-hash') ? this.g('hs-ver-hash').value.trim().toLowerCase() : '';\r\n    var algo = this.g('hs-ver-algo') ? this.g('hs-ver-algo').value : 'SHA-256';\r\n    var result = this.g('hs-verify-result');\r\n    var diffHint = this.g('hs-diff-hint');\r\n    if(!text || !known){ this.toast('\u26a0\ufe0f Enter text and known hash'); return; }\r\n    var computed = '';\r\n    if(algo === 'MD5'){ computed = pthMD5(text); }\r\n    else if(algo === 'CRC32'){ computed = pthCRC32(text); }\r\n    else{\r\n      try{\r\n        var buf = await crypto.subtle.digest(algo, this.strToAB(text));\r\n        computed = this.bufToHex(buf);\r\n      }catch(e){ if(result){ result.textContent='Error computing hash'; result.className='hs-verify-result nomatch'; result.style.display='block'; } return; }\r\n    }\r\n    var match = computed === known;\r\n    if(result){\r\n      result.textContent = match ? '\u2705 MATCH \u2014 Hash verified successfully!' : '\u274c MISMATCH \u2014 Hashes do not match';\r\n      result.className = 'hs-verify-result ' + (match ? 'match' : 'nomatch');\r\n      result.style.display = 'block';\r\n    }\r\n    if(!match && diffHint){\r\n      \/* Find first differing position *\/\r\n      var diffPos = -1;\r\n      var maxLen = Math.max(computed.length, known.length);\r\n      for(var i=0;i<maxLen;i++){\r\n        if(computed[i] !== known[i]){ diffPos = i; break; }\r\n      }\r\n      if(diffPos >= 0){\r\n        diffHint.textContent = '\ud83d\udd0d First difference at position ' + diffPos + ' \u2014 computed: \"' + (computed[diffPos]||'\u2014') + '\" vs known: \"' + (known[diffPos]||'\u2014') + '\"';\r\n        diffHint.style.display = 'block';\r\n      }\r\n    } else if(diffHint){ diffHint.style.display = 'none'; }\r\n  },\r\n\r\n  \/* \u2500\u2500 HMAC \u2500\u2500 *\/\r\n  generateHMAC: async function(){\r\n    var msg = this.g('hs-hmac-text') ? this.g('hs-hmac-text').value : '';\r\n    var key = this.g('hs-hmac-key') ? this.g('hs-hmac-key').value : '';\r\n    if(!msg || !key){ this.toast('\u26a0\ufe0f Enter message and key'); return; }\r\n    try{\r\n      var keyAB = this.strToAB(key);\r\n      var msgAB = this.strToAB(msg);\r\n      var cryptoKey = await crypto.subtle.importKey('raw', keyAB,\r\n        {name:'HMAC', hash:{name: this.hmacAlgo}}, false, ['sign']);\r\n      var sig = await crypto.subtle.sign('HMAC', cryptoKey, msgAB);\r\n      var hex = this.bufToHex(sig);\r\n      var b64 = this.bufToB64(sig);\r\n      var hexEl = this.g('hs-hmac-hex'); if(hexEl) hexEl.value = hex;\r\n      var b64El = this.g('hs-hmac-b64'); if(b64El) b64El.value = b64;\r\n      this.toast('\u2705 HMAC-' + this.hmacAlgo + ' generated');\r\n    }catch(e){ this.toast('\u274c HMAC error: ' + e.message, 4000); }\r\n  },\r\n\r\n  \/* \u2500\u2500 Batch \u2500\u2500 *\/\r\n  runBatch: async function(){\r\n    var input = this.g('hs-batch-in') ? this.g('hs-batch-in').value.trim() : '';\r\n    var algo = this.g('hs-batch-algo') ? this.g('hs-batch-algo').value : 'SHA-256';\r\n    var resultsDiv = this.g('hs-batch-results');\r\n    if(!input){ this.toast('\u26a0\ufe0f Enter items to hash'); return; }\r\n    var lines = input.split('\\n').filter(function(l){ return l.trim(); });\r\n    this.batchData = [];\r\n    var results = [];\r\n    for(var i=0;i<lines.length;i++){\r\n      var line = lines[i].trim();\r\n      var hash = '';\r\n      if(algo === 'MD5') hash = pthMD5(line);\r\n      else if(algo === 'CRC32') hash = pthCRC32(line);\r\n      else{\r\n        try{ var buf = await crypto.subtle.digest(algo, this.strToAB(line)); hash = this.bufToHex(buf); }\r\n        catch(e){ hash = 'error'; }\r\n      }\r\n      results.push({input:line, hash:hash, algo:algo});\r\n      this.batchData.push({input:line, hash:hash, algo:algo});\r\n    }\r\n    \/* Render table *\/\r\n    var html = '<table class=\"hs-batch-table\"><thead><tr><th>#<\/th><th>Input<\/th><th>' + algo + '<\/th><\/tr><\/thead><tbody>';\r\n    for(var j=0;j<results.length;j++){\r\n      html += '<tr><td>'+(j+1)+'<\/td><td>'+results[j].input.replace(\/<\/g,'&lt;')+'<\/td><td>'+results[j].hash+'<\/td><\/tr>';\r\n    }\r\n    html += '<\/tbody><\/table>';\r\n    if(resultsDiv) resultsDiv.innerHTML = html;\r\n    var dlBtn = this.g('hs-batch-dl');\r\n    if(dlBtn) dlBtn.style.display = 'inline-flex';\r\n    this.toast('\u2705 Hashed ' + results.length + ' items');\r\n  },\r\n\r\n  downloadBatchCSV: function(){\r\n    if(!this.batchData.length){ this.toast('Run batch first'); return; }\r\n    var csv = 'Input,' + this.batchData[0].algo + '\\n';\r\n    this.batchData.forEach(function(row){\r\n      csv += '\"' + row.input.replace(\/\"\/g,'\"\"') + '\",' + row.hash + '\\n';\r\n    });\r\n    var a = document.createElement('a');\r\n    a.href = URL.createObjectURL(new Blob([csv],{type:'text\/csv'}));\r\n    a.download = 'pth-batch-hashes.csv';\r\n    a.click();\r\n    this.toast('\u2705 CSV downloaded');\r\n  },\r\n\r\n  \/* \u2500\u2500 Encoder \u2500\u2500 *\/\r\n  ENC_DESCS: {\r\n    base64:'Encode\/decode text as Base64 (RFC 4648)',\r\n    url:'Percent-encode\/decode URL characters',\r\n    hex:'Convert text to\/from hexadecimal bytes',\r\n    binary:'Convert text to\/from binary (8-bit per char)',\r\n    html:'Escape\/unescape HTML special characters',\r\n    rot13:'ROT13 substitution cipher (encode = decode)',\r\n    morse:'Convert text to\/from Morse code (\u00b7 \u2212)'\r\n  },\r\n\r\n  encode: function(){\r\n    var mode = this.encMode;\r\n    var input = this.g('hs-enc-in') ? this.g('hs-enc-in').value : '';\r\n    var out = '';\r\n    try{\r\n      if(mode==='base64') out = btoa(unescape(encodeURIComponent(input)));\r\n      else if(mode==='url') out = encodeURIComponent(input);\r\n      else if(mode==='hex'){\r\n        for(var i=0;i<input.length;i++) out += ('00'+input.charCodeAt(i).toString(16)).slice(-2);\r\n      }\r\n      else if(mode==='binary'){\r\n        var parts = [];\r\n        for(var i2=0;i2<input.length;i2++) parts.push(('00000000'+input.charCodeAt(i2).toString(2)).slice(-8));\r\n        out = parts.join(' ');\r\n      }\r\n      else if(mode==='html'){\r\n        out = input.replace(\/&\/g,'&amp;').replace(\/<\/g,'&lt;').replace(\/>\/g,'&gt;').replace(\/\"\/g,'&quot;').replace(\/'\/g,'&#39;');\r\n      }\r\n      else if(mode==='rot13'){\r\n        out = input.replace(\/[a-zA-Z]\/g,function(c){return String.fromCharCode((c<='Z'?90:122)>=c.charCodeAt(0)+13?c.charCodeAt(0)+13:c.charCodeAt(0)-13);});\r\n      }\r\n      else if(mode==='morse'){\r\n        out = input.toUpperCase().split('').map(function(ch){return MORSE_MAP[ch]||'?';}).join(' ');\r\n      }\r\n    }catch(e){ out = 'Error: ' + e.message; }\r\n    var outEl = this.g('hs-enc-out'); if(outEl) outEl.value = out;\r\n  },\r\n\r\n  decode: function(){\r\n    var mode = this.encMode;\r\n    var input = this.g('hs-enc-in') ? this.g('hs-enc-in').value : '';\r\n    var out = '';\r\n    try{\r\n      if(mode==='base64') out = decodeURIComponent(escape(atob(input.trim())));\r\n      else if(mode==='url') out = decodeURIComponent(input);\r\n      else if(mode==='hex'){\r\n        var hex = input.replace(\/\\s\/g,'');\r\n        for(var i=0;i<hex.length;i+=2) out += String.fromCharCode(parseInt(hex.substr(i,2),16));\r\n      }\r\n      else if(mode==='binary'){\r\n        var bins = input.trim().split(\/\\s+\/);\r\n        bins.forEach(function(b){ out += String.fromCharCode(parseInt(b,2)); });\r\n      }\r\n      else if(mode==='html'){\r\n        var d2 = document.createElement('div'); d2.innerHTML = input; out = d2.textContent;\r\n      }\r\n      else if(mode==='rot13'){\r\n        out = input.replace(\/[a-zA-Z]\/g,function(c){return String.fromCharCode((c<='Z'?90:122)>=c.charCodeAt(0)+13?c.charCodeAt(0)+13:c.charCodeAt(0)-13);});\r\n      }\r\n      else if(mode==='morse'){\r\n        out = input.split(' ').map(function(s){return s==='\/'?' ':(MORSE_REV[s]||'?');}).join('');\r\n      }\r\n    }catch(e){ out = 'Error: ' + e.message; }\r\n    var outEl = this.g('hs-enc-out'); if(outEl) outEl.value = out;\r\n  },\r\n\r\n  \/* \u2500\u2500 Copy \u2500\u2500 *\/\r\n  copyText: function(id){\r\n    var el = this.g(id); if(!el) return;\r\n    var val = el.value || el.textContent;\r\n    if(!val){ this.toast('Nothing to copy'); return; }\r\n    try{\r\n      navigator.clipboard.writeText(val).then(function(){ });\r\n    }catch(e){ var ta=document.createElement('textarea');ta.value=val;document.body.appendChild(ta);ta.select();document.execCommand('copy');ta.remove(); }\r\n    this.toast('\ud83d\udccb Copied!');\r\n  },\r\n\r\n  copyAllHashes: function(){\r\n    var algos = [['SHA-256','sha256'],['SHA-512','sha512'],['SHA-384','sha384'],['SHA-1','sha1'],['MD5','md5'],['CRC32','crc32']];\r\n    var self = this;\r\n    var lines = [];\r\n    algos.forEach(function(a){\r\n      var el = self.g('hs-out-'+a[1]);\r\n      if(el && el.value) lines.push(a[0]+': '+el.value);\r\n    });\r\n    if(!lines.length){ this.toast('Hash some text first'); return; }\r\n    try{ navigator.clipboard.writeText(lines.join('\\n')); }catch(e){}\r\n    this.toast('\ud83d\udccb All ' + lines.length + ' hashes copied!');\r\n  },\r\n\r\n  \/* \u2500\u2500 Switch tab \u2500\u2500 *\/\r\n  switchTab: function(tab){\r\n    var self = this;\r\n    this.tab = tab;\r\n    document.querySelectorAll('#pth-hs .hs-tab').forEach(function(b){\r\n      var on = b.getAttribute('data-tab') === tab;\r\n      b.classList.toggle('on', on);\r\n      b.setAttribute('aria-selected', on ? 'true' : 'false');\r\n    });\r\n    document.querySelectorAll('#pth-hs .hs-panel').forEach(function(p){\r\n      p.classList.toggle('on', p.id === 'hs-p-'+tab);\r\n    });\r\n  },\r\n\r\n  \/* \u2500\u2500 File compare \u2500\u2500 *\/\r\n  compareFiles: function(){\r\n    var ha = this.g('hs-hash-a') ? this.g('hs-hash-a').value : '';\r\n    var hb = this.g('hs-hash-b') ? this.g('hs-hash-b').value : '';\r\n    var res = this.g('hs-cmp-result');\r\n    if(!ha || !hb){ if(res){ res.style.display='none'; } return; }\r\n    var match = ha === hb;\r\n    if(res){\r\n      res.textContent = match ? '\u2705 Files are IDENTICAL (same SHA-256 hash)' : '\u274c Files are DIFFERENT (hashes do not match)';\r\n      res.style.background = match ? '#ecfdf5' : '#fef2f2';\r\n      res.style.border = '1px solid ' + (match ? '#a7f3d0' : '#fecaca');\r\n      res.style.color = match ? '#047857' : '#dc2626';\r\n      res.style.display = 'block';\r\n    }\r\n  },\r\n\r\n  \/* \u2500\u2500 INIT \u2500\u2500 *\/\r\n  init: function(){\r\n    var self = this;\r\n\r\n    \/* Tab switching *\/\r\n    document.querySelectorAll('#pth-hs .hs-tab').forEach(function(btn){\r\n      btn.addEventListener('click', function(){ self.switchTab(btn.getAttribute('data-tab')); });\r\n    });\r\n\r\n    \/* Text hasher \u2014 real-time *\/\r\n    var textIn = this.g('hs-text-in');\r\n    if(textIn){\r\n      textIn.addEventListener('input', function(){\r\n        self.updateEntropy(textIn.value);\r\n        clearTimeout(self._ht);\r\n        self._ht = setTimeout(function(){ self.hashText(textIn.value); }, 300);\r\n      });\r\n    }\r\n\r\n    \/* Format buttons *\/\r\n    document.querySelectorAll('#hs-p-text .hs-fmt-btn').forEach(function(btn){\r\n      btn.addEventListener('click', function(){\r\n        document.querySelectorAll('#hs-p-text .hs-fmt-btn').forEach(function(b){ b.classList.remove('on'); b.setAttribute('aria-pressed','false'); });\r\n        btn.classList.add('on');\r\n        btn.setAttribute('aria-pressed','true');\r\n        self.fmt = btn.getAttribute('data-fmt');\r\n        if(textIn && textIn.value) self.hashText(textIn.value);\r\n      });\r\n    });\r\n\r\n    \/* Copy all hashes *\/\r\n    this.bev(this.g('hs-copy-all'), 'click', function(){ self.copyAllHashes(); });\r\n    this.bev(this.g('hs-clear-text'), 'click', function(){ if(textIn) textIn.value=''; self.hashText(''); self.updateEntropy(''); });\r\n\r\n    \/* Individual copy buttons *\/\r\n    document.querySelectorAll('[data-cp]').forEach(function(btn){\r\n      btn.addEventListener('click', function(){ self.copyText(btn.getAttribute('data-cp')); });\r\n    });\r\n\r\n    \/* File tab \u2014 single mode *\/\r\n    var fileDrop = this.g('hs-file-drop');\r\n    var fileInput = this.g('hs-file-input');\r\n    if(fileDrop){\r\n      fileDrop.addEventListener('click', function(){ if(fileInput) fileInput.click(); });\r\n      fileDrop.addEventListener('keydown', function(e){ if(e.key==='Enter'||e.key===' '){ e.preventDefault(); if(fileInput) fileInput.click(); }});\r\n      fileDrop.addEventListener('dragover', function(e){ e.preventDefault(); fileDrop.classList.add('drag'); });\r\n      fileDrop.addEventListener('dragleave', function(){ fileDrop.classList.remove('drag'); });\r\n      fileDrop.addEventListener('drop', function(e){\r\n        e.preventDefault(); fileDrop.classList.remove('drag');\r\n        if(e.dataTransfer.files[0]) self.processFile(e.dataTransfer.files[0],'hs-fout-','hs-file-name','hs-file-size');\r\n      });\r\n    }\r\n    if(fileInput) fileInput.addEventListener('change', function(){ if(fileInput.files[0]) self.processFile(fileInput.files[0],'hs-fout-','hs-file-name','hs-file-size'); });\r\n\r\n    \/* File mode toggle *\/\r\n    this.bev(this.g('hs-file-mode-single'), 'click', function(){\r\n      self.g('hs-file-single').style.display='';\r\n      self.g('hs-file-compare').style.display='none';\r\n      self.g('hs-file-mode-single').classList.add('on'); self.g('hs-file-mode-single').setAttribute('aria-pressed','true');\r\n      self.g('hs-file-mode-compare').classList.remove('on'); self.g('hs-file-mode-compare').setAttribute('aria-pressed','false');\r\n    });\r\n    this.bev(this.g('hs-file-mode-compare'), 'click', function(){\r\n      self.g('hs-file-single').style.display='none';\r\n      self.g('hs-file-compare').style.display='';\r\n      self.g('hs-file-mode-compare').classList.add('on'); self.g('hs-file-mode-compare').setAttribute('aria-pressed','true');\r\n      self.g('hs-file-mode-single').classList.remove('on'); self.g('hs-file-mode-single').setAttribute('aria-pressed','false');\r\n    });\r\n\r\n    \/* File compare A\/B *\/\r\n    var wireCompareFile = function(dropId, inputId, hashId, nameId){\r\n      var drop = self.g(dropId), inp = self.g(inputId);\r\n      if(drop){\r\n        drop.addEventListener('click', function(){ if(inp) inp.click(); });\r\n        drop.addEventListener('dragover', function(e){ e.preventDefault(); drop.classList.add('drag'); });\r\n        drop.addEventListener('dragleave', function(){ drop.classList.remove('drag'); });\r\n        drop.addEventListener('drop', function(e){\r\n          e.preventDefault(); drop.classList.remove('drag');\r\n          if(e.dataTransfer.files[0]) processCompareFile(e.dataTransfer.files[0], hashId, nameId, drop);\r\n        });\r\n      }\r\n      if(inp) inp.addEventListener('change', function(){ if(inp.files[0]) processCompareFile(inp.files[0], hashId, nameId, drop); });\r\n    };\r\n    var processCompareFile = function(file, hashId, nameId, drop){\r\n      if(drop) drop.textContent = '\u23f3 Hashing...';\r\n      var r = new FileReader();\r\n      r.onload = async function(e){\r\n        try{\r\n          var buf = await crypto.subtle.digest('SHA-256', e.target.result);\r\n          var hex = self.bufToHex(buf);\r\n          var el = self.g(hashId); if(el) el.value = hex;\r\n          var nel = self.g(nameId); if(nel) nel.textContent = file.name + ' (' + self.formatSize(file.size) + ')';\r\n          if(drop) drop.textContent = '\u2705 ' + file.name;\r\n          self.compareFiles();\r\n        }catch(err){ if(drop) drop.textContent = '\u274c Error'; }\r\n      };\r\n      r.readAsArrayBuffer(file);\r\n    };\r\n    wireCompareFile('hs-drop-a','hs-file-a','hs-hash-a','hs-name-a');\r\n    wireCompareFile('hs-drop-b','hs-file-b','hs-hash-b','hs-name-b');\r\n\r\n    \/* Verifier *\/\r\n    this.bev(this.g('hs-verify-btn'), 'click', function(){ self.verifyHash(); });\r\n    this.bev(this.g('hs-ver-clear'), 'click', function(){\r\n      ['hs-ver-text','hs-ver-hash'].forEach(function(id){ var el=self.g(id);if(el)el.value=''; });\r\n      var vr=self.g('hs-verify-result');if(vr)vr.style.display='none';\r\n      var dh=self.g('hs-diff-hint');if(dh)dh.style.display='none';\r\n    });\r\n    this.bev(this.g('hs-auto-detect'), 'click', function(){\r\n      var hash = self.g('hs-ver-hash') ? self.g('hs-ver-hash').value.trim() : '';\r\n      var algo = self.autoDetectAlgo(hash);\r\n      var det = self.g('hs-detected-algo');\r\n      if(algo){\r\n        if(det) det.textContent = '\u2192 Detected: ' + algo;\r\n        var sel = self.g('hs-ver-algo'); if(sel) sel.value = algo;\r\n        self.toast('\ud83d\udd0d Detected: ' + algo);\r\n      } else {\r\n        if(det) det.textContent = '\u2192 Unknown length';\r\n        self.toast('\u26a0\ufe0f Cannot auto-detect \u2014 unusual length', 3000);\r\n      }\r\n    });\r\n\r\n    \/* HMAC algo buttons *\/\r\n    document.querySelectorAll('[data-hmac]').forEach(function(btn){\r\n      btn.addEventListener('click', function(){\r\n        document.querySelectorAll('[data-hmac]').forEach(function(b){ b.classList.remove('on'); b.setAttribute('aria-pressed','false'); });\r\n        btn.classList.add('on'); btn.setAttribute('aria-pressed','true');\r\n        self.hmacAlgo = btn.getAttribute('data-hmac');\r\n      });\r\n    });\r\n    this.bev(this.g('hs-hmac-btn'), 'click', function(){ self.generateHMAC(); });\r\n\r\n    \/* Batch *\/\r\n    this.bev(this.g('hs-batch-run'), 'click', function(){ self.runBatch(); });\r\n    this.bev(this.g('hs-batch-dl'), 'click', function(){ self.downloadBatchCSV(); });\r\n    this.bev(this.g('hs-batch-clear'), 'click', function(){\r\n      var bi=self.g('hs-batch-in');if(bi)bi.value='';\r\n      var br=self.g('hs-batch-results');if(br)br.innerHTML='';\r\n      var bd=self.g('hs-batch-dl');if(bd)bd.style.display='none';\r\n      self.batchData=[];\r\n    });\r\n\r\n    \/* Encoder *\/\r\n    document.querySelectorAll('[data-enc]').forEach(function(btn){\r\n      btn.addEventListener('click', function(){\r\n        document.querySelectorAll('[data-enc]').forEach(function(b){ b.classList.remove('on'); b.setAttribute('aria-pressed','false'); });\r\n        btn.classList.add('on'); btn.setAttribute('aria-pressed','true');\r\n        self.encMode = btn.getAttribute('data-enc');\r\n        var desc = self.g('hs-enc-desc');\r\n        if(desc) desc.textContent = self.ENC_DESCS[self.encMode] || '';\r\n        \/* Clear output on mode switch *\/\r\n        var outEl = self.g('hs-enc-out'); if(outEl) outEl.value = '';\r\n      });\r\n    });\r\n    this.bev(this.g('hs-enc-encode'), 'click', function(){ self.encode(); });\r\n    this.bev(this.g('hs-enc-decode'), 'click', function(){ self.decode(); });\r\n    this.bev(this.g('hs-enc-swap'), 'click', function(){\r\n      var inp = self.g('hs-enc-in'), out = self.g('hs-enc-out');\r\n      if(!inp||!out) return;\r\n      var tmp = inp.value; inp.value = out.value; out.value = tmp;\r\n    });\r\n    this.bev(this.g('hs-enc-copy'), 'click', function(){ self.copyText('hs-enc-out'); });\r\n    this.bev(this.g('hs-enc-clear'), 'click', function(){\r\n      ['hs-enc-in','hs-enc-out'].forEach(function(id){ var el=self.g(id);if(el)el.value=''; });\r\n    });\r\n    \/* Set initial encoder description *\/\r\n    var desc0 = this.g('hs-enc-desc');\r\n    if(desc0) desc0.textContent = this.ENC_DESCS['base64'];\r\n\r\n    \/* Keyboard shortcut: Enter in verify hash input *\/\r\n    var verHash = this.g('hs-ver-hash');\r\n    if(verHash) verHash.addEventListener('keydown', function(e){ if(e.key==='Enter'){ e.preventDefault(); self.verifyHash(); }});\r\n\r\n    self.toast('\ud83d\udd10 PTH Secure Hash Studio v4.0 ready!', 2000);\r\n\r\n    \/* \u2500\u2500 SAMPLE BUTTONS \u2500\u2500 *\/\r\n    var BATCH_SAMPLES = {\r\n      fruits: 'apple\\nbanana\\ncherry\\nmango\\nstrawberry',\r\n      passwords: 'password123\\n123456\\nqwerty\\nadmin\\nletmein',\r\n      urls: 'https:\/\/schoolict.net\/tools\\nhttps:\/\/google.com\\nhttps:\/\/github.com\\nhttps:\/\/cloudflare.com',\r\n      numbers: '1\\n2\\n3\\n4\\n5\\n6\\n7\\n8\\n9\\n10'\r\n    };\r\n\r\n    var VERIFY_SAMPLES = {\r\n      hello:        {text:'hello',         hash:'2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824', algo:'SHA-256'},\r\n      password123:  {text:'password123',   hash:'ef92b778bafe771e89245b89ecbc08a44a4e166c06659911881f383d4473e94f', algo:'SHA-256'},\r\n      PrimeToolHub: {text:'PrimeToolHub',  hash:'',                                                                   algo:'SHA-256'}\r\n    };\r\n\r\n    \/* Text Hasher samples *\/\r\n    document.querySelectorAll('[data-sample-text]').forEach(function(btn){\r\n      btn.addEventListener('click', function(){\r\n        var txt = btn.getAttribute('data-sample-text');\r\n        var el = self.g('hs-text-in'); if(!el) return;\r\n        el.value = txt;\r\n        el.dispatchEvent(new Event('input'));\r\n        self.toast('Sample loaded: ' + (txt.substring(0,20)||(txt===''?'(empty)':'')) + (txt.length>20?'...':''));\r\n      });\r\n    });\r\n\r\n    \/* Verifier samples *\/\r\n    document.querySelectorAll('[data-sample-verify]').forEach(function(btn){\r\n      btn.addEventListener('click', async function(){\r\n        var key = btn.getAttribute('data-sample-verify');\r\n        var s = VERIFY_SAMPLES[key]; if(!s) return;\r\n        var textEl = self.g('hs-ver-text'), hashEl = self.g('hs-ver-hash'), algoEl = self.g('hs-ver-algo');\r\n        if(textEl) textEl.value = s.text;\r\n        if(algoEl) algoEl.value = s.algo;\r\n        \/* Compute hash if not hardcoded *\/\r\n        var hash = s.hash;\r\n        if(!hash){\r\n          try{\r\n            var buf = await crypto.subtle.digest(s.algo, self.strToAB(s.text));\r\n            hash = self.bufToHex(buf);\r\n          }catch(e){ hash = pthMD5(s.text); }\r\n        }\r\n        if(hashEl) hashEl.value = hash;\r\n        var det = self.g('hs-detected-algo');\r\n        if(det) det.textContent = '';\r\n        self.toast('Sample loaded \u2014 click Verify Hash!');\r\n      });\r\n    });\r\n\r\n    \/* HMAC samples *\/\r\n    document.querySelectorAll('[data-sample-hmac-msg]').forEach(function(btn){\r\n      btn.addEventListener('click', function(){\r\n        var msg = btn.getAttribute('data-sample-hmac-msg');\r\n        var key = btn.getAttribute('data-sample-hmac-key');\r\n        var msgEl = self.g('hs-hmac-text'), keyEl = self.g('hs-hmac-key');\r\n        if(msgEl) msgEl.value = msg;\r\n        if(keyEl) keyEl.value = key;\r\n        self.toast('Sample loaded \u2014 click Generate HMAC!');\r\n      });\r\n    });\r\n\r\n    \/* Batch samples *\/\r\n    document.querySelectorAll('[data-sample-batch]').forEach(function(btn){\r\n      btn.addEventListener('click', function(){\r\n        var key = btn.getAttribute('data-sample-batch');\r\n        var data2 = BATCH_SAMPLES[key]; if(!data2) return;\r\n        var el = self.g('hs-batch-in'); if(el) el.value = data2;\r\n        self.toast('Sample loaded \u2014 click Hash All!');\r\n      });\r\n    });\r\n\r\n    \/* Encoder samples *\/\r\n    document.querySelectorAll('[data-sample-enc]').forEach(function(btn){\r\n      btn.addEventListener('click', function(){\r\n        var txt = btn.getAttribute('data-sample-enc');\r\n        var el = self.g('hs-enc-in'); if(el) el.value = txt;\r\n        var outEl = self.g('hs-enc-out'); if(outEl) outEl.value = '';\r\n        \/* Auto-switch mode if SOS (hint morse) *\/\r\n        if(txt === 'SOS'){\r\n          document.querySelectorAll('[data-enc]').forEach(function(b){\r\n            var isMorse = b.getAttribute('data-enc')==='morse';\r\n            b.classList.toggle('on', isMorse);\r\n            b.setAttribute('aria-pressed', isMorse ? 'true' : 'false');\r\n          });\r\n          self.encMode = 'morse';\r\n          var desc = self.g('hs-enc-desc');\r\n          if(desc) desc.textContent = self.ENC_DESCS['morse'];\r\n        }\r\n        self.toast('Sample loaded \u2014 click Encode!');\r\n      });\r\n    });\r\n  }\r\n};\r\n\r\n\/* Bootstrap *\/\r\nfunction pthHSRun(){\r\n  if(!window.pthHashApp.ok && document.getElementById('pth-hs')){\r\n    window.pthHashApp.ok = true;\r\n    window.pthHashApp.init();\r\n  }\r\n}\r\npthHSRun();\r\ndocument.addEventListener('DOMContentLoaded', pthHSRun);\r\nwindow.addEventListener('load', function(){ setTimeout(pthHSRun, 50); });\r\nsetTimeout(pthHSRun, 300);\r\nvar _hsMO = new MutationObserver(function(){ pthHSRun(); });\r\nif(document.body) _hsMO.observe(document.body, {childList:true, subtree:true});\r\nsetTimeout(function(){ _hsMO.disconnect(); }, 10000);\r\n\r\n})();\r\n<\/script>\n\n\n\n\n<style>\n.pth-feat-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(260px,1fr));gap:18px;margin:28px 0}\n.pth-feat-box{background:#f8fafc;border:1px solid #e2e8f0;border-radius:12px;padding:20px 22px}\n.pth-feat-title{font-size:1rem;font-weight:800;color:#0f172a;margin:0 0 9px;display:flex;align-items:center;gap:7px}\n.pth-feat-text{font-size:.9rem;color:#1e293b;font-weight:500;line-height:1.75;margin:0}\n.pth-steps-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(210px,1fr));gap:14px;margin-top:14px}\n.pth-step{background:#fff;border:1px solid #e2e8f0;border-radius:10px;padding:16px 18px}\n.pth-step-num{width:30px;height:30px;border-radius:50%;background:#1d4ed8;color:#fff;font-weight:900;font-size:.9rem;display:flex;align-items:center;justify-content:center;margin-bottom:8px}\n.pth-step-name{font-size:.88rem;font-weight:800;color:#0f172a;margin-bottom:4px}\n.pth-step-desc{font-size:.8rem;color:#334155;font-weight:500;line-height:1.6;margin:0}\n.pth-hash-ex{background:#0f172a;border-radius:8px;padding:12px 16px;margin:10px 0;font-family:'Courier New',monospace;font-size:.75rem;color:#a5f3fc;overflow-x:auto;white-space:nowrap}\n.pth-hash-ex .hl{color:#fde68a}\n<\/style>\n \n<div class=\"pth-feat-grid\">\n \n\n <div class=\"pth-feat-box\">\n  <p class=\"pth-feat-title\">\ud83d\udd0d Verifier \u2014 Auto-Detect + Diff Position<\/p>\n  <p class=\"pth-feat-text\">Paste any known hash and the original text. Click <strong>\ud83d\udd0d Auto-detect Algo<\/strong> to identify the algorithm by hash length automatically \u2014 32 chars = MD5, 64 = SHA-256, 128 = SHA-512. The tool re-computes the hash and reports \u2705 MATCH or \u274c MISMATCH. On a mismatch, it shows the exact character position where the two hashes first differ \u2014 useful when debugging copy-paste truncation or encoding mismatches.<\/p>\n <\/div>\n \n <div class=\"pth-feat-box\">\n  <p class=\"pth-feat-title\">\ud83d\udd10 HMAC \u2014 Web Crypto API, 4 Algorithms<\/p>\n  <p class=\"pth-feat-text\">Enter a message and a secret key. Choose HMAC-SHA256, HMAC-SHA512, HMAC-SHA384, or HMAC-SHA1. The output appears in both HEX and BASE64 format. Everything runs through the browser&#8217;s native <code>crypto.subtle.sign()<\/code> \u2014 the same cryptographic engine used by HTTPS and JWT libraries. Three pre-loaded samples cover the most common real-world HMAC use cases: API request signing, webhook payload verification, and JWT-style session tokens.<\/p>\n <\/div>\n \n <div class=\"pth-feat-box\">\n  <p class=\"pth-feat-title\">\ud83d\udccb Batch CSV \u2014 Hash Many Items at Once<\/p>\n  <p class=\"pth-feat-text\">Paste a list of words, passwords, emails, or URLs \u2014 one per line. Select any algorithm and click <strong>\u26a1 Hash All<\/strong>. Results appear in a scrollable table with input and hash side by side. Click <strong>\u2b07 Download CSV<\/strong> to export the full table as a comma-separated file with columns for input and hash. Four sample sets load instantly: fruits, common passwords, URLs, and numbers 1\u201310.<\/p>\n <\/div>\n \n <div class=\"pth-feat-box\">\n  <p class=\"pth-feat-title\">\ud83d\udd04 Encoder \u2014 7 Modes Including ROT13 and Morse<\/p>\n  <p class=\"pth-feat-text\">Seven encoding modes in one panel: <strong>Base64<\/strong> (RFC 4648), <strong>URL Encode<\/strong> (percent-encoding), <strong>Hex<\/strong> (byte-by-byte), <strong>Binary<\/strong> (8-bit per character), <strong>HTML Entities<\/strong> (&amp;amp; escaping), <strong>ROT13<\/strong> (Caesar cipher), and <strong>Morse Code<\/strong> (dot-dash). Every mode supports both encode and decode, plus a Swap button to reverse the direction. Clicking the SOS sample automatically switches to Morse Code mode. For standalone full-featured Base64 work, see the <a href=\"\/free-base64-encoder-decoder-utf-8-supported\/\" rel=\"noopener\">PTH Base64 Encoder\/Decoder<\/a>.<\/p>\n <\/div>\n \n<\/div>\n \n<h2 style=\"font-size:1.3rem;font-weight:800;color:#0f172a;margin:32px 0 6px;\">How to Use PTH Secure Hash Studio<\/h2>\n<p style=\"font-size:.85rem;color:#475569;margin:0 0 12px;\">Four steps from opening the tool to a verified hash or HMAC output.<\/p>\n \n<div class=\"pth-steps-grid\">\n <div class=\"pth-step\">\n  <div class=\"pth-step-num\">1<\/div>\n  <div class=\"pth-step-name\">Open the Tool and Pick a Tab<\/div>\n  <p class=\"pth-step-desc\">The <strong>\u270f\ufe0f Text Hasher<\/strong> tab opens by default, ready to hash immediately. For file integrity checking, click <strong>\ud83d\udcc1 File Checksum<\/strong>. For API or webhook authentication, click <strong>\ud83d\udd10 HMAC<\/strong>. For verifying a known hash from a software download page, click <strong>\ud83d\udd0d Verifier<\/strong>.<\/p>\n <\/div>\n <div class=\"pth-step\">\n  <div class=\"pth-step-num\">2<\/div>\n  <div class=\"pth-step-name\">Load a Sample or Enter Your Own Data<\/div>\n  <p class=\"pth-step-desc\">Every tab has purple <strong>Try:<\/strong> sample buttons above the input area. Click any sample to auto-fill the inputs with a realistic example. For the Verifier tab, clicking a sample pre-fills both the original text and the known SHA-256 hash \u2014 just click <strong>Verify Hash<\/strong> to see it in action before using your own data.<\/p>\n <\/div>\n <div class=\"pth-step\">\n  <div class=\"pth-step-num\">3<\/div>\n  <div class=\"pth-step-name\">Choose Format and Copy<\/div>\n  <p class=\"pth-step-desc\">In the Text Hasher, use the <strong>HEX \/ HEX UPPER \/ BASE64<\/strong> toggle buttons below the entropy meter to switch output format before copying. Click <strong>\ud83d\udccb<\/strong> next to any individual algorithm to copy just that hash, or click <strong>\ud83d\udccb Copy All<\/strong> to copy all six hashes at once in a labelled multi-line format.<\/p>\n <\/div>\n <div class=\"pth-step\">\n  <div class=\"pth-step-num\">4<\/div>\n  <div class=\"pth-step-name\">Export or Download<\/div>\n  <p class=\"pth-step-desc\">In the Batch CSV tab, after hashing a list, click <strong>\u2b07 Download CSV<\/strong> to save the input-hash table as a <code>.csv<\/code> file. For the Encoder tab, click <strong>\ud83d\udccb Copy Output<\/strong> to copy the encoded result. All outputs stay local \u2014 nothing is sent to PrimeToolHub&#8217;s server at any point.<\/p>\n <\/div>\n<\/div>\n\n\n\n<p class=\"wp-block-paragraph\">Last updated: July 2026<\/p>\n\n\n<!-- schoolictTool-il:641-2098 -->\n\n<p class=\"schoolictTool-il wp-block-paragraph\">Learn how it works: <a href=\"https:\/\/schoolict.net\/tools\/free-offline-secure-hash-generator-article\/\">How Cryptographic Hashes Protect File Integrity<\/a>.<\/p>\n\n<!-- \/schoolictTool-il:641-2098 -->\n\n\n<h2 id=\"\ud83d\udd34-what-this-tool-actually-does-that-others-dont\" class=\"wp-block-heading\">\ud83d\udd34 What This Tool Actually Does That Others Don&#8217;t<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Most online hash generators give you a text field and one algorithm. PTH Secure Hash Studio combines six use cases \u2014 text hashing, file integrity checking, hash verification, HMAC generation, batch processing, and text encoding \u2014 in a single browser page. None of your input reaches a server. The SHA-2 family of algorithms runs through the browser&#8217;s built-in&nbsp;<code>crypto.subtle.digest()<\/code>&nbsp;Web Crypto API. MD5 and CRC32 run through pure-JavaScript implementations that are loaded once with the page. This means the tool works offline after the initial page load, with no internet dependency for the hashing operations themselves.<\/p>\n\n\n\n<h3 id=\"real-input-\u2192-real-output-examples\" class=\"wp-block-heading\">Real Input \u2192 Real Output Examples<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Here are exact outputs for the sample strings the tool uses, so you can confirm the results match when testing:<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">SHA-256(&#8216;hello&#8217;) = 2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824<br>SHA-256(&#8216;Hello, World!&#8217;) = dffd6021bb2bd5b0af676290809ec3a53191dd81c7f70a4b28688a362182986f<br>SHA-256(&#8216;password123&#8217;) = ef92b778bafe771e89245b89ecbc08a44a4e166c06659911881f383d4473e94f<br>MD5(&#8216;hello&#8217;) = 5d41402abc4b2a76b9719d911017c592<br>MD5(&#8216;password123&#8217;) = 482c811da5d5b4bc6d497ffa98491e38<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Notice that SHA-256(&#8216;password123&#8217;) is 64 hexadecimal characters long (256 bits), while MD5(&#8216;password123&#8217;) is 32 characters (128 bits). Also notice that SHA-256(&#8216;hello&#8217;) and SHA-256(&#8216;Hello, World!&#8217;) share no visible pattern even though the inputs are similar \u2014 this avalanche effect is a core property of cryptographic hash functions and one of the reasons they are trusted for integrity verification.<\/p>\n\n\n\n<h3 id=\"\ud83d\udfe1-the-hmac-tab-when-a-hash-alone-is-not-enough\" class=\"wp-block-heading\">\ud83d\udfe1 The HMAC Tab \u2014 When a Hash Alone Is Not Enough<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\"><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">A plain SHA-256 hash tells you that data has not changed. But it does not tell you who created it. Anyone who knows the data can compute the same hash. HMAC solves this by mixing a secret key into the hash computation using the formula defined in RFC 2104. Only someone who knows both the data and the secret key can produce the correct HMAC value.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The most practical use of HMAC in web development is webhook verification. When GitHub, Stripe, or Shopify sends a webhook to your server, they include an HMAC-SHA256 signature of the request body in a header. Your server re-computes the HMAC using your shared secret and compares it to the header value. If they match, the webhook came from the genuine service \u2014 not from someone spoofing a request to your endpoint. The Webhook sample in the HMAC tab uses exactly this pattern: a payload string containing amount, currency, and timestamp fields, signed with a shared secret.<\/p>\n\n\n\n<h3 id=\"\ud83d\udfe2-file-checksum-why-this-matters-more-than-you-think\" class=\"wp-block-heading\">\ud83d\udfe2 File Checksum \u2014 Why This Matters More Than You Think<\/h3>\n\n\n<figure class=\"pth-article-figure pth-img-left\" style=\"float:left; width:600px; max-width:100%; margin:4px 28px 16px 0; clear:left;\"><img decoding=\"async\" src=\"https:\/\/schoolict.net\/tools\/wp-content\/uploads\/2026\/07\/pth-file-checksum-compare-800x447.jpeg\" alt=\"File Checksum\" width=\"600\" height=\"338\" loading=\"lazy\" data-no-lazy=\"1\" class=\"pth-article-img\" style=\"width:100%;height:auto;display:block;border-radius:10px;border:1px solid #e2e8f0;\"><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">When you download a Linux ISO, a WordPress theme zip, or a Python installer from the internet, the download page usually lists a SHA-256 checksum. The purpose is to give you a way to confirm that the file you received is byte-for-byte identical to the file the server published. If a malicious actor intercepts the download and replaces the installer with one that contains malware, the SHA-256 hash will be completely different \u2014 the avalanche effect means even one byte change produces an entirely different 64-character output.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Drop your downloaded file into the File Checksum tab, select SHA-256, and compare the output against the hash on the official download page. The Compare Two Files mode is useful when you have two copies of a file \u2014 such as a backup and an original \u2014 and need to confirm they are identical without opening or reading their content.<\/p>\n\n\n\n<h3 id=\"\ud83d\udd34-the-encoder-tab-rot-13-and-morse-are-not-cryptography\" class=\"wp-block-heading\">\ud83d\udd34 The Encoder Tab \u2014 ROT13 and Morse Are Not Cryptography<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">It is worth being explicit about what the Encoder tab is and is not. Base64, URL encoding, Hex, Binary, and HTML Entities are encoding schemes \u2014 reversible transformations that change how data is represented without adding any secrecy. ROT13 and Morse Code are also purely encoding: anyone who knows the encoding can decode the output instantly. None of these provide security or privacy. They are included because they are genuinely useful for development work \u2014 Base64 for embedding binary data in JSON, URL encoding for query strings, HTML entities for preventing XSS, ROT13 for obfuscating spoiler text, Morse for signal testing. If you need actual encryption, that is a different tool for a different purpose.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">For dedicated Base64 work with UTF-8 support, image encoding, and batch file encoding, see the&nbsp;<a href=\"https:\/\/schoolict.net\/tools\/free-base64-encoder-decoder-utf-8-supported\/\">PTH Base64 Encoder\/Decoder Studio<\/a>. For percent-encoding and URL decoding with query parameter parsing, see the&nbsp;<a href=\"https:\/\/schoolict.net\/tools\/universal-url-encoder-decoder\/\">PTH URL Encoder\/Decoder<\/a>.<\/p>\n\n\n\n\n \n<style>\n.pth-faq-wrap{margin-top:44px;margin-bottom:36px}\n.pth-faq-head{font-size:1.7rem;font-weight:800;color:#0f172a;margin:0 0 22px;padding-bottom:8px;border-bottom:2px solid #e2e8f0}\n.pth-faq-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(260px,1fr));gap:18px}\n.pth-faq-card{background:#f8fafc;padding:22px;border-radius:11px;border:1px solid #e2e8f0}\n.pth-faq-q{color:#0f172a;font-size:.95rem;font-weight:700;margin:0 0 10px;line-height:1.4}\n.pth-faq-a{margin:0;font-size:.88rem;color:#1e293b;line-height:1.65;font-weight:500}\n<\/style>\n \n<div class=\"pth-faq-wrap\">\n <h2 class=\"pth-faq-head\">\u2753 Frequently Asked Questions<\/h2>\n <div class=\"pth-faq-grid\">\n \n  <div class=\"pth-faq-card\">\n   <p class=\"pth-faq-q\">Is my text or file sent to a server when I hash it?<\/p>\n   <p class=\"pth-faq-a\">No. All hashing runs inside your browser. SHA-256, SHA-512, SHA-384, and SHA-1 use the Web Crypto API&#8217;s <code>crypto.subtle.digest()<\/code>, which is a browser-native function. MD5 and CRC32 run through pure-JavaScript implementations loaded with the page. No data leaves your device at any point \u2014 not even to PrimeToolHub&#8217;s server.<\/p>\n  <\/div>\n \n  <div class=\"pth-faq-card\">\n   <p class=\"pth-faq-q\">What is the difference between SHA-256 and MD5?<\/p>\n   <p class=\"pth-faq-a\">SHA-256 produces a 256-bit (64-character hex) output and is cryptographically secure for integrity verification and digital signatures. MD5 produces a 128-bit (32-character hex) output and is fast, but is no longer considered cryptographically secure \u2014 collision attacks against MD5 have been demonstrated. Use SHA-256 or SHA-512 for anything security-related. MD5 is still widely used for non-security checksums where speed matters and collision resistance is not required.<\/p>\n  <\/div>\n \n  <div class=\"pth-faq-card\">\n   <p class=\"pth-faq-q\">How does auto-detect algorithm work in the Verifier?<\/p>\n   <p class=\"pth-faq-a\">The tool detects the algorithm by measuring the hex string length: 8 chars = CRC32, 32 = MD5, 40 = SHA-1, 64 = SHA-256, 96 = SHA-384, 128 = SHA-512. This works because each algorithm produces a fixed-length output. Click the purple <strong>\ud83d\udd0d Auto-detect Algo<\/strong> button in the Verifier tab after pasting the known hash \u2014 the algorithm dropdown updates automatically.<\/p>\n  <\/div>\n \n  <div class=\"pth-faq-card\">\n   <p class=\"pth-faq-q\">What does the entropy meter show in the Text Hasher?<\/p>\n   <p class=\"pth-faq-a\">The entropy meter calculates Shannon entropy \u2014 a measure of how unpredictable the characters in your input are. It counts character frequency, applies the entropy formula, and shows total bits. A short or repetitive string like &#8220;aaaaaa&#8221; scores very low (red bar). A long, random string scores high (green bar). This is useful for quickly checking whether a password, token, or key has sufficient randomness before hashing it.<\/p>\n  <\/div>\n \n  <div class=\"pth-faq-card\">\n   <p class=\"pth-faq-q\">Can I hash a large file like a 4GB ISO?<\/p>\n   <p class=\"pth-faq-a\">The tool reads files using the browser&#8217;s FileReader API, which loads the file into memory before hashing. Available memory limits the practical maximum file size \u2014 in most desktop browsers, files up to 500 MB work reliably. Very large files (2 GB+) may cause the browser to slow or run out of memory depending on your device. For large files, a command-line tool such as <code>sha256sum<\/code> (Linux\/Mac) or <code>CertUtil -hashfile<\/code> (Windows) is more suitable.<\/p>\n  <\/div>\n \n  <div class=\"pth-faq-card\">\n   <p class=\"pth-faq-q\">What is HMAC and when should I use it?<\/p>\n   <p class=\"pth-faq-a\">HMAC (Hash-based Message Authentication Code) is a hash computed using both the message content and a secret key. Use it when you need to prove that a message was created by someone who knows the shared secret \u2014 for example, signing API requests, verifying webhook payloads, or creating tamper-proof session tokens. A plain SHA-256 hash only tells you the data has not changed; HMAC also proves it came from the expected sender.<\/p>\n  <\/div>\n \n  <div class=\"pth-faq-card\">\n   <p class=\"pth-faq-q\">Why does hashing the same text twice give the same result?<\/p>\n   <p class=\"pth-faq-a\">Hash functions are deterministic \u2014 the same input always produces the same output. This is the property that makes them useful for verification: you can compute the hash of a file, share it publicly, and anyone who downloads the file can verify it by computing the hash themselves and comparing. If anything in the file changed \u2014 even a single bit \u2014 the hash would be completely different.<\/p>\n  <\/div>\n \n  <div class=\"pth-faq-card\">\n   <p class=\"pth-faq-q\">How does the Batch CSV tab work?<\/p>\n   <p class=\"pth-faq-a\">Paste a list of items \u2014 passwords, emails, words, or any strings \u2014 one per line in the text area. Select an algorithm from the dropdown (SHA-256, MD5, CRC32, etc.) and click <strong>\u26a1 Hash All<\/strong>. The tool processes each line and displays results in a table. Click <strong>\u2b07 Download CSV<\/strong> to save the full table as a <code>.csv<\/code> file with two columns: Input and Hash. Useful for generating password hash tables for testing or auditing a list of values.<\/p>\n  <\/div>\n \n  <div class=\"pth-faq-card\">\n   <p class=\"pth-faq-q\">Is ROT13 a form of encryption?<\/p>\n   <p class=\"pth-faq-a\">No. ROT13 is a substitution cipher where each letter is shifted 13 positions in the alphabet. It provides no cryptographic security \u2014 anyone who recognises ROT13 can decode it instantly. It is used historically for hiding spoilers in forums, obfuscating puzzle answers, and as a learning example in programming. The Encoder tab includes it because it is a frequently requested text transformation, not because it offers privacy.<\/p>\n  <\/div>\n \n <\/div>\n<\/div>\n \n","protected":false},"excerpt":{"rendered":"<p>Free Secure Hash Generator &amp; File Checksum (SHA-256, MD5) Instantly generate MD5, SHA-1, SHA-256, and SHA-512 hashes from text or verify file checksums completely offline securely in your browser. \ud83d\udd0d Verifier \u2014 Auto-Detect + Diff Position Paste any known hash and the original text. Click \ud83d\udd0d Auto-detect Algo to identify the algorithm by hash length &#8230; <a title=\"Free Secure Hash Generator &amp; File Checksum (SHA-256, MD5)\" class=\"read-more\" href=\"https:\/\/schoolict.net\/tools\/free-secure-hash-generator\/\" aria-label=\"Read more about Free Secure Hash Generator &amp; File Checksum (SHA-256, MD5)\">Read more<\/a><\/p>\n","protected":false},"author":1,"featured_media":648,"parent":0,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"","meta":{"footnotes":""},"class_list":["post-641","page","type-page","status-publish","has-post-thumbnail"],"_links":{"self":[{"href":"https:\/\/schoolict.net\/tools\/wp-json\/wp\/v2\/pages\/641","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/schoolict.net\/tools\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/schoolict.net\/tools\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/schoolict.net\/tools\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/schoolict.net\/tools\/wp-json\/wp\/v2\/comments?post=641"}],"version-history":[{"count":1,"href":"https:\/\/schoolict.net\/tools\/wp-json\/wp\/v2\/pages\/641\/revisions"}],"predecessor-version":[{"id":7239,"href":"https:\/\/schoolict.net\/tools\/wp-json\/wp\/v2\/pages\/641\/revisions\/7239"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/schoolict.net\/tools\/wp-json\/wp\/v2\/media\/648"}],"wp:attachment":[{"href":"https:\/\/schoolict.net\/tools\/wp-json\/wp\/v2\/media?parent=641"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}