bridgedb.crypto

This module contains general utilities for working with external cryptographic tools and libraries, including OpenSSL and GnuPG. It also includes utilities for creating callable HMAC functions, generating HMACs for data, and generating and/or storing key material.

bridgedb.crypto
  |_getGPGContext() - Get a pre-configured GPGME context.
  |_getHMAC() - Compute an HMAC with some key for some data.
  |_getHMACFunc() - Get a callable for producing HMACs with the given key.
  |_getKey() - Load the master HMAC key from a file, or create a new one.
  |_getRSAKey() - Load an RSA key from a file, or create a new one.
  |_gpgSignMessage() - Sign a message string according to a GPGME context.
  |_writeKeyToFile() - Write to a file readable only by the process owner.
  |
  \_SSLVerifyingContextFactory - OpenSSL.SSL.Context factory which verifies
     |                           certificate chains and matches hostnames.
     |_getContext() - Retrieve an SSL context configured for certificate
     |                verification.
     |_getHostnameFromURL() - Parses the hostname from the request URL.
     \_verifyHostname() - Check that the cert CN matches the request
                          hostname.
DIGESTMOD()

The hash digest to use for HMACs.

NEW_BUFFER_INTERFACE = True

True if we have the new-style buffer interface; False otherwise.

exception PKCS1PaddingError[source]

Bases: exceptions.Exception

Raised when there is a problem adding or removing PKCS#1 padding.

exception RSAKeyGenerationError[source]

Bases: exceptions.Exception

Raised when there was an error creating an RSA keypair.

writeKeyToFile(key, filename)[source]

Write key to filename, with 0400 permissions.

If filename doesn’t exist, it will be created. If it does exist already, and is writable by the owner of the current process, then it will be truncated to zero-length and overwritten.

Parameters:
  • key (bytes) – A key (or some other private data) to write to filename.
  • filename (str) – The path of the file to write to.
Raises:

Any exceptions which may occur.

getRSAKey(filename, bits=2048)[source]

Load the RSA key stored in filename, or create and save a new key.

>>> from bridgedb import crypto
>>> keyfile = 'doctest_getRSAKey'
>>> message = "The secret words are Squeamish Ossifrage."
>>> keypair = crypto.getRSAKey(keyfile, bits=2048)
>>> (secretkey, publickey) = keypair
>>> encrypted = publickey.encrypt(message)
>>> assert encrypted != message
>>> decrypted = secretkey.decrypt(encrypted)
>>> assert message == decrypted

If filename already exists, it is assumed to contain a PEM-encoded RSA private key, which will be read from the file. (The parameters of a private RSA key contain the public exponent and public modulus, which together comprise the public key ― ergo having two separate keyfiles is assumed unnecessary.)

If filename doesn’t exist, a new RSA keypair will be created, and the private key will be stored in filename, using writeKeyToFile().

Once the private key is either loaded or created, the public key is extracted from it. Both keys are then input into PKCS#1 RSAES-OAEP cipher schemes (see RFC 3447 §7.1) in order to introduce padding, and then returned.

Parameters:
  • filename (str) – The filename to which the secret parameters of the RSA key are stored in.
  • bits (int) – If no key is found within the file, create a new key with this bitlength and store it in filename.
Return type:

tuple of Crypto.Cipher.PKCS1_OAEP.PKCS1OAEP_Cipher

Returns:

A 2-tuple of (privatekey, publickey), which are PKCS#1 RSAES-OAEP padded and encoded private and public keys, forming an RSA keypair.

getKey(filename)[source]

Load the master key stored in filename, or create a new key.

If filename does not exist, create a new 32-byte key and store it in filename.

>>> import os
>>> from bridgedb import crypto
>>> name = 'doctest_getKey'
>>> os.path.exists(name)
False
>>> k1 = crypto.getKey(name)
>>> os.path.exists(name)
True
>>> open(name).read() == k1
True
>>> k2 = crypto.getKey(name)
>>> k1 == k2
True
Parameters:filename (string) – The filename to store the secret key in.
Return type:bytes
Returns:A byte string containing the secret key.
getHMAC(key, value)[source]

Return the HMAC of value using the key.

getHMACFunc(key, hex=True)[source]

Return a function that computes the HMAC of its input using the key.

Parameters:hex (bool) – If True, the output of the function will be hex-encoded.
Return type:callable
Returns:A function which can be uses to generate HMACs.
removePKCS1Padding(message)[source]

Remove PKCS#1 padding from a message.

(PKCS#1 v1.0? See ticket #13042.)

Each block is 128 bytes total in size:

  • 2 bytes for the type info ('\x00\x01')
  • 1 byte for the separator ('\x00')
  • variable length padding ('\xFF')
  • variable length for the message

For more information on the structure of PKCS#1 padding, see RFC 2313, particularly the notes in §8.1.

Parameters:message (str) – A message which is PKCS#1 padded.
Raises PKCS1PaddingError:
 if there is an issue parsing the message.
Return type:bytes
Returns:The message without the PKCS#1 padding.
initializeGnuPG(config)[source]

Initialize a GnuPG interface and test our configured keys.

Note

This function uses python-gnupg.

Parameters:config (bridgedb.persistent.Conf) – The loaded config file.
Return type:2-tuple
Returns:If EMAIL_GPG_SIGNING_ENABLED isn’t True, or we couldn’t initialize GnuPG and make a successful test signature with the specified key, then a 2-tuple of None is returned. Otherwise, the first item in the tuple is a gnupg.GPG interface with the GnuPG homedir set to the EMAIL_GPG_HOMEDIR option and the signing key specified by the EMAIL_GPG_SIGNING_KEY_FINGERPRINT option in bridgedb.conf set as the default key. The second item in the tuple is a signing function with the passphrase (as specified in either EMAIL_GPG_PASSPHRASE or EMAIL_GPG_PASSPHRASE_FILE) already set.
class SSLVerifyingContextFactory(url, **kwargs)[source]

Bases: twisted.internet._sslverify.OpenSSLCertificateOptions

OpenSSL.SSL.Context factory which does full certificate-chain and hostname verfication.

Create a client-side verifying SSL Context factory.

To pass acceptable certificates for a server which does client-authentication checks: initialise with a caCerts=[] keyword argument, which should be a list of OpenSSL.crypto.X509 instances (one for each peer certificate to add to the store), and set SSLVerifyingContextFactory.isClient=False.

Parameters:
  • url (str) – The URL being requested by an twisted.web.client.Agent.
  • isClient (bool) – True if we’re being used in a client implementation; False if we’re a server.
isClient = True
getContext(hostname=None, port=None)[source]

Retrieve a configured OpenSSL.SSL.Context.

Any certificates in the caCerts list given during initialisation are added to the Context‘s certificate store.

The hostname and port arguments seem unused, but they are required due to some Twisted and pyOpenSSL internals. See twisted.web.client.Agent._wrapContextFactory.

Return type:OpenSSL.SSL.Context
Returns:An SSL Context which verifies certificates.
getHostnameFromURL(url)[source]

Parse the hostname from the originally requested URL.

Parameters:url (str) – The URL being requested by an twisted.web.client.Agent.
Return type:str
Returns:The full hostname (including any subdomains).
verifyHostname(connection, x509, errnum, depth, okay)[source]

Callback method for additional SSL certificate validation.

If the certificate is signed by a valid CA, and the chain is valid, verify that the level 0 certificate has a subject common name which is valid for the hostname of the originally requested URL.

Parameters:
  • connection – An OpenSSL.SSL.Connection.
  • x509 – An OpenSSL.crypto.X509 object.
  • errnum – A pyOpenSSL error number. See that project’s docs.
  • depth – The depth which the current certificate is at in the certificate chain.
  • okay (bool) – True if all the pyOpenSSL default checks on the certificate passed. False otherwise.