- Go でランダム文字列を生成するには crypt/rand などの乱数生成器を使う方法がある
- 加えて、パスワードなどの平文を生成する際に、「英大文字、小文字、数字が必ず一つ以上含まれていること」などのポリシーに則った文字列を生成したい時がある
- そんな時用のスニペット
main.go
package main
import (
"crypto/rand"
"fmt"
"math/big"
)
func main() {
pp, _ := newPlainPassword(16)
fmt.Println(pp)
}
func newPlainPassword(length int) (string, error) {
const (
uppercaseCharset = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
lowercaseCharset = "abcdefghijklmnopqrstuvwxyz"
numbersCharset = "0123456789"
)
const minimumTokenLength = 10
if length < minimumTokenLength {
return "", fmt.Errorf("長さは %d 文字以上である必要があります", minimumTokenLength)
}
var token []byte
// 英小文字を追加、英大文字を追加、数字を一個ずつ追加
for _, charset := range []string{lowercaseCharset, uppercaseCharset, numbersCharset} {
randomIndex, err := rand.Int(rand.Reader, big.NewInt(int64(len(charset))))
if err != nil {
return "", fmt.Errorf("failed to rand.Int, error: %s", err.Error())
}
token = append(token, charset[randomIndex.Int64()])
}
// 残りの文字を生成
charset := uppercaseCharset + lowercaseCharset + numbersCharset
for i := 3; i < length; i++ {
randomIndex, err := rand.Int(rand.Reader, big.NewInt(int64(len(charset))))
if err != nil {
return "", fmt.Errorf("failed to rand.Int, error: %s", err.Error())
}
token = append(token, charset[randomIndex.Int64()])
}
// 先頭3桁に法則性が発生してしまうため、生成したパスワードをランダムに並び替える
for i := 0; i < len(token)-1; i++ {
j, err := rand.Int(rand.Reader, big.NewInt(int64(len(token)-i)))
if err != nil {
return "", fmt.Errorf("failed to rand.Int, error: %s", err.Error())
}
token[i], token[int64(i)+j.Int64()] = token[int64(i)+j.Int64()], token[i]
}
return string(token), nil
}