mirror of
https://github.com/shadps4-emu/ext-cryptopp.git
synced 2024-11-23 09:59:42 +00:00
reduce risk of reusing random numbers after VM state rollback
This commit is contained in:
parent
b1be555667
commit
f41245df6f
14
modes.cpp
14
modes.cpp
@ -24,15 +24,6 @@ void Modes_TestInstantiations()
|
||||
}
|
||||
#endif
|
||||
|
||||
void CipherModeBase::GetNextIV(byte *IV)
|
||||
{
|
||||
if (!IsForwardTransformation())
|
||||
throw NotImplemented("CipherModeBase: GetNextIV() must be called on an encryption object");
|
||||
|
||||
m_cipher->ProcessBlock(m_register);
|
||||
memcpy(IV, m_register, BlockSize());
|
||||
}
|
||||
|
||||
void CTR_ModePolicy::SeekToIteration(lword iterationCount)
|
||||
{
|
||||
int carry=0;
|
||||
@ -45,11 +36,6 @@ void CTR_ModePolicy::SeekToIteration(lword iterationCount)
|
||||
}
|
||||
}
|
||||
|
||||
void CTR_ModePolicy::CipherGetNextIV(byte *IV)
|
||||
{
|
||||
IncrementCounterByOne(IV, m_counterArray, BlockSize());
|
||||
}
|
||||
|
||||
inline void CTR_ModePolicy::ProcessMultipleBlocks(byte *output, const byte *input, size_t n)
|
||||
{
|
||||
unsigned int s = BlockSize(), j = 0;
|
||||
|
5
modes.h
5
modes.h
@ -40,7 +40,6 @@ public:
|
||||
unsigned int OptimalDataAlignment() const {return BlockSize();}
|
||||
|
||||
unsigned int IVSize() const {return BlockSize();}
|
||||
void GetNextIV(byte *IV);
|
||||
virtual IV_Requirement IVRequirement() const =0;
|
||||
|
||||
protected:
|
||||
@ -64,7 +63,6 @@ class CRYPTOPP_NO_VTABLE ModePolicyCommonTemplate : public CipherModeBase, publi
|
||||
{
|
||||
unsigned int GetAlignment() const {return m_cipher->BlockAlignment();}
|
||||
void CipherSetKey(const NameValuePairs ¶ms, const byte *key, size_t length);
|
||||
void CipherGetNextIV(byte *IV) {CipherModeBase::GetNextIV(IV);}
|
||||
};
|
||||
|
||||
template <class POLICY_INTERFACE>
|
||||
@ -137,7 +135,6 @@ private:
|
||||
assert(iterationCount == 1);
|
||||
assert(m_cipher->IsForwardTransformation()); // OFB mode needs the "encrypt" direction of the underlying block cipher, even to decrypt
|
||||
m_cipher->ProcessBlock(keystreamBuffer);
|
||||
memcpy_s(m_register, m_register.size(), keystreamBuffer, BlockSize());
|
||||
}
|
||||
void CipherResynchronize(byte *keystreamBuffer, const byte *iv)
|
||||
{
|
||||
@ -150,10 +147,10 @@ class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE CTR_ModePolicy : public ModePolicyCommonTe
|
||||
public:
|
||||
bool IsRandomAccess() const {return true;}
|
||||
IV_Requirement IVRequirement() const {return UNIQUE_IV;}
|
||||
void CipherGetNextIV(byte *IV);
|
||||
static const char * CRYPTOPP_API StaticAlgorithmName() {return "CTR";}
|
||||
|
||||
private:
|
||||
unsigned int GetAlignment() const {return m_cipher->BlockAlignment();}
|
||||
unsigned int GetBytesPerIteration() const {return BlockSize();}
|
||||
unsigned int GetIterationsToBuffer() const {return m_cipher->OptimalNumberOfParallelBlocks();}
|
||||
void WriteKeystream(byte *buffer, size_t iterationCount)
|
||||
|
20
pubkey.h
20
pubkey.h
@ -1033,13 +1033,23 @@ public:
|
||||
ma.m_empty = true;
|
||||
Integer e(representative, representative.size());
|
||||
|
||||
Integer r;
|
||||
// hash message digest into random number k to prevent reusing the same k on a different messages
|
||||
// after virtual machine rollback
|
||||
if (rng.CanIncorporateEntropy())
|
||||
rng.IncorporateEntropy(representative, representative.size());
|
||||
Integer k(rng, 1, params.GetSubgroupOrder()-1);
|
||||
Integer r, s;
|
||||
r = params.ConvertElementToInteger(params.ExponentiateBase(k));
|
||||
alg.Sign(params, key.GetPrivateExponent(), k, e, r, s);
|
||||
|
||||
/*
|
||||
Integer r, s;
|
||||
if (this->MaxRecoverableLength() > 0)
|
||||
r.Decode(ma.m_semisignature, ma.m_semisignature.size());
|
||||
else
|
||||
r.Decode(ma.m_presignature, ma.m_presignature.size());
|
||||
Integer s;
|
||||
alg.Sign(params, key.GetPrivateExponent(), ma.m_k, e, r, s);
|
||||
*/
|
||||
|
||||
size_t rLen = alg.RLen(params);
|
||||
r.Encode(signature, rLen);
|
||||
@ -1054,11 +1064,17 @@ public:
|
||||
protected:
|
||||
void RestartMessageAccumulator(RandomNumberGenerator &rng, PK_MessageAccumulatorBase &ma) const
|
||||
{
|
||||
// k needs to be generated before hashing for signature schemes with recovery
|
||||
// but to defend against VM rollbacks we need to generate k after hashing.
|
||||
// so this code is commented out, since no DL-based signature scheme with recovery
|
||||
// has been implemented in Crypto++ anyway
|
||||
/*
|
||||
const DL_ElgamalLikeSignatureAlgorithm<T> &alg = this->GetSignatureAlgorithm();
|
||||
const DL_GroupParameters<T> ¶ms = this->GetAbstractGroupParameters();
|
||||
ma.m_k.Randomize(rng, 1, params.GetSubgroupOrder()-1);
|
||||
ma.m_presignature.New(params.GetEncodedElementSize(false));
|
||||
params.ConvertElementToInteger(params.ExponentiateBase(ma.m_k)).Encode(ma.m_presignature, ma.m_presignature.size());
|
||||
*/
|
||||
}
|
||||
};
|
||||
|
||||
|
116
randpool.cpp
116
randpool.cpp
@ -1,99 +1,59 @@
|
||||
// randpool.cpp - written and placed in the public domain by Wei Dai
|
||||
// The algorithm in this module comes from PGP's randpool.c
|
||||
// RandomPool used to follow the design of randpool in PGP 2.6.x,
|
||||
// but as of version 5.5 it has been redesigned to reduce the risk
|
||||
// of reusing random numbers after state rollback (which may occur
|
||||
// when running in a virtual machine like VMware).
|
||||
|
||||
#include "pch.h"
|
||||
|
||||
#ifndef CRYPTOPP_IMPORTS
|
||||
|
||||
#include "randpool.h"
|
||||
#include "mdc.h"
|
||||
#include "aes.h"
|
||||
#include "sha.h"
|
||||
#include "modes.h"
|
||||
#include "hrtimer.h"
|
||||
#include <time.h>
|
||||
|
||||
NAMESPACE_BEGIN(CryptoPP)
|
||||
|
||||
typedef MDC<SHA> RandomPoolCipher;
|
||||
|
||||
RandomPool::RandomPool(unsigned int poolSize)
|
||||
: pool(poolSize), key(RandomPoolCipher::DEFAULT_KEYLENGTH)
|
||||
RandomPool::RandomPool()
|
||||
: m_pCipher(new AES::Encryption), m_keySet(false)
|
||||
{
|
||||
assert(poolSize > key.size());
|
||||
|
||||
addPos=0;
|
||||
getPos=poolSize;
|
||||
memset(pool, 0, poolSize);
|
||||
memset(key, 0, key.size());
|
||||
}
|
||||
|
||||
void RandomPool::Stir()
|
||||
void RandomPool::IncorporateEntropy(const byte *input, size_t length)
|
||||
{
|
||||
CFB_Mode<RandomPoolCipher>::Encryption cipher;
|
||||
SHA256 hash;
|
||||
hash.Update(m_key, 32);
|
||||
hash.Update(input, length);
|
||||
hash.Final(m_key);
|
||||
m_keySet = false;
|
||||
}
|
||||
|
||||
for (int i=0; i<2; i++)
|
||||
void RandomPool::GenerateIntoBufferedTransformation(BufferedTransformation &target, const std::string &channel, lword size)
|
||||
{
|
||||
if (size > 0)
|
||||
{
|
||||
cipher.SetKeyWithIV(key, key.size(), pool.end()-cipher.IVSize());
|
||||
cipher.ProcessString(pool, pool.size());
|
||||
memcpy(key, pool, key.size());
|
||||
if (!m_keySet)
|
||||
m_pCipher->SetKey(m_key, 32);
|
||||
|
||||
Timer timer;
|
||||
TimerWord tw = timer.GetCurrentTimerValue();
|
||||
CRYPTOPP_COMPILE_ASSERT(sizeof(tw) <= 16);
|
||||
*(TimerWord *)m_seed.data() += tw;
|
||||
|
||||
time_t t = time(NULL);
|
||||
CRYPTOPP_COMPILE_ASSERT(sizeof(t) <= 8);
|
||||
*(time_t *)(m_seed.data()+8) += t;
|
||||
|
||||
do
|
||||
{
|
||||
m_pCipher->ProcessBlock(m_seed);
|
||||
size_t len = UnsignedMin(16, size);
|
||||
target.ChannelPut(channel, m_seed, len);
|
||||
size -= len;
|
||||
} while (size > 0);
|
||||
}
|
||||
|
||||
addPos = 0;
|
||||
getPos = key.size();
|
||||
}
|
||||
|
||||
size_t RandomPool::Put2(const byte *inString, size_t length, int messageEnd, bool blocking)
|
||||
{
|
||||
size_t t;
|
||||
|
||||
while (length > (t = pool.size() - addPos))
|
||||
{
|
||||
xorbuf(pool+addPos, inString, t);
|
||||
inString += t;
|
||||
length -= t;
|
||||
Stir();
|
||||
}
|
||||
|
||||
if (length)
|
||||
{
|
||||
xorbuf(pool+addPos, inString, length);
|
||||
addPos += length;
|
||||
getPos = pool.size(); // Force stir on get
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t RandomPool::TransferTo2(BufferedTransformation &target, lword &transferBytes, const std::string &channel, bool blocking)
|
||||
{
|
||||
if (!blocking)
|
||||
throw NotImplemented("RandomPool: nonblocking transfer is not implemented by this object");
|
||||
|
||||
lword size = transferBytes;
|
||||
|
||||
while (size > 0)
|
||||
{
|
||||
if (getPos == pool.size())
|
||||
Stir();
|
||||
size_t t = UnsignedMin(pool.size() - getPos, size);
|
||||
target.ChannelPut(channel, pool+getPos, t);
|
||||
size -= t;
|
||||
getPos += t;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
byte RandomPool::GenerateByte()
|
||||
{
|
||||
if (getPos == pool.size())
|
||||
Stir();
|
||||
|
||||
return pool[getPos++];
|
||||
}
|
||||
|
||||
void RandomPool::GenerateBlock(byte *outString, size_t size)
|
||||
{
|
||||
ArraySink sink(outString, size);
|
||||
TransferTo(sink, size);
|
||||
}
|
||||
|
||||
NAMESPACE_END
|
||||
|
39
randpool.h
39
randpool.h
@ -7,38 +7,25 @@
|
||||
NAMESPACE_BEGIN(CryptoPP)
|
||||
|
||||
//! Randomness Pool
|
||||
/*! This class can be used to generate
|
||||
pseudorandom bytes after seeding the pool with
|
||||
the Put() methods */
|
||||
class CRYPTOPP_DLL RandomPool : public RandomNumberGenerator,
|
||||
public Bufferless<BufferedTransformation>
|
||||
/*! This class can be used to generate cryptographic quality
|
||||
pseudorandom bytes after seeding the pool with IncorporateEntropy() */
|
||||
class CRYPTOPP_DLL RandomPool : public RandomNumberGenerator, public NotCopyable
|
||||
{
|
||||
public:
|
||||
//! poolSize must be greater than 16
|
||||
RandomPool(unsigned int poolSize=384);
|
||||
RandomPool();
|
||||
|
||||
size_t Put2(const byte *begin, size_t length, int messageEnd, bool blocking);
|
||||
bool CanIncorporateEntropy() const {return true;}
|
||||
void IncorporateEntropy(const byte *input, size_t length);
|
||||
void GenerateIntoBufferedTransformation(BufferedTransformation &target, const std::string &channel, lword size);
|
||||
|
||||
bool AnyRetrievable() const {return true;}
|
||||
lword MaxRetrievable() const {return ULONG_MAX;}
|
||||
|
||||
size_t TransferTo2(BufferedTransformation &target, lword &transferBytes, const std::string &channel=NULL_CHANNEL, bool blocking=true);
|
||||
size_t CopyRangeTo2(BufferedTransformation &target, lword &begin, lword end=LWORD_MAX, const std::string &channel=NULL_CHANNEL, bool blocking=true) const
|
||||
{
|
||||
throw NotImplemented("RandomPool: CopyRangeTo2() is not supported by this store");
|
||||
}
|
||||
|
||||
byte GenerateByte();
|
||||
void GenerateBlock(byte *output, size_t size);
|
||||
|
||||
void IsolatedInitialize(const NameValuePairs ¶meters) {}
|
||||
|
||||
protected:
|
||||
void Stir();
|
||||
// for backwards compatibility. use RandomNumberSource, RandomNumberStore, and RandomNumberSink for other BufferTransformation functionality
|
||||
void Put(const byte *input, size_t length) {IncorporateEntropy(input, length);}
|
||||
|
||||
private:
|
||||
SecByteBlock pool, key;
|
||||
size_t addPos, getPos;
|
||||
FixedSizeSecBlock<byte, 32> m_key;
|
||||
FixedSizeSecBlock<byte, 16> m_seed;
|
||||
member_ptr<BlockCipher> m_pCipher;
|
||||
bool m_keySet;
|
||||
};
|
||||
|
||||
NAMESPACE_END
|
||||
|
29
salsa.cpp
29
salsa.cpp
@ -17,17 +17,6 @@ void Salsa20_TestInstantiations()
|
||||
Salsa20::Encryption x;
|
||||
}
|
||||
|
||||
void Salsa20_Policy::CipherGetNextIV(byte *IV)
|
||||
{
|
||||
word32 j6, j7;
|
||||
|
||||
j6 = m_state[14] + 1;
|
||||
j7 = m_state[11] + (j6 == 0);
|
||||
|
||||
PutWord(false, LITTLE_ENDIAN_ORDER, IV, j6);
|
||||
PutWord(false, LITTLE_ENDIAN_ORDER, IV+4, j7);
|
||||
}
|
||||
|
||||
void Salsa20_Policy::CipherSetKey(const NameValuePairs ¶ms, const byte *key, size_t length)
|
||||
{
|
||||
m_rounds = params.GetIntValueWithDefault(Name::Rounds(), 20);
|
||||
@ -87,10 +76,20 @@ void Salsa20_Policy::OperateKeystream(KeystreamOperation operation, byte *output
|
||||
{
|
||||
int i;
|
||||
#if CRYPTOPP_BOOL_SSE2_INTRINSICS_AVAILABLE
|
||||
#define SSE2_QUARTER_ROUND(a, b, d, i) {\
|
||||
__m128i t = _mm_add_epi32(a, d); \
|
||||
b = _mm_xor_si128(b, _mm_slli_epi32(t, i)); \
|
||||
b = _mm_xor_si128(b, _mm_srli_epi32(t, 32-i));}
|
||||
|
||||
if (HasSSE2())
|
||||
{
|
||||
__m128i *s = (__m128i *)m_state.data();
|
||||
|
||||
#if CRYPTOPP_GCC_VERSION >= 40000 || _MSC_VER > 1400 || (defined(_MSC_VER) && CRYPTOPP_BOOL_X86)
|
||||
// This code triggers an internal compiler error on MSVC 2005 when compiling
|
||||
// for x64 with optimizations on. hopefully it will get fixed in the next release.
|
||||
// A bug report has been submitted at http://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=274123
|
||||
// Also, GCC 3.4.4 generates incorrect code for x86 at -O2.
|
||||
if (iterationCount >= 4)
|
||||
{
|
||||
__m128i ss[16];
|
||||
@ -139,11 +138,6 @@ void Salsa20_Policy::OperateKeystream(KeystreamOperation operation, byte *output
|
||||
|
||||
for (i=m_rounds; i>0; i-=2)
|
||||
{
|
||||
#define SSE2_QUARTER_ROUND(a, b, d, i) {\
|
||||
__m128i t = _mm_add_epi32(a, d); \
|
||||
b = _mm_xor_si128(b, _mm_slli_epi32(t, i)); \
|
||||
b = _mm_xor_si128(b, _mm_srli_epi32(t, 32-i));}
|
||||
|
||||
#define QUARTER_ROUND(a, b, c, d) \
|
||||
SSE2_QUARTER_ROUND(a, b, d, 7) \
|
||||
SSE2_QUARTER_ROUND(b, c, a, 9) \
|
||||
@ -205,6 +199,7 @@ void Salsa20_Policy::OperateKeystream(KeystreamOperation operation, byte *output
|
||||
#undef SALSA_OUTPUT
|
||||
} while ((iterationCount-=4) >= 4);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!IsP4()) while (iterationCount)
|
||||
{
|
||||
@ -333,6 +328,6 @@ void Salsa20_Policy::OperateKeystream(KeystreamOperation operation, byte *output
|
||||
if (++m_state[8] == 0)
|
||||
++m_state[5];
|
||||
}
|
||||
}
|
||||
} // see comment above if an internal compiler error occurs here
|
||||
|
||||
NAMESPACE_END
|
||||
|
1
salsa.h
1
salsa.h
@ -18,7 +18,6 @@ class CRYPTOPP_NO_VTABLE Salsa20_Policy : public AdditiveCipherConcretePolicy<wo
|
||||
protected:
|
||||
void CipherSetKey(const NameValuePairs ¶ms, const byte *key, size_t length);
|
||||
void OperateKeystream(KeystreamOperation operation, byte *output, const byte *input, size_t iterationCount);
|
||||
void CipherGetNextIV(byte *IV);
|
||||
void CipherResynchronize(byte *keystreamBuffer, const byte *IV);
|
||||
bool IsRandomAccess() const {return true;}
|
||||
void SeekToIteration(lword iterationCount);
|
||||
|
1
seal.h
1
seal.h
@ -18,7 +18,6 @@ class CRYPTOPP_NO_VTABLE SEAL_Policy : public AdditiveCipherConcretePolicy<word3
|
||||
protected:
|
||||
void CipherSetKey(const NameValuePairs ¶ms, const byte *key, size_t length);
|
||||
void OperateKeystream(KeystreamOperation operation, byte *output, const byte *input, size_t iterationCount);
|
||||
void CipherGetNextIV(byte *IV) {PutWord(false, BIG_ENDIAN_ORDER, IV, m_outsideCounter+1);}
|
||||
void CipherResynchronize(byte *keystreamBuffer, const byte *IV);
|
||||
bool IsRandomAccess() const {return true;}
|
||||
void SeekToIteration(lword iterationCount);
|
||||
|
@ -73,7 +73,6 @@ struct CRYPTOPP_DLL CRYPTOPP_NO_VTABLE AdditiveCipherAbstractPolicy
|
||||
virtual bool CanOperateKeystream() const {return false;}
|
||||
virtual void OperateKeystream(KeystreamOperation operation, byte *output, const byte *input, size_t iterationCount) {assert(false);}
|
||||
virtual void CipherSetKey(const NameValuePairs ¶ms, const byte *key, size_t length) =0;
|
||||
virtual void CipherGetNextIV(byte *iv) {throw NotImplemented("SimpleKeyingInterface: this object doesn't support GetNextIV()");}
|
||||
virtual void CipherResynchronize(byte *keystreamBuffer, const byte *iv) {throw NotImplemented("SimpleKeyingInterface: this object doesn't support resynchronization");}
|
||||
virtual bool IsRandomAccess() const =0;
|
||||
virtual void SeekToIteration(lword iterationCount) {assert(!IsRandomAccess()); throw NotImplemented("StreamTransformation: this object doesn't support random access");}
|
||||
@ -133,10 +132,8 @@ template <class BASE = AbstractPolicyHolder<AdditiveCipherAbstractPolicy, TwoBas
|
||||
class CRYPTOPP_NO_VTABLE AdditiveCipherTemplate : public BASE
|
||||
{
|
||||
public:
|
||||
byte GenerateByte();
|
||||
void GenerateBlock(byte *output, size_t size);
|
||||
void ProcessData(byte *outString, const byte *inString, size_t length);
|
||||
void GetNextIV(byte *iv) {this->AccessPolicy().CipherGetNextIV(iv);}
|
||||
void Resynchronize(const byte *iv);
|
||||
unsigned int OptimalBlockSize() const {return this->GetPolicy().GetOptimalBlockSize();}
|
||||
unsigned int GetOptimalNextBlockSize() const {return (unsigned int)this->m_leftOver;}
|
||||
@ -170,7 +167,6 @@ public:
|
||||
virtual bool CanIterate() const {return false;}
|
||||
virtual void Iterate(byte *output, const byte *input, CipherDir dir, size_t iterationCount) {assert(false);}
|
||||
virtual void CipherSetKey(const NameValuePairs ¶ms, const byte *key, size_t length) =0;
|
||||
virtual void CipherGetNextIV(byte *iv) {throw NotImplemented("SimpleKeyingInterface: this object doesn't support GetNextIV()");}
|
||||
virtual void CipherResynchronize(const byte *iv) {throw NotImplemented("SimpleKeyingInterface: this object doesn't support resynchronization");}
|
||||
};
|
||||
|
||||
@ -236,7 +232,6 @@ class CRYPTOPP_NO_VTABLE CFB_CipherTemplate : public BASE
|
||||
{
|
||||
public:
|
||||
void ProcessData(byte *outString, const byte *inString, size_t length);
|
||||
void GetNextIV(byte *iv) {this->AccessPolicy().CipherGetNextIV(iv);}
|
||||
void Resynchronize(const byte *iv);
|
||||
unsigned int OptimalBlockSize() const {return this->GetPolicy().GetBytesPerIteration();}
|
||||
unsigned int GetOptimalNextBlockSize() const {return (unsigned int)m_leftOver;}
|
||||
|
Loading…
Reference in New Issue
Block a user