crypto.go 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138
  1. package ntlmssp
  2. import (
  3. "bytes"
  4. "crypto/hmac"
  5. "crypto/md5"
  6. "encoding/binary"
  7. "fmt"
  8. "strings"
  9. "unicode/utf16"
  10. "imuslab.com/smb/driver/mod/smb/encoder"
  11. "golang.org/x/crypto/md4"
  12. )
  13. /*
  14. func convertUTF16ToLittleEndianBytes(u []uint16) []byte {
  15. b := make([]byte, 2*len(u))
  16. for index, value := range u {
  17. binary.LittleEndian.PutUint16(b[index*2:], value)
  18. }
  19. return b
  20. }
  21. // s.encode('utf-16le')
  22. func UnicodeEncode(p string) []byte {
  23. return convertUTF16ToLittleEndianBytes(utf16.Encode([]rune(p)))
  24. }
  25. func MD4(data []byte) []byte {
  26. h := md4.New()
  27. h.Write(data)
  28. return h.Sum(nil)
  29. }
  30. func MD5(data []byte) []byte {
  31. h := md5.New()
  32. h.Write(data)
  33. return h.Sum(nil)
  34. }
  35. func HMAC_MD5(key, data []byte) []byte {
  36. h := hmac.New(md5.New, key)
  37. h.Write(data)
  38. return h.Sum(nil)
  39. }
  40. // Version 2 of NTLM hash function
  41. func Ntowfv2(password, user, domain string) []byte {
  42. return HMAC_MD5(MD4(UnicodeEncode(password)), UnicodeEncode(strings.ToUpper(user)+domain))
  43. }
  44. // Same as NTOWFv2
  45. func Lmowfv2(password, user, domain string) []byte {
  46. return Ntowfv2(password, user, domain)
  47. }
  48. */
  49. func Ntowfv1(pass string) []byte {
  50. hash := md4.New()
  51. hash.Write(encoder.ToUnicode(pass))
  52. return hash.Sum(nil)
  53. }
  54. func Ntowfv2(pass, user, domain string) []byte {
  55. h := hmac.New(md5.New, Ntowfv1(pass))
  56. h.Write(encoder.ToUnicode(strings.ToUpper(user) + domain))
  57. return h.Sum(nil)
  58. }
  59. func Lmowfv2(pass, user, domain string) []byte {
  60. return Ntowfv2(pass, user, domain)
  61. }
  62. func NTPasswordHash(password string) string {
  63. input := utf16.Encode([]rune(password))
  64. h := md4.New()
  65. if err := binary.Write(h, binary.LittleEndian, input); err != nil {
  66. // these are all in-memory operations with no error modes,
  67. // but just in case
  68. panic(fmt.Errorf("impossible error hashing password: %w", err))
  69. }
  70. output := h.Sum(nil)
  71. // encode to conventional uppercase hex
  72. return fmt.Sprintf("%X", output)
  73. }
  74. func ComputeResponseNTLMv2(nthash, lmhash, clientChallenge, serverChallenge, timestamp, serverName []byte) []byte {
  75. temp := []byte{1, 1}
  76. temp = append(temp, 0, 0, 0, 0, 0, 0)
  77. temp = append(temp, timestamp...)
  78. temp = append(temp, clientChallenge...)
  79. temp = append(temp, 0, 0, 0, 0)
  80. temp = append(temp, serverName...)
  81. temp = append(temp, 0, 0, 0, 0)
  82. return ComputeResponseNTLMv2Check(nthash, serverChallenge, temp)
  83. // h := hmac.New(md5.New, nthash)
  84. // h.Write(append(serverChallenge, temp...))
  85. // ntproof := h.Sum(nil)
  86. // return append(ntproof, temp...)
  87. }
  88. func ComputeResponseNTLMv2Check(nthash, serverChallenge, temp []byte) []byte {
  89. h := hmac.New(md5.New, nthash)
  90. h.Write(append(serverChallenge, temp...))
  91. ntproof := h.Sum(nil)
  92. return append(ntproof, temp...)
  93. }
  94. func NTLMv2KeyExchangeKey(ntProofStr []byte, password, name, domain string) []byte {
  95. // // https://msdn.microsoft.com/en-us/library/cc236700.aspx
  96. // byte[] responseKeyNT = NTLMCryptography.NTOWFv2(password, message.UserName, message.DomainName);
  97. // byte[] ntProofStr = ByteReader.ReadBytes(message.NtChallengeResponse, 0, 16);
  98. // sessionBaseKey = new HMACMD5(responseKeyNT).ComputeHash(ntProofStr);
  99. // keyExchangeKey = sessionBaseKey;
  100. nthash := Ntowfv2(password, name, domain)
  101. h := hmac.New(md5.New, nthash)
  102. h.Write(ntProofStr)
  103. return h.Sum(nil)
  104. }
  105. func NTLMv2Verify(serverChallenge, clientChallengeStructurePadded []byte, password, name, domain string) []byte {
  106. nthash := Ntowfv2(password, name, domain)
  107. // logx.Printf("nthash: %v", nthash)
  108. temp := clientChallengeStructurePadded
  109. w := bytes.NewBuffer(make([]byte, 0))
  110. binary.Write(w, binary.LittleEndian, serverChallenge)
  111. h := hmac.New(md5.New, nthash)
  112. h.Write(append(serverChallenge, temp...))
  113. return h.Sum(nil)
  114. // return ComputeResponseNTLMv2Check(nthash, w.Bytes(), tail)
  115. }