Skip to content

Commit

Permalink
churn nonces each reseed
Browse files Browse the repository at this point in the history
  • Loading branch information
jrick committed Jun 12, 2024
1 parent cbabe1c commit 1a595c6
Showing 1 changed file with 33 additions and 12 deletions.
45 changes: 33 additions & 12 deletions peer/internal/uprng/uprng.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@ package uprng

import (
cryptorand "crypto/rand"
"encoding/binary"
"io"
"math/bits"
"sync"
"time"

Expand All @@ -27,20 +29,42 @@ const (
maxCipherDuration = 20 * time.Second
)

var (
key = make([]byte, chacha20.KeySize)
nonce = make([]byte, chacha20.NonceSize)
)
// nonce implements a 12-byte little endian counter suitable for use as an
// incrementing ChaCha20 nonce.
type nonce struct {
limbs [3]uint32
bytes []byte
}

func newNonce() *nonce {
return &nonce{bytes: make([]byte, chacha20.NonceSize)}
}

func (n *nonce) inc() {
var carry uint32
n.limbs[0], carry = bits.Add32(n.limbs[0], 1, carry)
n.limbs[1], carry = bits.Add32(n.limbs[1], 0, carry)
n.limbs[2], carry = bits.Add32(n.limbs[2], 0, carry)
n.limbs[0], _ = bits.Add32(n.limbs[0], 0, carry)
binary.LittleEndian.PutUint32(n.bytes[0:4], n.limbs[0])
binary.LittleEndian.PutUint32(n.bytes[4:8], n.limbs[1])
binary.LittleEndian.PutUint32(n.bytes[8:12], n.limbs[2])
}

type prng struct {
cipher *chacha20.Cipher
read int
t time.Time
key []byte
nonce *nonce
mu sync.Mutex
}

func newPRNG() *prng {
p := new(prng)
p := &prng{
nonce: newNonce(),
key: make([]byte, chacha20.KeySize),
}
p.seed()
return p
}
Expand All @@ -49,20 +73,17 @@ func newPRNG() *prng {
// cipher has been originally seeded.
// Panics only during initial seeding if a crypto/rand read errors.
func (p *prng) seed() {
_, err := cryptorand.Read(key)
_, err := cryptorand.Read(p.key)
if err != nil && p.cipher == nil {
panic(err)
}
if p.cipher != nil {
p.cipher.XORKeyStream(key, key)
p.cipher.XORKeyStream(p.key, p.key)
}

// never errors with correct key and nonce sizes
cipher, _ := chacha20.NewUnauthenticatedCipher(key, nonce)

for i := range key {
key[i] = 0
}
cipher, _ := chacha20.NewUnauthenticatedCipher(p.key, p.nonce.bytes)
p.nonce.inc()

p.cipher = cipher
p.read = 0
Expand Down

0 comments on commit 1a595c6

Please sign in to comment.