Skip to content

Commit

Permalink
Optimize random string generation (#403)
Browse files Browse the repository at this point in the history
  • Loading branch information
anuraaga authored Sep 6, 2022
1 parent 0e151c9 commit b1d1bb4
Show file tree
Hide file tree
Showing 5 changed files with 28 additions and 23 deletions.
44 changes: 24 additions & 20 deletions internal/strings/strings.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,36 +4,40 @@
package strings

import (
"crypto/rand"
"math/rand"
"strings"
"sync"
"time"
)

const letterBytes = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
const (
randomBytes = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
letterIdxBits = 6 // 6 bits to represent a letter index
letterIdxMask = 1<<letterIdxBits - 1 // All 1-bits, as many as letterIdxBits
letterIdxMax = 63 / letterIdxBits // # of letter indices fitting in 63 bits
)

var mu sync.Mutex
var src = rand.NewSource(time.Now().UnixNano())

// SafeRandom returns a random string of length n
// RandomString returns a random string of length n
// It is safe to use this function in concurrent environments
// If it fails, it will try again, it should fail more than once
func SafeRandom(length int) string {
bytes := make([]byte, length)
// There is an entropy bug here with a lot of concurrency, so we need sync

mu.Lock()
_, err := rand.Read(bytes)
mu.Unlock()
if err != nil {
// TODO is it ok?
return SafeRandom(length)
// Implementation from https://stackoverflow.com/a/31832326
func RandomString(n int) string {
sb := strings.Builder{}
sb.Grow(n)
// A src.Int63() generates 63 random bits, enough for letterIdxMax characters!
for i, cache, remain := n-1, src.Int63(), letterIdxMax; i >= 0; {
if remain == 0 {
cache, remain = src.Int63(), letterIdxMax
}
if idx := int(cache & letterIdxMask); idx < len(letterBytes) {
sb.WriteByte(letterBytes[idx])
i--
}
cache >>= letterIdxBits
remain--
}

for i, b := range bytes {
bytes[i] = randomBytes[b%byte(len(randomBytes))]
}
return string(bytes)
return sb.String()
}

// ValidHex returns true if the byte is a valid hex character
Expand Down
2 changes: 1 addition & 1 deletion loggers/formats.go
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ func legacyJSONFormatter(al *AuditLog) ([]byte, error) {
}

func nativeFormatter(al *AuditLog) ([]byte, error) {
boundary := utils.SafeRandom(10)
boundary := utils.RandomString(10)
parts := map[byte]string{}
// [27/Jul/2016:05:46:16 +0200] V5guiH8AAQEAADTeJ2wAAAAK 192.168.3.1 50084 192.168.3.111 80
parts['A'] = fmt.Sprintf("[%s] %s %s %d %s %d", al.Transaction.Timestamp, al.Transaction.ID,
Expand Down
2 changes: 1 addition & 1 deletion seclang/directives_log_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ func TestSecAuditLogDirectivesConcurrent(t *testing.T) {
`, filepath.Join(auditpath, "audit.log"), auditpath)); err != nil {
t.Error(err)
}
id := utils.SafeRandom(10)
id := utils.RandomString(10)
if waf.AuditLogWriter == nil {
t.Error("Invalid audit logger (nil)")
return
Expand Down
1 change: 1 addition & 0 deletions testing/coreruleset_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ func BenchmarkCRSSimplePOST(b *testing.B) {
if err != nil {
b.Error(err)
}
b.ResetTimer() // only benchmark execution, not compilation
for i := 0; i < b.N; i++ {
tx := waf.NewTransaction(context.Background())
tx.ProcessConnection("127.0.0.1", 8080, "127.0.0.1", 8080)
Expand Down
2 changes: 1 addition & 1 deletion waf.go
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@ type WAF struct {
// NewTransaction Creates a new initialized transaction for this WAF instance
func (w *WAF) NewTransaction(ctx context.Context) *Transaction {
tx := transactionPool.Get().(*Transaction)
tx.ID = utils.SafeRandom(19)
tx.ID = utils.RandomString(19)
tx.MatchedRules = []types.MatchedRule{}
tx.Interruption = nil
tx.Collections = [types.VariablesCount]collection.Collection{}
Expand Down

0 comments on commit b1d1bb4

Please sign in to comment.