1 | --- old-from_zaula_new_and_improved/pycryptopp/publickey/ecdsamodule.cpp 2009-03-02 14:23:06.000000000 -0700 |
---|
2 | +++ new-from_zaula_new_and_improved/pycryptopp/publickey/ecdsamodule.cpp 2009-03-02 14:23:09.000000000 -0700 |
---|
3 | @@ -1,9 +1,12 @@ |
---|
4 | /** |
---|
5 | * ecdsamodule.cpp -- Python wrappers around Crypto++'s |
---|
6 | - * ECDSA(1363)/EMSA1(SHA-256), more precisely: <a |
---|
7 | - * href="http://www.weidai.com/scan-mirror/sig.html#ECDSA">ECDSA</a> with GF(P) |
---|
8 | - * ("ECP") as the elliptic curve group parameters and SHA-256 as the hash |
---|
9 | - * function |
---|
10 | + * ECDSA(1363)/EMSA1(Tiger) -- <a |
---|
11 | + * href="http://www.weidai.com/scan-mirror/sig.html#ECDSA">ECDSA</a>. |
---|
12 | + * |
---|
13 | + * The keys (192-bit) use the curve ASN1::secp192r1() and Tiger as the hash |
---|
14 | + * function. There is a custom Key Derivation Protocol to generate private |
---|
15 | + * (signing) keys from unguessable seeds -- see source code for details and |
---|
16 | + * doc string for usage. |
---|
17 | */ |
---|
18 | |
---|
19 | #include <Python.h> |
---|
20 | @@ -19,37 +22,105 @@ |
---|
21 | #include "osrng.h" |
---|
22 | #include "eccrypto.h" |
---|
23 | #include "oids.h" |
---|
24 | +#include "tiger.h" |
---|
25 | +#include "sha.h" |
---|
26 | +#include "pubkey.h" |
---|
27 | + |
---|
28 | +// for _dump |
---|
29 | +#include <iostream> |
---|
30 | +#include "ecp.h" |
---|
31 | +#include "hex.h" |
---|
32 | + |
---|
33 | +/* The ECDSA key size that pycryptopp currently supports -- you should do your |
---|
34 | + own research, and I recommend http://keylength.com , but basically this is |
---|
35 | + probably secure for most purposes for at least the next few years, and |
---|
36 | + possibly for longer. */ |
---|
37 | +static const int SMALL_KEY_SIZE_BITS=192; |
---|
38 | |
---|
39 | USING_NAMESPACE(CryptoPP) |
---|
40 | |
---|
41 | PyDoc_STRVAR(ecdsa__doc__, |
---|
42 | -"ecdsa -- ECDSA(1363)/EMSA1(SHA-256) signatures\n\ |
---|
43 | +"ecdsa -- ECDSA(1363)/EMSA1(Tiger) signatures\n\ |
---|
44 | +\n\ |
---|
45 | +To create a new ECDSA signing key (deterministically from a 12-byte seed), construct an instance of the class, passing the seed as argument, i.e. SigningKey(seed). If you call serialize() on that instance, you'll get that seed back.\n\ |
---|
46 | \n\ |
---|
47 | -To create a new ECDSA signing key from the operating system's random number generator, call generate().\n\ |
---|
48 | -To deserialize an ECDSA signing key from a string, call create_signing_key_from_string().\n\ |
---|
49 | +To get a verifying key from a signing key, call get_verifying_key() on the signing key instance.\n\ |
---|
50 | \n\ |
---|
51 | -To get an ECDSA verifying key from an ECDSA signing key, call get_verifying_key() on the signing key.\n\ |
---|
52 | -To deserialize an ECDSA verifying key from a string, call create_verifying_key_from_string()."); |
---|
53 | +To deserialize an ECDSA verifying key from a string, call VerifyingKey(serialized_verifying_key)."); |
---|
54 | |
---|
55 | static PyObject *ecdsa_error; |
---|
56 | |
---|
57 | typedef struct { |
---|
58 | PyObject_HEAD |
---|
59 | - |
---|
60 | - /* internal */ |
---|
61 | - ECDSA<ECP, SHA256>::Verifier *k; |
---|
62 | + ECDSA<ECP, SHA1>::Verifier k; |
---|
63 | } VerifyingKey; |
---|
64 | |
---|
65 | PyDoc_STRVAR(VerifyingKey__doc__, |
---|
66 | "an ECDSA verifying key"); |
---|
67 | |
---|
68 | +struct VerifyingKey_type; |
---|
69 | +static PyObject* |
---|
70 | +VerifyingKey_alloc(PyTypeObject* typ, Py_ssize_t nitems) { |
---|
71 | + VerifyingKey* k = new VerifyingKey(); |
---|
72 | + if (!k) |
---|
73 | + return PyErr_NoMemory(); |
---|
74 | + |
---|
75 | + memset(k, 0, sizeof(PyObject)); |
---|
76 | + k->ob_refcnt = 1; |
---|
77 | + k->ob_type = typ; |
---|
78 | + |
---|
79 | + return reinterpret_cast<PyObject*>(k); |
---|
80 | +} |
---|
81 | + |
---|
82 | static void |
---|
83 | -VerifyingKey_dealloc(VerifyingKey* self) { |
---|
84 | - if (self->k) |
---|
85 | - delete self->k; |
---|
86 | - self->ob_type->tp_free((PyObject*)self); |
---|
87 | +VerifyingKey_free(void* self) { |
---|
88 | + delete reinterpret_cast<VerifyingKey*>(self); |
---|
89 | +} |
---|
90 | + |
---|
91 | +static PyObject * |
---|
92 | +VerifyingKey__dump(VerifyingKey *self, PyObject *dummy) { |
---|
93 | + const CryptoMaterial& x = self->k.GetMaterial(); |
---|
94 | + std::cout << x.GetValueNames(); |
---|
95 | + Py_RETURN_NONE; |
---|
96 | +} |
---|
97 | + |
---|
98 | +static int |
---|
99 | +VerifyingKey___init__(PyObject* self, PyObject* args, PyObject* kwdict) { |
---|
100 | + static const char *kwlist[] = { "serializedverifyingkey", NULL }; |
---|
101 | + const char *serializedverifyingkey; |
---|
102 | + Py_ssize_t serializedverifyingkeysize = 0; |
---|
103 | + |
---|
104 | + if (!PyArg_ParseTupleAndKeywords(args, kwdict, "t#:VerifyingKey__init__", const_cast<char**>(kwlist), &serializedverifyingkey, &serializedverifyingkeysize)) |
---|
105 | + return NULL; |
---|
106 | + assert (serializedverifyingkeysize >= 0); |
---|
107 | + |
---|
108 | + if (serializedverifyingkeysize != 25) { |
---|
109 | + PyErr_Format(ecdsa_error, "Precondition violation: size in bits is required to be %d (for %d-bit key), but it was %d", 25, SMALL_KEY_SIZE_BITS, serializedverifyingkeysize); |
---|
110 | + return -1; |
---|
111 | + } |
---|
112 | + |
---|
113 | + VerifyingKey *mself = reinterpret_cast<VerifyingKey*>(self); |
---|
114 | + |
---|
115 | + StringSource ss(reinterpret_cast<const byte*>(serializedverifyingkey), serializedverifyingkeysize, true); |
---|
116 | + |
---|
117 | + ECP::Element element; |
---|
118 | + DL_GroupParameters_EC<ECP> params(ASN1::secp192r1()); |
---|
119 | + params.SetPointCompression(true); |
---|
120 | + try { |
---|
121 | + element = params.DecodeElement(reinterpret_cast<const byte*>(serializedverifyingkey), true); |
---|
122 | + mself->k = ECDSA<ECP, SHA1>::Verifier(params, element); |
---|
123 | + } catch (InvalidDataFormat le) { |
---|
124 | + PyErr_Format(ecdsa_error, "Serialized verifying key was corrupted. Crypto++ gave this exception: %s", le.what()); |
---|
125 | + return -1; |
---|
126 | + } |
---|
127 | + |
---|
128 | + return 0; |
---|
129 | } |
---|
130 | |
---|
131 | +PyDoc_STRVAR(VerifyingKey__dump__doc__, |
---|
132 | + |
---|
133 | +"Print to stdout some descriptions of the math pieces."); |
---|
134 | + |
---|
135 | static PyObject * |
---|
136 | VerifyingKey_verify(VerifyingKey *self, PyObject *args, PyObject *kwdict) { |
---|
137 | static const char *kwlist[] = { "msg", "signature", NULL }; |
---|
138 | @@ -62,14 +133,7 @@ |
---|
139 | assert (msgsize >= 0); |
---|
140 | assert (signaturesize >= 0); |
---|
141 | |
---|
142 | - Py_ssize_t sigsize = self->k->SignatureLength(); |
---|
143 | - if (sigsize != signaturesize) |
---|
144 | - return PyErr_Format(ecdsa_error, "Precondition violation: signatures are required to be of size %zu, but it was %zu", sigsize, signaturesize); |
---|
145 | - assert (sigsize >= 0); |
---|
146 | - |
---|
147 | - assert (signaturesize == sigsize); |
---|
148 | - |
---|
149 | - if (self->k->VerifyMessage(reinterpret_cast<const byte*>(msg), msgsize, reinterpret_cast<const byte*>(signature), signaturesize)) |
---|
150 | + if (self->k.VerifyMessage(reinterpret_cast<const byte*>(msg), msgsize, reinterpret_cast<const byte*>(signature), signaturesize)) |
---|
151 | Py_RETURN_TRUE; |
---|
152 | else |
---|
153 | Py_RETURN_FALSE; |
---|
154 | @@ -80,14 +144,17 @@ |
---|
155 | |
---|
156 | static PyObject * |
---|
157 | VerifyingKey_serialize(VerifyingKey *self, PyObject *dummy) { |
---|
158 | - std::string outstr; |
---|
159 | - StringSink ss(outstr); |
---|
160 | - self->k->DEREncode(ss); |
---|
161 | - PyStringObject* result = reinterpret_cast<PyStringObject*>(PyString_FromStringAndSize(outstr.c_str(), outstr.size())); |
---|
162 | - if (!result) |
---|
163 | - return NULL; |
---|
164 | + const DL_PublicKey_EC<ECP>* pubkey; |
---|
165 | + pubkey = dynamic_cast<const DL_PublicKey_EC<ECP>*>(&(self->k.GetPublicKey())); |
---|
166 | + const DL_GroupParameters_EC<ECP>& params = pubkey->GetGroupParameters(); |
---|
167 | |
---|
168 | - return reinterpret_cast<PyObject*>(result); |
---|
169 | + Py_ssize_t len = params.GetEncodedElementSize(true); |
---|
170 | +// params.SetPointCompression(true); |
---|
171 | + PyObject* result = PyString_FromStringAndSize(NULL, len); |
---|
172 | + |
---|
173 | + params.EncodeElement(true, pubkey->GetPublicElement(), reinterpret_cast<byte*>(PyString_AS_STRING(result))); |
---|
174 | + |
---|
175 | + return result; |
---|
176 | } |
---|
177 | |
---|
178 | PyDoc_STRVAR(VerifyingKey_serialize__doc__, |
---|
179 | @@ -97,6 +164,7 @@ |
---|
180 | static PyMethodDef VerifyingKey_methods[] = { |
---|
181 | {"verify", reinterpret_cast<PyCFunction>(VerifyingKey_verify), METH_KEYWORDS, VerifyingKey_verify__doc__}, |
---|
182 | {"serialize", reinterpret_cast<PyCFunction>(VerifyingKey_serialize), METH_NOARGS, VerifyingKey_serialize__doc__}, |
---|
183 | + {"_dump", reinterpret_cast<PyCFunction>(VerifyingKey__dump), METH_NOARGS, VerifyingKey__dump__doc__}, |
---|
184 | {NULL}, |
---|
185 | }; |
---|
186 | |
---|
187 | @@ -106,7 +174,7 @@ |
---|
188 | "ecdsa.VerifyingKey", /*tp_name*/ |
---|
189 | sizeof(VerifyingKey), /*tp_basicsize*/ |
---|
190 | 0, /*tp_itemsize*/ |
---|
191 | - reinterpret_cast<destructor>(VerifyingKey_dealloc), /*tp_dealloc*/ |
---|
192 | + 0, /*tp_dealloc*/ |
---|
193 | 0, /*tp_print*/ |
---|
194 | 0, /*tp_getattr*/ |
---|
195 | 0, /*tp_setattr*/ |
---|
196 | @@ -123,42 +191,179 @@ |
---|
197 | 0, /*tp_as_buffer*/ |
---|
198 | Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/ |
---|
199 | VerifyingKey__doc__, /* tp_doc */ |
---|
200 | - 0, /* tp_traverse */ |
---|
201 | - 0, /* tp_clear */ |
---|
202 | - 0, /* tp_richcompare */ |
---|
203 | - 0, /* tp_weaklistoffset */ |
---|
204 | - 0, /* tp_iter */ |
---|
205 | - 0, /* tp_iternext */ |
---|
206 | + 0, /* tp_traverse */ |
---|
207 | + 0, /* tp_clear */ |
---|
208 | + 0, /* tp_richcompare */ |
---|
209 | + 0, /* tp_weaklistoffset */ |
---|
210 | + 0, /* tp_iter */ |
---|
211 | + 0, /* tp_iternext */ |
---|
212 | VerifyingKey_methods, /* tp_methods */ |
---|
213 | + 0, /* tp_members */ |
---|
214 | + 0, /* tp_getset */ |
---|
215 | + 0, /* tp_base */ |
---|
216 | + 0, /* tp_dict */ |
---|
217 | + 0, /* tp_descr_get */ |
---|
218 | + 0, /* tp_descr_set */ |
---|
219 | + 0, /* tp_dictoffset */ |
---|
220 | + VerifyingKey___init__, /* tp_init */ |
---|
221 | + VerifyingKey_alloc, /* tp_alloc */ |
---|
222 | + 0, /* tp_new */ |
---|
223 | + VerifyingKey_free /* tp_free */ |
---|
224 | }; |
---|
225 | |
---|
226 | -/** This function is only for internal use by ecdsamodule.cpp. */ |
---|
227 | -static VerifyingKey* |
---|
228 | -VerifyingKey_construct() { |
---|
229 | - VerifyingKey *self = reinterpret_cast<VerifyingKey*>(VerifyingKey_type.tp_alloc(&VerifyingKey_type, 0)); |
---|
230 | - if (!self) |
---|
231 | - return NULL; |
---|
232 | - self->k = NULL; |
---|
233 | - return self; |
---|
234 | -} |
---|
235 | - |
---|
236 | PyDoc_STRVAR(SigningKey__doc__, |
---|
237 | "an ECDSA signing key"); |
---|
238 | |
---|
239 | typedef struct { |
---|
240 | PyObject_HEAD |
---|
241 | - |
---|
242 | - /* internal */ |
---|
243 | - ECDSA<ECP, SHA256>::Signer *k; |
---|
244 | + ECDSA<ECP, SHA1>::Signer k; |
---|
245 | } SigningKey; |
---|
246 | |
---|
247 | +struct SigningKey_type; |
---|
248 | +static PyObject* |
---|
249 | +SigningKey_alloc(PyTypeObject* typ, Py_ssize_t nitems) { |
---|
250 | + SigningKey* k = new SigningKey(); |
---|
251 | + if (!k) |
---|
252 | + return PyErr_NoMemory(); |
---|
253 | + |
---|
254 | + memset(k, 0, sizeof(PyObject)); |
---|
255 | + k->ob_refcnt = 1; |
---|
256 | + k->ob_type = typ; |
---|
257 | + |
---|
258 | + return reinterpret_cast<PyObject*>(k); |
---|
259 | +} |
---|
260 | + |
---|
261 | static void |
---|
262 | -SigningKey_dealloc(SigningKey* self) { |
---|
263 | - if (self->k) |
---|
264 | - delete self->k; |
---|
265 | - self->ob_type->tp_free((PyObject*)self); |
---|
266 | +SigningKey_free(void* self) { |
---|
267 | + delete reinterpret_cast<SigningKey*>(self); |
---|
268 | } |
---|
269 | |
---|
270 | +static const char* TAG_AND_SALT = "102:pycryptopp v0.5.3 key derivation algorithm using Tiger hash to generate ECDSA 192-bit secret exponents," \ |
---|
271 | + "16:H1yGNvUONoc0FD1d,"; |
---|
272 | +static const size_t TAG_AND_SALT_len = 127; |
---|
273 | + |
---|
274 | +static int |
---|
275 | +SigningKey___init__(PyObject* self, PyObject* args, PyObject* kwdict) { |
---|
276 | + static const char *kwlist[] = { "seed", NULL }; |
---|
277 | + const char* seed; |
---|
278 | + int seedlen; |
---|
279 | + if (!PyArg_ParseTupleAndKeywords(args, kwdict, "t#:SigningKey___init__", const_cast<char**>(kwlist), &seed, &seedlen)) { |
---|
280 | + return -1; |
---|
281 | + } |
---|
282 | + |
---|
283 | + if (seedlen != 12) { |
---|
284 | + PyErr_Format(ecdsa_error, "Precondition violation: seed is required to be of length 12, but it was %d", seedlen); |
---|
285 | + return -1; |
---|
286 | + } |
---|
287 | + |
---|
288 | + OID curve; |
---|
289 | + Integer grouporderm1; |
---|
290 | + byte privexpbytes[24] = {0}; |
---|
291 | + Integer privexponentm1; |
---|
292 | + privexponentm1.Decode(privexpbytes, sizeof(privexpbytes)); assert (priveexponentm1 == 0); // just checking.. |
---|
293 | + |
---|
294 | + curve = ASN1::secp192r1(); |
---|
295 | + grouporderm1 = DL_GroupParameters_EC<ECP>(curve).GetGroupOrder() - 1; |
---|
296 | + Tiger t; |
---|
297 | + |
---|
298 | + t.Update(reinterpret_cast<const byte*>(TAG_AND_SALT), TAG_AND_SALT_len); |
---|
299 | + t.Update(reinterpret_cast<const byte*>(seed), seedlen); |
---|
300 | + t.TruncatedFinal(privexpbytes, Tiger::DIGESTSIZE); |
---|
301 | + privexponentm1.Decode(privexpbytes, sizeof(privexpbytes)); |
---|
302 | + |
---|
303 | + while (privexponentm1 >= grouporderm1) { |
---|
304 | + Tiger t2; |
---|
305 | + t2.Update(reinterpret_cast<const byte*>(TAG_AND_SALT), TAG_AND_SALT_len); |
---|
306 | + std::cerr << "WHEE " << sizeof(privexpbytes) << "\n";std::cerr.flush(); |
---|
307 | + t2.Update(privexpbytes, sizeof(privexpbytes)); |
---|
308 | + t2.TruncatedFinal(privexpbytes, Tiger::DIGESTSIZE); |
---|
309 | + privexponentm1.Decode(privexpbytes, sizeof(privexpbytes)); |
---|
310 | + } |
---|
311 | + |
---|
312 | + SigningKey* mself = reinterpret_cast<SigningKey*>(self); |
---|
313 | + mself->k.AccessKey().Initialize(curve, privexponentm1+1); |
---|
314 | + |
---|
315 | + return 0; |
---|
316 | +} |
---|
317 | + |
---|
318 | +PyDoc_STRVAR(SigningKey__init____doc__, |
---|
319 | +"Create a signing key (192 bits) deterministically from the given seed.\n\ |
---|
320 | +\n\ |
---|
321 | +This implies that if someone can guess the seed then they can learn the signing key. A good way to get an unguessable seed is os.urandom(12).\n\ |
---|
322 | +\n\ |
---|
323 | +@param seed seed\n\ |
---|
324 | +\n\ |
---|
325 | +@precondition len(seed) >= ceil(sizeinbits/16.0)"); |
---|
326 | + |
---|
327 | +static PyObject * |
---|
328 | +SigningKey__dump(SigningKey *self, PyObject *dummy) { |
---|
329 | + const DL_GroupParameters_EC<ECP>& gp = self->k.GetKey().GetGroupParameters(); |
---|
330 | + std::cout << "whee " << gp.GetEncodedElementSize(true) << "\a"; |
---|
331 | + std::cout << "booo " << gp.GetEncodedElementSize(false) << "\n"; |
---|
332 | + |
---|
333 | + ECPPoint p = gp.GetSubgroupGenerator(); |
---|
334 | + std::cout << "generator " << p.x << ", " << p.y << "\n"; |
---|
335 | + |
---|
336 | + std::cout << "GroupOrder: "; |
---|
337 | + std::cout << gp.GetGroupOrder(); |
---|
338 | + std::cout << "\n"; |
---|
339 | + |
---|
340 | + std::string s; |
---|
341 | + StringSink* ss = new StringSink(s); |
---|
342 | + HexEncoder he(ss); |
---|
343 | + std::cout << "AlgorithmID: "; |
---|
344 | + gp.GetAlgorithmID().DEREncode(he); |
---|
345 | + std::cout << s << "\n"; |
---|
346 | + |
---|
347 | + const ECP& ec = gp.GetCurve(); |
---|
348 | + Integer fieldsize = ec.FieldSize(); |
---|
349 | + std::cout << "field size " << fieldsize.BitCount() << " " << fieldsize.ByteCount() << " " << ec.FieldSize() << "\n"; |
---|
350 | + std::cout << "Curve: "; |
---|
351 | + std::cout << "curve field max element bit length: " << ec.GetField().MaxElementBitLength() << "\n"; |
---|
352 | + std::cout << "curve field modulus: " << ec.GetField().GetModulus() << "\n"; |
---|
353 | + std::cout << "curve A: " << ec.GetA() << ", curve B: " << ec.GetB(); |
---|
354 | + |
---|
355 | + const ECP::Field& f = ec.GetField(); |
---|
356 | + std::cout << "curve field modulus: " << f.GetModulus() << "\n"; |
---|
357 | + std::cout << "curve field identity: " << f.Identity() << "\n"; |
---|
358 | + |
---|
359 | + std::string cfs; |
---|
360 | + StringSink* cfss = new StringSink(cfs); |
---|
361 | + HexEncoder cfhe(cfss); |
---|
362 | + f.DEREncode(cfhe); |
---|
363 | + std::cout << "curve field derencoding: " << cfs << "\n"; |
---|
364 | + |
---|
365 | + const CryptoMaterial& cm = self->k.GetMaterial(); |
---|
366 | + Integer i; |
---|
367 | + cm.GetValue("SubgroupOrder", i); |
---|
368 | + std::cout << "\n"; |
---|
369 | + std::cout << "SubgroupOrder: "; |
---|
370 | + std::cout << i; |
---|
371 | + std::cout << "\n"; |
---|
372 | + ECP::Element e; |
---|
373 | + cm.GetValue("SubgroupGenerator", e); |
---|
374 | + std::cout << "SubgroupGenerator: "; |
---|
375 | + std::cout << e.x << ", " << e.y; |
---|
376 | + std::cout << "\n"; |
---|
377 | + |
---|
378 | + std::cout << "private key: "; |
---|
379 | + |
---|
380 | + const PrivateKey& privkey = self->k.GetPrivateKey(); |
---|
381 | + |
---|
382 | + std::cout << privkey.GetValueNames() << "\n"; |
---|
383 | + |
---|
384 | + Integer privi; |
---|
385 | + privkey.GetValue("PrivateExponent", privi); |
---|
386 | + std::cout << privi << "\n"; |
---|
387 | + std::cout << "numbits: " << privi.BitCount() << "\n"; |
---|
388 | + std::cout << "numbytes: " << privi.ByteCount() << "\n"; |
---|
389 | + |
---|
390 | + Py_RETURN_NONE; |
---|
391 | +} |
---|
392 | + |
---|
393 | +PyDoc_STRVAR(SigningKey__dump__doc__, |
---|
394 | +"Print to stdout some descriptions of the math pieces."); |
---|
395 | + |
---|
396 | static PyObject * |
---|
397 | SigningKey_sign(SigningKey *self, PyObject *msgobj) { |
---|
398 | const char *msg; |
---|
399 | @@ -166,22 +371,32 @@ |
---|
400 | PyString_AsStringAndSize(msgobj, const_cast<char**>(&msg), reinterpret_cast<Py_ssize_t*>(&msgsize)); |
---|
401 | assert (msgsize >= 0); |
---|
402 | |
---|
403 | - Py_ssize_t sigsize = self->k->SignatureLength(); |
---|
404 | + Py_ssize_t sigsize; |
---|
405 | + sigsize = self->k.SignatureLength(); |
---|
406 | + |
---|
407 | PyStringObject* result = reinterpret_cast<PyStringObject*>(PyString_FromStringAndSize(NULL, sigsize)); |
---|
408 | if (!result) |
---|
409 | return NULL; |
---|
410 | assert (sigsize >= 0); |
---|
411 | |
---|
412 | AutoSeededRandomPool randpool(false); |
---|
413 | - Py_ssize_t siglengthwritten = self->k->SignMessage( |
---|
414 | - randpool, |
---|
415 | - reinterpret_cast<const byte*>(msg), |
---|
416 | - msgsize, |
---|
417 | - reinterpret_cast<byte*>(PyString_AS_STRING(result))); |
---|
418 | + |
---|
419 | + Py_ssize_t siglengthwritten; |
---|
420 | + try { |
---|
421 | + siglengthwritten = self->k.SignMessage( |
---|
422 | + randpool, |
---|
423 | + reinterpret_cast<const byte*>(msg), |
---|
424 | + msgsize, |
---|
425 | + reinterpret_cast<byte*>(PyString_AS_STRING(result))); |
---|
426 | + } catch (InvalidDataFormat le) { |
---|
427 | + Py_DECREF(result); |
---|
428 | + return PyErr_Format(ecdsa_error, "Signing key was corrupted. Crypto++ gave this exception: %s", le.what()); |
---|
429 | + } |
---|
430 | + |
---|
431 | if (siglengthwritten < sigsize) |
---|
432 | fprintf(stderr, "%s: %d: %s: %s", __FILE__, __LINE__, "SigningKey_sign", "INTERNAL ERROR: signature was shorter than expected."); |
---|
433 | else if (siglengthwritten > sigsize) { |
---|
434 | - fprintf(stderr, "%s: %d: %s: %s", __FILE__, __LINE__, "SigningKey_sign", "INTERNAL ERROR: signature was longer than expected, so invalid memory was overwritten."); |
---|
435 | + fprintf(stderr, "%s: %d: %s: %s", __FILE__, __LINE__, "SigningKey_sign", "INTERNAL ERROR: signature was longer than expected, so memory was invalidly overwritten."); |
---|
436 | abort(); |
---|
437 | } |
---|
438 | assert (siglengthwritten >= 0); |
---|
439 | @@ -190,43 +405,30 @@ |
---|
440 | } |
---|
441 | |
---|
442 | PyDoc_STRVAR(SigningKey_sign__doc__, |
---|
443 | -"Return a signature on the argument."); |
---|
444 | + "Return a signature on the argument."); //XXX If randseed is not None then it is required to be an "); // XXX randseed! |
---|
445 | |
---|
446 | static PyObject * |
---|
447 | SigningKey_get_verifying_key(SigningKey *self, PyObject *dummy) { |
---|
448 | - VerifyingKey *verifier = reinterpret_cast<VerifyingKey*>(VerifyingKey_construct()); |
---|
449 | + VerifyingKey *verifier = PyObject_New(VerifyingKey, &VerifyingKey_type); |
---|
450 | + |
---|
451 | if (!verifier) |
---|
452 | return NULL; |
---|
453 | |
---|
454 | - verifier->k = new ECDSA<ECP, SHA256>::Verifier(*(self->k)); |
---|
455 | - if (!verifier->k) |
---|
456 | - return PyErr_NoMemory(); |
---|
457 | + ECDSA<ECP, SHA1>::Verifier* kp; |
---|
458 | + kp = new ECDSA<ECP, SHA1>::Verifier(self->k); |
---|
459 | + |
---|
460 | + verifier->k = (*kp); |
---|
461 | + |
---|
462 | return reinterpret_cast<PyObject*>(verifier); |
---|
463 | } |
---|
464 | |
---|
465 | PyDoc_STRVAR(SigningKey_get_verifying_key__doc__, |
---|
466 | "Return the corresponding verifying key."); |
---|
467 | |
---|
468 | -static PyObject * |
---|
469 | -SigningKey_serialize(SigningKey *self, PyObject *dummy) { |
---|
470 | - Py_ssize_t len = self->k->GetKey().GetGroupParameters().GetSubgroupOrder().ByteCount(); |
---|
471 | - PyObject* result = PyString_FromStringAndSize(NULL, len); |
---|
472 | - |
---|
473 | - const DL_PrivateKey_EC<ECP>& privkey = dynamic_cast<const DL_PrivateKey_EC<ECP>&>(self->k->GetPrivateKey()); |
---|
474 | - |
---|
475 | - privkey.GetPrivateExponent().Encode(reinterpret_cast<byte*>(PyString_AS_STRING(result)), len); |
---|
476 | - |
---|
477 | - return result; |
---|
478 | -} |
---|
479 | - |
---|
480 | -PyDoc_STRVAR(SigningKey_serialize__doc__, |
---|
481 | -"Return a string containing the key material. The string can be passed to \n\ |
---|
482 | -create_signing_key_from_string() to instantiate a new copy of this key."); |
---|
483 | - |
---|
484 | static PyMethodDef SigningKey_methods[] = { |
---|
485 | {"sign", reinterpret_cast<PyCFunction>(SigningKey_sign), METH_O, SigningKey_sign__doc__}, |
---|
486 | + {"_dump", reinterpret_cast<PyCFunction>(SigningKey__dump), METH_NOARGS, SigningKey__dump__doc__}, |
---|
487 | {"get_verifying_key", reinterpret_cast<PyCFunction>(SigningKey_get_verifying_key), METH_NOARGS, SigningKey_get_verifying_key__doc__}, |
---|
488 | - {"serialize", reinterpret_cast<PyCFunction>(SigningKey_serialize), METH_NOARGS, SigningKey_serialize__doc__}, |
---|
489 | {NULL}, |
---|
490 | }; |
---|
491 | |
---|
492 | @@ -236,7 +438,7 @@ |
---|
493 | "ecdsa.SigningKey", /*tp_name*/ |
---|
494 | sizeof(SigningKey), /*tp_basicsize*/ |
---|
495 | 0, /*tp_itemsize*/ |
---|
496 | - (destructor)SigningKey_dealloc, /*tp_dealloc*/ |
---|
497 | + 0, /*tp_dealloc*/ |
---|
498 | 0, /*tp_print*/ |
---|
499 | 0, /*tp_getattr*/ |
---|
500 | 0, /*tp_setattr*/ |
---|
501 | @@ -251,143 +453,34 @@ |
---|
502 | 0, /*tp_getattro*/ |
---|
503 | 0, /*tp_setattro*/ |
---|
504 | 0, /*tp_as_buffer*/ |
---|
505 | - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/ |
---|
506 | - SigningKey__doc__, /* tp_doc */ |
---|
507 | - 0, /* tp_traverse */ |
---|
508 | - 0, /* tp_clear */ |
---|
509 | - 0, /* tp_richcompare */ |
---|
510 | - 0, /* tp_weaklistoffset */ |
---|
511 | - 0, /* tp_iter */ |
---|
512 | - 0, /* tp_iternext */ |
---|
513 | - SigningKey_methods /* tp_methods */ |
---|
514 | + Py_TPFLAGS_DEFAULT, /*tp_flags*/ |
---|
515 | + SigningKey__doc__, /* tp_doc */ |
---|
516 | + 0, /* tp_traverse */ |
---|
517 | + 0, /* tp_clear */ |
---|
518 | + 0, /* tp_richcompare */ |
---|
519 | + 0, /* tp_weaklistoffset */ |
---|
520 | + 0, /* tp_iter */ |
---|
521 | + 0, /* tp_iternext */ |
---|
522 | + SigningKey_methods, /* tp_methods */ |
---|
523 | + 0, /* tp_members */ |
---|
524 | + 0, /* tp_getset */ |
---|
525 | + 0, /* tp_base */ |
---|
526 | + 0, /* tp_dict */ |
---|
527 | + 0, /* tp_descr_get */ |
---|
528 | + 0, /* tp_descr_set */ |
---|
529 | + 0, /* tp_dictoffset */ |
---|
530 | + SigningKey___init__, /* tp_init */ |
---|
531 | + SigningKey_alloc, /* tp_alloc */ |
---|
532 | + 0, /* tp_new */ |
---|
533 | + SigningKey_free /* tp_free */ |
---|
534 | }; |
---|
535 | |
---|
536 | -/** This function is only for internal use by ecdsamodule.cpp. */ |
---|
537 | -static SigningKey* |
---|
538 | -SigningKey_construct() { |
---|
539 | - SigningKey *self = reinterpret_cast<SigningKey*>(SigningKey_type.tp_alloc(&SigningKey_type, 0)); |
---|
540 | - if (!self) |
---|
541 | - return NULL; |
---|
542 | - self->k = NULL; |
---|
543 | - return self; |
---|
544 | -} |
---|
545 | - |
---|
546 | -/* The smaller ECDSA key size that pycryptopp supports -- you should do your |
---|
547 | - own research, and I recommend http://keylength.com , but basically this is |
---|
548 | - probably secure for most purposes for at least the next few years, and |
---|
549 | - possibly for longer. */ |
---|
550 | -static const int SMALL_KEY_SIZE_BITS=192; |
---|
551 | - |
---|
552 | -/* The larger ECDSA key size that pycryptopp supports -- you should do your |
---|
553 | - own research, and I recommend http://keylength.com , but basically this is |
---|
554 | - probably secure for many years, unless there is a surprising breakthrough in |
---|
555 | - the theory of elliptic curve cryptography. */ |
---|
556 | -static const int LARGE_KEY_SIZE_BITS=521; |
---|
557 | - |
---|
558 | -static PyObject * |
---|
559 | -generate(PyObject *dummy, PyObject *args, PyObject *kwdict) { |
---|
560 | - static const char *kwlist[] = { |
---|
561 | - "sizeinbits", |
---|
562 | - NULL |
---|
563 | - }; |
---|
564 | - int sizeinbits; |
---|
565 | - |
---|
566 | - if (!PyArg_ParseTupleAndKeywords(args, kwdict, "i:generate", const_cast<char**>(kwlist), &sizeinbits)) |
---|
567 | - return NULL; |
---|
568 | - |
---|
569 | - if (sizeinbits != SMALL_KEY_SIZE_BITS && sizeinbits != LARGE_KEY_SIZE_BITS) |
---|
570 | - return PyErr_Format(ecdsa_error, "Precondition violation: size in bits is required to be either %d or %d, but it was %d", SMALL_KEY_SIZE_BITS, LARGE_KEY_SIZE_BITS, sizeinbits); |
---|
571 | - |
---|
572 | - AutoSeededRandomPool osrng(false); |
---|
573 | - SigningKey *signer = SigningKey_construct(); |
---|
574 | - if (!signer) |
---|
575 | - return NULL; |
---|
576 | - |
---|
577 | - OID curve; |
---|
578 | - if (sizeinbits == 192) |
---|
579 | - curve = ASN1::secp192r1(); |
---|
580 | - else |
---|
581 | - curve = ASN1::secp521r1(); |
---|
582 | - |
---|
583 | - signer->k = new ECDSA<ECP, SHA256>::Signer(osrng, curve); |
---|
584 | - if (!signer->k) |
---|
585 | - return PyErr_NoMemory(); |
---|
586 | - return reinterpret_cast<PyObject*>(signer); |
---|
587 | -} |
---|
588 | - |
---|
589 | -PyDoc_STRVAR(generate__doc__, |
---|
590 | -"Create a signing key using the operating system's random number generator.\n\ |
---|
591 | -\n\ |
---|
592 | -@param sizeinbits size of the key in bits\n\ |
---|
593 | -\n\ |
---|
594 | -@precondition sizeinbits in (192, 521)"); |
---|
595 | - |
---|
596 | -static PyObject * |
---|
597 | -create_verifying_key_from_string(PyObject *dummy, PyObject *args, PyObject *kwdict) { |
---|
598 | - static const char *kwlist[] = { |
---|
599 | - "serializedverifyingkey", |
---|
600 | - NULL |
---|
601 | - }; |
---|
602 | - const char *serializedverifyingkey; |
---|
603 | - Py_ssize_t serializedverifyingkeysize = 0; |
---|
604 | - |
---|
605 | - if (!PyArg_ParseTupleAndKeywords(args, kwdict, "t#:create_verifying_key_from_string", const_cast<char**>(kwlist), &serializedverifyingkey, &serializedverifyingkeysize)) |
---|
606 | - return NULL; |
---|
607 | - assert (serializedverifyingkeysize >= 0); |
---|
608 | - |
---|
609 | - VerifyingKey *verifier = reinterpret_cast<VerifyingKey*>(VerifyingKey_construct()); |
---|
610 | - if (!verifier) |
---|
611 | - return NULL; |
---|
612 | - StringSource ss(reinterpret_cast<const byte*>(serializedverifyingkey), serializedverifyingkeysize, true); |
---|
613 | - |
---|
614 | - verifier->k = new ECDSA<ECP, SHA256>::Verifier(ss); |
---|
615 | - if (!verifier->k) |
---|
616 | - return PyErr_NoMemory(); |
---|
617 | - return reinterpret_cast<PyObject*>(verifier); |
---|
618 | -} |
---|
619 | - |
---|
620 | PyDoc_STRVAR(create_verifying_key_from_string__doc__, |
---|
621 | -"Create a verifying key from its serialized state."); |
---|
622 | - |
---|
623 | -static PyObject * |
---|
624 | -create_signing_key_from_string(PyObject *dummy, PyObject *args, PyObject *kwdict) { |
---|
625 | - static const char *kwlist[] = { |
---|
626 | - "serializedsigningkey", |
---|
627 | - NULL |
---|
628 | - }; |
---|
629 | - const char *serializedsigningkey; |
---|
630 | - Py_ssize_t serializedsigningkeysize = 0; |
---|
631 | - |
---|
632 | - if (!PyArg_ParseTupleAndKeywords(args, kwdict, "t#:create_signing_key_from_string", const_cast<char**>(kwlist), &serializedsigningkey, &serializedsigningkeysize)) |
---|
633 | - return NULL; |
---|
634 | - if (serializedsigningkeysize != 24 && serializedsigningkeysize != 66) |
---|
635 | - return PyErr_Format(ecdsa_error, "Precondition violation: size in bytes of the serialized signing key is required to be either %d (for %d-bit keys) or %d (for %d-bit keys), but it was %d", 24, SMALL_KEY_SIZE_BITS, 66, LARGE_KEY_SIZE_BITS, serializedsigningkeysize); |
---|
636 | - |
---|
637 | - |
---|
638 | - SigningKey *verifier = SigningKey_construct(); |
---|
639 | - if (!verifier) |
---|
640 | - return NULL; |
---|
641 | - |
---|
642 | - OID curve; |
---|
643 | - if (serializedsigningkeysize == 24) |
---|
644 | - curve = ASN1::secp192r1(); |
---|
645 | - else |
---|
646 | - curve = ASN1::secp521r1(); |
---|
647 | - Integer privexponent(reinterpret_cast<const byte*>(serializedsigningkey), serializedsigningkeysize); |
---|
648 | - |
---|
649 | - verifier->k = new ECDSA<ECP, SHA256>::Signer(curve, privexponent); |
---|
650 | - if (!verifier->k) |
---|
651 | - return PyErr_NoMemory(); |
---|
652 | - return reinterpret_cast<PyObject*>(verifier); |
---|
653 | -} |
---|
654 | - |
---|
655 | -PyDoc_STRVAR(create_signing_key_from_string__doc__, |
---|
656 | -"Create a signing key from its serialized state."); |
---|
657 | +"Create a verifying key from its serialized state.\n\ |
---|
658 | +\n\ |
---|
659 | +@precondition Length of serialized key is required to be 24 (for 192-bit key)."); //XXX actually 25 length |
---|
660 | |
---|
661 | static PyMethodDef ecdsa_functions[] = { |
---|
662 | - {"generate", reinterpret_cast<PyCFunction>(generate), METH_KEYWORDS, generate__doc__}, |
---|
663 | - {"create_verifying_key_from_string", reinterpret_cast<PyCFunction>(create_verifying_key_from_string), METH_KEYWORDS, create_verifying_key_from_string__doc__}, |
---|
664 | - {"create_signing_key_from_string", reinterpret_cast<PyCFunction>(create_signing_key_from_string), METH_KEYWORDS, create_signing_key_from_string__doc__}, |
---|
665 | {NULL, NULL, 0, NULL} /* sentinel */ |
---|
666 | }; |
---|
667 | |
---|
668 | @@ -399,8 +492,10 @@ |
---|
669 | PyObject *module; |
---|
670 | PyObject *module_dict; |
---|
671 | |
---|
672 | + VerifyingKey_type.tp_new = PyType_GenericNew; |
---|
673 | if (PyType_Ready(&VerifyingKey_type) < 0) |
---|
674 | return; |
---|
675 | + SigningKey_type.tp_new = PyType_GenericNew; |
---|
676 | if (PyType_Ready(&SigningKey_type) < 0) |
---|
677 | return; |
---|
678 | |
---|
679 | diff -rN -u old-from_zaula_new_and_improved/pycryptopp/test/test_ecdsa.py new-from_zaula_new_and_improved/pycryptopp/test/test_ecdsa.py |
---|
680 | --- old-from_zaula_new_and_improved/pycryptopp/test/test_ecdsa.py 2009-03-02 14:23:06.000000000 -0700 |
---|
681 | +++ new-from_zaula_new_and_improved/pycryptopp/test/test_ecdsa.py 2009-03-02 14:23:09.000000000 -0700 |
---|
682 | @@ -2,10 +2,39 @@ |
---|
683 | |
---|
684 | import random |
---|
685 | |
---|
686 | +import os |
---|
687 | +SEED = os.environ.get('REPEATABLE_RANDOMNESS_SEED', None) |
---|
688 | + |
---|
689 | +if SEED is None: |
---|
690 | + # Generate a seed which is fairly short (to ease cut-and-paste, writing it |
---|
691 | + # down, etc.). Note that Python's random module's seed() function is going |
---|
692 | + # to take the hash() of this seed, which is a 32-bit value (currently) so |
---|
693 | + # there is no point in making this seed larger than 32 bits. Make it 30 |
---|
694 | + # bits, which conveniently fits into six base-32 chars. Include a separator |
---|
695 | + # because chunking facilitates memory (including working and short-term |
---|
696 | + # memory) in humans. |
---|
697 | + chars = "ybndrfg8ejkmcpqxot1uwisza345h769" # Zooko's choice, rationale in "DESIGN" doc in z-base-32 project |
---|
698 | + SEED = ''.join([random.choice(chars) for x in range(3)] + ['-'] + [random.choice(chars) for x in range(3)]) |
---|
699 | + |
---|
700 | +import logging |
---|
701 | +logging.info("REPEATABLE_RANDOMNESS_SEED: %s\n" % SEED) |
---|
702 | +logging.info("In order to reproduce this run of the code, set the environment variable \"REPEATABLE_RANDOMNESS_SEED\" to %s before executing.\n" % SEED) |
---|
703 | +random.seed(SEED) |
---|
704 | + |
---|
705 | +def seed_which_refuses(a): |
---|
706 | + logging.warn("I refuse to reseed to %s -- I already seeded with %s.\n" % (a, SEED,)) |
---|
707 | + return |
---|
708 | +random.seed = seed_which_refuses |
---|
709 | + |
---|
710 | +from random import randrange |
---|
711 | + |
---|
712 | import unittest |
---|
713 | |
---|
714 | from pycryptopp.publickey import ecdsa |
---|
715 | |
---|
716 | +def randstr(n, rr=randrange): |
---|
717 | + return ''.join([chr(rr(0, 256)) for x in xrange(n)]) |
---|
718 | + |
---|
719 | from base64 import b32encode |
---|
720 | def ab(x): # debuggery |
---|
721 | if len(x) >= 3: |
---|
722 | @@ -17,102 +46,186 @@ |
---|
723 | elif len(x) == 0: |
---|
724 | return "%s:%s" % (len(x), "--empty--",) |
---|
725 | |
---|
726 | -def randstr(n): |
---|
727 | - return ''.join(map(chr, map(random.randrange, [0]*n, [256]*n))) |
---|
728 | +def div_ceil(n, d): |
---|
729 | + """ |
---|
730 | + The smallest integer k such that k*d >= n. |
---|
731 | + """ |
---|
732 | + return (n/d) + (n%d != 0) |
---|
733 | + |
---|
734 | +KEYBITS=192 |
---|
735 | + |
---|
736 | +# The number of bytes required for a seed to have the same security level as a |
---|
737 | +# key in this elliptic curve: 2 bits of public key per bit of security. |
---|
738 | +SEEDBITS=div_ceil(192, 2) |
---|
739 | +SEEDBYTES=div_ceil(SEEDBITS, 8) |
---|
740 | + |
---|
741 | +# The number of bytes required to encode a public key in this elliptic curve. |
---|
742 | +PUBKEYBYTES=div_ceil(KEYBITS, 8)+1 # 1 byte for the sign of the y component |
---|
743 | + |
---|
744 | +# The number of bytes requires to encode a signature in this elliptic curve. |
---|
745 | +SIGBITS=KEYBITS*2 |
---|
746 | +SIGBYTES=div_ceil(SIGBITS, 8) |
---|
747 | |
---|
748 | -KEYSIZE=192 # The choices are 192 or 521 -- they are both secure, and 192 makes for faster unit tests. |
---|
749 | class Signer(unittest.TestCase): |
---|
750 | - def test_generate_bad_size(self): |
---|
751 | + def test_construct_from_same_seed_is_reproducible(self): |
---|
752 | + seed = randstr(SEEDBYTES) |
---|
753 | + signer1 = ecdsa.SigningKey(seed) |
---|
754 | + self.failUnlessEqual(signer1.serialize(), seed) |
---|
755 | + signer2 = ecdsa.SigningKey(seed) |
---|
756 | + self.failUnlessEqual(signer1.serialize(), signer2.serialize()) |
---|
757 | + self.failUnlessEqual(signer1.get_verifying_key().serialize(), signer2.get_verifying_key().serialize()) |
---|
758 | + |
---|
759 | + # ... and using different seeds constructs a different private key. |
---|
760 | + seed3 = randstr(SEEDBYTES) |
---|
761 | + assert seed3 != seed, "Internal error in Python random module's PRNG (or in pycryptopp's hacks to it to facilitate testing) -- got two identical strings from randstr(%s)" % SEEDBYTES |
---|
762 | + signer3 = ecdsa.SigningKey(seed3) |
---|
763 | + self.failUnlessEqual(signer3.serialize(), seed3) |
---|
764 | + self.failUnlessEqual(signer1.serialize(), signer3.serialize()) |
---|
765 | + self.failIfEqual(signer1.get_verifying_key().serialize(), signer3.get_verifying_key().serialize()) |
---|
766 | + |
---|
767 | + # Also try the all-zeroes string just because bugs sometimes are |
---|
768 | + # data-dependent on zero or cause bogus zeroes. |
---|
769 | + seed4 = '\x00'*SEEDBYTES |
---|
770 | + assert seed4 != seed, "Internal error in Python random module's PRNG (or in pycryptopp's hacks to it to facilitate testing) -- got the all-zeroes string from randstr(%s)" % SEEDBYTES |
---|
771 | + signer4 = ecdsa.SigningKey(seed4) |
---|
772 | + self.failUnlessEqual(signer4.serialize(), seed4) |
---|
773 | + self.failUnlessEqual(signer4.serialize(), signer1.serialize()) |
---|
774 | + self.failIfEqual(signer4.get_verifying_key().serialize(), signer1.get_verifying_key().serialize()) |
---|
775 | + |
---|
776 | + signer5 = ecdsa.SigningKey(seed4) |
---|
777 | + self.failUnlessEqual(signer5.serialize(), seed4) |
---|
778 | + self.failUnlessEqual(signer5.serialize(), signer4.serialize()) |
---|
779 | + self.failUnlessEqual(signer5.get_verifying_key().serialize(), signer4.get_verifying_key().serialize()) |
---|
780 | + |
---|
781 | + def test_construct_short_seed(self): |
---|
782 | try: |
---|
783 | - signer = ecdsa.generate(KEYSIZE-1) |
---|
784 | + signer = ecdsa.SigningKey("\x00\x00\x00") |
---|
785 | except ecdsa.Error, le: |
---|
786 | - self.failUnless("size in bits is required to be " in str(le), le) |
---|
787 | + self.failUnless("seed is required to be of length >=" in str(le), le) |
---|
788 | else: |
---|
789 | - self.fail("Should have raised error from size being too small.") |
---|
790 | + self.fail("Should have raised error from seed being too short.") |
---|
791 | + |
---|
792 | + def test_construct_bad_arg_type(self): |
---|
793 | try: |
---|
794 | - signer = ecdsa.generate(sizeinbits=KEYSIZE-1) |
---|
795 | - except ecdsa.Error, le: |
---|
796 | - self.failUnless("size in bits is required to be " in str(le), le) |
---|
797 | + signer = ecdsa.SigningKey(1) |
---|
798 | + except TypeError, le: |
---|
799 | + self.failUnless("must be string" in str(le), le) |
---|
800 | else: |
---|
801 | - self.fail("Should have raised error from size being too small.") |
---|
802 | + self.fail("Should have raised error from seed being of the wrong type.") |
---|
803 | |
---|
804 | - def test_generate(self): |
---|
805 | - signer = ecdsa.generate(KEYSIZE) |
---|
806 | - # Hooray! It didn't raise an exception! We win! |
---|
807 | - signer = ecdsa.generate(sizeinbits=KEYSIZE) |
---|
808 | - # Hooray! It didn't raise an exception! We win! |
---|
809 | - |
---|
810 | - def test_sign(self): |
---|
811 | - signer = ecdsa.generate(KEYSIZE) |
---|
812 | - result = signer.sign("abc") |
---|
813 | - self.failUnlessEqual(len(result), 2*((KEYSIZE+7)/8)) |
---|
814 | - # TODO: test against someone's official test vectors. |
---|
815 | +class Verifier(unittest.TestCase): |
---|
816 | + def test_from_signer_and_serialize_and_deserialize(self): |
---|
817 | + seed = randstr(SEEDBYTES) |
---|
818 | + signer = ecdsa.SigningKey(seed) |
---|
819 | + |
---|
820 | + verifier = signer.get_verifying_key() |
---|
821 | + s1 = verifier.serialize() |
---|
822 | + self.failUnlessEqual(len(s1), PUBKEYBYTES) |
---|
823 | + verifier2 = ecdsa.create_verifying_key_from_string(s1) |
---|
824 | + s2 = verifier.serialize() |
---|
825 | + self.failUnlessEqual(s1, s2) |
---|
826 | + |
---|
827 | +def flip_one_bit(s): |
---|
828 | + i = randrange(0, len(s)) |
---|
829 | + result = s[:i] + chr(ord(s[i])^(0x01<<randrange(0, 8))) + s[i+1:] |
---|
830 | + assert result != s, "Internal error -- flip_one_bit() produced the same string as its input: %s == %s" % (result, s) |
---|
831 | + return result |
---|
832 | + |
---|
833 | +def randmsg(): |
---|
834 | + # Choose a random message size from a range probably large enough to |
---|
835 | + # exercise any different code paths which depend on the message length. |
---|
836 | + randmsglen = randrange(0, SIGBYTES*2+2) |
---|
837 | + return randstr(randmsglen) |
---|
838 | |
---|
839 | class SignAndVerify(unittest.TestCase): |
---|
840 | - def _help_test_sign_and_check(self, signer, verifier, msg): |
---|
841 | + def _help_test_sign_and_check_good_keys(self, signer, verifier): |
---|
842 | + msg = randmsg() |
---|
843 | + |
---|
844 | sig = signer.sign(msg) |
---|
845 | - self.failUnlessEqual(len(sig), 2*((KEYSIZE+7)/8)) |
---|
846 | + self.failUnlessEqual(len(sig), SIGBYTES) |
---|
847 | self.failUnless(verifier.verify(msg, sig)) |
---|
848 | |
---|
849 | - def test_sign_and_check_a(self): |
---|
850 | - signer = ecdsa.generate(KEYSIZE) |
---|
851 | - verifier = signer.get_verifying_key() |
---|
852 | - return self._help_test_sign_and_check(signer, verifier, "a") |
---|
853 | - |
---|
854 | - def _help_test_sign_and_check_random(self, signer, verifier): |
---|
855 | - for i in range(3): |
---|
856 | - l = random.randrange(0, 2**10) |
---|
857 | - msg = randstr(l) |
---|
858 | - self._help_test_sign_and_check(signer, verifier, msg) |
---|
859 | - |
---|
860 | - def test_sign_and_check_random(self): |
---|
861 | - signer = ecdsa.generate(KEYSIZE) |
---|
862 | - verifier = signer.get_verifying_key() |
---|
863 | - return self._help_test_sign_and_check_random(signer, verifier) |
---|
864 | - |
---|
865 | - def _help_test_sign_and_failcheck(self, signer, verifier, msg): |
---|
866 | - sig = signer.sign("a") |
---|
867 | - sig = sig[:-1] + chr(ord(sig[-1])^0x01) |
---|
868 | - self.failUnless(not verifier.verify(msg, sig)) |
---|
869 | + # Now flip one bit of the signature and make sure that the signature doesn't check. |
---|
870 | + badsig = flip_one_bit(sig) |
---|
871 | + self.failIf(verifier.verify(msg, badsig)) |
---|
872 | + |
---|
873 | + # Now generate a random signature and make sure that the signature doesn't check. |
---|
874 | + badsig = randstr(len(sig)) |
---|
875 | + assert badsig != sig, "Internal error -- randstr() produced the same string twice: %s == %s" % (badsig, sig) |
---|
876 | + self.failIf(verifier.verify(msg, badsig)) |
---|
877 | + |
---|
878 | + # Now flip one bit of the message and make sure that the original signature doesn't check. |
---|
879 | + badmsg = flip_one_bit(msg) |
---|
880 | + self.failIf(verifier.verify(badmsg, sig)) |
---|
881 | + |
---|
882 | + # Now generate a random message and make sure that the original signature doesn't check. |
---|
883 | + badmsg = randstr(len(msg)) |
---|
884 | + assert badmsg != msg, "Internal error -- randstr() produced the same string twice: %s == %s" % (badmsg, msg) |
---|
885 | + self.failIf(verifier.verify(badmsg, sig)) |
---|
886 | + |
---|
887 | + def _help_test_sign_and_check_bad_keys(self, signer, verifier): |
---|
888 | + """ |
---|
889 | + Make sure that this signer/verifier pair cannot produce and verify signatures. |
---|
890 | + """ |
---|
891 | + msg = randmsg() |
---|
892 | |
---|
893 | - def test_sign_and_failcheck_a(self): |
---|
894 | - signer = ecdsa.generate(KEYSIZE) |
---|
895 | - verifier = signer.get_verifying_key() |
---|
896 | - return self._help_test_sign_and_failcheck(signer, verifier, "a") |
---|
897 | - |
---|
898 | - def _help_test_sign_and_failcheck_random(self, signer, verifier): |
---|
899 | - for i in range(3): |
---|
900 | - l = random.randrange(0, 2**10) |
---|
901 | - msg = randstr(l) |
---|
902 | - self._help_test_sign_and_failcheck(signer, verifier, msg) |
---|
903 | + sig = signer.sign(msg) |
---|
904 | + self.failUnlessEqual(len(sig), SIGBYTES) |
---|
905 | + self.failIf(verifier.verify(msg, sig)) |
---|
906 | |
---|
907 | - def test_sign_and_failcheck_random(self): |
---|
908 | - signer = ecdsa.generate(KEYSIZE) |
---|
909 | - verifier = signer.get_verifying_key() |
---|
910 | - return self._help_test_sign_and_failcheck_random(signer, verifier) |
---|
911 | + def test(self): |
---|
912 | + seed = randstr(SEEDBYTES) |
---|
913 | + sys.stdout.write("xxx 0\n");sys.stdout.flush() |
---|
914 | + signer = ecdsa.SigningKey(seed) |
---|
915 | + sys.stdout.write("xxx 1\n");sys.stdout.flush() |
---|
916 | + verifier = signer.get_verifying_key() |
---|
917 | + sys.stdout.write("xxx 2\n");sys.stdout.flush() |
---|
918 | + self._help_test_sign_and_check_good_keys(signer, verifier) |
---|
919 | + sys.stdout.write("xxx 3\n");sys.stdout.flush() |
---|
920 | + |
---|
921 | + vstr = verifier.serialize() |
---|
922 | + verifier2 = ecdsa.create_verifying_key_from_string(vstr) |
---|
923 | + self._help_test_sign_and_check_good_keys(signer, verifier2) |
---|
924 | + |
---|
925 | + signer2 = ecdsa.SigningKey(seed) |
---|
926 | + self._help_test_sign_and_check_good_keys(signer2, verifier2) |
---|
927 | + |
---|
928 | + verifier3 = signer2.get_verifying_key() |
---|
929 | + self._help_test_sign_and_check_good_keys(signer, verifier3) |
---|
930 | |
---|
931 | - def test_serialize_and_deserialize_verifying_key_and_test(self): |
---|
932 | - signer = ecdsa.generate(KEYSIZE) |
---|
933 | - verifier = signer.get_verifying_key() |
---|
934 | - serstr = verifier.serialize() |
---|
935 | - verifier = None |
---|
936 | - newverifier = ecdsa.create_verifying_key_from_string(serstr) |
---|
937 | - self._help_test_sign_and_check(signer, newverifier, "a") |
---|
938 | - self._help_test_sign_and_check_random(signer, newverifier) |
---|
939 | - self._help_test_sign_and_failcheck(signer, newverifier, "a") |
---|
940 | - self._help_test_sign_and_failcheck_random(signer, newverifier) |
---|
941 | + # Now test various ways that the keys could be corrupted or ill-matched. |
---|
942 | |
---|
943 | - def test_serialize_and_deserialize_signing_key_and_test(self): |
---|
944 | - signer = ecdsa.generate(KEYSIZE) |
---|
945 | - verifier = signer.get_verifying_key() |
---|
946 | - serstr = signer.serialize() |
---|
947 | - signer = None |
---|
948 | - newsigner = ecdsa.create_signing_key_from_string(serstr) |
---|
949 | - self._help_test_sign_and_check(newsigner, verifier, "a") |
---|
950 | - self._help_test_sign_and_check_random(newsigner, verifier) |
---|
951 | - self._help_test_sign_and_failcheck(newsigner, verifier, "a") |
---|
952 | - self._help_test_sign_and_failcheck_random(newsigner, verifier) |
---|
953 | + # Flip one bit of the public key. |
---|
954 | + badvstr = flip_one_bit(vstr) |
---|
955 | + try: |
---|
956 | + badverifier = ecdsa.create_verifying_key_from_string(badvstr) |
---|
957 | + except ecdsa.Error, le: |
---|
958 | + # Ok, fine, the verifying key was corrupted and Crypto++ detected this fact. |
---|
959 | + pass |
---|
960 | + else: |
---|
961 | + self._help_test_sign_and_check_bad_keys(signer, badverifier) |
---|
962 | |
---|
963 | + # Randomize all bits of the public key. |
---|
964 | + badvstr = randstr(len(vstr)) |
---|
965 | + assert badvstr != vstr, "Internal error -- randstr() produced the same string twice: %s == %s" % (badvstr, vstr) |
---|
966 | + try: |
---|
967 | + badverifier = ecdsa.create_verifying_key_from_string(badvstr) |
---|
968 | + except ecdsa.Error, le: |
---|
969 | + # Ok, fine, the key was corrupted and Crypto++ detected this fact. |
---|
970 | + pass |
---|
971 | + else: |
---|
972 | + self._help_test_sign_and_check_bad_keys(signer, badverifier) |
---|
973 | + |
---|
974 | + # Flip one bit of the private key. |
---|
975 | + badseed = flip_one_bit(seed) |
---|
976 | + badsigner = ecdsa.SigningKey(badseed) |
---|
977 | + self._help_test_sign_and_check_bad_keys(badsigner, verifier) |
---|
978 | + |
---|
979 | + # Randomize all bits of the private key. |
---|
980 | + badseed = randstr(len(seed)) |
---|
981 | + assert badseed != seed, "Internal error -- randstr() produced the same string twice: %s == %s" % (badseed, seed) |
---|
982 | + badsigner = ecdsa.SigningKey(badseed) |
---|
983 | + self._help_test_sign_and_check_bad_keys(badsigner, verifier) |
---|
984 | |
---|
985 | if __name__ == "__main__": |
---|
986 | unittest.main() |
---|