diff options
| -rw-r--r-- | challenge/c34.go | 269 | 
1 files changed, 252 insertions, 17 deletions
| diff --git a/challenge/c34.go b/challenge/c34.go index 5a0f109..86a40b8 100644 --- a/challenge/c34.go +++ b/challenge/c34.go @@ -14,11 +14,15 @@ import (  )  func C34(args []string) { -	if len(args) != 2 { -		fmt.Println("Usage: cryptopals -c 34 ENTITY PORT") +	if len(args) < 2 { +		fmt.Println("Usage: cryptopals -c 34 ENTITY PORT [S-PORT]")  		return  	}  	entity := args[0] +	if entity == "attacker" && len(args) != 3 { +		fmt.Println("Usage: cryptopals -c 34 attacker PORT S-PORT") +		return +	}  	port, err := lib.StrToNum(args[1])  	if err != nil {  		fmt.Println("Port invalid") @@ -28,6 +32,18 @@ func C34(args []string) {  		fmt.Println("Error: port number must be >= 12000")  		return  	} +	sport := 0 +	if entity == "attacker" { +		sport, err = lib.StrToNum(args[2]) +		if err != nil { +			fmt.Println("S-Port invalid") +			return +		} +		if sport < 12000 { +			fmt.Println("Error: port number must be >= 12000") +			return +		} +	}  	// Cipher functions.  	// @@ -47,7 +63,12 @@ func C34(args []string) {  	// Encipher using AES-CBC.  	encipher := func(skey *big.Int, msg string) (string, error) {  		// Make key out of DH sesssion key. -		k := skey.Bytes()[0:16] +		skeyb := skey.Bytes() +		if len(skeyb) < 16 { +			// Pad it to 16 bytes. +			skeyb = append(skeyb, make([]byte, 16-len(skeyb))...) +		} +		k := skeyb[0:16]  		// Make initialization vector.  		iv, err := lib.RandomBytes(16) @@ -68,7 +89,12 @@ func C34(args []string) {  	// Decipher using AES-CBC.  	decipher := func(skey *big.Int, packet string) (string, error) {  		// Make key out of DH sesssion key. -		k := skey.Bytes()[0:16] +		skeyb := skey.Bytes() +		if len(skeyb) < 16 { +			// Pad it to 16 bytes. +			skeyb = append(skeyb, make([]byte, 16-len(skeyb))...) +		} +		k := skeyb[0:16]  		// Decode packet  		cipher, iv := cipherPacketDecode(packet) @@ -118,11 +144,14 @@ func C34(args []string) {  	}  	// Handle connection from a client.  	serverHandleConn := func(conn net.Conn) { +		defer conn.Close() +  		// Do DH handshake.  		skey, err := serverDHHandshake(conn)  		if err != nil {  			fmt.Printf("DH Handshake failed [%v]: %v\n",  				conn.RemoteAddr(), err) +			return  		}  		fmt.Printf("Made secure connection with %v\n", conn.RemoteAddr()) @@ -146,6 +175,9 @@ func C34(args []string) {  			}  			fmt.Printf("Received from [%v]: '%v'\n", conn.RemoteAddr(), msg) +			// Make msg to client. +			msg = fmt.Sprintf("-> %s", msg) +  			// Encrypt and echo back message.  			cpacket, err := encipher(skey, msg)  			if err != nil { @@ -230,9 +262,10 @@ func C34(args []string) {  		// Make a secure connection to server.  		conn, skey, err := clientSecureConnToServer()  		if err != nil { -			fmt.Printf("Unable to establish secure connection: %v", err) +			fmt.Printf("Unable to establish secure connection: %v\n", err)  			return  		} +		defer conn.Close()  		fmt.Printf("Made secure connection with %v\n", conn.RemoteAddr())  		// Enter write loop. @@ -273,12 +306,174 @@ func C34(args []string) {  				return  			}  			// Barf server's response. -			fmt.Printf("Server: %s\n", smsg) +			fmt.Printf("%s\n", smsg) +		} +	} +	// Attacker handling. +	// +	// Slurp DH params from client. +	attackerSlurpDHParams := func(conn net.Conn) ([]string, error) { +		// Read DH packet from client. +		packet, err := bufio.NewReader(conn).ReadString('\n') +		if err != nil { +			return []string{}, err +		} +		// Remove newline character from packet. +		packet = packet[:len(packet)-1] + +		// Try to read DH paramters from packet. +		params := lib.StrSplitAt('+', packet) +		if len(params) != 3 { +			return []string{}, lib.CPError{"DH paramters invalid"} +		} + +		// Try make a DH from params. +		_, ok := lib.NewDH(params[0], params[1]) +		if !ok { +			return []string{}, lib.CPError{"DH initialization failed"} +		} +		return params, nil +	} +	// Forward initial DH request to server. Initial "parameter" +	// injection happens here (p+g+p). +	attackerConnectToServer := func(p, g string) (net.Conn, error) { +		// Try to connect to server. +		addr := fmt.Sprintf(":%d", sport) +		conn, err := net.Dial("tcp", addr) +		if err != nil { +			return conn, err +		} + +		// Make DH packet: p+g+p +		pub, ok := new(big.Int).SetString(lib.StripSpaceChars(p), 16) +		if !ok { +			return conn, lib.CPError{"Unable to parse p"} +		} +		packet := fmt.Sprintf("%v+%v+%v", p, g, pub) + +		// Sent DH packet to server. +		fmt.Fprintf(conn, "%s\n", packet) + +		// Wait and try to get server's DH public key. +		_, err = bufio.NewReader(conn).ReadString('\n') +		if err != nil { +			return conn, err +		} + +		// Return server connection. +		return conn, nil +	} +	// Handle connection from a client. +	attackerHandleConn := func(conn net.Conn) { +		defer conn.Close() + +		// Read DH params from client. +		dhParams, err := attackerSlurpDHParams(conn) +		if err != nil { +			fmt.Printf("Error: %v\n", err) +			return +		} + +		// Forward request to server with p+g+p. +		// connServer: connection to server. +		connServer, err := attackerConnectToServer( +			dhParams[0], +			dhParams[1], +		) +		if err != nil { +			fmt.Printf("Error: %v\n", err) +			return +		} +		defer connServer.Close() + +		// Respond to client with p as the public key. +		pub, ok := new(big.Int).SetString(lib.StripSpaceChars(dhParams[0]), 16) +		if !ok { +			fmt.Printf("Error: Unable to parse p\n") +			return +		} +		fmt.Fprintf(conn, "%v\n", pub) + +		// Enter loop. +		skey := new(big.Int).SetInt64(0) // Session key is zero. +		for { +			// Read from client. +			packet, err := bufio.NewReader(conn).ReadString('\n') +			if err != nil { +				fmt.Printf("Closed connection to [%v]\n", +					conn.RemoteAddr()) +				return +			} +			// Remove newline character. +			packet = packet[:len(packet)-1] + +			// Decipher packet. +			msg, err := decipher(skey, packet) +			if err != nil { +				fmt.Printf("Message decryption failed for [%v]: %v\n", +					conn.RemoteAddr(), err) +				return +			} +			fmt.Printf("Received from client [%v]: '%v'\n", +				conn.RemoteAddr(), msg) + +			// Encrypt and forward message to server. +			spacket, err := encipher(skey, msg) +			if err != nil { +				fmt.Printf("Message encryption failed for [%v]: %v\n", +					connServer.RemoteAddr(), err) +				return +			} +			// Send message to server. +			fmt.Fprintf(connServer, "%s\n", spacket) + +			// Read encrypted message from server. +			spacket, err = bufio.NewReader(connServer).ReadString('\n') +			if err != nil { +				fmt.Printf("Closed connection to [%v]\n", +					connServer.RemoteAddr()) +				return +			} +			// Remove newline character. +			spacket = spacket[:len(spacket)-1] + +			// Decipher packet. +			msg, err = decipher(skey, spacket) +			if err != nil { +				fmt.Printf("Message decryption failed for [%v]: %v\n", +					connServer.RemoteAddr(), err) +				return +			} +			fmt.Printf("Received from server [%v]: '%v'\n", +				connServer.RemoteAddr(), msg) + +			// Encrypt and echo back message. +			cpacket, err := encipher(skey, msg) +			if err != nil { +				fmt.Printf("Message encryption failed for [%v]: %v\n", +					conn.RemoteAddr(), err) +				return +			} +			// Send message to client. +			fmt.Fprintf(conn, "%s\n", cpacket)  		}  	} -	// Attacker +	// Start (mitm) attacker server.  	attackerSpawn := func() { -		// Stub for now. +		p := fmt.Sprintf(":%d", port) +		ln, err := net.Listen("tcp", p) +		if err != nil { +			fmt.Printf("Attacker listen error: %v\n", err) +			return +		} +		for { +			fmt.Println("Waiting for connection...") +			conn, err := ln.Accept() +			if err != nil { +				fmt.Printf("Attacker accept error: %v", err) +			} +			go attackerHandleConn(conn) +		}  	}  	// Take action based on entity. @@ -296,20 +491,60 @@ func C34(args []string) {  // Output:  // -// Part I: +// https://ricketyspace.net/cryptopals/c34.webm +// +//  Part I:  //  // $ ./cryptopals -c 34 server 12000  // Waiting for connection...  // Waiting for connection... -// Made secure connection with 127.0.0.1:1698 -// Received from [127.0.0.1:1698]: 'ice ice baby' -// Received from [127.0.0.1:1698]: 'vip' -// Closed connection to [127.0.0.1:1698] +// Made secure connection with 127.0.0.1:6546 +// Received from [127.0.0.1:6546]: 'Books are such a drudgery.' +// Closed connection to [127.0.0.1:6546]  //  // $ ./cryptopals -c 34 client 12000  // Made secure connection with 127.0.0.1:12000 -// > ice ice baby -// Server: ice ice baby -// > vip -// Server: vip +// > Books are such a drudgery. +// -> Books are such a drudgery. +// > ^C +// +// Part II: +// +// $ ./cryptopals -c 34 server 12000 +// Waiting for connection... +// Made secure connection with 127.0.0.1:46128 +// Received from [127.0.0.1:46128]: 'When I have fears that I may cease to be' +// Received from [127.0.0.1:46128]: 'Before my pen has glean'd my teeming brain,' +// Received from [127.0.0.1:46128]: 'Before high piled books, in charactry,' +// Received from [127.0.0.1:46128]: 'Hold like rich garners the full ripen'd grain;' +// Received from [127.0.0.1:46128]: '...' +// Closed connection to [127.0.0.1:46128] +// +// $ ./cryptopals -c 34 attacker 12001 12000 +// Waiting for connection... +// Waiting for connection... +// Received from client [127.0.0.1:9186]: 'When I have fears that I may cease to be' +// Received from server [127.0.0.1:12000]: '-> When I have fears that I may cease to be' +// Received from client [127.0.0.1:9186]: 'Before my pen has glean'd my teeming brain,' +// Received from server [127.0.0.1:12000]: '-> Before my pen has glean'd my teeming brain,' +// Received from client [127.0.0.1:9186]: 'Before high piled books, in charactry,' +// Received from server [127.0.0.1:12000]: '-> Before high piled books, in charactry,' +// Received from client [127.0.0.1:9186]: 'Hold like rich garners the full ripen'd grain;' +// Received from server [127.0.0.1:12000]: '-> Hold like rich garners the full ripen'd grain;' +// Received from client [127.0.0.1:9186]: '...' +// Received from server [127.0.0.1:12000]: '-> ...' +// Closed connection to [127.0.0.1:9186] +// +// $ ./cryptopals -c 34 client 12001 +// Made secure connection with 127.0.0.1:12001 +// > When I have fears that I may cease to be +// -> When I have fears that I may cease to be +// > Before my pen has glean'd my teeming brain, +// -> Before my pen has glean'd my teeming brain, +// > Before high piled books, in charactry, +// -> Before high piled books, in charactry, +// > Hold like rich garners the full ripen'd grain; +// -> Hold like rich garners the full ripen'd grain; +// > ... +// -> ...  // > ^C | 
