| 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() |
|---|