英文:
Generate all possible n-character passwords
问题
作为学习Go的一部分,我正在编写一个简单的暴力密码破解器。
要在Python中生成使用字符A-E的所有可能的两个字符密码,可以使用itertools.product():
package main
import (
"fmt"
)
func main() {
characters := []rune{'A', 'B', 'C', 'D', 'E'}
length := 2
generatePasswords(characters, length)
}
func generatePasswords(characters []rune, length int) {
password := make([]rune, length)
generateHelper(characters, password, 0)
}
func generateHelper(characters []rune, password []rune, index int) {
if index == len(password) {
fmt.Println(string(password))
return
}
for _, char := range characters {
password[index] = char
generateHelper(characters, password, index+1)
}
}
然而,我在Go中遇到了困难。
其他问题似乎是关于排列组合的,这不完全是我想要的。虽然Python文档中包含了该函数的示例实现,但我不知道如何将yield
翻译成Go。
我想我应该提到两个限制:
- 我希望密码的长度是可变的。也就是说,我可能想要进行8位字符密码、6位字符密码或其他长度的密码。这意味着我们不能只是嵌套n个循环。
- 我不希望一次性将所有密码都保存在内存中。
英文:
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:
- I'd like the length of the password to be variable. That is, I may want to do 8-character passwords, or 6-character, or something else. This means we can't just nest n loops.
- I don't want to have all of them in memory at once.
答案1
得分: 11
你想要的基本上是一个集合与自身的n元笛卡尔积。所以对于所有的3个字符的密码,你想要的是Prod(set,set,set)。这可以通过迭代构建。首先构建n-1个元素的积,然后对于每个积和初始集合的每个元素,添加该元素。例如,所有的2个字符的密码 -> 只有'a'或'b'是有效字符的3个字符的密码。
"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
}
// 将输入复制到初始积集合中--一个由一个字符集合组成的集合
prod := make([]string, len(input))
for i, char := range input {
prod[i] = string(char)
}
for i := 1; i < n; i++ {
// 更大的积应该是输入大小乘以n-1大小的积
next := make([]string, 0, len(input)*len(prod))
// 将每个字符添加到每个单词中,并将其添加到新集合中
for _, word := range prod {
for _, char := range input {
next = append(next, word + string(char))
}
}
prod = next
}
return prod
}
Playground版本:http://play.golang.org/p/6LhApeJ1bv
值得注意的是,这个解决方案还有很大的改进空间。如果你想要构建长度为6-18的所有密码,独立地为每个密码调用这个方法将重新计算先前计算过的集合。我将把编写更好的版本留给你。根据我给你展示的内容,修改代码以接受任意的(n-m)元积并计算n元积不应该太困难。(提示:考虑如何递归地完成这个任务)
英文:
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)
答案2
得分: 8
例如,满足您的限制条件,
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)
}
}
输出:
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
英文:
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
答案3
得分: 1
package main
import (
"fmt"
"strings"
"strconv"
// 字符串的排列组合
"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, ""))
}
}
}
以上是你提供的代码的翻译结果。
英文:
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, ""))
}
}
}
答案4
得分: 0
这是一个Iterium包:https://github.com/mowshon/iterium
以下是使用Iterium.Product()
和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)
// 将字符切片合并为字符串类型的密码
//
// 已经包含了拉丁字母的大写和小写字母`iterium.AsciiLetters`
// https://github.com/mowshon/iterium/blob/main/string.go
// 您可以使用它,而不必从头开始创建切片。
//
// 例如: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)
}
}
输出:
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
英文:
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
答案5
得分: -1
使用select for channels来生成唯一密码
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
}
}
}
这段代码使用select for channels来生成唯一密码。它定义了四个字符串变量:Capschar、smallchar、nums和specials,分别表示大写字母、小写字母、数字和特殊字符。然后,它创建了一个带有缓冲区大小l的字符串通道out,并在函数结束时关闭该通道。接下来,使用select语句从不同的字符串中选择一个随机字符,并将其发送到out通道中。如果无法发送字符到通道中,则函数返回。
英文:
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
}
}
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论