Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

v0.2.1 Update #20

Merged
merged 3 commits into from
May 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
- All transformations support multibyte characters.

```
Usage of Password Transformation Tool (ptt) version (0.2.0):
Usage of Password Transformation Tool (ptt) version (0.2.1):

ptt [options] [...]
Accepts standard input and/or additonal arguments.
Expand Down Expand Up @@ -48,6 +48,8 @@ Options:
Show statistics output when possible.
-vvv
Show verbose statistics output when possible.
-w int
Number of words to generate for passphrases if applicable.

The -f, -k, -r, -tf, -tp, and -u flags can be used multiple times and together.

Expand Down Expand Up @@ -78,6 +80,8 @@ Transformation Modes:
Transforms input by swapping tokens from a partial mask file and a input file.
-t overwrite -i [index]
Transforms input into overwrite rules starting at index.
-t passphrase -w [words] -tf [file]
Transforms input by randomly generating passphrases with a given number of words and separators from a file.
-t pop -rm [uldsb]
Transforms input by generating tokens from popping strings at character boundaries.
-t prepend
Expand Down
2 changes: 2 additions & 0 deletions docs/USAGE.md
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,7 @@ The following transformations can be used with the `-t` flag:
- `swap`: Transforms input by swapping tokens with exact matches from a ':' separated file.
- `pop`: Transforms input by generating tokens from popping strings at character boundaries.
- `mask-swap`: Transforms input by swapping tokens from a partial mask file and a input file.
- `passphrase`: Transforms input by randomly generating passphrases with a given number of words and separators from a file.

The modes also have aliases that can be used with the `-t` flag instead of the
keywords above:
Expand All @@ -146,6 +147,7 @@ keywords above:
- `swap`: `s`, `replace`
- `pop`: `po`, `split`, `boundary-split`, `boundary-pop`, `pop-split`, `split-pop`
- `mask-swap`: `ms`, `shuf`, `shuffle`, `token-swap`
- `passphrase`: `pp`, `phrase`

### Examples

Expand Down
16 changes: 16 additions & 0 deletions docs/WORDLISTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ wordlists. There are several ways to generate wordlists using PTT:
This is implemented in the `pop` module.
- `token-swapping`: Generates tokens by swapping characters in a string. This is
implemented in the `mask-swap` module.
- `passphrases`: Generates passphrases by combining words from a wordlist. This
is implemented in the `passphrase` module.

All modes support multibyte characters and can properly convert them. One
transformation can be used at a time.
Expand Down Expand Up @@ -70,3 +72,17 @@ This mode is most similar to token-swapping in that it generates new
candidates by using masks. However, it is unique in that it uses partial
masks to limit the swap positions from prior applications.

### Passphrases
The `passphrase` module generates passphrases by combining words from a wordlist.
The `-w` flag can be used to specify the number of words to use in the passphrase.
The `-tf` flag is optional and can be used to specify a file containing separators
to use between words. The syntax is as follows:
```
ptt -f <input-file> -t passphrase -w <word-count> -tf <separator-file>
```

The passphrases are generated randomly by selecting words and separators from the input.
If no separator file is provided, no separators will be used. The default word count is 0.
The number of passphrases generated is equal to the number of lines in the input file
*including* duplicates. This means that the item count is also used to determine the number
of passphrases generated.
10 changes: 6 additions & 4 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import (
"github.com/jakewnuk/ptt/pkg/utils"
)

var version = "0.2.0"
var version = "0.2.1"
var wg sync.WaitGroup
var mutex = &sync.Mutex{}
var retain models.FileArgumentFlag
Expand Down Expand Up @@ -59,6 +59,7 @@ func main() {
"mask-match -tf [file]": "Transforms input by keeping only strings with matching masks from a mask file.",
"swap -tf [file]": "Transforms input by swapping tokens with exact matches from a ':' separated file.",
"mask-swap -tf [file]": "Transforms input by swapping tokens from a partial mask file and a input file.",
"passphrase -w [words] -tf [file]": "Transforms input by randomly generating passphrases with a given number of words and separators from a file.",
}

// Sort and print transformation modes
Expand All @@ -85,6 +86,7 @@ func main() {
jsonOutput := flag.String("o", "", "Output to JSON file in addition to stdout.")
bypassMap := flag.Bool("b", false, "Bypass map creation and use stdout as primary output.")
debugMode := flag.Int("d", 0, "Enable debug mode with verbosity levels [0-2].")
passPhraseWords := flag.Int("w", 0, "Number of words to generate for passphrases if applicable.")
flag.Var(&retain, "k", "Only keep items in a file.")
flag.Var(&remove, "r", "Only keep items not in a file.")
flag.Var(&readFiles, "f", "Read additional files for input.")
Expand Down Expand Up @@ -135,7 +137,7 @@ func main() {

// Apply transformation if provided
if *transformation != "" && templateFiles == nil {
primaryMap = transform.TransformationController(primaryMap, *transformation, intRange.Start, intRange.End, *verbose, *replacementMask, transformationFilesMap, *bypassMap, *debugMode)
primaryMap = transform.TransformationController(primaryMap, *transformation, intRange.Start, intRange.End, *verbose, *replacementMask, transformationFilesMap, *bypassMap, *debugMode, *passPhraseWords)
} else if templateFiles != nil && *transformation == "" {
fmt.Fprintf(os.Stderr, "[*] Using template files for multiple transformations.\n")

Expand All @@ -148,9 +150,9 @@ func main() {
// Apply transformations from template files
for i, template := range transformationTemplateArray {
if i == 0 {
temporaryMap = transform.TransformationController(primaryMap, template.TransformationMode, template.StartIndex, template.EndIndex, template.Verbose, template.ReplacementMask, transformationFilesMap, template.Bypass, *debugMode)
temporaryMap = transform.TransformationController(primaryMap, template.TransformationMode, template.StartIndex, template.EndIndex, template.Verbose, template.ReplacementMask, transformationFilesMap, template.Bypass, *debugMode, *passPhraseWords)
} else {
temporaryMap = utils.CombineMaps(temporaryMap, transform.TransformationController(primaryMap, template.TransformationMode, template.StartIndex, template.EndIndex, template.Verbose, template.ReplacementMask, transformationFilesMap, template.Bypass, *debugMode))
temporaryMap = utils.CombineMaps(temporaryMap, transform.TransformationController(primaryMap, template.TransformationMode, template.StartIndex, template.EndIndex, template.Verbose, template.ReplacementMask, transformationFilesMap, template.Bypass, *debugMode, *passPhraseWords))
}
}
primaryMap = temporaryMap
Expand Down
104 changes: 103 additions & 1 deletion pkg/transform/transform.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package transform

import (
"fmt"
"math/rand"
"os"

"github.com/jakewnuk/ptt/pkg/format"
Expand Down Expand Up @@ -31,11 +32,12 @@ import (
// use for modes like retain-mask
// bypass (bool): If true, the map is not used for output or filtering
// debug (int): Different debug levels to use for debugging [0-2]
// passphraseWord (int): The number of words to use for passphrase generation
//
// Returns:
//
// (map[string]int): A map of transformed values
func TransformationController(input map[string]int, mode string, startingIndex int, endingIndex int, verbose bool, replacementMask string, transformationFilesMap map[string]int, bypass bool, debug int) (output map[string]int) {
func TransformationController(input map[string]int, mode string, startingIndex int, endingIndex int, verbose bool, replacementMask string, transformationFilesMap map[string]int, bypass bool, debug int, passphraseWord int) (output map[string]int) {

functionDebug := false
if debug > 1 {
Expand Down Expand Up @@ -113,6 +115,12 @@ func TransformationController(input map[string]int, mode string, startingIndex i
os.Exit(1)
}
output = mask.ShuffleMap(input, replacementMask, transformationFilesMap, bypass, functionDebug)
case "passphrase", "phrase", "pp":
if passphraseWord == 0 {
fmt.Fprintf(os.Stderr, "[!] Passphrase operations require use of the -w flag to specify the number of words to use\n")
os.Exit(1)
}
output = MakePassphraseMap(input, transformationFilesMap, bypass, functionDebug, passphraseWord)
default:
output = input
}
Expand Down Expand Up @@ -163,3 +171,97 @@ func ReplaceKeysInMap(originalMap map[string]int, replacements map[string]int, b
}
return newMap
}

// MakePassphraseMap takes a map of keys and creates a new map with new
// passphrases for each key. The transformation file is used to insert
// separators between the words. If the replacement mask is set to blank, then
// the words are concatenated together without any separators. Passphrases are
// generated by selecting a random word from the transformation file for each key.
//
// Args:
//
// input (map[string]int): The original map to replace keys in
// transformationFilesMap (map[string]int): A map of transformation files to
// use for constructing the passphrases
// bypass (bool): If true, the map is not used for output or filtering
// debug (bool): If true, print additional debug information to stderr
// passphraseWord (int): The number of words to use for passphrase generation
//
// Returns:
//
// (map[string]int): A new map with the keys replaced
func MakePassphraseMap(input map[string]int, transformationFilesMap map[string]int, bypass bool, debug bool, passphraseWord int) map[string]int {
newMap := make(map[string]int)

for key, value := range input {

for i := 0; i < value; i++ {
newKeyPhrase := GeneratePassphrase(input, transformationFilesMap, passphraseWord)
if debug {
fmt.Fprintf(os.Stderr, "Key: %s\n", key)
fmt.Fprintf(os.Stderr, "New Phrase: %s\n", newKeyPhrase)
}

if !bypass {
newMap[newKeyPhrase] = value
} else {
fmt.Println(newKeyPhrase)
}
}
}
return newMap
}

// GeneratePassphrase takes a key and a map of transformation files and
// generates a passphrase based on the number of words specified. The words
// are selected from the transformation files and concatenated together with
// a separator. If the replacement mask is set to blank, then the words are
// concatenated together without any separators.
//
// Args:
//
// passWords (map[string]int): Content of the passphrase for use as words in
// the passphrase
// transformationFilesMap (map[string]int): Content of the transformation
// files for use as separators between words
// passphraseWord (int): The number of words to use for passphrase generation
//
// Returns:
//
// (string): The generated passphrase
func GeneratePassphrase(passWords map[string]int, transformationFilesMap map[string]int, passphraseWord int) string {
words := make([]string, passphraseWord)

seps := make([]string, 0, len(transformationFilesMap))
for k := range transformationFilesMap {
seps = append(seps, k)
}

if len(seps) == 0 {
seps = append(seps, "")
}

keys := make([]string, 0, len(passWords))
for k := range passWords {
keys = append(keys, k)
}

for i := 0; i < passphraseWord; i++ {
sep := seps[rand.Intn(len(seps))]
key := keys[rand.Intn(len(keys))]

if i+1 >= passphraseWord {
words[i] = fmt.Sprintf("%s%s", key, "")
} else {
words[i] = fmt.Sprintf("%s%s", key, sep)
}

}

var newKeyPhrase string
for _, word := range words {
newKeyPhrase += word
}

return newKeyPhrase
}
3 changes: 2 additions & 1 deletion pkg/transform/transform_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@ import (
// Functions without Unit Tests
// ----------------------------------------------------------------------------
// - TransformationController (TransformationController)
// -
// - MakePassphraseMap (Generation Functions)
// - GeneratePassphrase (Generation Functions)

// Unit Test for ReplaceKeysInMap
func TestReplaceKeysInMap(t *testing.T) {
Expand Down