diff --git a/README.rst b/README.rst index 84cfa50..82baa5b 100644 --- a/README.rst +++ b/README.rst @@ -25,8 +25,6 @@ supporting them. • RSA from the Crypto++ library ; see pycryptopp.publickey.rsa ; deprecated in favor of Ed25519 -• Ecdsa from the Crypto++ library ; see pycryptopp.publickey.ecdsa ; - deprecated in favor of Ed25519 • SHA-256 from the Crypto++ library ; see pycryptopp.hash.sha256 ; deprecated in favor of the Python Standard Library's hashlib module diff --git a/_doubleloadtester.cpp b/_doubleloadtester.cpp index 64e95f8..cfe75c2 100644 --- a/_doubleloadtester.cpp +++ b/_doubleloadtester.cpp @@ -10,7 +10,7 @@ static PyMethodDef _doubleloadtester_functions[] = { }; /* from Crypto++ */ -#ifdef DISABLE_EMBEDDED_CRYPTOPP +#ifdef PYCRYPTOPP_USE_SYSTEM_CRYPTOPP #include #else #include diff --git a/pycryptopp.egg-info/stdeb.cfg b/pycryptopp.egg-info/stdeb.cfg index 19fb032..ef9f418 100644 --- a/pycryptopp.egg-info/stdeb.cfg +++ b/pycryptopp.egg-info/stdeb.cfg @@ -1,3 +1,3 @@ [pycryptopp] Copyright-File: copyright -Setup-Env-Vars: PYCRYPTOPP_DISABLE_EMBEDDED_CRYPTOPP=1 +Setup-Env-Vars: PYCRYPTOPP_USE_SYSTEM_CRYPTOPP_WITH_ASM=1 diff --git a/setup.py b/setup.py index 431ff36..a336495 100644 --- a/setup.py +++ b/setup.py @@ -1,11 +1,11 @@ # -*- coding: utf-8 -*- -# Copyright © 2009-2012 Zooko Wilcox-O'Hearn +# Copyright © 2009-2013 Zooko Wilcox-O'Hearn # Author: Zooko Wilcox-O'Hearn # # See README.rst for licensing information. -import os, platform, re, subprocess, sys +import os, platform, re, sys from setuptools import Extension, setup from setuptools import Command @@ -18,25 +18,30 @@ import versioneer -# ECDSA=False -ECDSA=True - DEBUG=False if "--debug" in sys.argv: DEBUG=True sys.argv.remove("--debug") -DISABLE_EMBEDDED_CRYPTOPP=False if "--disable-embedded-cryptopp" in sys.argv: - DISABLE_EMBEDDED_CRYPTOPP=True - sys.argv.remove("--disable-embedded-cryptopp") + print "The --disable-embedded-cryptopp option has been removed. Use either --use-system-cryptopp-with-asm or --use-system-cryptopp-without-asm." + sys.exit(1) # Unfortunately stdeb v0.3 doesn't seem to offer a way to pass command-line # arguments to setup.py when building for Debian, but it does offer a way to # pass environment variables, so we here check for that in addition to the # command-line argument check above. if os.environ.get('PYCRYPTOPP_DISABLE_EMBEDDED_CRYPTOPP') == "1": - DISABLE_EMBEDDED_CRYPTOPP=True + print "The PYCRYPTOPP_DISABLE_EMBEDDED_CRYPTOPP environment variable is not supported. Use either PYCRYPTOPP_USE_SYSTEM_CRYPTOPP_WITH_ASM or PYCRYPTOPP_USE_SYSTEM_CRYPTOPP_WITHOUT_ASM." + sys.exit(1) + +USE_SYSTEM_CRYPTOPP=False # False, "with asm", or "without asm" +if "--use-system-cryptopp-with-asm" in sys.argv: + USE_SYSTEM_CRYPTOPP='with asm' + sys.argv.remove("--use-system-cryptopp-with-asm") +elif "--use-system-cryptopp-without-asm" in sys.argv: + USE_SYSTEM_CRYPTOPP='without asm' + sys.argv.remove("--use-system-cryptopp-without-asm") EMBEDDED_CRYPTOPP_DIR='src-cryptopp' @@ -76,8 +81,11 @@ else: extra_compile_args.append("-w") -if DISABLE_EMBEDDED_CRYPTOPP: - define_macros.append(('DISABLE_EMBEDDED_CRYPTOPP', 1)) +if USE_SYSTEM_CRYPTOPP: + define_macros.append(('PYCRYPTOPP_USE_SYSTEM_CRYPTOPP', 1)) + + if USE_SYSTEM_CRYPTOPP == "without asm": + define_macros.append(('CRYPTOPP_DISABLE_ASM', 1)) # Link with a Crypto++ library that is already installed on the system. @@ -106,28 +114,14 @@ else: # Build the bundled Crypto++ library which is included by source # code in the pycryptopp tree and link against it. + define_macros.append(('CRYPTOPP_DISABLE_ASM', 1)) + include_dirs.append(".") if 'sunos' in platform.system().lower(): extra_compile_args.append('-Wa,--divide') # allow use of "/" operator - if 'win32' in sys.platform.lower(): - try: - res = subprocess.Popen(['cl'], stdin=open(os.devnull), stdout=subprocess.PIPE).communicate() - except EnvironmentError, le: - # Okay I guess we're not using the "cl.exe" compiler. - using_msvc = False - else: - using_msvc = True - else: - using_msvc = False - - if using_msvc: - # We can handle out-of-line assembly. - cryptopp_src = [ os.path.join(EMBEDDED_CRYPTOPP_DIR, x) for x in os.listdir(EMBEDDED_CRYPTOPP_DIR) if x.endswith(('.cpp', '.asm')) ] - else: - # We can't handle out-of-line assembly. - cryptopp_src = [ os.path.join(EMBEDDED_CRYPTOPP_DIR, x) for x in os.listdir(EMBEDDED_CRYPTOPP_DIR) if x.endswith('.cpp') ] + cryptopp_src = [ os.path.join(EMBEDDED_CRYPTOPP_DIR, x) for x in os.listdir(EMBEDDED_CRYPTOPP_DIR) if x.endswith('.cpp') ] # Mac OS X extended attribute files when written to a non-Mac-OS-X # filesystem come out as "._$FNAME", for example "._rdtables.cpp", @@ -137,34 +131,6 @@ extra_srcs.extend(cryptopp_src) -# In either case, we must provide a value for CRYPTOPP_DISABLE_ASM that -# matches the one used when Crypto++ was originally compiled. The Crypto++ -# GNUmakefile tests the assembler version and only enables assembly for -# recent versions of the GNU assembler (2.10 or later). The /usr/bin/as on -# Mac OS-X 10.6 is too old. - -try: - sp = subprocess.Popen(['as', '-v'], stdin=subprocess.PIPE, - stdout=subprocess.PIPE, stderr=subprocess.PIPE, - universal_newlines=True) - sp.stdin.close() - sp.wait() - if re.search("GNU assembler version (0|1|2.0)", sp.stderr.read()): - define_macros.append(('CRYPTOPP_DISABLE_ASM', 1)) -except EnvironmentError: - # Okay, nevermind. Maybe there isn't even an 'as' executable on this - # platform. - pass -else: - try: - # that "as -v" step creates an empty a.out, so clean it up. Modern GNU - # "as" has --version, which emits the version number without actually - # assembling anything, but older versions only have -v, which emits a - # version number and *then* assembles from stdin. - os.unlink("a.out") - except EnvironmentError: - pass - trove_classifiers=[ "Environment :: Console", "License :: OSI Approved :: GNU General Public License (GPL)", # See README.rst for alternative licensing. @@ -189,8 +155,6 @@ 'src/pycryptopp/cipher/aesmodule.cpp', 'src/pycryptopp/cipher/xsalsa20module.cpp', ] -if ECDSA: - srcs.append('src/pycryptopp/publickey/ecdsamodule.cpp') if BUILD_DOUBLE_LOAD_TESTER: srcs.append('_doubleloadtester.cpp', ) @@ -225,7 +189,7 @@ setup_requires.append('setuptools_pyflakes >= 1.0.0') # stdeb is required to produce Debian files with "sdist_dsc". -# http://github.com/astraw/stdeb/tree/master +# https://github.com/astraw/stdeb/tree/master if "sdist_dsc" in sys.argv: setup_requires.append('stdeb') @@ -433,7 +397,7 @@ def _setup(longdescription): description='Python wrappers for a few algorithms from the Crypto++ library', long_description=longdescription, author='Zooko Wilcox-O\'Hearn', - author_email='zooko@zooko.com', + author_email='zookog@gmail.com', url='https://tahoe-lafs.org/trac/' + PKG, license='GNU GPL', # see README.rst for details -- there is also an alternative licence packages=["pycryptopp", diff --git a/src/pycryptopp/_pycryptoppmodule.cpp b/src/pycryptopp/_pycryptoppmodule.cpp index 1c99817..cf9820d 100644 --- a/src/pycryptopp/_pycryptoppmodule.cpp +++ b/src/pycryptopp/_pycryptoppmodule.cpp @@ -1,13 +1,12 @@ #include -#include "publickey/ecdsamodule.hpp" #include "publickey/rsamodule.hpp" #include "hash/sha256module.hpp" #include "cipher/aesmodule.hpp" #include "cipher/xsalsa20module.hpp" /* from Crypto++ */ -#ifdef DISABLE_EMBEDDED_CRYPTOPP +#ifdef PYCRYPTOPP_USE_SYSTEM_CRYPTOPP #include #else #include @@ -17,7 +16,7 @@ PyDoc_STRVAR(_pycryptopp__doc__, "_pycryptopp -- Python wrappers for a few algorithms from Crypto++\n\ \n\ from pycryptopp import publickey\n\ -from pycryptopp.publickey import ecdsa\n\ +from pycryptopp.publickey import ed25519\n\ from pycryptopp.publickey import rsa\n\ from pycryptopp import cipher\n\ from pycryptopp.cipher import aes\n\ @@ -46,7 +45,7 @@ init_pycryptopp(void) { PyObject* version; /* a tuple of (Crypto++ version, extra-version) */ - #ifndef DISABLE_EMBEDDED_CRYPTOPP + #ifndef PYCRYPTOPP_USE_SYSTEM_CRYPTOPP /* In the version of Crypto++ which is included in pycryptopp, there is a symbol named `cryptopp_extra_version' which is declared (external variable) in config.h and defined in cryptlib.cpp. Of course it is @@ -64,7 +63,6 @@ init_pycryptopp(void) { return; - init_ecdsa(module); init_rsa(module); init_sha256(module); init_aes(module); diff --git a/src/pycryptopp/bench/bench_algs.py b/src/pycryptopp/bench/bench_algs.py index a896d2b..e9f4124 100644 --- a/src/pycryptopp/bench/bench_algs.py +++ b/src/pycryptopp/bench/bench_algs.py @@ -1,6 +1,16 @@ import bench_sigs, bench_ciphers, bench_hashes +def print_versions(): + import pycryptopp + print "pycryptopp: ", pycryptopp + print "pycryptopp.__version__: ", pycryptopp.__version__, + print "pycryptopp._pycryptopp.cryptopp_version: ", pycryptopp._pycryptopp.cryptopp_version + print "pycryptopp.publickey.ed25519._version.get_versions(): ", pycryptopp.publickey.ed25519._version.get_versions() + import pkg_resources + print "pkg_resources.require('pycryptopp'): ", pkg_resources.require('pycryptopp') + def bench(MAXTIME=10.0): + print_versions() bench_sigs.bench(MAXTIME) bench_ciphers.bench(MAXTIME) bench_hashes.bench(MAXTIME) diff --git a/src/pycryptopp/bench/bench_sigs.py b/src/pycryptopp/bench/bench_sigs.py index e0fe37b..d2b89c8 100644 --- a/src/pycryptopp/bench/bench_sigs.py +++ b/src/pycryptopp/bench/bench_sigs.py @@ -1,37 +1,9 @@ -from pycryptopp.publickey import ecdsa, ed25519, rsa +from pycryptopp.publickey import ed25519, rsa from common import insecurerandstr, rep_bench msg = 'crypto libraries should come with benchmarks' -class ECDSA256(object): - def __init__(self): - self.seed = insecurerandstr(32) - self.signer = None - - def gen(self, N): - for i in xrange(N): - ecdsa.SigningKey(self.seed) - - def sign_init(self, N): - self.signer = ecdsa.SigningKey(self.seed) - - def sign(self, N): - signer = self.signer - for i in xrange(N): - signer.sign(msg) - - def ver_init(self, N): - signer = ecdsa.SigningKey(self.seed) - self.sig = signer.sign(msg) - self.verifier = signer.get_verifying_key() - - def ver(self, N): - sig = self.sig - verifier = self.verifier - for i in xrange(N): - verifier.verify(sig, msg) - class Ed25519(object): def __init__(self): self.seed = insecurerandstr(32) @@ -119,7 +91,7 @@ def ver(self, N): verifier.verify(msg, sig) def bench_sigs(MAXTIME): - for klass in [ECDSA256, Ed25519,]: + for klass in [Ed25519,]: print klass ob = klass() print "generate key" diff --git a/src/pycryptopp/cipher/aesmodule.cpp b/src/pycryptopp/cipher/aesmodule.cpp index 360827d..0bcdf5b 100644 --- a/src/pycryptopp/cipher/aesmodule.cpp +++ b/src/pycryptopp/cipher/aesmodule.cpp @@ -12,7 +12,7 @@ typedef int Py_ssize_t; /* from Crypto++ */ -#ifdef DISABLE_EMBEDDED_CRYPTOPP +#ifdef PYCRYPTOPP_USE_SYSTEM_CRYPTOPP #include #include #else diff --git a/src/pycryptopp/cipher/xsalsa20module.cpp b/src/pycryptopp/cipher/xsalsa20module.cpp index ab29787..7abc9b1 100644 --- a/src/pycryptopp/cipher/xsalsa20module.cpp +++ b/src/pycryptopp/cipher/xsalsa20module.cpp @@ -10,7 +10,7 @@ typedef int Py_ssize_t; #include "xsalsa20module.hpp" -#ifdef DISABLE_EMBEDDED_CRYPTOPP +#ifdef PYCRYPTOPP_USE_SYSTEM_CRYPTOPP #include #else #include diff --git a/src/pycryptopp/hash/sha256module.cpp b/src/pycryptopp/hash/sha256module.cpp index bf9d8e3..af828bb 100644 --- a/src/pycryptopp/hash/sha256module.cpp +++ b/src/pycryptopp/hash/sha256module.cpp @@ -11,7 +11,7 @@ typedef int Py_ssize_t; #include /* from Crypto++ */ -#ifdef DISABLE_EMBEDDED_CRYPTOPP +#ifdef PYCRYPTOPP_USE_SYSTEM_CRYPTOPP #include #include #include diff --git a/src/pycryptopp/publickey/__init__.py b/src/pycryptopp/publickey/__init__.py index be9d7ad..178f3c0 100644 --- a/src/pycryptopp/publickey/__init__.py +++ b/src/pycryptopp/publickey/__init__.py @@ -1,3 +1,3 @@ -import ecdsa, rsa, ed25519 +import rsa, ed25519 -quiet_pyflakes=[ecdsa, rsa, ed25519] +quiet_pyflakes=[rsa, ed25519] diff --git a/src/pycryptopp/publickey/ecdsa.py b/src/pycryptopp/publickey/ecdsa.py deleted file mode 100644 index c25ba33..0000000 --- a/src/pycryptopp/publickey/ecdsa.py +++ /dev/null @@ -1,5 +0,0 @@ -from pycryptopp import _import_my_names - -_import_my_names(globals(), "ecdsa_") - -del _import_my_names diff --git a/src/pycryptopp/publickey/ecdsamodule.cpp b/src/pycryptopp/publickey/ecdsamodule.cpp deleted file mode 100644 index ab18a50..0000000 --- a/src/pycryptopp/publickey/ecdsamodule.cpp +++ /dev/null @@ -1,521 +0,0 @@ -/** -* Things to do: -* Make it work and pass tests. -* compressed pub keys -- check out Wei Dai's example code on mailinglist as linked to from pycryptopp trac by Brian -* Make new KDF (standard, Crypto++-compatible). -* in C++ -* in Python -* use Crypto++ Randomize()'s -* provide RNG class which is P1363-SHA-256 - -* Profit! -* Migrate pair-programming to Bespin. -* Put a Tahoe backend under Bespin. -*/ - -/** - * ecdsamodule.cpp -- Python wrappers around Crypto++'s - * ECDSA(1363)/EMSA1(SHA-256) -- ECDSA. - * - * The keys (256-bit) use the curve ASN1::secp256r1() and SHA-256 as the - * hash function. The Key Derivation Protocol is P1363_KDF2 - * http://www.users.zetnet.co.uk/hopwood/crypto/scan/prf.html#KDF2 - * to generate private (signing) keys from unguessable seeds -- see - * source code for details and doc string for usage. - */ - -#define PY_SSIZE_T_CLEAN -#include -#if (PY_VERSION_HEX < 0x02050000) -typedef int Py_ssize_t; -#endif - -#include - -#include "ecdsamodule.hpp" - -/* from Crypto++ */ -#ifdef DISABLE_EMBEDDED_CRYPTOPP -#include -#include -#include -#include -#include -#include -// only needed for debugging -- the _dump() function -#include -#include -#include -#else -#include -#include -#include -#include -#include -#include -// only needed for debugging -- the _dump() function -#include -#include -#include -#endif - -static const int KEY_SIZE_BITS=256; - -USING_NAMESPACE(CryptoPP) - -static const char*const ecdsa___doc__ = "ecdsa -- ECDSA(1363)/EMSA1(SHA-256) signatures\n\ -\n\ -To create a new ECDSA signing key (deterministically from a 32-byte seed), construct an instance of the class, passing the seed as argument, i.e. SigningKey(seed).\n\ -\n\ -To get a verifying key from a signing key, call get_verifying_key() on the signing key instance.\n\ -\n\ -To deserialize an ECDSA verifying key from a string, call VerifyingKey(serialized_verifying_key)."; - -static PyObject *ecdsa_error; - -typedef struct { - PyObject_HEAD - - /* internal */ - ECDSA::Verifier *k; -} VerifyingKey; - -PyDoc_STRVAR(VerifyingKey__doc__, -"an ECDSA verifying key"); - -static int -VerifyingKey___init__(PyObject* self, PyObject* args, PyObject* kwdict) { - static const char *kwlist[] = { "serializedverifyingkey", NULL }; - const char *serializedverifyingkey; - Py_ssize_t serializedverifyingkeysize = 0; - - if (!PyArg_ParseTupleAndKeywords(args, kwdict, "t#:VerifyingKey__init__", const_cast(kwlist), &serializedverifyingkey, &serializedverifyingkeysize)) - return NULL; - assert (serializedverifyingkeysize >= 0); - - if (serializedverifyingkeysize != 33) { - PyErr_Format(ecdsa_error, "Precondition violation: size in bits is required to be %d (for %d-bit key), but it was %d", 33, KEY_SIZE_BITS, serializedverifyingkeysize); - return -1; - } - - VerifyingKey *mself = reinterpret_cast(self); - - StringSource ss(reinterpret_cast(serializedverifyingkey), serializedverifyingkeysize, true); - - ECP::Element element; - DL_GroupParameters_EC params(ASN1::secp256r1()); - params.SetPointCompression(true); - try { - element = params.DecodeElement(reinterpret_cast(serializedverifyingkey), true); - mself->k = new ECDSA::Verifier(params, element); - if (!mself->k) { - PyErr_NoMemory(); - return -1; - } - } catch (InvalidDataFormat le) { - PyErr_Format(ecdsa_error, "Serialized verifying key was corrupted. Crypto++ gave this exception: %s", le.what()); - return -1; - } - - return 0; -} - -static void -VerifyingKey_dealloc(VerifyingKey* self) { - if (self->k) - delete self->k; - self->ob_type->tp_free((PyObject*)self); -} - -static PyObject * -VerifyingKey_verify(VerifyingKey *self, PyObject *args, PyObject *kwdict) { - static const char *kwlist[] = { "msg", "signature", NULL }; - const char *msg; - Py_ssize_t msgsize; - const char *signature; - Py_ssize_t signaturesize = 0; - if (!PyArg_ParseTupleAndKeywords(args, kwdict, "t#t#:verify", const_cast(kwlist), &msg, &msgsize, &signature, &signaturesize)) - return NULL; - assert (msgsize >= 0); - assert (signaturesize >= 0); - - if (self->k->VerifyMessage(reinterpret_cast(msg), msgsize, reinterpret_cast(signature), signaturesize)) - Py_RETURN_TRUE; - else - Py_RETURN_FALSE; -} - -PyDoc_STRVAR(VerifyingKey_verify__doc__, -"Return whether the signature is a valid signature on the msg."); - -static PyObject * -VerifyingKey_serialize(VerifyingKey *self, PyObject *dummy) { - ECDSA::Verifier *pubkey; - pubkey = new ECDSA::Verifier(*(self->k)); - const DL_GroupParameters_EC& params = pubkey->GetKey().GetGroupParameters(); - - Py_ssize_t len = params.GetEncodedElementSize(true); - PyObject* result = PyString_FromStringAndSize(NULL, len); - if (!result) - return NULL; - - params.EncodeElement(true, pubkey->GetKey().GetPublicElement(), - reinterpret_cast(PyString_AS_STRING(result))); - - return result; -} - -PyDoc_STRVAR(VerifyingKey_serialize__doc__, -"Return a string containing the key material. The string can be passed to \n\ -the constructor of VerifyingKey to instantiate a new copy of this key."); - -static PyMethodDef VerifyingKey_methods[] = { - {"verify", reinterpret_cast(VerifyingKey_verify), METH_KEYWORDS, VerifyingKey_verify__doc__}, - {"serialize", reinterpret_cast(VerifyingKey_serialize), METH_NOARGS, VerifyingKey_serialize__doc__}, - {NULL}, -}; - -static PyTypeObject VerifyingKey_type = { - PyObject_HEAD_INIT(NULL) - 0, /*ob_size*/ - "ecdsa.VerifyingKey", /*tp_name*/ - sizeof(VerifyingKey), /*tp_basicsize*/ - 0, /*tp_itemsize*/ - (destructor)VerifyingKey_dealloc, /*tp_dealloc*/ - 0, /*tp_print*/ - 0, /*tp_getattr*/ - 0, /*tp_setattr*/ - 0, /*tp_compare*/ - 0, /*tp_repr*/ - 0, /*tp_as_number*/ - 0, /*tp_as_sequence*/ - 0, /*tp_as_mapping*/ - 0, /*tp_hash */ - 0, /*tp_call*/ - 0, /*tp_str*/ - 0, /*tp_getattro*/ - 0, /*tp_setattro*/ - 0, /*tp_as_buffer*/ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/ - VerifyingKey__doc__, /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - VerifyingKey_methods, /* tp_methods */ - 0, /* tp_members */ - 0, /* tp_getset */ - 0, /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - 0, /* tp_dictoffset */ - VerifyingKey___init__, /* tp_init */ -}; - -typedef struct { - PyObject_HEAD - - /* internal */ - ECDSA::Signer *k; -} SigningKey; - -static void -SigningKey_dealloc(SigningKey* self) { - if (self->k) - delete self->k; - self->ob_type->tp_free((PyObject*)self); -} - -static const char* TAG_AND_SALT = "102:pycryptopp v0.5.3 key derivation algorithm using SHA-256 hash to generate ECDSA 256-bit secret exponents," \ - "16:H1yGNvUONoc0FD1d,"; -static const size_t TAG_AND_SALT_len = 127; - -/** copied from Crypto++'s integer.cpp */ -/** The following is in Crypto++'s integer.cpp and we use them: -* void Integer::Randomize(RandomNumberGenerator &rng, size_t nbits) -* { -* const size_t nbytes = nbits/8 + 1; -* SecByteBlock buf(nbytes); -* rng.GenerateBlock(buf, nbytes); -* if (nbytes) -* buf[0] = (byte)Crop(buf[0], nbits % 8); -* Decode(buf, nbytes, UNSIGNED); -* } -* void Integer::Randomize(RandomNumberGenerator &rng, const Integer &min, const Integer &max) -* { -* if (min > max) -* throw InvalidArgument("Integer: Min must be no greater than Max"); -* -* Integer range = max - min; -* const unsigned int nbits = range.BitCount(); -* -* do -* { -* Randomize(rng, nbits); -* } -* while (*this > range); -* -* *this += min; -* } -* -*/ - -static int -SigningKey___init__(PyObject* self, PyObject* args, PyObject* kwdict) { - static const char *kwlist[] = { "seed", NULL }; - const char* seed; - Py_ssize_t seedlen; - if (!PyArg_ParseTupleAndKeywords(args, kwdict, "t#:SigningKey___init__", const_cast(kwlist), &seed, &seedlen)) { - return -1; - } - - if (seedlen != 32) { - PyErr_Format(ecdsa_error, "Precondition violation: seed is required to be of length 32, but it was %zd", seedlen); - return -1; - } - - OID curve; - Integer grouporderm1; - byte privexpbytes[32] = {0}; - Integer privexponentm1; - privexponentm1.Decode(privexpbytes, sizeof(privexpbytes)); assert (privexponentm1 == 0); // just checking.. - - DL_GroupParameters_EC params(ASN1::secp256r1()); - params.SetPointCompression(true); - grouporderm1 = params.GetGroupOrder() - 1; - SHA256 t; - - t.Update(reinterpret_cast(TAG_AND_SALT), TAG_AND_SALT_len); - t.Update(reinterpret_cast(seed), seedlen); - t.TruncatedFinal(privexpbytes, SHA256::DIGESTSIZE); - privexponentm1.Decode(privexpbytes, sizeof(privexpbytes)); - - while (privexponentm1 >= grouporderm1) { - SHA256 t2; - t2.Update(reinterpret_cast(TAG_AND_SALT), TAG_AND_SALT_len); - std::cerr << "WHEE " << sizeof(privexpbytes) << "\n";std::cerr.flush(); - t2.Update(privexpbytes, sizeof(privexpbytes)); - t2.TruncatedFinal(privexpbytes, SHA256::DIGESTSIZE); - privexponentm1.Decode(privexpbytes, sizeof(privexpbytes)); - } - - SigningKey* mself = reinterpret_cast(self); - - mself->k = new ECDSA::Signer(params, privexponentm1+1); - - if (!mself->k) { - PyErr_NoMemory(); - return -1; - } - - return 0; -} - -PyDoc_STRVAR(SigningKey__init____doc__, -"Create a signing key (256 bits) deterministically from the given seed.\n\ -\n\ -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(32).\n\ -\n\ -@param seed seed\n\ -\n\ -@precondition len(seed) >= ceil(sizeinbits/16.0)"); - -static PyObject * -SigningKey__dump(SigningKey *self, PyObject *dummy) { - const DL_GroupParameters_EC& gp = self->k->GetKey().GetGroupParameters(); - std::cout << "whee " << gp.GetEncodedElementSize(true) << "\a"; - std::cout << "booo " << gp.GetEncodedElementSize(false) << "\n"; - - ECPPoint p = gp.GetSubgroupGenerator(); - std::cout << "generator " << p.x << ", " << p.y << "\n"; - - std::cout << "GroupOrder: "; - std::cout << gp.GetGroupOrder(); - std::cout << "\n"; - - std::string s; - StringSink* ss = new StringSink(s); - HexEncoder he(ss); - std::cout << "AlgorithmID: "; - gp.GetAlgorithmID().DEREncode(he); - std::cout << s << "\n"; - - const ECP& ec = gp.GetCurve(); - Integer fieldsize = ec.FieldSize(); - std::cout << "field size " << fieldsize.BitCount() << " " << fieldsize.ByteCount() << " " << ec.FieldSize() << "\n"; - std::cout << "Curve: "; - std::cout << "curve field max element bit length: " << ec.GetField().MaxElementBitLength() << "\n"; - std::cout << "curve field modulus: " << ec.GetField().GetModulus() << "\n"; - std::cout << "curve A: " << ec.GetA() << ", curve B: " << ec.GetB(); - - const ECP::Field& f = ec.GetField(); - std::cout << "curve field modulus: " << f.GetModulus() << "\n"; - std::cout << "curve field identity: " << f.Identity() << "\n"; - - std::string cfs; - StringSink* cfss = new StringSink(cfs); - HexEncoder cfhe(cfss); - f.DEREncode(cfhe); - std::cout << "curve field derencoding: " << cfs << "\n"; - - const CryptoMaterial& cm = self->k->GetMaterial(); - Integer i; - cm.GetValue("SubgroupOrder", i); - std::cout << "\n"; - std::cout << "SubgroupOrder: "; - std::cout << i; - std::cout << "\n"; - ECP::Element e; - cm.GetValue("SubgroupGenerator", e); - std::cout << "SubgroupGenerator: "; - std::cout << e.x << ", " << e.y; - std::cout << "\n"; - - std::cout << "private key: "; - - const PrivateKey& privkey = self->k->GetPrivateKey(); - - std::cout << privkey.GetValueNames() << "\n"; - - Integer privi; - privkey.GetValue("PrivateExponent", privi); - std::cout << privi << "\n"; - std::cout << "numbits: " << privi.BitCount() << "\n"; - std::cout << "numbytes: " << privi.ByteCount() << "\n"; - - Py_RETURN_NONE; -} - -PyDoc_STRVAR(SigningKey__dump__doc__, -"Print to stdout some descriptions of the math pieces."); - -static PyObject * -SigningKey_sign(SigningKey *self, PyObject *msgobj) { - const char *msg; - Py_ssize_t msgsize; - PyString_AsStringAndSize(msgobj, const_cast(&msg), reinterpret_cast(&msgsize)); - assert (msgsize >= 0); - - Py_ssize_t sigsize; - sigsize = self->k->SignatureLength(); - - PyStringObject* result = reinterpret_cast(PyString_FromStringAndSize(NULL, sigsize)); - if (!result) - return NULL; - assert (sigsize >= 0); - - AutoSeededRandomPool randpool(false); //XXX - - Py_ssize_t siglengthwritten; - try { - siglengthwritten = self->k->SignMessage( - randpool, - reinterpret_cast(msg), - msgsize, - reinterpret_cast(PyString_AS_STRING(result))); - } catch (InvalidDataFormat le) { - Py_DECREF(result); - return PyErr_Format(ecdsa_error, "Signing key was corrupted. Crypto++ gave this exception: %s", le.what()); - } - - if (siglengthwritten < sigsize) - fprintf(stderr, "%s: %d: %s: %s", __FILE__, __LINE__, "SigningKey_sign", "INTERNAL ERROR: signature was shorter than expected."); - else if (siglengthwritten > sigsize) { - fprintf(stderr, "%s: %d: %s: %s", __FILE__, __LINE__, "SigningKey_sign", "INTERNAL ERROR: signature was longer than expected, so memory was invalidly overwritten."); - abort(); - } - assert (siglengthwritten >= 0); - - return reinterpret_cast(result); -} - -PyDoc_STRVAR(SigningKey_sign__doc__, - "Return a signature on the argument."); //XXX If randseed is not None then it is required to be an "); // XXX randseed! - -static PyObject * -SigningKey_get_verifying_key(SigningKey *self, PyObject *dummy) { - VerifyingKey *verifier = PyObject_New(VerifyingKey, &VerifyingKey_type); - if (!verifier) - return NULL; - - verifier->k = new ECDSA::Verifier(*(self->k)); - if (!verifier->k) - return PyErr_NoMemory(); - verifier->k->AccessKey().AccessGroupParameters().SetPointCompression(true); - - return reinterpret_cast(verifier); -} - -PyDoc_STRVAR(SigningKey_get_verifying_key__doc__, -"Return the corresponding verifying key."); - -static PyMethodDef SigningKey_methods[] = { - {"sign", reinterpret_cast(SigningKey_sign), METH_O, SigningKey_sign__doc__}, - {"_dump", reinterpret_cast(SigningKey__dump), METH_NOARGS, SigningKey__dump__doc__}, - {"get_verifying_key", reinterpret_cast(SigningKey_get_verifying_key), METH_NOARGS, SigningKey_get_verifying_key__doc__}, - {NULL}, -}; - -static PyTypeObject SigningKey_type = { - PyObject_HEAD_INIT(NULL) - 0, /*ob_size*/ - "ecdsa.SigningKey", /*tp_name*/ - sizeof(SigningKey), /*tp_basicsize*/ - 0, /*tp_itemsize*/ - (destructor)SigningKey_dealloc, /*tp_dealloc*/ - 0, /*tp_print*/ - 0, /*tp_getattr*/ - 0, /*tp_setattr*/ - 0, /*tp_compare*/ - 0, /*tp_repr*/ - 0, /*tp_as_number*/ - 0, /*tp_as_sequence*/ - 0, /*tp_as_mapping*/ - 0, /*tp_hash */ - 0, /*tp_call*/ - 0, /*tp_str*/ - 0, /*tp_getattro*/ - 0, /*tp_setattro*/ - 0, /*tp_as_buffer*/ - Py_TPFLAGS_DEFAULT, /*tp_flags*/ - SigningKey__init____doc__, /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - SigningKey_methods, /* tp_methods */ - 0, /* tp_members */ - 0, /* tp_getset */ - 0, /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - 0, /* tp_dictoffset */ - SigningKey___init__, /* tp_init */ -}; - -void -init_ecdsa(PyObject*const module) { - VerifyingKey_type.tp_new = PyType_GenericNew; - if (PyType_Ready(&VerifyingKey_type) < 0) - return; - Py_INCREF(&VerifyingKey_type); - PyModule_AddObject(module, "ecdsa_VerifyingKey", (PyObject *)&VerifyingKey_type); - - SigningKey_type.tp_new = PyType_GenericNew; - if (PyType_Ready(&SigningKey_type) < 0) - return; - Py_INCREF(&SigningKey_type); - PyModule_AddObject(module, "ecdsa_SigningKey", (PyObject *)&SigningKey_type); - - ecdsa_error = PyErr_NewException(const_cast("_ecdsa.Error"), NULL, NULL); - PyModule_AddObject(module, "ecdsa_Error", ecdsa_error); - - PyModule_AddStringConstant(module, "ecdsa___doc__", const_cast(ecdsa___doc__)); -} diff --git a/src/pycryptopp/publickey/ecdsamodule.hpp b/src/pycryptopp/publickey/ecdsamodule.hpp deleted file mode 100644 index ad3c4fc..0000000 --- a/src/pycryptopp/publickey/ecdsamodule.hpp +++ /dev/null @@ -1,7 +0,0 @@ -#ifndef __INCL_ECDSAMODULE_HPP -#define __INCL_ECDSAMODULE_HPP - -void -init_ecdsa(PyObject* module); - -#endif /* #ifndef __INCL_ECDSAMODULE_HPP */ diff --git a/src/pycryptopp/publickey/rsamodule.cpp b/src/pycryptopp/publickey/rsamodule.cpp index f423017..c8b87ce 100644 --- a/src/pycryptopp/publickey/rsamodule.cpp +++ b/src/pycryptopp/publickey/rsamodule.cpp @@ -14,7 +14,7 @@ typedef int Py_ssize_t; #include "rsamodule.hpp" /* from Crypto++ */ -#ifdef DISABLE_EMBEDDED_CRYPTOPP +#ifdef PYCRYPTOPP_USE_SYSTEM_CRYPTOPP #include #include #include diff --git a/src/pycryptopp/test/test_ecdsa.py b/src/pycryptopp/test/test_ecdsa.py deleted file mode 100644 index 85f809d..0000000 --- a/src/pycryptopp/test/test_ecdsa.py +++ /dev/null @@ -1,258 +0,0 @@ -import random -import base64 - -import os -SEED = os.environ.get('REPEATABLE_RANDOMNESS_SEED', None) - -if SEED is None: - # Generate a seed which is fairly short (to ease cut-and-paste, writing it - # down, etc.). Note that Python's random module's seed() function is going - # to take the hash() of this seed, which is a 32-bit value (currently) so - # there is no point in making this seed larger than 32 bits. Make it 30 - # bits, which conveniently fits into six base-32 chars. Include a separator - # because chunking facilitates memory (including working and short-term - # memory) in humans. - chars = "ybndrfg8ejkmcpqxot1uwisza345h769" # Zooko's choice, rationale in "DESIGN" doc in z-base-32 project - SEED = ''.join([random.choice(chars) for x in range(3)] + ['-'] + [random.choice(chars) for x in range(3)]) - -import logging -logging.info("REPEATABLE_RANDOMNESS_SEED: %s\n" % SEED) -logging.info("In order to reproduce this run of the code, set the environment variable \"REPEATABLE_RANDOMNESS_SEED\" to %s before executing.\n" % SEED) -random.seed(SEED) - -def seed_which_refuses(a): - logging.warn("I refuse to reseed to %s -- I already seeded with %s.\n" % (a, SEED,)) - return -random.seed = seed_which_refuses - -from random import randrange - -import unittest - -from pycryptopp.publickey import ecdsa - -def randstr(n, rr=randrange): - return ''.join([chr(rr(0, 256)) for x in xrange(n)]) - -from base64 import b32encode -def ab(x): # debuggery - if len(x) >= 3: - return "%s:%s" % (len(x), b32encode(x[-3:]),) - elif len(x) == 2: - return "%s:%s" % (len(x), b32encode(x[-2:]),) - elif len(x) == 1: - return "%s:%s" % (len(x), b32encode(x[-1:]),) - elif len(x) == 0: - return "%s:%s" % (len(x), "--empty--",) - -def div_ceil(n, d): - """ - The smallest integer k such that k*d >= n. - """ - return (n/d) + (n%d != 0) - -KEYBITS =256 - -SEEDBITS=256 -SEEDBYTES=div_ceil(SEEDBITS, 8) - -# The number of bytes required to encode a public key in this elliptic curve. -PUBKEYBYTES=div_ceil(KEYBITS, 8)+1 # 1 byte for the sign of the y component - -# The number of bytes requires to encode a signature in this elliptic curve. -SIGBITS=KEYBITS*2 -SIGBYTES=div_ceil(SIGBITS, 8) - -class Signer(unittest.TestCase): - def test_construct(self): - seed = randstr(SEEDBYTES) - ecdsa.SigningKey(seed) - - def test_sign(self): - seed = randstr(SEEDBYTES) - signer = ecdsa.SigningKey(seed) - sig = signer.sign("message") - self.failUnlessEqual(len(sig), SIGBYTES) - - def test_sign_and_verify(self): - seed = randstr(SEEDBYTES) - signer = ecdsa.SigningKey(seed) - sig = signer.sign("message") - v = signer.get_verifying_key() - self.failUnless(v.verify("message", sig)) - - def test_sign_and_verify_emptymsg(self): - seed = randstr(SEEDBYTES) - signer = ecdsa.SigningKey(seed) - sig = signer.sign("") - v = signer.get_verifying_key() - self.failUnless(v.verify("", sig)) - - def test_construct_from_same_seed_is_reproducible(self): - seed = randstr(SEEDBYTES) - signer1 = ecdsa.SigningKey(seed) - signer2 = ecdsa.SigningKey(seed) - self.failUnlessEqual(signer1.get_verifying_key().serialize(), signer2.get_verifying_key().serialize()) - - # ... and using different seeds constructs a different private key. - seed3 = randstr(SEEDBYTES) - 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 - signer3 = ecdsa.SigningKey(seed3) - self.failIfEqual(signer1.get_verifying_key().serialize(), signer3.get_verifying_key().serialize()) - - # Also try the all-zeroes string just because bugs sometimes are - # data-dependent on zero or cause bogus zeroes. - seed4 = '\x00'*SEEDBYTES - 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 - signer4 = ecdsa.SigningKey(seed4) - self.failIfEqual(signer4.get_verifying_key().serialize(), signer1.get_verifying_key().serialize()) - - signer5 = ecdsa.SigningKey(seed4) - self.failUnlessEqual(signer5.get_verifying_key().serialize(), signer4.get_verifying_key().serialize()) - - def test_construct_short_seed(self): - try: - ecdsa.SigningKey("\x00\x00\x00") - except ecdsa.Error, le: - self.failUnless("seed is required to be of length " in str(le), le) - else: - self.fail("Should have raised error from seed being too short.") - - def test_construct_bad_arg_type(self): - try: - ecdsa.SigningKey(1) - except TypeError, le: - self.failUnless("must be string" in str(le), le) - else: - self.fail("Should have raised error from seed being of the wrong type.") - -class Verifier(unittest.TestCase): - def test_from_signer_and_serialize_and_deserialize(self): - seed = randstr(SEEDBYTES) - signer = ecdsa.SigningKey(seed) - - verifier = signer.get_verifying_key() - s1 = verifier.serialize() - self.failUnlessEqual(len(s1), PUBKEYBYTES) - ecdsa.VerifyingKey(s1) - s2 = verifier.serialize() - self.failUnlessEqual(s1, s2) - -def flip_one_bit(s): - assert s - i = randrange(0, len(s)) - result = s[:i] + chr(ord(s[i])^(0x01<