Skip to content

Commit 4bc9733

Browse files
committed
Fix sybrenstuvel#12 Allow pickling of keys.
Pickling is now possible, with the added note that one should never unpickle from an untrusted or unauthenticated source.
1 parent f1c5554 commit 4bc9733

3 files changed

Lines changed: 52 additions & 0 deletions

File tree

doc/reference.rst

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,14 @@ Functions
2121
Classes
2222
--------------------------------------------------
2323

24+
.. note::
25+
26+
Storing public and private keys via the `pickle` module is possible.
27+
However, it is insecure to load a key from an untrusted source.
28+
The pickle module is not secure against erroneous or maliciously
29+
constructed data. Never unpickle data received from an untrusted
30+
or unauthenticated source.
31+
2432
.. autoclass:: rsa.PublicKey
2533
:members:
2634
:inherited-members:

rsa/key.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,14 @@
2323
late as possible, such that other functionality will remain working in absence
2424
of pyasn1.
2525
26+
.. note::
27+
28+
Storing public and private keys via the `pickle` module is possible.
29+
However, it is insecure to load a key from an untrusted source.
30+
The pickle module is not secure against erroneous or maliciously
31+
constructed data. Never unpickle data received from an untrusted
32+
or unauthenticated source.
33+
2634
"""
2735

2836
import logging
@@ -154,6 +162,14 @@ def __getitem__(self, key):
154162
def __repr__(self):
155163
return 'PublicKey(%i, %i)' % (self.n, self.e)
156164

165+
def __getstate__(self):
166+
"""Returns the key as tuple for pickling."""
167+
return self.n, self.e
168+
169+
def __setstate__(self, state):
170+
"""Sets the key from tuple."""
171+
self.n, self.e = state
172+
157173
def __eq__(self, other):
158174
if other is None:
159175
return False
@@ -337,6 +353,14 @@ def __getitem__(self, key):
337353
def __repr__(self):
338354
return 'PrivateKey(%(n)i, %(e)i, %(d)i, %(p)i, %(q)i)' % self
339355

356+
def __getstate__(self):
357+
"""Returns the key as tuple for pickling."""
358+
return self.n, self.e, self.d, self.p, self.q, self.exp1, self.exp2, self.coef
359+
360+
def __setstate__(self, state):
361+
"""Sets the key from tuple."""
362+
self.n, self.e, self.d, self.p, self.q, self.exp1, self.exp2, self.coef = state
363+
340364
def __eq__(self, other):
341365
if other is None:
342366
return False

tests/test_load_save_keys.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
import base64
2020
import unittest
2121
import os.path
22+
import pickle
2223

2324
from rsa._compat import b
2425

@@ -152,3 +153,22 @@ def test_load_from_disk(self):
152153

153154
self.assertEqual(15945948582725241569, privkey.p)
154155
self.assertEqual(14617195220284816877, privkey.q)
156+
157+
158+
class PickleTest(unittest.TestCase):
159+
"""Test saving and loading keys by pickling."""
160+
161+
def test_private_key(self):
162+
pk = rsa.key.PrivateKey(3727264081, 65537, 3349121513, 65063, 57287)
163+
164+
pickled = pickle.dumps(pk)
165+
unpickled = pickle.loads(pickled)
166+
self.assertEqual(pk, unpickled)
167+
168+
def test_public_key(self):
169+
pk = rsa.key.PublicKey(3727264081, 65537)
170+
171+
pickled = pickle.dumps(pk)
172+
unpickled = pickle.loads(pickled)
173+
174+
self.assertEqual(pk, unpickled)

0 commit comments

Comments
 (0)