Генерирование случайного массива байтов с фиксированной длиной в Go

У меня есть байтовый массив с фиксированной длиной 4.

token := make([]byte, 4)

Мне нужно установить каждый байт на случайный байт. Как я могу это сделать, в самом эффективном? Методы math/rand не предоставляют функцию Random Byte, насколько мне известно.

Возможно, есть встроенный способ, или мне нужно создать случайную строку и преобразовать ее в массив байтов?

Ответ 1

Пакет rand

import "math/rand" 

func Читать

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

Чтение генерирует случайные байты len (p) из источника по умолчанию и записывает их в p. Он всегда возвращает len (p) и ошибку nil.

f unc (* Rand) Читать

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

Чтение генерирует случайные байты len (p) и записывает их в p. Так всегда возвращает len (p) и ошибку nil.

Например,

package main

import (
    "math/rand"
    "fmt"
)

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

Вывод:

[187 163 35 30]

Ответ 2

Go 1.6 добавил новую функцию в пакет math/rand:

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

который заполняет переданный кусочек byte случайными данными. Используя этот rand.Read():

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

rand.Read() имеет 2 возвращаемых значения: количество "прочитанных" байтов и (необязательная) error. Это должно соответствовать общему интерфейсу io.Reader, но документация rand.Read() гласит, что (несмотря на свою подпись) он на самом деле никогда не вернет ошибку non- nil, поэтому мы можем не проверять ее, что упрощает ее к этому:

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

Не забудьте вызвать rand.Seed() чтобы правильно инициализировать его перед использованием пакета math/rand, например:

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

Примечание: до Go 1.6 не было никакой функции math/rand.Read(), но была (и есть crypto/rand.Read() функция crypto/rand.Read(), но пакет crypto/rand реализует криптографически безопасный генератор псевдослучайных чисел, так что это намного медленнее, чем math/rand.

Ответ 3

Использование math.Rand означает, что вы используете системный CSPRNG, предоставляемый вашей операционной системой. Это означает использование /dev/urandom/и Windows CryptGenRandom API. Gos crypto/rand package, к счастью, абстрагирует эти детали реализации, чтобы минимизировать риск ошибиться.

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

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