|
6 | 6 | ''' |
7 | 7 |
|
8 | 8 | import rsa.prime |
| 9 | +import rsa.pem |
9 | 10 |
|
10 | 11 | class PublicKey(object): |
11 | 12 | '''Represents a public RSA key. |
@@ -75,19 +76,6 @@ class PrivateKey(object): |
75 | 76 |
|
76 | 77 | ''' |
77 | 78 |
|
78 | | - # RSAPrivateKey ::= SEQUENCE { |
79 | | - # version Version, |
80 | | - # modulus INTEGER, -- n |
81 | | - # publicExponent INTEGER, -- e |
82 | | - # privateExponent INTEGER, -- d |
83 | | - # prime1 INTEGER, -- p |
84 | | - # prime2 INTEGER, -- q |
85 | | - # exponent1 INTEGER, -- d mod (p-1) |
86 | | - # exponent2 INTEGER, -- d mod (q-1) |
87 | | - # coefficient INTEGER, -- (inverse of q) mod p |
88 | | - # otherPrimeInfos OtherPrimeInfos OPTIONAL |
89 | | - # } |
90 | | - |
91 | 79 | __slots__ = ('n', 'e', 'd', 'p', 'q', 'exp1', 'exp2', 'coef') |
92 | 80 |
|
93 | 81 | def __init__(self, n, e, d, p, q, exp1=None, exp2=None, coef=None): |
@@ -119,6 +107,24 @@ def __getitem__(self, key): |
119 | 107 | def __repr__(self): |
120 | 108 | return u'PrivateKey(%(n)i, %(e)i, %(d)i, %(p)i, %(q)i)' % self |
121 | 109 |
|
| 110 | + def __eq__(self, other): |
| 111 | + if other is None: |
| 112 | + return False |
| 113 | + |
| 114 | + if not isinstance(other, PrivateKey): |
| 115 | + return False |
| 116 | + |
| 117 | + return (self.n == other.n and |
| 118 | + self.e == other.e and |
| 119 | + self.d == other.d and |
| 120 | + self.p == other.p and |
| 121 | + self.q == other.q and |
| 122 | + self.exp1 == other.exp1 and |
| 123 | + self.exp2 == other.exp2 and |
| 124 | + self.coef == other.coef) |
| 125 | + |
| 126 | + def __ne__(self, other): |
| 127 | + return not (self == other) |
122 | 128 |
|
123 | 129 | def extended_gcd(a, b): |
124 | 130 | """Returns a tuple (r, i, j) such that r = gcd(a, b) = ia + jb |
@@ -234,7 +240,68 @@ def newkeys(nbits): |
234 | 240 | PrivateKey(n, e, d, p, q) |
235 | 241 | ) |
236 | 242 |
|
237 | | -__all__ = ['PublicKey', 'PrivateKey', 'newkeys'] |
| 243 | +def load_private_key_der(keyfile): |
| 244 | + r'''Loads a key in DER format. |
| 245 | +
|
| 246 | + @param keyfile: contents of a DER-encoded file that contains the private |
| 247 | + key. |
| 248 | + @return: a PrivateKey object |
| 249 | +
|
| 250 | + First let's construct a DER encoded key: |
| 251 | +
|
| 252 | + >>> import base64 |
| 253 | + >>> b64der = 'MC4CAQACBQDeKYlRAgMBAAECBQDHn4npAgMA/icCAwDfxwIDANcXAgInbwIDAMZt' |
| 254 | + >>> der = base64.decodestring(b64der) |
| 255 | +
|
| 256 | + This loads the file: |
| 257 | +
|
| 258 | + >>> load_private_key_der(der) |
| 259 | + PrivateKey(3727264081, 65537, 3349121513, 65063, 57287) |
| 260 | +
|
| 261 | + ''' |
| 262 | + |
| 263 | + from pyasn1.codec.der import decoder |
| 264 | + (priv, _) = decoder.decode(keyfile) |
| 265 | + |
| 266 | + # ASN.1 contents of DER encoded private key: |
| 267 | + # |
| 268 | + # RSAPrivateKey ::= SEQUENCE { |
| 269 | + # version Version, |
| 270 | + # modulus INTEGER, -- n |
| 271 | + # publicExponent INTEGER, -- e |
| 272 | + # privateExponent INTEGER, -- d |
| 273 | + # prime1 INTEGER, -- p |
| 274 | + # prime2 INTEGER, -- q |
| 275 | + # exponent1 INTEGER, -- d mod (p-1) |
| 276 | + # exponent2 INTEGER, -- d mod (q-1) |
| 277 | + # coefficient INTEGER, -- (inverse of q) mod p |
| 278 | + # otherPrimeInfos OtherPrimeInfos OPTIONAL |
| 279 | + # } |
| 280 | + |
| 281 | + if priv[0] != 0: |
| 282 | + raise ValueError('Unable to read this file, version %s != 0' % priv[0]) |
| 283 | + |
| 284 | + return PrivateKey(*priv[1:9]) |
| 285 | + |
| 286 | +def load_private_key_pem(keyfile): |
| 287 | + '''Loads a PEM-encoded private key file. |
| 288 | +
|
| 289 | + The contents of the file before the "-----BEGIN RSA PRIVATE KEY-----" and |
| 290 | + after the "-----END RSA PRIVATE KEY-----" lines is ignored. |
| 291 | +
|
| 292 | + @param keyfile: contents of a PEM-encoded file that contains the private |
| 293 | + key. |
| 294 | + @return: a PrivateKey object |
| 295 | + ''' |
| 296 | + |
| 297 | + PEM_START = '-----BEGIN RSA PRIVATE KEY-----' |
| 298 | + PEM_END = '-----END RSA PRIVATE KEY-----' |
| 299 | + |
| 300 | + der = rsa.pem.load_pem(keyfile, PEM_START, PEM_END) |
| 301 | + return load_private_key_der(der) |
| 302 | + |
| 303 | + |
| 304 | +__all__ = ['PublicKey', 'PrivateKey', 'newkeys', 'load'] |
238 | 305 |
|
239 | 306 | if __name__ == '__main__': |
240 | 307 | import doctest |
|
0 commit comments