用Golang生成一个强大的随机普通密码

583 阅读1分钟

你可以使用下面的例子来生成一个长度可变的强随机密码串。显然,如果密码很短,它就不会很强!长密码也不一定意味着它很强。请阅读代码中的注释,以便你知道它到底是如何工作的。

package main

import (
	"fmt"
	"math/rand"
	"strings"
	"time"
)

var list = []string{
	"(){}[]<>/+=-_,.~€#!@£$%^&*?|",
	"0123456789",
	"abcdefghijklmnopqrstuvwxyz",
	"ABCDEFGHIJKLMNOPQRSTUVWXYZ",
}

// GeneratePlainPassword generates a random plain password string.
// It consists of four groups which are certain symbols, numbers,
// lower and upper case letters. As per the length and the remainder,
// character selecting is evenly distributed within these groups.
// Although it is unlikely, a final password might contain duplicated
// characters. If a specific character was selected previously, it gets
// dropped in order to increase randomness. Depending on the length
// this is repeated set amount of times to prevent infinite loop and
// applies to all four groups. Greater the length, greater chance in
// duplicated characters.
func GeneratePlainPassword(length int) (string, error) {
	if length < 1 {
		return "", nil
	}

	var (
		retry  int
		group  int
		chars string
	)

	if length <= 4 {
		retry = 1
	} else if length > 20 && length <= 50 {
		retry = 20
	} else if length > 50 {
		retry = 30
	} else {
		retry = 10
	}

	rand.Seed(time.Now().UnixNano())

	for i := 1; i <= length; i++ {
		switch group {
		case 0:
			pick(0, 31, retry, &chars)
			group++
		case 1:
			pick(1, 10, retry, &chars)
			group++
		case 2:
			pick(2, 26, retry, &chars)
			group++
		case 3:
			pick(3, 26, retry, &chars)
			group = 0
		default:
			return "", fmt.Errorf("out of group range")
		}
	}

	psw := []byte(chars)
	rand.Shuffle(length, func(i, j int) { psw[i], psw[j] = psw[j], psw[i] })

	return string(psw), nil
}

func pick(key, len, retry int, chars *string) {
	var try int

	for {
		try++

		idx := rand.Intn(len)
		char := list[key][idx:idx+1]
		if !strings.Contains(*chars, char) || try == retry {
			*chars += char

			break
		}
	}
}

例子

RETRY: n/a
LENGTH: 0
PASSWR: 
------------------------------------------------------------
RETRY: 1
LENGTH: 3
PASSWR: )4a
------------------------------------------------------------
RETRY: 10
LENGTH: 10
PASSWR: +i79d>W=4F
------------------------------------------------------------
RETRY: 20
LENGTH: 25
PASSWR: Mtm*d/>BN39?1y+J,kC54[8Lv
------------------------------------------------------------
RETRY: 30
LENGTH: 55
PASSWR: [QZ2b/=61.z]98^*Txqfst3!u£cS0#?XGVL%U3,0H1yj7KOmvr6&4C5
------------------------------------------------------------
RETRY: 30
LENGTH: 110
PASSWR: MaWYO)Bb3_&95O{qVn3kF,3]yT(R4~9P€7Z[l0N!0U&2#rw37J^Efgo£7.q)c8HL6?Sp44vm1/I=5@46h5stC}2i2uGe-X$zs|+A3xDj*Q4dK%