#ifndef CRYPTOPP_PSSR_H #define CRYPTOPP_PSSR_H #include "pubkey.h" #include NAMESPACE_BEGIN(CryptoPP) // TODO: implement standard variant of PSSR template > class PSSR : public SignatureEncodingMethodWithRecovery { public: PSSR(unsigned int representativeBitLen); PSSR(const byte *representative, unsigned int representativeBitLen); ~PSSR() {} void Update(const byte *input, unsigned int length); unsigned int DigestSize() const {return BitsToBytes(representativeBitLen);} void Restart() {h.Restart();} void Encode(RandomNumberGenerator &rng, byte *representative); bool Verify(const byte *representative); DecodingResult Decode(byte *message); unsigned int MaximumRecoverableLength() const {return MaximumRecoverableLength(representativeBitLen);} static unsigned int MaximumRecoverableLength(unsigned int representativeBitLen); static bool AllowLeftoverMessage() {return true;} protected: static void EncodeRepresentative(byte *representative, unsigned int representativeBitLen, const byte *w, const byte *seed, const byte *m1, unsigned int m1Len); static unsigned int DecodeRepresentative(const byte *representative, unsigned int representativeBitLen, byte *w, byte *seed, byte *m1); unsigned int representativeBitLen, m1Len; H h; SecByteBlock m1, w, seed; }; template PSSR::PSSR(unsigned int representativeBitLen) : representativeBitLen(representativeBitLen), m1Len(0) , m1(MaximumRecoverableLength()), w(H::DIGESTSIZE), seed(H::DIGESTSIZE) { } template PSSR::PSSR(const byte *representative, unsigned int representativeBitLen) : representativeBitLen(representativeBitLen), m1Len(0) , m1(MaximumRecoverableLength()), w(H::DIGESTSIZE), seed(H::DIGESTSIZE) { m1Len = DecodeRepresentative(representative, representativeBitLen, w, seed, m1); h.Update(m1, m1Len); } template void PSSR::Update(const byte *input, unsigned int length) { unsigned int m1LenInc = STDMIN(length, MaximumRecoverableLength() - m1Len); memcpy(m1+m1Len, input, m1LenInc); m1Len += m1LenInc; h.Update(input, length); } template void PSSR::Encode(RandomNumberGenerator &rng, byte *representative) { rng.GenerateBlock(seed, seed.size()); h.Update(seed, seed.size()); h.Final(w); EncodeRepresentative(representative, representativeBitLen, w, seed, m1, m1Len); } template bool PSSR::Verify(const byte *representative) { SecByteBlock m1r(MaximumRecoverableLength()), wr(H::DIGESTSIZE); unsigned int m1rLen = DecodeRepresentative(representative, representativeBitLen, wr, seed, m1r); h.Update(seed, seed.size()); h.Final(w); return m1Len==m1rLen && memcmp(m1, m1r, m1Len)==0 && w==wr; } template DecodingResult PSSR::Decode(byte *message) { SecByteBlock wh(H::DIGESTSIZE); h.Update(seed, seed.size()); h.Final(wh); if (wh == w) { memcpy(message, m1, m1Len); return DecodingResult(m1Len); } else return DecodingResult(); } template unsigned int PSSR::MaximumRecoverableLength(unsigned int paddedLength) { return paddedLength/8 > 1+2*H::DIGESTSIZE ? paddedLength/8-1-2*H::DIGESTSIZE : 0; } template void PSSR::EncodeRepresentative(byte *pssrBlock, unsigned int pssrBlockLen, const byte *w, const byte *seed, const byte *m1, unsigned int m1Len) { assert (m1Len <= MaximumRecoverableLength(pssrBlockLen)); // convert from bit length to byte length if (pssrBlockLen % 8 != 0) { pssrBlock[0] = 0; pssrBlock++; } pssrBlockLen /= 8; const unsigned int hLen = H::DIGESTSIZE; const unsigned int wLen = hLen, seedLen = hLen, dbLen = pssrBlockLen-wLen-seedLen; byte *const maskedSeed = pssrBlock+wLen; byte *const maskedDB = pssrBlock+wLen+seedLen; memcpy(pssrBlock, w, wLen); memcpy(maskedSeed, seed, seedLen); memset(maskedDB, 0, dbLen-m1Len-1); maskedDB[dbLen-m1Len-1] = 0x01; memcpy(maskedDB+dbLen-m1Len, m1, m1Len); MGF::GenerateAndMask(maskedSeed, seedLen+dbLen, w, wLen); } template unsigned int PSSR::DecodeRepresentative(const byte *pssrBlock, unsigned int pssrBlockLen, byte *w, byte *seed, byte *m1) { // convert from bit length to byte length if (pssrBlockLen % 8 != 0) { if (pssrBlock[0] != 0) return 0; pssrBlock++; } pssrBlockLen /= 8; const unsigned int hLen = H::DIGESTSIZE; const unsigned int wLen = hLen, seedLen = hLen, dbLen = pssrBlockLen-wLen-seedLen; if (pssrBlockLen < 2*hLen+1) return 0; memcpy(w, pssrBlock, wLen); SecByteBlock t(pssrBlock+wLen, pssrBlockLen-wLen); byte *const maskedSeed = t; byte *const maskedDB = t+seedLen; MGF::GenerateAndMask(maskedSeed, seedLen+dbLen, w, wLen); memcpy(seed, maskedSeed, seedLen); // DB = 00 ... || 01 || M byte *M = std::find_if(maskedDB, maskedDB+dbLen, std::bind2nd(std::not_equal_to(), 0)); if (M!=maskedDB+dbLen && *M == 0x01) { M++; memcpy(m1, M, maskedDB+dbLen-M); return maskedDB+dbLen-M; } else return 0; } NAMESPACE_END #endif