-
Notifications
You must be signed in to change notification settings - Fork 0
/
challenge32.go
91 lines (80 loc) · 1.97 KB
/
challenge32.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
package set4
import (
"crypto/rand"
"fmt"
"net/http"
"net/http/httptest"
"net/url"
"time"
"github.com/alokmenghrajani/go-cryptopals/utils"
)
func Challenge32() {
utils.PrintTitle(4, 32)
// Generate random key
key := make([]byte, 16)
_, err := rand.Read(key)
utils.PanicOnErr(err)
fmt.Printf("expected signature:\n% x\n", utils.HmacSha1(key, []byte("foo"))[0:5])
// Use httptest as it makes some things simpler
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
file := r.URL.Query().Get("file")
if file != "foo" {
w.WriteHeader(404)
return
}
expectedSig := utils.HmacSha1(key, []byte(file))
// truncate expectedSig to speed things up
expectedSig = expectedSig[0:5]
sig := utils.HexToByteSlice(r.URL.Query().Get("signature"))
if !slowCompare(expectedSig, sig, 5*time.Millisecond) {
w.WriteHeader(500)
return
}
w.WriteHeader(200)
}))
defer ts.Close()
// use timing information to bruteforce the signature
client := ts.Client()
u, err := url.Parse(ts.URL)
utils.PanicOnErr(err)
query := u.Query()
query.Add("file", "foo")
sig := make([]byte, 5)
ok := false
outer:
for i := 0; i < len(sig); i++ {
bestTime := 0 * time.Second
bestValue := 0
for b := 0; b < 256; b++ {
sig[i] = byte(b)
query.Set("signature", utils.ByteSliceToHex(sig))
u.RawQuery = query.Encode()
start := time.Now()
// Iterating 4x is much simpler than doing complicated math... A bit of statistical
// analysis would enable us to lower the wait in slowCompare
for j := 0; j < 4; j++ {
res, err := client.Get(u.String())
utils.PanicOnErr(err)
if res.StatusCode == 200 {
fmt.Printf("%02x ", b)
ok = true
break outer
}
}
d := time.Since(start)
if d > bestTime {
bestTime = d
bestValue = b
}
}
sig[i] = byte(bestValue)
fmt.Printf("%02x ", bestValue)
}
fmt.Println()
if ok {
fmt.Println("response code: 200")
} else {
fmt.Println("failed")
}
fmt.Println()
}