Skip to content

Commit 6d715f0

Browse files
v0.1.5-2024-11-30; fix #6
1 parent f3db64f commit 6d715f0

File tree

9 files changed

+113
-169
lines changed

9 files changed

+113
-169
lines changed

README.md

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,19 +21,21 @@ _**This toolset is proudly the first publicly released Phantom Vault Extractor a
2121
```
2222
### Decryptor usage example:
2323
```
24-
./phantom_decryptor.bin -h phantom.txt -w wordlist.txt
2524
-----------------------------------------------
2625
| Cyclone's Phantom Vault Decryptor |
2726
| https://github.com/cyclone-github/phantom_pwn |
2827
-----------------------------------------------
2928
30-
Vault file: phantom.txt
29+
Vault file: hash.txt
3130
Valid Vaults: 1
3231
CPU Threads: 16
3332
Wordlist: wordlist.txt
34-
Working...
33+
2024/11/30 14:11:35 Working...
34+
{"encryptedKey":{"digest":"sha256","encrypted":"5pLvA3bCjNGYBbSjjFY3mdPknwFfp3cz9dCBv6izyyrqEhYCBkKwo3zZUzBP44KtY3","iterations":10000,"kdf":"pbkdf2","nonce":"NZT6kw5Cd5VeZu5yJGJcFcP24tnmg4xsR","salt":"A43vTZnm9c5CiQ6FLTdV9v"},"version":1}:password
35+
2024/11/30 14:11:39 Decrypted: 1/1 6181.36 h/s 00h:00m:03s
36+
37+
2024/11/30 14:11:39 Finished
3538
36-
Decrypted: 0/1 6360.82 h/s 00h:01m:00s
3739
```
3840
### Decryptor supported options:
3941
```

phantom_decryptor/go.mod

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ go 1.22.4
44

55
require (
66
github.com/btcsuite/btcutil v1.0.2
7-
golang.org/x/crypto v0.26.0
7+
golang.org/x/crypto v0.29.0
88
)
99

10-
require golang.org/x/sys v0.23.0 // indirect
10+
require golang.org/x/sys v0.27.0 // indirect

phantom_decryptor/go.sum

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,16 +22,16 @@ github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1Cpa
2222
golang.org/x/crypto v0.0.0-20170930174604-9419663f5a44/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
2323
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
2424
golang.org/x/crypto v0.0.0-20200115085410-6d4e4cb37c7d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
25-
golang.org/x/crypto v0.26.0 h1:RrRspgV4mU+YwB4FYnuBoKsUapNIL5cohGAmSH3azsw=
26-
golang.org/x/crypto v0.26.0/go.mod h1:GY7jblb9wI+FOo5y8/S2oY4zWP07AkOJ4+jxCqdqn54=
25+
golang.org/x/crypto v0.29.0 h1:L5SG1JTTXupVV3n6sUqMTeWbjAyfPwoda2DLX8J8FrQ=
26+
golang.org/x/crypto v0.29.0/go.mod h1:+F4F4N5hv6v38hfeYwTdx20oUvLLc+QfrE9Ax9HtgRg=
2727
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
2828
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
2929
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
3030
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
3131
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
3232
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
33-
golang.org/x/sys v0.23.0 h1:YfKFowiIMvtgl1UERQoTPPToxltDeZfbj4H7dVUCwmM=
34-
golang.org/x/sys v0.23.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
33+
golang.org/x/sys v0.27.0 h1:wBqf8DvsY9Y/2P8gAfPDEYNuS30J4lPHJxXSb/nJZ+s=
34+
golang.org/x/sys v0.27.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
3535
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
3636
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
3737
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=

phantom_decryptor/main.go

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,11 @@ v0.1.3-2024-07-06-1100;
3737
fixed https://github.com/cyclone-github/phantom_pwn/issues/3
3838
v0.1.4-2024-08-31-1630;
3939
finished implementing flag -o {output file}
40+
v0.1.5-2024-11-30-1415;
41+
fix https://github.com/cyclone-github/phantom_pwn/issues/6
42+
swapped crackedCount and lineProcessed channels for atomic int32 for better performance
43+
multiple performance optimizations in process.go
44+
print vault:password when vault is cracked
4045
*/
4146

4247
// main func
@@ -80,11 +85,15 @@ func main() {
8085
// set CPU threads
8186
numThreads := setNumThreads(*threadFlag)
8287

83-
// channels / variables
84-
crackedCountCh := make(chan int, 10) // buffer of 10 to reduce blocking
85-
linesProcessedCh := make(chan int, 1000) // buffer of 1000 to reduce blocking
88+
// variables
89+
var (
90+
crackedCount int32
91+
linesProcessed int32
92+
wg sync.WaitGroup
93+
)
94+
95+
// channels
8696
stopChan := make(chan struct{})
87-
var wg sync.WaitGroup
8897

8998
// goroutine to watch for ctrl+c
9099
handleGracefulShutdown(stopChan)
@@ -102,14 +111,16 @@ func main() {
102111

103112
// monitor status of workers
104113
wg.Add(1)
105-
go monitorPrintStats(crackedCountCh, linesProcessedCh, stopChan, startTime, validVaultCount, &wg, *statsIntervalFlag)
114+
go monitorPrintStats(&crackedCount, &linesProcessed, stopChan, startTime, validVaultCount, &wg, *statsIntervalFlag)
106115

107116
// start the processing logic
108-
startProc(*wordlistFileFlag, *outputFile, numThreads, stopChan, vaults, crackedCountCh, linesProcessedCh)
117+
startProc(*wordlistFileFlag, *outputFile, numThreads, vaults, &crackedCount, &linesProcessed, stopChan)
109118

110119
// close stop channel to signal all workers to stop
111-
time.Sleep(10 * time.Millisecond)
112120
closeStopChannel(stopChan)
121+
122+
// wait for monitorPrintStats to finish
123+
wg.Wait()
113124
}
114125

115126
// end code

phantom_decryptor/print_welcome.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import (
88

99
// version func
1010
func versionFunc() {
11-
fmt.Fprintln(os.Stderr, "Cyclone's Phantom Vault Decryptor v0.1.4-2024-08-31-1630\nhttps://github.com/cyclone-github/phantom_pwn\n")
11+
fmt.Fprintln(os.Stderr, "Cyclone's Phantom Vault Decryptor v0.1.5-2024-11-30-1415\nhttps://github.com/cyclone-github/phantom_pwn\n")
1212
}
1313

1414
// help func

phantom_decryptor/process.go

Lines changed: 62 additions & 138 deletions
Original file line numberDiff line numberDiff line change
@@ -2,185 +2,109 @@ package main
22

33
import (
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("\nPassword: '%s'\n", password))
95+
writerMu.Lock()
96+
atomic.AddInt32(crackedCount, 1)
97+
writer.WriteString(output)
17198
writer.Flush()
172-
} else {
173-
fmt.Printf("\nPassword: '%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

Comments
 (0)