Skip to content
This repository was archived by the owner on Jan 18, 2025. It is now read-only.

Added support for pure Python RSA library when present. #1

Closed
wants to merge 5 commits into from
Closed
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
76 changes: 73 additions & 3 deletions crypt.py
Original file line number Diff line number Diff line change
Expand Up @@ -244,16 +244,86 @@ def from_string(key, password='notasecret'):
PyCryptoVerifier = None
PyCryptoSigner = None

# Use pure Python RSA module if installed.
# Dependencies:
# For signing only: easy_install rsa
# For X509 verifications: easy_install rsa pyasn1_modules
try:
import rsa

def _BitStringToByteString(bs):
def BitsToInt(bits):
return sum(v * (2 ** (7 - j)) for j, v in enumerate(bits))
return str(bytearray([BitsToInt(bs[i:i + 8]) for i in range(0, len(bs), 8)]))

# Equivalent class to OpenSSLVerifier above
class RsaVerifier(object):
def __init__(self, pubkey):
self._pubkey = pubkey

def verify(self, message, signature):
try:
return rsa.pkcs1.verify(message, signature, self._pubkey)
except rsa.pkcs1.VerificationError:
return False

@staticmethod
def from_string(key_pem, is_x509_cert):
if is_x509_cert:
try:
from pyasn1.codec.der import decoder
from pyasn1_modules.rfc2459 import Certificate

der = rsa.pem.load_pem(key_pem, 'CERTIFICATE')
asn1_cert, _ = decoder.decode(der, asn1Spec=Certificate())

pubkey = rsa.PublicKey.load_pkcs1(_BitStringToByteString(
asn1_cert['tbsCertificate']['subjectPublicKeyInfo']['subjectPublicKey']), 'DER')
except ImportError:
raise NotImplementedError(
'Please install pyasn1 and pyasn1_modules to parse x509.')
else:
pubkey = rsa.PublicKey.load_pkcs1(key_pem, 'PEM')
return RsaVerifier(pubkey)


# Equivalent class to OpenSSLSigner above
class RsaSigner(object):
def __init__(self, pkey):
self._key = pkey

This comment was marked as spam.

This comment was marked as spam.

This comment was marked as spam.

This comment was marked as spam.

This comment was marked as spam.

This comment was marked as spam.


def sign(self, message):
return rsa.pkcs1.sign(message, self._key, 'SHA-256')

@staticmethod
def from_string(key, password='notasecret'):
if key.startswith('-----BEGIN '):
pkey = rsa.key.PrivateKey.load_pkcs1(key, 'PEM')
else:
raise NotImplementedError(
'PKCS12 format is not supported by the RSA library. '
'Either install PyOpenSSL, or '
'please convert .p12 format to .pem format: \n'
'cat key.p12 | openssl pkcs12 -nodes -nocerts -passin '
'pass:notasecret | openssl rsa > key.pem')
return RsaSigner(pkey)

except ImportError:
RsaSigner = None

This comment was marked as spam.

This comment was marked as spam.

RsaVerifier = None

if OpenSSLSigner:
if OpenSSLSigner: # Supports PEM, X509, PKCS12
Signer = OpenSSLSigner
Verifier = OpenSSLVerifier
elif PyCryptoSigner:
elif RsaSigner: # Supports PEM, X509
Signer = RsaSigner
Verifier = RsaVerifier
elif PyCryptoSigner: # Supports PEM
Signer = PyCryptoSigner
Verifier = PyCryptoVerifier
else:
raise ImportError('No encryption library found. Please install either '
'PyOpenSSL, or PyCrypto 2.6 or later')
'PyOpenSSL, PyCrypto 2.6 or later, or rsa.')


def _urlsafe_b64encode(raw_bytes):
Expand Down