pFad - Phone/Frame/Anonymizer/Declutterfier! Saves Data!


--- a PPN by Garber Painting Akron. With Image Size Reduction included!

URL: http://github.com/space88man/cryptography_engine

GitHub - space88man/cryptography_engine: Python 3 pyca/cryptography wrappers for OpenSSL ENGINE operations · GitHub
Skip to content

space88man/cryptography_engine

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

6 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

cryptography_engine

A thin set of wrappers over OpenSSL Engine key operations based on pyca/cryptography

Read Me First!

Update 2021-09-29: Test matrix updated to Python 3.10rc2 (Fedora 35 beta).

  • platform linux — Python 3.10.0rc2, pytest-6.2.5, py-1.10.0, pluggy-1.0.0
  • cryptography — 3.4.8
  • softhsm — 2.6.1
  • (engine) openssl-pkcs11 — 0.4.11

Update 2021-04-19: pyca/cryptography removed bindings to ENGINE_xxx functions for a while, and these were reinstated in PR#5449. There are now a few tweaks to work with new bindings. The old code can be found in the for-2.5 branch.


This package uses pyca/cryptography internal and hazmat objects so it is dependent on the version of pyca/cryptography and will break if various internal symbols disappear.

The tests use the pkcs11 engine with SoftHSMv2 v2.3.

The tests assume that there is a SoftHSMv2 token in tmp/tokens. You can either copy from tests/tokens OR create a new one using the script ./test_tokens.sh if your version of SoftHSMv2 is not binary compatible with v2.3. You will need pkcs11-tool from opensc to create a token.

The tests call out to an external openssl binary using subprocess for verification. Note that there is a OpenSSL configuration file in tests/fixtures/openssl.cnf that provides the PIN (default value: userpin).

## set OPENSSL_ENGINES var to find libpkcs11.so/pkcs11.so if you are not using
## a locally compiled wheel. The PyPI wheel expects to find engines in
## /opt/pyca/cryptography/openssl/lib/engines-1.1

## EITHER
$ mkdir tmp; cp -r tests/tokens tmp/

## OR

$ ./test_tokens.sh
+ export SOFTHSM2_CONF=tests/softhsm2.conf
+ SOFTHSM2_CONF=tests/softhsm2.conf
+ SOFTHSM2_SO=/usr/lib64/libsofthsm2.so
+ MY_USER_PIN=userpin
+ MY_SO_PIN=sopin
+ MY_LABEL=MyToken1
+ mkdir -p tmp/tokens
+ rm -rf tmp/tokens/*
+ softhsm2-util --init-token --slot 0 --label MyToken1 --pin userpin --so-pin sopin
The token has been initialized and is reassigned to slot 1116624427
++ pkcs11-tool --module /usr/lib64/libsofthsm2.so -L
++ grep 'Slot 0'
++ sed 's/.*ID //'
+ SLOTID=0x428e562b
+ pkcs11-tool --module /usr/lib64/libsofthsm2.so --slot 0x428e562b --login --pin userpin -k --key-type RSA:2048 -a RSA-0001 -d 0001
Key pair generated:
Private Key Object; RSA
  label:      RSA-0001
  ID:         0001
  Usage:      decrypt, sign, unwrap
Public Key Object; RSA 2048 bits
  label:      RSA-0001
  ID:         0001
  Usage:      encrypt, verify, wrap
+ pkcs11-tool --module /usr/lib64/libsofthsm2.so --slot 0x428e562b --login --pin userpin -k --key-type EC:secp384r1 -a EC-0003 -d 0003
Key pair generated:
Private Key Object; EC
  label:      EC-0003
  ID:         0003
  Usage:      decrypt, sign, unwrap, derive
Public Key Object; EC  EC_POINT 384 bits
  EC_POINT:   046104d8840668fd9bdc55db075ae37de3349f405d60e2749f91660271188ea485c2da367ad230499725218b4a43fab616141765d6b50535ee1b871916da1eaabfae3f15c883665fbcfb7a267dcabbef8577800cf5840bb77f490aec8ba4337ded16f1
  EC_PARAMS:  06052b81040022
  label:      EC-0003
  ID:         0003
  Usage:      encrypt, verify, wrap, derive

$ pip install -e .
$ pytest tests
======================== test session starts ========================
platform linux -- Python 3.9.2, pytest-6.2.3, py-1.10.0, pluggy-0.13.1
rootdir: /cryptography_engine, inifile:
collected 8 items

tests/test_engine.py ........                                 [100%]

===================== 8 passed in 0.87 seconds ======================

Usage:

Get OpenSSL ENGINE reference

# you may need to set OPENSSL_ENGINES environment var if using
# 3rd party wheels, e.g., from PyPI.
# export OPENSSL_ENGINES=/usr/lib64/engines-1.1

import cryptography_engine.engine as engine

# get an engine object

'''engine_init(<name_of_token>, <list of ENGINE_ctrl_cmd_string-tuples (cmd_name, arg)>
The ENGINE_ctrl_cmd_string tuples depend on the OpenSSL engine.
'''

e = engine.engine_init('pkcs11', [('PIN', my_token_pin)])

Asymmetric Key Operations

These keys are cryptography key objects and can be used similarly.

import cryptography_engine.engine as engine
e = engine.engine_init('pkcs11', ('PIN', my_token_pin))

# get a private key
'''engine_load_private_key(engine, label_of_private_key)'''
prvkey = engine.engine_load_private_key(e, alias)

# get a public key

'''engine_load_public_key(engine, label_of_public_key)'''
pubkey = engine.engine_load_public_key(e, alias)

Utility Functions

cryptography methods need arguments of hashes and padding; these utility module-level functions simplify calling cryptography methods.

# AsymmetricPadding instances
engine_padding_pkcs1() # gets a PKCS1v15 instance
engine_padding_oaep(mgf1_hash_name, oaep_md_name, label) # gets an OAEP instance
engine_padding_pss(hash_name, salt_length) # gets a PSS instance

# HashAlgorithm instances
engine_hashes(hash_name) # gets a HashAlgorithm instance

# EllipticCurveSignatureAlgorithm
ecdsa_with_hash(hash_name) # gets a ECDSA instance

Object-Oriented Interfaces

Use engine keys just like cryptography key objects:

# RSA Signing/Verification
padding = engine.engine_padding_pkcs1() #IS-A AsymmetricPadding
algorithm = engine.engine_hashes('sha256') #IS-A HashAlgorithm
signature = prvkey.sign(data, padding, algorithm)

# raise InvalidSignature exception if verification fails
pubkey.verify(signature, data, padding, algorithm)

# RSA_PSS
padding = engine.engine_padding_pss('sha256', 32)
algorithm = engine.engine_hashes('sha256')
signature = prvkey.sign(data, padding, algorithm)
pubkey.verify(signature, data, padding, algorithm)

# EC Signing/Verification
algorithm = engine.ecdsa_with_hash('sha256')
signature = prvkey.sign(data, algorithm)
pubkey.verify(signature, data, algorithm)

# Encryption/Decryption
padding = engine.engine_padding_pkcs1()
ciphertext = pubkey.encrypt(plaintext, padding)
recoveredtext = prvkey.decrypt(ciphertext, padding)

padding = engine.engine_padding_oaep('sha256', 'sha256')
ciphertext = pubkey.encrypt(plaintext, padding)
recoveredtext = prvkey.decrypt(ciphertext, padding)

Low-level Functions

These execute engine functions directly and don't use cryptography's object-oriented interfaces. They use raw cffi EVP_PKEY objects such as the internal _evp_pkey attr of cryptography OpenSSL-backed key objects.

For the low-level functions algorithm is the name of the hash("sha1", "sha256" etc) and padding is a tuple consisting of an int and padding-specific options.

  • algorithm: hash_name: str #"sha1" "sha256" "sha384" "sha512" prepended with "pre:" for pre-hashed data
  • padding: tuple,:
    • PKCS1v15: (1,)
    • PSS: (6, salt_length: int)
    • OAEP: (4, mgf1_md_name: str, oaep_md_name: str)

Sign/Verify Data

import cryptography_engine.engine as engine

# get a pubkey/prvkey from engine...
# using cffi EVP_PKEY* keys, so access _evp_pkey attr

signature = engine.engine_sign(prvkey._evp_pkey, data, "sha256", (1,))
signature = engine.engine_sign(prvkey._evp_pkey, data, "pre:sha256", (6, -1))
signature = engine.engine_sign(prvkey._evp_pkey, data, "sha384", (6, -2))
# -1 - OpenSSL special value - use hash length
# -2 - OpenSSL special value - maximal salt length

assert engine.engine_verify(pubkey._evp_pkey, signature, data, algorithm, padding)

# returns True/False if verification succeeds

# data/signature: bytes
#
# algorithm: str sha1|sha256|sha384|sha512
#     hash used for digesting data
#     prepend algorithm  with 'pre:' if data is prehashed like cryptography's Prehashed class
#     i.e., pre:sha1|pre:sha256|pre:sha384|pre:sha512
#
# padding: tuple
#     RSASSA_PKCS1v15: 1 == engine.RSAPadding.RSA_PKCS1_PADDING
#         (1, )
#     RSASS_PSS: 6 == engine.RSAPadding.RSA_PKCS1_PSS_PADDING
#         (6, 32)
#         (6, -1)
#         (6, -2)

Encryption/Decryption

import cryptography_engine.engine as engine

# get a pubkey/prvkey from engine...
# using cffi EVP_PKEY* keys, so access _evp_pkey attr

# padding = (1, )
# or
# padding = (4, 'sha256', 'sha256')

ciphertext = engine.engine_encrypt(pubkey._evp_pkey, plaintext, padding)
recovered = engine.engine_decrypt(prvkey._evp_pkey, ciphertext, padding)
assert recovered == plaintext

# plaintext/ciphertext: bytes
#
# padding: tuple
#     RSAES_PKCS1v15: 1 == engine.RSAPadding.RSA_PKCS1_PADDING
#         (1, )
#
#     RSAES_OAEP: 4 == engine.RSAPadding.RSA_PKCS1_OAEP_PADDING
#         (4, 'sha256', 'sha256')

About

Python 3 pyca/cryptography wrappers for OpenSSL ENGINE operations

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

pFad - Phonifier reborn

Pfad - The Proxy pFad © 2024 Your Company Name. All rights reserved.





Check this box to remove all script contents from the fetched content.



Check this box to remove all images from the fetched content.


Check this box to remove all CSS styles from the fetched content.


Check this box to keep images inefficiently compressed and original size.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy