diff options
Diffstat (limited to 'challenge')
-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 |