Skip to content

Commit 049cc4a

Browse files
committed
Moved key load/save to PrivateKey class
1 parent 6ab5251 commit 049cc4a

2 files changed

Lines changed: 114 additions & 110 deletions

File tree

rsa/key.py

Lines changed: 110 additions & 106 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,114 @@ def __eq__(self, other):
131131
def __ne__(self, other):
132132
return not (self == other)
133133

134+
@classmethod
135+
def load_pkcs1_der(cls, keyfile):
136+
r'''Loads a key in PKCS#1 DER format.
137+
138+
@param keyfile: contents of a DER-encoded file that contains the private
139+
key.
140+
@return: a PrivateKey object
141+
142+
First let's construct a DER encoded key:
143+
144+
>>> import base64
145+
>>> b64der = 'MC4CAQACBQDeKYlRAgMBAAECBQDHn4npAgMA/icCAwDfxwIDANcXAgInbwIDAMZt'
146+
>>> der = base64.decodestring(b64der)
147+
148+
This loads the file:
149+
150+
>>> PrivateKey.load_pkcs1_der(der)
151+
PrivateKey(3727264081, 65537, 3349121513, 65063, 57287)
152+
153+
'''
154+
155+
from pyasn1.codec.der import decoder
156+
(priv, _) = decoder.decode(keyfile)
157+
158+
# ASN.1 contents of DER encoded private key:
159+
#
160+
# RSAPrivateKey ::= SEQUENCE {
161+
# version Version,
162+
# modulus INTEGER, -- n
163+
# publicExponent INTEGER, -- e
164+
# privateExponent INTEGER, -- d
165+
# prime1 INTEGER, -- p
166+
# prime2 INTEGER, -- q
167+
# exponent1 INTEGER, -- d mod (p-1)
168+
# exponent2 INTEGER, -- d mod (q-1)
169+
# coefficient INTEGER, -- (inverse of q) mod p
170+
# otherPrimeInfos OtherPrimeInfos OPTIONAL
171+
# }
172+
173+
if priv[0] != 0:
174+
raise ValueError('Unable to read this file, version %s != 0' % priv[0])
175+
176+
return cls(*priv[1:9])
177+
178+
def save_pkcs1_der(self):
179+
'''Saves the private key in PKCS#1 DER format.
180+
181+
@param priv_key: the private key to save
182+
@returns: the DER-encoded private key.
183+
'''
184+
185+
from pyasn1.type import univ, namedtype, tag
186+
from pyasn1.codec.der import encoder
187+
188+
class AsnPrivKey(univ.Sequence):
189+
componentType = namedtype.NamedTypes(
190+
namedtype.NamedType('version', univ.Integer()),
191+
namedtype.NamedType('modulus', univ.Integer()),
192+
namedtype.NamedType('publicExponent', univ.Integer()),
193+
namedtype.NamedType('privateExponent', univ.Integer()),
194+
namedtype.NamedType('prime1', univ.Integer()),
195+
namedtype.NamedType('prime2', univ.Integer()),
196+
namedtype.NamedType('exponent1', univ.Integer()),
197+
namedtype.NamedType('exponent2', univ.Integer()),
198+
namedtype.NamedType('coefficient', univ.Integer()),
199+
)
200+
201+
# Create the ASN object
202+
asn_key = AsnPrivKey()
203+
asn_key.setComponentByName('version', 0)
204+
asn_key.setComponentByName('modulus', self.n)
205+
asn_key.setComponentByName('publicExponent', self.e)
206+
asn_key.setComponentByName('privateExponent', self.d)
207+
asn_key.setComponentByName('prime1', self.p)
208+
asn_key.setComponentByName('prime2', self.q)
209+
asn_key.setComponentByName('exponent1', self.exp1)
210+
asn_key.setComponentByName('exponent2', self.exp2)
211+
asn_key.setComponentByName('coefficient', self.coef)
212+
213+
return encoder.encode(asn_key)
214+
215+
@classmethod
216+
def load_pkcs1_pem(cls, keyfile):
217+
'''Loads a PKCS#1 PEM-encoded private key file.
218+
219+
The contents of the file before the "-----BEGIN RSA PRIVATE KEY-----" and
220+
after the "-----END RSA PRIVATE KEY-----" lines is ignored.
221+
222+
@param keyfile: contents of a PEM-encoded file that contains the private
223+
key.
224+
@return: a PrivateKey object
225+
'''
226+
227+
der = rsa.pem.load_pem(keyfile, 'RSA PRIVATE KEY')
228+
return cls.load_pkcs1_der(der)
229+
230+
def save_pkcs1_pem(self):
231+
'''Saves a PKCS#1 PEM-encoded private key file.
232+
233+
@param keyfile: a PrivateKey object
234+
@return: contents of a PEM-encoded file that contains the private key.
235+
'''
236+
237+
der = self.save_pkcs1_der()
238+
return rsa.pem.save_pem(der, 'RSA PRIVATE KEY')
239+
240+
241+
134242
def extended_gcd(a, b):
135243
"""Returns a tuple (r, i, j) such that r = gcd(a, b) = ia + jb
136244
"""
@@ -245,112 +353,8 @@ def newkeys(nbits):
245353
PrivateKey(n, e, d, p, q)
246354
)
247355

248-
def load_private_key_der(keyfile):
249-
r'''Loads a key in DER format.
250-
251-
@param keyfile: contents of a DER-encoded file that contains the private
252-
key.
253-
@return: a PrivateKey object
254-
255-
First let's construct a DER encoded key:
256-
257-
>>> import base64
258-
>>> b64der = 'MC4CAQACBQDeKYlRAgMBAAECBQDHn4npAgMA/icCAwDfxwIDANcXAgInbwIDAMZt'
259-
>>> der = base64.decodestring(b64der)
260-
261-
This loads the file:
262-
263-
>>> load_private_key_der(der)
264-
PrivateKey(3727264081, 65537, 3349121513, 65063, 57287)
265-
266-
'''
267-
268-
from pyasn1.codec.der import decoder
269-
(priv, _) = decoder.decode(keyfile)
270-
271-
# ASN.1 contents of DER encoded private key:
272-
#
273-
# RSAPrivateKey ::= SEQUENCE {
274-
# version Version,
275-
# modulus INTEGER, -- n
276-
# publicExponent INTEGER, -- e
277-
# privateExponent INTEGER, -- d
278-
# prime1 INTEGER, -- p
279-
# prime2 INTEGER, -- q
280-
# exponent1 INTEGER, -- d mod (p-1)
281-
# exponent2 INTEGER, -- d mod (q-1)
282-
# coefficient INTEGER, -- (inverse of q) mod p
283-
# otherPrimeInfos OtherPrimeInfos OPTIONAL
284-
# }
285-
286-
if priv[0] != 0:
287-
raise ValueError('Unable to read this file, version %s != 0' % priv[0])
288-
289-
return PrivateKey(*priv[1:9])
290-
291-
def save_private_key_der(priv_key):
292-
'''Saves the private key in DER format.
293-
294-
@param priv_key: the private key to save
295-
@returns: the DER-encoded private key.
296-
'''
297-
298-
from pyasn1.type import univ, namedtype, tag
299-
from pyasn1.codec.der import encoder
300-
301-
class AsnPrivKey(univ.Sequence):
302-
componentType = namedtype.NamedTypes(
303-
namedtype.NamedType('version', univ.Integer()),
304-
namedtype.NamedType('modulus', univ.Integer()),
305-
namedtype.NamedType('publicExponent', univ.Integer()),
306-
namedtype.NamedType('privateExponent', univ.Integer()),
307-
namedtype.NamedType('prime1', univ.Integer()),
308-
namedtype.NamedType('prime2', univ.Integer()),
309-
namedtype.NamedType('exponent1', univ.Integer()),
310-
namedtype.NamedType('exponent2', univ.Integer()),
311-
namedtype.NamedType('coefficient', univ.Integer()),
312-
)
313-
314-
# Create the ASN object
315-
asn_key = AsnPrivKey()
316-
asn_key.setComponentByName('version', 0)
317-
asn_key.setComponentByName('modulus', priv_key.n)
318-
asn_key.setComponentByName('publicExponent', priv_key.e)
319-
asn_key.setComponentByName('privateExponent', priv_key.d)
320-
asn_key.setComponentByName('prime1', priv_key.p)
321-
asn_key.setComponentByName('prime2', priv_key.q)
322-
asn_key.setComponentByName('exponent1', priv_key.exp1)
323-
asn_key.setComponentByName('exponent2', priv_key.exp2)
324-
asn_key.setComponentByName('coefficient', priv_key.coef)
325-
326-
return encoder.encode(asn_key)
327-
328-
def load_private_key_pem(keyfile):
329-
'''Loads a PEM-encoded private key file.
330-
331-
The contents of the file before the "-----BEGIN RSA PRIVATE KEY-----" and
332-
after the "-----END RSA PRIVATE KEY-----" lines is ignored.
333-
334-
@param keyfile: contents of a PEM-encoded file that contains the private
335-
key.
336-
@return: a PrivateKey object
337-
'''
338-
339-
der = rsa.pem.load_pem(keyfile, 'RSA PRIVATE KEY')
340-
return load_private_key_der(der)
341-
342-
def save_private_key_pem(priv_key):
343-
'''Saves a PEM-encoded private key file.
344-
345-
@param keyfile: a PrivateKey object
346-
@return: contents of a PEM-encoded file that contains the private key.
347-
'''
348-
349-
der = save_private_key_der(priv_key)
350-
return rsa.pem.save_pem(der, 'RSA PRIVATE KEY')
351-
352-
353-
__all__ = ['PublicKey', 'PrivateKey', 'newkeys', 'load']
356+
__all__ = ['PublicKey', 'PrivateKey', 'newkeys', 'load_private_key_der',
357+
'load_private_key_pem', 'save_private_key_der', 'save_private_key_pem']
354358

355359
if __name__ == '__main__':
356360
import doctest

tests/test_load_save_keys.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ class DerTest(unittest.TestCase):
3333
def test_load_private_key(self):
3434
'''Test loading private DER keys.'''
3535

36-
key = rsa.key.load_private_key_der(PRIVATE_DER)
36+
key = rsa.key.PrivateKey.load_pkcs1_der(PRIVATE_DER)
3737
expected = rsa.key.PrivateKey(3727264081, 65537, 3349121513, 65063, 57287)
3838

3939
self.assertEqual(expected, key)
@@ -42,7 +42,7 @@ def test_save_private_key(self):
4242
'''Test saving private DER keys.'''
4343

4444
key = rsa.key.PrivateKey(3727264081, 65537, 3349121513, 65063, 57287)
45-
der = rsa.key.save_private_key_der(key)
45+
der = key.save_pkcs1_der()
4646

4747
self.assertEqual(PRIVATE_DER, der)
4848

@@ -53,7 +53,7 @@ class PemTest(unittest.TestCase):
5353
def test_load_private_key(self):
5454
'''Test loading private PEM files.'''
5555

56-
key = rsa.key.load_private_key_pem(PRIVATE_PEM)
56+
key = rsa.key.PrivateKey.load_pkcs1_pem(PRIVATE_PEM)
5757
expected = rsa.key.PrivateKey(3727264081, 65537, 3349121513, 65063, 57287)
5858

5959
self.assertEqual(expected, key)
@@ -62,7 +62,7 @@ def test_save_private_key(self):
6262
'''Test saving private PEM files.'''
6363

6464
key = rsa.key.PrivateKey(3727264081, 65537, 3349121513, 65063, 57287)
65-
pem = rsa.key.save_private_key_pem(key)
65+
pem = key.save_pkcs1_pem()
6666

6767
self.assertEqual(CLEAN_PRIVATE_PEM, pem)
6868

0 commit comments

Comments
 (0)