QUuid, QHttpMultipart and QHash: use QRandomGenerator
QRandomGenerator can produce more than 31 bits of data. And it uses /dev/urandom for us on Unix, so QHash does not need to duplicate that part. Change-Id: Icd0e0d4b27cb4e5eb892fffd14b52a0d91f179eb Reviewed-by: Lars Knoll <lars.knoll@qt.io>
This commit is contained in:
parent
5483b30868
commit
f17095653e
@ -40,14 +40,13 @@
|
|||||||
|
|
||||||
#include "quuid.h"
|
#include "quuid.h"
|
||||||
|
|
||||||
|
#include "qcryptographichash.h"
|
||||||
#include "qdatastream.h"
|
#include "qdatastream.h"
|
||||||
#include "qendian.h"
|
|
||||||
#include "qdebug.h"
|
#include "qdebug.h"
|
||||||
|
#include "qendian.h"
|
||||||
|
#include "qrandom.h"
|
||||||
#include "private/qtools_p.h"
|
#include "private/qtools_p.h"
|
||||||
|
|
||||||
#ifndef QT_BOOTSTRAPPED
|
|
||||||
#include "qcryptographichash.h"
|
|
||||||
#endif
|
|
||||||
QT_BEGIN_NAMESPACE
|
QT_BEGIN_NAMESPACE
|
||||||
|
|
||||||
// 16 bytes (a uint, two shorts and a uchar[8]), each represented by two hex
|
// 16 bytes (a uint, two shorts and a uchar[8]), each represented by two hex
|
||||||
@ -918,17 +917,10 @@ bool QUuid::operator>(const QUuid &other) const Q_DECL_NOTHROW
|
|||||||
/*!
|
/*!
|
||||||
\fn QUuid QUuid::createUuid()
|
\fn QUuid QUuid::createUuid()
|
||||||
|
|
||||||
On any platform other than Windows, this function returns a new
|
On any platform other than Windows, this function returns a new UUID with
|
||||||
UUID with variant QUuid::DCE and version QUuid::Random. If
|
variant QUuid::DCE and version QUuid::Random. On Windows, a GUID is
|
||||||
the /dev/urandom device exists, then the numbers used to construct
|
generated using the Windows API and will be of the type that the API
|
||||||
the UUID will be of cryptographic quality, which will make the UUID
|
decides to create.
|
||||||
unique. Otherwise, the numbers of the UUID will be obtained from
|
|
||||||
the local pseudo-random number generator (qrand(), which is seeded
|
|
||||||
by qsrand()) which is usually not of cryptograhic quality, which
|
|
||||||
means that the UUID can't be guaranteed to be unique.
|
|
||||||
|
|
||||||
On a Windows platform, a GUID is generated, which almost certainly
|
|
||||||
\e{will} be unique, on this or any other system, networked or not.
|
|
||||||
|
|
||||||
\sa variant(), version()
|
\sa variant(), version()
|
||||||
*/
|
*/
|
||||||
@ -948,82 +940,12 @@ QUuid QUuid::createUuid()
|
|||||||
|
|
||||||
#else // Q_OS_WIN
|
#else // Q_OS_WIN
|
||||||
|
|
||||||
QT_BEGIN_INCLUDE_NAMESPACE
|
|
||||||
#include "qdatetime.h"
|
|
||||||
#include "qfile.h"
|
|
||||||
#include "qthreadstorage.h"
|
|
||||||
#include <stdlib.h> // for RAND_MAX
|
|
||||||
QT_END_INCLUDE_NAMESPACE
|
|
||||||
|
|
||||||
#if !defined(QT_BOOTSTRAPPED) && defined(Q_OS_UNIX)
|
|
||||||
Q_GLOBAL_STATIC(QThreadStorage<QFile *>, devUrandomStorage);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
QUuid QUuid::createUuid()
|
QUuid QUuid::createUuid()
|
||||||
{
|
{
|
||||||
QUuid result;
|
QUuid result(Qt::Uninitialized);
|
||||||
uint *data = &(result.data1);
|
uint *data = &(result.data1);
|
||||||
|
enum { AmountToRead = 4 };
|
||||||
#if defined(Q_OS_UNIX)
|
QRandomGenerator::fillRange(data, AmountToRead);
|
||||||
QFile *devUrandom;
|
|
||||||
# if !defined(QT_BOOTSTRAPPED)
|
|
||||||
devUrandom = devUrandomStorage()->localData();
|
|
||||||
if (!devUrandom) {
|
|
||||||
devUrandom = new QFile(QLatin1String("/dev/urandom"));
|
|
||||||
devUrandom->open(QIODevice::ReadOnly | QIODevice::Unbuffered);
|
|
||||||
devUrandomStorage()->setLocalData(devUrandom);
|
|
||||||
}
|
|
||||||
# else
|
|
||||||
QFile file(QLatin1String("/dev/urandom"));
|
|
||||||
devUrandom = &file;
|
|
||||||
devUrandom->open(QIODevice::ReadOnly | QIODevice::Unbuffered);
|
|
||||||
# endif
|
|
||||||
enum { AmountToRead = 4 * sizeof(uint) };
|
|
||||||
if (devUrandom->isOpen()
|
|
||||||
&& devUrandom->read((char *) data, AmountToRead) == AmountToRead) {
|
|
||||||
// we got what we wanted, nothing more to do
|
|
||||||
;
|
|
||||||
} else
|
|
||||||
#endif
|
|
||||||
{
|
|
||||||
static const int intbits = sizeof(int)*8;
|
|
||||||
static int randbits = 0;
|
|
||||||
if (!randbits) {
|
|
||||||
int r = 0;
|
|
||||||
int max = RAND_MAX;
|
|
||||||
do { ++r; } while ((max=max>>1));
|
|
||||||
randbits = r;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Seed the PRNG once per thread with a combination of current time, a
|
|
||||||
// stack address and a serial counter (since thread stack addresses are
|
|
||||||
// re-used).
|
|
||||||
#ifndef QT_BOOTSTRAPPED
|
|
||||||
static QThreadStorage<int *> uuidseed;
|
|
||||||
if (!uuidseed.hasLocalData())
|
|
||||||
{
|
|
||||||
int *pseed = new int;
|
|
||||||
static QBasicAtomicInt serial = Q_BASIC_ATOMIC_INITIALIZER(0);
|
|
||||||
qsrand(*pseed = QDateTime::currentSecsSinceEpoch()
|
|
||||||
+ quintptr(&pseed)
|
|
||||||
+ 2 + serial.fetchAndAddRelaxed(1));
|
|
||||||
uuidseed.setLocalData(pseed);
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
static bool seeded = false;
|
|
||||||
if (!seeded)
|
|
||||||
qsrand(QDateTime::currentSecsSinceEpoch()
|
|
||||||
+ quintptr(&seeded));
|
|
||||||
#endif
|
|
||||||
|
|
||||||
int chunks = 16 / sizeof(uint);
|
|
||||||
while (chunks--) {
|
|
||||||
uint randNumber = 0;
|
|
||||||
for (int filled = 0; filled < intbits; filled += randbits)
|
|
||||||
randNumber |= qrand()<<filled;
|
|
||||||
*(data+chunks) = randNumber;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
result.data4[0] = (result.data4[0] & 0x3F) | 0x80; // UV_DCE
|
result.data4[0] = (result.data4[0] & 0x3F) | 0x80; // UV_DCE
|
||||||
result.data3 = (result.data3 & 0x0FFF) | 0x4000; // UV_Random
|
result.data3 = (result.data3 & 0x0FFF) | 0x4000; // UV_Random
|
||||||
|
@ -65,6 +65,7 @@ QT_BEGIN_NAMESPACE
|
|||||||
|
|
||||||
class Q_CORE_EXPORT QUuid
|
class Q_CORE_EXPORT QUuid
|
||||||
{
|
{
|
||||||
|
QUuid(Qt::Initialization) {}
|
||||||
public:
|
public:
|
||||||
enum Variant {
|
enum Variant {
|
||||||
VarUnknown =-1,
|
VarUnknown =-1,
|
||||||
|
@ -63,13 +63,9 @@
|
|||||||
|
|
||||||
#ifndef QT_BOOTSTRAPPED
|
#ifndef QT_BOOTSTRAPPED
|
||||||
#include <qcoreapplication.h>
|
#include <qcoreapplication.h>
|
||||||
|
#include <qrandom.h>
|
||||||
#endif // QT_BOOTSTRAPPED
|
#endif // QT_BOOTSTRAPPED
|
||||||
|
|
||||||
#ifdef Q_OS_UNIX
|
|
||||||
#include <stdio.h>
|
|
||||||
#include "private/qcore_unix_p.h"
|
|
||||||
#endif // Q_OS_UNIX
|
|
||||||
|
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
|
|
||||||
QT_BEGIN_NAMESPACE
|
QT_BEGIN_NAMESPACE
|
||||||
@ -298,39 +294,7 @@ static uint qt_create_qhash_seed()
|
|||||||
return seed;
|
return seed;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef Q_OS_UNIX
|
seed = QRandomGenerator::get32();
|
||||||
int randomfd = qt_safe_open("/dev/urandom", O_RDONLY);
|
|
||||||
if (randomfd == -1)
|
|
||||||
randomfd = qt_safe_open("/dev/random", O_RDONLY | O_NONBLOCK);
|
|
||||||
if (randomfd != -1) {
|
|
||||||
if (qt_safe_read(randomfd, reinterpret_cast<char *>(&seed), sizeof(seed)) == sizeof(seed)) {
|
|
||||||
qt_safe_close(randomfd);
|
|
||||||
return seed;
|
|
||||||
}
|
|
||||||
qt_safe_close(randomfd);
|
|
||||||
}
|
|
||||||
#endif // Q_OS_UNIX
|
|
||||||
|
|
||||||
#if defined(Q_OS_WIN32) && !defined(Q_CC_GNU)
|
|
||||||
errno_t err;
|
|
||||||
err = rand_s(&seed);
|
|
||||||
if (err == 0)
|
|
||||||
return seed;
|
|
||||||
#endif // Q_OS_WIN32
|
|
||||||
|
|
||||||
// general fallback: initialize from the current timestamp, pid,
|
|
||||||
// and address of a stack-local variable
|
|
||||||
quint64 timestamp = QDateTime::currentMSecsSinceEpoch();
|
|
||||||
seed ^= timestamp;
|
|
||||||
seed ^= (timestamp >> 32);
|
|
||||||
|
|
||||||
quint64 pid = QCoreApplication::applicationPid();
|
|
||||||
seed ^= pid;
|
|
||||||
seed ^= (pid >> 32);
|
|
||||||
|
|
||||||
quintptr seedPtr = reinterpret_cast<quintptr>(&seed);
|
|
||||||
seed ^= seedPtr;
|
|
||||||
seed ^= (qulonglong(seedPtr) >> 32); // no-op on 32-bit platforms
|
|
||||||
#endif // QT_BOOTSTRAPPED
|
#endif // QT_BOOTSTRAPPED
|
||||||
|
|
||||||
return seed;
|
return seed;
|
||||||
|
@ -41,7 +41,7 @@
|
|||||||
#include "qhttpmultipart_p.h"
|
#include "qhttpmultipart_p.h"
|
||||||
#include "QtCore/qdatetime.h" // for initializing the random number generator with QTime
|
#include "QtCore/qdatetime.h" // for initializing the random number generator with QTime
|
||||||
#include "QtCore/qmutex.h"
|
#include "QtCore/qmutex.h"
|
||||||
#include "QtCore/qthreadstorage.h"
|
#include "QtCore/qrandom.h"
|
||||||
|
|
||||||
QT_BEGIN_NAMESPACE
|
QT_BEGIN_NAMESPACE
|
||||||
|
|
||||||
@ -431,23 +431,16 @@ void QHttpPartPrivate::checkHeaderCreated() const
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Q_GLOBAL_STATIC(QThreadStorage<bool *>, seedCreatedStorage);
|
|
||||||
|
|
||||||
QHttpMultiPartPrivate::QHttpMultiPartPrivate() : contentType(QHttpMultiPart::MixedType), device(new QHttpMultiPartIODevice(this))
|
QHttpMultiPartPrivate::QHttpMultiPartPrivate() : contentType(QHttpMultiPart::MixedType), device(new QHttpMultiPartIODevice(this))
|
||||||
{
|
{
|
||||||
if (!seedCreatedStorage()->hasLocalData()) {
|
// 24 random bytes, becomes 32 characters when encoded to Base64
|
||||||
qsrand(QTime(0,0,0).msecsTo(QTime::currentTime()) ^ reinterpret_cast<quintptr>(this));
|
quint32 random[6];
|
||||||
seedCreatedStorage()->setLocalData(new bool(true));
|
QRandomGenerator::fillRange(random);
|
||||||
}
|
boundary = "boundary_.oOo._"
|
||||||
|
+ QByteArray::fromRawData(reinterpret_cast<char *>(random), sizeof(random)).toBase64();
|
||||||
boundary = QByteArray("boundary_.oOo._")
|
|
||||||
+ QByteArray::number(qrand()).toBase64()
|
|
||||||
+ QByteArray::number(qrand()).toBase64()
|
|
||||||
+ QByteArray::number(qrand()).toBase64();
|
|
||||||
|
|
||||||
// boundary must not be longer than 70 characters, see RFC 2046, section 5.1.1
|
// boundary must not be longer than 70 characters, see RFC 2046, section 5.1.1
|
||||||
if (boundary.count() > 70)
|
Q_ASSERT(boundary.count() <= 70);
|
||||||
boundary = boundary.left(70);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
qint64 QHttpMultiPartIODevice::size() const
|
qint64 QHttpMultiPartIODevice::size() const
|
||||||
|
Loading…
x
Reference in New Issue
Block a user