package ntlm
import (
"bytes"
"crypto/rc4"
"errors"
"github.com/hirochachacha/go-smb2/internal/utf16le"
)
type Session struct {
isClientSide bool
user string
negotiateFlags uint32
exportedSessionKey []byte
clientSigningKey []byte
serverSigningKey []byte
clientHandle *rc4 .Cipher
serverHandle *rc4 .Cipher
infoMap map [uint16 ][]byte
}
func (s *Session ) User () string {
return s .user
}
func (s *Session ) SessionKey () []byte {
return s .exportedSessionKey
}
type InfoMap struct {
NbComputerName string
NbDomainName string
DnsComputerName string
DnsDomainName string
DnsTreeName string
}
func (s *Session ) InfoMap () *InfoMap {
return &InfoMap {
NbComputerName : utf16le .DecodeToString (s .infoMap [MsvAvNbComputerName ]),
NbDomainName : utf16le .DecodeToString (s .infoMap [MsvAvNbDomainName ]),
DnsComputerName : utf16le .DecodeToString (s .infoMap [MsvAvDnsComputerName ]),
DnsDomainName : utf16le .DecodeToString (s .infoMap [MsvAvDnsDomainName ]),
DnsTreeName : utf16le .DecodeToString (s .infoMap [MsvAvDnsTreeName ]),
}
}
func (s *Session ) Overhead () int {
return 16
}
func (s *Session ) Sum (plaintext []byte , seqNum uint32 ) ([]byte , uint32 ) {
if s .negotiateFlags &NTLMSSP_NEGOTIATE_SIGN == 0 {
return nil , 0
}
if s .isClientSide {
return mac (nil , s .negotiateFlags , s .clientHandle , s .clientSigningKey , seqNum , plaintext )
}
return mac (nil , s .negotiateFlags , s .serverHandle , s .serverSigningKey , seqNum , plaintext )
}
func (s *Session ) CheckSum (sum , plaintext []byte , seqNum uint32 ) (bool , uint32 ) {
if s .negotiateFlags &NTLMSSP_NEGOTIATE_SIGN == 0 {
if sum == nil {
return true , 0
}
return false , 0
}
if s .isClientSide {
ret , seqNum := mac (nil , s .negotiateFlags , s .serverHandle , s .serverSigningKey , seqNum , plaintext )
if !bytes .Equal (sum , ret ) {
return false , 0
}
return true , seqNum
}
ret , seqNum := mac (nil , s .negotiateFlags , s .clientHandle , s .clientSigningKey , seqNum , plaintext )
if !bytes .Equal (sum , ret ) {
return false , 0
}
return true , seqNum
}
func (s *Session ) Seal (dst , plaintext []byte , seqNum uint32 ) ([]byte , uint32 ) {
ret , ciphertext := sliceForAppend (dst , len (plaintext )+16 )
switch {
case s .negotiateFlags &NTLMSSP_NEGOTIATE_SEAL != 0 :
s .clientHandle .XORKeyStream (ciphertext [16 :], plaintext )
if s .isClientSide {
_, seqNum = mac (ciphertext [:0 ], s .negotiateFlags , s .clientHandle , s .clientSigningKey , seqNum , plaintext )
} else {
_, seqNum = mac (ciphertext [:0 ], s .negotiateFlags , s .serverHandle , s .serverSigningKey , seqNum , plaintext )
}
case s .negotiateFlags &NTLMSSP_NEGOTIATE_SIGN != 0 :
copy (ciphertext [16 :], plaintext )
if s .isClientSide {
_, seqNum = mac (ciphertext [:0 ], s .negotiateFlags , s .clientHandle , s .clientSigningKey , seqNum , plaintext )
} else {
_, seqNum = mac (ciphertext [:0 ], s .negotiateFlags , s .serverHandle , s .serverSigningKey , seqNum , plaintext )
}
}
return ret , seqNum
}
func (s *Session ) Unseal (dst , ciphertext []byte , seqNum uint32 ) ([]byte , uint32 , error ) {
ret , plaintext := sliceForAppend (dst , len (ciphertext )-16 )
switch {
case s .negotiateFlags &NTLMSSP_NEGOTIATE_SEAL != 0 :
s .serverHandle .XORKeyStream (plaintext , ciphertext [16 :])
var sum []byte
if s .isClientSide {
sum , seqNum = mac (nil , s .negotiateFlags , s .serverHandle , s .serverSigningKey , seqNum , plaintext )
} else {
sum , seqNum = mac (nil , s .negotiateFlags , s .clientHandle , s .clientSigningKey , seqNum , plaintext )
}
if !bytes .Equal (ciphertext [:16 ], sum ) {
return nil , 0 , errors .New ("signature mismatch" )
}
case s .negotiateFlags &NTLMSSP_NEGOTIATE_SIGN != 0 :
copy (plaintext , ciphertext [16 :])
var sum []byte
if s .isClientSide {
sum , seqNum = mac (nil , s .negotiateFlags , s .serverHandle , s .serverSigningKey , seqNum , plaintext )
} else {
sum , seqNum = mac (nil , s .negotiateFlags , s .clientHandle , s .clientSigningKey , seqNum , plaintext )
}
if !bytes .Equal (ciphertext [:16 ], sum ) {
return nil , 0 , errors .New ("signature mismatch" )
}
default :
copy (plaintext , ciphertext [16 :])
for _ , s := range ciphertext [:16 ] {
if s != 0x0 {
return nil , 0 , errors .New ("signature mismatch" )
}
}
}
return ret , seqNum , nil
}
The pages are generated with Golds v0.6.7 . (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu .
PR and bug reports are welcome and can be submitted to the issue list .
Please follow @Go100and1 (reachable from the left QR code) to get the latest news of Golds .