@@ -2,185 +2,109 @@ package main
22
33import (
44 "bufio"
5- "bytes"
65 "fmt"
7- "io"
86 "log"
97 "os"
108 "sync"
119 "sync/atomic"
12- "time"
1310)
1411
1512// process logic
16- func startProc (wordlistFileFlag string , outputPath string , numGoroutines int , stopChan chan struct {}, vaults []Vault , crackedCountCh chan int , linesProcessedCh chan int ) {
17- const readBufferSize = 1024 * 1024 // read buffer
18- const writeBufferSize = 128 * 1024 // write buffer
19-
20- var linesHashed int64 = 0
21- var procWg sync.WaitGroup
22- var readWg sync.WaitGroup
23- var writeWg sync.WaitGroup
24- var hexDecodeErrors int64 = 0 // hex error counter
25-
26- readChunks := make (chan []byte , 500 ) // channel for reading chunks of data
27- writeData := make (chan []byte , 10 ) // channel for writing processed data
28-
13+ func startProc (wordlistFileFlag string , outputPath string , numGoroutines int , vaults []Vault , crackedCount * int32 , linesProcessed * int32 , stopChan chan struct {}) {
2914 var file * os.File
3015 var err error
16+
3117 if wordlistFileFlag == "" {
32- file = os .Stdin // default to stdin if no input flag is provided
18+ file = os .Stdin
3319 } else {
3420 file , err = os .Open (wordlistFileFlag )
3521 if err != nil {
36- log .Printf ("Error opening file: %v\n " , err )
37- return
22+ log .Fatalf ("Error opening file: %v\n " , err )
3823 }
3924 defer file .Close ()
4025 }
4126
42- startTime := time .Now ()
43-
44- readWg .Add (1 )
45- go func () {
46- defer readWg .Done ()
47- var remainder []byte
48- reader := bufio .NewReaderSize (file , readBufferSize )
49- for {
50- chunk := make ([]byte , readBufferSize )
51- n , err := reader .Read (chunk )
52- if err == io .EOF {
53- break
54- }
55- if err != nil {
56- fmt .Println (os .Stderr , "Error reading chunk:" , err )
57- return
58- }
27+ var outputFile * os.File
28+ if outputPath != "" {
29+ outputFile , err = os .OpenFile (outputPath , os .O_APPEND | os .O_CREATE | os .O_WRONLY , 0644 )
30+ if err != nil {
31+ log .Fatalf ("Error opening output file: %v" , err )
32+ }
33+ defer outputFile .Close ()
34+ }
5935
60- chunk = chunk [:n ]
61- chunk = append (remainder , chunk ... )
36+ var writer * bufio.Writer
37+ if outputPath != "" {
38+ writer = bufio .NewWriter (outputFile )
39+ } else {
40+ writer = bufio .NewWriter (os .Stdout )
41+ }
42+ defer writer .Flush ()
6243
63- lastNewline := bytes .LastIndexByte (chunk , '\n' )
64- if lastNewline == - 1 {
65- remainder = chunk
66- } else {
67- readChunks <- chunk [:lastNewline + 1 ]
68- remainder = chunk [lastNewline + 1 :]
69- }
70- }
71- if len (remainder ) > 0 {
72- readChunks <- remainder
73- }
74- close (readChunks )
75- }()
44+ var (
45+ writerMu sync.Mutex
46+ wg sync.WaitGroup
47+ )
7648
49+ // start worker goroutines
50+ linesCh := make (chan []byte , 1000 )
7751 for i := 0 ; i < numGoroutines ; i ++ {
78- procWg .Add (1 )
52+ wg .Add (1 )
7953 go func () {
80- defer procWg .Done ()
81- for chunk := range readChunks {
82- localBuffer := bytes .NewBuffer (nil )
83- writer := bufio .NewWriterSize (localBuffer , writeBufferSize )
84- processChunk (chunk , & linesHashed , & hexDecodeErrors , writer , stopChan , vaults , crackedCountCh , linesProcessedCh )
85- writer .Flush ()
86- if localBuffer .Len () > 0 {
87- writeData <- localBuffer .Bytes ()
88- }
54+ defer wg .Done ()
55+ for password := range linesCh {
56+ processPassword (password , vaults , & writerMu , writer , crackedCount , linesProcessed , stopChan )
8957 }
9058 }()
9159 }
9260
93- writeWg .Add (1 )
94- go func () {
95- defer writeWg .Done ()
96- var writer * bufio.Writer
97- if outputPath != "" {
98- outFile , err := os .OpenFile (outputPath , os .O_APPEND | os .O_CREATE | os .O_WRONLY , 0644 )
99- if err != nil {
100- fmt .Println (os .Stderr , "Error creating output file:" , err )
101- return
102- }
103- defer outFile .Close ()
104- writer = bufio .NewWriterSize (outFile , writeBufferSize )
105- } else {
106- writer = bufio .NewWriterSize (os .Stdout , writeBufferSize )
107- }
108-
109- for data := range writeData {
110- writer .Write (data )
111- }
112- writer .Flush ()
113- }()
114-
115- procWg .Wait ()
116- readWg .Wait ()
117- close (writeData )
118- writeWg .Wait ()
119-
120- elapsedTime := time .Since (startTime )
121- runTime := float64 (elapsedTime .Seconds ())
122- linesPerSecond := float64 (linesHashed ) / elapsedTime .Seconds ()
123- if hexDecodeErrors > 0 {
124- log .Printf ("HEX decode errors: %d\n " , hexDecodeErrors )
61+ // read lines from file and send them to workers
62+ scanner := bufio .NewScanner (file )
63+ for scanner .Scan () {
64+ line := scanner .Bytes ()
65+ password := make ([]byte , len (line ))
66+ copy (password , line )
67+ linesCh <- password
12568 }
126- log .Printf ("Finished processing %d lines in %.3f sec (%.3f lines/sec)\n " , linesHashed , runTime , linesPerSecond )
127- }
69+ close (linesCh )
12870
129- // process wordlist chunks
130- func processChunk (chunk []byte , count * int64 , hexErrorCount * int64 , writer * bufio.Writer , stopChan chan struct {}, vaults []Vault , crackedCountCh chan int , linesProcessedCh chan int ) {
131- lineStart := 0
132- for i := 0 ; i < len (chunk ); i ++ {
133- if chunk [i ] == '\n' {
134- password := chunk [lineStart :i ]
135- decodedBytes , _ , hexErrCount := checkForHexBytes (password )
136- startCracker (stopChan , decodedBytes , vaults , crackedCountCh , linesProcessedCh , writer )
137- atomic .AddInt64 (count , 1 )
138- atomic .AddInt64 (hexErrorCount , int64 (hexErrCount ))
139- lineStart = i + 1 // move start index past the newline
140- }
71+ if err := scanner .Err (); err != nil {
72+ log .Fatalf ("Error reading file: %v\n " , err )
14173 }
14274
143- // handle cases where there is no newline at the end of the chunk
144- if lineStart < len (chunk ) {
145- password := chunk [lineStart :]
146- decodedBytes , _ , hexErrCount := checkForHexBytes (password )
147- startCracker (stopChan , decodedBytes , vaults , crackedCountCh , linesProcessedCh , writer )
148- atomic .AddInt64 (count , 1 )
149- atomic .AddInt64 (hexErrorCount , int64 (hexErrCount ))
150- }
75+ wg .Wait ()
15176
152- writer . Flush ( )
77+ log . Println ( "Finished" )
15378}
15479
155- // hash cracking worker
156- func startCracker (stopChan chan struct {}, password []byte , vaults []Vault , crackedCountCh chan int , linesProcessedCh chan int , writer * bufio.Writer ) {
157- allDecrypted := true
80+ func processPassword (password []byte , vaults []Vault , writerMu * sync.Mutex , writer * bufio.Writer , crackedCount * int32 , linesProcessed * int32 , stopChan chan struct {}) {
81+ atomic .AddInt32 (linesProcessed , 1 )
82+ // check for hex, ignore hexErrCount
83+ decodedPassword , _ , _ := checkForHexBytes (password )
15884
15985 for i := range vaults {
160- if ! vaults [i ].Decrypted { // check only undecrypted vaults
161- decryptedData , err := decryptVault (vaults [i ].EncryptedData , password , vaults [i ].Salt , vaults [i ].Nonce , vaults [i ].Iterations , vaults [i ].Kdf )
162- if err != nil {
163- allDecrypted = false
164- continue // skip to next vault if decryption fails
86+ if atomic .LoadInt32 (& vaults [i ].Decrypted ) == 0 {
87+ decryptedData , err := decryptVault (vaults [i ].EncryptedData , decodedPassword , vaults [i ].Salt , vaults [i ].Nonce , vaults [i ].Iterations , vaults [i ].Kdf )
88+ if err != nil || ! isValid (decryptedData ) {
89+ continue
16590 }
166- if isValid ( decryptedData ) {
167- crackedCountCh <- 1
168- vaults [i ].Decrypted = true
91+
92+ if atomic . CompareAndSwapInt32 ( & vaults [ i ]. Decrypted , 0 , 1 ) {
93+ output := fmt . Sprintf ( "%s:%s \n " , vaults [i ].VaultText , string ( decodedPassword ))
16994 if writer != nil {
170- writer .WriteString (fmt .Sprintf ("\n Password: '%s'\n " , password ))
95+ writerMu .Lock ()
96+ atomic .AddInt32 (crackedCount , 1 )
97+ writer .WriteString (output )
17198 writer .Flush ()
172- } else {
173- fmt .Printf ("\n Password: '%s'\n " , password )
99+ writerMu .Unlock ()
100+ }
101+
102+ // exit if all vaults are cracked
103+ if isAllVaultsCracked (vaults ) {
104+ closeStopChannel (stopChan )
174105 }
175- } else {
176- allDecrypted = false
106+ return
177107 }
178108 }
179109 }
180-
181- linesProcessedCh <- 1
182-
183- if allDecrypted {
184- closeStopChannel (stopChan )
185- }
186110}
0 commit comments