package main
import (
"fmt"
"math/rand"
)
func main() {
// NewSource возвращает новый псевдослучайный источник с заданным значением.
sec1 := rand.New(rand.NewSource(10))
sec2 := rand.New(rand.NewSource(10))
for i := 0; i < 5; i++ {
// генерация случайных значений из источников
rnd1 := sec1.Int()
rnd2 := sec2.Int()
if rnd1 != rnd2 {
fmt.Println("Сгенерированная случайным образом последовательность")
break
} else {
fmt.Printf("rnd1: %d, rnd2: %d\n", rnd1, rnd2)
}
}
}
$ go run main.go
rnd1: 5221277731205826435, rnd2: 5221277731205826435
rnd1: 3852159813000522384, rnd2: 3852159813000522384
rnd1: 8532807521486154107, rnd2: 8532807521486154107
rmd1: 3888302351045490779, rnd2: 3888302351045490779
rmd1: 4512466281294657143, rnd2: 4512466281294657143
Source()
. Такой подход обычно применяется в тестах, так как он воспроизводит последовательность чисел.math/rand
не подходит для генерации чувствительных данных, например куки-файлов, токенов или ключей. Для подобных задач генератор случайных чисел должен сохранять непредсказуемость и быть стойким к дешифрованию. rand.Read()
из пакета crypto/rand
. В параметре функции нужно передать слайс байт ненулевой длины, который будет заполнен случайными байтами. Размер слайса не изменяется.hex.EncodeToString()
из пакета encoding/hex
:package main
import (
"crypto/rand"
"encoding/hex"
"fmt"
)
func main() {
// определяем слайс байт нужной длины
b := make([]byte, 16)
_, err := rand.Read(b) // записываем байты в слайс b
if err != nil {
fmt.Printf("error: %v\n", err)
return
}
fmt.Println(hex.EncodeToString(b))
}
hex.EncodeToString()
возвращает строку в 16-теричном формате.1b126d63a8122a2f7c34d9983a4301d0
b9652aa716b126cf8a393aa6d848ee4b
hash.Hash
.package main
import (
"crypto/sha256"
"fmt"
)
func main() {
src := []byte("Здесь могло быть написано, чем Go лучше Rust. " +
"Но после хеширования уже не прочитаешь.")
// создаём новый hash.Hash, вычисляющий контрольную сумму SHA-256
h := sha256.New()
// передаём байты для хеширования
h.Write(src)
// вычисляем хеш
dst := h.Sum(nil)
fmt.Printf("%x", dst)
}
Sum256(data []byte)
. Она возвращает массив из 32 байт — это длина получаемого хеша.hmac.New(h func() hash.Hash, key []byte) hash.Hash
нужно указать используемую криптографическую хеш-функцию и ключ.package main
import (
"crypto/hmac"
"crypto/rand"
"crypto/sha256"
"fmt"
)
func generateRandom(size int) ([]byte, error) {
// генерируем случайную последовательность байт
b := make([]byte, size)
_, err := rand.Read(b)
if err != nil {
return nil, err
}
return b, nil
}
func main() {
// подписываемое сообщение
src := []byte("Видишь гофера? Нет. И я нет. А он есть.")
// создаём случайный ключ
key, err := generateRandom(16)
if err != nil {
fmt.Printf("error: %v\n", err)
return
}
// подписываем алгоритмом HMAC, используя SHA-256
h := hmac.New(sha256.New, key)
h.Write(src)
dst := h.Sum(nil)
fmt.Printf("%x", dst)
}
hmac.Equal
проверить, что подписи совпадают.cipher.Block
из пакета crypto/cipher.package main
import (
"crypto/aes"
"crypto/rand"
"fmt"
)
func generateRandom(size int) ([]byte, error) {
// генерируем криптостойкие случайные байты в b
b := make([]byte, size)
_, err := rand.Read(b)
if err != nil {
return nil, err
}
return b, nil
}
func main() {
src := []byte("Слепой банкир") // данные, которые хотим зашифровать
fmt.Printf("original: %s\n", src)
// константа aes.BlockSize определяет размер блока, она равна 16 байтам
key, err := generateRandom(aes.BlockSize) // ключ шифрования
if err != nil {
fmt.Printf("error: %v\n", err)
return
}
// получаем cipher.Block
aesblock, err := aes.NewCipher(key)
if err != nil {
fmt.Printf("error: %v\n", err)
return
}
dst := make([]byte, aes.BlockSize) // зашифровываем
aesblock.Encrypt(dst, src)
fmt.Printf("encrypted: %x\n", dst)
src2 := make([]byte, aes.BlockSize) // расшифровываем
aesblock.Decrypt(src2, dst)
fmt.Printf("decrypted: %s\n", src2)
}
package main
import (
"crypto/aes"
"crypto/cipher"
"crypto/rand"
"fmt"
)
func generateRandom(size int) ([]byte, error) {
// генерируем криптостойкие случайные байты в b
b := make([]byte, size)
_, err := rand.Read(b)
if err != nil {
return nil, err
}
return b, nil
}
func main() {
src := []byte("Ключ от сердца") // данные, которые хотим зашифровать
fmt.Printf("original: %s\n", src)
// будем использовать AES-256, создав ключ длиной 32 байта
key, err := generateRandom(2 * aes.BlockSize) // ключ шифрования
if err != nil {
fmt.Printf("error: %v\n", err)
return
}
// NewCipher создает и возвращает новый cipher.Block.
// Ключевым аргументом должен быть ключ AES, 16, 24 или 32 байта
// для выбора AES-128, AES-192 или AES-256.
aesblock, err := aes.NewCipher(key)
if err != nil {
fmt.Printf("error: %v\n", err)
return
}
// NewGCM возвращает заданный 128-битный блочный шифр
aesgcm, err := cipher.NewGCM(aesblock)
if err != nil {
fmt.Printf("error: %v\n", err)
return
}
// создаём вектор инициализации
nonce, err := generateRandom(aesgcm.NonceSize())
if err != nil {
fmt.Printf("error: %v\n", err)
return
}
dst := aesgcm.Seal(nil, nonce, src, nil) // зашифровываем
fmt.Printf("encrypted: %x\n", dst)
src2, err := aesgcm.Open(nil, nonce, dst, nil) // расшифровываем
if err != nil {
fmt.Printf("error: %v\n", err)
return
}
fmt.Printf("decrypted: %s\n", src2)
}
math/rand
.crypto/sha256
.crypto/md5
.crypto/cipher
.