-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathhashcracker.go
135 lines (118 loc) · 3.77 KB
/
hashcracker.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
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
package main
import (
"fmt"
"math"
"bytes"
"crypto/md5"
"crypto/sha1"
"crypto/sha256"
"crypto/sha512"
"encoding/hex"
)
type HASHCracker struct {
hash []uint8
chars [] uint8
minLen uint8
maxLen uint8
solution chan string
stopchan chan struct{}
endchan chan struct{}
hashFunc func([]byte) []byte
}
func NewHASHCracker(algorithm string, hashString string, chars []uint8, minLen uint8, maxLen uint8) *HASHCracker {
// decode hash
hash, err := hex.DecodeString(hashString)
if err != nil {
panic("Hash is not valid!")
}
// getting hash function
var hashFunc func([]byte) []byte
switch algorithm {
case "sha1":
hashFunc = func(msg []byte) []byte {
res := sha1.Sum(msg)
return res[:]
}
case "sha256":
hashFunc = func(msg []byte) []byte {
res := sha256.Sum256(msg)
return res[:]
}
case "sha512":
hashFunc = func(msg []byte) []byte {
res := sha512.Sum512(msg)
return res[:]
}
case "md5":
hashFunc = func(msg []byte) []byte {
res := md5.Sum(msg)
return res[:]
}
default:
panic("Wrong hashing algorithm name was passed!")
}
return &HASHCracker{
hash, chars, minLen, maxLen,
make(chan string), make(chan struct{}), make(chan struct{}),
hashFunc}
}
func (s *HASHCracker) checkIsSuit(bNum *ByteNumber) bool {
// translate premutation to current charset
msg := bNum.Translate(s.chars)
hashSum := []uint8(s.hashFunc(msg))
return bytes.Equal(hashSum, s.hash)
}
func (s *HASHCracker) bruteForce(bNum *ByteNumber, iterations uint64) {
for iterations > 0 {
select {
default:
if s.checkIsSuit(bNum) {
s.solution <- string(bNum.Translate(s.chars))
return
}
bNum.Inc()
iterations--
case <-s.stopchan:
return
}
}
s.endchan <- struct{}{}
}
func (s *HASHCracker) Crack(goroutines uint32) string {
fmt.Printf("Start cracking hash %x\n", s.hash)
for msgLen := s.minLen; msgLen < s.maxLen + 1; msgLen++ {
// number of all possible variants
var variants uint64 = uint64(math.Pow(float64(len(s.chars)), float64(msgLen)))
var jobs uint32 = goroutines
if variants <= uint64(goroutines) {
jobs = 1
}
// number of hashes to check in one goroutine
var itersInGorutine uint64 = variants / uint64(jobs)
fmt.Println("Check mesages with length:", msgLen, "| Possible variants:", variants)
// start goroutines
for i := uint32(0); i < jobs - 1; i++ {
variants -= itersInGorutine
// make object that represents premutation on (i * premutation) step
bNum := NewByteNumber(uint64(i) * itersInGorutine, uint8(len(s.chars)), msgLen)
// brute force all premutations from (i * itersInGorutine) to (i * itersInGorutine + itersInGorutine)
go s.bruteForce(bNum, itersInGorutine)
}
bNum := NewByteNumber(uint64(jobs - 1) * itersInGorutine, uint8(len(s.chars)), msgLen)
go s.bruteForce(bNum, variants - 1)
// wait for all goroutines to finish work or get solution
var group uint32 = jobs
for group > 0 {
select {
case <-s.endchan:
group--
continue
case solution := <-s.solution:
// if the solution came then tell other goroutines to stop
close(s.stopchan)
return solution
}
}
}
return ""
}