-
Notifications
You must be signed in to change notification settings - Fork 0
/
main.go
118 lines (104 loc) · 2.81 KB
/
main.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
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
package main
import (
"crypto/rand"
"flag"
"fmt"
"math/big"
"os"
)
type Settings struct {
MaxLength uint
ShowInfo bool
}
func ParseFlags() Settings {
var settings Settings
flag.UintVar(&settings.MaxLength, "m", 0, "maxlen")
flag.BoolVar(&settings.ShowInfo, "i", false, "show entropy and estimated time to crack")
flag.Parse()
return settings
}
func main() {
settings := ParseFlags()
if settings.MaxLength > 0 && settings.MaxLength < 3 {
fmt.Println("maxlen must be at least 3")
os.Exit(1)
}
wordFn := func() string {
return randomWord(settings.MaxLength)
}
parts := []string{wordFn(), wordFn(), wordFn(), randomAlphaNumericSegment()}
x := randomInt(4)
parts[x], parts[3] = parts[3], parts[x]
passphrase := fmt.Sprintf("%s-%s-%s-%s", parts[0], parts[1], parts[2], parts[3])
fmt.Println(passphrase)
if settings.ShowInfo {
bruteEnt := bruteforceEntropy(passphrase)
wordlistEnt := wordlistEntropy(passphrase, '-', len(words))
fmt.Fprintln(os.Stderr, "Entropy and estimated time to crack using a fast GPU-based attack (20 MH/s, one or more RTX 4090):")
fmt.Fprintf(os.Stderr, "* Brute-force: %5.1f bits (%s)\n", bruteEnt, estimateTimeToCrack(bruteEnt))
fmt.Fprintf(os.Stderr, "* Known wordlist: %5.1f bits (%s)\n", wordlistEnt, estimateTimeToCrack(wordlistEnt))
if settings.MaxLength > 0 {
smallWords := wordlistSubset(settings.MaxLength)
wordlistEntWithSize := wordlistEntropy(passphrase, '-', len(smallWords))
fmt.Fprintf(os.Stderr, "* Known wordlist and parameters (-m=%d): %5.1f bits (%s)\n", settings.MaxLength, wordlistEntWithSize, estimateTimeToCrack(wordlistEntWithSize))
}
}
}
func randomInt(max int) int64 {
n, err := rand.Int(rand.Reader, big.NewInt(int64(max)))
if err != nil {
panic(err)
}
return n.Int64()
}
func randomByte() byte {
var b [1]byte
n, err := rand.Read(b[:])
if err != nil {
panic(err)
}
if n != 1 {
panic("expected to read 1 byte")
}
return b[0]
}
// wordlistSubset returns a subset of the wordlist with words of length
func wordlistSubset(maxLength uint) []string {
var wordlist []string
for _, word := range words {
if uint(len(word)) <= maxLength {
wordlist = append(wordlist, word)
}
}
return wordlist
}
func randomWord(maxLength uint) string {
numWords := len(words)
word := words[randomInt(numWords)]
if maxLength > 0 {
for uint(len(word)) > maxLength {
word = words[randomInt(numWords)]
}
}
return word
}
func randomAlphaNumericSegment() string {
var segment string
var hasChar, hasNum bool
for segment = ""; len(segment) < 3 || !(hasChar && hasNum); {
hasChar = false
hasNum = false
segment = ""
for i := 0; i < 3; i++ {
c := randomByte()
if c >= '0' && c <= '9' {
hasNum = true
segment += string(c)
} else if c >= 'A' && c <= 'Z' {
hasChar = true
segment += string(c)
}
}
}
return segment
}