// ToPublic converts a Elligator representative to a Curve25519 public key. func (repr *Representative) ToPublic() *PublicKey { pub := new(PublicKey) extra25519.RepresentativeToPublicKey(pub.Bytes(), repr.Bytes()) return pub }
// Process handshake message on the client side. // This function is intended to be called on client's side. // If this is the final handshake message, then new Peer object // will be created and used as a transport. If no mutually // authenticated Peer is ready, then return nil. func (h *Handshake) Client(data []byte) *Peer { // ENC(H(DSAPub), R+1, El(SDHPub)) + ENC(K, R, RS + SS) + IDtag if h.rServer == nil && h.key == nil && ((!h.Conf.Encless && len(data) >= 80) || (h.Conf.Encless && len(data) == 2*(EnclessEnlargeSize+h.Conf.MTU))) { // Decrypt remote public key sDHRepr := new([32]byte) var tmp []byte var err error if h.Conf.Encless { tmp, err = EnclessDecode( h.dsaPubH, h.rNonceNext(1), data[:len(data)/2], ) if err != nil { log.Println("Unable to decode packet from", h.addr, err) return nil } copy(sDHRepr[:], tmp[:32]) } else { salsa20.XORKeyStream( sDHRepr[:], data[:32], h.rNonceNext(1), h.dsaPubH, ) } // Compute shared key sDH := new([32]byte) extra25519.RepresentativeToPublicKey(sDH, sDHRepr) h.key = dhKeyGen(h.dhPriv, sDH) // Decrypt Rs h.rServer = new([RSize]byte) h.sServer = new([SSize]byte) if h.Conf.Encless { tmp, err = EnclessDecode( h.key, h.rNonce[:], data[len(data)/2:len(data)-xtea.BlockSize], ) if err != nil { log.Println("Unable to decode packet from", h.addr, err) return nil } copy(h.rServer[:], tmp[:RSize]) copy(h.sServer[:], tmp[RSize:RSize+SSize]) } else { decRs := make([]byte, RSize+SSize) salsa20.XORKeyStream( decRs, data[SSize:SSize+RSize+SSize], h.rNonce[:], h.key, ) copy(h.rServer[:], decRs[:RSize]) copy(h.sServer[:], decRs[RSize:]) } // Generate R* and signature and encrypt them h.rClient = new([RSize]byte) if _, err = Rand.Read(h.rClient[:]); err != nil { log.Fatalln("Error reading random for R:", err) } h.sClient = new([SSize]byte) if _, err = Rand.Read(h.sClient[:]); err != nil { log.Fatalln("Error reading random for S:", err) } sign := ed25519.Sign(h.Conf.DSAPriv, h.key[:]) var enc []byte if h.Conf.Noise { enc = make([]byte, h.Conf.MTU-xtea.BlockSize) } else { enc = make([]byte, RSize+RSize+SSize+ed25519.SignatureSize) } copy(enc, h.rServer[:]) copy(enc[RSize:], h.rClient[:]) copy(enc[RSize+RSize:], h.sClient[:]) copy(enc[RSize+RSize+SSize:], sign[:]) if h.Conf.Encless { enc, err = EnclessEncode(h.key, h.rNonceNext(1), enc) if err != nil { panic(err) } } else { salsa20.XORKeyStream(enc, enc, h.rNonceNext(1), h.key) } // Send that to server h.conn.Write(append(enc, idTag(h.Conf.Id, h.Conf.TimeSync, enc)...)) h.LastPing = time.Now() } else // ENC(K, R+2, RC) + IDtag if h.key != nil && ((!h.Conf.Encless && len(data) >= 16) || (h.Conf.Encless && len(data) == EnclessEnlargeSize+h.Conf.MTU)) { var err error // Decrypt rClient var dec []byte if h.Conf.Encless { dec, err = EnclessDecode( h.key, h.rNonceNext(2), data[:len(data)-xtea.BlockSize], ) if err != nil { log.Println("Unable to decode packet from", h.addr, err) return nil } dec = dec[:RSize] } else { dec = make([]byte, RSize) salsa20.XORKeyStream(dec, data[:RSize], h.rNonceNext(2), h.key) } if subtle.ConstantTimeCompare(dec, h.rClient[:]) != 1 { log.Println("Invalid client's random number with", h.addr) return nil } // Switch peer peer := newPeer( true, h.addr, h.conn, h.Conf, keyFromSecrets(h.sServer[:], h.sClient[:]), ) h.LastPing = time.Now() return peer } else { log.Println("Invalid handshake stage from", h.addr) } return nil }
// Process handshake message on the server side. // This function is intended to be called on server's side. // If this is the final handshake message, then new Peer object // will be created and used as a transport. If no mutually // authenticated Peer is ready, then return nil. func (h *Handshake) Server(data []byte) *Peer { // R + ENC(H(DSAPub), R, El(CDHPub)) + IDtag if h.rNonce == nil && ((!h.Conf.Encless && len(data) >= 48) || (h.Conf.Encless && len(data) == EnclessEnlargeSize+h.Conf.MTU)) { h.rNonce = new([RSize]byte) copy(h.rNonce[:], data[:RSize]) // Decrypt remote public key cDHRepr := new([32]byte) if h.Conf.Encless { out, err := EnclessDecode( h.dsaPubH, h.rNonce[:], data[RSize:len(data)-xtea.BlockSize], ) if err != nil { log.Println("Unable to decode packet from", h.addr, err) return nil } copy(cDHRepr[:], out) } else { salsa20.XORKeyStream( cDHRepr[:], data[RSize:RSize+32], h.rNonce[:], h.dsaPubH, ) } // Generate DH keypair var dhPubRepr *[32]byte h.dhPriv, dhPubRepr = dhKeypairGen() // Compute shared key cDH := new([32]byte) extra25519.RepresentativeToPublicKey(cDH, cDHRepr) h.key = dhKeyGen(h.dhPriv, cDH) var encPub []byte var err error if h.Conf.Encless { encPub = make([]byte, h.Conf.MTU) copy(encPub, dhPubRepr[:]) encPub, err = EnclessEncode(h.dsaPubH, h.rNonceNext(1), encPub) if err != nil { panic(err) } } else { encPub = make([]byte, 32) salsa20.XORKeyStream(encPub, dhPubRepr[:], h.rNonceNext(1), h.dsaPubH) } // Generate R* and encrypt them h.rServer = new([RSize]byte) if _, err = Rand.Read(h.rServer[:]); err != nil { log.Fatalln("Error reading random for R:", err) } h.sServer = new([SSize]byte) if _, err = Rand.Read(h.sServer[:]); err != nil { log.Fatalln("Error reading random for S:", err) } var encRs []byte if h.Conf.Noise && !h.Conf.Encless { encRs = make([]byte, h.Conf.MTU-len(encPub)-xtea.BlockSize) } else if h.Conf.Encless { encRs = make([]byte, h.Conf.MTU-xtea.BlockSize) } else { encRs = make([]byte, RSize+SSize) } copy(encRs, append(h.rServer[:], h.sServer[:]...)) if h.Conf.Encless { encRs, err = EnclessEncode(h.key, h.rNonce[:], encRs) if err != nil { panic(err) } } else { salsa20.XORKeyStream(encRs, encRs, h.rNonce[:], h.key) } // Send that to client h.conn.Write(append(encPub, append( encRs, idTag(h.Conf.Id, h.Conf.TimeSync, encPub)..., )...)) h.LastPing = time.Now() } else // ENC(K, R+1, RS + RC + SC + Sign(DSAPriv, K)) + IDtag if h.rClient == nil && ((!h.Conf.Encless && len(data) >= 120) || (h.Conf.Encless && len(data) == EnclessEnlargeSize+h.Conf.MTU)) { var dec []byte var err error if h.Conf.Encless { dec, err = EnclessDecode( h.key, h.rNonceNext(1), data[:len(data)-xtea.BlockSize], ) if err != nil { log.Println("Unable to decode packet from", h.addr, err) return nil } dec = dec[:RSize+RSize+SSize+ed25519.SignatureSize] } else { dec = make([]byte, RSize+RSize+SSize+ed25519.SignatureSize) salsa20.XORKeyStream( dec, data[:RSize+RSize+SSize+ed25519.SignatureSize], h.rNonceNext(1), h.key, ) } if subtle.ConstantTimeCompare(dec[:RSize], h.rServer[:]) != 1 { log.Println("Invalid server's random number with", h.addr) return nil } sign := new([ed25519.SignatureSize]byte) copy(sign[:], dec[RSize+RSize+SSize:]) if !ed25519.Verify(h.Conf.Verifier.Pub, h.key[:], sign) { log.Println("Invalid signature from", h.addr) return nil } // Send final answer to client var enc []byte if h.Conf.Noise { enc = make([]byte, h.Conf.MTU-xtea.BlockSize) } else { enc = make([]byte, RSize) } copy(enc, dec[RSize:RSize+RSize]) if h.Conf.Encless { enc, err = EnclessEncode(h.key, h.rNonceNext(2), enc) if err != nil { panic(err) } } else { salsa20.XORKeyStream(enc, enc, h.rNonceNext(2), h.key) } h.conn.Write(append(enc, idTag(h.Conf.Id, h.Conf.TimeSync, enc)...)) // Switch peer peer := newPeer( false, h.addr, h.conn, h.Conf, keyFromSecrets(h.sServer[:], dec[RSize+RSize:RSize+RSize+SSize])) h.LastPing = time.Now() return peer } else { log.Println("Invalid handshake message from", h.addr) } return nil }
func (public *Public) recompute() (err error) { extra25519.RepresentativeToPublicKey(&public.public, &public.uniform) return }
// Process handshake message on the client side. // This function is intended to be called on client's side. // If this is the final handshake message, then new Peer object // will be created and used as a transport. If no mutually // authenticated Peer is ready, then return nil. func (h *Handshake) Client(data []byte) *Peer { // ENC(H(DSAPub), R+1, El(SDHPub)) + ENC(K, R, RS + SS) + IDtag if h.rServer == nil && h.key == nil { // Decrypt remote public key and compute shared key sDHRepr := new([32]byte) salsa20.XORKeyStream(sDHRepr[:], data[:32], h.rNonceNext(1), h.dsaPubH) sDH := new([32]byte) extra25519.RepresentativeToPublicKey(sDH, sDHRepr) h.key = dhKeyGen(h.dhPriv, sDH) // Decrypt Rs decRs := make([]byte, RSize+SSize) salsa20.XORKeyStream(decRs, data[SSize:32+RSize+SSize], h.rNonce[:], h.key) h.rServer = new([RSize]byte) copy(h.rServer[:], decRs[:RSize]) h.sServer = new([SSize]byte) copy(h.sServer[:], decRs[RSize:]) // Generate R* and signature and encrypt them h.rClient = new([RSize]byte) if err := randRead(h.rClient[:]); err != nil { log.Fatalln("Error reading random for R:", err) } h.sClient = new([SSize]byte) if err := randRead(h.sClient[:]); err != nil { log.Fatalln("Error reading random for S:", err) } sign := ed25519.Sign(h.Conf.DSAPriv, h.key[:]) var enc []byte if h.Conf.Noise { enc = make([]byte, MTU-xtea.BlockSize) } else { enc = make([]byte, RSize+RSize+SSize+ed25519.SignatureSize) } copy(enc, append(h.rServer[:], append(h.rClient[:], append(h.sClient[:], sign[:]...)...)...)) salsa20.XORKeyStream(enc, enc, h.rNonceNext(1), h.key) // Send that to server h.conn.Write(append(enc, idTag(h.Conf.Id, enc)...)) h.LastPing = time.Now() } else // ENC(K, R+2, RC) + IDtag if h.key != nil { // Decrypt rClient dec := make([]byte, RSize) salsa20.XORKeyStream(dec, data[:RSize], h.rNonceNext(2), h.key) if subtle.ConstantTimeCompare(dec, h.rClient[:]) != 1 { log.Println("Invalid client's random number with", h.addr) return nil } // Switch peer peer := newPeer( true, h.addr, h.conn, h.Conf, keyFromSecrets(h.sServer[:], h.sClient[:]), ) h.LastPing = time.Now() return peer } else { log.Println("Invalid handshake stage from", h.addr) } return nil }
// Process handshake message on the server side. // This function is intended to be called on server's side. // If this is the final handshake message, then new Peer object // will be created and used as a transport. If no mutually // authenticated Peer is ready, then return nil. func (h *Handshake) Server(data []byte) *Peer { // R + ENC(H(DSAPub), R, El(CDHPub)) + IDtag if h.rNonce == nil { // Generate DH keypair var dhPubRepr *[32]byte h.dhPriv, dhPubRepr = dhKeypairGen() h.rNonce = new([RSize]byte) copy(h.rNonce[:], data[:RSize]) // Decrypt remote public key and compute shared key cDHRepr := new([32]byte) salsa20.XORKeyStream( cDHRepr[:], data[RSize:RSize+32], h.rNonce[:], h.dsaPubH, ) cDH := new([32]byte) extra25519.RepresentativeToPublicKey(cDH, cDHRepr) h.key = dhKeyGen(h.dhPriv, cDH) encPub := make([]byte, 32) salsa20.XORKeyStream(encPub, dhPubRepr[:], h.rNonceNext(1), h.dsaPubH) // Generate R* and encrypt them h.rServer = new([RSize]byte) if err := randRead(h.rServer[:]); err != nil { log.Fatalln("Error reading random for R:", err) } h.sServer = new([SSize]byte) if err := randRead(h.sServer[:]); err != nil { log.Fatalln("Error reading random for S:", err) } var encRs []byte if h.Conf.Noise { encRs = make([]byte, MTU-len(encPub)-xtea.BlockSize) } else { encRs = make([]byte, RSize+SSize) } copy(encRs, append(h.rServer[:], h.sServer[:]...)) salsa20.XORKeyStream(encRs, encRs, h.rNonce[:], h.key) // Send that to client h.conn.Write(append(encPub, append(encRs, idTag(h.Conf.Id, encPub)...)...)) h.LastPing = time.Now() } else // ENC(K, R+1, RS + RC + SC + Sign(DSAPriv, K)) + IDtag if h.rClient == nil { // Decrypted Rs compare rServer dec := make([]byte, RSize+RSize+SSize+ed25519.SignatureSize) salsa20.XORKeyStream( dec, data[:RSize+RSize+SSize+ed25519.SignatureSize], h.rNonceNext(1), h.key, ) if subtle.ConstantTimeCompare(dec[:RSize], h.rServer[:]) != 1 { log.Println("Invalid server's random number with", h.addr) return nil } sign := new([ed25519.SignatureSize]byte) copy(sign[:], dec[RSize+RSize+SSize:]) if !ed25519.Verify(h.Conf.DSAPub, h.key[:], sign) { log.Println("Invalid signature from", h.addr) return nil } // Send final answer to client var enc []byte if h.Conf.Noise { enc = make([]byte, MTU-xtea.BlockSize) } else { enc = make([]byte, RSize) } copy(enc, dec[RSize:RSize+RSize]) salsa20.XORKeyStream(enc, enc, h.rNonceNext(2), h.key) h.conn.Write(append(enc, idTag(h.Conf.Id, enc)...)) // Switch peer peer := newPeer( false, h.addr, h.conn, h.Conf, keyFromSecrets(h.sServer[:], dec[RSize+RSize:RSize+RSize+SSize])) h.LastPing = time.Now() return peer } else { log.Println("Invalid handshake message from", h.addr) } return nil }