Skip to content
This repository has been archived by the owner on Apr 9, 2020. It is now read-only.

Commit

Permalink
Merge pull request #477 from ssoxer/independent-ivs
Browse files Browse the repository at this point in the history
Generate independent IVs in the server
  • Loading branch information
madeye authored Jun 14, 2019
2 parents ac922d1 + 1c9f757 commit 6a03846
Show file tree
Hide file tree
Showing 3 changed files with 92 additions and 24 deletions.
15 changes: 0 additions & 15 deletions shadowsocks/conn.go
Original file line number Diff line number Diff line change
Expand Up @@ -78,18 +78,6 @@ func Dial(addr, server string, cipher *Cipher) (c *Conn, err error) {
return DialWithRawAddr(ra, server, cipher)
}

func (c *Conn) GetIv() (iv []byte) {
iv = make([]byte, len(c.iv))
copy(iv, c.iv)
return
}

func (c *Conn) GetKey() (key []byte) {
key = make([]byte, len(c.key))
copy(key, c.key)
return
}

func (c *Conn) Read(b []byte) (n int, err error) {
if c.dec == nil {
iv := make([]byte, c.info.ivLen)
Expand All @@ -99,9 +87,6 @@ func (c *Conn) Read(b []byte) (n int, err error) {
if err = c.initDecrypt(iv); err != nil {
return
}
if len(c.iv) == 0 {
c.iv = iv
}
}

cipherData := c.readBuf
Expand Down
89 changes: 89 additions & 0 deletions shadowsocks/conn_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
package shadowsocks

import (
"bytes"
"io"
"net"
"testing"
)

func mustNewCipher(method string) *Cipher {
const testPassword = "password"
cipher, err := NewCipher(method, testPassword)
if err != nil {
panic(err)
}
return cipher
}

type transcriptConn struct {
net.Conn
ReadTranscript []byte
}

func (conn *transcriptConn) Read(p []byte) (int, error) {
n, err := conn.Conn.Read(p)
conn.ReadTranscript = append(conn.ReadTranscript, p[:n]...)
return n, err
}

func connIVs(method string) (clientIV, serverIV []byte, err error) {
// underlying network connection
clientConn, serverConn := net.Pipe()
// make a transcript of bytes at the network level
clientTranscriptConn := &transcriptConn{Conn: clientConn}
serverTranscriptConn := &transcriptConn{Conn: serverConn}
// connection at the ShadowSocks level
clientSSConn := NewConn(clientTranscriptConn, mustNewCipher(method))
serverSSConn := NewConn(serverTranscriptConn, mustNewCipher(method))

clientToServerData := []byte("clientToServerData")
serverToClientData := []byte("serverToClientData")

go func() {
defer serverSSConn.Close()
buf := make([]byte, len(clientToServerData))
// read the client IV
_, err := io.ReadFull(serverSSConn, buf)
if err != nil {
return
}
// send the server IV
_, err = serverSSConn.Write(serverToClientData)
if err != nil {
return
}
}()

// send the client IV
_, err = clientSSConn.Write(clientToServerData)
if err != nil {
return
}
// read the server IV
buf := make([]byte, len(serverToClientData))
_, err = io.ReadFull(clientSSConn, buf)
if err != nil {
return
}

// pull the IVs out of the network transcripts
clientIV = serverTranscriptConn.ReadTranscript[:clientSSConn.Cipher.info.ivLen]
serverIV = clientTranscriptConn.ReadTranscript[:serverSSConn.Cipher.info.ivLen]

return
}

func TestIndependentIVs(t *testing.T) {
for method := range cipherMethod {
clientIV, serverIV, err := connIVs(method)
if err != nil {
t.Errorf("%s connection error: %s", method, err)
continue
}
if bytes.Equal(clientIV, serverIV) {
t.Errorf("%s equal client and server IVs", method)
continue
}
}
}
12 changes: 3 additions & 9 deletions shadowsocks/encrypt.go
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,6 @@ type Cipher struct {
dec cipher.Stream
key []byte
info *cipherInfo
iv []byte
}

// NewCipher creates a cipher that can be used in Dial() etc.
Expand All @@ -215,14 +214,9 @@ func NewCipher(method, password string) (c *Cipher, err error) {

// Initializes the block cipher with CFB mode, returns IV.
func (c *Cipher) initEncrypt() (iv []byte, err error) {
if c.iv == nil {
iv = make([]byte, c.info.ivLen)
if _, err := io.ReadFull(rand.Reader, iv); err != nil {
return nil, err
}
c.iv = iv
} else {
iv = c.iv
iv = make([]byte, c.info.ivLen)
if _, err := io.ReadFull(rand.Reader, iv); err != nil {
return nil, err
}
c.enc, err = c.info.newStream(c.key, iv, Encrypt)
return
Expand Down

0 comments on commit 6a03846

Please sign in to comment.