diff --git a/src/wolfcrypt/_build_ffi.py b/src/wolfcrypt/_build_ffi.py index 5393772..a25fe4b 100644 --- a/src/wolfcrypt/_build_ffi.py +++ b/src/wolfcrypt/_build_ffi.py @@ -130,6 +130,10 @@ ffi.cdef( int wc_RsaSetRNG(RsaKey* key, WC_RNG* rng); int wc_FreeRsaKey(RsaKey* key); + int wc_MakeRsaKey(RsaKey* key, int size, long e, WC_RNG* rng); + int wc_RsaKeyToDer(RsaKey* key, byte* output, word32 inLen); + int wc_RsaKeyToPublicDer(RsaKey* key, byte* output, word32 inLen); + int wc_RsaPrivateKeyDecode(const byte*, word32*, RsaKey*, word32); int wc_RsaPublicKeyDecode(const byte*, word32*, RsaKey*, word32); int wc_RsaEncryptSize(RsaKey*); diff --git a/src/wolfcrypt/ciphers.py b/src/wolfcrypt/ciphers.py index c24932e..16cd960 100644 --- a/src/wolfcrypt/ciphers.py +++ b/src/wolfcrypt/ciphers.py @@ -273,20 +273,21 @@ class _Rsa(object): # pylint: disable=too-few-public-methods class RsaPublic(_Rsa): - def __init__(self, key): - key = t2b(key) + def __init__(self, key=None): + if key != None: + key = t2b(key) _Rsa.__init__(self) idx = _ffi.new("word32*") idx[0] = 0 - ret = _lib.wc_RsaPublicKeyDecode(key, idx, - self.native_object, len(key)) + self.native_object, len(key)) if ret < 0: raise WolfCryptError("Invalid key error (%d)" % ret) self.output_size = _lib.wc_RsaEncryptSize(self.native_object) + self.size = len(key) if self.output_size <= 0: # pragma: no cover raise WolfCryptError("Invalid key error (%d)" % self.output_size) @@ -336,22 +337,61 @@ class RsaPublic(_Rsa): class RsaPrivate(RsaPublic): - def __init__(self, key): # pylint: disable=super-init-not-called - key = t2b(key) + @classmethod + def make_key(cls, size, rng=Random()): + """ + Generates a new key pair of desired length **size**. + """ + rsa = cls(None) + if rsa == None: # pragma: no cover + raise WolfCryptError("Invalid key error (%d)" % ret) + + ret = _lib.wc_MakeRsaKey(rsa.native_object, size, 65537, rng.native_object) + if ret < 0: + raise WolfCryptError("Key generation error (%d)" % ret) + rsa.output_size = _lib.wc_RsaEncryptSize(rsa.native_object) + rsa.size = size + if rsa.output_size <= 0: # pragma: no cover + raise WolfCryptError("Invalid key size error (%d)" % rsa.output_size) + return rsa + def __init__(self, key = None): # pylint: disable=super-init-not-called _Rsa.__init__(self) # pylint: disable=non-parent-init-called idx = _ffi.new("word32*") idx[0] = 0 - ret = _lib.wc_RsaPrivateKeyDecode(key, idx, - self.native_object, len(key)) - if ret < 0: - raise WolfCryptError("Invalid key error (%d)" % ret) + if key != None: + key = t2b(key) + ret = _lib.wc_RsaPrivateKeyDecode(key, idx, + self.native_object, len(key)) + if ret < 0: + raise WolfCryptError("Invalid key error (%d)" % ret) - self.output_size = _lib.wc_RsaEncryptSize(self.native_object) - if self.output_size <= 0: # pragma: no cover - raise WolfCryptError("Invalid key error (%d)" % self.output_size) + self.size = len(key) + self.output_size = _lib.wc_RsaEncryptSize(self.native_object) + if self.output_size <= 0: # pragma: no cover + raise WolfCryptError("Invalid key size error (%d)" % self.output_size) + + def encode_key(self): + """ + Encodes the RSA private and public keys in an ASN sequence. + + Returns the encoded key. + """ + priv = _ffi.new("byte[%d]" % (self.size * 4)) + pub = _ffi.new("byte[%d]" % (self.size * 4)) + + + ret = _lib.wc_RsaKeyToDer(self.native_object, priv, self.size) + if ret <= 0: # pragma: no cover + raise WolfCryptError("Private RSA key error (%d)" % ret) + privlen = ret + ret = _lib.wc_RsaKeyToPublicDer(self.native_object, pub, self.size) + if ret <= 0: # pragma: no cover + raise WolfCryptError("Public RSA key encode error (%d)" % ret) + publen = ret + return _ffi.buffer(priv, privlen)[:], _ffi.buffer(pub, publen)[:] def decrypt(self, ciphertext): """ diff --git a/tests/test_ciphers.py b/tests/test_ciphers.py index 9dde93b..cf86c37 100644 --- a/tests/test_ciphers.py +++ b/tests/test_ciphers.py @@ -213,6 +213,9 @@ def test_new_rsa_raises(vectors): with pytest.raises(WolfCryptError): RsaPublic(vectors[RsaPublic].key[:-1]) # invalid key length + with pytest.raises(WolfCryptError): # invalid key size + RsaPrivate.make_key(16384) + def test_rsa_encrypt_decrypt(rsa_private, rsa_public): plaintext = t2b("Everyone gets Friday off.") @@ -247,17 +250,14 @@ def test_rsa_sign_verify(rsa_private, rsa_public): assert 1024 / 8 == len(signature) == rsa_private.output_size assert plaintext == rsa_private.verify(signature) - @pytest.fixture def ecc_private(vectors): return EccPrivate(vectors[EccPrivate].key) - @pytest.fixture def ecc_public(vectors): return EccPublic(vectors[EccPublic].key) - def test_new_ecc_raises(vectors): with pytest.raises(WolfCryptError): EccPrivate(vectors[EccPrivate].key[:-1]) # invalid key length