@ -48,19 +48,45 @@ import (
// This type is not generally safe for concurrent use, but reading and writing of messages
// This type is not generally safe for concurrent use, but reading and writing of messages
// may happen concurrently after the handshake.
// may happen concurrently after the handshake.
type Conn struct {
type Conn struct {
dialDest * ecdsa . PublicKey
dialDest * ecdsa . PublicKey
conn net . Conn
conn net . Conn
handshake * handshakeState
session * sessionState
snappy bool
// These are the buffers for snappy compression.
// Compression is enabled if they are non-nil.
snappyReadBuffer [ ] byte
snappyWriteBuffer [ ] byte
}
}
type handshakeState struct {
// sessionState contains the session keys.
type sessionState struct {
enc cipher . Stream
enc cipher . Stream
dec cipher . Stream
dec cipher . Stream
macCipher cipher . Block
egressMAC hashMAC
egressMAC hash . Hash
ingressMAC hashMAC
ingressMAC hash . Hash
rbuf readBuffer
wbuf writeBuffer
}
// hashMAC holds the state of the RLPx v4 MAC contraption.
type hashMAC struct {
cipher cipher . Block
hash hash . Hash
aesBuffer [ 16 ] byte
hashBuffer [ 32 ] byte
seedBuffer [ 32 ] byte
}
func newHashMAC ( cipher cipher . Block , h hash . Hash ) hashMAC {
m := hashMAC { cipher : cipher , hash : h }
if cipher . BlockSize ( ) != len ( m . aesBuffer ) {
panic ( fmt . Errorf ( "invalid MAC cipher block size %d" , cipher . BlockSize ( ) ) )
}
if h . Size ( ) != len ( m . hashBuffer ) {
panic ( fmt . Errorf ( "invalid MAC digest size %d" , h . Size ( ) ) )
}
return m
}
}
// NewConn wraps the given network connection. If dialDest is non-nil, the connection
// NewConn wraps the given network connection. If dialDest is non-nil, the connection
@ -76,7 +102,13 @@ func NewConn(conn net.Conn, dialDest *ecdsa.PublicKey) *Conn {
// after the devp2p Hello message exchange when the negotiated version indicates that
// after the devp2p Hello message exchange when the negotiated version indicates that
// compression is available on both ends of the connection.
// compression is available on both ends of the connection.
func ( c * Conn ) SetSnappy ( snappy bool ) {
func ( c * Conn ) SetSnappy ( snappy bool ) {
c . snappy = snappy
if snappy {
c . snappyReadBuffer = [ ] byte { }
c . snappyWriteBuffer = [ ] byte { }
} else {
c . snappyReadBuffer = nil
c . snappyWriteBuffer = nil
}
}
}
// SetReadDeadline sets the deadline for all future read operations.
// SetReadDeadline sets the deadline for all future read operations.
@ -95,12 +127,13 @@ func (c *Conn) SetDeadline(time time.Time) error {
}
}
// Read reads a message from the connection.
// Read reads a message from the connection.
// The returned data buffer is valid until the next call to Read.
func ( c * Conn ) Read ( ) ( code uint64 , data [ ] byte , wireSize int , err error ) {
func ( c * Conn ) Read ( ) ( code uint64 , data [ ] byte , wireSize int , err error ) {
if c . hand shak e == nil {
if c . session == nil {
panic ( "can't ReadMsg before handshake" )
panic ( "can't ReadMsg before handshake" )
}
}
frame , err := c . hand shak e. readFrame ( c . conn )
frame , err := c . session . readFrame ( c . conn )
if err != nil {
if err != nil {
return 0 , nil , 0 , err
return 0 , nil , 0 , err
}
}
@ -111,7 +144,7 @@ func (c *Conn) Read() (code uint64, data []byte, wireSize int, err error) {
wireSize = len ( data )
wireSize = len ( data )
// If snappy is enabled, verify and decompress message.
// If snappy is enabled, verify and decompress message.
if c . snappy {
if c . snappyReadBuffer != nil {
var actualSize int
var actualSize int
actualSize , err = snappy . DecodedLen ( data )
actualSize , err = snappy . DecodedLen ( data )
if err != nil {
if err != nil {
@ -120,51 +153,55 @@ func (c *Conn) Read() (code uint64, data []byte, wireSize int, err error) {
if actualSize > maxUint24 {
if actualSize > maxUint24 {
return code , nil , 0 , errPlainMessageTooLarge
return code , nil , 0 , errPlainMessageTooLarge
}
}
data , err = snappy . Decode ( nil , data )
c . snappyReadBuffer = growslice ( c . snappyReadBuffer , actualSize )
data , err = snappy . Decode ( c . snappyReadBuffer , data )
}
}
return code , data , wireSize , err
return code , data , wireSize , err
}
}
func ( h * handshakeState ) readFrame ( conn io . Reader ) ( [ ] byte , error ) {
func ( h * sessionState ) readFrame ( conn io . Reader ) ( [ ] byte , error ) {
// read the header
h . rbuf . reset ( )
headbuf := make ( [ ] byte , 32 )
if _ , err := io . ReadFull ( conn , headbuf ) ; err != nil {
// Read the frame header.
header , err := h . rbuf . read ( conn , 32 )
if err != nil {
return nil , err
return nil , err
}
}
// verify header mac
// Verify header MAC.
should MAC := updateMAC ( h . ingressMAC , h . macCipher , headbuf [ : 16 ] )
wantHeader MAC := h . ingressMAC . computeHeader ( header [ : 16 ] )
if ! hmac . Equal ( shouldMAC , headbuf [ 16 : ] ) {
if ! hmac . Equal ( wantHeaderMAC , header [ 16 : ] ) {
return nil , errors . New ( "bad header MAC" )
return nil , errors . New ( "bad header MAC" )
}
}
h . dec . XORKeyStream ( headbuf [ : 16 ] , headbuf [ : 16 ] ) // first half is now decrypted
fsize := readInt24 ( headbuf )
// ignore protocol type for now
// read the frame content
// Decrypt the frame header to get the frame size.
var rsize = fsize // frame size rounded up to 16 byte boundary
h . dec . XORKeyStream ( header [ : 16 ] , header [ : 16 ] )
fsize := readUint24 ( header [ : 16 ] )
// Frame size rounded up to 16 byte boundary for padding.
rsize := fsize
if padding := fsize % 16 ; padding > 0 {
if padding := fsize % 16 ; padding > 0 {
rsize += 16 - padding
rsize += 16 - padding
}
}
framebuf := make ( [ ] byte , rsize )
if _ , err := io . ReadFull ( conn , framebuf ) ; err != nil {
// Read the frame content.
frame , err := h . rbuf . read ( conn , int ( rsize ) )
if err != nil {
return nil , err
return nil , err
}
}
// read and validate frame MAC. we can re-use headbuf for that.
// Validate frame MAC.
h . ingressMAC . Write ( framebuf )
frameMAC , err := h . rbuf . read ( conn , 16 )
fmacseed := h . ingressMAC . Sum ( nil )
if err != nil {
if _ , err := io . ReadFull ( conn , headbuf [ : 16 ] ) ; err != nil {
return nil , err
return nil , err
}
}
shouldMAC = updateMAC ( h . ingressMAC , h . macCipher , fmacseed )
wantFrameMAC := h . ingressMAC . computeFrame ( frame )
if ! hmac . Equal ( shouldMAC , headbuf [ : 16 ] ) {
if ! hmac . Equal ( wantFrameMAC , frameMAC ) {
return nil , errors . New ( "bad frame MAC" )
return nil , errors . New ( "bad frame MAC" )
}
}
// decrypt frame content
// Decrypt the frame data.
h . dec . XORKeyStream ( framebuf , framebuf )
h . dec . XORKeyStream ( frame , frame )
return framebuf [ : fsize ] , nil
return frame [ : fsize ] , nil
}
}
// Write writes a message to the connection.
// Write writes a message to the connection.
@ -172,83 +209,90 @@ func (h *handshakeState) readFrame(conn io.Reader) ([]byte, error) {
// Write returns the written size of the message data. This may be less than or equal to
// Write returns the written size of the message data. This may be less than or equal to
// len(data) depending on whether snappy compression is enabled.
// len(data) depending on whether snappy compression is enabled.
func ( c * Conn ) Write ( code uint64 , data [ ] byte ) ( uint32 , error ) {
func ( c * Conn ) Write ( code uint64 , data [ ] byte ) ( uint32 , error ) {
if c . hand shak e == nil {
if c . session == nil {
panic ( "can't WriteMsg before handshake" )
panic ( "can't WriteMsg before handshake" )
}
}
if len ( data ) > maxUint24 {
if len ( data ) > maxUint24 {
return 0 , errPlainMessageTooLarge
return 0 , errPlainMessageTooLarge
}
}
if c . snappy {
if c . snappyWriteBuffer != nil {
data = snappy . Encode ( nil , data )
// Ensure the buffer has sufficient size.
// Package snappy will allocate its own buffer if the provided
// one is smaller than MaxEncodedLen.
c . snappyWriteBuffer = growslice ( c . snappyWriteBuffer , snappy . MaxEncodedLen ( len ( data ) ) )
data = snappy . Encode ( c . snappyWriteBuffer , data )
}
}
wireSize := uint32 ( len ( data ) )
wireSize := uint32 ( len ( data ) )
err := c . handshake . writeFrame ( c . conn , code , data )
err := c . session . writeFrame ( c . conn , code , data )
return wireSize , err
return wireSize , err
}
}
func ( h * hand shak eState) writeFrame ( conn io . Writer , code uint64 , data [ ] byte ) error {
func ( h * session State ) writeFrame ( conn io . Writer , code uint64 , data [ ] byte ) error {
ptype , _ := rlp . EncodeToBytes ( code )
h . wbuf . reset ( )
// write header
// Write header.
headbuf := make ( [ ] byte , 32 )
fsize := rlp . IntSize ( code ) + len ( data )
fsize := len ( ptype ) + len ( data )
if fsize > maxUint24 {
if fsize > maxUint24 {
return errPlainMessageTooLarge
return errPlainMessageTooLarge
}
}
putInt24 ( uint32 ( fsize ) , headbuf )
header := h . wbuf . appendZero ( 16 )
copy ( headbuf [ 3 : ] , zeroHeader )
putUint24 ( uint32 ( fsize ) , header )
h . enc . XORKeyStream ( headbuf [ : 16 ] , headbuf [ : 16 ] ) // first half is now encrypted
copy ( header [ 3 : ] , zeroHeader )
h . enc . XORKeyStream ( header , header )
// write header MAC
// Write header MAC.
copy ( headbuf [ 16 : ] , updateMAC ( h . egressMAC , h . macCipher , headbuf [ : 16 ] ) )
h . wbuf . Write ( h . egressMAC . computeHeader ( header ) )
if _ , err := conn . Write ( headbuf ) ; err != nil {
return err
}
// write encrypted frame, updating the egress MAC hash with
// Encode and encrypt the frame data.
// the data written to conn.
offset := len ( h . wbuf . data )
tee := cipher . StreamWriter { S : h . enc , W : io . MultiWriter ( conn , h . egressMAC ) }
h . wbuf . data = rlp . AppendUint64 ( h . wbuf . data , code )
if _ , err := tee . Write ( ptype ) ; err != nil {
h . wbuf . Write ( data )
return err
}
if _ , err := tee . Write ( data ) ; err != nil {
return err
}
if padding := fsize % 16 ; padding > 0 {
if padding := fsize % 16 ; padding > 0 {
if _ , err := tee . Write ( zero16 [ : 16 - padding ] ) ; err != nil {
h . wbuf . appendZero ( 16 - padding )
return err
}
}
}
framedata := h . wbuf . data [ offset : ]
h . enc . XORKeyStream ( framedata , framedata )
// write frame MAC. egress MAC hash is up to date because
// Write frame MAC.
// frame content was written to it as well.
h . wbuf . Write ( h . egressMAC . computeFrame ( framedata ) )
fmacseed := h . egressMAC . Sum ( nil )
mac := updateMAC ( h . egressMAC , h . macCipher , fmacseed )
_ , err := conn . Write ( h . wbuf . data )
_ , err := conn . Write ( mac )
return err
return err
}
}
func readInt24 ( b [ ] byte ) uint32 {
// computeHeader computes the MAC of a frame header.
return uint32 ( b [ 2 ] ) | uint32 ( b [ 1 ] ) << 8 | uint32 ( b [ 0 ] ) << 16
func ( m * hashMAC ) computeHeader ( header [ ] byte ) [ ] byte {
sum1 := m . hash . Sum ( m . hashBuffer [ : 0 ] )
return m . compute ( sum1 , header )
}
}
func putInt24 ( v uint32 , b [ ] byte ) {
// computeFrame computes the MAC of framedata.
b [ 0 ] = byte ( v >> 16 )
func ( m * hashMAC ) computeFrame ( framedata [ ] byte ) [ ] byte {
b [ 1 ] = byte ( v >> 8 )
m . hash . Write ( framedata )
b [ 2 ] = byte ( v )
seed := m . hash . Sum ( m . seedBuffer [ : 0 ] )
return m . compute ( seed , seed [ : 16 ] )
}
}
// updateMAC reseeds the given hash with encrypted seed.
// compute computes the MAC of a 16-byte 'seed'.
// it returns the first 16 bytes of the hash sum after seeding.
//
func updateMAC ( mac hash . Hash , block cipher . Block , seed [ ] byte ) [ ] byte {
// To do this, it encrypts the current value of the hash state, then XORs the ciphertext
aesbuf := make ( [ ] byte , aes . BlockSize )
// with seed. The obtained value is written back into the hash state and hash output is
block . Encrypt ( aesbuf , mac . Sum ( nil ) )
// taken again. The first 16 bytes of the resulting sum are the MAC value.
for i := range aesbuf {
//
aesbuf [ i ] ^ = seed [ i ]
// This MAC construction is a horrible, legacy thing.
func ( m * hashMAC ) compute ( sum1 , seed [ ] byte ) [ ] byte {
if len ( seed ) != len ( m . aesBuffer ) {
panic ( "invalid MAC seed" )
}
m . cipher . Encrypt ( m . aesBuffer [ : ] , sum1 )
for i := range m . aesBuffer {
m . aesBuffer [ i ] ^ = seed [ i ]
}
}
mac . Write ( aesbuf )
m . hash . Write ( m . aesBuffer [ : ] )
return mac . Sum ( nil ) [ : 16 ]
sum2 := m . hash . Sum ( m . hashBuffer [ : 0 ] )
return sum2 [ : 16 ]
}
}
// Handshake performs the handshake. This must be called before any data is written
// Handshake performs the handshake. This must be called before any data is written
@ -257,23 +301,26 @@ func (c *Conn) Handshake(prv *ecdsa.PrivateKey) (*ecdsa.PublicKey, error) {
var (
var (
sec Secrets
sec Secrets
err error
err error
h handshakeState
)
)
if c . dialDest != nil {
if c . dialDest != nil {
sec , err = initiatorEncHandshake ( c . conn , prv , c . dialDest )
sec , err = h . runInitiator ( c . conn , prv , c . dialDest )
} else {
} else {
sec , err = receiverEncHandshake ( c . conn , prv )
sec , err = h . runRecipient ( c . conn , prv )
}
}
if err != nil {
if err != nil {
return nil , err
return nil , err
}
}
c . InitWithSecrets ( sec )
c . InitWithSecrets ( sec )
c . session . rbuf = h . rbuf
c . session . wbuf = h . wbuf
return sec . remote , err
return sec . remote , err
}
}
// InitWithSecrets injects connection secrets as if a handshake had
// InitWithSecrets injects connection secrets as if a handshake had
// been performed. This cannot be called after the handshake.
// been performed. This cannot be called after the handshake.
func ( c * Conn ) InitWithSecrets ( sec Secrets ) {
func ( c * Conn ) InitWithSecrets ( sec Secrets ) {
if c . hand shak e != nil {
if c . session != nil {
panic ( "can't handshake twice" )
panic ( "can't handshake twice" )
}
}
macc , err := aes . NewCipher ( sec . MAC )
macc , err := aes . NewCipher ( sec . MAC )
@ -287,12 +334,11 @@ func (c *Conn) InitWithSecrets(sec Secrets) {
// we use an all-zeroes IV for AES because the key used
// we use an all-zeroes IV for AES because the key used
// for encryption is ephemeral.
// for encryption is ephemeral.
iv := make ( [ ] byte , encc . BlockSize ( ) )
iv := make ( [ ] byte , encc . BlockSize ( ) )
c . hand shak e = & hand shak eState{
c . session = & session State {
enc : cipher . NewCTR ( encc , iv ) ,
enc : cipher . NewCTR ( encc , iv ) ,
dec : cipher . NewCTR ( encc , iv ) ,
dec : cipher . NewCTR ( encc , iv ) ,
macCipher : macc ,
egressMAC : newHashMAC ( macc , sec . EgressMAC ) ,
egressMAC : sec . EgressMAC ,
ingressMAC : newHashMAC ( macc , sec . IngressMAC ) ,
ingressMAC : sec . IngressMAC ,
}
}
}
}
@ -303,28 +349,18 @@ func (c *Conn) Close() error {
// Constants for the handshake.
// Constants for the handshake.
const (
const (
maxUint24 = int ( ^ uint32 ( 0 ) >> 8 )
sskLen = 16 // ecies.MaxSharedKeyLength(pubKey) / 2
sskLen = 16 // ecies.MaxSharedKeyLength(pubKey) / 2
sigLen = crypto . SignatureLength // elliptic S256
sigLen = crypto . SignatureLength // elliptic S256
pubLen = 64 // 512 bit pubkey in uncompressed representation without format byte
pubLen = 64 // 512 bit pubkey in uncompressed representation without format byte
shaLen = 32 // hash length (for nonce etc)
shaLen = 32 // hash length (for nonce etc)
authMsgLen = sigLen + shaLen + pubLen + shaLen + 1
authRespLen = pubLen + shaLen + 1
eciesOverhead = 65 /* pubkey */ + 16 /* IV */ + 32 /* MAC */
eciesOverhead = 65 /* pubkey */ + 16 /* IV */ + 32 /* MAC */
encAuthMsgLen = authMsgLen + eciesOverhead // size of encrypted pre-EIP-8 initiator handshake
encAuthRespLen = authRespLen + eciesOverhead // size of encrypted pre-EIP-8 handshake reply
)
)
var (
var (
// this is used in place of actual frame header data.
// this is used in place of actual frame header data.
// TODO: replace this when Msg contains the protocol type code.
// TODO: replace this when Msg contains the protocol type code.
zeroHeader = [ ] byte { 0xC2 , 0x80 , 0x80 }
zeroHeader = [ ] byte { 0xC2 , 0x80 , 0x80 }
// sixteen zero bytes
zero16 = make ( [ ] byte , 16 )
// errPlainMessageTooLarge is returned if a decompressed message length exceeds
// errPlainMessageTooLarge is returned if a decompressed message length exceeds
// the allowed 24 bits (i.e. length >= 16MB).
// the allowed 24 bits (i.e. length >= 16MB).
@ -338,19 +374,20 @@ type Secrets struct {
remote * ecdsa . PublicKey
remote * ecdsa . PublicKey
}
}
// encHandshak e contains the state of the encryption handshake.
// handshakeStat e contains the state of the encryption handshake.
type encHandshak e struct {
type handshakeStat e struct {
initiator bool
initiator bool
remote * ecies . PublicKey // remote-pubk
remote * ecies . PublicKey // remote-pubk
initNonce , respNonce [ ] byte // nonce
initNonce , respNonce [ ] byte // nonce
randomPrivKey * ecies . PrivateKey // ecdhe-random
randomPrivKey * ecies . PrivateKey // ecdhe-random
remoteRandomPub * ecies . PublicKey // ecdhe-random-pubk
remoteRandomPub * ecies . PublicKey // ecdhe-random-pubk
rbuf readBuffer
wbuf writeBuffer
}
}
// RLPx v4 handshake auth (defined in EIP-8).
// RLPx v4 handshake auth (defined in EIP-8).
type authMsgV4 struct {
type authMsgV4 struct {
gotPlain bool // whether read packet had plain format.
Signature [ sigLen ] byte
Signature [ sigLen ] byte
InitiatorPubkey [ pubLen ] byte
InitiatorPubkey [ pubLen ] byte
Nonce [ shaLen ] byte
Nonce [ shaLen ] byte
@ -370,17 +407,16 @@ type authRespV4 struct {
Rest [ ] rlp . RawValue ` rlp:"tail" `
Rest [ ] rlp . RawValue ` rlp:"tail" `
}
}
// receiverEncHandshake negotiates a session token on conn.
// runRecipient negotiates a session token on conn.
// it should be called on the listening side of the connection.
// it should be called on the listening side of the connection.
//
//
// prv is the local client's private key.
// prv is the local client's private key.
func receiverEncHandshake ( conn io . ReadWriter , prv * ecdsa . PrivateKey ) ( s Secrets , err error ) {
func ( h * handshakeState ) runRecipient ( conn io . ReadWriter , prv * ecdsa . PrivateKey ) ( s Secrets , err error ) {
authMsg := new ( authMsgV4 )
authMsg := new ( authMsgV4 )
authPacket , err := readHandshakeMsg ( authMsg , encAuthMsgLen , prv , conn )
authPacket , err := h . readMsg ( authMsg , prv , conn )
if err != nil {
if err != nil {
return s , err
return s , err
}
}
h := new ( encHandshake )
if err := h . handleAuthMsg ( authMsg , prv ) ; err != nil {
if err := h . handleAuthMsg ( authMsg , prv ) ; err != nil {
return s , err
return s , err
}
}
@ -389,22 +425,18 @@ func receiverEncHandshake(conn io.ReadWriter, prv *ecdsa.PrivateKey) (s Secrets,
if err != nil {
if err != nil {
return s , err
return s , err
}
}
var authRespPacket [ ] byte
authRespPacket , err := h . sealEIP8 ( authRespMsg )
if authMsg . gotPlain {
authRespPacket , err = authRespMsg . sealPlain ( h )
} else {
authRespPacket , err = sealEIP8 ( authRespMsg , h )
}
if err != nil {
if err != nil {
return s , err
return s , err
}
}
if _ , err = conn . Write ( authRespPacket ) ; err != nil {
if _ , err = conn . Write ( authRespPacket ) ; err != nil {
return s , err
return s , err
}
}
return h . secrets ( authPacket , authRespPacket )
return h . secrets ( authPacket , authRespPacket )
}
}
func ( h * encHandshak e) handleAuthMsg ( msg * authMsgV4 , prv * ecdsa . PrivateKey ) error {
func ( h * handshakeStat e) handleAuthMsg ( msg * authMsgV4 , prv * ecdsa . PrivateKey ) error {
// Import the remote identity.
// Import the remote identity.
rpub , err := importPublicKey ( msg . InitiatorPubkey [ : ] )
rpub , err := importPublicKey ( msg . InitiatorPubkey [ : ] )
if err != nil {
if err != nil {
@ -438,7 +470,7 @@ func (h *encHandshake) handleAuthMsg(msg *authMsgV4, prv *ecdsa.PrivateKey) erro
// secrets is called after the handshake is completed.
// secrets is called after the handshake is completed.
// It extracts the connection secrets from the handshake values.
// It extracts the connection secrets from the handshake values.
func ( h * encHandshak e) secrets ( auth , authResp [ ] byte ) ( Secrets , error ) {
func ( h * handshakeStat e) secrets ( auth , authResp [ ] byte ) ( Secrets , error ) {
ecdheSecret , err := h . randomPrivKey . GenerateShared ( h . remoteRandomPub , sskLen , sskLen )
ecdheSecret , err := h . randomPrivKey . GenerateShared ( h . remoteRandomPub , sskLen , sskLen )
if err != nil {
if err != nil {
return Secrets { } , err
return Secrets { } , err
@ -471,21 +503,23 @@ func (h *encHandshake) secrets(auth, authResp []byte) (Secrets, error) {
// staticSharedSecret returns the static shared secret, the result
// staticSharedSecret returns the static shared secret, the result
// of key agreement between the local and remote static node key.
// of key agreement between the local and remote static node key.
func ( h * encHandshak e) staticSharedSecret ( prv * ecdsa . PrivateKey ) ( [ ] byte , error ) {
func ( h * handshakeStat e) staticSharedSecret ( prv * ecdsa . PrivateKey ) ( [ ] byte , error ) {
return ecies . ImportECDSA ( prv ) . GenerateShared ( h . remote , sskLen , sskLen )
return ecies . ImportECDSA ( prv ) . GenerateShared ( h . remote , sskLen , sskLen )
}
}
// initiatorEncHandshake negotiates a session token on conn.
// runInitiator negotiates a session token on conn.
// it should be called on the dialing side of the connection.
// it should be called on the dialing side of the connection.
//
//
// prv is the local client's private key.
// prv is the local client's private key.
func initiatorEncHandshake ( conn io . ReadWriter , prv * ecdsa . PrivateKey , remote * ecdsa . PublicKey ) ( s Secrets , err error ) {
func ( h * handshakeState ) runInitiator ( conn io . ReadWriter , prv * ecdsa . PrivateKey , remote * ecdsa . PublicKey ) ( s Secrets , err error ) {
h := & encHandshake { initiator : true , remote : ecies . ImportECDSAPublic ( remote ) }
h . initiator = true
h . remote = ecies . ImportECDSAPublic ( remote )
authMsg , err := h . makeAuthMsg ( prv )
authMsg , err := h . makeAuthMsg ( prv )
if err != nil {
if err != nil {
return s , err
return s , err
}
}
authPacket , err := sealEIP8 ( authMsg , h )
authPacket , err := h . sealEIP8 ( authMsg )
if err != nil {
if err != nil {
return s , err
return s , err
}
}
@ -495,18 +529,19 @@ func initiatorEncHandshake(conn io.ReadWriter, prv *ecdsa.PrivateKey, remote *ec
}
}
authRespMsg := new ( authRespV4 )
authRespMsg := new ( authRespV4 )
authRespPacket , err := readHandshakeMsg ( authRespMsg , encAuthRespLen , prv , conn )
authRespPacket , err := h . readMsg ( authRespMsg , prv , conn )
if err != nil {
if err != nil {
return s , err
return s , err
}
}
if err := h . handleAuthResp ( authRespMsg ) ; err != nil {
if err := h . handleAuthResp ( authRespMsg ) ; err != nil {
return s , err
return s , err
}
}
return h . secrets ( authPacket , authRespPacket )
return h . secrets ( authPacket , authRespPacket )
}
}
// makeAuthMsg creates the initiator handshake message.
// makeAuthMsg creates the initiator handshake message.
func ( h * encHandshak e) makeAuthMsg ( prv * ecdsa . PrivateKey ) ( * authMsgV4 , error ) {
func ( h * handshakeStat e) makeAuthMsg ( prv * ecdsa . PrivateKey ) ( * authMsgV4 , error ) {
// Generate random initiator nonce.
// Generate random initiator nonce.
h . initNonce = make ( [ ] byte , shaLen )
h . initNonce = make ( [ ] byte , shaLen )
_ , err := rand . Read ( h . initNonce )
_ , err := rand . Read ( h . initNonce )
@ -538,13 +573,13 @@ func (h *encHandshake) makeAuthMsg(prv *ecdsa.PrivateKey) (*authMsgV4, error) {
return msg , nil
return msg , nil
}
}
func ( h * encHandshak e) handleAuthResp ( msg * authRespV4 ) ( err error ) {
func ( h * handshakeStat e) handleAuthResp ( msg * authRespV4 ) ( err error ) {
h . respNonce = msg . Nonce [ : ]
h . respNonce = msg . Nonce [ : ]
h . remoteRandomPub , err = importPublicKey ( msg . RandomPubkey [ : ] )
h . remoteRandomPub , err = importPublicKey ( msg . RandomPubkey [ : ] )
return err
return err
}
}
func ( h * encHandshak e) makeAuthResp ( ) ( msg * authRespV4 , err error ) {
func ( h * handshakeStat e) makeAuthResp ( ) ( msg * authRespV4 , err error ) {
// Generate random nonce.
// Generate random nonce.
h . respNonce = make ( [ ] byte , shaLen )
h . respNonce = make ( [ ] byte , shaLen )
if _ , err = rand . Read ( h . respNonce ) ; err != nil {
if _ , err = rand . Read ( h . respNonce ) ; err != nil {
@ -558,81 +593,53 @@ func (h *encHandshake) makeAuthResp() (msg *authRespV4, err error) {
return msg , nil
return msg , nil
}
}
func ( msg * authMsgV4 ) decodePlain ( input [ ] byte ) {
// readMsg reads an encrypted handshake message, decoding it into msg.
n := copy ( msg . Signature [ : ] , input )
func ( h * handshakeState ) readMsg ( msg interface { } , prv * ecdsa . PrivateKey , r io . Reader ) ( [ ] byte , error ) {
n += shaLen // skip sha3(initiator-ephemeral-pubk)
h . rbuf . reset ( )
n += copy ( msg . InitiatorPubkey [ : ] , input [ n : ] )
h . rbuf . grow ( 512 )
copy ( msg . Nonce [ : ] , input [ n : ] )
msg . Version = 4
msg . gotPlain = true
}
func ( msg * authRespV4 ) sealPlain ( hs * encHandshake ) ( [ ] byte , error ) {
// Read the size prefix.
buf := make ( [ ] byte , authRespLen )
prefix , err := h . rbuf . read ( r , 2 )
n := copy ( buf , msg . RandomPubkey [ : ] )
if err != nil {
copy ( buf [ n : ] , msg . Nonce [ : ] )
return nil , err
return ecies . Encrypt ( rand . Reader , hs . remote , buf , nil , nil )
}
}
size := binary . BigEndian . Uint16 ( prefix )
func ( msg * authRespV4 ) decodePlain ( input [ ] byte ) {
// Read the handshake packet.
n := copy ( msg . RandomPubkey [ : ] , input )
packet , err := h . rbuf . read ( r , int ( size ) )
copy ( msg . Nonce [ : ] , input [ n : ] )
if err != nil {
msg . Version = 4
return nil , err
}
dec , err := ecies . ImportECDSA ( prv ) . Decrypt ( packet , nil , prefix )
if err != nil {
return nil , err
}
// Can't use rlp.DecodeBytes here because it rejects
// trailing data (forward-compatibility).
s := rlp . NewStream ( bytes . NewReader ( dec ) , 0 )
err = s . Decode ( msg )
return h . rbuf . data [ : len ( prefix ) + len ( packet ) ] , err
}
}
var padSpace = make ( [ ] byte , 300 )
// sealEIP8 encrypts a handshake message.
func ( h * handshakeState ) sealEIP8 ( msg interface { } ) ( [ ] byte , error ) {
h . wbuf . reset ( )
func sealEIP8 ( msg interface { } , h * encHandshake ) ( [ ] byte , error ) {
// Write the message plaintext.
buf := new ( bytes . Buffer )
if err := rlp . Encode ( & h . wbuf , msg ) ; err != nil {
if err := rlp . Encode ( buf , msg ) ; err != nil {
return nil , err
return nil , err
}
}
// pad with random amount of data. the amount needs to be at least 100 bytes to make
// P ad with random amount of data. the amount needs to be at least 100 bytes to make
// the message distinguishable from pre-EIP-8 handshakes.
// the message distinguishable from pre-EIP-8 handshakes.
pad := padSpace [ : mrand . Intn ( len ( padSpace ) - 100 ) + 100 ]
h . wbuf . appendZero ( mrand . Intn ( 100 ) + 100 )
buf . Write ( pad )
prefix := make ( [ ] byte , 2 )
prefix := make ( [ ] byte , 2 )
binary . BigEndian . PutUint16 ( prefix , uint16 ( buf . Len ( ) + eciesOverhead ) )
binary . BigEndian . PutUint16 ( prefix , uint16 ( len ( h . wbuf . data ) + eciesOverhead ) )
enc , err := ecies . Encrypt ( rand . Reader , h . remote , buf . Bytes ( ) , nil , prefix )
enc , err := ecies . Encrypt ( rand . Reader , h . remote , h . wbuf . data , nil , prefix )
return append ( prefix , enc ... ) , err
return append ( prefix , enc ... ) , err
}
}
type plainDecoder interface {
decodePlain ( [ ] byte )
}
func readHandshakeMsg ( msg plainDecoder , plainSize int , prv * ecdsa . PrivateKey , r io . Reader ) ( [ ] byte , error ) {
buf := make ( [ ] byte , plainSize )
if _ , err := io . ReadFull ( r , buf ) ; err != nil {
return buf , err
}
// Attempt decoding pre-EIP-8 "plain" format.
key := ecies . ImportECDSA ( prv )
if dec , err := key . Decrypt ( buf , nil , nil ) ; err == nil {
msg . decodePlain ( dec )
return buf , nil
}
// Could be EIP-8 format, try that.
prefix := buf [ : 2 ]
size := binary . BigEndian . Uint16 ( prefix )
if size < uint16 ( plainSize ) {
return buf , fmt . Errorf ( "size underflow, need at least %d bytes" , plainSize )
}
buf = append ( buf , make ( [ ] byte , size - uint16 ( plainSize ) + 2 ) ... )
if _ , err := io . ReadFull ( r , buf [ plainSize : ] ) ; err != nil {
return buf , err
}
dec , err := key . Decrypt ( buf [ 2 : ] , nil , prefix )
if err != nil {
return buf , err
}
// Can't use rlp.DecodeBytes here because it rejects
// trailing data (forward-compatibility).
s := rlp . NewStream ( bytes . NewReader ( dec ) , 0 )
return buf , s . Decode ( msg )
}
// importPublicKey unmarshals 512 bit public keys.
// importPublicKey unmarshals 512 bit public keys.
func importPublicKey ( pubKey [ ] byte ) ( * ecies . PublicKey , error ) {
func importPublicKey ( pubKey [ ] byte ) ( * ecies . PublicKey , error ) {
var pubKey65 [ ] byte
var pubKey65 [ ] byte