package ntlmssp import ( "bytes" "crypto/hmac" "crypto/md5" "encoding/binary" "fmt" "strings" "unicode/utf16" "imuslab.com/smb/driver/mod/smb/encoder" "golang.org/x/crypto/md4" ) /* func convertUTF16ToLittleEndianBytes(u []uint16) []byte { b := make([]byte, 2*len(u)) for index, value := range u { binary.LittleEndian.PutUint16(b[index*2:], value) } return b } // s.encode('utf-16le') func UnicodeEncode(p string) []byte { return convertUTF16ToLittleEndianBytes(utf16.Encode([]rune(p))) } func MD4(data []byte) []byte { h := md4.New() h.Write(data) return h.Sum(nil) } func MD5(data []byte) []byte { h := md5.New() h.Write(data) return h.Sum(nil) } func HMAC_MD5(key, data []byte) []byte { h := hmac.New(md5.New, key) h.Write(data) return h.Sum(nil) } // Version 2 of NTLM hash function func Ntowfv2(password, user, domain string) []byte { return HMAC_MD5(MD4(UnicodeEncode(password)), UnicodeEncode(strings.ToUpper(user)+domain)) } // Same as NTOWFv2 func Lmowfv2(password, user, domain string) []byte { return Ntowfv2(password, user, domain) } */ func Ntowfv1(pass string) []byte { hash := md4.New() hash.Write(encoder.ToUnicode(pass)) return hash.Sum(nil) } func Ntowfv2(pass, user, domain string) []byte { h := hmac.New(md5.New, Ntowfv1(pass)) h.Write(encoder.ToUnicode(strings.ToUpper(user) + domain)) return h.Sum(nil) } func Lmowfv2(pass, user, domain string) []byte { return Ntowfv2(pass, user, domain) } func NTPasswordHash(password string) string { input := utf16.Encode([]rune(password)) h := md4.New() if err := binary.Write(h, binary.LittleEndian, input); err != nil { // these are all in-memory operations with no error modes, // but just in case panic(fmt.Errorf("impossible error hashing password: %w", err)) } output := h.Sum(nil) // encode to conventional uppercase hex return fmt.Sprintf("%X", output) } func ComputeResponseNTLMv2(nthash, lmhash, clientChallenge, serverChallenge, timestamp, serverName []byte) []byte { temp := []byte{1, 1} temp = append(temp, 0, 0, 0, 0, 0, 0) temp = append(temp, timestamp...) temp = append(temp, clientChallenge...) temp = append(temp, 0, 0, 0, 0) temp = append(temp, serverName...) temp = append(temp, 0, 0, 0, 0) return ComputeResponseNTLMv2Check(nthash, serverChallenge, temp) // h := hmac.New(md5.New, nthash) // h.Write(append(serverChallenge, temp...)) // ntproof := h.Sum(nil) // return append(ntproof, temp...) } func ComputeResponseNTLMv2Check(nthash, serverChallenge, temp []byte) []byte { h := hmac.New(md5.New, nthash) h.Write(append(serverChallenge, temp...)) ntproof := h.Sum(nil) return append(ntproof, temp...) } func NTLMv2KeyExchangeKey(ntProofStr []byte, password, name, domain string) []byte { // // https://msdn.microsoft.com/en-us/library/cc236700.aspx // byte[] responseKeyNT = NTLMCryptography.NTOWFv2(password, message.UserName, message.DomainName); // byte[] ntProofStr = ByteReader.ReadBytes(message.NtChallengeResponse, 0, 16); // sessionBaseKey = new HMACMD5(responseKeyNT).ComputeHash(ntProofStr); // keyExchangeKey = sessionBaseKey; nthash := Ntowfv2(password, name, domain) h := hmac.New(md5.New, nthash) h.Write(ntProofStr) return h.Sum(nil) } func NTLMv2Verify(serverChallenge, clientChallengeStructurePadded []byte, password, name, domain string) []byte { nthash := Ntowfv2(password, name, domain) // logx.Printf("nthash: %v", nthash) temp := clientChallengeStructurePadded w := bytes.NewBuffer(make([]byte, 0)) binary.Write(w, binary.LittleEndian, serverChallenge) h := hmac.New(md5.New, nthash) h.Write(append(serverChallenge, temp...)) return h.Sum(nil) // return ComputeResponseNTLMv2Check(nthash, w.Bytes(), tail) }