diff --git a/nacl/nacl.py b/nacl/nacl.py index aa78d8524c7a7bf6c5733e57d915709e4901c6c5..20cc74d351916749ca598cfb52d231688ac5b259 100644 --- a/nacl/nacl.py +++ b/nacl/nacl.py @@ -66,6 +66,11 @@ ffi.cdef( """ void randombytes(unsigned char * const buf, const unsigned long long buf_len); """ + + # Low Level - Scalar Multiplication + """ + int crypto_scalarmult_curve25519_base(unsigned char *q, const unsigned char *n); + """ ) @@ -98,3 +103,5 @@ lib.crypto_box_beforenm = wrap_nacl_function(lib.crypto_box_beforenm) lib.crypto_hash = wrap_nacl_function(lib.crypto_hash) lib.crypto_hash_sha256 = wrap_nacl_function(lib.crypto_hash_sha256) lib.crypto_hash_sha512 = wrap_nacl_function(lib.crypto_hash_sha512) + +lib.crypto_scalarmult_curve25519_base = wrap_nacl_function(lib.crypto_scalarmult_curve25519_base) diff --git a/nacl/public.py b/nacl/public.py index c62b6eddd8da4bc50e56d6d998262e9da036954c..0f84a7b87ade7beacaf15e1b463326e2532c5daa 100644 --- a/nacl/public.py +++ b/nacl/public.py @@ -5,6 +5,7 @@ from . import six from . import nacl, encoding from .exceptions import CryptoError +from .utils import random class PublicKey(encoding.Encodable, six.StringFixer, object): @@ -47,12 +48,24 @@ class PrivateKey(encoding.Encodable, six.StringFixer, object): PRIVATEKEY_SIZE = nacl.lib.crypto_box_SECRETKEYBYTES def __init__(self, private_key, encoder=encoding.RawEncoder): - self._private_key = encoder.decode(private_key) - self._public_key = None + # Decode the secret_key + private_key = encoder.decode(private_key) - if len(self._private_key) != self.PRIVATEKEY_SIZE: - raise ValueError('The private key must be exactly %s bytes long' % - self.PRIVATEKEY_SIZE) + # Verify that our seed is the proper size + skey_size = nacl.lib.crypto_box_SECRETKEYBYTES + if len(private_key) != skey_size: + raise ValueError( + 'The secret key must be exactly %d bytes long' % (skey_size,)) + + pk = nacl.ffi.new("unsigned char[]", nacl.lib.crypto_box_PUBLICKEYBYTES) + + if not nacl.lib.crypto_scalarmult_curve25519_base(pk, private_key): + raise CryptoError("Failed to generate a key pair") + + _pkey = nacl.ffi.buffer(pk, nacl.lib.crypto_box_PUBLICKEYBYTES)[:] + + self._private_key = private_key + self.public_key = PublicKey(_pkey) def __bytes__(self): return self._private_key @@ -64,27 +77,9 @@ class PrivateKey(encoding.Encodable, six.StringFixer, object): :rtype: :class:`~nacl.public.PrivateKey` """ - pk = nacl.ffi.new("unsigned char[]", PublicKey.PUBLICKEY_SIZE) - sk = nacl.ffi.new("unsigned char[]", cls.PRIVATEKEY_SIZE) - - public_key = nacl.ffi.buffer(pk, PublicKey.PUBLICKEY_SIZE)[:] - private_key = nacl.ffi.buffer(sk, cls.PRIVATEKEY_SIZE)[:] - - if not nacl.lib.crypto_box_keypair(public_key, private_key): - raise CryptoError("Failed to generate key pair") - - sk = cls(private_key) - sk.public_key = public_key - - return sk - - @property - def public_key(self): - return self._public_key - - @public_key.setter - def public_key(self, value): - self._public_key = value + return cls(random(nacl.lib.nacl.lib.crypto_box_SECRETKEYBYTES), + encoder=encoding.RawEncoder, + ) class Box(encoding.Encodable, six.StringFixer, object):