在 Go 中生成一个随机的、固定长度的字节数组

Generating a random, fixed-length byte array in Go

我有一个字节数组,固定长度为 4。

1
token := make([]byte, 4)

我需要将每个字节设置为随机字节。我怎样才能做到这一点,以最有效的方式? math/rand 方法不提供随机字节函数,就我而言。

也许有一种内置方法,或者我应该生成一个随机字符串并将其转换为字节数组?


Package rand

1
import"math/rand"

func Read

1
func Read(p []byte) (n int, err error)

Read generates len(p) random bytes from the default Source and writes
them into p. It always returns len(p) and a nil error.

func (*Rand) Read

1
func (r *Rand) Read(p []byte) (n int, err error)

Read generates len(p) random bytes and writes them into p. It always
returns len(p) and a nil error.

例如,

1
2
3
4
5
6
7
8
9
10
11
12
package main

import (
   "math/rand"
   "fmt"
)

func main() {
    token := make([]byte, 4)
    rand.Read(token)
    fmt.Println(token)
}

输出:

1
[187 163 35 30]


Go 1.6 在 math/rand 包中添加了一个新功能:

1
func Read(p []byte) (n int, err error)

用随机数据填充传递的 byte 切片。使用这个 rand.Read():

1
2
3
4
5
token := make([]byte, 4)
if _, err := rand.Read(token); err != nil {
    // Handle err
}
fmt.Println(token)

rand.Read() 有 2 个返回值:"读取"字节数和(可选)error。这是为了符合通用的 io.Reader 接口,但是 rand.Read() 的文档指出(尽管有它的签名)它实际上永远不会返回非 nil 错误,所以我们可以省略检查它,这将其简化为这个:

1
2
3
token := make([]byte, 4)
rand.Read(token)
fmt.Println(token)

在使用 math/rand 包之前不要忘记调用 rand.Seed() 来正确初始化它,例如:

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

注意:在 Go 1.6 之前没有 math/rand.Read() 函数,但是有(并且仍然是)一个 crypto/rand.Read() 函数,但是 crypto/rand 包实现了一个加密安全的伪随机数生成器,所以它要慢得多比 math/rand.


使用 math.Rand 意味着您正在使用操作系统提供的系统 CSPRNG。这意味着使用 /dev/urandom/ 和 Windows 的 CryptGenRandom API。
幸运的是,Go 的 crypto/rand 包将这些实现细节抽象出来,以尽量减少出错的风险。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import(
  "crypto/rand"
  "encoding/base64"
 )

// GenerateRandomBytes returns securely generated random bytes.
// It will return an error if the system'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
}