LoginSignup
0
0

【Go】ポリシーに則ったランダムパスワード文字列の生成

Posted at
  • 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
}

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0