initial commit

This commit is contained in:
Conor Hunt
2012-11-09 15:39:05 -05:00
commit cb96a1fb85
29 changed files with 3109 additions and 0 deletions

259
src/ntlm/ntlmv2.go Normal file
View File

@@ -0,0 +1,259 @@
// Receve an Authenticate message and authenticate the user
package ntlm
import (
"bytes"
"errors"
"ntlm/messages"
"strings"
)
/*******************************
Shared Session Data and Methods
*******************************/
type V2Session struct {
SessionData
}
func (n *V2Session) SetUserInfo(username string, password string, domain string) {
n.user = username
n.password = password
n.userDomain = domain
}
func (n *V2Session) SetMode(mode Mode) {
n.mode = mode
}
func (n *V2Session) fetchResponseKeys() (err error) {
n.responseKeyLM = lmowfv2(n.user, n.password, n.userDomain)
n.responseKeyNT = ntowfv2(n.user, n.password, n.userDomain)
return
}
// Define ComputeResponse(NegFlg, ResponseKeyNT, ResponseKeyLM, CHALLENGE_MESSAGE.ServerChallenge, ClientChallenge, Time, ServerName)
// ServerNameBytes - The NtChallengeResponseFields.NTLMv2_RESPONSE.NTLMv2_CLIENT_CHALLENGE.AvPairs field structure of the AUTHENTICATE_MESSAGE payload.
func (n *V2Session) computeExpectedResponses(timestamp []byte, avPairBytes []byte) (err error) {
temp := concat([]byte{0x01}, []byte{0x01}, zeroBytes(6), timestamp, n.clientChallenge, zeroBytes(4), avPairBytes, zeroBytes(4))
ntProofStr := hmacMd5(n.responseKeyNT, concat(n.serverChallenge, temp))
n.ntChallengeResponse = concat(ntProofStr, temp)
n.lmChallengeResponse = concat(hmacMd5(n.responseKeyLM, concat(n.serverChallenge, n.clientChallenge)), n.clientChallenge)
n.sessionBaseKey = hmacMd5(n.responseKeyNT, ntProofStr)
return
}
func (n *V2Session) computeKeyExchangeKey() (err error) {
n.keyExchangeKey = n.sessionBaseKey
return
}
func (n *V2Session) calculateKeys() (err error) {
n.clientSigningKey = signKey(n.negotiateFlags, n.exportedSessionKey, "Client")
n.serverSigningKey = signKey(n.negotiateFlags, n.exportedSessionKey, "Server")
n.clientSealingKey = sealKey(n.negotiateFlags, n.exportedSessionKey, "Client")
n.serverSealingKey = sealKey(n.negotiateFlags, n.exportedSessionKey, "Server")
return
}
func (n *V2Session) Seal(message []byte) ([]byte, error) {
return nil, nil
}
func (n *V2Session) Sign(message []byte) ([]byte, error) {
return nil, nil
}
func (n *V2Session) Mac(message []byte,sequenceNumber int) ([]byte, error) {
return nil, nil
}
/**************
Server Session
**************/
type V2ServerSession struct {
V2Session
}
func (n *V2ServerSession) ProcessNegotiateMessage(nm *messages.Negotiate) (err error) {
n.negotiateMessage = nm
return
}
func (n *V2ServerSession) GenerateChallengeMessage() (cm *messages.Challenge, err error) {
// TODO: Generate this challenge message
return
}
func (n *V2ServerSession) ProcessAuthenticateMessage(am *messages.Authenticate) (err error) {
n.authenticateMessage = am
n.negotiateFlags = am.NegotiateFlags
n.clientChallenge = am.ClientChallenge()
n.encryptedRandomSessionKey = am.EncryptedRandomSessionKey.Payload
err = n.fetchResponseKeys()
if err != nil {
return err
}
timestamp := am.NtlmV2Response.NtlmV2ClientChallenge.TimeStamp
avPairsBytes := am.NtlmV2Response.NtlmV2ClientChallenge.AvPairs.Bytes()
err = n.computeExpectedResponses(timestamp, avPairsBytes)
if err != nil {
return err
}
err = n.computeKeyExchangeKey()
if err != nil {
return err
}
if !bytes.Equal(am.NtChallengeResponseFields.Payload, n.ntChallengeResponse) {
if !bytes.Equal(am.LmChallengeResponse.Payload, n.lmChallengeResponse) {
return errors.New("Could not authenticate")
}
}
n.mic = am.Mic
am.Mic = zeroBytes(16)
err = n.computeExportedSessionKey()
if err != nil {
return err
}
err = n.calculateKeys()
if err != nil {
return err
}
n.clientHandle, err = rc4Init(n.clientSealingKey)
if err != nil {
return err
}
n.serverHandle, err = rc4Init(n.serverSealingKey)
if err != nil {
return err
}
return nil
}
func (n *V2ServerSession) computeExportedSessionKey() (err error) {
if messages.NTLMSSP_NEGOTIATE_KEY_EXCH.IsSet(n.negotiateFlags) {
n.exportedSessionKey, err = rc4K(n.keyExchangeKey, n.encryptedRandomSessionKey)
if err != nil {
return err
}
// TODO: Calculate mic correctly. This calculation is not producing the right results now
// n.calculatedMic = HmacMd5(n.exportedSessionKey, concat(n.challengeMessage.Payload, n.authenticateMessage.Bytes))
} else {
n.exportedSessionKey = n.keyExchangeKey
// TODO: Calculate mic correctly. This calculation is not producing the right results now
// n.calculatedMic = HmacMd5(n.keyExchangeKey, concat(n.challengeMessage.Payload, n.authenticateMessage.Bytes))
}
return nil
}
/*************
Client Session
**************/
type V2ClientSession struct {
V2Session
}
func (n *V2ClientSession) GenerateNegotiateMessage() (nm *messages.Negotiate, err error) {
return nil, nil
}
func (n *V2ClientSession) ProcessChallengeMessage(cm *messages.Challenge) (err error) {
n.challengeMessage = cm
n.serverChallenge = cm.ServerChallenge
n.clientChallenge = randomBytes(8)
// Set up the default flags for processing the response. These are the flags that we will return
// in the authenticate message
flags := uint32(0)
flags = messages.NTLMSSP_NEGOTIATE_KEY_EXCH.Set(flags)
flags = messages.NTLMSSP_NEGOTIATE_VERSION.Set(flags)
flags = messages.NTLMSSP_NEGOTIATE_TARGET_INFO.Set(flags)
flags = messages.NTLMSSP_NEGOTIATE_IDENTIFY.Set(flags)
flags = messages.NTLMSSP_NEGOTIATE_ALWAYS_SIGN.Set(flags)
flags = messages.NTLMSSP_NEGOTIATE_NTLM.Set(flags)
flags = messages.NTLMSSP_NEGOTIATE_DATAGRAM.Set(flags)
flags = messages.NTLMSSP_NEGOTIATE_SIGN.Set(flags)
flags = messages.NTLMSSP_REQUEST_TARGET.Set(flags)
flags = messages.NTLMSSP_NEGOTIATE_UNICODE.Set(flags)
n.negotiateFlags = flags
err = n.fetchResponseKeys()
if err != nil {
return err
}
// TODO: Create the AvPairs and timestamp
/*
//err = n.computeExpectedResponses()
//if err != nil { return err }
err = n.computeKeyExchangeKey()
if err != nil { return err }
err = n.computeEncryptedSessionKey()
if err != nil { return err }
err = n.calculateKeys()
if err != nil { return err }
n.clientHandle, err = rc4Init(n.clientSealingKey)
if err != nil { return err }
n.serverHandle, err = rc4Init(n.serverSealingKey)
if err != nil { return err }
*/
return nil
}
func (n *V2ClientSession) GenerateAuthenticateMessage() (am *messages.Authenticate, err error) {
am = new(messages.Authenticate)
am.Signature = []byte("NTLMSSP\x00")
am.MessageType = uint32(3)
am.LmChallengeResponse, _ = messages.CreateBytePayload(n.lmChallengeResponse)
am.NtChallengeResponseFields, _ = messages.CreateBytePayload(n.ntChallengeResponse)
am.DomainName, _ = messages.CreateStringPayload(n.userDomain)
am.UserName, _ = messages.CreateStringPayload(n.user)
am.Workstation, _ = messages.CreateStringPayload("SQUAREMILL")
am.EncryptedRandomSessionKey, _ = messages.CreateBytePayload(n.encryptedRandomSessionKey)
am.NegotiateFlags = n.negotiateFlags
am.Version = &messages.VersionStruct{ProductMajorVersion: uint8(5), ProductMinorVersion: uint8(1), ProductBuild: uint16(2600), NTLMRevisionCurrent: uint8(15)}
return am, nil
}
func (n *V2ClientSession) computeEncryptedSessionKey() (err error) {
if messages.NTLMSSP_NEGOTIATE_KEY_EXCH.IsSet(n.negotiateFlags) {
n.exportedSessionKey = randomBytes(16)
n.encryptedRandomSessionKey, err = rc4K(n.keyExchangeKey, n.exportedSessionKey)
if err != nil {
return err
}
} else {
n.encryptedRandomSessionKey = n.keyExchangeKey
}
return nil
}
/********************************
NTLM V2 Password hash functions
*********************************/
// Define ntowfv2(Passwd, User, UserDom) as
func ntowfv2(user string, passwd string, userDom string) []byte {
concat := utf16FromString(strings.ToUpper(user) + userDom)
return hmacMd5(md4(utf16FromString(passwd)), concat)
}
// Define lmowfv2(Passwd, User, UserDom) as
func lmowfv2(user string, passwd string, userDom string) []byte {
return ntowfv2(user, passwd, userDom)
}