Packages
hackney
3.0.2
4.7.2
4.7.1
4.7.0
4.6.1
4.6.0
4.5.2
4.5.1
4.5.0
4.4.5
4.4.3
4.4.2
4.4.1
4.4.0
4.3.0
4.2.3
4.2.2
4.2.1
4.2.0
4.1.0
4.0.3
4.0.2
4.0.1
4.0.0
3.2.1
3.2.0
3.1.2
3.1.1
3.1.0
3.0.3
3.0.2
3.0.1
3.0.0
retired
2.0.1
2.0.0
2.0.0-beta.1
1.25.0
1.24.1
1.24.0
1.23.0
1.22.0
1.21.0
1.20.1
1.20.0
1.19.1
1.19.0
1.18.2
1.18.1
1.18.0
1.17.4
1.17.3
1.17.2
1.17.1
1.17.0
1.16.0
1.15.2
1.15.1
1.15.0
1.14.3
1.14.2
1.14.0
1.13.0
1.12.1
1.12.0
1.11.0
1.10.1
1.10.0
1.9.0
1.8.6
1.8.5
1.8.4
1.8.3
1.8.2
1.8.0
1.7.1
1.7.0
1.6.6
retired
1.6.5
1.6.4
retired
1.6.3
1.6.2
1.6.1
1.6.0
1.5.7
1.5.6
1.5.5
1.5.4
1.5.3
1.5.2
1.5.1
1.5.0
1.4.10
1.4.8
1.4.7
1.4.6
1.4.5
1.4.4
1.4.3
1.4.2
1.4.1
1.4.0
1.3.2
1.3.1
1.3.0
1.2.0
1.1.0
1.0.6
1.0.5
1.0.2
1.0.1
0.15.2
0.15.0
0.14.3
0.14.2
0.14.1
0.14.0
0.13.1
Simple HTTP client with HTTP/1.1, HTTP/2, and HTTP/3 support
Security advisory:
This version has known vulnerabilities.
View advisories
Current section
Files
Jump to
Current section
Files
c_src/boringssl/crypto/fipsmodule/entropy/jitter.cc.inc
// Copyright 2025 The BoringSSL Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// BoringCrypto Jitter Entropy version 20250725.
#include <openssl/base.h>
#if defined(OPENSSL_LINUX) || defined(OPENSSL_MACOS)
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include <array>
#include <type_traits>
#include <utility>
#include <openssl/mem.h>
#include "internal.h"
#include "sha512.cc.inc"
#if defined(__x86_64__)
#include <x86intrin.h>
#endif
BSSL_NAMESPACE_BEGIN
namespace entropy {
namespace {
#if defined(__x86_64__)
static inline uint64_t GetTimestamp() { return _rdtsc(); }
#elif defined(__aarch64__)
static inline uint64_t GetTimestamp() {
// Ideally this would use __arm_rsr64 from <arm_acle.h>. Clang has supported
// it Clang 3.7 (2016), but GCC did not add it until GCC 14.1.0 (2024). See
// https://crbug.com/440670941. When our minimum GCC is past that point,
// switch this back to __arm_rsr64.
uint64_t ret;
__asm__ volatile("mrs %0, cntvct_el0" : "=r"(ret));
return ret;
}
#else
static inline uint64_t GetTimestamp() {
struct timespec ts;
clock_gettime(CLOCK_MONOTONIC_RAW, &ts);
return ts.tv_sec * 1000000000ULL + ts.tv_nsec;
}
#endif
class MemoryOffsetLCG {
public:
MemoryOffsetLCG() : state(GetTimestamp() & 0xFFFFFFFF) {}
uint32_t Next() {
state = state * 1664525 + 1013904223;
return state;
}
private:
uint32_t state;
};
class MemoryAccessSampler {
public:
MemoryAccessSampler(size_t array_size, unsigned num_samples)
: array_size_(array_size),
num_samples_(num_samples),
array_(reinterpret_cast<uint8_t *>(OPENSSL_malloc(array_size_))) {
if (array_ == nullptr || //
array_size_ == 0 || //
array_size_ > (1u << 26) || //
array_size_ & (array_size_ - 1)) {
abort();
}
}
~MemoryAccessSampler() { OPENSSL_free(const_cast<uint8_t *>(array_)); }
MemoryAccessSampler(const MemoryAccessSampler &) = delete;
MemoryAccessSampler &operator=(const MemoryAccessSampler &) = delete;
MemoryAccessSampler(MemoryAccessSampler &&other)
: array_size_(other.array_size_),
num_samples_(other.num_samples_),
lcg_(other.lcg_),
array_(other.array_) {
other.array_ = nullptr;
}
bool Next(uint64_t *out) {
// Perform some memory accesses and measure how long it took. The LCG is
// intended to defeat any CPU predictors and thus expose this code to as
// much system entropy as possible.
for (unsigned i = 0; i < num_samples_; i++) {
// The lower bits of an LCG tend to fall into short cycles and so are
// discarded here.
array_[(lcg_.Next() >> 6) & (array_size_ - 1)] += 1;
}
*out = GetTimestamp();
return true;
}
private:
const size_t array_size_;
const unsigned num_samples_;
MemoryOffsetLCG lcg_;
volatile uint8_t *array_;
};
template <typename T>
class DeltaSampler {
public:
explicit DeltaSampler(T &&sub_sampler)
: sub_sampler_(std::forward<T>(sub_sampler)) {}
// Next function to return the delta between two subsequent samples
bool Next(uint64_t *out) {
uint64_t sample;
if (!sub_sampler_.Next(&sample)) {
return false;
}
if (!initialized_) {
last_sample_ = sample;
if (!sub_sampler_.Next(&sample)) {
return false;
}
initialized_ = true;
}
*out = sample - last_sample_;
last_sample_ = sample;
return true;
}
private:
bool initialized_ = false;
T sub_sampler_;
uint64_t last_sample_ = 0;
};
template <typename U>
DeltaSampler(U &&sub_sampler) -> DeltaSampler<std::decay_t<U>>;
template <typename T>
class MaskSampler {
public:
explicit MaskSampler(uint8_t mask, T &&sub_sampler)
: mask_(mask), sub_sampler_(std::forward<T>(sub_sampler)) {}
bool Next(uint8_t *out) {
uint64_t sample;
if (!sub_sampler_.Next(&sample)) {
return false;
}
*out = sample & mask_;
return true;
}
private:
const uint8_t mask_;
T sub_sampler_;
};
template <typename U>
MaskSampler(uint8_t mask, U &&sub_sampler) -> MaskSampler<std::decay_t<U>>;
// The estimated entropy per sample from MaskSampler.
constexpr float kH = 0.8;
// kAlphaLog2 is log_2(alpha), where alpha is the standard false-positive
// probability from SP 800-90B.
static constexpr float kAlphaLog2 = -20;
// kAlpha is the variable of the same name from section 4.4.1 of SP 800-90B.
constexpr float kAlpha = 1.0 / (1 << static_cast<unsigned>(-kAlphaLog2));
// Ceil rounds up its non-negative argument to the next integer. (std::ceil
// isn't constexpr until C++23.)
constexpr unsigned Ceil(float val) {
auto truncated = static_cast<unsigned>(val);
if (val == static_cast<float>(truncated)) {
return truncated;
}
if (val > 0) {
return truncated + 1;
}
__builtin_unreachable();
}
template <typename T>
class RepetitionCountTest {
public:
static constexpr unsigned kThreshold = 1 + Ceil(-kAlphaLog2 / kH);
static_assert(kThreshold == 26);
explicit RepetitionCountTest(T &&sub_sampler)
: sub_sampler_(std::forward<T>(sub_sampler)) {}
bool Next(uint8_t *out) {
uint8_t sample;
if (!sub_sampler_.Next(&sample)) {
return false;
}
if (sample == last_sample_) {
count_++;
} else {
count_ = 1;
last_sample_ = sample;
}
if (count_ >= kThreshold) {
return false;
}
*out = sample;
return true;
}
private:
T sub_sampler_;
unsigned count_ = 0;
uint8_t last_sample_ = 0;
};
template <typename U>
RepetitionCountTest(U &&sub_sampler) -> RepetitionCountTest<std::decay_t<U>>;
constexpr double BinomialPMF(int64_t k, int64_t n, double p) {
if (k < 0 || k > n) {
return 0.0;
}
double result = 1.0;
for (int64_t i = 0; i < k; ++i) {
result *= (n - i);
result /= (i + 1);
}
for (int64_t i = 0; i < k; ++i) {
result *= p;
}
for (int64_t i = 0; i < n - k; ++i) {
result *= (1 - p);
}
return result;
}
// CritBinom implements the Excel function of the same name.
constexpr unsigned CritBinom(unsigned trials, double probability_s,
double alpha) {
if (probability_s < 0.0 || probability_s > 1.0 || alpha < 0.0 ||
alpha > 1.0) {
__builtin_unreachable();
}
double cumulative = 0.0;
for (unsigned k = 0; k <= trials; ++k) {
cumulative += BinomialPMF(k, trials, probability_s);
if (cumulative >= alpha) {
return k;
}
}
return trials;
}
// ExpTaylor calculates e^x using the Taylor series: e^x = 1 + x + x²/2! +
// x³/3! + ...
constexpr double ExpTaylor(double x) {
double sum = 1.0;
double term = 1.0;
for (int i = 1; i < 25; ++i) {
term *= x / i;
sum += term;
}
return sum;
}
// Power2 calculates 2^exp by calculating e^(ln(2) * exp) = e^(ln(2)) ^ exp =
// 2^exp. (std::pow isn't constexpr until C++26.)
constexpr double Power2(double exp) {
constexpr double ln2 = 0.693147180559945309417232121458;
return ExpTaylor(exp * ln2);
}
// AdaptiveProportionTestCutoff implements the function from the footnote on
// page 27 of SP 800-90B.
constexpr unsigned AdaptiveProportionTestCutoff(unsigned W, float H,
float alpha) {
return 1 + CritBinom(W, Power2(-H), 1.0 - alpha);
}
// These are the example values from table 2 of SP 800-90B, to show that
// we're calculating the values correctly.
static_assert(AdaptiveProportionTestCutoff(512, 0.5, kAlpha) == 410);
static_assert(AdaptiveProportionTestCutoff(512, 1, kAlpha) == 311);
static_assert(AdaptiveProportionTestCutoff(512, 2, kAlpha) == 177);
static_assert(AdaptiveProportionTestCutoff(512, 4, kAlpha) == 62);
static_assert(AdaptiveProportionTestCutoff(512, 8, kAlpha) == 13);
template <typename T>
class AdaptiveProportionTest {
public:
// The size of the sliding window, representing the number of recent samples
// to analyze.
static constexpr unsigned kWindowSize = 512;
// The maximum number of times any single byte value is allowed to appear
// within the sliding window.
static constexpr unsigned kThreshold =
AdaptiveProportionTestCutoff(kWindowSize, kH, kAlpha);
static_assert(kThreshold == 348);
explicit AdaptiveProportionTest(T &&sub_sampler)
: sub_sampler_(std::forward<T>(sub_sampler)) {
counts_.fill(0);
}
bool Next(uint8_t *out) {
uint8_t sample;
if (!sub_sampler_.Next(&sample)) {
return false;
}
*out = sample;
if (samples_processed_ >= kWindowSize) {
const uint8_t evicted_sample = buffer_[buffer_idx_];
counts_[evicted_sample]--;
}
buffer_[buffer_idx_] = sample;
const uint16_t new_count = ++counts_[sample];
if (new_count > kThreshold) {
return false;
}
buffer_idx_ = (buffer_idx_ + 1) % kWindowSize;
samples_processed_++;
return true;
}
private:
T sub_sampler_;
// A circular buffer to store the most recent `kWindowSize` samples.
std::array<uint8_t, kWindowSize> buffer_{};
// An array to store the frequency counts of each possible byte value (0-255)
// within the current window.
std::array<uint16_t, 256> counts_{};
// The current index for writing into the circular buffer.
size_t buffer_idx_ = 0;
// The total number of samples processed. Used to determine when the buffer
// is full and eviction should begin.
size_t samples_processed_ = 0;
};
template <typename U>
AdaptiveProportionTest(U &&sub_sampler)
-> AdaptiveProportionTest<std::decay_t<U>>;
template <typename T>
class SeedSampler {
public:
// NIST requires 1024 samples at start-up time. This code is structured so
// that the entropy generator is considered to be starting afresh for each
// seed.
static constexpr unsigned kNumSamples = 1024;
explicit SeedSampler(T &&sub_sampler)
: sub_sampler_(std::forward<T>(sub_sampler)) {}
bool Next(uint8_t out_seed[48]) {
// HMAC-SHA384 `kNumSamples` samples with an all-zero key:
SHA512_CTX ctx;
SHA384_Init(&ctx);
uint8_t block[kSHA384Block];
memset(block, 0x36, sizeof(block));
SHA384_Update(&ctx, block, sizeof(block));
static_assert(kNumSamples % sizeof(block) == 0);
for (unsigned i = 0; i < kNumSamples / sizeof(block); i++) {
for (unsigned j = 0; j < sizeof(block); j++) {
if (!sub_sampler_.Next(&block[j])) {
return false;
}
}
SHA384_Update(&ctx, block, sizeof(block));
}
SHA384_Final(out_seed, &ctx);
SHA384_Init(&ctx);
memset(block, 0x5c, sizeof(block));
SHA384_Update(&ctx, block, sizeof(block));
SHA384_Update(&ctx, out_seed, kSHA384DigestLength);
SHA384_Final(out_seed, &ctx);
return true;
}
private:
T sub_sampler_;
};
template <typename U>
SeedSampler(U &&sub_sampler) -> SeedSampler<std::decay_t<U>>;
constexpr size_t kMemorySize = 1u << 25;
constexpr size_t kMemoryAccessesPerSample = 16;
constexpr size_t kBitsPerSample = 8;
constexpr uint8_t kMask = (1u << kBitsPerSample) - 1;
} // namespace
int GetVersion() { return 20250725; }
bool GetSeed(uint8_t out[48]) {
auto sampler(SeedSampler(AdaptiveProportionTest(RepetitionCountTest(
MaskSampler(kMask, DeltaSampler(MemoryAccessSampler(
kMemorySize, kMemoryAccessesPerSample)))))));
return sampler.Next(out);
}
bool GetSamples(uint64_t *out, size_t n) {
auto sampler(
DeltaSampler(MemoryAccessSampler(kMemorySize, kMemoryAccessesPerSample)));
for (size_t i = 0; i < n; i++) {
if (!sampler.Next(&out[i])) {
return false;
}
}
return true;
}
} // namespace entropy
BSSL_NAMESPACE_END
#endif // LINUX || MACOS