forked from saily/vnc2video
-
Notifications
You must be signed in to change notification settings - Fork 0
/
security_vnc.go
120 lines (102 loc) · 2.88 KB
/
security_vnc.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
package vnc2video
import (
"bytes"
"crypto/des"
"encoding/binary"
"fmt"
)
// ServerAuthVNC is the standard password authentication. See 7.2.2.
type ServerAuthVNC struct {
Challenge []byte
Password []byte
Crypted []byte
}
func (*ServerAuthVNC) Type() SecurityType {
return SecTypeVNC
}
func (*ServerAuthVNC) SubType() SecuritySubType {
return SecSubTypeUnknown
}
func (auth *ServerAuthVNC) WriteChallenge(c Conn) error {
if err := binary.Write(c, binary.BigEndian, auth.Challenge); err != nil {
return err
}
return c.Flush()
}
func (auth *ServerAuthVNC) ReadChallenge(c Conn) error {
var crypted [16]byte
if err := binary.Read(c, binary.BigEndian, &crypted); err != nil {
return err
}
auth.Crypted = crypted[:]
return nil
}
func (auth *ServerAuthVNC) Auth(c Conn) error {
if err := auth.WriteChallenge(c); err != nil {
return err
}
if err := auth.ReadChallenge(c); err != nil {
return err
}
encrypted, err := AuthVNCEncode(auth.Password, auth.Challenge)
if err != nil {
return err
}
if !bytes.Equal(encrypted, auth.Crypted) {
return fmt.Errorf("password invalid")
}
return nil
}
// ClientAuthVNC is the standard password authentication. See 7.2.2.
type ClientAuthVNC struct {
Challenge []byte
Password []byte
}
func (*ClientAuthVNC) Type() SecurityType {
return SecTypeVNC
}
func (*ClientAuthVNC) SubType() SecuritySubType {
return SecSubTypeUnknown
}
func (auth *ClientAuthVNC) Auth(c Conn) error {
if len(auth.Password) == 0 {
return fmt.Errorf("Security Handshake failed; no password provided for VNCAuth.")
}
var challenge [16]byte
if err := binary.Read(c, binary.BigEndian, &challenge); err != nil {
return err
}
encrypted, err := AuthVNCEncode(auth.Password, challenge[:])
if err != nil {
return err
}
// Send the encrypted challenge back to server
if err := binary.Write(c, binary.BigEndian, encrypted); err != nil {
return err
}
return c.Flush()
}
func AuthVNCEncode(password []byte, challenge []byte) ([]byte, error) {
if len(challenge) != 16 {
return nil, fmt.Errorf("challenge size not 16 byte long")
}
// Copy password string to 8 byte 0-padded slice
key := make([]byte, 8)
copy(key, password)
// Each byte of the password needs to be reversed. This is a
// non RFC-documented behaviour of VNC clients and servers
for i := range key {
key[i] = (key[i]&0x55)<<1 | (key[i]&0xAA)>>1 // Swap adjacent bits
key[i] = (key[i]&0x33)<<2 | (key[i]&0xCC)>>2 // Swap adjacent pairs
key[i] = (key[i]&0x0F)<<4 | (key[i]&0xF0)>>4 // Swap the 2 halves
}
// Encrypt challenge with key.
cipher, err := des.NewCipher(key)
if err != nil {
return nil, err
}
for i := 0; i < len(challenge); i += cipher.BlockSize() {
cipher.Encrypt(challenge[i:i+cipher.BlockSize()], challenge[i:i+cipher.BlockSize()])
}
return challenge, nil
}