你可以使用”crypto/rand”包来生成一个随机整数。

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

How can I generate a random int using the "crypto/rand" package?

问题

说我想要使用以下代码在0和27之间生成一个安全的随机整数:

func Int(rand io.Reader, max *big.Int) (n *big.Int, err error)

"crypto/rand"包中。

我该如何做到这一点?

我真的不明白这是如何工作的,为什么它不返回内置的Go整数之一,而是返回指向某个big.Int类型的指针?

编辑:

这个对于令牌来说是否足够安全?

func getToken(length int) string {
    token := ""
    codeAlphabet := "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
    codeAlphabet += "abcdefghijklmnopqrstuvwxyz"
    codeAlphabet += "0123456789"

    for i := 0; i < length; i++ {
        token += string(codeAlphabet[cryptoRandSecure(int64(len(codeAlphabet)))])
    }
    return token
}

func cryptoRandSecure(max int64) int64 {
    nBig, err := rand.Int(rand.Reader, big.NewInt(max))
    if err != nil {
        log.Println(err)
    }
    return nBig.Int64()
}

func main() {
    fmt.Println(getToken(32))
}

这将输出类似以下的内容:

qZDbuPwNQGrgVmZCU9A7FUWbp8eIfn0Z

EwZVoQ5D5SEfdhiRsDfH6dU6tAovILCZ

cOqzODVP0GwbiNBwtmqLA78rFgV9d3VT
英文:

Say I would like to generate a secure random int between 0 and 27 using:

func Int(rand io.Reader, max *big.Int) (n *big.Int, err error)

in the &quot;crypto/rand&quot; package.

How would I do that?

I do not really understand how this works, why does it not return one of the built in Go ints instead of pointer to some big.Int type?

EDIT:

Would this be considered secure enough for tokens?

func getToken(length int) string {
	token := &quot;&quot;
	codeAlphabet := &quot;ABCDEFGHIJKLMNOPQRSTUVWXYZ&quot;
	codeAlphabet += &quot;abcdefghijklmnopqrstuvwxyz&quot;
	codeAlphabet += &quot;0123456789&quot;

	for i := 0; i &lt; length; i++ {
		token += string(codeAlphabet[cryptoRandSecure(int64(len(codeAlphabet)))])
	}
	return token
}

func cryptoRandSecure(max int64) int64 {
	nBig, err := rand.Int(rand.Reader, big.NewInt(max))
	if err != nil {
		log.Println(err)
	}
	return nBig.Int64()
}

func main() {
	fmt.Println(getToken(32))
}

This would output something like this:

qZDbuPwNQGrgVmZCU9A7FUWbp8eIfn0Z

EwZVoQ5D5SEfdhiRsDfH6dU6tAovILCZ

cOqzODVP0GwbiNBwtmqLA78rFgV9d3VT

答案1

得分: 48

以下是翻译好的代码:

这是一段可工作的代码:

package main

import (
	"fmt"
	"crypto/rand"
	"math/big"
)

func main() {
	nBig, err := rand.Int(rand.Reader, big.NewInt(27))
	if err != nil {
		panic(err)
	}
	n := nBig.Int64()
	fmt.Printf("这是一个在[0,27)范围内的随机数:%d\n", n)
}

但是要生成一个随机令牌,我会这样做:

package main

import (
	"crypto/rand"
	"encoding/base32"
	"fmt"
)

func main() {
	token := getToken(10)
	fmt.Println("这是一个随机令牌:", token)
}

func getToken(length int) string {
	randomBytes := make([]byte, 32)
	_, err := rand.Read(randomBytes)
	if err != nil {
		panic(err)
	}
	return base32.StdEncoding.EncodeToString(randomBytes)[:length]
}
英文:

Here is some working code :

package main

import (
	&quot;fmt&quot;
	&quot;crypto/rand&quot;
	&quot;math/big&quot;
)

func main() {
	nBig, err := rand.Int(rand.Reader, big.NewInt(27))
	if err != nil {
		panic(err)
	}
	n := nBig.Int64()
	fmt.Printf(&quot;Here is a random %T in [0,27) : %d\n&quot;, n, n)
}

But to generate a random token, I'd do something like this :

package main

import (
	&quot;crypto/rand&quot;
	&quot;encoding/base32&quot;
	&quot;fmt&quot;
)

func main() {
	token := getToken(10)
	fmt.Println(&quot;Here is a random token : &quot;, token)
}

func getToken(length int) string {
	randomBytes := make([]byte, 32)
	_, err := rand.Read(randomBytes)
	if err != nil {
		panic(err)
	}
	return base32.StdEncoding.EncodeToString(randomBytes)[:length]
}

答案2

得分: 36

如果你正在生成用于会话ID、OAuth Bearer令牌、CSRF或类似用途的安全令牌,你应该生成一个理想情况下为256位(32字节)或不少于192位(24字节)的令牌。

值在0到27之间的令牌可以在不到一秒钟内被暴力破解,因此不能被视为安全。

例如:

package main

import (
	"crypto/rand"
	"encoding/base64"
)

// GenerateRandomBytes返回安全生成的随机字节。
// 如果系统的安全随机数生成器无法正常工作,它将返回错误,此时调用者不应继续执行。
func GenerateRandomBytes(n int) ([]byte, error) {
	b := make([]byte, n)
	_, err := rand.Read(b)
	// 注意,只有当我们读取了len(b)字节时,err才为nil。
	if err != nil {
		return nil, err
	}

	return b, nil
}

// GenerateRandomString返回一个URL安全的、base64编码的安全生成的随机字符串。
func GenerateRandomString(s int) (string, error) {
	b, err := GenerateRandomBytes(s)
	return base64.URLEncoding.EncodeToString(b), err
}

func main() {
	// 示例:这将给我们一个44字节的base64编码输出
	token, err := GenerateRandomString(32)
	if err != nil {
		// 向用户提供适当模糊的错误,但在内部记录详细信息。
	}
}

base64输出适用于头部、HTTP表单、JSON主体等。

如果你需要一个整数,可能需要解释一下你的用例,因为系统要求令牌为整数可能有些奇怪。

英文:

If you're generating secure tokens for session IDs, OAuth Bearer tokens, CSRF or similar: you want to generate a token of (ideally) 256 bits (32 bytes) or no less than 192 bits (24 bytes).

A token with values between (0-27) can be brute-forced in less than a second and could not be considered secure.

e.g.

package main

import (
	&quot;crypto/rand&quot;
	&quot;encoding/base64&quot;
)

// GenerateRandomBytes returns securely generated random bytes.
// It will return an error if the system&#39;s secure random
// number generator fails to function correctly, in which
// case the caller should not continue.
func GenerateRandomBytes(n int) ([]byte, error) {
	b := make([]byte, n)
	_, err := rand.Read(b)
	// Note that err == nil only if we read len(b) bytes.
	if err != nil {
		return nil, err
	}

	return b, nil
}

// GenerateRandomString returns a URL-safe, base64 encoded
// securely generated random string.
func GenerateRandomString(s int) (string, error) {
	b, err := GenerateRandomBytes(s)
	return base64.URLEncoding.EncodeToString(b), err
}

func main() {
	// Example: this will give us a 44 byte, base64 encoded output
	token, err := GenerateRandomString(32)
	if err != nil {
		// Serve an appropriately vague error to the
		// user, but log the details internally.
    }
}

The base64 output is safe for headers, HTTP forms, JSON bodies, etc.

If you need an integer it may help to explain your use-case, as it would be odd for a system to require tokens as ints.

答案3

得分: 2

如果你只需要一个小的数字(即[0, 255]范围内),你可以直接从包的Reader中读取一个字节:

b := []byte{0}
if _, err := rand.Reader.Read(b); err != nil {
    panic(err)
}
n := b[0]
fmt.Println(n)

Playground: http://play.golang.org/p/4VO52LiEVh(这个示例在那里无法运行,我不知道它是否按预期工作,或者是一个playground的bug)。

英文:

If you only need a small number (i.e. [0, 255]), you could just read a byte out of the package's Reader:

b := []byte{0}
if _, err := rand.Reader.Read(b); err != nil {
	panic(err)
}
n := b[0]
fmt.Println(n)

Playground: http://play.golang.org/p/4VO52LiEVh (the example won't work there, I don't know if it's working as intended or it's a playground bug).

huangapple
  • 本文由 发表于 2015年9月2日 17:44:11
  • 转载请务必保留本文链接:https://go.coder-hub.com/32349807.html
匿名

发表评论

匿名网友

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

确定