Aşağıdaki örneği kullanarak, Golang ile farklı uzunluklarda güçlü ve rastgele bir şifre oluşturabilirsiniz. Malumen şifre kısaysa, güçlü olmayacaktır! Uzun şifrelerin mutlaka güçlü olacağıda varsayılamaz. İşlemin tam olarak nasıl çalıştığını anlamak için lütfen koddaki yorumu okuyun.


Şifre


package main

import (
"errors"
"fmt"
"math/rand/v2"
"strings"
)

// To reduce the chances of inappropriate or offensive words from being
// generated, vowels are excluded in the lower and upper charsets.
var (
symbols = []rune("<>{}[]()?,./;':!@$%^&*()_+#-=")
numbers = []rune("0123456789")
lowers = []rune("bcdfghjklmnpqrstvwxyz")
uppers = []rune("BCDFGHJKLMNPQRSTVWXYZ")
)

// Password is used to define what the password should look like. All
// configuration groups are optional but at least one is required.
//
// - If a group if set as `nil` or not set at all, default charset will be used.
// - In order to avoid using certain group, set it as `[]rune{}`.
type Password struct {
// Symbols optionally defines list of allowed symbols.
Symbols []rune

// Numbers optionally defines list of allowed numbers.
Numbers []rune

// Lowers optionally defines list of allowed lower case letters.
Lowers []rune

// Uppers optionally defines list of allowed upper case letters.
Uppers []rune
}

// Generate generates a random password for the given length based on the
// configuration groups. Character selecting is evenly distributed between each
// groups. In case there is a remainder, it is added to first enabled group. The
// `length` must be `> 8` as per 'NIST Password Guidelines'.
func (p Password) Generate(length int) (string, error) {
if length < 8 {
return "", fmt.Errorf("invalid length: %d", length)
}

if p.Symbols == nil {
p.Symbols = symbols
}
if p.Numbers == nil {
p.Numbers = numbers
}
if p.Lowers == nil {
p.Lowers = lowers
}
if p.Uppers == nil {
p.Uppers = uppers
}

var groups int

if len(p.Symbols) != 0 {
groups++
}
if len(p.Numbers) != 0 {
groups++
}
if len(p.Lowers) != 0 {
groups++
}
if len(p.Uppers) != 0 {
groups++
}

if groups == 0 {
return "", errors.New("at least one charset is required")
}

var (
retry = p.retry(length)
limit = length / groups
remainder = length - (groups * limit)
chars = ""
)

if len(p.Symbols) != 0 {
chars += p.pick(p.Symbols, limit+remainder, retry)
remainder = 0
}

if len(p.Numbers) != 0 {
chars += p.pick(p.Numbers, limit+remainder, retry)
remainder = 0
}

if len(p.Uppers) != 0 {
chars += p.pick(p.Uppers, limit+remainder, retry)
remainder = 0
}

if len(p.Lowers) != 0 {
chars += p.pick(p.Lowers, limit+remainder, retry)
remainder = 0
}

pasword := []rune(chars)

rand.Shuffle(length, func(i, j int) {
pasword[i], pasword[j] = pasword[j], pasword[i]
})

return string(pasword), nil
}

// retry works out maximum how many times the `pick()` method should retry to
// pick a unique charcter. If the password length is a high number, chances of
// picking same character is also high. Hence, retry count is kept higher to
// help increase chances of uniqueness although it wont always be guaranteed.
func (p Password) retry(length int) int {
if length >= 50 {
return 30
} else if length >= 30 {
return 20
}

return 10
}

// pick tries its best to pick a unique and limited characters from the given
// charset. In case uniqueness is not achievable for any character in iterations
// retry exists to prevent infinite loop and moves on. The longer the password
// length, the higher the chance of having similar characters.
func (p Password) pick(charset []rune, limit, retry int) string {
var (
try int
chars strings.Builder
length = len(charset)
)

for i := 0; i < limit; i++ {
try++

char := charset[rand.IntN(length)]
if !strings.ContainsRune(chars.String(), char) {
chars.WriteString(string(char))
try = 0

continue
}

if try < retry {
i--

continue
}

chars.WriteString(string(char))
}

return chars.String()
}

func main() {
var pass Password

for _, v := range []int{9, 17, 40, 100} {
res, _ := pass.Generate(v)
fmt.Println(len(res))
fmt.Println(res)
}
}

Test


$ go run -race main.go
9
_Zbj{4/7N
-------------------------------------------------------------
17
!l{9HsS617%pm]KD,
-------------------------------------------------------------
40
Y9)5xwr7>DR-}v=$dbp21B/3hG^MfL06QH,6y4K(
-------------------------------------------------------------
100
n2lmcN7SKz565C-}:d7/x_BwsPQ65BGXf3%R9y=jqcT!K8t?pX8F6D;^(,7G9kJp31#$+4gdhL.*Y712HV]xv10@'YBM>)b[r{35
-------------------------------------------------------------