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
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
|
// Copyright © 2021 siddharth ravikumar <s@ricketyspace.net>
// SPDX-License-Identifier: ISC
package challenge
import (
"fmt"
"ricketyspace.net/cryptopals/lib"
)
func C13() {
type Profile map[string]string
key, err := lib.RandomBytes(16)
if err != nil {
fmt.Printf("key generation error: %v\n", err)
}
counter := int64(10000)
profiles := make(map[string]Profile, 0)
genUid := func() int64 {
uid := counter
counter += 1
return uid
}
parse := func(encoded string) map[string]string {
m := make(map[string]string, 0)
kvs := lib.StrSplitAt('&', encoded)
for i := 0; i < len(kvs); i++ {
kv := lib.StrSplitAt('=', kvs[i])
m[lib.StripSpaceChars(kv[0])] = kv[1]
}
return m
}
encode := func(p Profile) string {
ep := "email=" + p["email"] // Encoded profile.
ep += "&uid=" + p["uid"]
ep += "&role=" + p["role"]
return ep
}
decode := func(encoded string) Profile {
return parse(encoded)
}
encrypt := func(encoded string) []byte {
return lib.AESEncryptECB(lib.StrToBytes(encoded), key)
}
decrypt := func(cipher []byte) string {
return lib.BytesToStr(lib.AESDecryptECB(cipher, key))
}
sanitize := func(email string) string {
if len(email) < 1 {
return ""
}
se := "" // sanitized email
// Strip meta characters
for i := 0; i < len(email); i++ {
if email[i] == '&' || email[i] == '=' {
continue
}
se += string(email[i])
}
return se
}
profileFor := func(email string) string {
e := sanitize(email)
if len(e) == 0 {
panic("email invalid")
}
if p, ok := profiles[e]; ok {
// Profile already exists.
return encode(p)
}
// Create profile.
p := make(Profile, 0)
p["email"] = e
p["uid"] = lib.NumToStr(genUid())
p["role"] = "user"
profiles[e] = p
return encode(p)
}
adminBlock := lib.BytesToStr(lib.Pkcs7Padding(lib.StrToBytes("admin"), 16))
ep := profileFor("foo@abacus" + adminBlock)
encryptedEP := encrypt(ep)
adminBlockCipher := encryptedEP[16:32] // Second block in the cipher
ep = profileFor("foo@abacus")
encryptedEP = encrypt(ep)
for i := 0; i < 16; i++ { // Replace last block with the admin cipher block.
encryptedEP[32+i] = adminBlockCipher[i]
}
adminEP := decrypt(encryptedEP)
adminProfile := decode(adminEP)
fmt.Printf("Admin Encoded Profile: %v\n", adminEP)
fmt.Printf("Admin Profile: %v\n", adminProfile)
}
// Output:
// Admin Encoded Profile: email=foo@abacus&uid=10001&role=admin
// Admin Profile: map[email:foo@abacus role:admin uid:10001]
|