Crypto++  8.9
Free C++ class library of cryptographic schemes
pkcspad.cpp
1 // pkcspad.cpp - originally written and placed in the public domain by Wei Dai
2 
3 #include "pch.h"
4 
5 #ifndef CRYPTOPP_PKCSPAD_CPP // SunCC workaround: compiler could cause this file to be included twice
6 #define CRYPTOPP_PKCSPAD_CPP
7 
8 #include "pkcspad.h"
9 #include "emsa2.h"
10 #include "hashfwd.h"
11 #include "misc.h"
12 #include "trap.h"
13 
14 NAMESPACE_BEGIN(CryptoPP)
15 
16 // Typedef/cast change due to Clang, http://github.com/weidai11/cryptopp/issues/300
17 template<> const byte PKCS_DigestDecoration<Weak1::MD2>::decoration[] = {0x30,0x20,0x30,0x0c,0x06,0x08,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x02,0x02,0x05,0x00,0x04,0x10};
18 template<> const unsigned int PKCS_DigestDecoration<Weak1::MD2>::length = (unsigned int)sizeof(PKCS_DigestDecoration<Weak1::MD2>::decoration);
19 
20 template<> const byte PKCS_DigestDecoration<Weak1::MD5>::decoration[] = {0x30,0x20,0x30,0x0c,0x06,0x08,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x02,0x05,0x05,0x00,0x04,0x10};
21 template<> const unsigned int PKCS_DigestDecoration<Weak1::MD5>::length = (unsigned int)sizeof(PKCS_DigestDecoration<Weak1::MD5>::decoration);
22 
23 template<> const byte PKCS_DigestDecoration<RIPEMD160>::decoration[] = {0x30,0x21,0x30,0x09,0x06,0x05,0x2b,0x24,0x03,0x02,0x01,0x05,0x00,0x04,0x14};
24 template<> const unsigned int PKCS_DigestDecoration<RIPEMD160>::length = (unsigned int)sizeof(PKCS_DigestDecoration<RIPEMD160>::decoration);
25 
26 template<> const byte PKCS_DigestDecoration<Tiger>::decoration[] = {0x30,0x29,0x30,0x0D,0x06,0x09,0x2B,0x06,0x01,0x04,0x01,0xDA,0x47,0x0C,0x02,0x05,0x00,0x04,0x18};
27 template<> const unsigned int PKCS_DigestDecoration<Tiger>::length = (unsigned int)sizeof(PKCS_DigestDecoration<Tiger>::decoration);
28 
29 // Inclusion based on DLL due to Clang, http://github.com/weidai11/cryptopp/issues/300
30 #ifndef CRYPTOPP_IS_DLL
31 template<> const byte PKCS_DigestDecoration<SHA1>::decoration[] = {0x30,0x21,0x30,0x09,0x06,0x05,0x2B,0x0E,0x03,0x02,0x1A,0x05,0x00,0x04,0x14};
32 template<> const unsigned int PKCS_DigestDecoration<SHA1>::length = (unsigned int)sizeof(PKCS_DigestDecoration<SHA1>::decoration);
33 
34 template<> const byte PKCS_DigestDecoration<SHA224>::decoration[] = {0x30,0x2d,0x30,0x0d,0x06,0x09,0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x02,0x04,0x05,0x00,0x04,0x1c};
35 template<> const unsigned int PKCS_DigestDecoration<SHA224>::length = (unsigned int)sizeof(PKCS_DigestDecoration<SHA224>::decoration);
36 
37 template<> const byte PKCS_DigestDecoration<SHA256>::decoration[] = {0x30,0x31,0x30,0x0d,0x06,0x09,0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x02,0x01,0x05,0x00,0x04,0x20};
38 template<> const unsigned int PKCS_DigestDecoration<SHA256>::length = (unsigned int)sizeof(PKCS_DigestDecoration<SHA256>::decoration);
39 
40 template<> const byte PKCS_DigestDecoration<SHA384>::decoration[] = {0x30,0x41,0x30,0x0d,0x06,0x09,0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x02,0x02,0x05,0x00,0x04,0x30};
41 template<> const unsigned int PKCS_DigestDecoration<SHA384>::length = (unsigned int)sizeof(PKCS_DigestDecoration<SHA384>::decoration);
42 
43 template<> const byte PKCS_DigestDecoration<SHA512>::decoration[] = {0x30,0x51,0x30,0x0d, 0x06,0x09,0x60,0x86, 0x48,0x01,0x65,0x03, 0x04,0x02,0x03,0x05, 0x00,0x04,0x40};
44 template<> const unsigned int PKCS_DigestDecoration<SHA512>::length = (unsigned int)sizeof(PKCS_DigestDecoration<SHA512>::decoration);
45 
46 // http://github.com/weidai11/cryptopp/issues/517. OIDs and encoded prefixes found at
47 // http://www.ietf.org/archive/id/draft-jivsov-openpgp-sha3-01.txt
48 template<> const byte PKCS_DigestDecoration<SHA3_256>::decoration[] = {0x30,0x31,0x30,0x0d, 0x06,0x09,0x60,0x86, 0x48,0x01,0x65,0x03, 0x04,0x02,0x08,0x05, 0x00,0x04,0x20};
49 template<> const unsigned int PKCS_DigestDecoration<SHA3_256>::length = (unsigned int)sizeof(PKCS_DigestDecoration<SHA3_256>::decoration);
50 
51 template<> const byte PKCS_DigestDecoration<SHA3_384>::decoration[] = {0x30,0x41,0x30,0x0d, 0x06,0x09,0x60,0x86, 0x48,0x01,0x65,0x03, 0x04,0x02,0x09,0x05, 0x00,0x04,0x30};
52 template<> const unsigned int PKCS_DigestDecoration<SHA3_384>::length = (unsigned int)sizeof(PKCS_DigestDecoration<SHA3_384>::decoration);
53 
54 template<> const byte PKCS_DigestDecoration<SHA3_512>::decoration[] = {0x30,0x51,0x30,0x0d, 0x06,0x09,0x60,0x86, 0x48,0x01,0x65,0x03, 0x04,0x02,0x0a,0x05, 0x00,0x04,0x40};
55 template<> const unsigned int PKCS_DigestDecoration<SHA3_512>::length = (unsigned int)sizeof(PKCS_DigestDecoration<SHA3_512>::decoration);
56 #endif
57 
58 size_t PKCS_EncryptionPaddingScheme::MaxUnpaddedLength(size_t paddedLength) const
59 {
60  return SaturatingSubtract(paddedLength/8, 10U);
61 }
62 
63 void PKCS_EncryptionPaddingScheme::Pad(RandomNumberGenerator& rng, const byte *input, size_t inputLen, byte *pkcsBlock, size_t pkcsBlockLen, const NameValuePairs& parameters) const
64 {
65  CRYPTOPP_UNUSED(parameters);
66  CRYPTOPP_ASSERT (inputLen <= MaxUnpaddedLength(pkcsBlockLen)); // this should be checked by caller
67 
68  // convert from bit length to byte length
69  if (pkcsBlockLen % 8 != 0)
70  {
71  pkcsBlock[0] = 0;
72  pkcsBlock++;
73  }
74  pkcsBlockLen /= 8;
75 
76  pkcsBlock[0] = 2; // block type 2
77 
78  // pad with non-zero random bytes
79  for (unsigned i = 1; i < pkcsBlockLen-inputLen-1; i++)
80  pkcsBlock[i] = (byte)rng.GenerateWord32(1, 0xff);
81 
82  pkcsBlock[pkcsBlockLen-inputLen-1] = 0; // separator
83  std::memcpy(pkcsBlock+pkcsBlockLen-inputLen, input, inputLen);
84 }
85 
86 DecodingResult PKCS_EncryptionPaddingScheme::Unpad(const byte *pkcsBlock, size_t pkcsBlockLen, byte *output, const NameValuePairs& parameters) const
87 {
88  CRYPTOPP_UNUSED(parameters);
89  bool invalid = false;
90  size_t maxOutputLen = MaxUnpaddedLength(pkcsBlockLen);
91 
92  // convert from bit length to byte length
93  if (pkcsBlockLen % 8 != 0)
94  {
95  invalid = (pkcsBlock[0] != 0) || invalid;
96  pkcsBlock++;
97  }
98  pkcsBlockLen /= 8;
99 
100  // Require block type 2.
101  invalid = (pkcsBlock[0] != 2) || invalid;
102 
103  // Constant-time separator search to mitigate timing attacks (Marvin Attack, CVE-2022-4304)
104  // Scan every byte to find first zero separator without variable-time loop termination
105  size_t separatorIndex = 0;
106  size_t foundSeparator = 0;
107 
108  for (size_t j = 1; j < pkcsBlockLen; j++)
109  {
110  // Check if current byte is zero (separator)
111  size_t isZero = (pkcsBlock[j] == 0) ? 1 : 0;
112  size_t notFoundYet = 1 - foundSeparator;
113 
114  // Constant-time conditional: record position using bitwise ops
115  // Equivalent to: if (isZero && notFoundYet) separatorIndex = j;
116  size_t mask = -(isZero & notFoundYet); // all 1s if true, all 0s if false
117  separatorIndex = (separatorIndex & ~mask) | (j & mask);
118 
119  // Mark that we found a separator
120  foundSeparator |= isZero;
121  }
122 
123  // Position after the separator
124  size_t i = separatorIndex + 1;
125  CRYPTOPP_ASSERT(i==pkcsBlockLen || pkcsBlock[i-1]==0);
126 
127  size_t outputLen = pkcsBlockLen - i;
128  invalid = (outputLen > maxOutputLen) || invalid;
129  invalid = (foundSeparator == 0) || invalid; // No separator found
130 
131  // Always perform memcpy to avoid timing leak from early return
132  // This ensures both valid and invalid padding take the same code path
133  std::memcpy (output, pkcsBlock+i, outputLen);
134 
135  // Return error on invalid padding, otherwise return decoded length
136  return invalid ? DecodingResult() : DecodingResult(outputLen);
137 }
138 
139 // ********************************************************
140 
141 #ifndef CRYPTOPP_IMPORTS
142 
143 void PKCS1v15_SignatureMessageEncodingMethod::ComputeMessageRepresentative(RandomNumberGenerator &rng,
144  const byte *recoverableMessage, size_t recoverableMessageLength,
145  HashTransformation &hash, HashIdentifier hashIdentifier, bool messageEmpty,
146  byte *representative, size_t representativeBitLength) const
147 {
148  CRYPTOPP_UNUSED(rng), CRYPTOPP_UNUSED(recoverableMessage), CRYPTOPP_UNUSED(recoverableMessageLength);
149  CRYPTOPP_UNUSED(messageEmpty), CRYPTOPP_UNUSED(hashIdentifier);
150  CRYPTOPP_ASSERT(representativeBitLength >= MinRepresentativeBitLength(hashIdentifier.second, hash.DigestSize()));
151 
152  size_t pkcsBlockLen = representativeBitLength;
153  // convert from bit length to byte length
154  if (pkcsBlockLen % 8 != 0)
155  {
156  representative[0] = 0;
157  representative++;
158  }
159  pkcsBlockLen /= 8;
160 
161  representative[0] = 1; // block type 1
162 
163  unsigned int digestSize = hash.DigestSize();
164  byte *pPadding = representative + 1;
165  byte *pDigest = representative + pkcsBlockLen - digestSize;
166  byte *pHashId = pDigest - hashIdentifier.second;
167  byte *pSeparator = pHashId - 1;
168 
169  // pad with 0xff
170  std::memset(pPadding, 0xff, pSeparator-pPadding);
171  *pSeparator = 0;
172  std::memcpy(pHashId, hashIdentifier.first, hashIdentifier.second);
173  hash.Final(pDigest);
174 }
175 
176 #endif
177 
178 NAMESPACE_END
179 
180 #endif
Interface for hash functions and data processing part of MACs.
Definition: cryptlib.h:1118
virtual unsigned int DigestSize() const =0
Provides the digest size of the hash.
virtual void Final(byte *digest)
Computes the hash of the current message.
Definition: cryptlib.h:1147
Interface for retrieving values given their names.
Definition: cryptlib.h:327
PKCS #1 decoration data structure.
Definition: pkcspad.h:35
size_t MaxUnpaddedLength(size_t paddedLength) const
max size of unpadded message in bytes, given max size of padded message in bits (1 less than size of ...
Definition: pkcspad.cpp:58
Interface for random number generators.
Definition: cryptlib.h:1440
virtual word32 GenerateWord32(word32 min=0, word32 max=0xffffffffUL)
Generate a random 32 bit word in the range min to max, inclusive.
Classes and functions for various padding schemes used in public key algorithms.
Forward declarations for hash functions used in signature encoding methods.
Utility functions for the Crypto++ library.
T1 SaturatingSubtract(const T1 &a, const T2 &b)
Performs a saturating subtract clamped at 0.
Definition: misc.h:1302
Crypto++ library namespace.
Precompiled header file.
Classes for PKCS padding schemes.
Returns a decoding results.
Definition: cryptlib.h:283
Debugging and diagnostic assertions.
#define CRYPTOPP_ASSERT(exp)
Debugging and diagnostic assertion.
Definition: trap.h:68