From d9c9edb96c2cd6e784a073894d65a843681006aa Mon Sep 17 00:00:00 2001 From: siddharth Date: Sun, 20 Feb 2022 17:10:59 -0500 Subject: challenge: do challenge 35 - part ii --- challenge/c35.go | 340 ++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 339 insertions(+), 1 deletion(-) (limited to 'challenge') diff --git a/challenge/c35.go b/challenge/c35.go index cb2d166..b266e47 100644 --- a/challenge/c35.go +++ b/challenge/c35.go @@ -15,10 +15,15 @@ import ( func C35(args []string) { if len(args) < 2 { - fmt.Println("Usage: cryptopals -c 35 ENTITY PORT") + fmt.Println("Usage: cryptopals -c 35 ENTITY PORT [S-PORT] [G]") return } entity := args[0] + if entity == "attacker" && len(args) != 4 { + fmt.Println("Usage: cryptopals -c 35 attacker PORT S-PORT G") + fmt.Println("\n G should be '1', 'p' or 'p-1'") + return + } port, err := lib.StrToNum(args[1]) if err != nil { fmt.Println("Port invalid") @@ -28,6 +33,24 @@ func C35(args []string) { fmt.Println("Error: port number must be >= 12000") return } + sport := 0 + gtype := "" + 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 + } + gtype = lib.StripSpaceChars(args[3]) + if gtype != "1" && gtype != "p" && gtype != "p-1" { + fmt.Println("Error: G is invalid") + return + } + } // Cipher functions. // @@ -325,6 +348,257 @@ func C35(args []string) { 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) != 2 { + 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 + } + // Return DH param `g` based on gtype. + attackerGetDHG := func(p string) (string, *big.Int, bool) { + if gtype == "1" { + return "1", new(big.Int).SetInt64(1), true + } + + // Convert string `p` to big.Int. + pi, ok := new(big.Int).SetString(p, 16) + if !ok { + return "", nil, false + } + + if gtype == "p" { + return p, pi, true + } + + if gtype != "p-1" { + return "", nil, false + } + + // gtype is "p-1"; make it. + pi.Sub(pi, new(big.Int).SetInt64(1)) + return fmt.Sprintf("%x", pi), pi, true + } + // Try to make a connection with the server using DH and + // return serve'rs DH public key. + attackerSecureConnToServer := func(p, g string) (net.Conn, *big.Int, error) { + // Try to connect to server. + addr := fmt.Sprintf(":%d", sport) + conn, err := net.Dial("tcp", addr) + if err != nil { + return conn, nil, err + } + + // Initialize DH. + dh, ok := lib.NewDH(p, g) + if !ok { + return conn, nil, lib.CPError{"DH initialization failed"} + } + + // Make DH packet: p+g + packet := fmt.Sprintf("%v+%v", p, g) + + // Sent DH packet to server. + fmt.Fprintf(conn, "%s\n", packet) + + // Wait and try to get ACK from server. + spacket, err := bufio.NewReader(conn).ReadString('\n') + if err != nil { + return conn, nil, err + } + // Remove newline character. + spacket = spacket[:len(spacket)-1] + if spacket != "ACK" { + return conn, nil, lib.CPError{"ACK failed"} + } + + // Send DH public key to server. + fmt.Fprintf(conn, "%v\n", dh.Pub()) + + // Get server's DH public key. + spacket, err = bufio.NewReader(conn).ReadString('\n') + if err != nil { + return conn, nil, err + } + // Remove newline character. + spacket = spacket[:len(spacket)-1] + + // Parse server's DH public key. + sPub, ok := new(big.Int).SetString(lib.StripSpaceChars(spacket), 10) + if !ok { + return conn, nil, lib.CPError{"Server's DH key invalid"} + } + + // Return server connection and server's DH public key. + return conn, dh.SharedSecret(sPub), 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 + } + + // DH params for the server. + p := dhParams[0] + g, gi, ok := attackerGetDHG(p) + if !ok { + fmt.Println("Error: Unable to get DH param 'g'") + return + } + sconn, skey, err := attackerSecureConnToServer(p, g) + if err != nil { + fmt.Printf("Error: %v\n", err) + return + } + defer sconn.Close() + + // Send ACK to client. + fmt.Fprintf(conn, "ACK\n") + + // Wait and get client's DH public key + packet, err := bufio.NewReader(conn).ReadString('\n') + if err != nil { + fmt.Println("Error: Unable to read client's DH public key") + return + } + // Remove newline character. + packet = packet[:len(packet)-1] + + // Parse client's DH public key. + _, ok = new(big.Int).SetString(lib.StripSpaceChars(packet), 10) + if !ok { + fmt.Println("Error: client DH public key invalid") + return + } + + // Send server's session key as public key to client. + fmt.Fprintf(conn, "%v\n", skey) + + // Client session key. + ckey := new(big.Int).Set(skey) + ckeyAlt := new(big.Int) + ckeyConfirmed := true + if gtype == "p-1" { + // ckey can be 1 or p-1. Set ckeyAlt to p-1 if + // ckey is 1; 1 otherwise. + ckeyConfirmed = false + if ckey.Cmp(new(big.Int).SetInt64(1)) == 0 { + ckeyAlt.Set(gi) + } else { + ckeyAlt.Set(new(big.Int).SetInt64(1)) + } + } + + // Enter mitm loop + 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. + if !ckeyConfirmed { + _, err = decipher(ckey, packet) + if err != nil { + ckey = ckeyAlt + ckeyConfirmed = true + } + } + msg, err := decipher(ckey, 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", + sconn.RemoteAddr(), err) + return + } + // Send message to server. + fmt.Fprintf(sconn, "%s\n", spacket) + + // Read encrypted message from server. + spacket, err = bufio.NewReader(sconn).ReadString('\n') + if err != nil { + fmt.Printf("Closed connection to [%v]\n", + sconn.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", + sconn.RemoteAddr(), err) + return + } + fmt.Printf("Received from server [%v]: '%v'\n", + sconn.RemoteAddr(), msg) + + // Encrypt and echo back message. + cpacket, err := encipher(ckey, 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) + } + } + // Start (mitm) attacker server. + attackerSpawn := func() { + 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. switch { @@ -332,6 +606,8 @@ func C35(args []string) { serverSpawn() case entity == "client": clientSpawn() + case entity == "attacker": + attackerSpawn() default: fmt.Println("Error: Uknown entity") } @@ -356,3 +632,65 @@ func C35(args []string) { // -> Kara Swisher's Sway. // > ^C // +// Part II: +// +// https://ricketyspace.net/cryptopals/c35.webm +// +// $ ./cryptopals -c 35 server 12000 +// Waiting for connection... +// Waiting for connection... +// Made secure connection with 127.0.0.1:27477 +// Received from [127.0.0.1:27477]: 'If the red slayer think he slays,' +// Closed connection to [127.0.0.1:27477] +// Waiting for connection... +// Made secure connection with 127.0.0.1:46947 +// Received from [127.0.0.1:46947]: 'Or if the slain think he is slain,' +// Closed connection to [127.0.0.1:46947] +// Waiting for connection... +// Made secure connection with 127.0.0.1:42735 +// Received from [127.0.0.1:42735]: 'They know not well the subtle ways' +// Received from [127.0.0.1:42735]: 'I keep, and pass, and turn again.' +// Closed connection to [127.0.0.1:42735] +// ^C +// +// $ ./cryptopals -c 35 attacker 12001 12000 1 +// Waiting for connection... +// Waiting for connection... +// Received from client [127.0.0.1:12597]: 'If the red slayer think he slays,' +// Received from server [127.0.0.1:12000]: '-> If the red slayer think he slays,' +// Closed connection to [127.0.0.1:12597] +// ^C +// ada$ ./cryptopals -c 35 attacker 12001 12000 p +// Waiting for connection... +// Waiting for connection... +// Received from client [127.0.0.1:47227]: 'Or if the slain think he is slain,' +// Received from server [127.0.0.1:12000]: '-> Or if the slain think he is slain,' +// Closed connection to [127.0.0.1:47227] +// ^C +// ada$ ./cryptopals -c 35 attacker 12001 12000 p-1 +// Waiting for connection... +// Waiting for connection... +// Received from client [127.0.0.1:9193]: 'They know not well the subtle ways' +// Received from server [127.0.0.1:12000]: '-> They know not well the subtle ways' +// Received from client [127.0.0.1:9193]: 'I keep, and pass, and turn again.' +// Received from server [127.0.0.1:12000]: '-> I keep, and pass, and turn again.' +// Closed connection to [127.0.0.1:9193] +// ^C +// +// $ ./cryptopals -c 35 client 12001 +// Made secure connection with 127.0.0.1:12001 +// > If the red slayer think he slays, +// -> If the red slayer think he slays, +// > ^C +// ada$ ./cryptopals -c 35 client 12001 +// Made secure connection with 127.0.0.1:12001 +// > Or if the slain think he is slain, +// -> Or if the slain think he is slain, +// > ^C +// ada$ ./cryptopals -c 35 client 12001 +// Made secure connection with 127.0.0.1:12001 +// > They know not well the subtle ways +// -> They know not well the subtle ways +// > I keep, and pass, and turn again. +// -> I keep, and pass, and turn again. +// > ^C -- cgit v1.2.3