Created
February 11, 2025 12:30
-
-
Save Alceatraz/b16e9f658efedf19c1ca4698dbc3982b to your computer and use it in GitHub Desktop.
APR1(Apache MD5) htpasswd generate in JavaScript
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <!doctype html> | |
| <html lang="en"> | |
| <head> | |
| <meta charset="UTF-8"/> | |
| <title>APR1 HTPasswd Generator</title> | |
| </head> | |
| <body> | |
| <p>See console</p> | |
| </body> | |
| <script> | |
| const md5_ff = (a, b, c, d, x, s, t) => md5_cmn((b & c) | ((~b) & d), a, b, x, s, t); | |
| const md5_gg = (a, b, c, d, x, s, t) => md5_cmn((b & d) | (c & (~d)), a, b, x, s, t); | |
| const md5_hh = (a, b, c, d, x, s, t) => md5_cmn(b ^ c ^ d, a, b, x, s, t); | |
| const md5_ii = (a, b, c, d, x, s, t) => md5_cmn(c ^ (b | (~d)), a, b, x, s, t); | |
| const md5_cmn = (q, a, b, x, s, t) => safe_add(bit_rol(safe_add(safe_add(a, q), safe_add(x, t)), s), b); | |
| const bit_rol = (num, cnt) => (num << cnt) | (num >>> (32 - cnt)); | |
| const safe_add = (x, y) => { | |
| const lsw = (x & 0xFFFF) + (y & 0xFFFF); | |
| const msw = (x >> 16) + (y >> 16) + (lsw >> 16); | |
| return (msw << 16) | (lsw & 0xFFFF); | |
| }; | |
| const md5_core = (x, len) => { | |
| x[len >> 5] |= 0x80 << ((len) % 32); | |
| x[(((len + 64) >>> 9) << 4) + 14] = len; | |
| let a = 1732584193; | |
| let b = -271733879; | |
| let c = -1732584194; | |
| let d = 271733878; | |
| for (let i = 0; i < x.length; i += 16) { | |
| const old_a = a; | |
| const old_b = b; | |
| const old_c = c; | |
| const old_d = d; | |
| a = md5_ff(a, b, c, d, x[i + 0x0], 0x7, -0x28955b88); | |
| d = md5_ff(d, a, b, c, x[i + 0x1], 12, -389564586); | |
| c = md5_ff(c, d, a, b, x[i + 0x2], 17, 606105819); | |
| b = md5_ff(b, c, d, a, x[i + 0x3], 22, -1044525330); | |
| a = md5_ff(a, b, c, d, x[i + 0x4], 7, -176418897); | |
| d = md5_ff(d, a, b, c, x[i + 0x5], 12, 1200080426); | |
| c = md5_ff(c, d, a, b, x[i + 0x6], 17, -1473231341); | |
| b = md5_ff(b, c, d, a, x[i + 0x7], 22, -45705983); | |
| a = md5_ff(a, b, c, d, x[i + 0x8], 7, 1770035416); | |
| d = md5_ff(d, a, b, c, x[i + 0x9], 12, -1958414417); | |
| c = md5_ff(c, d, a, b, x[i + 0xa], 17, -42063); | |
| b = md5_ff(b, c, d, a, x[i + 0xB], 22, -1990404162); | |
| a = md5_ff(a, b, c, d, x[i + 0xC], 7, 1804603682); | |
| d = md5_ff(d, a, b, c, x[i + 0xd], 12, -40341101); | |
| c = md5_ff(c, d, a, b, x[i + 0xE], 17, -1502002290); | |
| b = md5_ff(b, c, d, a, x[i + 0xF], 22, 1236535329); | |
| a = md5_gg(a, b, c, d, x[i + 0x1], 5, -165796510); | |
| d = md5_gg(d, a, b, c, x[i + 0x6], 9, -1069501632); | |
| c = md5_gg(c, d, a, b, x[i + 0xB], 14, 643717713); | |
| b = md5_gg(b, c, d, a, x[i + 0x0], 0x14, -373897302); | |
| a = md5_gg(a, b, c, d, x[i + 0x5], 5, -701558691); | |
| d = md5_gg(d, a, b, c, x[i + 0xA], 9, 38016083); | |
| c = md5_gg(c, d, a, b, x[i + 0xF], 14, -660478335); | |
| b = md5_gg(b, c, d, a, x[i + 0x4], 20, -405537848); | |
| a = md5_gg(a, b, c, d, x[i + 0x9], 5, 568446438); | |
| d = md5_gg(d, a, b, c, x[i + 0xE], 9, -1019803690); | |
| c = md5_gg(c, d, a, b, x[i + 0x3], 14, -187363961); | |
| b = md5_gg(b, c, d, a, x[i + 0x8], 20, 1163531501); | |
| a = md5_gg(a, b, c, d, x[i + 0xD], 5, -1444681467); | |
| d = md5_gg(d, a, b, c, x[i + 0x2], 9, -51403784); | |
| c = md5_gg(c, d, a, b, x[i + 0x7], 14, 1735328473); | |
| b = md5_gg(b, c, d, a, x[i + 0xC], 20, -1926607734); | |
| a = md5_hh(a, b, c, d, x[i + 0x5], 4, -378558); | |
| d = md5_hh(d, a, b, c, x[i + 0x8], 11, -2022574463); | |
| c = md5_hh(c, d, a, b, x[i + 0xB], 16, 1839030562); | |
| b = md5_hh(b, c, d, a, x[i + 0xE], 23, -35309556); | |
| a = md5_hh(a, b, c, d, x[i + 0x1], 4, -1530992060); | |
| d = md5_hh(d, a, b, c, x[i + 0x4], 11, 1272893353); | |
| c = md5_hh(c, d, a, b, x[i + 0x7], 16, -155497632); | |
| b = md5_hh(b, c, d, a, x[i + 0xA], 23, -1094730640); | |
| a = md5_hh(a, b, c, d, x[i + 0xD], 4, 681279174); | |
| d = md5_hh(d, a, b, c, x[i + 0x0], 11, -358537222); | |
| c = md5_hh(c, d, a, b, x[i + 0x3], 16, -722521979); | |
| b = md5_hh(b, c, d, a, x[i + 0x6], 23, 76029189); | |
| a = md5_hh(a, b, c, d, x[i + 0x9], 4, -640364487); | |
| d = md5_hh(d, a, b, c, x[i + 0xC], 11, -421815835); | |
| c = md5_hh(c, d, a, b, x[i + 0xF], 16, 530742520); | |
| b = md5_hh(b, c, d, a, x[i + 0x2], 23, -995338651); | |
| a = md5_ii(a, b, c, d, x[i + 0x0], 6, -198630844); | |
| d = md5_ii(d, a, b, c, x[i + 0x7], 10, 1126891415); | |
| c = md5_ii(c, d, a, b, x[i + 0xE], 15, -1416354905); | |
| b = md5_ii(b, c, d, a, x[i + 0x5], 21, -57434055); | |
| a = md5_ii(a, b, c, d, x[i + 0xC], 6, 1700485571); | |
| d = md5_ii(d, a, b, c, x[i + 0x3], 10, -1894986606); | |
| c = md5_ii(c, d, a, b, x[i + 0xA], 15, -1051523); | |
| b = md5_ii(b, c, d, a, x[i + 0x1], 21, -2054922799); | |
| a = md5_ii(a, b, c, d, x[i + 0x8], 6, 1873313359); | |
| d = md5_ii(d, a, b, c, x[i + 0xF], 10, -30611744); | |
| c = md5_ii(c, d, a, b, x[i + 0x6], 15, -1560198380); | |
| b = md5_ii(b, c, d, a, x[i + 0xD], 21, 1309151649); | |
| a = md5_ii(a, b, c, d, x[i + 0x4], 6, -145523070); | |
| d = md5_ii(d, a, b, c, x[i + 0xB], 10, -1120210379); | |
| c = md5_ii(c, d, a, b, x[i + 0x2], 15, 718787259); | |
| b = md5_ii(b, c, d, a, x[i + 0x9], 21, -343485551); | |
| a = safe_add(a, old_a); | |
| b = safe_add(b, old_b); | |
| c = safe_add(c, old_c); | |
| d = safe_add(d, old_d); | |
| } | |
| return Array(a, b, c, d); | |
| }; | |
| const md5_hash = content => { | |
| const length = content.length; | |
| const inputLength = length >> 2; | |
| const input = Array(inputLength); | |
| let i; | |
| for (i = 0; i < inputLength; i++) { | |
| input[i] = 0; | |
| } | |
| for (i = 0; i < length * 8; i += 8) { | |
| input[i >> 5] |= (content.charCodeAt(i / 8) & 0xFF) << (i % 32); | |
| } | |
| const hash = md5_core(input, length * 8); | |
| let output = ''; | |
| for (let i = 0; i < hash.length * 32; i += 8) { | |
| output += String.fromCharCode((hash[i >> 5] >>> (i % 32)) & 0xFF); | |
| } | |
| return output; | |
| }; | |
| //========================================================================== | |
| const secureRandom = array => { | |
| const browser_crypto = window.crypto || window["msCrypto"]; | |
| browser_crypto.getRandomValues(array); | |
| } | |
| //========================================================================== | |
| const APR1_MARK = '$apr1$'; | |
| const APR1_CHAR = "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; | |
| const apr1_char = (data, size) => { | |
| if (size === undefined) { | |
| size = 4; | |
| } | |
| let temp = ''; | |
| for (let i = 0; i < size; i++) { | |
| temp = temp + APR1_CHAR.charAt(data & 0x3F); | |
| data = data >>> 6; | |
| } | |
| return temp; | |
| } | |
| function apr1_salt() { | |
| const secret = new Uint32Array(2); | |
| secureRandom(secret); | |
| return apr1_char(secret[0]) + apr1_char(secret[1]) | |
| } | |
| const apr1_hash = (password, salt = apr1_salt()) => { | |
| let input = password + APR1_MARK + salt; | |
| const hash_psp = md5_hash(password + salt + password); | |
| for (let i = password.length; i > 0; i = i - 16) { | |
| input += hash_psp.substring(0, i > 16 ? 16 : i) | |
| } | |
| for (let i = password.length; i !== 0; i >>= 1) { | |
| input += 1 & i ? String.fromCharCode(0) : password.charAt(0); | |
| } | |
| let roll = md5_hash(input); | |
| for (let i = 0; i < 1000; ++i) { | |
| let temp = i & 1 ? password : roll.substring(0, 0x10); | |
| if (i % 3) temp += salt; | |
| if (i % 7) temp += password; | |
| temp += i & 1 ? roll.substring(0, 0x10) : password; | |
| roll = md5_hash(temp); | |
| } | |
| const data = []; | |
| for (let i = 0; i < roll.length; i++) { | |
| data.push(roll.charCodeAt(i)); | |
| } | |
| let result = APR1_MARK + salt + "$"; | |
| result += apr1_char(data[0x0] << 16 | data[0x6] << 8 | data[0xC]); | |
| result += apr1_char(data[0x1] << 16 | data[0x7] << 8 | data[0xD]); | |
| result += apr1_char(data[0x2] << 16 | data[0x8] << 8 | data[0xE]); | |
| result += apr1_char(data[0x3] << 16 | data[0x9] << 8 | data[0xF]); | |
| result += apr1_char(data[0x4] << 16 | data[0xA] << 8 | data[0x5]); | |
| result += apr1_char(data[0xB], 2); | |
| return result; | |
| }; | |
| //============================================================================ | |
| const randomString = size => { | |
| let temp = ''; | |
| for (let i = 0; i < size; i++) { | |
| temp += APR1_CHAR.charAt(Math.random() * 64); | |
| } | |
| return temp; | |
| } | |
| window.onload = () => { | |
| const username = 'demo'; | |
| const password = randomString(8); | |
| const hash1 = apr1_hash(password); | |
| const hash2 = apr1_hash(password, '00000000'); | |
| console.info('username ' + username); | |
| console.info('password ' + password); | |
| console.info('hash1 ' + hash1); | |
| console.info('hash2 ' + hash2); | |
| } | |
| </script> | |
| </html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment