122 lines
2.8 KiB
Go
122 lines
2.8 KiB
Go
package vnc
|
|
|
|
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
|
|
}
|
|
fmt.Printf("rrrr\n")
|
|
// 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
|
|
}
|