mirror of
https://github.com/theupdateframework/python-tuf
synced 2026-05-24 10:08:28 +00:00
Add import and export functions for passphrase-protected pem files in keys.py
This commit is contained in:
parent
45af91191a
commit
5eb0858e45
1 changed files with 179 additions and 0 deletions
179
tuf/keys.py
179
tuf/keys.py
|
|
@ -759,6 +759,185 @@ def verify_signature(key_dict, signature, data):
|
|||
|
||||
|
||||
|
||||
|
||||
|
||||
def import_rsakey_from_encrypted_pem(encrypted_pem, password):
|
||||
"""
|
||||
<Purpose>
|
||||
Generate public and private RSA keys, with modulus length 'bits'. In
|
||||
addition, a keyid identifier for the RSA key is generated. The object
|
||||
returned conforms to 'tuf.formats.RSAKEY_SCHEMA' and has the
|
||||
form:
|
||||
{'keytype': 'rsa',
|
||||
'keyid': keyid,
|
||||
'keyval': {'public': '-----BEGIN RSA PUBLIC KEY----- ...',
|
||||
'private': '-----BEGIN RSA PRIVATE KEY----- ...'}}
|
||||
|
||||
The public and private keys are strings in PEM format.
|
||||
|
||||
Although the PyCrypto crytography library called sets a 1024-bit minimum
|
||||
key size, generate() enforces a minimum key size of 2048 bits. If 'bits' is
|
||||
unspecified, a 3072-bit RSA key is generated, which is the key size
|
||||
recommended by TUF.
|
||||
|
||||
>>> rsa_key = generate_rsa_key()
|
||||
>>> private = rsa_key['keyval']['private']
|
||||
>>> passphrase = 'secret'
|
||||
>>> encrypted_pem = create_rsa_encrypted_pem(private, passphrase)
|
||||
>>> rsa_key2 = import_rsakey_from_encrypted_pem(encrypted_pem, passphrase)
|
||||
>>> rsa_key == rsa_key2
|
||||
True
|
||||
|
||||
<Arguments>
|
||||
encrypted_pem:
|
||||
The key size, or key length, of the RSA key. 'bits' must be 2048, or
|
||||
greater, and a multiple of 256.
|
||||
|
||||
password:
|
||||
|
||||
<Exceptions>
|
||||
tuf.FormatError, if 'bits' is improperly or invalid (i.e., not an integer
|
||||
and not at least 2048).
|
||||
|
||||
tuf.UnsupportedLibraryError, if any of the cryptography libraries specified
|
||||
in 'tuf.conf.py' are unsupported or unavailable.
|
||||
|
||||
ValueError, if an exception occurs after calling the RSA key generation
|
||||
routine. 'bits' must be a multiple of 256. The 'ValueError' exception is
|
||||
raised by the key generation function of the cryptography library called.
|
||||
|
||||
<Side Effects>
|
||||
The RSA keys are generated by calling PyCrypto's
|
||||
Crypto.PublicKey.RSA.generate().
|
||||
|
||||
<Returns>
|
||||
A dictionary containing the RSA keys and other identifying information.
|
||||
Conforms to 'tuf.formats.RSAKEY_SCHEMA'.
|
||||
"""
|
||||
|
||||
# Does 'encrypted_pem' have the correct format?
|
||||
# This check will ensure 'encrypted_pem' conforms to
|
||||
# 'tuf.formats.PEMRSA_SCHEMA'.
|
||||
tuf.formats.PEMRSA_SCHEMA.check_match(encrypted_pem)
|
||||
|
||||
# Does 'password' have the correct format?
|
||||
tuf.formats.PASSWORD_SCHEMA.check_match(password)
|
||||
|
||||
# Raise 'tuf.UnsupportedLibraryError' if the following libraries, specified in
|
||||
# 'tuf.conf', are unsupported or unavailable:
|
||||
# 'tuf.conf.RSA_CRYPTO_LIBRARY' and 'tuf.conf.ED25519_CRYPTO_LIBRARY'.
|
||||
_check_crypto_libraries()
|
||||
|
||||
# Begin building the RSA key dictionary.
|
||||
rsakey_dict = {}
|
||||
keytype = 'rsa'
|
||||
public = None
|
||||
private = None
|
||||
|
||||
# Generate the public and private RSA keys. The PyCrypto module performs
|
||||
# the actual key generation. Raise 'ValueError' if 'bits' is less than 1024
|
||||
# or not a multiple of 256, although a 2048-bit minimum is enforced by
|
||||
# tuf.formats.RSAKEYBITS_SCHEMA.check_match().
|
||||
if _RSA_CRYPTO_LIBRARY == 'pycrypto':
|
||||
public, private = \
|
||||
tuf.pycrypto_keys.create_rsa_public_and_private_from_encrypted_pem(encrypted_pem,
|
||||
password)
|
||||
else:
|
||||
message = 'Invalid crypto library: '+repr(_RSA_CRYPTO_LIBRARY)+'.'
|
||||
raise tuf.UnsupportedLibraryError(message)
|
||||
|
||||
# Generate the keyid of the RSA key. 'key_value' corresponds to the
|
||||
# 'keyval' entry of the 'RSAKEY_SCHEMA' dictionary. The private key
|
||||
# information is not included in the generation of the 'keyid' identifier.
|
||||
key_value = {'public': public,
|
||||
'private': ''}
|
||||
keyid = _get_keyid(keytype, key_value)
|
||||
|
||||
# Build the 'rsakey_dict' dictionary. Update 'key_value' with the RSA
|
||||
# private key prior to adding 'key_value' to 'rsakey_dict'.
|
||||
key_value['private'] = private
|
||||
|
||||
rsakey_dict['keytype'] = keytype
|
||||
rsakey_dict['keyid'] = keyid
|
||||
rsakey_dict['keyval'] = key_value
|
||||
|
||||
return rsakey_dict
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
def create_rsa_encrypted_pem(private_key, passphrase):
|
||||
"""
|
||||
<Purpose>
|
||||
Return a string in PEM format, where the private part of the RSA key is
|
||||
encrypted. The private part of the RSA key is encrypted by the Triple
|
||||
Data Encryption Algorithm (3DES) and Cipher-block chaining (CBC) for the
|
||||
mode of operation. Password-Based Key Derivation Function 1 (PBKF1) + MD5
|
||||
is used to strengthen 'passphrase'.
|
||||
|
||||
https://en.wikipedia.org/wiki/Triple_DES
|
||||
https://en.wikipedia.org/wiki/PBKDF2
|
||||
|
||||
>>> rsa_key = generate_rsa_key()
|
||||
>>> private = rsa_key['keyval']['private']
|
||||
>>> passphrase = 'secret'
|
||||
>>> encrypted_pem = create_rsa_encrypted_pem(private, passphrase)
|
||||
>>> tuf.formats.PEMRSA_SCHEMA.matches(encrypted_pem)
|
||||
True
|
||||
|
||||
<Arguments>
|
||||
private_key:
|
||||
The private key string in PEM format.
|
||||
|
||||
passphrase:
|
||||
The passphrase, or password, to encrypt the private part of the RSA
|
||||
key. 'passphrase' is not used directly as the encryption key, a stronger
|
||||
encryption key is derived from it.
|
||||
|
||||
<Exceptions>
|
||||
tuf.FormatError, if the arguments are improperly formatted.
|
||||
|
||||
tuf.CryptoError, if an RSA key in encrypted PEM format cannot be created.
|
||||
|
||||
TypeError, 'private_key' is unset.
|
||||
|
||||
<Side Effects>
|
||||
PyCrypto's Crypto.PublicKey.RSA.exportKey() called to perform the actual
|
||||
generation of the PEM-formatted output.
|
||||
|
||||
<Returns>
|
||||
A string in PEM format, where the private RSA key is encrypted.
|
||||
Conforms to 'tuf.formats.PEMRSA_SCHEMA'.
|
||||
"""
|
||||
|
||||
# Does 'private_key' have the correct format?
|
||||
# This check will ensure 'private_key' has the appropriate number
|
||||
# of objects and object types, and that all dict keys are properly named.
|
||||
# Raise 'tuf.FormatError' if the check fails.
|
||||
tuf.formats.PEMRSA_SCHEMA.check_match(private_key)
|
||||
|
||||
# Does 'passphrase' have the correct format?
|
||||
tuf.formats.PASSWORD_SCHEMA.check_match(passphrase)
|
||||
|
||||
encrypted_pem = None
|
||||
|
||||
# Generate the public and private RSA keys. The PyCrypto module performs
|
||||
# the actual key generation. Raise 'ValueError' if 'bits' is less than 1024
|
||||
# or not a multiple of 256, although a 2048-bit minimum is enforced by
|
||||
# tuf.formats.RSAKEYBITS_SCHEMA.check_match().
|
||||
if _RSA_CRYPTO_LIBRARY == 'pycrypto':
|
||||
encrypted_pem = \
|
||||
tuf.pycrypto_keys.create_rsa_encrypted_pem(private_key, passphrase)
|
||||
else:
|
||||
message = 'Invalid crypto library: '+repr(_RSA_CRYPTO_LIBRARY)+'.'
|
||||
raise tuf.UnsupportedLibraryError(message)
|
||||
|
||||
return encrypted_pem
|
||||
|
||||
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
# The interactive sessions of the documentation strings can
|
||||
# be tested by running 'keys.py' as a standalone module.
|
||||
|
|
|
|||
Loading…
Reference in a new issue