生成所有可能的n个字符密码

huangapple go评论87阅读模式
英文:

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。

我想我应该提到两个限制:

  1. 我希望密码的长度是可变的。也就是说,我可能想要进行8位字符密码、6位字符密码或其他长度的密码。这意味着我们不能只是嵌套n个循环。
  2. 我不希望一次性将所有密码都保存在内存中。
英文:

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:

  1. 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.
  2. 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'.

&quot;ab&quot; = {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 &lt;= 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 &lt; 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 &quot;fmt&quot;

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 &gt;= 0; i-- {
			x[i]++
			if x[i] &lt; len(r) {
				break
			}
			x[i] = 0
			if i &lt;= 0 {
				x = x[0:0]
				break
			}
		}
		return string(p)
	}
}

func main() {
	np := nextPassword(2, &quot;ABCDE&quot;)
	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	(
	&quot;fmt&quot;
	&quot;strings&quot;
	&quot;strconv&quot;

	// permutation and combination of charactersList
	&quot;github.com/ernestosuarez/itertools&quot;
)


func main()  {
	passwordLength := &quot;1,2,4&quot;
	characters := &quot;abcdefghijklmnopqrstuvwxyz0123456789!@#$%^&amp;*()+-./&quot;

	passwordLengthList := strings.Split(passwordLength, &quot;,&quot;)
	charactersList := strings.Split(characters, &quot;&quot;)

	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, &quot;&quot;))
		}
	}
}

答案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 (
	&quot;fmt&quot;
	&quot;github.com/mowshon/iterium&quot;
	&quot;strings&quot;
)

func main() {
	letters := []string{&quot;A&quot;, &quot;B&quot;, &quot;C&quot;, &quot;D&quot;, &quot;E&quot;}
	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, &quot;&quot;)
	})

	fmt.Println(&quot;Total:&quot;, 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 := &quot;ABCDEFGHIJKLMNOPQRSTUVWXYZ&quot;
smallchar := &quot;abcdefghijklmnopqrstuvwxyz&quot;
nums := &quot;0123456789&quot;
specials := &quot;!@#$%ˆ&amp;*()?&gt;&lt;&quot;
out = make(chan string, l)
defer close(out)
for {
	select {
	case out &lt;- string(Capschar[rand.Intn(len(strings.Split(Capschar, &quot;&quot;)))]):
	case out &lt;- string(Capschar[rand.Intn(len(strings.Split(Capschar, &quot;&quot;)))]):
	case out &lt;- string(Capschar[rand.Intn(len(strings.Split(Capschar, &quot;&quot;)))]):
	case out &lt;- string(smallchar[rand.Intn(len(strings.Split(smallchar, &quot;&quot;)))]):
	case out &lt;- string(smallchar[rand.Intn(len(strings.Split(smallchar, &quot;&quot;)))]):
	case out &lt;- string(smallchar[rand.Intn(len(strings.Split(smallchar, &quot;&quot;)))]):
	case out &lt;- string(nums[rand.Intn(len(strings.Split(nums, &quot;&quot;)))]):
	case out &lt;- string(specials[rand.Intn(len(strings.Split(specials, &quot;&quot;)))]):
	default:
		return

	}
}

}

huangapple
  • 本文由 发表于 2014年3月30日 09:10:48
  • 转载请务必保留本文链接:https://go.coder-hub.com/22739085.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定