|
|
@@ -0,0 +1,277 @@
|
|
|
+package wire
|
|
|
+
|
|
|
+import (
|
|
|
+ "testing"
|
|
|
+
|
|
|
+ "github.com/stretchr/testify/assert"
|
|
|
+)
|
|
|
+
|
|
|
+func TestWeakMD5PasswordHash(t *testing.T) {
|
|
|
+ tests := []struct {
|
|
|
+ name string
|
|
|
+ password string
|
|
|
+ authKey string
|
|
|
+ want []byte
|
|
|
+ }{
|
|
|
+ {
|
|
|
+ name: "empty password and auth key",
|
|
|
+ password: "",
|
|
|
+ authKey: "",
|
|
|
+ want: []byte{0x13, 0xfd, 0x0b, 0x9e, 0x89, 0xf4, 0xb8, 0x36, 0xa7, 0x65, 0x8b, 0x9d, 0xca, 0xad, 0x2a, 0xd4},
|
|
|
+ },
|
|
|
+ {
|
|
|
+ name: "password and auth key",
|
|
|
+ password: "password123",
|
|
|
+ authKey: "authkey456",
|
|
|
+ want: []byte{0x04, 0x79, 0x63, 0x82, 0x0d, 0xa7, 0xbb, 0xfe, 0x6a, 0x9b, 0x41, 0xa4, 0x5c, 0x47, 0xcb, 0xcb},
|
|
|
+ },
|
|
|
+ }
|
|
|
+
|
|
|
+ for _, tt := range tests {
|
|
|
+ t.Run(tt.name, func(t *testing.T) {
|
|
|
+ got := WeakMD5PasswordHash(tt.password, tt.authKey)
|
|
|
+ assert.Equal(t, tt.want, got)
|
|
|
+ })
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+func TestStrongMD5PasswordHash(t *testing.T) {
|
|
|
+ tests := []struct {
|
|
|
+ name string
|
|
|
+ password string
|
|
|
+ authKey string
|
|
|
+ want []byte
|
|
|
+ }{
|
|
|
+ {
|
|
|
+ name: "empty password and auth key",
|
|
|
+ password: "",
|
|
|
+ authKey: "",
|
|
|
+ want: []byte{0x1f, 0xa2, 0xb6, 0x99, 0x59, 0x84, 0xb0, 0x14, 0x68, 0xa3, 0x7c, 0x77, 0x42, 0x90, 0x0a, 0xc9},
|
|
|
+ },
|
|
|
+ {
|
|
|
+ name: "password and auth key",
|
|
|
+ password: "password123",
|
|
|
+ authKey: "authkey456",
|
|
|
+ want: []byte{0xb9, 0x07, 0x91, 0xcc, 0xcb, 0x5c, 0x57, 0x71, 0xbd, 0xcb, 0xc9, 0x39, 0x82, 0xf7, 0x94, 0x84},
|
|
|
+ },
|
|
|
+ }
|
|
|
+
|
|
|
+ for _, tt := range tests {
|
|
|
+ t.Run(tt.name, func(t *testing.T) {
|
|
|
+ got := StrongMD5PasswordHash(tt.password, tt.authKey)
|
|
|
+ assert.Equal(t, tt.want, got)
|
|
|
+ })
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+func TestRoastOSCARPassword(t *testing.T) {
|
|
|
+ tests := []struct {
|
|
|
+ name string
|
|
|
+ roastedPass []byte
|
|
|
+ want []byte
|
|
|
+ }{
|
|
|
+ {
|
|
|
+ name: "empty password",
|
|
|
+ roastedPass: []byte{},
|
|
|
+ want: []byte{},
|
|
|
+ },
|
|
|
+ {
|
|
|
+ name: "single byte password",
|
|
|
+ roastedPass: []byte{0xF3},
|
|
|
+ want: []byte{0x00},
|
|
|
+ },
|
|
|
+ {
|
|
|
+ name: "multiple bytes password",
|
|
|
+ roastedPass: []byte{0xF3, 0x26, 0x81, 0xC4},
|
|
|
+ want: []byte{0x00, 0x00, 0x00, 0x00},
|
|
|
+ },
|
|
|
+ {
|
|
|
+ name: "password longer than roast table",
|
|
|
+ roastedPass: []byte{0xF3, 0x26, 0x81, 0xC4, 0x39, 0x86, 0xDB, 0x92, 0x71, 0xA3, 0xB9, 0xE6, 0x53, 0x7A, 0x95, 0x7C, 0xF3, 0x26},
|
|
|
+ want: []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
|
|
|
+ },
|
|
|
+ {
|
|
|
+ name: "non-zero roasted password",
|
|
|
+ roastedPass: []byte{0xE3, 0x16, 0x91, 0xD4},
|
|
|
+ want: []byte{0x10, 0x30, 0x10, 0x10},
|
|
|
+ },
|
|
|
+ }
|
|
|
+
|
|
|
+ for _, tt := range tests {
|
|
|
+ t.Run(tt.name, func(t *testing.T) {
|
|
|
+ got := RoastOSCARPassword(tt.roastedPass)
|
|
|
+ assert.Equal(t, tt.want, got)
|
|
|
+ })
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+func TestRoastKerberosPassword(t *testing.T) {
|
|
|
+ tests := []struct {
|
|
|
+ name string
|
|
|
+ roastedPass []byte
|
|
|
+ want []byte
|
|
|
+ }{
|
|
|
+ {
|
|
|
+ name: "empty password",
|
|
|
+ roastedPass: []byte{},
|
|
|
+ want: []byte{},
|
|
|
+ },
|
|
|
+ {
|
|
|
+ name: "single byte password",
|
|
|
+ roastedPass: []byte{0x76},
|
|
|
+ want: []byte{0x00},
|
|
|
+ },
|
|
|
+ {
|
|
|
+ name: "multiple bytes password",
|
|
|
+ roastedPass: []byte{0x76, 0x91, 0xc5, 0xe7},
|
|
|
+ want: []byte{0x00, 0x00, 0x00, 0x00},
|
|
|
+ },
|
|
|
+ {
|
|
|
+ name: "password longer than roast table",
|
|
|
+ roastedPass: []byte{0x76, 0x91, 0xc5, 0xe7, 0xd0, 0xd9, 0x95, 0xdd, 0x9e, 0x2F, 0xea, 0xd8, 0x6B, 0x21, 0xc2, 0xbc, 0x76, 0x91},
|
|
|
+ want: []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
|
|
|
+ },
|
|
|
+ {
|
|
|
+ name: "non-zero roasted password",
|
|
|
+ roastedPass: []byte{0x66, 0x81, 0xd5, 0xf7},
|
|
|
+ want: []byte{0x10, 0x10, 0x10, 0x10},
|
|
|
+ },
|
|
|
+ }
|
|
|
+
|
|
|
+ for _, tt := range tests {
|
|
|
+ t.Run(tt.name, func(t *testing.T) {
|
|
|
+ got := RoastKerberosPassword(tt.roastedPass)
|
|
|
+ assert.Equal(t, tt.want, got)
|
|
|
+ })
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+func TestRoastOSCARJavaPassword(t *testing.T) {
|
|
|
+ tests := []struct {
|
|
|
+ name string
|
|
|
+ roastedPass []byte
|
|
|
+ want []byte
|
|
|
+ }{
|
|
|
+ {
|
|
|
+ name: "empty password",
|
|
|
+ roastedPass: []byte{},
|
|
|
+ want: []byte{},
|
|
|
+ },
|
|
|
+ {
|
|
|
+ name: "single byte password",
|
|
|
+ roastedPass: []byte{0xF3},
|
|
|
+ want: []byte{0x00},
|
|
|
+ },
|
|
|
+ {
|
|
|
+ name: "multiple bytes password",
|
|
|
+ roastedPass: []byte{0xF3, 0xB3, 0x6C, 0x99},
|
|
|
+ want: []byte{0x00, 0x00, 0x00, 0x00},
|
|
|
+ },
|
|
|
+ {
|
|
|
+ name: "password longer than roast table",
|
|
|
+ roastedPass: []byte{0xF3, 0xB3, 0x6C, 0x99, 0x95, 0x3F, 0xAC, 0xB6, 0xC5, 0xFA, 0x6B, 0x63, 0x69, 0x6C, 0xC3, 0x9A, 0xF3, 0xB3},
|
|
|
+ want: []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
|
|
|
+ },
|
|
|
+ {
|
|
|
+ name: "non-zero roasted password",
|
|
|
+ roastedPass: []byte{0xE3, 0xA3, 0x5C, 0x89},
|
|
|
+ want: []byte{0x10, 0x10, 0x30, 0x10},
|
|
|
+ },
|
|
|
+ }
|
|
|
+
|
|
|
+ for _, tt := range tests {
|
|
|
+ t.Run(tt.name, func(t *testing.T) {
|
|
|
+ got := RoastOSCARJavaPassword(tt.roastedPass)
|
|
|
+ assert.Equal(t, tt.want, got)
|
|
|
+ })
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+func TestRoastTOCPassword(t *testing.T) {
|
|
|
+ tests := []struct {
|
|
|
+ name string
|
|
|
+ roastedPass []byte
|
|
|
+ want []byte
|
|
|
+ }{
|
|
|
+ {
|
|
|
+ name: "empty password",
|
|
|
+ roastedPass: []byte{},
|
|
|
+ want: []byte{},
|
|
|
+ },
|
|
|
+ {
|
|
|
+ name: "single byte password",
|
|
|
+ roastedPass: []byte{0x54}, // 'T'
|
|
|
+ want: []byte{0x00},
|
|
|
+ },
|
|
|
+ {
|
|
|
+ name: "multiple bytes password",
|
|
|
+ roastedPass: []byte{0x54, 0x69, 0x63, 0x2F, 0x54, 0x6F, 0x63}, // "Tic/Toc"
|
|
|
+ want: []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
|
|
|
+ },
|
|
|
+ {
|
|
|
+ name: "password longer than roast table",
|
|
|
+ roastedPass: []byte{0x54, 0x69, 0x63, 0x2F, 0x54, 0x6F, 0x63, 0x54, 0x69, 0x63, 0x2F, 0x54, 0x6F, 0x63},
|
|
|
+ want: []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
|
|
|
+ },
|
|
|
+ {
|
|
|
+ name: "non-zero roasted password",
|
|
|
+ roastedPass: []byte{0x44, 0x59, 0x53, 0x1F},
|
|
|
+ want: []byte{0x10, 0x30, 0x30, 0x30},
|
|
|
+ },
|
|
|
+ }
|
|
|
+
|
|
|
+ for _, tt := range tests {
|
|
|
+ t.Run(tt.name, func(t *testing.T) {
|
|
|
+ got := RoastTOCPassword(tt.roastedPass)
|
|
|
+ assert.Equal(t, tt.want, got)
|
|
|
+ })
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+// Test that roasting and unroasting are reversible operations
|
|
|
+func TestRoastPasswordReversibility(t *testing.T) {
|
|
|
+ tests := []struct {
|
|
|
+ name string
|
|
|
+ clearPass []byte
|
|
|
+ roastTable []byte
|
|
|
+ roastFunc func([]byte) []byte
|
|
|
+ }{
|
|
|
+ {
|
|
|
+ name: "OSCAR password reversibility",
|
|
|
+ clearPass: []byte("password123"),
|
|
|
+ roastTable: []byte{0xF3, 0x26, 0x81, 0xC4, 0x39, 0x86, 0xDB, 0x92, 0x71, 0xA3, 0xB9, 0xE6, 0x53, 0x7A, 0x95, 0x7C},
|
|
|
+ roastFunc: RoastOSCARPassword,
|
|
|
+ },
|
|
|
+ {
|
|
|
+ name: "Kerberos password reversibility",
|
|
|
+ clearPass: []byte("password123"),
|
|
|
+ roastTable: []byte{0x76, 0x91, 0xc5, 0xe7, 0xd0, 0xd9, 0x95, 0xdd, 0x9e, 0x2F, 0xea, 0xd8, 0x6B, 0x21, 0xc2, 0xbc},
|
|
|
+ roastFunc: RoastKerberosPassword,
|
|
|
+ },
|
|
|
+ {
|
|
|
+ name: "OSCAR Java password reversibility",
|
|
|
+ clearPass: []byte("password123"),
|
|
|
+ roastTable: []byte{0xF3, 0xB3, 0x6C, 0x99, 0x95, 0x3F, 0xAC, 0xB6, 0xC5, 0xFA, 0x6B, 0x63, 0x69, 0x6C, 0xC3, 0x9A},
|
|
|
+ roastFunc: RoastOSCARJavaPassword,
|
|
|
+ },
|
|
|
+ {
|
|
|
+ name: "TOC password reversibility",
|
|
|
+ clearPass: []byte("password123"),
|
|
|
+ roastTable: []byte("Tic/Toc"),
|
|
|
+ roastFunc: RoastTOCPassword,
|
|
|
+ },
|
|
|
+ }
|
|
|
+
|
|
|
+ for _, tt := range tests {
|
|
|
+ t.Run(tt.name, func(t *testing.T) {
|
|
|
+ // First, roast the clear password
|
|
|
+ roasted := roastPass(tt.clearPass, tt.roastTable)
|
|
|
+
|
|
|
+ // Then, unroast it using the roast function
|
|
|
+ unroasted := tt.roastFunc(roasted)
|
|
|
+
|
|
|
+ // The result should be the original clear password
|
|
|
+ assert.Equal(t, tt.clearPass, unroasted)
|
|
|
+ })
|
|
|
+ }
|
|
|
+}
|