signature:
def _unarmor_pem ( data , password = None ) :
    """Removes PEM - encoding from a public key , private key or certificate . If the
 private key is encrypted , the password will be used to decrypt it .
 : param data :
 A byte string of the PEM - encoded data
 : param password :
 A byte string of the encryption password , or None
 : return :
 A 3 - element tuple in the format : ( key _ type , algorithm , der _ bytes ) . The
 key _ type will be a unicode string of " public key " , " private key " or
 " certificate " . The algorithm will be a unicode string of " rsa " , " dsa "
 or " ec " ."""

implementation:
object_type , headers , der_bytes = pem . unarmor ( data )
type_regex = '^((DSA|EC|RSA) PRIVATE KEY|ENCRYPTED PRIVATE KEY|PRIVATE KEY|PUBLIC KEY|RSA PUBLIC KEY|CERTIFICATE)'
armor_type = re . match ( type_regex , object_type )
if not armor_type :
    raise ValueError ( pretty_message ( '''
            data does not seem to contain a PEM-encoded certificate, private
            key or public key
            ''' ) )
pem_header = armor_type . group ( 1 )
data = data . strip ( )
# RSA private keys are encrypted after being DER - encoded , but before base64
# encoding , so they need to be hanlded specially
if pem_header in set ( [ 'RSA PRIVATE KEY' , 'DSA PRIVATE KEY' , 'EC PRIVATE KEY' ] ) :
    algo = armor_type . group ( 2 ) . lower ( )
    return ( 'private key' , algo , _unarmor_pem_openssl_private ( headers , der_bytes , password ) )
key_type = pem_header . lower ( )
algo = None
if key_type == 'encrypted private key' :
    key_type = 'private key'
elif key_type == 'rsa public key' :
    key_type = 'public key'
    algo = 'rsa'
return ( key_type , algo , der_bytes )


signature:
def _unarmor_pem_openssl_private ( headers , data , password ) :
    """Parses a PKCS # 1 private key , or encrypted private key
 : param headers :
 A dict of " Name : Value " lines from right after the PEM header
 : param data :
 A byte string of the DER - encoded PKCS # 1 private key
 : param password :
 A byte string of the password to use if the private key is encrypted
 : return :
 A byte string of the DER - encoded private key"""

implementation:
enc_algo = None
enc_iv_hex = None
enc_iv = None
if 'DEK-Info' in headers :
    params = headers [ 'DEK-Info' ]
    if params . find ( ',' ) != - 1 :
        enc_algo , enc_iv_hex = params . strip ( ) . split ( ',' )
    else :
        enc_algo = 'RC4'
if not enc_algo :
    return data
if enc_iv_hex :
    enc_iv = binascii . unhexlify ( enc_iv_hex . encode ( 'ascii' ) )
enc_algo = enc_algo . lower ( )
enc_key_length = { 'aes-128-cbc' : 16 , 'aes-128' : 16 , 'aes-192-cbc' : 24 , 'aes-192' : 24 , 'aes-256-cbc' : 32 , 'aes-256' : 32 , 'rc4' : 16 , 'rc4-64' : 8 , 'rc4-40' : 5 , 'rc2-64-cbc' : 8 , 'rc2-40-cbc' : 5 , 'rc2-cbc' : 16 , 'rc2' : 16 , 'des-ede3-cbc' : 24 , 'des-ede3' : 24 , 'des3' : 24 , 'des-ede-cbc' : 16 , 'des-cbc' : 8 , 'des' : 8 , } [ enc_algo ]
enc_key = hashlib . md5 ( password + enc_iv [ 0 : 8 ] ) . digest ( )
while enc_key_length > len ( enc_key ) :
    enc_key += hashlib . md5 ( enc_key + password + enc_iv [ 0 : 8 ] ) . digest ( )
enc_key = enc_key [ 0 : enc_key_length ]
enc_algo_name = { 'aes-128-cbc' : 'aes' , 'aes-128' : 'aes' , 'aes-192-cbc' : 'aes' , 'aes-192' : 'aes' , 'aes-256-cbc' : 'aes' , 'aes-256' : 'aes' , 'rc4' : 'rc4' , 'rc4-64' : 'rc4' , 'rc4-40' : 'rc4' , 'rc2-64-cbc' : 'rc2' , 'rc2-40-cbc' : 'rc2' , 'rc2-cbc' : 'rc2' , 'rc2' : 'rc2' , 'des-ede3-cbc' : 'tripledes' , 'des-ede3' : 'tripledes' , 'des3' : 'tripledes' , 'des-ede-cbc' : 'tripledes' , 'des-cbc' : 'des' , 'des' : 'des' , } [ enc_algo ]
decrypt_func = crypto_funcs [ enc_algo_name ]
if enc_algo_name == 'rc4' :
    return decrypt_func ( enc_key , data )
return decrypt_func ( enc_key , data , enc_iv )


signature:
def parse_pkcs12 ( data , password = None ) :
    """Parses a PKCS # 12 ANS . 1 DER - encoded structure and extracts certs and keys
 : param data :
 A byte string of a DER - encoded PKCS # 12 file
 : param password :
 A byte string of the password to any encrypted data
 : raises :
 ValueError - when any of the parameters are of the wrong type or value
 OSError - when an error is returned by one of the OS decryption functions
 : return :
 A three - element tuple of :
 1 . An asn1crypto . keys . PrivateKeyInfo object
 2 . An asn1crypto . x509 . Certificate object
 3 . A list of zero or more asn1crypto . x509 . Certificate objects that are
 " extra " certificates , possibly intermediates from the cert chain"""

implementation:
if not isinstance ( data , byte_cls ) :
    raise TypeError ( pretty_message ( '''
            data must be a byte string, not %s
            ''' , type_name ( data ) ) )
if password is not None :
    if not isinstance ( password , byte_cls ) :
        raise TypeError ( pretty_message ( '''
                password must be a byte string, not %s
                ''' , type_name ( password ) ) )
else :
    password = b''
certs = { }
private_keys = { }
pfx = pkcs12 . Pfx . load ( data )
auth_safe = pfx [ 'auth_safe' ]
if auth_safe [ 'content_type' ] . native != 'data' :
    raise ValueError ( pretty_message ( '''
            Only password-protected PKCS12 files are currently supported
            ''' ) )
authenticated_safe = pfx . authenticated_safe
mac_data = pfx [ 'mac_data' ]
if mac_data :
    mac_algo = mac_data [ 'mac' ] [ 'digest_algorithm' ] [ 'algorithm' ] . native
    key_length = { 'sha1' : 20 , 'sha224' : 28 , 'sha256' : 32 , 'sha384' : 48 , 'sha512' : 64 , 'sha512_224' : 28 , 'sha512_256' : 32 , } [ mac_algo ]
    mac_key = pkcs12_kdf ( mac_algo , password , mac_data [ 'mac_salt' ] . native , mac_data [ 'iterations' ] . native , key_length , 3 # ID 3 is for generating an HMAC key
    )
    hash_mod = getattr ( hashlib , mac_algo )
    computed_hmac = hmac . new ( mac_key , auth_safe [ 'content' ] . contents , hash_mod ) . digest ( )
    stored_hmac = mac_data [ 'mac' ] [ 'digest' ] . native
    if not constant_compare ( computed_hmac , stored_hmac ) :
        raise ValueError ( 'Password provided is invalid' )
for content_info in authenticated_safe :
    content = content_info [ 'content' ]
    if isinstance ( content , core . OctetString ) :
        _parse_safe_contents ( content . native , certs , private_keys , password )
    elif isinstance ( content , cms . EncryptedData ) :
        encrypted_content_info = content [ 'encrypted_content_info' ]
        encryption_algorithm_info = encrypted_content_info [ 'content_encryption_algorithm' ]
        encrypted_content = encrypted_content_info [ 'encrypted_content' ] . native
        decrypted_content = _decrypt_encrypted_data ( encryption_algorithm_info , encrypted_content , password )
        _parse_safe_contents ( decrypted_content , certs , private_keys , password )
    else :
        raise ValueError ( pretty_message ( '''
                Public-key-based PKCS12 files are not currently supported
                ''' ) )
key_fingerprints = set ( private_keys . keys ( ) )
cert_fingerprints = set ( certs . keys ( ) )
common_fingerprints = sorted ( list ( key_fingerprints & cert_fingerprints ) )
key = None
cert = None
other_certs = [ ]
if len ( common_fingerprints ) >= 1 :
    fingerprint = common_fingerprints [ 0 ]
    key = private_keys [ fingerprint ]
    cert = certs [ fingerprint ]
    other_certs = [ certs [ f ] for f in certs if f != fingerprint ]
    return ( key , cert , other_certs )
if len ( private_keys ) > 0 :
    first_key = sorted ( list ( private_keys . keys ( ) ) ) [ 0 ]
    key = private_keys [ first_key ]
if len ( certs ) > 0 :
    first_key = sorted ( list ( certs . keys ( ) ) ) [ 0 ]
    cert = certs [ first_key ]
    del certs [ first_key ]
if len ( certs ) > 0 :
    other_certs = sorted ( list ( certs . values ( ) ) )
return ( key , cert , other_certs )


signature:
def _parse_safe_contents ( safe_contents , certs , private_keys , password ) :
    """Parses a SafeContents PKCS # 12 ANS . 1 structure and extracts certs and keys
 : param safe _ contents :
 A byte string of ber - encoded SafeContents , or a asn1crypto . pkcs12 . SafeContents
 parsed object
 : param certs :
 A dict to store certificates in
 : param keys :
 A dict to store keys in
 : param password :
 A byte string of the password to any encrypted data"""

implementation:
if isinstance ( safe_contents , byte_cls ) :
    safe_contents = pkcs12 . SafeContents . load ( safe_contents )
for safe_bag in safe_contents :
    bag_value = safe_bag [ 'bag_value' ]
    if isinstance ( bag_value , pkcs12 . CertBag ) :
        if bag_value [ 'cert_id' ] . native == 'x509' :
            cert = bag_value [ 'cert_value' ] . parsed
            public_key_info = cert [ 'tbs_certificate' ] [ 'subject_public_key_info' ]
            certs [ public_key_info . fingerprint ] = bag_value [ 'cert_value' ] . parsed
    elif isinstance ( bag_value , keys . PrivateKeyInfo ) :
        private_keys [ bag_value . fingerprint ] = bag_value
    elif isinstance ( bag_value , keys . EncryptedPrivateKeyInfo ) :
        encryption_algorithm_info = bag_value [ 'encryption_algorithm' ]
        encrypted_key_bytes = bag_value [ 'encrypted_data' ] . native
        decrypted_key_bytes = _decrypt_encrypted_data ( encryption_algorithm_info , encrypted_key_bytes , password )
        private_key = keys . PrivateKeyInfo . load ( decrypted_key_bytes )
        private_keys [ private_key . fingerprint ] = private_key
    elif isinstance ( bag_value , pkcs12 . SafeContents ) :
        _parse_safe_contents ( bag_value , certs , private_keys , password )
    else : # We don ' t care about CRL bags or secret bags
        pass


signature:
def _decrypt_encrypted_data ( encryption_algorithm_info , encrypted_content , password ) :
    """Decrypts encrypted ASN . 1 data
 : param encryption _ algorithm _ info :
 An instance of asn1crypto . pkcs5 . Pkcs5EncryptionAlgorithm
 : param encrypted _ content :
 A byte string of the encrypted content
 : param password :
 A byte string of the encrypted content ' s password
 : return :
 A byte string of the decrypted plaintext"""

implementation:
decrypt_func = crypto_funcs [ encryption_algorithm_info . encryption_cipher ]
# Modern , PKCS # 5 PBES2 - based encryption
if encryption_algorithm_info . kdf == 'pbkdf2' :
    if encryption_algorithm_info . encryption_cipher == 'rc5' :
        raise ValueError ( pretty_message ( '''
                PBES2 encryption scheme utilizing RC5 encryption is not supported
                ''' ) )
    enc_key = pbkdf2 ( encryption_algorithm_info . kdf_hmac , password , encryption_algorithm_info . kdf_salt , encryption_algorithm_info . kdf_iterations , encryption_algorithm_info . key_length )
    enc_iv = encryption_algorithm_info . encryption_iv
    plaintext = decrypt_func ( enc_key , encrypted_content , enc_iv )
elif encryption_algorithm_info . kdf == 'pbkdf1' :
    derived_output = pbkdf1 ( encryption_algorithm_info . kdf_hmac , password , encryption_algorithm_info . kdf_salt , encryption_algorithm_info . kdf_iterations , encryption_algorithm_info . key_length + 8 )
    enc_key = derived_output [ 0 : 8 ]
    enc_iv = derived_output [ 8 : 16 ]
    plaintext = decrypt_func ( enc_key , encrypted_content , enc_iv )
elif encryption_algorithm_info . kdf == 'pkcs12_kdf' :
    enc_key = pkcs12_kdf ( encryption_algorithm_info . kdf_hmac , password , encryption_algorithm_info . kdf_salt , encryption_algorithm_info . kdf_iterations , encryption_algorithm_info . key_length , 1 # ID 1 is for generating a key
    )
    # Since RC4 is a stream cipher , we don ' t use an IV
    if encryption_algorithm_info . encryption_cipher == 'rc4' :
        plaintext = decrypt_func ( enc_key , encrypted_content )
    else :
        enc_iv = pkcs12_kdf ( encryption_algorithm_info . kdf_hmac , password , encryption_algorithm_info . kdf_salt , encryption_algorithm_info . kdf_iterations , encryption_algorithm_info . encryption_block_size , 2 # ID 2 is for generating an IV
        )
        plaintext = decrypt_func ( enc_key , encrypted_content , enc_iv )
return plaintext


signature:
def aes_cbc_no_padding_decrypt ( key , data , iv ) :
    """Decrypts AES ciphertext in CBC mode using a 128 , 192 or 256 bit key and no
 padding .
 : param key :
 The encryption key - a byte string either 16 , 24 or 32 bytes long
 : param data :
 The ciphertext - a byte string
 : param iv :
 The initialization vector - a byte string 16 - bytes long
 : raises :
 ValueError - when any of the parameters contain an invalid value
 TypeError - when any of the parameters are of the wrong type
 OSError - when an error is returned by OpenSSL
 : return :
 A byte string of the plaintext"""

implementation:
cipher = _calculate_aes_cipher ( key )
if len ( iv ) != 16 :
    raise ValueError ( pretty_message ( '''
            iv must be 16 bytes long - is %s
            ''' , len ( iv ) ) )
return _decrypt ( cipher , key , data , iv , False )


signature:
def aes_cbc_pkcs7_encrypt ( key , data , iv ) :
    """Encrypts plaintext using AES in CBC mode with a 128 , 192 or 256 bit key and
 PKCS # 7 padding .
 : param key :
 The encryption key - a byte string either 16 , 24 or 32 bytes long
 : param data :
 The plaintext - a byte string
 : param iv :
 The initialization vector - either a byte string 16 - bytes long or None
 to generate an IV
 : raises :
 ValueError - when any of the parameters contain an invalid value
 TypeError - when any of the parameters are of the wrong type
 OSError - when an error is returned by OpenSSL
 : return :
 A tuple of two byte strings ( iv , ciphertext )"""

implementation:
cipher = _calculate_aes_cipher ( key )
if not iv :
    iv = rand_bytes ( 16 )
elif len ( iv ) != 16 :
    raise ValueError ( pretty_message ( '''
            iv must be 16 bytes long - is %s
            ''' , len ( iv ) ) )
return ( iv , _encrypt ( cipher , key , data , iv , True ) )


signature:
def aes_cbc_pkcs7_decrypt ( key , data , iv ) :
    """Decrypts AES ciphertext in CBC mode using a 128 , 192 or 256 bit key
 : param key :
 The encryption key - a byte string either 16 , 24 or 32 bytes long
 : param data :
 The ciphertext - a byte string
 : param iv :
 The initialization vector - a byte string 16 - bytes long
 : raises :
 ValueError - when any of the parameters contain an invalid value
 TypeError - when any of the parameters are of the wrong type
 OSError - when an error is returned by OpenSSL
 : return :
 A byte string of the plaintext"""

implementation:
cipher = _calculate_aes_cipher ( key )
if len ( iv ) != 16 :
    raise ValueError ( pretty_message ( '''
            iv must be 16 bytes long - is %s
            ''' , len ( iv ) ) )
return _decrypt ( cipher , key , data , iv , True )


signature:
def _calculate_aes_cipher ( key ) :
    """Determines if the key is a valid AES 128 , 192 or 256 key
 : param key :
 A byte string of the key to use
 : raises :
 ValueError - when an invalid key is provided
 : return :
 A unicode string of the AES variation - " aes128 " , " aes192 " or " aes256" """

implementation:
if len ( key ) not in [ 16 , 24 , 32 ] :
    raise ValueError ( pretty_message ( '''
            key must be either 16, 24 or 32 bytes (128, 192 or 256 bits)
            long - is %s
            ''' , len ( key ) ) )
if len ( key ) == 16 :
    cipher = 'aes128'
elif len ( key ) == 24 :
    cipher = 'aes192'
elif len ( key ) == 32 :
    cipher = 'aes256'
return cipher


signature:
def rc4_encrypt ( key , data ) :
    """Encrypts plaintext using RC4 with a 40-128 bit key
 : param key :
 The encryption key - a byte string 5-16 bytes long
 : param data :
 The plaintext - a byte string
 : raises :
 ValueError - when any of the parameters contain an invalid value
 TypeError - when any of the parameters are of the wrong type
 OSError - when an error is returned by OpenSSL
 : return :
 A byte string of the ciphertext"""

implementation:
if len ( key ) < 5 or len ( key ) > 16 :
    raise ValueError ( pretty_message ( '''
            key must be 5 to 16 bytes (40 to 128 bits) long - is %s
            ''' , len ( key ) ) )
return _encrypt ( 'rc4' , key , data , None , None )


signature:
def rc4_decrypt ( key , data ) :
    """Decrypts RC4 ciphertext using a 40-128 bit key
 : param key :
 The encryption key - a byte string 5-16 bytes long
 : param data :
 The ciphertext - a byte string
 : raises :
 ValueError - when any of the parameters contain an invalid value
 TypeError - when any of the parameters are of the wrong type
 OSError - when an error is returned by OpenSSL
 : return :
 A byte string of the plaintext"""

implementation:
if len ( key ) < 5 or len ( key ) > 16 :
    raise ValueError ( pretty_message ( '''
            key must be 5 to 16 bytes (40 to 128 bits) long - is %s
            ''' , len ( key ) ) )
return _decrypt ( 'rc4' , key , data , None , None )


signature:
def tripledes_cbc_pkcs5_decrypt ( key , data , iv ) :
    """Decrypts 3DES ciphertext in CBC mode using either the 2 or 3 key variant
 (16 or 24 byte long key ) and PKCS # 5 padding .
 : param key :
 The encryption key - a byte string 16 or 24 bytes long ( 2 or 3 key mode )
 : param data :
 The ciphertext - a byte string
 : param iv :
 The initialization vector - a byte string 8 - bytes long
 : raises :
 ValueError - when any of the parameters contain an invalid value
 TypeError - when any of the parameters are of the wrong type
 OSError - when an error is returned by OpenSSL
 : return :
 A byte string of the plaintext"""

implementation:
if len ( key ) != 16 and len ( key ) != 24 :
    raise ValueError ( pretty_message ( '''
            key must be 16 bytes (2 key) or 24 bytes (3 key) long - is %s
            ''' , len ( key ) ) )
if len ( iv ) != 8 :
    raise ValueError ( pretty_message ( '''
            iv must be 8 bytes long - is %s
            ''' , len ( iv ) ) )
cipher = 'tripledes_3key'
# Expand 2 - key to actual 24 byte byte string used by cipher
if len ( key ) == 16 :
    key = key + key [ 0 : 8 ]
    cipher = 'tripledes_2key'
return _decrypt ( cipher , key , data , iv , True )


signature:
def des_cbc_pkcs5_decrypt ( key , data , iv ) :
    """Decrypts DES ciphertext in CBC mode using a 56 bit key and PKCS # 5 padding .
 : param key :
 The encryption key - a byte string 8 bytes long ( includes error correction bits )
 : param data :
 The ciphertext - a byte string
 : param iv :
 The initialization vector - a byte string 8 - bytes long
 : raises :
 ValueError - when any of the parameters contain an invalid value
 TypeError - when any of the parameters are of the wrong type
 OSError - when an error is returned by OpenSSL
 : return :
 A byte string of the plaintext"""

implementation:
if len ( key ) != 8 :
    raise ValueError ( pretty_message ( '''
            key must be 8 bytes (56 bits + 8 parity bits) long - is %s
            ''' , len ( key ) ) )
if len ( iv ) != 8 :
    raise ValueError ( pretty_message ( '''
            iv must be 8 bytes long - is %s
            ''' , len ( iv ) ) )
return _decrypt ( 'des' , key , data , iv , True )


signature:
def _encrypt ( cipher , key , data , iv , padding ) :
    """Encrypts plaintext
 : param cipher :
 A unicode string of " aes128 " , " aes192 " , " aes256 " , " des " ,
 " tripledes _ 2key " , " tripledes _ 3key " , " rc2 " , " rc4"
 : param key :
 The encryption key - a byte string 5-32 bytes long
 : param data :
 The plaintext - a byte string
 : param iv :
 The initialization vector - a byte string - unused for RC4
 : param padding :
 Boolean , if padding should be used - unused for RC4
 : raises :
 ValueError - when any of the parameters contain an invalid value
 TypeError - when any of the parameters are of the wrong type
 OSError - when an error is returned by OpenSSL
 : return :
 A byte string of the ciphertext"""

implementation:
if not isinstance ( key , byte_cls ) :
    raise TypeError ( pretty_message ( '''
            key must be a byte string, not %s
            ''' , type_name ( key ) ) )
if not isinstance ( data , byte_cls ) :
    raise TypeError ( pretty_message ( '''
            data must be a byte string, not %s
            ''' , type_name ( data ) ) )
if cipher != 'rc4' and not isinstance ( iv , byte_cls ) :
    raise TypeError ( pretty_message ( '''
            iv must be a byte string, not %s
            ''' , type_name ( iv ) ) )
if cipher != 'rc4' and not padding :
    raise ValueError ( 'padding must be specified' )
evp_cipher_ctx = None
try :
    evp_cipher_ctx = libcrypto . EVP_CIPHER_CTX_new ( )
    if is_null ( evp_cipher_ctx ) :
        handle_openssl_error ( 0 )
    evp_cipher , buffer_size = _setup_evp_encrypt_decrypt ( cipher , data )
    if iv is None :
        iv = null ( )
    if cipher in set ( [ 'rc2' , 'rc4' ] ) :
        res = libcrypto . EVP_EncryptInit_ex ( evp_cipher_ctx , evp_cipher , null ( ) , null ( ) , null ( ) )
        handle_openssl_error ( res )
        res = libcrypto . EVP_CIPHER_CTX_set_key_length ( evp_cipher_ctx , len ( key ) )
        handle_openssl_error ( res )
        if cipher == 'rc2' :
            res = libcrypto . EVP_CIPHER_CTX_ctrl ( evp_cipher_ctx , LibcryptoConst . EVP_CTRL_SET_RC2_KEY_BITS , len ( key ) * 8 , null ( ) )
            handle_openssl_error ( res )
        evp_cipher = null ( )
    res = libcrypto . EVP_EncryptInit_ex ( evp_cipher_ctx , evp_cipher , null ( ) , key , iv )
    handle_openssl_error ( res )
    if padding is not None :
        res = libcrypto . EVP_CIPHER_CTX_set_padding ( evp_cipher_ctx , int ( padding ) )
        handle_openssl_error ( res )
    buffer = buffer_from_bytes ( buffer_size )
    output_length = new ( libcrypto , 'int *' )
    res = libcrypto . EVP_EncryptUpdate ( evp_cipher_ctx , buffer , output_length , data , len ( data ) )
    handle_openssl_error ( res )
    output = bytes_from_buffer ( buffer , deref ( output_length ) )
    res = libcrypto . EVP_EncryptFinal_ex ( evp_cipher_ctx , buffer , output_length )
    handle_openssl_error ( res )
    output += bytes_from_buffer ( buffer , deref ( output_length ) )
    return output
finally :
    if evp_cipher_ctx :
        libcrypto . EVP_CIPHER_CTX_free ( evp_cipher_ctx )


signature:
def _setup_evp_encrypt_decrypt ( cipher , data ) :
    """Creates an EVP _ CIPHER pointer object and determines the buffer size
 necessary for the parameter specified .
 : param evp _ cipher _ ctx :
 An EVP _ CIPHER _ CTX pointer
 : param cipher :
 A unicode string of " aes128 " , " aes192 " , " aes256 " , " des " ,
 " tripledes _ 2key " , " tripledes _ 3key " , " rc2 " , " rc4"
 : param key :
 The key byte string
 : param data :
 The plaintext or ciphertext as a byte string
 : param padding :
 If padding is to be used
 : return :
 A 2 - element tuple with the first element being an EVP _ CIPHER pointer
 and the second being an integer that is the required buffer size"""

implementation:
evp_cipher = { 'aes128' : libcrypto . EVP_aes_128_cbc , 'aes192' : libcrypto . EVP_aes_192_cbc , 'aes256' : libcrypto . EVP_aes_256_cbc , 'rc2' : libcrypto . EVP_rc2_cbc , 'rc4' : libcrypto . EVP_rc4 , 'des' : libcrypto . EVP_des_cbc , 'tripledes_2key' : libcrypto . EVP_des_ede_cbc , 'tripledes_3key' : libcrypto . EVP_des_ede3_cbc , } [ cipher ] ( )
if cipher == 'rc4' :
    buffer_size = len ( data )
else :
    block_size = { 'aes128' : 16 , 'aes192' : 16 , 'aes256' : 16 , 'rc2' : 8 , 'des' : 8 , 'tripledes_2key' : 8 , 'tripledes_3key' : 8 , } [ cipher ]
    buffer_size = block_size * int ( math . ceil ( len ( data ) / block_size ) )
return ( evp_cipher , buffer_size )


signature:
def handle_error ( result ) :
    """Extracts the last Windows error message into a python unicode string
 : param result :
 A function result , 0 or None indicates failure
 : return :
 A unicode string error message"""

implementation:
if result :
    return
_ , error_string = get_error ( )
if not isinstance ( error_string , str_cls ) :
    error_string = _try_decode ( error_string )
raise OSError ( error_string )


signature:
def handle_error ( result , exception_class = None ) :
    """Extracts the last Windows error message into a python unicode string
 : param result :
 A function result , 0 or None indicates failure
 : param exception _ class :
 The exception class to use for the exception if an error occurred
 : return :
 A unicode string error message"""

implementation:
if result == 0 :
    return
if result == Secur32Const . SEC_E_OUT_OF_SEQUENCE :
    raise TLSError ( 'A packet was received out of order' )
if result == Secur32Const . SEC_E_MESSAGE_ALTERED :
    raise TLSError ( 'A packet was received altered' )
if result == Secur32Const . SEC_E_CONTEXT_EXPIRED :
    raise TLSError ( 'The TLS session expired' )
_ , error_string = get_error ( )
if not isinstance ( error_string , str_cls ) :
    error_string = _try_decode ( error_string )
if exception_class is None :
    exception_class = OSError
raise exception_class ( ( 'SECURITY_STATUS error 0x%0.2X: ' % result ) + error_string )


signature:
def generate_pair ( algorithm , bit_size = None , curve = None ) :
    """Generates a public / private key pair
 : param algorithm :
 The key algorithm - " rsa " , " dsa " or " ec "
 : param bit _ size :
 An integer - used for " rsa " and " dsa " . For " rsa " the value maye be 1024,
 2048 , 3072 or 4096 . For " dsa " the value may be 1024 , plus 2048 or 3072
 if OpenSSL 1.0.0 or newer is available .
 : param curve :
 A unicode string - used for " ec " keys . Valid values include " secp256r1 " ,
 " secp384r1 " and " secp521r1 " .
 : raises :
 ValueError - when any of the parameters contain an invalid value
 TypeError - when any of the parameters are of the wrong type
 OSError - when an error is returned by the OS crypto library
 : return :
 A 2 - element tuple of ( PublicKey , PrivateKey ) . The contents of each key
 may be saved by calling . asn1 . dump ( ) ."""

implementation:
if algorithm not in set ( [ 'rsa' , 'dsa' , 'ec' ] ) :
    raise ValueError ( pretty_message ( '''
            algorithm must be one of "rsa", "dsa", "ec", not %s
            ''' , repr ( algorithm ) ) )
if algorithm == 'rsa' :
    if bit_size not in set ( [ 1024 , 2048 , 3072 , 4096 ] ) :
        raise ValueError ( pretty_message ( '''
                bit_size must be one of 1024, 2048, 3072, 4096, not %s
                ''' , repr ( bit_size ) ) )
elif algorithm == 'dsa' :
    if libcrypto_version_info < ( 1 , ) :
        if bit_size != 1024 :
            raise ValueError ( pretty_message ( '''
                    bit_size must be 1024, not %s
                    ''' , repr ( bit_size ) ) )
    else :
        if bit_size not in set ( [ 1024 , 2048 , 3072 ] ) :
            raise ValueError ( pretty_message ( '''
                    bit_size must be one of 1024, 2048, 3072, not %s
                    ''' , repr ( bit_size ) ) )
elif algorithm == 'ec' :
    if curve not in set ( [ 'secp256r1' , 'secp384r1' , 'secp521r1' ] ) :
        raise ValueError ( pretty_message ( '''
                curve must be one of "secp256r1", "secp384r1", "secp521r1",
                not %s
                ''' , repr ( curve ) ) )
if algorithm == 'rsa' :
    rsa = None
    exponent = None
    try :
        rsa = libcrypto . RSA_new ( )
        if is_null ( rsa ) :
            handle_openssl_error ( 0 )
        exponent_pointer = new ( libcrypto , 'BIGNUM **' )
        result = libcrypto . BN_dec2bn ( exponent_pointer , b'65537' )
        handle_openssl_error ( result )
        exponent = unwrap ( exponent_pointer )
        result = libcrypto . RSA_generate_key_ex ( rsa , bit_size , exponent , null ( ) )
        handle_openssl_error ( result )
        buffer_length = libcrypto . i2d_RSAPublicKey ( rsa , null ( ) )
        if buffer_length < 0 :
            handle_openssl_error ( buffer_length )
        buffer = buffer_from_bytes ( buffer_length )
        result = libcrypto . i2d_RSAPublicKey ( rsa , buffer_pointer ( buffer ) )
        if result < 0 :
            handle_openssl_error ( result )
        public_key_bytes = bytes_from_buffer ( buffer , buffer_length )
        buffer_length = libcrypto . i2d_RSAPrivateKey ( rsa , null ( ) )
        if buffer_length < 0 :
            handle_openssl_error ( buffer_length )
        buffer = buffer_from_bytes ( buffer_length )
        result = libcrypto . i2d_RSAPrivateKey ( rsa , buffer_pointer ( buffer ) )
        if result < 0 :
            handle_openssl_error ( result )
        private_key_bytes = bytes_from_buffer ( buffer , buffer_length )
    finally :
        if rsa :
            libcrypto . RSA_free ( rsa )
        if exponent :
            libcrypto . BN_free ( exponent )
elif algorithm == 'dsa' :
    dsa = None
    try :
        dsa = libcrypto . DSA_new ( )
        if is_null ( dsa ) :
            handle_openssl_error ( 0 )
        result = libcrypto . DSA_generate_parameters_ex ( dsa , bit_size , null ( ) , 0 , null ( ) , null ( ) , null ( ) )
        handle_openssl_error ( result )
        result = libcrypto . DSA_generate_key ( dsa )
        handle_openssl_error ( result )
        buffer_length = libcrypto . i2d_DSA_PUBKEY ( dsa , null ( ) )
        if buffer_length < 0 :
            handle_openssl_error ( buffer_length )
        buffer = buffer_from_bytes ( buffer_length )
        result = libcrypto . i2d_DSA_PUBKEY ( dsa , buffer_pointer ( buffer ) )
        if result < 0 :
            handle_openssl_error ( result )
        public_key_bytes = bytes_from_buffer ( buffer , buffer_length )
        buffer_length = libcrypto . i2d_DSAPrivateKey ( dsa , null ( ) )
        if buffer_length < 0 :
            handle_openssl_error ( buffer_length )
        buffer = buffer_from_bytes ( buffer_length )
        result = libcrypto . i2d_DSAPrivateKey ( dsa , buffer_pointer ( buffer ) )
        if result < 0 :
            handle_openssl_error ( result )
        private_key_bytes = bytes_from_buffer ( buffer , buffer_length )
    finally :
        if dsa :
            libcrypto . DSA_free ( dsa )
elif algorithm == 'ec' :
    ec_key = None
    try :
        curve_id = { 'secp256r1' : LibcryptoConst . NID_X9_62_prime256v1 , 'secp384r1' : LibcryptoConst . NID_secp384r1 , 'secp521r1' : LibcryptoConst . NID_secp521r1 , } [ curve ]
        ec_key = libcrypto . EC_KEY_new_by_curve_name ( curve_id )
        if is_null ( ec_key ) :
            handle_openssl_error ( 0 )
        result = libcrypto . EC_KEY_generate_key ( ec_key )
        handle_openssl_error ( result )
        libcrypto . EC_KEY_set_asn1_flag ( ec_key , LibcryptoConst . OPENSSL_EC_NAMED_CURVE )
        buffer_length = libcrypto . i2o_ECPublicKey ( ec_key , null ( ) )
        if buffer_length < 0 :
            handle_openssl_error ( buffer_length )
        buffer = buffer_from_bytes ( buffer_length )
        result = libcrypto . i2o_ECPublicKey ( ec_key , buffer_pointer ( buffer ) )
        if result < 0 :
            handle_openssl_error ( result )
        public_key_point_bytes = bytes_from_buffer ( buffer , buffer_length )
        # i2o _ ECPublicKey only returns the ECPoint bytes , so we have to
        # manually wrap it in a PublicKeyInfo structure to get it to parse
        public_key = keys . PublicKeyInfo ( { 'algorithm' : keys . PublicKeyAlgorithm ( { 'algorithm' : 'ec' , 'parameters' : keys . ECDomainParameters ( name = 'named' , value = curve ) } ) , 'public_key' : public_key_point_bytes } )
        public_key_bytes = public_key . dump ( )
        buffer_length = libcrypto . i2d_ECPrivateKey ( ec_key , null ( ) )
        if buffer_length < 0 :
            handle_openssl_error ( buffer_length )
        buffer = buffer_from_bytes ( buffer_length )
        result = libcrypto . i2d_ECPrivateKey ( ec_key , buffer_pointer ( buffer ) )
        if result < 0 :
            handle_openssl_error ( result )
        private_key_bytes = bytes_from_buffer ( buffer , buffer_length )
    finally :
        if ec_key :
            libcrypto . EC_KEY_free ( ec_key )
return ( load_public_key ( public_key_bytes ) , load_private_key ( private_key_bytes ) )


signature:
def generate_dh_parameters ( bit_size ) :
    """Generates DH parameters for use with Diffie - Hellman key exchange . Returns
 a structure in the format of DHParameter defined in PKCS # 3 , which is also
 used by the OpenSSL dhparam tool .
 THIS CAN BE VERY TIME CONSUMING !
 : param bit _ size :
 The integer bit size of the parameters to generate . Must be between 512
 and 4096 , and divisible by 64 . Recommended secure value as of early 2016
 is 2048 , with an absolute minimum of 1024.
 : raises :
 ValueError - when any of the parameters contain an invalid value
 TypeError - when any of the parameters are of the wrong type
 OSError - when an error is returned by the OS crypto library
 : return :
 An asn1crypto . algos . DHParameters object . Use
 oscrypto . asymmetric . dump _ dh _ parameters ( ) to save to disk for usage with
 web servers ."""

implementation:
if not isinstance ( bit_size , int_types ) :
    raise TypeError ( pretty_message ( '''
            bit_size must be an integer, not %s
            ''' , type_name ( bit_size ) ) )
if bit_size < 512 :
    raise ValueError ( 'bit_size must be greater than or equal to 512' )
if bit_size > 4096 :
    raise ValueError ( 'bit_size must be less than or equal to 4096' )
if bit_size % 64 != 0 :
    raise ValueError ( 'bit_size must be a multiple of 64' )
dh = None
try :
    dh = libcrypto . DH_new ( )
    if is_null ( dh ) :
        handle_openssl_error ( 0 )
    result = libcrypto . DH_generate_parameters_ex ( dh , bit_size , LibcryptoConst . DH_GENERATOR_2 , null ( ) )
    handle_openssl_error ( result )
    buffer_length = libcrypto . i2d_DHparams ( dh , null ( ) )
    if buffer_length < 0 :
        handle_openssl_error ( buffer_length )
    buffer = buffer_from_bytes ( buffer_length )
    result = libcrypto . i2d_DHparams ( dh , buffer_pointer ( buffer ) )
    if result < 0 :
        handle_openssl_error ( result )
    dh_params_bytes = bytes_from_buffer ( buffer , buffer_length )
    return algos . DHParameters . load ( dh_params_bytes )
finally :
    if dh :
        libcrypto . DH_free ( dh )


signature:
def load_certificate ( source ) :
    """Loads an x509 certificate into a Certificate object
 : param source :
 A byte string of file contents , a unicode string filename or an
 asn1crypto . x509 . Certificate object
 : raises :
 ValueError - when any of the parameters contain an invalid value
 TypeError - when any of the parameters are of the wrong type
 OSError - when an error is returned by the OS crypto library
 : return :
 A Certificate object"""

implementation:
if isinstance ( source , asn1x509 . Certificate ) :
    certificate = source
elif isinstance ( source , byte_cls ) :
    certificate = parse_certificate ( source )
elif isinstance ( source , str_cls ) :
    with open ( source , 'rb' ) as f :
        certificate = parse_certificate ( f . read ( ) )
else :
    raise TypeError ( pretty_message ( '''
            source must be a byte string, unicode string or
            asn1crypto.x509.Certificate object, not %s
            ''' , type_name ( source ) ) )
return _load_x509 ( certificate )


signature:
def _load_x509 ( certificate ) :
    """Loads an ASN . 1 object of an x509 certificate into a Certificate object
 : param certificate :
 An asn1crypto . x509 . Certificate object
 : return :
 A Certificate object"""

implementation:
source = certificate . dump ( )
buffer = buffer_from_bytes ( source )
evp_pkey = libcrypto . d2i_X509 ( null ( ) , buffer_pointer ( buffer ) , len ( source ) )
if is_null ( evp_pkey ) :
    handle_openssl_error ( 0 )
return Certificate ( evp_pkey , certificate )


signature:
def load_private_key ( source , password = None ) :
    """Loads a private key into a PrivateKey object
 : param source :
 A byte string of file contents , a unicode string filename or an
 asn1crypto . keys . PrivateKeyInfo object
 : param password :
 A byte or unicode string to decrypt the private key file . Unicode
 strings will be encoded using UTF - 8 . Not used is the source is a
 PrivateKeyInfo object .
 : raises :
 ValueError - when any of the parameters contain an invalid value
 TypeError - when any of the parameters are of the wrong type
 oscrypto . errors . AsymmetricKeyError - when the private key is incompatible with the OS crypto library
 OSError - when an error is returned by the OS crypto library
 : return :
 A PrivateKey object"""

implementation:
if isinstance ( source , keys . PrivateKeyInfo ) :
    private_object = source
else :
    if password is not None :
        if isinstance ( password , str_cls ) :
            password = password . encode ( 'utf-8' )
        if not isinstance ( password , byte_cls ) :
            raise TypeError ( pretty_message ( '''
                    password must be a byte string, not %s
                    ''' , type_name ( password ) ) )
    if isinstance ( source , str_cls ) :
        with open ( source , 'rb' ) as f :
            source = f . read ( )
    elif not isinstance ( source , byte_cls ) :
        raise TypeError ( pretty_message ( '''
                source must be a byte string, unicode string or
                asn1crypto.keys.PrivateKeyInfo object, not %s
                ''' , type_name ( source ) ) )
    private_object = parse_private ( source , password )
return _load_key ( private_object )


signature:
def load_public_key ( source ) :
    """Loads a public key into a PublicKey object
 : param source :
 A byte string of file contents , a unicode string filename or an
 asn1crypto . keys . PublicKeyInfo object
 : raises :
 ValueError - when any of the parameters contain an invalid value
 TypeError - when any of the parameters are of the wrong type
 oscrypto . errors . AsymmetricKeyError - when the public key is incompatible with the OS crypto library
 OSError - when an error is returned by the OS crypto library
 : return :
 A PublicKey object"""

implementation:
if isinstance ( source , keys . PublicKeyInfo ) :
    public_key = source
elif isinstance ( source , byte_cls ) :
    public_key = parse_public ( source )
elif isinstance ( source , str_cls ) :
    with open ( source , 'rb' ) as f :
        public_key = parse_public ( f . read ( ) )
else :
    raise TypeError ( pretty_message ( '''
            source must be a byte string, unicode string or
            asn1crypto.keys.PublicKeyInfo object, not %s
            ''' , type_name ( public_key ) ) )
if public_key . algorithm == 'dsa' :
    if libcrypto_version_info < ( 1 , ) and public_key . hash_algo == 'sha2' :
        raise AsymmetricKeyError ( pretty_message ( '''
                OpenSSL 0.9.8 only supports DSA keys based on SHA1 (2048 bits or
                less) - this key is based on SHA2 and is %s bits
                ''' , public_key . bit_size ) )
    elif public_key . hash_algo is None :
        raise IncompleteAsymmetricKeyError ( pretty_message ( '''
                The DSA key does not contain the necessary p, q and g
                parameters and can not be used
                ''' ) )
data = public_key . dump ( )
buffer = buffer_from_bytes ( data )
evp_pkey = libcrypto . d2i_PUBKEY ( null ( ) , buffer_pointer ( buffer ) , len ( data ) )
if is_null ( evp_pkey ) :
    handle_openssl_error ( 0 )
return PublicKey ( evp_pkey , public_key )


signature:
def _load_key ( private_object ) :
    """Loads a private key into a PrivateKey object
 : param private _ object :
 An asn1crypto . keys . PrivateKeyInfo object
 : return :
 A PrivateKey object"""

implementation:
if libcrypto_version_info < ( 1 , ) and private_object . algorithm == 'dsa' and private_object . hash_algo == 'sha2' :
    raise AsymmetricKeyError ( pretty_message ( '''
            OpenSSL 0.9.8 only supports DSA keys based on SHA1 (2048 bits or
            less) - this key is based on SHA2 and is %s bits
            ''' , private_object . bit_size ) )
source = private_object . unwrap ( ) . dump ( )
buffer = buffer_from_bytes ( source )
evp_pkey = libcrypto . d2i_AutoPrivateKey ( null ( ) , buffer_pointer ( buffer ) , len ( source ) )
if is_null ( evp_pkey ) :
    handle_openssl_error ( 0 )
return PrivateKey ( evp_pkey , private_object )


signature:
def _encrypt ( certificate_or_public_key , data , padding ) :
    """Encrypts plaintext using an RSA public key or certificate
 : param certificate _ or _ public _ key :
 A PublicKey , Certificate or PrivateKey object
 : param data :
 The byte string to encrypt
 : param padding :
 The padding mode to use
 : raises :
 ValueError - when any of the parameters contain an invalid value
 TypeError - when any of the parameters are of the wrong type
 OSError - when an error is returned by the OS crypto library
 : return :
 A byte string of the encrypted data"""

implementation:
if not isinstance ( certificate_or_public_key , ( Certificate , PublicKey ) ) :
    raise TypeError ( pretty_message ( '''
            certificate_or_public_key must be an instance of the Certificate or
            PublicKey class, not %s
            ''' , type_name ( certificate_or_public_key ) ) )
if not isinstance ( data , byte_cls ) :
    raise TypeError ( pretty_message ( '''
            data must be a byte string, not %s
            ''' , type_name ( data ) ) )
rsa = None
try :
    buffer_size = libcrypto . EVP_PKEY_size ( certificate_or_public_key . evp_pkey )
    buffer = buffer_from_bytes ( buffer_size )
    rsa = libcrypto . EVP_PKEY_get1_RSA ( certificate_or_public_key . evp_pkey )
    res = libcrypto . RSA_public_encrypt ( len ( data ) , data , buffer , rsa , padding )
    handle_openssl_error ( res )
    return bytes_from_buffer ( buffer , res )
finally :
    if rsa :
        libcrypto . RSA_free ( rsa )


signature:
def _decrypt ( private_key , ciphertext , padding ) :
    """Decrypts RSA ciphertext using a private key
 : param private _ key :
 A PrivateKey object
 : param ciphertext :
 The ciphertext - a byte string
 : param padding :
 The padding mode to use
 : raises :
 ValueError - when any of the parameters contain an invalid value
 TypeError - when any of the parameters are of the wrong type
 OSError - when an error is returned by the OS crypto library
 : return :
 A byte string of the plaintext"""

implementation:
if not isinstance ( private_key , PrivateKey ) :
    raise TypeError ( pretty_message ( '''
            private_key must be an instance of the PrivateKey class, not %s
            ''' , type_name ( private_key ) ) )
if not isinstance ( ciphertext , byte_cls ) :
    raise TypeError ( pretty_message ( '''
            ciphertext must be a byte string, not %s
            ''' , type_name ( ciphertext ) ) )
rsa = None
try :
    buffer_size = libcrypto . EVP_PKEY_size ( private_key . evp_pkey )
    buffer = buffer_from_bytes ( buffer_size )
    rsa = libcrypto . EVP_PKEY_get1_RSA ( private_key . evp_pkey )
    res = libcrypto . RSA_private_decrypt ( len ( ciphertext ) , ciphertext , buffer , rsa , padding )
    handle_openssl_error ( res )
    return bytes_from_buffer ( buffer , res )
finally :
    if rsa :
        libcrypto . RSA_free ( rsa )


signature:
def _verify ( certificate_or_public_key , signature , data , hash_algorithm , rsa_pss_padding = False ) :
    """Verifies an RSA , DSA or ECDSA signature
 : param certificate _ or _ public _ key :
 A Certificate or PublicKey instance to verify the signature with
 : param signature :
 A byte string of the signature to verify
 : param data :
 A byte string of the data the signature is for
 : param hash _ algorithm :
 A unicode string of " md5 " , " sha1 " , " sha224 " , " sha256 " , " sha384 " or " sha512"
 : param rsa _ pss _ padding :
 If the certificate _ or _ public _ key is an RSA key , this enables PSS padding
 : raises :
 oscrypto . errors . SignatureError - when the signature is determined to be invalid
 ValueError - when any of the parameters contain an invalid value
 TypeError - when any of the parameters are of the wrong type
 OSError - when an error is returned by the OS crypto library"""

implementation:
if not isinstance ( certificate_or_public_key , ( Certificate , PublicKey ) ) :
    raise TypeError ( pretty_message ( '''
            certificate_or_public_key must be an instance of the Certificate or
            PublicKey class, not %s
            ''' , type_name ( certificate_or_public_key ) ) )
if not isinstance ( signature , byte_cls ) :
    raise TypeError ( pretty_message ( '''
            signature must be a byte string, not %s
            ''' , type_name ( signature ) ) )
if not isinstance ( data , byte_cls ) :
    raise TypeError ( pretty_message ( '''
            data must be a byte string, not %s
            ''' , type_name ( data ) ) )
valid_hash_algorithms = set ( [ 'md5' , 'sha1' , 'sha224' , 'sha256' , 'sha384' , 'sha512' ] )
if certificate_or_public_key . algorithm == 'rsa' and not rsa_pss_padding :
    valid_hash_algorithms |= set ( [ 'raw' ] )
if hash_algorithm not in valid_hash_algorithms :
    valid_hash_algorithms_error = '"md5", "sha1", "sha224", "sha256", "sha384", "sha512"'
    if certificate_or_public_key . algorithm == 'rsa' and not rsa_pss_padding :
        valid_hash_algorithms_error += ', "raw"'
    raise ValueError ( pretty_message ( '''
            hash_algorithm must be one of %s, not %s
            ''' , valid_hash_algorithms_error , repr ( hash_algorithm ) ) )
if certificate_or_public_key . algorithm != 'rsa' and rsa_pss_padding :
    raise ValueError ( pretty_message ( '''
            PSS padding can only be used with RSA keys - the key provided is a
            %s key
            ''' , certificate_or_public_key . algorithm . upper ( ) ) )
if certificate_or_public_key . algorithm == 'rsa' and hash_algorithm == 'raw' :
    if len ( data ) > certificate_or_public_key . byte_size - 11 :
        raise ValueError ( pretty_message ( '''
                data must be 11 bytes shorter than the key size when
                hash_algorithm is "raw" - key size is %s bytes, but data is
                %s bytes long
                ''' , certificate_or_public_key . byte_size , len ( data ) ) )
    rsa = None
    try :
        rsa = libcrypto . EVP_PKEY_get1_RSA ( certificate_or_public_key . evp_pkey )
        if is_null ( rsa ) :
            handle_openssl_error ( 0 )
        buffer_size = libcrypto . EVP_PKEY_size ( certificate_or_public_key . evp_pkey )
        decrypted_buffer = buffer_from_bytes ( buffer_size )
        decrypted_length = libcrypto . RSA_public_decrypt ( len ( signature ) , signature , decrypted_buffer , rsa , LibcryptoConst . RSA_PKCS1_PADDING )
        handle_openssl_error ( decrypted_length )
        decrypted_bytes = bytes_from_buffer ( decrypted_buffer , decrypted_length )
        if not constant_compare ( data , decrypted_bytes ) :
            raise SignatureError ( 'Signature is invalid' )
        return
    finally :
        if rsa :
            libcrypto . RSA_free ( rsa )
evp_md_ctx = None
rsa = None
dsa = None
dsa_sig = None
ec_key = None
ecdsa_sig = None
try :
    if libcrypto_version_info < ( 1 , 1 ) :
        evp_md_ctx = libcrypto . EVP_MD_CTX_create ( )
    else :
        evp_md_ctx = libcrypto . EVP_MD_CTX_new ( )
    evp_md = { 'md5' : libcrypto . EVP_md5 , 'sha1' : libcrypto . EVP_sha1 , 'sha224' : libcrypto . EVP_sha224 , 'sha256' : libcrypto . EVP_sha256 , 'sha384' : libcrypto . EVP_sha384 , 'sha512' : libcrypto . EVP_sha512 } [ hash_algorithm ] ( )
    if libcrypto_version_info < ( 1 , ) :
        if certificate_or_public_key . algorithm == 'rsa' and rsa_pss_padding :
            digest = getattr ( hashlib , hash_algorithm ) ( data ) . digest ( )
            rsa = libcrypto . EVP_PKEY_get1_RSA ( certificate_or_public_key . evp_pkey )
            if is_null ( rsa ) :
                handle_openssl_error ( 0 )
            buffer_size = libcrypto . EVP_PKEY_size ( certificate_or_public_key . evp_pkey )
            decoded_buffer = buffer_from_bytes ( buffer_size )
            decoded_length = libcrypto . RSA_public_decrypt ( len ( signature ) , signature , decoded_buffer , rsa , LibcryptoConst . RSA_NO_PADDING )
            handle_openssl_error ( decoded_length )
            res = libcrypto . RSA_verify_PKCS1_PSS ( rsa , digest , evp_md , decoded_buffer , LibcryptoConst . EVP_MD_CTX_FLAG_PSS_MDLEN )
        elif certificate_or_public_key . algorithm == 'rsa' :
            res = libcrypto . EVP_DigestInit_ex ( evp_md_ctx , evp_md , null ( ) )
            handle_openssl_error ( res )
            res = libcrypto . EVP_DigestUpdate ( evp_md_ctx , data , len ( data ) )
            handle_openssl_error ( res )
            res = libcrypto . EVP_VerifyFinal ( evp_md_ctx , signature , len ( signature ) , certificate_or_public_key . evp_pkey )
        elif certificate_or_public_key . algorithm == 'dsa' :
            digest = getattr ( hashlib , hash_algorithm ) ( data ) . digest ( )
            signature_buffer = buffer_from_bytes ( signature )
            signature_pointer = buffer_pointer ( signature_buffer )
            dsa_sig = libcrypto . d2i_DSA_SIG ( null ( ) , signature_pointer , len ( signature ) )
            if is_null ( dsa_sig ) :
                raise SignatureError ( 'Signature is invalid' )
            dsa = libcrypto . EVP_PKEY_get1_DSA ( certificate_or_public_key . evp_pkey )
            if is_null ( dsa ) :
                handle_openssl_error ( 0 )
            res = libcrypto . DSA_do_verify ( digest , len ( digest ) , dsa_sig , dsa )
        elif certificate_or_public_key . algorithm == 'ec' :
            digest = getattr ( hashlib , hash_algorithm ) ( data ) . digest ( )
            signature_buffer = buffer_from_bytes ( signature )
            signature_pointer = buffer_pointer ( signature_buffer )
            ecdsa_sig = libcrypto . d2i_ECDSA_SIG ( null ( ) , signature_pointer , len ( signature ) )
            if is_null ( ecdsa_sig ) :
                raise SignatureError ( 'Signature is invalid' )
            ec_key = libcrypto . EVP_PKEY_get1_EC_KEY ( certificate_or_public_key . evp_pkey )
            if is_null ( ec_key ) :
                handle_openssl_error ( 0 )
            res = libcrypto . ECDSA_do_verify ( digest , len ( digest ) , ecdsa_sig , ec_key )
    else :
        evp_pkey_ctx_pointer_pointer = new ( libcrypto , 'EVP_PKEY_CTX **' )
        res = libcrypto . EVP_DigestVerifyInit ( evp_md_ctx , evp_pkey_ctx_pointer_pointer , evp_md , null ( ) , certificate_or_public_key . evp_pkey )
        handle_openssl_error ( res )
        evp_pkey_ctx_pointer = unwrap ( evp_pkey_ctx_pointer_pointer )
        if rsa_pss_padding : # Enable PSS padding
            res = libcrypto . EVP_PKEY_CTX_ctrl ( evp_pkey_ctx_pointer , LibcryptoConst . EVP_PKEY_RSA , - 1 , # All operations
            LibcryptoConst . EVP_PKEY_CTRL_RSA_PADDING , LibcryptoConst . RSA_PKCS1_PSS_PADDING , null ( ) )
            handle_openssl_error ( res )
            # Use the hash algorithm output length as the salt length
            res = libcrypto . EVP_PKEY_CTX_ctrl ( evp_pkey_ctx_pointer , LibcryptoConst . EVP_PKEY_RSA , LibcryptoConst . EVP_PKEY_OP_SIGN | LibcryptoConst . EVP_PKEY_OP_VERIFY , LibcryptoConst . EVP_PKEY_CTRL_RSA_PSS_SALTLEN , - 1 , null ( ) )
            handle_openssl_error ( res )
        res = libcrypto . EVP_DigestUpdate ( evp_md_ctx , data , len ( data ) )
        handle_openssl_error ( res )
        res = libcrypto . EVP_DigestVerifyFinal ( evp_md_ctx , signature , len ( signature ) )
    if res < 1 :
        raise SignatureError ( 'Signature is invalid' )
    handle_openssl_error ( res )
finally :
    if evp_md_ctx :
        if libcrypto_version_info < ( 1 , 1 ) :
            libcrypto . EVP_MD_CTX_destroy ( evp_md_ctx )
        else :
            libcrypto . EVP_MD_CTX_free ( evp_md_ctx )
    if rsa :
        libcrypto . RSA_free ( rsa )
    if dsa :
        libcrypto . DSA_free ( dsa )
    if dsa_sig :
        libcrypto . DSA_SIG_free ( dsa_sig )
    if ec_key :
        libcrypto . EC_KEY_free ( ec_key )
    if ecdsa_sig :
        libcrypto . ECDSA_SIG_free ( ecdsa_sig )


signature:
def rsa_pkcs1v15_sign ( private_key , data , hash_algorithm ) :
    """Generates an RSASSA - PKCS - v1.5 signature .
 When the hash _ algorithm is " raw " , the operation is identical to RSA
 private key encryption . That is : the data is not hashed and no ASN . 1
 structure with an algorithm identifier of the hash algorithm is placed in
 the encrypted byte string .
 : param private _ key :
 The PrivateKey to generate the signature with
 : param data :
 A byte string of the data the signature is for
 : param hash _ algorithm :
 A unicode string of " md5 " , " sha1 " , " sha224 " , " sha256 " , " sha384 " ,
 " sha512 " or " raw "
 : raises :
 ValueError - when any of the parameters contain an invalid value
 TypeError - when any of the parameters are of the wrong type
 OSError - when an error is returned by the OS crypto library
 : return :
 A byte string of the signature"""

implementation:
if private_key . algorithm != 'rsa' :
    raise ValueError ( pretty_message ( '''
            The key specified is not an RSA private key, but %s
            ''' , private_key . algorithm . upper ( ) ) )
return _sign ( private_key , data , hash_algorithm )


signature:
def _sign ( private_key , data , hash_algorithm , rsa_pss_padding = False ) :
    """Generates an RSA , DSA or ECDSA signature
 : param private _ key :
 The PrivateKey to generate the signature with
 : param data :
 A byte string of the data the signature is for
 : param hash _ algorithm :
 A unicode string of " md5 " , " sha1 " , " sha224 " , " sha256 " , " sha384 " or " sha512"
 : param rsa _ pss _ padding :
 If the private _ key is an RSA key , this enables PSS padding
 : raises :
 ValueError - when any of the parameters contain an invalid value
 TypeError - when any of the parameters are of the wrong type
 OSError - when an error is returned by the OS crypto library
 : return :
 A byte string of the signature"""

implementation:
if not isinstance ( private_key , PrivateKey ) :
    raise TypeError ( pretty_message ( '''
            private_key must be an instance of PrivateKey, not %s
            ''' , type_name ( private_key ) ) )
if not isinstance ( data , byte_cls ) :
    raise TypeError ( pretty_message ( '''
            data must be a byte string, not %s
            ''' , type_name ( data ) ) )
valid_hash_algorithms = set ( [ 'md5' , 'sha1' , 'sha224' , 'sha256' , 'sha384' , 'sha512' ] )
if private_key . algorithm == 'rsa' and not rsa_pss_padding :
    valid_hash_algorithms |= set ( [ 'raw' ] )
if hash_algorithm not in valid_hash_algorithms :
    valid_hash_algorithms_error = '"md5", "sha1", "sha224", "sha256", "sha384", "sha512"'
    if private_key . algorithm == 'rsa' and not rsa_pss_padding :
        valid_hash_algorithms_error += ', "raw"'
    raise ValueError ( pretty_message ( '''
            hash_algorithm must be one of %s, not %s
            ''' , valid_hash_algorithms_error , repr ( hash_algorithm ) ) )
if private_key . algorithm != 'rsa' and rsa_pss_padding :
    raise ValueError ( pretty_message ( '''
            PSS padding can only be used with RSA keys - the key provided is a
            %s key
            ''' , private_key . algorithm . upper ( ) ) )
if private_key . algorithm == 'rsa' and hash_algorithm == 'raw' :
    if len ( data ) > private_key . byte_size - 11 :
        raise ValueError ( pretty_message ( '''
                data must be 11 bytes shorter than the key size when
                hash_algorithm is "raw" - key size is %s bytes, but data is
                %s bytes long
                ''' , private_key . byte_size , len ( data ) ) )
    rsa = None
    try :
        rsa = libcrypto . EVP_PKEY_get1_RSA ( private_key . evp_pkey )
        if is_null ( rsa ) :
            handle_openssl_error ( 0 )
        buffer_size = libcrypto . EVP_PKEY_size ( private_key . evp_pkey )
        signature_buffer = buffer_from_bytes ( buffer_size )
        signature_length = libcrypto . RSA_private_encrypt ( len ( data ) , data , signature_buffer , rsa , LibcryptoConst . RSA_PKCS1_PADDING )
        handle_openssl_error ( signature_length )
        return bytes_from_buffer ( signature_buffer , signature_length )
    finally :
        if rsa :
            libcrypto . RSA_free ( rsa )
evp_md_ctx = None
rsa = None
dsa = None
dsa_sig = None
ec_key = None
ecdsa_sig = None
try :
    if libcrypto_version_info < ( 1 , 1 ) :
        evp_md_ctx = libcrypto . EVP_MD_CTX_create ( )
    else :
        evp_md_ctx = libcrypto . EVP_MD_CTX_new ( )
    evp_md = { 'md5' : libcrypto . EVP_md5 , 'sha1' : libcrypto . EVP_sha1 , 'sha224' : libcrypto . EVP_sha224 , 'sha256' : libcrypto . EVP_sha256 , 'sha384' : libcrypto . EVP_sha384 , 'sha512' : libcrypto . EVP_sha512 } [ hash_algorithm ] ( )
    if libcrypto_version_info < ( 1 , ) :
        if private_key . algorithm == 'rsa' and rsa_pss_padding :
            digest = getattr ( hashlib , hash_algorithm ) ( data ) . digest ( )
            rsa = libcrypto . EVP_PKEY_get1_RSA ( private_key . evp_pkey )
            if is_null ( rsa ) :
                handle_openssl_error ( 0 )
            buffer_size = libcrypto . EVP_PKEY_size ( private_key . evp_pkey )
            em_buffer = buffer_from_bytes ( buffer_size )
            res = libcrypto . RSA_padding_add_PKCS1_PSS ( rsa , em_buffer , digest , evp_md , LibcryptoConst . EVP_MD_CTX_FLAG_PSS_MDLEN )
            handle_openssl_error ( res )
            signature_buffer = buffer_from_bytes ( buffer_size )
            signature_length = libcrypto . RSA_private_encrypt ( buffer_size , em_buffer , signature_buffer , rsa , LibcryptoConst . RSA_NO_PADDING )
            handle_openssl_error ( signature_length )
        elif private_key . algorithm == 'rsa' :
            buffer_size = libcrypto . EVP_PKEY_size ( private_key . evp_pkey )
            signature_buffer = buffer_from_bytes ( buffer_size )
            signature_length = new ( libcrypto , 'unsigned int *' )
            res = libcrypto . EVP_DigestInit_ex ( evp_md_ctx , evp_md , null ( ) )
            handle_openssl_error ( res )
            res = libcrypto . EVP_DigestUpdate ( evp_md_ctx , data , len ( data ) )
            handle_openssl_error ( res )
            res = libcrypto . EVP_SignFinal ( evp_md_ctx , signature_buffer , signature_length , private_key . evp_pkey )
            handle_openssl_error ( res )
            signature_length = deref ( signature_length )
        elif private_key . algorithm == 'dsa' :
            digest = getattr ( hashlib , hash_algorithm ) ( data ) . digest ( )
            dsa = libcrypto . EVP_PKEY_get1_DSA ( private_key . evp_pkey )
            if is_null ( dsa ) :
                handle_openssl_error ( 0 )
            dsa_sig = libcrypto . DSA_do_sign ( digest , len ( digest ) , dsa )
            if is_null ( dsa_sig ) :
                handle_openssl_error ( 0 )
            buffer_size = libcrypto . i2d_DSA_SIG ( dsa_sig , null ( ) )
            signature_buffer = buffer_from_bytes ( buffer_size )
            signature_pointer = buffer_pointer ( signature_buffer )
            signature_length = libcrypto . i2d_DSA_SIG ( dsa_sig , signature_pointer )
            handle_openssl_error ( signature_length )
        elif private_key . algorithm == 'ec' :
            digest = getattr ( hashlib , hash_algorithm ) ( data ) . digest ( )
            ec_key = libcrypto . EVP_PKEY_get1_EC_KEY ( private_key . evp_pkey )
            if is_null ( ec_key ) :
                handle_openssl_error ( 0 )
            ecdsa_sig = libcrypto . ECDSA_do_sign ( digest , len ( digest ) , ec_key )
            if is_null ( ecdsa_sig ) :
                handle_openssl_error ( 0 )
            buffer_size = libcrypto . i2d_ECDSA_SIG ( ecdsa_sig , null ( ) )
            signature_buffer = buffer_from_bytes ( buffer_size )
            signature_pointer = buffer_pointer ( signature_buffer )
            signature_length = libcrypto . i2d_ECDSA_SIG ( ecdsa_sig , signature_pointer )
            handle_openssl_error ( signature_length )
    else :
        buffer_size = libcrypto . EVP_PKEY_size ( private_key . evp_pkey )
        signature_buffer = buffer_from_bytes ( buffer_size )
        signature_length = new ( libcrypto , 'size_t *' , buffer_size )
        evp_pkey_ctx_pointer_pointer = new ( libcrypto , 'EVP_PKEY_CTX **' )
        res = libcrypto . EVP_DigestSignInit ( evp_md_ctx , evp_pkey_ctx_pointer_pointer , evp_md , null ( ) , private_key . evp_pkey )
        handle_openssl_error ( res )
        evp_pkey_ctx_pointer = unwrap ( evp_pkey_ctx_pointer_pointer )
        if rsa_pss_padding : # Enable PSS padding
            res = libcrypto . EVP_PKEY_CTX_ctrl ( evp_pkey_ctx_pointer , LibcryptoConst . EVP_PKEY_RSA , - 1 , # All operations
            LibcryptoConst . EVP_PKEY_CTRL_RSA_PADDING , LibcryptoConst . RSA_PKCS1_PSS_PADDING , null ( ) )
            handle_openssl_error ( res )
            # Use the hash algorithm output length as the salt length
            res = libcrypto . EVP_PKEY_CTX_ctrl ( evp_pkey_ctx_pointer , LibcryptoConst . EVP_PKEY_RSA , LibcryptoConst . EVP_PKEY_OP_SIGN | LibcryptoConst . EVP_PKEY_OP_VERIFY , LibcryptoConst . EVP_PKEY_CTRL_RSA_PSS_SALTLEN , - 1 , null ( ) )
            handle_openssl_error ( res )
        res = libcrypto . EVP_DigestUpdate ( evp_md_ctx , data , len ( data ) )
        handle_openssl_error ( res )
        res = libcrypto . EVP_DigestSignFinal ( evp_md_ctx , signature_buffer , signature_length )
        handle_openssl_error ( res )
        signature_length = deref ( signature_length )
    return bytes_from_buffer ( signature_buffer , signature_length )
finally :
    if evp_md_ctx :
        if libcrypto_version_info < ( 1 , 1 ) :
            libcrypto . EVP_MD_CTX_destroy ( evp_md_ctx )
        else :
            libcrypto . EVP_MD_CTX_free ( evp_md_ctx )
    if rsa :
        libcrypto . RSA_free ( rsa )
    if dsa :
        libcrypto . DSA_free ( dsa )
    if dsa_sig :
        libcrypto . DSA_SIG_free ( dsa_sig )
    if ec_key :
        libcrypto . EC_KEY_free ( ec_key )
    if ecdsa_sig :
        libcrypto . ECDSA_SIG_free ( ecdsa_sig )


signature:
def public_key ( self ) :
    """: return :
 The PublicKey object for the public key this certificate contains"""

implementation:
if not self . _public_key and self . x509 :
    evp_pkey = libcrypto . X509_get_pubkey ( self . x509 )
    self . _public_key = PublicKey ( evp_pkey , self . asn1 [ 'tbs_certificate' ] [ 'subject_public_key_info' ] )
return self . _public_key


signature:
def generate_pair ( algorithm , bit_size = None , curve = None ) :
    """Generates a public / private key pair
 : param algorithm :
 The key algorithm - " rsa " , " dsa " or " ec "
 : param bit _ size :
 An integer - used for " rsa " and " dsa " . For " rsa " the value maye be 1024,
 2048 , 3072 or 4096 . For " dsa " the value may be 1024 , plus 2048 or 3072
 if on Windows 8 or newer .
 : param curve :
 A unicode string - used for " ec " keys . Valid values include " secp256r1 " ,
 " secp384r1 " and " secp521r1 " .
 : raises :
 ValueError - when any of the parameters contain an invalid value
 TypeError - when any of the parameters are of the wrong type
 OSError - when an error is returned by the OS crypto library
 : return :
 A 2 - element tuple of ( PublicKey , PrivateKey ) . The contents of each key
 may be saved by calling . asn1 . dump ( ) ."""

implementation:
if algorithm not in set ( [ 'rsa' , 'dsa' , 'ec' ] ) :
    raise ValueError ( pretty_message ( '''
            algorithm must be one of "rsa", "dsa", "ec", not %s
            ''' , repr ( algorithm ) ) )
if algorithm == 'rsa' :
    if bit_size not in set ( [ 1024 , 2048 , 3072 , 4096 ] ) :
        raise ValueError ( pretty_message ( '''
                bit_size must be one of 1024, 2048, 3072, 4096, not %s
                ''' , repr ( bit_size ) ) )
elif algorithm == 'dsa' : # Windows Vista and 7 only support SHA1 - based DSA keys
    if _win_version_info < ( 6 , 2 ) or _backend == 'winlegacy' :
        if bit_size != 1024 :
            raise ValueError ( pretty_message ( '''
                    bit_size must be 1024, not %s
                    ''' , repr ( bit_size ) ) )
    else :
        if bit_size not in set ( [ 1024 , 2048 , 3072 ] ) :
            raise ValueError ( pretty_message ( '''
                    bit_size must be one of 1024, 2048, 3072, not %s
                    ''' , repr ( bit_size ) ) )
elif algorithm == 'ec' :
    if curve not in set ( [ 'secp256r1' , 'secp384r1' , 'secp521r1' ] ) :
        raise ValueError ( pretty_message ( '''
                curve must be one of "secp256r1", "secp384r1", "secp521r1", not %s
                ''' , repr ( curve ) ) )
if _backend == 'winlegacy' :
    if algorithm == 'ec' :
        pub_info , priv_info = _pure_python_ec_generate_pair ( curve )
        return ( PublicKey ( None , pub_info ) , PrivateKey ( None , priv_info ) )
    return _advapi32_generate_pair ( algorithm , bit_size )
else :
    return _bcrypt_generate_pair ( algorithm , bit_size , curve )


signature:
def _advapi32_generate_pair ( algorithm , bit_size = None ) :
    """Generates a public / private key pair using CryptoAPI
 : param algorithm :
 The key algorithm - " rsa " or " dsa "
 : param bit _ size :
 An integer - used for " rsa " and " dsa " . For " rsa " the value maye be 1024,
 2048 , 3072 or 4096 . For " dsa " the value may be 1024.
 : raises :
 ValueError - when any of the parameters contain an invalid value
 TypeError - when any of the parameters are of the wrong type
 OSError - when an error is returned by the OS crypto library
 : return :
 A 2 - element tuple of ( PublicKey , PrivateKey ) . The contents of each key
 may be saved by calling . asn1 . dump ( ) ."""

implementation:
if algorithm == 'rsa' :
    provider = Advapi32Const . MS_ENH_RSA_AES_PROV
    algorithm_id = Advapi32Const . CALG_RSA_SIGN
    struct_type = 'RSABLOBHEADER'
else :
    provider = Advapi32Const . MS_ENH_DSS_DH_PROV
    algorithm_id = Advapi32Const . CALG_DSS_SIGN
    struct_type = 'DSSBLOBHEADER'
context_handle = None
key_handle = None
try :
    context_handle = open_context_handle ( provider , verify_only = False )
    key_handle_pointer = new ( advapi32 , 'HCRYPTKEY *' )
    flags = ( bit_size << 16 ) | Advapi32Const . CRYPT_EXPORTABLE
    res = advapi32 . CryptGenKey ( context_handle , algorithm_id , flags , key_handle_pointer )
    handle_error ( res )
    key_handle = unwrap ( key_handle_pointer )
    out_len = new ( advapi32 , 'DWORD *' )
    res = advapi32 . CryptExportKey ( key_handle , null ( ) , Advapi32Const . PRIVATEKEYBLOB , 0 , null ( ) , out_len )
    handle_error ( res )
    buffer_length = deref ( out_len )
    buffer_ = buffer_from_bytes ( buffer_length )
    res = advapi32 . CryptExportKey ( key_handle , null ( ) , Advapi32Const . PRIVATEKEYBLOB , 0 , buffer_ , out_len )
    handle_error ( res )
    blob_struct_pointer = struct_from_buffer ( advapi32 , struct_type , buffer_ )
    blob_struct = unwrap ( blob_struct_pointer )
    struct_size = sizeof ( advapi32 , blob_struct )
    private_blob = bytes_from_buffer ( buffer_ , buffer_length ) [ struct_size : ]
    if algorithm == 'rsa' :
        public_info , private_info = _advapi32_interpret_rsa_key_blob ( bit_size , blob_struct , private_blob )
    else : # The public key for a DSA key is not available in from the private
    # key blob , so we have to separately export the public key
        public_out_len = new ( advapi32 , 'DWORD *' )
        res = advapi32 . CryptExportKey ( key_handle , null ( ) , Advapi32Const . PUBLICKEYBLOB , 0 , null ( ) , public_out_len )
        handle_error ( res )
        public_buffer_length = deref ( public_out_len )
        public_buffer = buffer_from_bytes ( public_buffer_length )
        res = advapi32 . CryptExportKey ( key_handle , null ( ) , Advapi32Const . PUBLICKEYBLOB , 0 , public_buffer , public_out_len )
        handle_error ( res )
        public_blob = bytes_from_buffer ( public_buffer , public_buffer_length ) [ struct_size : ]
        public_info , private_info = _advapi32_interpret_dsa_key_blob ( bit_size , public_blob , private_blob )
    return ( load_public_key ( public_info ) , load_private_key ( private_info ) )
finally :
    if context_handle :
        close_context_handle ( context_handle )
    if key_handle :
        advapi32 . CryptDestroyKey ( key_handle )


signature:
def _bcrypt_generate_pair ( algorithm , bit_size = None , curve = None ) :
    """Generates a public / private key pair using CNG
 : param algorithm :
 The key algorithm - " rsa " , " dsa " or " ec "
 : param bit _ size :
 An integer - used for " rsa " and " dsa " . For " rsa " the value maye be 1024,
 2048 , 3072 or 4096 . For " dsa " the value may be 1024 , plus 2048 or 3072
 if on Windows 8 or newer .
 : param curve :
 A unicode string - used for " ec " keys . Valid values include " secp256r1 " ,
 " secp384r1 " and " secp521r1 " .
 : raises :
 ValueError - when any of the parameters contain an invalid value
 TypeError - when any of the parameters are of the wrong type
 OSError - when an error is returned by the OS crypto library
 : return :
 A 2 - element tuple of ( PublicKey , PrivateKey ) . The contents of each key
 may be saved by calling . asn1 . dump ( ) ."""

implementation:
if algorithm == 'rsa' :
    alg_constant = BcryptConst . BCRYPT_RSA_ALGORITHM
    struct_type = 'BCRYPT_RSAKEY_BLOB'
    private_blob_type = BcryptConst . BCRYPT_RSAFULLPRIVATE_BLOB
    public_blob_type = BcryptConst . BCRYPT_RSAPUBLIC_BLOB
elif algorithm == 'dsa' :
    alg_constant = BcryptConst . BCRYPT_DSA_ALGORITHM
    if bit_size > 1024 :
        struct_type = 'BCRYPT_DSA_KEY_BLOB_V2'
    else :
        struct_type = 'BCRYPT_DSA_KEY_BLOB'
    private_blob_type = BcryptConst . BCRYPT_DSA_PRIVATE_BLOB
    public_blob_type = BcryptConst . BCRYPT_DSA_PUBLIC_BLOB
else :
    alg_constant = { 'secp256r1' : BcryptConst . BCRYPT_ECDSA_P256_ALGORITHM , 'secp384r1' : BcryptConst . BCRYPT_ECDSA_P384_ALGORITHM , 'secp521r1' : BcryptConst . BCRYPT_ECDSA_P521_ALGORITHM , } [ curve ]
    bit_size = { 'secp256r1' : 256 , 'secp384r1' : 384 , 'secp521r1' : 521 , } [ curve ]
    struct_type = 'BCRYPT_ECCKEY_BLOB'
    private_blob_type = BcryptConst . BCRYPT_ECCPRIVATE_BLOB
    public_blob_type = BcryptConst . BCRYPT_ECCPUBLIC_BLOB
alg_handle = open_alg_handle ( alg_constant )
key_handle_pointer = new ( bcrypt , 'BCRYPT_KEY_HANDLE *' )
res = bcrypt . BCryptGenerateKeyPair ( alg_handle , key_handle_pointer , bit_size , 0 )
handle_error ( res )
key_handle = unwrap ( key_handle_pointer )
res = bcrypt . BCryptFinalizeKeyPair ( key_handle , 0 )
handle_error ( res )
private_out_len = new ( bcrypt , 'ULONG *' )
res = bcrypt . BCryptExportKey ( key_handle , null ( ) , private_blob_type , null ( ) , 0 , private_out_len , 0 )
handle_error ( res )
private_buffer_length = deref ( private_out_len )
private_buffer = buffer_from_bytes ( private_buffer_length )
res = bcrypt . BCryptExportKey ( key_handle , null ( ) , private_blob_type , private_buffer , private_buffer_length , private_out_len , 0 )
handle_error ( res )
private_blob_struct_pointer = struct_from_buffer ( bcrypt , struct_type , private_buffer )
private_blob_struct = unwrap ( private_blob_struct_pointer )
struct_size = sizeof ( bcrypt , private_blob_struct )
private_blob = bytes_from_buffer ( private_buffer , private_buffer_length ) [ struct_size : ]
if algorithm == 'rsa' :
    private_key = _bcrypt_interpret_rsa_key_blob ( 'private' , private_blob_struct , private_blob )
elif algorithm == 'dsa' :
    if bit_size > 1024 :
        private_key = _bcrypt_interpret_dsa_key_blob ( 'private' , 2 , private_blob_struct , private_blob )
    else :
        private_key = _bcrypt_interpret_dsa_key_blob ( 'private' , 1 , private_blob_struct , private_blob )
else :
    private_key = _bcrypt_interpret_ec_key_blob ( 'private' , private_blob_struct , private_blob )
public_out_len = new ( bcrypt , 'ULONG *' )
res = bcrypt . BCryptExportKey ( key_handle , null ( ) , public_blob_type , null ( ) , 0 , public_out_len , 0 )
handle_error ( res )
public_buffer_length = deref ( public_out_len )
public_buffer = buffer_from_bytes ( public_buffer_length )
res = bcrypt . BCryptExportKey ( key_handle , null ( ) , public_blob_type , public_buffer , public_buffer_length , public_out_len , 0 )
handle_error ( res )
public_blob_struct_pointer = struct_from_buffer ( bcrypt , struct_type , public_buffer )
public_blob_struct = unwrap ( public_blob_struct_pointer )
struct_size = sizeof ( bcrypt , public_blob_struct )
public_blob = bytes_from_buffer ( public_buffer , public_buffer_length ) [ struct_size : ]
if algorithm == 'rsa' :
    public_key = _bcrypt_interpret_rsa_key_blob ( 'public' , public_blob_struct , public_blob )
elif algorithm == 'dsa' :
    if bit_size > 1024 :
        public_key = _bcrypt_interpret_dsa_key_blob ( 'public' , 2 , public_blob_struct , public_blob )
    else :
        public_key = _bcrypt_interpret_dsa_key_blob ( 'public' , 1 , public_blob_struct , public_blob )
else :
    public_key = _bcrypt_interpret_ec_key_blob ( 'public' , public_blob_struct , public_blob )
return ( load_public_key ( public_key ) , load_private_key ( private_key ) )


implementation:
if not isinstance ( bit_size , int_types ) :
    raise TypeError ( pretty_message ( '''
            bit_size must be an integer, not %s
            ''' , type_name ( bit_size ) ) )
if bit_size < 512 :
    raise ValueError ( 'bit_size must be greater than or equal to 512' )
if bit_size > 4096 :
    raise ValueError ( 'bit_size must be less than or equal to 4096' )
if bit_size % 64 != 0 :
    raise ValueError ( 'bit_size must be a multiple of 64' )
alg_handle = None
# The following algorithm has elements taken from OpenSSL . In short , it
# generates random numbers and then ensures that they are valid for the
# hardcoded generator of 2 , and then ensures the number is a " safe " prime
# by ensuring p / / 2 is prime also .
# OpenSSL allows use of generator 2 or 5 , but we hardcode 2 since it is
# the default , and what is used by Security . framework on OS X also .
g = 2
try :
    byte_size = bit_size // 8
    if _backend == 'win' :
        alg_handle = open_alg_handle ( BcryptConst . BCRYPT_RNG_ALGORITHM )
        buffer = buffer_from_bytes ( byte_size )
    while True :
        if _backend == 'winlegacy' :
            rb = os . urandom ( byte_size )
        else :
            res = bcrypt . BCryptGenRandom ( alg_handle , buffer , byte_size , 0 )
            handle_error ( res )
            rb = bytes_from_buffer ( buffer )
        p = int_from_bytes ( rb )
        # If a number is even , it can ' t be prime
        if p % 2 == 0 :
            continue
        # Perform the generator checks outlined in OpenSSL ' s
        # dh _ builtin _ genparams ( ) located in dh _ gen . c
        if g == 2 :
            if p % 24 != 11 :
                continue
        elif g == 5 :
            rem = p % 10
            if rem != 3 and rem != 7 :
                continue
        divisible = False
        for prime in _SMALL_PRIMES :
            if p % prime == 0 :
                divisible = True
                break
        # If the number is not divisible by any of the small primes , then
        # move on to the full Miller - Rabin test .
        if not divisible and _is_prime ( bit_size , p ) :
            q = p // 2
            if _is_prime ( bit_size , q ) :
                return algos . DHParameters ( { 'p' : p , 'g' : g } )
finally :
    if alg_handle :
        close_alg_handle ( alg_handle )


signature:
def _is_prime ( bit_size , n ) :
    """An implementation of Miller – Rabin for checking if a number is prime .
 : param bit _ size :
 An integer of the number of bits in the prime number
 : param n :
 An integer , the prime number
 : return :
 A boolean"""

implementation:
r = 0
s = n - 1
while s % 2 == 0 :
    r += 1
    s //= 2
if bit_size >= 1300 :
    k = 2
elif bit_size >= 850 :
    k = 3
elif bit_size >= 650 :
    k = 4
elif bit_size >= 550 :
    k = 5
elif bit_size >= 450 :
    k = 6
for _ in range ( k ) :
    a = random . randrange ( 2 , n - 1 )
    x = pow ( a , s , n )
    if x == 1 or x == n - 1 :
        continue
    for _ in range ( r - 1 ) :
        x = pow ( x , 2 , n )
        if x == n - 1 :
            break
    else :
        return False
return True


signature:
def _advapi32_interpret_rsa_key_blob ( bit_size , blob_struct , blob ) :
    """Takes a CryptoAPI RSA private key blob and converts it into the ASN . 1
 structures for the public and private keys
 : param bit _ size :
 The integer bit size of the key
 : param blob _ struct :
 An instance of the advapi32 . RSAPUBKEY struct
 : param blob :
 A byte string of the binary data after the header
 : return :
 A 2 - element tuple of ( asn1crypto . keys . PublicKeyInfo ,
 asn1crypto . keys . PrivateKeyInfo )"""

implementation:
len1 = bit_size // 8
len2 = bit_size // 16
prime1_offset = len1
prime2_offset = prime1_offset + len2
exponent1_offset = prime2_offset + len2
exponent2_offset = exponent1_offset + len2
coefficient_offset = exponent2_offset + len2
private_exponent_offset = coefficient_offset + len2
public_exponent = blob_struct . rsapubkey . pubexp
modulus = int_from_bytes ( blob [ 0 : prime1_offset ] [ : : - 1 ] )
prime1 = int_from_bytes ( blob [ prime1_offset : prime2_offset ] [ : : - 1 ] )
prime2 = int_from_bytes ( blob [ prime2_offset : exponent1_offset ] [ : : - 1 ] )
exponent1 = int_from_bytes ( blob [ exponent1_offset : exponent2_offset ] [ : : - 1 ] )
exponent2 = int_from_bytes ( blob [ exponent2_offset : coefficient_offset ] [ : : - 1 ] )
coefficient = int_from_bytes ( blob [ coefficient_offset : private_exponent_offset ] [ : : - 1 ] )
private_exponent = int_from_bytes ( blob [ private_exponent_offset : private_exponent_offset + len1 ] [ : : - 1 ] )
public_key_info = keys . PublicKeyInfo ( { 'algorithm' : keys . PublicKeyAlgorithm ( { 'algorithm' : 'rsa' , } ) , 'public_key' : keys . RSAPublicKey ( { 'modulus' : modulus , 'public_exponent' : public_exponent , } ) , } )
rsa_private_key = keys . RSAPrivateKey ( { 'version' : 'two-prime' , 'modulus' : modulus , 'public_exponent' : public_exponent , 'private_exponent' : private_exponent , 'prime1' : prime1 , 'prime2' : prime2 , 'exponent1' : exponent1 , 'exponent2' : exponent2 , 'coefficient' : coefficient , } )
private_key_info = keys . PrivateKeyInfo ( { 'version' : 0 , 'private_key_algorithm' : keys . PrivateKeyAlgorithm ( { 'algorithm' : 'rsa' , } ) , 'private_key' : rsa_private_key , } )
return ( public_key_info , private_key_info )


signature:
def _advapi32_interpret_dsa_key_blob ( bit_size , public_blob , private_blob ) :
    """Takes a CryptoAPI DSS private key blob and converts it into the ASN . 1
 structures for the public and private keys
 : param bit _ size :
 The integer bit size of the key
 : param public _ blob :
 A byte string of the binary data after the public key header
 : param private _ blob :
 A byte string of the binary data after the private key header
 : return :
 A 2 - element tuple of ( asn1crypto . keys . PublicKeyInfo ,
 asn1crypto . keys . PrivateKeyInfo )"""

implementation:
len1 = 20
len2 = bit_size // 8
q_offset = len2
g_offset = q_offset + len1
x_offset = g_offset + len2
y_offset = x_offset
p = int_from_bytes ( private_blob [ 0 : q_offset ] [ : : - 1 ] )
q = int_from_bytes ( private_blob [ q_offset : g_offset ] [ : : - 1 ] )
g = int_from_bytes ( private_blob [ g_offset : x_offset ] [ : : - 1 ] )
x = int_from_bytes ( private_blob [ x_offset : x_offset + len1 ] [ : : - 1 ] )
y = int_from_bytes ( public_blob [ y_offset : y_offset + len2 ] [ : : - 1 ] )
public_key_info = keys . PublicKeyInfo ( { 'algorithm' : keys . PublicKeyAlgorithm ( { 'algorithm' : 'dsa' , 'parameters' : keys . DSAParams ( { 'p' : p , 'q' : q , 'g' : g , } ) } ) , 'public_key' : core . Integer ( y ) , } )
private_key_info = keys . PrivateKeyInfo ( { 'version' : 0 , 'private_key_algorithm' : keys . PrivateKeyAlgorithm ( { 'algorithm' : 'dsa' , 'parameters' : keys . DSAParams ( { 'p' : p , 'q' : q , 'g' : g , } ) } ) , 'private_key' : core . Integer ( x ) , } )
return ( public_key_info , private_key_info )


signature:
def _bcrypt_interpret_rsa_key_blob ( key_type , blob_struct , blob ) :
    """Take a CNG BCRYPT _ RSAFULLPRIVATE _ BLOB and converts it into an ASN . 1
 structure
 : param key _ type :
 A unicode string of " private " or " public "
 : param blob _ struct :
 An instance of BCRYPT _ RSAKEY _ BLOB
 : param blob :
 A byte string of the binary data contained after the struct
 : return :
 An asn1crypto . keys . PrivateKeyInfo or asn1crypto . keys . PublicKeyInfo
 object , based on the key _ type param"""

implementation:
public_exponent_byte_length = native ( int , blob_struct . cbPublicExp )
modulus_byte_length = native ( int , blob_struct . cbModulus )
modulus_offset = public_exponent_byte_length
public_exponent = int_from_bytes ( blob [ 0 : modulus_offset ] )
modulus = int_from_bytes ( blob [ modulus_offset : modulus_offset + modulus_byte_length ] )
if key_type == 'public' :
    return keys . PublicKeyInfo ( { 'algorithm' : keys . PublicKeyAlgorithm ( { 'algorithm' : 'rsa' , } ) , 'public_key' : keys . RSAPublicKey ( { 'modulus' : modulus , 'public_exponent' : public_exponent , } ) , } )
elif key_type == 'private' :
    prime1_byte_length = native ( int , blob_struct . cbPrime1 )
    prime2_byte_length = native ( int , blob_struct . cbPrime2 )
    prime1_offset = modulus_offset + modulus_byte_length
    prime2_offset = prime1_offset + prime1_byte_length
    exponent1_offset = prime2_offset + prime2_byte_length
    exponent2_offset = exponent1_offset + prime2_byte_length
    coefficient_offset = exponent2_offset + prime2_byte_length
    private_exponent_offset = coefficient_offset + prime1_byte_length
    prime1 = int_from_bytes ( blob [ prime1_offset : prime2_offset ] )
    prime2 = int_from_bytes ( blob [ prime2_offset : exponent1_offset ] )
    exponent1 = int_from_bytes ( blob [ exponent1_offset : exponent2_offset ] )
    exponent2 = int_from_bytes ( blob [ exponent2_offset : coefficient_offset ] )
    coefficient = int_from_bytes ( blob [ coefficient_offset : private_exponent_offset ] )
    private_exponent = int_from_bytes ( blob [ private_exponent_offset : private_exponent_offset + modulus_byte_length ] )
    rsa_private_key = keys . RSAPrivateKey ( { 'version' : 'two-prime' , 'modulus' : modulus , 'public_exponent' : public_exponent , 'private_exponent' : private_exponent , 'prime1' : prime1 , 'prime2' : prime2 , 'exponent1' : exponent1 , 'exponent2' : exponent2 , 'coefficient' : coefficient , } )
    return keys . PrivateKeyInfo ( { 'version' : 0 , 'private_key_algorithm' : keys . PrivateKeyAlgorithm ( { 'algorithm' : 'rsa' , } ) , 'private_key' : rsa_private_key , } )
else :
    raise ValueError ( pretty_message ( '''
            key_type must be one of "public", "private", not %s
            ''' , repr ( key_type ) ) )


signature:
def _bcrypt_interpret_dsa_key_blob ( key_type , version , blob_struct , blob ) :
    """Take a CNG BCRYPT _ DSA _ KEY _ BLOB or BCRYPT _ DSA _ KEY _ BLOB _ V2 and converts it
 into an ASN . 1 structure
 : param key _ type :
 A unicode string of " private " or " public "
 : param version :
 An integer - 1 or 2 , indicating the blob is BCRYPT _ DSA _ KEY _ BLOB or
 BCRYPT _ DSA _ KEY _ BLOB _ V2
 : param blob _ struct :
 An instance of BCRYPT _ DSA _ KEY _ BLOB or BCRYPT _ DSA _ KEY _ BLOB _ V2
 : param blob :
 A byte string of the binary data contained after the struct
 : return :
 An asn1crypto . keys . PrivateKeyInfo or asn1crypto . keys . PublicKeyInfo
 object , based on the key _ type param"""

implementation:
key_byte_length = native ( int , blob_struct . cbKey )
if version == 1 :
    q = int_from_bytes ( native ( byte_cls , blob_struct . q ) )
    g_offset = key_byte_length
    public_offset = g_offset + key_byte_length
    private_offset = public_offset + key_byte_length
    p = int_from_bytes ( blob [ 0 : g_offset ] )
    g = int_from_bytes ( blob [ g_offset : public_offset ] )
elif version == 2 :
    seed_byte_length = native ( int , blob_struct . cbSeedLength )
    group_byte_length = native ( int , blob_struct . cbGroupSize )
    q_offset = seed_byte_length
    p_offset = q_offset + group_byte_length
    g_offset = p_offset + key_byte_length
    public_offset = g_offset + key_byte_length
    private_offset = public_offset + key_byte_length
    # The seed is skipped since it is not part of the ASN . 1 structure
    q = int_from_bytes ( blob [ q_offset : p_offset ] )
    p = int_from_bytes ( blob [ p_offset : g_offset ] )
    g = int_from_bytes ( blob [ g_offset : public_offset ] )
else :
    raise ValueError ( 'version must be 1 or 2, not %s' % repr ( version ) )
if key_type == 'public' :
    public = int_from_bytes ( blob [ public_offset : private_offset ] )
    return keys . PublicKeyInfo ( { 'algorithm' : keys . PublicKeyAlgorithm ( { 'algorithm' : 'dsa' , 'parameters' : keys . DSAParams ( { 'p' : p , 'q' : q , 'g' : g , } ) } ) , 'public_key' : core . Integer ( public ) , } )
elif key_type == 'private' :
    private = int_from_bytes ( blob [ private_offset : private_offset + key_byte_length ] )
    return keys . PrivateKeyInfo ( { 'version' : 0 , 'private_key_algorithm' : keys . PrivateKeyAlgorithm ( { 'algorithm' : 'dsa' , 'parameters' : keys . DSAParams ( { 'p' : p , 'q' : q , 'g' : g , } ) } ) , 'private_key' : core . Integer ( private ) , } )
else :
    raise ValueError ( pretty_message ( '''
            key_type must be one of "public", "private", not %s
            ''' , repr ( key_type ) ) )


signature:
def _bcrypt_interpret_ec_key_blob ( key_type , blob_struct , blob ) :
    """Take a CNG BCRYPT _ ECCKEY _ BLOB and converts it into an ASN . 1 structure
 : param key _ type :
 A unicode string of " private " or " public "
 : param blob _ struct :
 An instance of BCRYPT _ ECCKEY _ BLOB
 : param blob :
 A byte string of the binary data contained after the struct
 : return :
 An asn1crypto . keys . PrivateKeyInfo or asn1crypto . keys . PublicKeyInfo
 object , based on the key _ type param"""

implementation:
magic = native ( int , blob_struct . dwMagic )
key_byte_length = native ( int , blob_struct . cbKey )
curve = { BcryptConst . BCRYPT_ECDSA_PRIVATE_P256_MAGIC : 'secp256r1' , BcryptConst . BCRYPT_ECDSA_PRIVATE_P384_MAGIC : 'secp384r1' , BcryptConst . BCRYPT_ECDSA_PRIVATE_P521_MAGIC : 'secp521r1' , BcryptConst . BCRYPT_ECDSA_PUBLIC_P256_MAGIC : 'secp256r1' , BcryptConst . BCRYPT_ECDSA_PUBLIC_P384_MAGIC : 'secp384r1' , BcryptConst . BCRYPT_ECDSA_PUBLIC_P521_MAGIC : 'secp521r1' , } [ magic ]
public = b'\x04' + blob [ 0 : key_byte_length * 2 ]
if key_type == 'public' :
    return keys . PublicKeyInfo ( { 'algorithm' : keys . PublicKeyAlgorithm ( { 'algorithm' : 'ec' , 'parameters' : keys . ECDomainParameters ( name = 'named' , value = curve ) } ) , 'public_key' : public , } )
elif key_type == 'private' :
    private = int_from_bytes ( blob [ key_byte_length * 2 : key_byte_length * 3 ] )
    return keys . PrivateKeyInfo ( { 'version' : 0 , 'private_key_algorithm' : keys . PrivateKeyAlgorithm ( { 'algorithm' : 'ec' , 'parameters' : keys . ECDomainParameters ( name = 'named' , value = curve ) } ) , 'private_key' : keys . ECPrivateKey ( { 'version' : 'ecPrivkeyVer1' , 'private_key' : private , 'public_key' : public , } ) , } )
else :
    raise ValueError ( pretty_message ( '''
            key_type must be one of "public", "private", not %s
            ''' , repr ( key_type ) ) )


signature:
def _load_key ( key_object , container ) :
    """Loads a certificate , public key or private key into a Certificate ,
 PublicKey or PrivateKey object
 : param key _ object :
 An asn1crypto . x509 . Certificate , asn1crypto . keys . PublicKeyInfo or
 asn1crypto . keys . PrivateKeyInfo object
 : param container :
 The class of the object to hold the key _ handle
 : raises :
 ValueError - when any of the parameters contain an invalid value
 TypeError - when any of the parameters are of the wrong type
 oscrypto . errors . AsymmetricKeyError - when the key is incompatible with the OS crypto library
 OSError - when an error is returned by the OS crypto library
 : return :
 A PrivateKey , PublicKey or Certificate object , based on container"""

implementation:
key_info = key_object
if isinstance ( key_object , x509 . Certificate ) :
    key_info = key_object [ 'tbs_certificate' ] [ 'subject_public_key_info' ]
algo = key_info . algorithm
curve_name = None
if algo == 'ec' :
    curve_type , curve_name = key_info . curve
    if curve_type != 'named' :
        raise AsymmetricKeyError ( pretty_message ( '''
                Windows only supports EC keys using named curves
                ''' ) )
    if curve_name not in set ( [ 'secp256r1' , 'secp384r1' , 'secp521r1' ] ) :
        raise AsymmetricKeyError ( pretty_message ( '''
                Windows only supports EC keys using the named curves
                secp256r1, secp384r1 and secp521r1
                ''' ) )
elif algo == 'dsa' :
    if key_info . hash_algo is None :
        raise IncompleteAsymmetricKeyError ( pretty_message ( '''
                The DSA key does not contain the necessary p, q and g
                parameters and can not be used
                ''' ) )
    elif key_info . bit_size > 1024 and ( _win_version_info < ( 6 , 2 ) or _backend == 'winlegacy' ) :
        raise AsymmetricKeyError ( pretty_message ( '''
                Windows XP, 2003, Vista, 7 and Server 2008 only support DSA
                keys based on SHA1 (1024 bits or less) - this key is based
                on %s and is %s bits
                ''' , key_info . hash_algo . upper ( ) , key_info . bit_size ) )
    elif key_info . bit_size == 2048 and key_info . hash_algo == 'sha1' :
        raise AsymmetricKeyError ( pretty_message ( '''
                Windows only supports 2048 bit DSA keys based on SHA2 - this
                key is 2048 bits and based on SHA1, a non-standard
                combination that is usually generated by old versions
                of OpenSSL
                ''' ) )
if _backend == 'winlegacy' :
    if algo == 'ec' :
        return container ( None , key_object )
    return _advapi32_load_key ( key_object , key_info , container )
return _bcrypt_load_key ( key_object , key_info , container , curve_name )


signature:
def _advapi32_load_key ( key_object , key_info , container ) :
    """Loads a certificate , public key or private key into a Certificate ,
 PublicKey or PrivateKey object via CryptoAPI
 : param key _ object :
 An asn1crypto . x509 . Certificate , asn1crypto . keys . PublicKeyInfo or
 asn1crypto . keys . PrivateKeyInfo object
 : param key _ info :
 An asn1crypto . keys . PublicKeyInfo or asn1crypto . keys . PrivateKeyInfo
 object
 : param container :
 The class of the object to hold the key _ handle
 : raises :
 ValueError - when any of the parameters contain an invalid value
 TypeError - when any of the parameters are of the wrong type
 oscrypto . errors . AsymmetricKeyError - when the key is incompatible with the OS crypto library
 OSError - when an error is returned by the OS crypto library
 : return :
 A PrivateKey , PublicKey or Certificate object , based on container"""

implementation:
key_type = 'public' if isinstance ( key_info , keys . PublicKeyInfo ) else 'private'
algo = key_info . algorithm
if algo == 'rsa' :
    provider = Advapi32Const . MS_ENH_RSA_AES_PROV
else :
    provider = Advapi32Const . MS_ENH_DSS_DH_PROV
context_handle = None
key_handle = None
try :
    context_handle = open_context_handle ( provider , verify_only = key_type == 'public' )
    blob = _advapi32_create_blob ( key_info , key_type , algo )
    buffer_ = buffer_from_bytes ( blob )
    key_handle_pointer = new ( advapi32 , 'HCRYPTKEY *' )
    res = advapi32 . CryptImportKey ( context_handle , buffer_ , len ( blob ) , null ( ) , 0 , key_handle_pointer )
    handle_error ( res )
    key_handle = unwrap ( key_handle_pointer )
    output = container ( key_handle , key_object )
    output . context_handle = context_handle
    if algo == 'rsa' :
        ex_blob = _advapi32_create_blob ( key_info , key_type , algo , signing = False )
        ex_buffer = buffer_from_bytes ( ex_blob )
        ex_key_handle_pointer = new ( advapi32 , 'HCRYPTKEY *' )
        res = advapi32 . CryptImportKey ( context_handle , ex_buffer , len ( ex_blob ) , null ( ) , 0 , ex_key_handle_pointer )
        handle_error ( res )
        output . ex_key_handle = unwrap ( ex_key_handle_pointer )
    return output
except ( Exception ) :
    if key_handle :
        advapi32 . CryptDestroyKey ( key_handle )
    if context_handle :
        close_context_handle ( context_handle )
    raise


signature:
def _advapi32_create_blob ( key_info , key_type , algo , signing = True ) :
    """Generates a blob for importing a key to CryptoAPI
 : param key _ info :
 An asn1crypto . keys . PublicKeyInfo or asn1crypto . keys . PrivateKeyInfo
 object
 : param key _ type :
 A unicode string of " public " or " private "
 : param algo :
 A unicode string of " rsa " or " dsa "
 : param signing :
 If the key handle is for signing - may only be False for rsa keys
 : return :
 A byte string of a blob to pass to advapi32 . CryptImportKey ( )"""

implementation:
if key_type == 'public' :
    blob_type = Advapi32Const . PUBLICKEYBLOB
else :
    blob_type = Advapi32Const . PRIVATEKEYBLOB
if algo == 'rsa' :
    struct_type = 'RSABLOBHEADER'
    if signing :
        algorithm_id = Advapi32Const . CALG_RSA_SIGN
    else :
        algorithm_id = Advapi32Const . CALG_RSA_KEYX
else :
    struct_type = 'DSSBLOBHEADER'
    algorithm_id = Advapi32Const . CALG_DSS_SIGN
blob_header_pointer = struct ( advapi32 , 'BLOBHEADER' )
blob_header = unwrap ( blob_header_pointer )
blob_header . bType = blob_type
blob_header . bVersion = Advapi32Const . CUR_BLOB_VERSION
blob_header . reserved = 0
blob_header . aiKeyAlg = algorithm_id
blob_struct_pointer = struct ( advapi32 , struct_type )
blob_struct = unwrap ( blob_struct_pointer )
blob_struct . publickeystruc = blob_header
bit_size = key_info . bit_size
len1 = bit_size // 8
len2 = bit_size // 16
if algo == 'rsa' :
    pubkey_pointer = struct ( advapi32 , 'RSAPUBKEY' )
    pubkey = unwrap ( pubkey_pointer )
    pubkey . bitlen = bit_size
    if key_type == 'public' :
        parsed_key_info = key_info [ 'public_key' ] . parsed
        pubkey . magic = Advapi32Const . RSA1
        pubkey . pubexp = parsed_key_info [ 'public_exponent' ] . native
        blob_data = int_to_bytes ( parsed_key_info [ 'modulus' ] . native , signed = False , width = len1 ) [ : : - 1 ]
    else :
        parsed_key_info = key_info [ 'private_key' ] . parsed
        pubkey . magic = Advapi32Const . RSA2
        pubkey . pubexp = parsed_key_info [ 'public_exponent' ] . native
        blob_data = int_to_bytes ( parsed_key_info [ 'modulus' ] . native , signed = False , width = len1 ) [ : : - 1 ]
        blob_data += int_to_bytes ( parsed_key_info [ 'prime1' ] . native , signed = False , width = len2 ) [ : : - 1 ]
        blob_data += int_to_bytes ( parsed_key_info [ 'prime2' ] . native , signed = False , width = len2 ) [ : : - 1 ]
        blob_data += int_to_bytes ( parsed_key_info [ 'exponent1' ] . native , signed = False , width = len2 ) [ : : - 1 ]
        blob_data += int_to_bytes ( parsed_key_info [ 'exponent2' ] . native , signed = False , width = len2 ) [ : : - 1 ]
        blob_data += int_to_bytes ( parsed_key_info [ 'coefficient' ] . native , signed = False , width = len2 ) [ : : - 1 ]
        blob_data += int_to_bytes ( parsed_key_info [ 'private_exponent' ] . native , signed = False , width = len1 ) [ : : - 1 ]
    blob_struct . rsapubkey = pubkey
else :
    pubkey_pointer = struct ( advapi32 , 'DSSPUBKEY' )
    pubkey = unwrap ( pubkey_pointer )
    pubkey . bitlen = bit_size
    if key_type == 'public' :
        pubkey . magic = Advapi32Const . DSS1
        params = key_info [ 'algorithm' ] [ 'parameters' ] . native
        key_data = int_to_bytes ( key_info [ 'public_key' ] . parsed . native , signed = False , width = len1 ) [ : : - 1 ]
    else :
        pubkey . magic = Advapi32Const . DSS2
        params = key_info [ 'private_key_algorithm' ] [ 'parameters' ] . native
        key_data = int_to_bytes ( key_info [ 'private_key' ] . parsed . native , signed = False , width = 20 ) [ : : - 1 ]
    blob_struct . dsspubkey = pubkey
    blob_data = int_to_bytes ( params [ 'p' ] , signed = False , width = len1 ) [ : : - 1 ]
    blob_data += int_to_bytes ( params [ 'q' ] , signed = False , width = 20 ) [ : : - 1 ]
    blob_data += int_to_bytes ( params [ 'g' ] , signed = False , width = len1 ) [ : : - 1 ]
    blob_data += key_data
    dssseed_pointer = struct ( advapi32 , 'DSSSEED' )
    dssseed = unwrap ( dssseed_pointer )
    # This indicates no counter or seed info is available
    dssseed . counter = 0xffffffff
    blob_data += struct_bytes ( dssseed_pointer )
return struct_bytes ( blob_struct_pointer ) + blob_data