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