From ef58efff8ba93f50f307656ea6b4a50bd3e6b993 Mon Sep 17 00:00:00 2001 From: cyclone <34043806+cyclone-github@users.noreply.github.com> Date: Tue, 18 Aug 2026 16:06:54 -0500 Subject: [PATCH] add modes: LDAP SHA/SSHA --- CHANGELOG.md | 1 + README.md | 3 +++ hashgen.go | 72 +++++++++++++++++++++++++++++++++++++++------------- 3 files changed, 59 insertions(+), 17 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 300eb49..65d623e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ add mode: sm3crypt -m 35100 add mode: cmiyc (KoreLogic CMIYC 2026 contest algo) add modes: Streebog/GOST 2012 -m 11700, 11750, 11760, 11800, 11850, 11860 add modes: SHA-384 UTF-16LE -m 10830, 10840, 10870 +add modes: LDAP SHA/SSHA -m 101, 1411, 1711 ``` ### v1.3.1; 2026-04-13 ``` diff --git a/README.md b/README.md index 80cfd19..2af8d5b 100644 --- a/README.md +++ b/README.md @@ -104,6 +104,7 @@ To use hashgen, type your mode, wordlist input & hash output files with a simple | md6-512 | | | **`SHA1`** | | | sha1 | 100 | +| ldap-sha | 101 (Netscape LDAP {SHA}) | | sha1sha1 | 4500 | | sha1passsalt | 110 | | sha1saltpass | 120 | @@ -121,6 +122,7 @@ To use hashgen, type your mode, wordlist input & hash output files with a simple | sha256 | 1400 | | sha256passsalt | 1410 | | sha256saltpass | 1420 | +| ssha256 | 1411 (LDAP {SSHA256}) | | 1430 | (hashcat compatible sha256 utf16le($pass).$salt) | | 1440 | (hashcat compatible sha256 $salt.utf16le($pass)) | | 1450 | (hashcat compatible HMAC-SHA256 key = $pass) | @@ -135,6 +137,7 @@ To use hashgen, type your mode, wordlist input & hash output files with a simple | sha512 | 1700 | | sha512passsalt | 1710 | | sha512saltpass | 1720 | +| ssha512 | 1711 (LDAP {SSHA512}) | | 1730 | (hashcat compatible sha512 utf16le($pass).$salt) | | 1740 | (hashcat compatible sha512 $salt.utf16le($pass)) | | 1750 | (hashcat compatible HMAC-SHA512 key = $pass) | diff --git a/hashgen.go b/hashgen.go index ca534a1..27dbeda 100644 --- a/hashgen.go +++ b/hashgen.go @@ -76,6 +76,7 @@ v1.3.2; 2026-08-18 add mode: cmiyc (KoreLogic CMIYC 2026 contest algo) add modes: Streebog/GOST 2012 -m 11700, 11750, 11760, 11800, 11850, 11860 add modes: SHA-384 UTF-16LE -m 10830, 10840, 10870 + add modes: LDAP SHA/SSHA -m 101, 1411, 1711 */ func versionFunc() { @@ -142,6 +143,7 @@ func helpFunc() { "phpass\t\t400\n" + "ripemd-160\t6000\n" + "sha1\t\t100\n" + + "ldap-sha\t101 (Netscape LDAP {SHA})\n" + "sha1sha1\t4500\n" + "sha1passsalt\t110\n" + "sha1saltpass\t120\n" + @@ -156,6 +158,7 @@ func helpFunc() { "sha256\t\t1400\n" + "sha256passsalt\t1410\n" + "sha256saltpass\t1420\n" + + "ssha256\t\t1411 (LDAP {SSHA256})\n" + "1430\t\t(hashcat compatible sha256 utf16le($pass).$salt)\n" + "1440\t\t(hashcat compatible sha256 $salt.utf16le($pass))\n" + "1470\t\t(hashcat compatible sha256 utf16le($pass))\n" + @@ -169,6 +172,7 @@ func helpFunc() { "sha512\t\t1700\n" + "sha512passsalt\t1710\n" + "sha512saltpass\t1720\n" + + "ssha512\t\t1711 (LDAP {SSHA512})\n" + "1730\t\t(hashcat compatible sha512 utf16le($pass).$salt)\n" + "1740\t\t(hashcat compatible sha512 $salt.utf16le($pass))\n" + "1770\t\t(hashcat compatible sha512 utf16le($pass))\n" + @@ -303,6 +307,54 @@ func utf16LEPassStrict(data []byte) ([]byte, bool) { return out, true } +// LDAP SHA/SSHA family -m 101 / 111 / 1411 / 1711 +func ldapSHA(password []byte, mode string, saltRaw []byte) string { + if mode == "101" || mode == "ldap-sha" { + digest := sha1.Sum(password) + return "{SHA}" + base64.StdEncoding.EncodeToString(digest[:]) + } + + salt := saltRaw + if salt == nil { + salt = make([]byte, 8) + if !readRand(salt) { + return "" + } + } + + var prefix string + var digest []byte + + switch mode { + case "111", "ssha": + prefix = "{SSHA}" + h := sha1.New() + _, _ = h.Write(password) + _, _ = h.Write(salt) + digest = h.Sum(nil) + case "1411", "ssha256": + prefix = "{SSHA256}" + h := sha256.New() + _, _ = h.Write(password) + _, _ = h.Write(salt) + digest = h.Sum(nil) + case "1711", "ssha512": + prefix = "{SSHA512}" + h := sha512.New() + _, _ = h.Write(password) + _, _ = h.Write(salt) + digest = h.Sum(nil) + default: + return "" + } + + payload := make([]byte, 0, len(digest)+len(salt)) + payload = append(payload, digest...) + payload = append(payload, salt...) + + return prefix + base64.StdEncoding.EncodeToString(payload) +} + // sha384 UTF-16LE family -m 10830 / 10840 / 10870 func sha384UTF16(password []byte, mode string, saltRaw []byte) string { pwU16, ok := utf16LEPassStrict(password) @@ -1637,23 +1689,9 @@ func hashBytesDispatch(hashFunc string, data []byte, cost int) (string, bool) { h := sha1.Sum(data) return hex.EncodeToString(h[:]), true - // ssha -m 111 - case "ssha", "111": - var salt [8]byte - if !readRand(salt[:]) { - return "", true - } - - h := sha1.New() - _, _ = h.Write(data) - _, _ = h.Write(salt[:]) - digest := h.Sum(nil) - - payload := make([]byte, 0, len(digest)+len(salt)) - payload = append(payload, digest...) - payload = append(payload, salt[:]...) - - return "{SSHA}" + base64.StdEncoding.EncodeToString(payload), true + // LDAP SHA/SSHA -m 101 / 111 / 1411 / 1711 + case "ldap-sha", "101", "ssha", "111", "ssha256", "1411", "ssha512", "1711": + return ldapSHA(data, hashFunc, nil), true // -m 110 sha1(pass.salt), -m 120 sha1(salt.pass) case "110", "sha1passsalt", "120", "sha1saltpass":