diff --git a/src/puppetlabs/puppetdb/cli/generate.clj b/src/puppetlabs/puppetdb/cli/generate.clj index aad0fb99c..711da89c2 100644 --- a/src/puppetlabs/puppetdb/cli/generate.clj +++ b/src/puppetlabs/puppetdb/cli/generate.clj @@ -246,6 +246,8 @@ [java.nio.file Files] [org.apache.commons.lang3 RandomStringUtils])) +(declare random-ascii-string) + (def resource-fact-path "puppetlabs/puppetdb/generate/samples/facts/baseline-agent-node.json") (defmulti weigh "Loosely weigh up the bytes of a structure." class) @@ -335,7 +337,7 @@ (recur (assoc parameters (parameter-name (rnd/safe-sample-normal 20 5 {:lowerb 5})) - (.nextAscii (RandomStringUtils/secure) + (random-ascii-string (rnd/safe-sample-normal 50 25 {:upperb (max 50 size)})))) parameters)))) @@ -461,6 +463,29 @@ :target (select-keys target [:type :title]) :relationship relation}) +(defn- random-ascii-string + "Generate a random ASCII string of the given length. + + Chunks requests to stay within the BouncyCastle FIPS DRBG per-request limit + of 262144 bits (32768 bytes). Apache Commons Lang3's RandomStringUtils + allocates a CachedRandomBits with size = (count * gapBits + 3) / 5 + 10 + bytes. For nextAscii (ASCII range 32-127, gap=95, gapBits=7) the maximum + count that keeps the cache within 32768 bytes is: + (count * 7 + 3) / 5 + 10 <= 32768 => count <= 23398" + [length] + (let [fips-max-chunk 23398 + ^RandomStringUtils secure-random (RandomStringUtils/secure)] + (if (<= length fips-max-chunk) + (.nextAscii secure-random length) + ;; Build incrementally to avoid intermediate vectors/strings for large values. + (let [^StringBuilder builder (StringBuilder. length)] + (loop [remaining length] + (if (<= remaining 0) + (.toString builder) + (let [chunk-size (min remaining fips-max-chunk)] + (.append builder (.nextAscii secure-random chunk-size)) + (recur (- remaining chunk-size))))))))) + (defn add-blob "Add a large parameter string blob to one of the given catalog's resource parameters. @@ -480,7 +505,7 @@ bsize (rnd/safe-sample-normal avg-blob-size-in-bytes standard-deviation {:lowerb lowerb :upperb upperb}) pname (format "content_blob_%s" (rnd/random-pronouncable-word))] (update-in catalog [:resources (rand-int (count resources)) :parameters] - #(merge % {pname (.nextAscii (RandomStringUtils/secure) bsize)})))) + #(merge % {pname (random-ascii-string bsize)})))) (defn system-seconds-str "Epoch seconds as a string. Used by default as a version string in Puppet diff --git a/src/puppetlabs/puppetdb/random.clj b/src/puppetlabs/puppetdb/random.clj index 12ae07d81..a51788f81 100644 --- a/src/puppetlabs/puppetdb/random.clj +++ b/src/puppetlabs/puppetdb/random.clj @@ -10,17 +10,39 @@ (def ^{:doc "Convenience for java.util.Random"} random (java.util.Random.)) +(defn- alphabetic-string + "Generate a random alphabetic string of the given length. + + Chunks requests to stay within the BouncyCastle FIPS DRBG per-request limit + of 262144 bits. Apache Commons Lang3's CachedRandomBits allocates + (count * gapBits + 3) / 5 + 10 bytes per call. For nextAlphabetic + (A-Z + a-z = 52 chars, gapBits = ceil(log2(52)) = 6) the maximum count per call is: + (count * 6 + 3) / 5 + 10 <= 32768 => count <= 27298" + [length] + (let [fips-max-chunk 27298 + ^RandomStringUtils secure-random (RandomStringUtils/secure)] + (if (<= length fips-max-chunk) + (.nextAlphabetic secure-random length) + ;; Build incrementally to avoid intermediate vectors/strings for large values. + (let [^StringBuilder builder (StringBuilder. length)] + (loop [remaining length] + (if (<= remaining 0) + (.toString builder) + (let [chunk-size (min remaining fips-max-chunk)] + (.append builder (.nextAlphabetic secure-random chunk-size)) + (recur (- remaining chunk-size))))))))) + (defn random-string "Generate a random string of optional length" ([] (.nextAlphabetic (RandomStringUtils/secure) (inc (rand-int 10)))) ([length] - (.nextAlphabetic (RandomStringUtils/secure) length))) + (alphabetic-string length))) (defn random-string-alpha "Generate a random string of optional length, only lower case alphabet chars" ([] (random-string (inc (rand-int 10)))) ([length] - (.toLowerCase (.nextAlphabetic (RandomStringUtils/secure) length)))) + (.toLowerCase (alphabetic-string length)))) (defn random-bool "Generate a random boolean"