Skip to content

Commit

Permalink
gh-683: secure_random() implementation
Browse files Browse the repository at this point in the history
Co-authored-by: lovvik <loicamagli@outlook.fr>
  • Loading branch information
2 people authored and gavv committed Feb 11, 2025
1 parent 03d5a22 commit 4fe2363
Show file tree
Hide file tree
Showing 17 changed files with 341 additions and 59 deletions.
5 changes: 3 additions & 2 deletions 3rdparty/SConscript
Original file line number Diff line number Diff line change
Expand Up @@ -222,9 +222,10 @@ elif 'openssl' in system_dependencies:
conf = Configure(env, custom_tests=env.CustomTests)

if not conf.AddPkgConfigDependency('libssl', '--cflags --libs', add_prefix=ossl_prefix):
conf.env.AddManualDependency(libs=['ssl'], prefix=ossl_prefix)
conf.env.AddManualDependency(libs=['ssl', 'crypto'], prefix=ossl_prefix)

if not conf.CheckLibWithHeaderExt('ssl', 'openssl/rand.h', 'C', run=not is_crosscompiling):
if not conf.CheckLibWithHeaderExt('ssl', 'openssl/rand.h', 'C', run=not is_crosscompiling) or \
not conf.CheckLibWithHeaderExt('crypto', 'openssl/crypto.h', 'C', run=not is_crosscompiling):
env.Die("OpenSSL not found (see 'config.log' for details)")

env = conf.Finish()
Expand Down
67 changes: 37 additions & 30 deletions shell.nix
Original file line number Diff line number Diff line change
@@ -1,34 +1,41 @@
{ pkgs ? import <nixpkgs> {} }:

pkgs.mkShell {
buildInputs = [
# build deps
pkgs.autoconf
pkgs.automake
pkgs.clang
pkgs.cmake
pkgs.gcc
pkgs.gengetopt
pkgs.gnumake
pkgs.intltool
pkgs.libtool
pkgs.meson
pkgs.pkg-config
pkgs.ragel
pkgs.scons
pkgs.clangStdenv.mkDerivation {
name = "clang-shell";

# other deps
pkgs.libpulseaudio
pkgs.libsndfile
pkgs.libunwind
pkgs.libuv
pkgs.openssl
pkgs.sox
pkgs.speexdsp
nativeBuildInputs = [
pkgs.clang-tools
# A properly wrapped clangd is already made available by the clang-tools derivation.
# clang-tools has to come before clang to set precedence in PATH for clangd.
pkgs.clang

# optional deps: formatting, tests, ...
pkgs.clang-tools
pkgs.cpputest
pkgs.gbenchmark
];
}
# build deps
pkgs.autoconf
pkgs.automake
pkgs.cmake
pkgs.gengetopt
pkgs.gnumake
pkgs.intltool
pkgs.libtool
pkgs.meson
pkgs.pkg-config
pkgs.ragel
pkgs.scons
];

buildInputs = [
# other deps
pkgs.libpulseaudio
pkgs.libsndfile
pkgs.libunwind
pkgs.libuuid
pkgs.libuv
pkgs.openssl
pkgs.sox
pkgs.speexdsp

# optional deps: formatting, tests, ...
pkgs.cpputest
pkgs.gbenchmark
];
}
48 changes: 48 additions & 0 deletions src/internal_modules/roc_core/secure_random.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
/*
* Copyright (c) 2025 Roc Streaming authors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/

//! @file roc_core/secure_random.h
//! @brief Helpers to generate cryptographically secure random numbers.

#ifndef ROC_CORE_SECURE_RANDOM_H_
#define ROC_CORE_SECURE_RANDOM_H_

#include "roc_core/attributes.h"
#include "roc_core/stddefs.h"

//! @warning On some platforms CSPRNG is not available. In this case a non-secure version
//! may be used instead (e.g. @p fast_random*()).

namespace roc {
namespace core {

//! Fill buffer @p buf with @p bufsz random bites.
//! Thread-safe. Uniformly distributed.
//!
//! @returns @p true in case of success, @p false in case of failure.
ROC_NODISCARD
bool secure_random(void* buf, size_t bufsz);

//! Get random 32-bit integer in range [@p from; @p to] and put it to @p dest.
//! Thread-safe. Uniformly distributed.
//!
//! @returns @p true in case of success, @p false in case of failure.
ROC_NODISCARD
bool secure_random_range_32(uint32_t from, uint32_t to, uint32_t& dest);

//! Get random 64-bit integer in range [@p from; @p to] and put it to @p dest.
//! Thread-safe. Uniformly distributed.
//!
//! @returns @p true in case of success, @p false in case of failure.
ROC_NODISCARD
bool secure_random_range_64(uint64_t from, uint64_t to, uint64_t& dest);

} // namespace core
} // namespace roc

#endif // ROC_CORE_SECURE_RANDOM_H_
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
/*
* Copyright (c) 2025 Roc Streaming authors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/

#include "roc_core/secure_random.h"
#include "roc_core/fast_random.h"

namespace roc {
namespace core {

bool secure_random(void* buf, size_t bufsz) {
unsigned char* ubuf = (unsigned char*)buf;

size_t i = 0;
while (i < bufsz) {
union {
uint32_t number;
unsigned char bytes[4];
} rand;
rand.number = fast_random_32();

// clang-format off
ubuf[i] = rand.bytes[0]; i++; if (i >= bufsz) { break; }
ubuf[i] = rand.bytes[1]; i++; if (i >= bufsz) { break; }
ubuf[i] = rand.bytes[2]; i++; if (i >= bufsz) { break; }
ubuf[i] = rand.bytes[3]; i++;
// clang-format on
}
return true;
}

bool secure_random_range_32(uint32_t from, uint32_t to, uint32_t& dest) {
dest = (uint32_t)fast_random_range(from, to);
return true;
}

bool secure_random_range_64(uint64_t from, uint64_t to, uint64_t& dest) {
dest = fast_random_range(from, to);
return true;
}

} // namespace core
} // namespace roc
7 changes: 4 additions & 3 deletions src/internal_modules/roc_core/target_nouuid/roc_core/uuid.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@
*/

#include "roc_core/uuid.h"
#include "roc_core/fast_random.h"
#include "roc_core/macro_helpers.h"
#include "roc_core/panic.h"
#include "roc_core/secure_random.h"
#include "roc_core/stddefs.h"

namespace roc {
Expand All @@ -35,8 +35,9 @@ bool uuid_generate(char* buf, size_t buf_sz) {
}

uint8_t bytes[16];
for (size_t i = 0; i < ROC_ARRAY_SIZE(bytes); i++) {
bytes[i] = (uint8_t)fast_random_range(0, 255);
bool ok = core::secure_random(bytes, ROC_ARRAY_SIZE(bytes));
if (!ok) {
return false;
}

// Set variant to OSF DCE UUID.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
/*
* Copyright (c) 2025 Roc Streaming authors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/

#include "roc_core/secure_random.h"
#include "roc_core/log.h"
#include "roc_core/macro_helpers.h"

#include <openssl/err.h>
#include <openssl/rand.h>

namespace roc {
namespace core {

bool secure_random(void* buf, size_t bufsz) {
// RAND_priv_bytes() is not needed right now as we do not use these random numbers
// privately. See also https://docs.openssl.org/3.0/man7/RAND/

int ok = RAND_bytes((unsigned char*)buf, (int)bufsz);

if (ok != 1) {
unsigned long err;
char err_str[256]; // minimum buf length is 256
memset(err_str, 0, ROC_ARRAY_SIZE(err_str));
while ((err = ERR_get_error()) != 0) {
ERR_error_string_n(err, err_str, ROC_ARRAY_SIZE(err_str));
roc_log(LogError, "secure random: OpenSSL RAND_bytes() failed: %s", err_str);
}
return false;
}
return true;
}

bool secure_random_range_32(uint32_t from, uint32_t to, uint32_t& dest) {
// validation `to >= from` exists in the 64-bit version called below

if (from == 0 && to == UINT32_MAX) {
return secure_random(&dest, sizeof(dest));
}

uint64_t rand64;
bool ok = secure_random_range_64(from, to, rand64);
if (!ok) {
return false;
}
dest = (uint32_t)rand64;
return true;
}

bool secure_random_range_64(uint64_t from, uint64_t to, uint64_t& dest) {
// same as fast_random_range() except it calls CSPRNG to get a uint64 value

roc_panic_if_msg(from > to, "secure random: invalid range: from=%llu to=%llu",
(unsigned long long)from, (unsigned long long)to);

// corner case check; needed to avoid a possible uint64_t overflow
if (from == 0 && to == UINT64_MAX) {
return secure_random(&dest, sizeof(dest));
}

const uint64_t range = to - from + 1;

// Generate a mask with 1's from bit 0 to the most significant bit in `range`.
// At each step, we double the count of leading 1's:
// 0001.......
// 00011......
// 0001111....
// Thanks to @rnovatorov for the hint.
uint64_t mask = range;
mask |= mask >> 1;
mask |= mask >> 2;
mask |= mask >> 4;
mask |= mask >> 8;
mask |= mask >> 16;
mask |= mask >> 32;

do {
bool ok = secure_random(&dest, sizeof(dest));
if (!ok) {
return false;
}
dest &= mask;
} while (dest >= range);

dest += from;

roc_panic_if_not(dest >= from);
roc_panic_if_not(dest <= to);

return true;
}

} // namespace core
} // namespace roc
17 changes: 12 additions & 5 deletions src/internal_modules/roc_fec/block_writer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,11 @@
*/

#include "roc_fec/block_writer.h"
#include "roc_core/fast_random.h"
#include "roc_core/log.h"
#include "roc_core/panic.h"
#include "roc_core/secure_random.h"
#include "roc_packet/fec_scheme.h"
#include "roc_status/code_to_str.h"
#include "roc_status/status_code.h"

namespace roc {
namespace fec {
Expand Down Expand Up @@ -46,9 +46,16 @@ BlockWriter::BlockWriter(const BlockWriterConfig& config,
return;
}

cur_sbn_ = (packet::blknum_t)core::fast_random_range(0, packet::blknum_t(-1));
cur_block_repair_sn_ =
(packet::seqnum_t)core::fast_random_range(0, packet::seqnum_t(-1));
bool ok = core::secure_random(&cur_sbn_, sizeof(cur_sbn_));
if (!ok) {
init_status_ = status::StatusErrRand;
return;
}
ok = core::secure_random(&cur_block_repair_sn_, sizeof(cur_block_repair_sn_));
if (!ok) {
init_status_ = status::StatusErrRand;
return;
}

if ((init_status_ = resize(config.n_source_packets, config.n_repair_packets))
!= status::StatusOK) {
Expand Down
1 change: 0 additions & 1 deletion src/internal_modules/roc_packet/interleaver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
#include "roc_packet/interleaver.h"
#include "roc_core/fast_random.h"
#include "roc_core/log.h"
#include "roc_status/code_to_str.h"

namespace roc {
namespace packet {
Expand Down
12 changes: 7 additions & 5 deletions src/internal_modules/roc_rtp/identity.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@
*/

#include "roc_rtp/identity.h"
#include "roc_core/fast_random.h"
#include "roc_core/log.h"
#include "roc_core/macro_helpers.h"
#include "roc_core/secure_random.h"
#include "roc_status/status_code.h"

namespace roc {
namespace rtp {
Expand Down Expand Up @@ -45,9 +45,11 @@ packet::stream_source_t Identity::ssrc() const {
}

status::StatusCode Identity::change_ssrc() {
ssrc_ =
(packet::stream_source_t)core::fast_random_range(1, packet::stream_source_t(-1));

bool ok = (packet::stream_source_t)core::secure_random_range_32(
1, packet::stream_source_t(-1), ssrc_);
if (!ok) {
return status::StatusErrRand;
}
roc_log(LogDebug, "rtp identity: ssrc=%lu cname=%s", (unsigned long)ssrc_, cname_);

return status::StatusOK;
Expand Down
6 changes: 2 additions & 4 deletions src/tests/roc_core/test_fast_random.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,11 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/

// see also test_secure_random.cpp

#include <CppUTest/TestHarness.h>

#include "roc_core/fast_random.h"
#include "roc_core/stddefs.h"

#include <CppUTest/TestHarness.h>

namespace roc {
namespace core {

Expand Down
Loading

0 comments on commit 4fe2363

Please sign in to comment.