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  }