summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorweidai <weidai@57ff6487-cd31-0410-9ec3-f628ee90f5f0>2007-05-04 15:37:46 +0000
committerweidai <weidai@57ff6487-cd31-0410-9ec3-f628ee90f5f0>2007-05-04 15:37:46 +0000
commit48e0b8231e112953680cacd9fa2bb6157184a657 (patch)
tree5c790bf6c465f48e0dca552dfff508cda8f7235f
parentd37d0425edebab09ec1ff767e9b89b68db52533d (diff)
downloadcryptopp-48e0b8231e112953680cacd9fa2bb6157184a657.tar.gz
reduce risk of reusing random numbers after VM state rollback
git-svn-id: svn://svn.code.sf.net/p/cryptopp/code/trunk/c5@340 57ff6487-cd31-0410-9ec3-f628ee90f5f0
-rw-r--r--modes.cpp14
-rw-r--r--modes.h5
-rw-r--r--pubkey.h20
-rw-r--r--randpool.cpp112
-rw-r--r--randpool.h39
-rwxr-xr-xsalsa.cpp29
-rwxr-xr-xsalsa.h1
-rw-r--r--seal.h1
-rw-r--r--strciphr.h5
9 files changed, 80 insertions, 146 deletions
diff --git a/modes.cpp b/modes.cpp
index b51afe9..5605922 100644
--- a/modes.cpp
+++ b/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;
diff --git a/modes.h b/modes.h
index a4f5bbe..442c320 100644
--- a/modes.h
+++ b/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 &params, 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)
diff --git a/pubkey.h b/pubkey.h
index 0204ba6..bdf0035 100644
--- a/pubkey.h
+++ b/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> &params = 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());
+ */
}
};
diff --git a/randpool.cpp b/randpool.cpp
index c2b44fa..11ece6d 100644
--- a/randpool.cpp
+++ b/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;
-
- for (int i=0; i<2; i++)
- {
- cipher.SetKeyWithIV(key, key.size(), pool.end()-cipher.IVSize());
- cipher.ProcessString(pool, pool.size());
- memcpy(key, pool, key.size());
- }
-
- 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;
+ SHA256 hash;
+ hash.Update(m_key, 32);
+ hash.Update(input, length);
+ hash.Final(m_key);
+ m_keySet = false;
}
-size_t RandomPool::TransferTo2(BufferedTransformation &target, lword &transferBytes, const std::string &channel, bool blocking)
+void RandomPool::GenerateIntoBufferedTransformation(BufferedTransformation &target, const std::string &channel, lword size)
{
- if (!blocking)
- throw NotImplemented("RandomPool: nonblocking transfer is not implemented by this object");
-
- lword size = transferBytes;
-
- while (size > 0)
+ if (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;
+ 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);
}
-
- 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
diff --git a/randpool.h b/randpool.h
index e4157f3..c25bc9b 100644
--- a/randpool.h
+++ b/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 &parameters) {}
-
-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
diff --git a/salsa.cpp b/salsa.cpp
index 4781218..5b2e115 100755
--- a/salsa.cpp
+++ b/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 &params, 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
diff --git a/salsa.h b/salsa.h
index 176a1a3..5b1431a 100755
--- a/salsa.h
+++ b/salsa.h
@@ -18,7 +18,6 @@ class CRYPTOPP_NO_VTABLE Salsa20_Policy : public AdditiveCipherConcretePolicy<wo
protected:
void CipherSetKey(const NameValuePairs &params, 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);
diff --git a/seal.h b/seal.h
index 551a338..c175a64 100644
--- a/seal.h
+++ b/seal.h
@@ -18,7 +18,6 @@ class CRYPTOPP_NO_VTABLE SEAL_Policy : public AdditiveCipherConcretePolicy<word3
protected:
void CipherSetKey(const NameValuePairs &params, 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);
diff --git a/strciphr.h b/strciphr.h
index 724bbbf..e3216a8 100644
--- a/strciphr.h
+++ b/strciphr.h
@@ -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 &params, 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 &params, 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;}