summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--challenge/c34.go269
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