github.com/usbarmory/tamago@v0.0.0-20240508072735-8612bbe1e454/internal/rng/aes.go (about) 1 // Copyright 2010 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 // 5 // This code is adapted from Go `rand_plan9.go`. 6 7 package rng 8 9 import ( 10 "crypto/aes" 11 "encoding/binary" 12 "sync" 13 ) 14 15 // DRBG is an AES-CTR based Deterministic Random Bit Generator. The generator 16 // is a fast key erasure RNG. 17 type DRBG struct { 18 sync.Mutex 19 20 // Seed represents the initial key for the AES-CTR cipher instance, it 21 // will be overwritten during use to implement key erasure. 22 Seed [32]byte 23 } 24 25 // GetRandomData returns len(b) random bytes. 26 func (r *DRBG) GetRandomData(b []byte) { 27 var counter uint64 28 var block [aes.BlockSize]byte 29 30 r.Lock() 31 blockCipher, err := aes.NewCipher(r.Seed[:]) 32 33 if err != nil { 34 panic(err) 35 } 36 37 inc := func() { 38 counter++ 39 if counter == 0 { 40 panic("DRBG counter wrapped") 41 } 42 binary.LittleEndian.PutUint64(block[:], counter) 43 } 44 45 blockCipher.Encrypt(r.Seed[:aes.BlockSize], block[:]) 46 inc() 47 blockCipher.Encrypt(r.Seed[aes.BlockSize:], block[:]) 48 inc() 49 r.Unlock() 50 51 for len(b) >= aes.BlockSize { 52 blockCipher.Encrypt(b[:aes.BlockSize], block[:]) 53 inc() 54 b = b[aes.BlockSize:] 55 } 56 if len(b) > 0 { 57 blockCipher.Encrypt(block[:], block[:]) 58 copy(b, block[:]) 59 } 60 }