Skip to content

Commit

Permalink
Merge PR #2882: CryptographicRandom: new class for acquiring random d…
Browse files Browse the repository at this point in the history
…ata for cryptographic purposes.
  • Loading branch information
mkrautz committed Mar 1, 2017
2 parents cae5d6d + aa25435 commit a58d708
Show file tree
Hide file tree
Showing 11 changed files with 319 additions and 2 deletions.
13 changes: 13 additions & 0 deletions 3rdparty/arc4random-src/LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
Copyright (c) 2008, Damien Miller <djm@openbsd.org>

Permission to use, copy, modify, and distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.

THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
84 changes: 84 additions & 0 deletions 3rdparty/arc4random-src/arc4random_uniform.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
/* $OpenBSD: arc4random_uniform.c,v 1.2 2015/09/13 08:31:47 guenther Exp $ */

/*
* Copyright (c) 2008, Damien Miller <djm@openbsd.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/

// This is arc4random_uniform.c from OpenBSD's source tree at
// $OPENBSD_ROOT/lib/libc/crypt/arc4random_uniform.c.
//
// Mumble-specific changes:
//
// - Change file extension to .cpp and rename to mumble_arc4random_uniform.cpp.
// - Add CryptographicRandom.h include.
// - Remove <sys/types.h> and <stdlib.h> includes, include <stdint.h> for uint32_t.
// - Added an implementation of arc4random called mumble_arc4random.
// - Rename arc4random_uniform to mumble_arc4random_uniform.
// - Change call to arc4random in mumble_arc4random_uniform to call
// mumble_arc4random instead of arc4random.
// - Remove DEF_WEAK for arc4random_uniform.
// - Disable MSVC warning 4146.

#include <stdint.h>
#include "CryptographicRandom.h"

#if defined(_MSC_VER)
// Disable "unary minus operator applied to unsigned type, result still unsigned"
// warning. The unary minus operator used in arc4random_uniform is perfectly valid.
# pragma warning(disable: 4146)
#endif

// Call through to CryptographicRandom::uint32()
uint32_t
mumble_arc4random(void)
{
return CryptographicRandom::uint32();
}

/*
* Calculate a uniformly distributed random number less than upper_bound
* avoiding "modulo bias".
*
* Uniformity is achieved by generating new random numbers until the one
* returned is outside the range [0, 2**32 % upper_bound). This
* guarantees the selected random number will be inside
* [2**32 % upper_bound, 2**32) which maps back to [0, upper_bound)
* after reduction modulo upper_bound.
*/
uint32_t
mumble_arc4random_uniform(uint32_t upper_bound)
{
uint32_t r, min;

if (upper_bound < 2)
return 0;

/* 2**32 % x == (2**32 - x) % x */
min = -upper_bound % upper_bound;

/*
* This could theoretically loop forever but each retry has
* p > 0.5 (worst case, usually far better) of selecting a
* number inside the range we need, so it should rarely need
* to re-roll.
*/
for (;;) {
r = mumble_arc4random();
if (r >= min)
break;
}

return r % upper_bound;
}
14 changes: 14 additions & 0 deletions 3rdparty/arc4random-src/arc4random_uniform.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// Copyright 2005-2017 The Mumble Developers. All rights reserved.
// Use of this source code is governed by a BSD-style license
// that can be found in the LICENSE file at the root of the
// Mumble source tree or at <https://www.mumble.info/LICENSE>.

#ifndef MUMBLE_3RDPARTY_ARC4RANDOM_UNIFORM_H_
#define MUMBLE_3RDPARTY_ARC4RANDOM_UNIFORM_H_

#include <stdint.h>

uint32_t mumble_arc4random(void);
uint32_t mumble_arc4random_uniform(uint32_t upper_bound);

#endif
1 change: 1 addition & 0 deletions scripts/mklic.pl
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ ($$$)
["licenseQQBonjour", "../3rdparty/qqbonjour-src/LICENSE", "QQBonjour", "https://doc.qt.io/archives/qq/qq23-bonjour.html"],
["licenseSmallFT", "../3rdparty/smallft-src/LICENSE", "smallft", "https://www.xiph.org"],
["licenseOldStyleLicenseHeaders", "../3rdPartyLicenses/mumble-old-license-headers/LICENSE.txt", "Old-style Mumble license headers", "https://www.mumble.info"],
["licenseArc4RandomUniform", "../3rdparty/arc4random-src/LICENSE", "arc4random_uniform", "https://www.openbsd.org"],

);

Expand Down
43 changes: 43 additions & 0 deletions src/CryptographicRandom.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
// Copyright 2005-2017 The Mumble Developers. All rights reserved.
// Use of this source code is governed by a BSD-style license
// that can be found in the LICENSE file at the root of the
// Mumble source tree or at <https://www.mumble.info/LICENSE>.

#include "murmur_pch.h"

#include "CryptographicRandom.h"

#include "arc4random_uniform.h"

void CryptographicRandom::fillBuffer(void *buf, int numBytes) {
// We treat negative and zero values of numBytes to be
// fatal errors in the program. Abort the program if such
// a value is passed to fillBuffer().
if (numBytes <= 0) {
qFatal("CryptographicRandom::fillBuffer(): numBytes is <= 0");
}

// RAND_bytes only returns an error if the entropy pool has not yet been sufficiently filled,
// or in the case of a catastrophic, unrecoverable error in the RAND_bytes implementation happens.
// OpenSSL needs at least 32-bytes of high-entropy random data to seed its CSPRNG.
// If OpenSSL cannot acquire enough random data to seed its CSPRNG at the time Mumble and Murmur
// are running, there is not much we can do about it other than aborting the program.
if (RAND_bytes(reinterpret_cast<unsigned char *>(buf), static_cast<int>(numBytes)) != 1) {
qFatal("CryptographicRandom::fillBuffer(): internal error in OpenSSL's RAND_bytes or entropy pool not yet filled.");
}
}

uint32_t CryptographicRandom::uint32() {
uint32_t ret = 0;

unsigned char buf[4];
CryptographicRandom::fillBuffer(buf, sizeof(buf));

ret = (buf[0]) | (buf[1] << 8) | (buf[2] << 16) | (buf[3] << 24);
return ret;
}

uint32_t CryptographicRandom::uniform(uint32_t upperBound) {
// Implemented in 3rdparty/arc4random/arc4random_uniform.c
return mumble_arc4random_uniform(upperBound);
}
45 changes: 45 additions & 0 deletions src/CryptographicRandom.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
// Copyright 2005-2017 The Mumble Developers. All rights reserved.
// Use of this source code is governed by a BSD-style license
// that can be found in the LICENSE file at the root of the
// Mumble source tree or at <https://www.mumble.info/LICENSE>.

#ifndef MUMBLE_CRYPTOGRAPHICRANDOM_H_
#define MUMBLE_CRYPTOGRAPHICRANDOM_H_

#include <stdint.h>

/// CryptographicRandom provides useful utilities for acquiring
/// pseudo-random data for use in cryptography.
class CryptographicRandom {
public:
/// Fill the buffer at |buf| with |numBytes| bytes of pseudo-random data.
/// The value of |numBytes| must be >= 0. Otherwise, program execution is aborted.
///
/// This function is equivalent to the arc4random_buf() function from OpenBSD.
///
/// This function should not ever fail. It is considered a catastrophic failure if
/// it does. The program is aborted if the function fails, because it is generally
/// impossible to recover from such a scenario.
static void fillBuffer(void *buf, int numBytes);

/// Return a pseudo-random number in the range of 0 to (2**32)-1.
///
/// This function is equivalent to the arc4random() function from OpenBSD.
///
/// This function should not ever fail. It is considered a catastrophic failure if
/// it does. The program is aborted if the function fails, because it is generally
/// impossible to recover from such a scenario.
static uint32_t uint32();

/// Calculate a uniformly distributed random number less than |upperBound|
/// avoiding "modulo bias".
///
/// This function is equivalent to the arc4random_uniform() function from OpenBSD.
///
/// This function should not ever fail. It is considered a catastrophic failure if
/// it does. The program is aborted if the function fails, because it is generally
/// impossible to recover from such a scenario.
static uint32_t uniform(uint32_t upperBound);
};

#endif
17 changes: 17 additions & 0 deletions src/licenses.h
Original file line number Diff line number Diff line change
Expand Up @@ -1354,6 +1354,22 @@ static const char *licenseOldStyleLicenseHeaders =
"SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.";


static const char *licenseArc4RandomUniform =
"Copyright (c) 2008, Damien Miller <djm@openbsd.org>\n"
"\n"
"Permission to use, copy, modify, and distribute this software for any\n"
"purpose with or without fee is hereby granted, provided that the above\n"
"copyright notice and this permission notice appear in all copies.\n"
"\n"
"THE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES\n"
"WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF\n"
"MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR\n"
"ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES\n"
"WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN\n"
"ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF\n"
"OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.";


static const ThirdPartyLicense licenses3rdParties[] = {
ThirdPartyLicense("CELT", "http://www.celt-codec.org/", licenseCELT),
ThirdPartyLicense("Opus", "http://www.opus-codec.org/", licenseOpus),
Expand All @@ -1378,6 +1394,7 @@ static const ThirdPartyLicense licenses3rdParties[] = {
ThirdPartyLicense("QQBonjour", "https://doc.qt.io/archives/qq/qq23-bonjour.html", licenseQQBonjour),
ThirdPartyLicense("smallft", "https://www.xiph.org", licenseSmallFT),
ThirdPartyLicense("Old-style Mumble license headers", "https://www.mumble.info", licenseOldStyleLicenseHeaders),
ThirdPartyLicense("arc4random_uniform", "https://www.openbsd.org", licenseArc4RandomUniform),
ThirdPartyLicense(),
};

Expand Down
9 changes: 7 additions & 2 deletions src/mumble.pri
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,14 @@ CONFIG += qt thread debug_and_release warn_on
DEFINES *= MUMBLE_VERSION_STRING=$$VERSION
INCLUDEPATH += $$PWD . ../mumble_proto
VPATH += $$PWD
HEADERS *= ACL.h Channel.h CryptState.h Connection.h Group.h HTMLFilter.h User.h Net.h OSInfo.h Timer.h SSL.h Version.h SSLCipherInfo.h SSLCipherInfoTable.h licenses.h License.h LogEmitter.h CryptographicHash.h
SOURCES *= ACL.cpp Group.cpp Channel.cpp Connection.cpp HTMLFilter.cpp User.cpp Timer.cpp CryptState.cpp OSInfo.cpp Net.cpp SSL.cpp Version.cpp SSLCipherInfo.cpp License.cpp LogEmitter.cpp CryptographicHash.cpp
HEADERS *= ACL.h Channel.h CryptState.h Connection.h Group.h HTMLFilter.h User.h Net.h OSInfo.h Timer.h SSL.h Version.h SSLCipherInfo.h SSLCipherInfoTable.h licenses.h License.h LogEmitter.h CryptographicHash.h CryptographicRandom.h
SOURCES *= ACL.cpp Group.cpp Channel.cpp Connection.cpp HTMLFilter.cpp User.cpp Timer.cpp CryptState.cpp OSInfo.cpp Net.cpp SSL.cpp Version.cpp SSLCipherInfo.cpp License.cpp LogEmitter.cpp CryptographicHash.cpp CryptographicRandom.cpp
LIBS *= -lmumble_proto

# Add arc4random_uniform
INCLUDEPATH *= ../../3rdparty/arc4random-src
SOURCES *= ../../3rdparty/arc4random-src/arc4random_uniform.cpp

# Note: Protobuf generates into its own directory so we can mark it as a
# system include folder for unix. Otherwise the generated code creates
# a lot of spurious warnings in ours.
Expand Down
74 changes: 74 additions & 0 deletions src/tests/TestCryptographicRandom/TestCryptographicRandom.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
// Copyright 2005-2017 The Mumble Developers. All rights reserved.
// Use of this source code is governed by a BSD-style license
// that can be found in the LICENSE file at the root of the
// Mumble source tree or at <https://www.mumble.info/LICENSE>.

#include <QtCore>
#include <QtTest>

#include "CryptographicRandom.h"

#include <stdint.h>
#include <stdlib.h>
#include <limits>

class TestCryptographicRandom : public QObject {
Q_OBJECT
private slots:
void fillBuffer();
void uint32();
void uniform();
};

// Verify the entropy of the data returned by the random source
// by zlib compressing it and ensuring the compressed size is at
// least 99% of the size of the input data.
//
// The inspiration for this check is from the rand_test.go file
// for Go standard library's crypt/rand package:
// https://golang.org/src/crypto/rand/rand_test.go
bool verifyEntropy(unsigned char *buf, int len) {
QByteArray flated = qCompress(buf, len);
return (flated.size() >= ((len * 99) / 100));
}

void TestCryptographicRandom::fillBuffer() {
const int buflen = 1000000;

for (int i = 0; i < 10; i++) {
unsigned char *buf = reinterpret_cast<unsigned char *>(calloc(buflen, 1));
CryptographicRandom::fillBuffer(buf, buflen);
QVERIFY(verifyEntropy(buf, buflen));
free(buf);
}
}

void TestCryptographicRandom::uint32() {
const int buflen = 1000000;

for (int i = 0; i < 10; i++) {
unsigned char *buf = reinterpret_cast<unsigned char *>(calloc(buflen, 1));
int niter = buflen / sizeof(uint32_t);
for (int j = 0; j < niter; j++) {
int off = j * sizeof(uint32_t);
uint32_t val = CryptographicRandom::uint32();
buf[off] = val & 0xff;
buf[off+1] = (val >> 8) & 0xff;
buf[off+2] = (val >> 16) & 0xff;
buf[off+3] = (val >> 24) & 0xff;
}
QVERIFY(verifyEntropy(buf, buflen));
free(buf);
}
}

void TestCryptographicRandom::uniform() {
for (uint32_t upperBound = 0; upperBound < 10000; upperBound++) {
uint32_t val = CryptographicRandom::uniform(upperBound);
QVERIFY(val <= upperBound);
}
}


QTEST_MAIN(TestCryptographicRandom)
#include "TestCryptographicRandom.moc"
20 changes: 20 additions & 0 deletions src/tests/TestCryptographicRandom/TestCryptographicRandom.pro
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# Copyright 2005-2017 The Mumble Developers. All rights reserved.
# Use of this source code is governed by a BSD-style license
# that can be found in the LICENSE file at the root of the
# Mumble source tree or at <https://www.mumble.info/LICENSE>.

include(../../../compiler.pri)
include(../../../qmake/openssl.pri)

TEMPLATE = app
QT = core testlib
CONFIG += testcase
CONFIG += qt warn_on
CONFIG -= app_bundle
LANGUAGE = C++
TARGET = TestCryptographicRandom
SOURCES = TestCryptographicRandom.cpp CryptographicRandom.cpp arc4random_uniform.cpp
HEADERS = CryptographicHash.h
VPATH += ../..
VPATH += ../../../3rdparty/arc4random-src
INCLUDEPATH += ../.. ../../murmur ../../mumble ../../../3rdparty/arc4random-src
1 change: 1 addition & 0 deletions src/tests/tests.pro
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,6 @@ TEMPLATE = subdirs
SUBDIRS += \
TestCrypt \
TestCryptographicHash \
TestCryptographicRandom \
TestPacketDataStream \
TestTimer

0 comments on commit a58d708

Please sign in to comment.