@@ -102,6 +102,15 @@ type Config struct {
102102 // Zero disables reseed-on-request-count.
103103 ReseedRequests uint64
104104
105+ // ForkDetectionInterval controls how often fork detection is performed.
106+ //
107+ // If 0 (default), fork detection runs on every output request (max safety, fully compliant).
108+ // If >0, fork detection is performed once every N output requests (advanced tuning; reduces overhead
109+ // at the cost of a negligible window of risk).
110+ //
111+ // WARNING: Setting this above zero is NOT recommended for compliance-sensitive environments.
112+ ForkDetectionInterval uint64
113+
105114 // KeySize specifies the AES key length to use for this DRBG instance.
106115 //
107116 // Acceptable values:
@@ -188,35 +197,51 @@ const (
188197 defaultRekeyBackoff = 100 * time .Millisecond
189198)
190199
191- // DefaultConfig returns a Config struct populated with production-safe, recommended defaults.
200+ // DefaultConfig returns a Config struct populated with production-safe, NIST SP 800-90A Section 10.2.1-aligned defaults.
201+ //
202+ // This function provides a robust baseline configuration for AES-CTR-DRBG instances, suitable for general-purpose
203+ // cryptographic use and high-concurrency workloads. All parameters are selected to ensure strong security, compliance
204+ // with FIPS 140-2 and NIST SP 800-90A requirements, and operational reliability under diverse system conditions.
205+ //
206+ // The returned configuration enables fork-safety (via PID tracking), supports domain separation via personalization,
207+ // and is compatible with Go's FIPS-140 mode (GODEBUG=fips140=on).
192208//
193209// Defaults:
194- // - KeySize: 32 bytes (AES-256)
195- // - MaxBytesPerKey: 1 GiB (1 << 30)
196- // - MaxInitRetries: 3
197- // - MaxRekeyAttempts: 5
198- // - MaxRekeyBackoff: 2 seconds
199- // - RekeyBackoff: 100 milliseconds
200- // - EnableKeyRotation: true
201- // - Personalization: nil (no domain separation)
210+ // - KeySize: 32 bytes (AES-256, recommended by NIST for most use cases)
211+ // - MaxBytesPerKey: 1 GiB (1 << 30); triggers key rotation for forward secrecy
212+ // - MaxInitRetries: 3 attempts to initialize each DRBG pool entry
213+ // - MaxRekeyAttempts: 5 attempts per automatic key rotation
214+ // - MaxRekeyBackoff: 2 seconds (maximum exponential backoff between failed rekey attempts)
215+ // - RekeyBackoff: 100 milliseconds (initial backoff for rekey attempts)
216+ // - EnableKeyRotation: false (key rotation is disabled by default—**set to true for forward secrecy**)
217+ // - Personalization: nil (no domain separation unless set by the caller)
218+ // - UseZeroBuffer: false (random output generated directly into caller's buffer)
219+ // - DefaultBufferSize: 0 (no preallocation of zero-filled buffers)
220+ // - Shards: runtime.GOMAXPROCS(0) (number of internal DRBG pools matches available CPUs)
221+ // - PredictionResistance: false (prediction resistance is disabled; enable only if required by policy)
222+ // - ForkDetectionInterval: 0 (fork detection performed on every output request for maximum safety)
223+ //
224+ // NIST Reference:
225+ // - See NIST SP 800-90A, Section 10.2.1 (CTR DRBG) for cryptographic construction details.
202226//
203227// Example usage:
204228//
205229// cfg := ctrdrbg.DefaultConfig()
206230func DefaultConfig () Config {
207231 return Config {
208- KeySize : KeySize256 ,
209- MaxBytesPerKey : defaultMaxBytes ,
210- MaxInitRetries : defaultInitRetries ,
211- MaxRekeyAttempts : defaultRekeyRetries ,
212- MaxRekeyBackoff : defaultMaxBackoff ,
213- RekeyBackoff : defaultRekeyBackoff ,
214- EnableKeyRotation : false ,
215- Personalization : nil ,
216- UseZeroBuffer : false ,
217- DefaultBufferSize : 0 ,
218- Shards : runtime .GOMAXPROCS (0 ),
219- PredictionResistance : false ,
232+ KeySize : KeySize256 ,
233+ MaxBytesPerKey : defaultMaxBytes ,
234+ MaxInitRetries : defaultInitRetries ,
235+ MaxRekeyAttempts : defaultRekeyRetries ,
236+ MaxRekeyBackoff : defaultMaxBackoff ,
237+ RekeyBackoff : defaultRekeyBackoff ,
238+ EnableKeyRotation : false ,
239+ Personalization : nil ,
240+ UseZeroBuffer : false ,
241+ DefaultBufferSize : 0 ,
242+ Shards : runtime .GOMAXPROCS (0 ),
243+ PredictionResistance : false ,
244+ ForkDetectionInterval : 0 ,
220245 }
221246}
222247
@@ -236,65 +261,41 @@ type Option func(*Config)
236261//
237262// Acceptable values are KeySize128 (16 bytes), KeySize192 (24 bytes), or KeySize256 (32 bytes).
238263// Any other value will cause NewReader to fail with an error at construction time.
239- //
240- // Example usage:
241- //
242- // r, err := ctrdrbg.NewReader(ctrdrbg.WithKeySize(ctrdrbg.KeySize192))
243264func WithKeySize (k KeySize ) Option { return func (cfg * Config ) { cfg .KeySize = k } }
244265
245266// WithMaxBytesPerKey returns an Option that sets the maximum number of bytes output per key before rekeying.
246267//
247268// This enforces a forward secrecy window: after MaxBytesPerKey random bytes are generated,
248269// the DRBG automatically performs a rekey operation (if key rotation is enabled) to derive a new key
249270// from fresh entropy. Lower this value to increase key rotation frequency for higher assurance.
250- //
251- // Example:
252- //
253- // r, err := ctrdrbg.NewReader(ctrdrbg.WithMaxBytesPerKey(1<<20)) // 1 MiB per key
254271func WithMaxBytesPerKey (n uint64 ) Option { return func (cfg * Config ) { cfg .MaxBytesPerKey = n } }
255272
256273// WithMaxInitRetries returns an Option that sets the maximum number of attempts to initialize a DRBG instance
257274// in the pool before failing.
258275//
259276// Increase this value if your system occasionally fails to gather entropy or encounters transient cryptographic errors
260277// at startup.
261- //
262- // Example:
263- //
264- // r, err := ctrdrbg.NewReader(ctrdrbg.WithMaxInitRetries(10))
265278func WithMaxInitRetries (n int ) Option { return func (cfg * Config ) { cfg .MaxInitRetries = n } }
266279
267280// WithMaxRekeyAttempts returns an Option that sets the maximum number of attempts allowed for
268281// asynchronous key rotation (rekey) in the DRBG.
269282//
270283// If all rekey attempts fail, the DRBG continues using the previous state. Exponential backoff is applied
271284// between attempts (see WithMaxRekeyBackoff and WithRekeyBackoff).
272- //
273- // Example:
274- //
275- // r, err := ctrdrbg.NewReader(ctrdrbg.WithMaxRekeyAttempts(7))
276285func WithMaxRekeyAttempts (n int ) Option { return func (cfg * Config ) { cfg .MaxRekeyAttempts = n } }
277286
278287// WithMaxRekeyBackoff returns an Option that sets the maximum duration for exponential backoff between
279288// failed rekey attempts.
280289//
281290// When a rekey attempt fails, the DRBG waits with exponentially increasing intervals, up to this maximum duration,
282291// before retrying. If set to zero, a default (2s) is used.
283- //
284- // Example:
285- //
286- // r, err := ctrdrbg.NewReader(ctrdrbg.WithMaxRekeyBackoff(5 * time.Second))
287292func WithMaxRekeyBackoff (d time.Duration ) Option {
288293 return func (cfg * Config ) { cfg .MaxRekeyBackoff = d }
289294}
290295
291296// WithRekeyBackoff returns an Option that sets the initial backoff duration before retrying a failed rekey operation.
292297//
293298// The first failure sleeps this duration, doubling for each subsequent failure, up to MaxRekeyBackoff.
294- //
295- // Example:
296- //
297- // r, err := ctrdrbg.NewReader(ctrdrbg.WithRekeyBackoff(250 * time.Millisecond))
298299func WithRekeyBackoff (d time.Duration ) Option {
299300 return func (cfg * Config ) { cfg .RekeyBackoff = d }
300301}
@@ -306,10 +307,6 @@ func WithRekeyBackoff(d time.Duration) Option {
306307//
307308// For most use cases, leave this enabled for forward secrecy and NIST alignment. Disable only for
308309// compliance testing or special-purpose scenarios.
309- //
310- // Example:
311- //
312- // r, err := ctrdrbg.NewReader(ctrdrbg.WithEnableKeyRotation(true))
313310func WithEnableKeyRotation (enable bool ) Option {
314311 return func (cfg * Config ) { cfg .EnableKeyRotation = enable }
315312}
@@ -321,10 +318,6 @@ func WithEnableKeyRotation(enable bool) Option {
321318// personalization values produce independent random streams, even if instantiated simultaneously.
322319//
323320// Use for tenant, application, service, or hardware isolation as required by your security model.
324- //
325- // Example:
326- //
327- // r, err := ctrdrbg.NewReader(ctrdrbg.WithPersonalization([]byte("my-tenant")))
328321func WithPersonalization (p []byte ) Option {
329322 return func (cfg * Config ) { cfg .Personalization = p }
330323}
@@ -336,10 +329,6 @@ func WithPersonalization(p []byte) Option {
336329// for CTR-mode output. If disabled (false), output is written directly to the destination buffer.
337330//
338331// This option primarily affects performance tuning; it does not impact cryptographic security.
339- //
340- // Example:
341- //
342- // r, err := ctrdrbg.NewReader(ctrdrbg.WithUseZeroBuffer(true))
343332func WithUseZeroBuffer (enable bool ) Option {
344333 return func (cfg * Config ) { cfg .UseZeroBuffer = enable }
345334}
@@ -348,10 +337,6 @@ func WithUseZeroBuffer(enable bool) Option {
348337// used for output if UseZeroBuffer is enabled.
349338//
350339// This can reduce allocations when large or repeated output requests are expected.
351- //
352- // Example:
353- //
354- // r, err := ctrdrbg.NewReader(ctrdrbg.WithDefaultBufferSize(4096))
355340func WithDefaultBufferSize (n int ) Option {
356341 return func (cfg * Config ) { cfg .DefaultBufferSize = n }
357342}
@@ -360,10 +345,6 @@ func WithDefaultBufferSize(n int) Option {
360345//
361346// Sharding improves parallelism and reduces contention under high concurrency, at the cost of increased memory use.
362347// If n <= 0, the shard count defaults to runtime.GOMAXPROCS(0).
363- //
364- // Example:
365- //
366- // r, err := ctrdrbg.NewReader(ctrdrbg.WithShards(8))
367348func WithShards (n int ) Option {
368349 return func (cfg * Config ) {
369350 if n <= 0 {
@@ -380,10 +361,6 @@ func WithShards(n int) Option {
380361//
381362// This mode increases system entropy usage and can impact performance in high-throughput scenarios.
382363// Use only when required by compliance or application policy.
383- //
384- // Example:
385- //
386- // r, err := ctrdrbg.NewReader(ctrdrbg.WithPredictionResistance(true))
387364func WithPredictionResistance (enable bool ) Option {
388365 return func (cfg * Config ) { cfg .PredictionResistance = enable }
389366}
@@ -392,10 +369,6 @@ func WithPredictionResistance(enable bool) Option {
392369//
393370// When set to a non-zero value, the DRBG will reseed after this interval elapses, even if no key rotation
394371// or manual reseed occurs. Set to zero to disable interval-based reseeding.
395- //
396- // Example:
397- //
398- // r, err := ctrdrbg.NewReader(ctrdrbg.WithReseedInterval(30 * time.Minute))
399372func WithReseedInterval (d time.Duration ) Option {
400373 return func (cfg * Config ) { cfg .ReseedInterval = d }
401374}
@@ -404,10 +377,14 @@ func WithReseedInterval(d time.Duration) Option {
404377// allowed before forcing an automatic reseed from system entropy.
405378//
406379// Set to zero to disable reseed-on-request-count behavior.
407- //
408- // Example:
409- //
410- // r, err := ctrdrbg.NewReader(ctrdrbg.WithReseedRequests(1000))
411380func WithReseedRequests (n uint64 ) Option {
412381 return func (cfg * Config ) { cfg .ReseedRequests = n }
413382}
383+
384+ // WithForkDetectionInterval sets the number of output requests between fork detection checks.
385+ //
386+ // WARNING: Setting this above zero introduces a window where a fork may not be detected immediately.
387+ // Only set for performance-tuned applications that do NOT require strict compliance!
388+ func WithForkDetectionInterval (n uint64 ) Option {
389+ return func (cfg * Config ) { cfg .ForkDetectionInterval = n }
390+ }
0 commit comments