security
import "github.com/TheManticoreProject/Manticore/crypto/spnego/ntlm/security"
Package security implements NTLMSSP per-message security: the message integrity (signing) and confidentiality (sealing) services used by GSS_WrapEx / GSS_GetMICEx once an NTLM authentication exchange has produced an exported session key.
It implements the extended session security (NTLMv2) variant of MS-NLMP sections 3.4.3 (SEAL), 3.4.4 (MAC / message signature), and 3.4.5 (SIGNKEY / SEALKEY key derivation). This is the machinery a connection-oriented DCE/RPC client needs to sign (PKT_INTEGRITY) and seal (PKT_PRIVACY) request stubs per [MS-RPCE] 3.3.
References:
- [MS-NLMP] 3.4 Session Security: https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-nlmp/0c2fa6f4-baf3-4f49-9a72-7c7d7c4c1bc8
- [MS-NLMP] 4.2.4.4 GSS_WrapEx Examples (the known-answer test vectors): https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-nlmp/9d9ed1f4-7c91-4d54-b4b2-b87ac1f5b64a
Index
- Constants
- type Context
- func NewContext(exportedSessionKey []byte, negFlg flags.NegotiateFlags) (*Context, error)
- func (c *Context) DecryptInbound(buf []byte)
- func (c *Context) SealWith(messageToSign, messageToEncrypt []byte) ([]byte, [SignatureSize]byte)
- func (c *Context) Sign(message []byte) [SignatureSize]byte
- func (c *Context) VerifySignature(messageToSign []byte, sig [SignatureSize]byte) error
Constants
SignatureSize is the size, in bytes, of an NTLMSSP_MESSAGE_SIGNATURE (version + checksum + sequence number), the value carried in the RPC auth_verifier.
const SignatureSize = 16
type Context
Context holds the per-direction signing keys, sealing RC4 stream ciphers, and sequence numbers for one authenticated NTLM session. A client uses the “client” keys to protect outbound PDUs and the “server” keys to verify inbound PDUs.
A Context is not safe for concurrent use: the RC4 handles and sequence numbers are stateful and advance with every message, so calls must be serialized in the same order the PDUs go on (and come off) the wire.
type Context struct {
// contains filtered or unexported fields
}
func NewContext
func NewContext(exportedSessionKey []byte, negFlg flags.NegotiateFlags) (*Context, error)
NewContext derives the signing and sealing keys from exportedSessionKey and the negotiated flags, and initializes the client and server RC4 sealing handles. With extended session security each direction gets its own keys, so client and server signatures never collide. negFlg must be the flags actually negotiated for the session (those carried in the AUTHENTICATE message).
func (*Context) DecryptInbound
func (c *Context) DecryptInbound(buf []byte)
DecryptInbound decrypts an inbound sealed region (a PKT_PRIVACY response stub plus padding) in place using the server sealing stream. It neither advances the sequence number nor verifies the signature; call VerifySignature afterwards over the now- plaintext PDU. Decryption must precede verification so the MAC covers plaintext.
func (*Context) SealWith
func (c *Context) SealWith(messageToSign, messageToEncrypt []byte) ([]byte, [SignatureSize]byte)
SealWith encrypts messageToEncrypt for an outbound PKT_PRIVACY PDU and computes the signature over messageToSign. In connection-oriented RPC the two differ: the signed region is the whole PDU (header, stub, padding, sec_trailer) computed over the plaintext, while only the stub and its padding are encrypted ([MS-RPCE] 3.3, NTLM2). The plaintext is encrypted first so that, when key exchange is negotiated, the checksum is encrypted with the subsequent keystream (MS-NLMP 3.4.3). It advances the outbound sequence number once and returns the ciphertext for the encrypted region.
func (*Context) Sign
func (c *Context) Sign(message []byte) [SignatureSize]byte
Sign returns the NTLMSSP_MESSAGE_SIGNATURE over message for an outbound PKT_INTEGRITY PDU. The message is left in cleartext; only the signature is produced. It advances the outbound sequence number.
func (*Context) VerifySignature
func (c *Context) VerifySignature(messageToSign []byte, sig [SignatureSize]byte) error
VerifySignature checks the signature of an inbound PDU over messageToSign and advances the inbound sequence number. For PKT_INTEGRITY messageToSign is the cleartext PDU minus its trailing auth_value; for PKT_PRIVACY the caller must have already decrypted the stub with DecryptInbound so the MAC is computed over plaintext.