/src/cryptopp/gfpcrypt.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | // dsa.cpp - originally written and placed in the public domain by Wei Dai |
2 | | |
3 | | #include "pch.h" |
4 | | #include "config.h" |
5 | | |
6 | | // TODO: fix the C4589 warnings |
7 | | #if CRYPTOPP_MSC_VERSION |
8 | | # pragma warning(disable: 4189 4589) |
9 | | #endif |
10 | | |
11 | | #ifndef CRYPTOPP_IMPORTS |
12 | | |
13 | | #include "gfpcrypt.h" |
14 | | #include "nbtheory.h" |
15 | | #include "modarith.h" |
16 | | #include "integer.h" |
17 | | #include "asn.h" |
18 | | #include "oids.h" |
19 | | #include "misc.h" |
20 | | |
21 | | NAMESPACE_BEGIN(CryptoPP) |
22 | | |
23 | | #if defined(CRYPTOPP_DEBUG) && !defined(CRYPTOPP_DOXYGEN_PROCESSING) |
24 | | void TestInstantiations_gfpcrypt() |
25 | | { |
26 | | GDSA<SHA1>::Signer test; |
27 | | GDSA<SHA1>::Verifier test1; |
28 | | DSA::Signer test5(NullRNG(), 100); |
29 | | DSA::Signer test2(test5); |
30 | | NR<SHA1>::Signer test3; |
31 | | NR<SHA1>::Verifier test4; |
32 | | DLIES<>::Encryptor test6; |
33 | | DLIES<>::Decryptor test7; |
34 | | } |
35 | | #endif |
36 | | |
37 | | void DL_GroupParameters_DSA::GenerateRandom(RandomNumberGenerator &rng, const NameValuePairs &alg) |
38 | 0 | { |
39 | 0 | Integer p, q, g; |
40 | |
|
41 | 0 | if (alg.GetValue("Modulus", p) && alg.GetValue("SubgroupGenerator", g)) |
42 | 0 | { |
43 | 0 | q = alg.GetValueWithDefault("SubgroupOrder", ComputeGroupOrder(p)/2); |
44 | 0 | Initialize(p, q, g); |
45 | 0 | } |
46 | 0 | else |
47 | 0 | { |
48 | 0 | int modulusSize = 2048, defaultSubgroupOrderSize; |
49 | 0 | alg.GetIntValue("ModulusSize", modulusSize) || alg.GetIntValue("KeySize", modulusSize); |
50 | |
|
51 | 0 | switch (modulusSize) |
52 | 0 | { |
53 | 0 | case 1024: |
54 | 0 | defaultSubgroupOrderSize = 160; |
55 | 0 | break; |
56 | 0 | case 2048: |
57 | 0 | defaultSubgroupOrderSize = 224; |
58 | 0 | break; |
59 | 0 | case 3072: |
60 | 0 | defaultSubgroupOrderSize = 256; |
61 | 0 | break; |
62 | 0 | default: |
63 | 0 | throw InvalidArgument("DSA: not a valid prime length"); |
64 | 0 | } |
65 | | |
66 | 0 | DL_GroupParameters_GFP::GenerateRandom(rng, CombinedNameValuePairs(alg, MakeParameters(Name::SubgroupOrderSize(), defaultSubgroupOrderSize, false))); |
67 | 0 | } |
68 | 0 | } |
69 | | |
70 | | bool DL_GroupParameters_DSA::ValidateGroup(RandomNumberGenerator &rng, unsigned int level) const |
71 | 0 | { |
72 | 0 | bool pass = DL_GroupParameters_GFP::ValidateGroup(rng, level); |
73 | 0 | CRYPTOPP_ASSERT(pass); |
74 | |
|
75 | 0 | const int pSize = GetModulus().BitCount(), qSize = GetSubgroupOrder().BitCount(); |
76 | 0 | pass = pass && ((pSize==1024 && qSize==160) || (pSize==2048 && qSize==224) || (pSize==2048 && qSize==256) || (pSize==3072 && qSize==256)); |
77 | 0 | CRYPTOPP_ASSERT(pass); |
78 | |
|
79 | 0 | return pass; |
80 | 0 | } |
81 | | |
82 | | void DL_SignatureMessageEncodingMethod_DSA::ComputeMessageRepresentative(RandomNumberGenerator &rng, |
83 | | const byte *recoverableMessage, size_t recoverableMessageLength, |
84 | | HashTransformation &hash, HashIdentifier hashIdentifier, bool messageEmpty, |
85 | | byte *representative, size_t representativeBitLength) const |
86 | 0 | { |
87 | 0 | CRYPTOPP_UNUSED(rng), CRYPTOPP_UNUSED(recoverableMessage), CRYPTOPP_UNUSED(recoverableMessageLength); |
88 | 0 | CRYPTOPP_UNUSED(messageEmpty), CRYPTOPP_UNUSED(hashIdentifier); |
89 | 0 | CRYPTOPP_ASSERT(recoverableMessageLength == 0); |
90 | 0 | CRYPTOPP_ASSERT(hashIdentifier.second == 0); |
91 | |
|
92 | 0 | const size_t representativeByteLength = BitsToBytes(representativeBitLength); |
93 | 0 | const size_t digestSize = hash.DigestSize(); |
94 | 0 | const size_t paddingLength = SaturatingSubtract(representativeByteLength, digestSize); |
95 | |
|
96 | 0 | std::memset(representative, 0, paddingLength); |
97 | 0 | hash.TruncatedFinal(representative+paddingLength, STDMIN(representativeByteLength, digestSize)); |
98 | |
|
99 | 0 | if (digestSize*8 > representativeBitLength) |
100 | 0 | { |
101 | 0 | Integer h(representative, representativeByteLength); |
102 | 0 | h >>= representativeByteLength*8 - representativeBitLength; |
103 | 0 | h.Encode(representative, representativeByteLength); |
104 | 0 | } |
105 | 0 | } |
106 | | |
107 | | void DL_SignatureMessageEncodingMethod_NR::ComputeMessageRepresentative(RandomNumberGenerator &rng, |
108 | | const byte *recoverableMessage, size_t recoverableMessageLength, |
109 | | HashTransformation &hash, HashIdentifier hashIdentifier, bool messageEmpty, |
110 | | byte *representative, size_t representativeBitLength) const |
111 | 0 | { |
112 | 0 | CRYPTOPP_UNUSED(rng);CRYPTOPP_UNUSED(recoverableMessage); CRYPTOPP_UNUSED(recoverableMessageLength); |
113 | 0 | CRYPTOPP_UNUSED(hash); CRYPTOPP_UNUSED(hashIdentifier); CRYPTOPP_UNUSED(messageEmpty); |
114 | 0 | CRYPTOPP_UNUSED(representative); CRYPTOPP_UNUSED(representativeBitLength); |
115 | |
|
116 | 0 | CRYPTOPP_ASSERT(recoverableMessageLength == 0); |
117 | 0 | CRYPTOPP_ASSERT(hashIdentifier.second == 0); |
118 | 0 | const size_t representativeByteLength = BitsToBytes(representativeBitLength); |
119 | 0 | const size_t digestSize = hash.DigestSize(); |
120 | 0 | const size_t paddingLength = SaturatingSubtract(representativeByteLength, digestSize); |
121 | |
|
122 | 0 | std::memset(representative, 0, paddingLength); |
123 | 0 | hash.TruncatedFinal(representative+paddingLength, STDMIN(representativeByteLength, digestSize)); |
124 | |
|
125 | 0 | if (digestSize*8 >= representativeBitLength) |
126 | 0 | { |
127 | 0 | Integer h(representative, representativeByteLength); |
128 | 0 | h >>= representativeByteLength*8 - representativeBitLength + 1; |
129 | 0 | h.Encode(representative, representativeByteLength); |
130 | 0 | } |
131 | 0 | } |
132 | | |
133 | | bool DL_GroupParameters_IntegerBased::ValidateGroup(RandomNumberGenerator &rng, unsigned int level) const |
134 | 0 | { |
135 | 0 | const Integer &p = GetModulus(), &q = GetSubgroupOrder(); |
136 | 0 | bool pass = true; |
137 | |
|
138 | 0 | CRYPTOPP_ASSERT(p > Integer::One() && p.IsOdd()); |
139 | 0 | pass = pass && p > Integer::One() && p.IsOdd(); |
140 | |
|
141 | 0 | CRYPTOPP_ASSERT(q > Integer::One() && q.IsOdd()); |
142 | 0 | pass = pass && q > Integer::One() && q.IsOdd(); |
143 | |
|
144 | 0 | if (level >= 1) |
145 | 0 | { |
146 | 0 | CRYPTOPP_ASSERT(GetCofactor() > Integer::One()); |
147 | 0 | CRYPTOPP_ASSERT(GetGroupOrder() % q == Integer::Zero()); |
148 | |
|
149 | 0 | pass = pass && GetCofactor() > Integer::One() && GetGroupOrder() % q == Integer::Zero(); |
150 | 0 | } |
151 | 0 | if (level >= 2) |
152 | 0 | { |
153 | 0 | CRYPTOPP_ASSERT(VerifyPrime(rng, q, level-2)); |
154 | 0 | CRYPTOPP_ASSERT(VerifyPrime(rng, p, level-2)); |
155 | |
|
156 | 0 | pass = pass && VerifyPrime(rng, q, level-2) && VerifyPrime(rng, p, level-2); |
157 | 0 | } |
158 | |
|
159 | 0 | return pass; |
160 | 0 | } |
161 | | |
162 | | bool DL_GroupParameters_IntegerBased::ValidateElement(unsigned int level, const Integer &g, const DL_FixedBasePrecomputation<Integer> *gpc) const |
163 | 0 | { |
164 | 0 | const Integer &p = GetModulus(), &q = GetSubgroupOrder(); |
165 | 0 | bool pass = true; |
166 | |
|
167 | 0 | CRYPTOPP_ASSERT(GetFieldType() == 1 ? g.IsPositive() : g.NotNegative()); |
168 | 0 | pass = pass && GetFieldType() == 1 ? g.IsPositive() : g.NotNegative(); |
169 | |
|
170 | 0 | CRYPTOPP_ASSERT(g < p && !IsIdentity(g)); |
171 | 0 | pass = pass && g < p && !IsIdentity(g); |
172 | |
|
173 | 0 | if (level >= 1) |
174 | 0 | { |
175 | 0 | if (gpc) |
176 | 0 | { |
177 | 0 | CRYPTOPP_ASSERT(gpc->Exponentiate(GetGroupPrecomputation(), Integer::One()) == g); |
178 | 0 | pass = pass && gpc->Exponentiate(GetGroupPrecomputation(), Integer::One()) == g; |
179 | 0 | } |
180 | 0 | } |
181 | 0 | if (level >= 2) |
182 | 0 | { |
183 | 0 | if (GetFieldType() == 2) |
184 | 0 | { |
185 | 0 | CRYPTOPP_ASSERT(Jacobi(g*g-4, p)==-1); |
186 | 0 | pass = pass && Jacobi(g*g-4, p)==-1; |
187 | 0 | } |
188 | | |
189 | | // verifying that Lucas((p+1)/2, w, p)==2 is omitted because it's too costly |
190 | | // and at most 1 bit is leaked if it's false |
191 | 0 | bool fullValidate = (GetFieldType() == 2 && level >= 3) || !FastSubgroupCheckAvailable(); |
192 | |
|
193 | 0 | if (fullValidate && pass) |
194 | 0 | { |
195 | 0 | Integer gp = gpc ? gpc->Exponentiate(GetGroupPrecomputation(), q) : ExponentiateElement(g, q); |
196 | 0 | CRYPTOPP_ASSERT(IsIdentity(gp)); |
197 | 0 | pass = pass && IsIdentity(gp); |
198 | 0 | } |
199 | 0 | else if (GetFieldType() == 1) |
200 | 0 | { |
201 | 0 | CRYPTOPP_ASSERT(Jacobi(g, p) == 1); |
202 | 0 | pass = pass && Jacobi(g, p) == 1; |
203 | 0 | } |
204 | 0 | } |
205 | |
|
206 | 0 | return pass; |
207 | 0 | } |
208 | | |
209 | | void DL_GroupParameters_IntegerBased::GenerateRandom(RandomNumberGenerator &rng, const NameValuePairs &alg) |
210 | 0 | { |
211 | 0 | Integer p, q, g; |
212 | |
|
213 | 0 | if (alg.GetValue("Modulus", p) && alg.GetValue("SubgroupGenerator", g)) |
214 | 0 | { |
215 | 0 | q = alg.GetValueWithDefault("SubgroupOrder", ComputeGroupOrder(p)/2); |
216 | 0 | } |
217 | 0 | else |
218 | 0 | { |
219 | 0 | int modulusSize, subgroupOrderSize; |
220 | |
|
221 | 0 | if (!alg.GetIntValue("ModulusSize", modulusSize)) |
222 | 0 | modulusSize = alg.GetIntValueWithDefault("KeySize", 2048); |
223 | |
|
224 | 0 | if (!alg.GetIntValue("SubgroupOrderSize", subgroupOrderSize)) |
225 | 0 | subgroupOrderSize = GetDefaultSubgroupOrderSize(modulusSize); |
226 | |
|
227 | 0 | PrimeAndGenerator pg; |
228 | 0 | pg.Generate(GetFieldType() == 1 ? 1 : -1, rng, modulusSize, subgroupOrderSize); |
229 | 0 | p = pg.Prime(); |
230 | 0 | q = pg.SubPrime(); |
231 | 0 | g = pg.Generator(); |
232 | 0 | } |
233 | |
|
234 | 0 | Initialize(p, q, g); |
235 | 0 | } |
236 | | |
237 | | void DL_GroupParameters_IntegerBased::EncodeElement(bool reversible, const Element &element, byte *encoded) const |
238 | 0 | { |
239 | 0 | CRYPTOPP_UNUSED(reversible); |
240 | 0 | element.Encode(encoded, GetModulus().ByteCount()); |
241 | 0 | } |
242 | | |
243 | | unsigned int DL_GroupParameters_IntegerBased::GetEncodedElementSize(bool reversible) const |
244 | 0 | { |
245 | 0 | CRYPTOPP_UNUSED(reversible); |
246 | 0 | return GetModulus().ByteCount(); |
247 | 0 | } |
248 | | |
249 | | Integer DL_GroupParameters_IntegerBased::DecodeElement(const byte *encoded, bool checkForGroupMembership) const |
250 | 0 | { |
251 | 0 | CRYPTOPP_UNUSED(checkForGroupMembership); |
252 | 0 | Integer g(encoded, GetModulus().ByteCount()); |
253 | 0 | if (!ValidateElement(1, g, NULLPTR)) |
254 | 0 | throw DL_BadElement(); |
255 | 0 | return g; |
256 | 0 | } |
257 | | |
258 | | void DL_GroupParameters_IntegerBased::BERDecode(BufferedTransformation &bt) |
259 | 0 | { |
260 | 0 | BERSequenceDecoder parameters(bt); |
261 | 0 | Integer p(parameters); |
262 | 0 | Integer q(parameters); |
263 | 0 | Integer g; |
264 | 0 | if (parameters.EndReached()) |
265 | 0 | { |
266 | 0 | g = q; |
267 | 0 | q = ComputeGroupOrder(p) / 2; |
268 | 0 | } |
269 | 0 | else |
270 | 0 | g.BERDecode(parameters); |
271 | 0 | parameters.MessageEnd(); |
272 | |
|
273 | 0 | SetModulusAndSubgroupGenerator(p, g); |
274 | 0 | SetSubgroupOrder(q); |
275 | 0 | } |
276 | | |
277 | | void DL_GroupParameters_IntegerBased::DEREncode(BufferedTransformation &bt) const |
278 | 0 | { |
279 | 0 | DERSequenceEncoder parameters(bt); |
280 | 0 | GetModulus().DEREncode(parameters); |
281 | 0 | m_q.DEREncode(parameters); |
282 | 0 | GetSubgroupGenerator().DEREncode(parameters); |
283 | 0 | parameters.MessageEnd(); |
284 | 0 | } |
285 | | |
286 | | bool DL_GroupParameters_IntegerBased::GetVoidValue(const char *name, const std::type_info &valueType, void *pValue) const |
287 | 0 | { |
288 | 0 | return GetValueHelper<DL_GroupParameters<Element> >(this, name, valueType, pValue) |
289 | 0 | CRYPTOPP_GET_FUNCTION_ENTRY(Modulus); |
290 | 0 | } |
291 | | |
292 | | void DL_GroupParameters_IntegerBased::AssignFrom(const NameValuePairs &source) |
293 | 0 | { |
294 | 0 | AssignFromHelper(this, source) |
295 | 0 | CRYPTOPP_SET_FUNCTION_ENTRY2(Modulus, SubgroupGenerator) |
296 | 0 | CRYPTOPP_SET_FUNCTION_ENTRY(SubgroupOrder) |
297 | 0 | ; |
298 | 0 | } |
299 | | |
300 | | OID DL_GroupParameters_IntegerBased::GetAlgorithmID() const |
301 | 0 | { |
302 | 0 | return ASN1::id_dsa(); |
303 | 0 | } |
304 | | |
305 | | void DL_GroupParameters_GFP::SimultaneousExponentiate(Element *results, const Element &base, const Integer *exponents, unsigned int exponentsCount) const |
306 | 0 | { |
307 | 0 | ModularArithmetic ma(GetModulus()); |
308 | 0 | ma.SimultaneousExponentiate(results, base, exponents, exponentsCount); |
309 | 0 | } |
310 | | |
311 | | DL_GroupParameters_GFP::Element DL_GroupParameters_GFP::MultiplyElements(const Element &a, const Element &b) const |
312 | 0 | { |
313 | 0 | return a_times_b_mod_c(a, b, GetModulus()); |
314 | 0 | } |
315 | | |
316 | | DL_GroupParameters_GFP::Element DL_GroupParameters_GFP::CascadeExponentiate(const Element &element1, const Integer &exponent1, const Element &element2, const Integer &exponent2) const |
317 | 0 | { |
318 | 0 | ModularArithmetic ma(GetModulus()); |
319 | 0 | return ma.CascadeExponentiate(element1, exponent1, element2, exponent2); |
320 | 0 | } |
321 | | |
322 | | Integer DL_GroupParameters_IntegerBased::GetMaxExponent() const |
323 | 0 | { |
324 | 0 | return STDMIN(GetSubgroupOrder()-1, Integer::Power2(2*DiscreteLogWorkFactor(GetFieldType()*GetModulus().BitCount()))); |
325 | 0 | } |
326 | | |
327 | | unsigned int DL_GroupParameters_IntegerBased::GetDefaultSubgroupOrderSize(unsigned int modulusSize) const |
328 | 0 | { |
329 | 0 | return 2*DiscreteLogWorkFactor(GetFieldType()*modulusSize); |
330 | 0 | } |
331 | | |
332 | | NAMESPACE_END |
333 | | |
334 | | #endif |