Reputation: 13744
As part of a learning-Go exercise, I'm writing a simplistic brute-force password cracker.
To generate all possible 2-character passwords that use the characters A-E in Python, I would use itertools.product():
from itertools import product
for permutation in product('ABCDE', repeat=2):
print permutation
However, I'm struggling to do this in Go.
Other questions seem to be about permutations, which isn't quite what I want. And while the Python docs include a sample implementation of the function, I don't know how to translate yield
into Go.
I suppose I should mention two restrictions:
Upvotes: 7
Views: 3666
Reputation: 999
There is an Iterium package: https://github.com/mowshon/iterium
Here is how to generate all possible passwords using Iterium.Product()
and Iterium.Map()
package main
import (
"fmt"
"github.com/mowshon/iterium"
"strings"
)
func main() {
letters := []string{"A", "B", "C", "D", "E"}
product := iterium.Product(letters, 2)
// Merge a character slice into a string type password
//
// Already has all the letters of the Latin alphabet in upper
// and lower case `iterium.AsciiLetters`
// https://github.com/mowshon/iterium/blob/main/string.go
// You can use it and not have to create a slice from scratch.
//
// e.g. iterium.Product(iterium.AsciiLetters, 2)
passwords := iterium.Map(product, func(slice []string) string {
return strings.Join(slice, "")
})
fmt.Println("Total:", passwords.Count())
for password := range passwords.Chan() {
fmt.Println(password)
}
}
Output:
Total: 25
AA
AB
AC
AD
AE
BA
BB
BC
BD
BE
CA
CB
CC
CD
CE
DA
DB
DC
DD
DE
EA
EB
EC
ED
EE
Upvotes: 0
Reputation: 51
package main
import (
"fmt"
"strings"
"strconv"
// permutation and combination of charactersList
"github.com/ernestosuarez/itertools"
)
func main() {
passwordLength := "1,2,4"
characters := "abcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*()+-./"
passwordLengthList := strings.Split(passwordLength, ",")
charactersList := strings.Split(characters, "")
for _, passLen := range passwordLengthList {
passLenInt, err := strconv.Atoi(passLen)
if err != nil {
panic(err)
}
for v := range itertools.PermutationsStr(charactersList, passLenInt) {
fmt.Println(strings.Join(v, ""))
}
}
}
Upvotes: 1
Reputation: 11
uses select for channels to generate unique passwords
func randombitsGen(l int) (out chan string) {
Capschar := "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
smallchar := "abcdefghijklmnopqrstuvwxyz"
nums := "0123456789"
specials := "!@#$%ˆ&*()?><"
out = make(chan string, l)
defer close(out)
for {
select {
case out <- string(Capschar[rand.Intn(len(strings.Split(Capschar, "")))]):
case out <- string(Capschar[rand.Intn(len(strings.Split(Capschar, "")))]):
case out <- string(Capschar[rand.Intn(len(strings.Split(Capschar, "")))]):
case out <- string(smallchar[rand.Intn(len(strings.Split(smallchar, "")))]):
case out <- string(smallchar[rand.Intn(len(strings.Split(smallchar, "")))]):
case out <- string(smallchar[rand.Intn(len(strings.Split(smallchar, "")))]):
case out <- string(nums[rand.Intn(len(strings.Split(nums, "")))]):
case out <- string(specials[rand.Intn(len(strings.Split(specials, "")))]):
default:
return
}
}
}
Upvotes: -1
Reputation: 166815
For example, satisfying your restrictions,
package main
import "fmt"
func nextPassword(n int, c string) func() string {
r := []rune(c)
p := make([]rune, n)
x := make([]int, len(p))
return func() string {
p := p[:len(x)]
for i, xi := range x {
p[i] = r[xi]
}
for i := len(x) - 1; i >= 0; i-- {
x[i]++
if x[i] < len(r) {
break
}
x[i] = 0
if i <= 0 {
x = x[0:0]
break
}
}
return string(p)
}
}
func main() {
np := nextPassword(2, "ABCDE")
for {
pwd := np()
if len(pwd) == 0 {
break
}
fmt.Println(pwd)
}
}
Output:
AA
AB
AC
AD
AE
BA
BB
BC
BD
BE
CA
CB
CC
CD
CE
DA
DB
DC
DD
DE
EA
EB
EC
ED
EE
Upvotes: 8
Reputation: 22226
What you want is basically the n-ary cartesian product of a set with itself. So for all 3-character passwords you want Prod(set,set,set). This can be constructed iteratively. First construct the n-1 product, then for each product and each element of the initial set, add the element. So for instance all 2 character passwords -> 3 character passwords where the only valid characters are 'a' or 'b'.
"ab" = {a,b}
-> {(a,a),(a,b),(b,a),(b,b)}
-> {(a,a,a),(a,a,b),(a,b,a),(a,b,b),(b,a,a),(b,a,b),(b,b,a),(b,b,b)}
func NAryProduct(input string, n int) []string {
if n <= 0 {
return nil
}
// Copy input into initial product set -- a set of
// one character sets
prod := make([]string, len(input))
for i, char := range input {
prod[i] = string(char)
}
for i := 1; i < n; i++ {
// The bigger product should be the size of the input times the size of
// the n-1 size product
next := make([]string, 0, len(input)*len(prod))
// Add each char to each word and add it to the new set
for _, word := range prod {
for _, char := range input {
next = append(next, word + string(char))
}
}
prod = next
}
return prod
}
Playground version: http://play.golang.org/p/6LhApeJ1bv
It should be noted that there's a lot of room for improvement on this solution. If you want to construct all passwords of length, say, 6-18, calling this method independently for each one will recalculate previously computed sets. I'll leave writing the better version up to you. Given what I've shown you, it shouldn't be too difficult to modify the code to take an arbitrary (n-m)ary product and compute the n-ary product from it. (Hint: think about how you'd do this recursively)
Upvotes: 11