Skip to content

Commit 7397b9a

Browse files
Merge pull request #344 from jpartlow/fips-drbg-limits
Addutional FIPS DRBG (deterministic random bit generator) limit changes
2 parents c23b506 + 81265f1 commit 7397b9a

4 files changed

Lines changed: 58 additions & 46 deletions

File tree

src/puppetlabs/puppetdb/cli/benchmark.clj

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -153,8 +153,7 @@
153153
ScheduledThreadPoolExecutor
154154
Semaphore
155155
TimeUnit)
156-
(org.apache.commons.compress.archivers.tar TarArchiveEntry)
157-
(org.apache.commons.lang3 RandomStringUtils)))
156+
(org.apache.commons.compress.archivers.tar TarArchiveEntry)))
158157

159158
;; FIXME: make sure --queriers respects DISCARD_ALL_QUERIES
160159

@@ -311,9 +310,9 @@
311310
(defmethod touch-parameter-value String [p]
312311
(let [len (count p)]
313312
(if (zero? len)
314-
(.nextAscii (RandomStringUtils/secure) 1) ; empty -> single char
313+
(rnd/random-ascii-string 1) ; empty -> single char
315314
(loop [attempts 5]
316-
(let [new-val (.nextAscii (RandomStringUtils/secure) len)]
315+
(let [new-val (rnd/random-ascii-string len)]
317316
(if (or (not= new-val p) (zero? attempts))
318317
new-val
319318
(recur (dec attempts))))))))

src/puppetlabs/puppetdb/cli/generate.clj

Lines changed: 3 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -243,10 +243,7 @@
243243
[puppetlabs.puppetdb.utils :as utils])
244244
(:import
245245
[java.nio.file.attribute FileAttribute]
246-
[java.nio.file Files]
247-
[org.apache.commons.lang3 RandomStringUtils]))
248-
249-
(declare random-ascii-string)
246+
[java.nio.file Files]))
250247

251248
(def resource-fact-path "puppetlabs/puppetdb/generate/samples/facts/baseline-agent-node.json")
252249

@@ -337,7 +334,7 @@
337334
(recur (assoc parameters
338335
(parameter-name
339336
(rnd/safe-sample-normal 20 5 {:lowerb 5}))
340-
(random-ascii-string
337+
(rnd/random-ascii-string
341338
(rnd/safe-sample-normal 50 25 {:upperb (max 50 size)}))))
342339
parameters))))
343340

@@ -463,29 +460,6 @@
463460
:target (select-keys target [:type :title])
464461
:relationship relation})
465462

466-
(defn- random-ascii-string
467-
"Generate a random ASCII string of the given length.
468-
469-
Chunks requests to stay within the BouncyCastle FIPS DRBG per-request limit
470-
of 262144 bits (32768 bytes). Apache Commons Lang3's RandomStringUtils
471-
allocates a CachedRandomBits with size = (count * gapBits + 3) / 5 + 10
472-
bytes. For nextAscii (ASCII range 32-127, gap=95, gapBits=7) the maximum
473-
count that keeps the cache within 32768 bytes is:
474-
(count * 7 + 3) / 5 + 10 <= 32768 => count <= 23398"
475-
[length]
476-
(let [fips-max-chunk 23398
477-
^RandomStringUtils secure-random (RandomStringUtils/secure)]
478-
(if (<= length fips-max-chunk)
479-
(.nextAscii secure-random length)
480-
;; Build incrementally to avoid intermediate vectors/strings for large values.
481-
(let [^StringBuilder builder (StringBuilder. length)]
482-
(loop [remaining length]
483-
(if (<= remaining 0)
484-
(.toString builder)
485-
(let [chunk-size (min remaining fips-max-chunk)]
486-
(.append builder (.nextAscii secure-random chunk-size))
487-
(recur (- remaining chunk-size)))))))))
488-
489463
(defn add-blob
490464
"Add a large parameter string blob to one of the given catalog's resource parameters.
491465
@@ -505,7 +479,7 @@
505479
bsize (rnd/safe-sample-normal avg-blob-size-in-bytes standard-deviation {:lowerb lowerb :upperb upperb})
506480
pname (format "content_blob_%s" (rnd/random-pronouncable-word))]
507481
(update-in catalog [:resources (rand-int (count resources)) :parameters]
508-
#(merge % {pname (random-ascii-string bsize)}))))
482+
#(merge % {pname (rnd/random-ascii-string bsize)}))))
509483

510484
(defn system-seconds-str
511485
"Epoch seconds as a string. Used by default as a version string in Puppet

src/puppetlabs/puppetdb/random.clj

Lines changed: 28 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -10,37 +10,52 @@
1010
(def ^{:doc "Convenience for java.util.Random"}
1111
random (java.util.Random.))
1212

13-
(defn- alphabetic-string
14-
"Generate a random alphabetic string of the given length.
13+
(defn- chunked-random-string
14+
"Generate a random alphabetic or ascii string of the given length.
1515
1616
Chunks requests to stay within the BouncyCastle FIPS DRBG per-request limit
17-
of 262144 bits. Apache Commons Lang3's CachedRandomBits allocates
18-
(count * gapBits + 3) / 5 + 10 bytes per call. For nextAlphabetic
19-
(A-Z + a-z = 52 chars, gapBits = ceil(log2(52)) = 6) the maximum count per call is:
20-
(count * 6 + 3) / 5 + 10 <= 32768 => count <= 27298"
21-
[length]
22-
(let [fips-max-chunk 27298
23-
^RandomStringUtils secure-random (RandomStringUtils/secure)]
17+
of 262144 bits (32768 bytes). Apache Commons Lang3's RandomStringUtils
18+
allocates a CachedRandomBits with size = (count * gapBits + 3) / 5 + 10
19+
bytes.
20+
21+
For nextAscii (ASCII range 32-127, gap=95, gapBits=7)
22+
the maximum count that keeps the cache within 32768 bytes is:
23+
(count * 7 + 3) / 5 + 10 <= 32768 => count <= 23398
24+
25+
For nextAlphabetic (A-Z + a-z = 52 chars, gapBits = ceil(log2(52)) = 6)
26+
the maximum count per call is:
27+
(count * 6 + 3) / 5 + 10 <= 32768 => count <= 27298"
28+
[method length]
29+
(let [^RandomStringUtils secure-random (RandomStringUtils/secure)
30+
[gen-fn fips-max-chunk] (case method
31+
:ascii [#(.nextAscii ^RandomStringUtils secure-random %) 23398]
32+
:alphabetic [#(.nextAlphabetic ^RandomStringUtils secure-random %) 27298])]
2433
(if (<= length fips-max-chunk)
25-
(.nextAlphabetic secure-random length)
34+
(gen-fn length)
2635
;; Build incrementally to avoid intermediate vectors/strings for large values.
2736
(let [^StringBuilder builder (StringBuilder. length)]
2837
(loop [remaining length]
2938
(if (<= remaining 0)
3039
(.toString builder)
3140
(let [chunk-size (min remaining fips-max-chunk)]
32-
(.append builder (.nextAlphabetic secure-random chunk-size))
41+
(.append builder (gen-fn chunk-size))
3342
(recur (- remaining chunk-size)))))))))
3443

44+
(defn- alphabetic-string [length]
45+
(chunked-random-string :alphabetic length))
46+
47+
(defn random-ascii-string [length]
48+
(chunked-random-string :ascii length))
49+
3550
(defn random-string
3651
"Generate a random string of optional length"
37-
([] (.nextAlphabetic (RandomStringUtils/secure) (inc (rand-int 10))))
52+
([] (alphabetic-string (inc (rand-int 10))))
3853
([length]
3954
(alphabetic-string length)))
4055

4156
(defn random-string-alpha
4257
"Generate a random string of optional length, only lower case alphabet chars"
43-
([] (random-string (inc (rand-int 10))))
58+
([] (random-string-alpha (inc (rand-int 10))))
4459
([length]
4560
(.toLowerCase (alphabetic-string length))))
4661

test/puppetlabs/puppetdb/random_test.clj

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
[clojure.test :refer :all]
44
[puppetlabs.puppetdb.random
55
:refer [distribute
6+
random-ascii-string
67
random-bool
78
random-node-name
89
random-pp-path
@@ -16,24 +17,47 @@
1617

1718
(deftest test-random-string
1819
(testing "should return a string of specified length"
20+
(is (>= 10 (count (random-string))))
1921
(is (= 8 (count (random-string 8))))
2022
(is (= 30 (count (random-string 30))))
2123
(is (= 100 (count (random-string 100)))))
2224

25+
(testing "should only contain alphabetic characters"
26+
(is (re-matches #"\A[a-zA-Z]+\z" (random-string)))
27+
(is (re-matches #"\A[a-zA-Z]{100}\z" (random-string 100))))
28+
2329
(testing "should only accept a positive integer"
2430
(is (thrown? IllegalArgumentException (random-string -1)))
2531
(is (thrown? ClassCastException (random-string "asdf")))))
2632

2733
(deftest test-random-string-alpha
2834
(testing "should return a string of specified length"
35+
(is (>= 10 (count (random-string-alpha))))
2936
(is (= 8 (count (random-string-alpha 8))))
3037
(is (= 30 (count (random-string-alpha 30))))
3138
(is (= 100 (count (random-string-alpha 100)))))
3239

40+
(testing "should only contain lowercase alphabetic characters"
41+
(is (re-matches #"\A[a-z]+\z" (random-string-alpha)))
42+
(is (re-matches #"\A[a-z]{100}\z" (random-string-alpha 100))))
43+
3344
(testing "should only accept a positive integer"
3445
(is (thrown? IllegalArgumentException (random-string-alpha -1)))
3546
(is (thrown? ClassCastException (random-string-alpha "asdf")))))
3647

48+
(deftest test-random-ascii-string
49+
(testing "should return a string of specified length"
50+
(is (= 8 (count (random-ascii-string 8))))
51+
(is (= 30 (count (random-ascii-string 30))))
52+
(is (= 100 (count (random-ascii-string 100)))))
53+
54+
(testing "should only contain ascii characters"
55+
(is (re-matches #"\A[\x20-\x7E]{100}\z" (random-ascii-string 100))))
56+
57+
(testing "should only accept a positive integer"
58+
(is (thrown? IllegalArgumentException (random-ascii-string -1)))
59+
(is (thrown? ClassCastException (random-ascii-string "asdf")))))
60+
3761
(deftest test-random-bool
3862
(testing "should return a boolean"
3963
(is (boolean? (random-bool)))))

0 commit comments

Comments
 (0)