Skip to content

Commit

Permalink
add functions for MPPE handshakes (RFC 3079)
Browse files Browse the repository at this point in the history
This patch adds support for adding MPPE send/recv keys that are attached to
MSCHAPv2 response packets, as described by RFC 3079.

The results from MakeKey() can be used as input for NewTunnelPassword().

Code is tested with examples from section 3.5 of the RFC.
  • Loading branch information
zonque authored and Tim Cooper committed Jul 20, 2020
1 parent b96a9ba commit 39bb143
Show file tree
Hide file tree
Showing 2 changed files with 209 additions and 0 deletions.
117 changes: 117 additions & 0 deletions rfc3079/mppe.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
package rfc3079

import (
"crypto/sha1"
"errors"

"layeh.com/radius/rfc2759"
)

// KeyLength is the length of keys involved with the functions below
type KeyLength uint

const (
// KeyLength40Bit - 40-bit
KeyLength40Bit = KeyLength(8)
// KeyLength128Bit - 128-bit
KeyLength128Bit = KeyLength(16)
)

var (
shaPad1 = []byte{
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
}

shaPad2 = []byte{
0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2,
0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2,
0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2,
0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2,
}

magic1 = []byte{
0x54, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74,
0x68, 0x65, 0x20, 0x4d, 0x50, 0x50, 0x45, 0x20, 0x4d,
0x61, 0x73, 0x74, 0x65, 0x72, 0x20, 0x4b, 0x65, 0x79,
}

magic2 = []byte{
0x4f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x69,
0x65, 0x6e, 0x74, 0x20, 0x73, 0x69, 0x64, 0x65, 0x2c, 0x20,
0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68,
0x65, 0x20, 0x73, 0x65, 0x6e, 0x64, 0x20, 0x6b, 0x65, 0x79,
0x3b, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73,
0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x73, 0x69, 0x64, 0x65,
0x2c, 0x20, 0x69, 0x74, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68,
0x65, 0x20, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x20,
0x6b, 0x65, 0x79, 0x2e,
}

magic3 = []byte{
0x4f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x69,
0x65, 0x6e, 0x74, 0x20, 0x73, 0x69, 0x64, 0x65, 0x2c, 0x20,
0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68,
0x65, 0x20, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x20,
0x6b, 0x65, 0x79, 0x3b, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68,
0x65, 0x20, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x73,
0x69, 0x64, 0x65, 0x2c, 0x20, 0x69, 0x74, 0x20, 0x69, 0x73,
0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x65, 0x6e, 0x64, 0x20,
0x6b, 0x65, 0x79, 0x2e,
}
)

// GetMasterKey - rfc3079, 3.4
func GetMasterKey(passwordHashHash, ntResponse []byte) []byte {
sha := sha1.New()
sha.Write(passwordHashHash)
sha.Write(ntResponse)
sha.Write(magic1)
digest := sha.Sum(nil)

return digest[:16]
}

// GetAsymmetricStartKey - rfc3079, 3.4
func GetAsymmetricStartKey(masterKey []byte, sessionKeyLength KeyLength, isSend bool) ([]byte, error) {
if len(masterKey) != 16 {
return []byte{}, errors.New("masterKey must be 16 bytes long")
}

s := []byte{}

if isSend {
s = magic3
} else {
s = magic2
}

sha := sha1.New()
sha.Write(masterKey)
sha.Write(shaPad1)
sha.Write(s)
sha.Write(shaPad2)
digest := sha.Sum(nil)

return digest[:sessionKeyLength], nil
}

// MakeKey - rfc2548, 2.4.2
func MakeKey(ntResponse []byte, password string, isSend bool) ([]byte, error) {
if len(ntResponse) != 24 {
return []byte{}, errors.New("ntresponse must be 24 bytes in size")
}

ucs2Password, err := rfc2759.ToUTF16(password)
if err != nil {
return []byte{}, err
}

passwordHash := rfc2759.HashPassword(ucs2Password)
passwordHashHash := rfc2759.HashPassword(passwordHash)
masterKey := GetMasterKey(passwordHashHash, ntResponse)

return GetAsymmetricStartKey(masterKey, KeyLength128Bit, isSend)
}
92 changes: 92 additions & 0 deletions rfc3079/mppe_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
package rfc3079

import (
"reflect"
"testing"
)

func TestGetMasterKey(t *testing.T) {
type args struct {
passwordHashHash []byte
ntResponse []byte
}
tests := []struct {
name string
args args
want []byte
}{
{
name: "rfc3079, 3.5.1",
args: args{
passwordHashHash: []byte{
0x41, 0xC0, 0x0C, 0x58, 0x4B, 0xD2, 0xD9, 0x1C, 0x40, 0x17, 0xA2, 0xA1, 0x2F, 0xA5, 0x9F, 0x3F,
},
ntResponse: []byte{
0x82, 0x30, 0x9E, 0xCD, 0x8D, 0x70, 0x8B, 0x5E, 0xA0, 0x8F, 0xAA, 0x39, 0x81, 0xCD, 0x83, 0x54, 0x42, 0x33,
0x11, 0x4A, 0x3D, 0x85, 0xD6, 0xDF,
},
},
want: []byte{
0xFD, 0xEC, 0xE3, 0x71, 0x7A, 0x8C, 0x83, 0x8C, 0xB3, 0x88, 0xE5, 0x27, 0xAE, 0x3C, 0xDD, 0x31,
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := GetMasterKey(tt.args.passwordHashHash, tt.args.ntResponse); !reflect.DeepEqual(got, tt.want) {
t.Errorf("GetMasterKey() = %v, want %v", got, tt.want)
}
})
}
}

func TestGetAsymmetricStartKey(t *testing.T) {
type args struct {
masterKey []byte
sessionKeyLength KeyLength
isSend bool
}
tests := []struct {
name string
args args
want []byte
}{
{
name: "40-bit, rfc3079, 3.5.1",
args: args{
masterKey: []byte{
0xFD, 0xEC, 0xE3, 0x71, 0x7A, 0x8C, 0x83, 0x8C, 0xB3, 0x88, 0xE5, 0x27, 0xAE, 0x3C, 0xDD, 0x31,
},
sessionKeyLength: KeyLength40Bit,
isSend: true,
},
want: []byte{
0x8B, 0x7C, 0xDC, 0x14, 0x9B, 0x99, 0x3A, 0x1B,
},
},
{
name: "128-bit, rfc3079, 3.5.3",
args: args{
masterKey: []byte{
0xFD, 0xEC, 0xE3, 0x71, 0x7A, 0x8C, 0x83, 0x8C, 0xB3, 0x88, 0xE5, 0x27, 0xAE, 0x3C, 0xDD, 0x31,
},
sessionKeyLength: 16,
isSend: true,
},
want: []byte{
0x8B, 0x7C, 0xDC, 0x14, 0x9B, 0x99, 0x3A, 0x1B, 0xA1, 0x18, 0xCB, 0x15, 0x3F, 0x56, 0xDC, 0xCB,
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := GetAsymmetricStartKey(tt.args.masterKey, tt.args.sessionKeyLength, tt.args.isSend)
if err != nil {
t.Errorf("err = %v", err)
}
if !reflect.DeepEqual(got, tt.want) {
t.Errorf("GetAsymmetricStartKey() = %v, want %v", got, tt.want)
}
})
}
}

0 comments on commit 39bb143

Please sign in to comment.