A modern asymmetric encryption scheme.
Project description
Psypher - A modern asymmetric encryption scheme.
Psypher is a modern cryptography module providing high-level security recipes with simple interfaces. It is built for securing communication through insecure channels.
Installation
This module is available via PyPI:
$ pip install psypher
If you want to use the source code directly, make sure you install the cryptography
dependency.
$ pip install cryptography
Basic Usage
All the interface Psypher provides is accessible through the Scheme
interface. Use the default
static method to obtain an instance of the default scheme (curve25519-chacha20poly1305
).
>>> from psypher import Scheme
>>> s1, s2 = Scheme.default(), Scheme.default()
>>> s1.__class__.__name__
'Curve25519ChaCha20Poly1305Scheme'
The private and public key is accessible with the privateKey
and publicKey
properties. The basic usage of these keys are shown below.
# key export (also suitable for public keys)
key1 = s1.privateKey.export() # bytes
key2 = s2.privateKey.exportJson() # str
# key import (also suitable for public keys)
psypher.secret.Curve25519PrivateKey.importKey(key1)
psypher.secret.Curve25519PrivateKey.importJson(key2)
# encrypted key export (private keys only)
key1 = s1.privateKey.secureExport(b'password')
key2 = s2.privateKey.secureExportJson(b'password')
# encrypted key import (private keys only)
psypher.secret.Curve25519PrivateKey.importKey(key1, b'password')
psypher.secret.Curve25519PrivateKey.importJson(key2, b'password')
# key fingerprint (public keys only)
print(s1.publicKey.digest)
When using encrypted key export, the default behaviours is to derive the wrapping key from the password using
PBKDF2
. However, you can specifyderive=False
to disable this kind of behaviour and to use your material as key directly.
IPublicKey.digest
is a cached property, so it might not behave as you expect it to be. See the Advanced Usage / Cache Mode to learn more.
The export
, exportJson
methods is also defined on the scheme as a shortcut to the public key. Use the receive
and receiveJson
methods to receive remote key from peers:
>>> s1.receive(s2.export())
>>> s2.receiveJson(s1.exportJson())
Use the shareSecret
property to calculate the negotiated shared secret. This property is CACHED, that means it only evaluates once. For detailed information about caching, please navigate to the Advanced Usage / Cache Mode section.
>>> s1.sharedSecret == s2.sharedSecret
True
To generate the digital signature of specific message, use the sign
method. Call verify
on the other side to verify the message. You can only verify messages signed by your peer. The signature generated is deterministic.
>>> data = b'My telephone number is 123456!'
>>> signature = s1.sign(data)
>>> s2.verify(data, signature)
True
>>> s2.verify(b'My telephone number is 654321!', signature)
False
If you just want to check the integrity of your message therefore don't require such cryptographical strength of your signature, or if you need a shorter signature value, the integritySign
method may suits you. It uses HMAC to sign the message, producing only 32 bytes output. Likewise, the integrityVerify
method can be used to verify this signature:
>>> data = b'My telephone number is 123456!'
>>> signature = s1.integritySign(data)
>>> s2.integrityVerify(data, signature)
True
>>> s2.integrityVerify(b'My telephone number is 654321!', signature)
False
To encrypt your message, use the encrypt
method. Call decrypt
on the other side to decrypt your message. You can only decrypt messages encrypted by your peer. The ciphertext is different each time you call encrypt
, even if you are encrypting the same message.
>>> data = b'The darkest secret lies here.'
>>> ciphertext = s2.encrypt(data)
>>> s1.decrypt(ciphertext) == data
True
>>> from psypher.errors import InvalidCiphertext
>>> try:
... s1.decrypt(b'This is absolutely illegal')
... except InvalidCiphertext:
... pass
Advanced Usage
Below are some complicated usages of this module beyond the normal usage.
Cache Mode
The cache mode is enabled by default, which means certain methods or property will only be calculated once and cached. Cached items includes IPublicKey.digest
and <KeyPairClass>.sharedSecret
. You can disable caching globally with the following statements:
>>> from psypher import cache
>>> cache.setenabled(False)
You can access the cache object through the unbound version of the method or property. Here are some usages:
# query
from psypher.secret import IPublicKey
IPublicKey.digest.fget.enabled
# partially disable
IPublicKey.digest.fget.enabled = False
EccKeyPair.sharedSecret.fget.enabled = False
# clear cache for all instances
Curve25519KeyPair.sharedSecret.fget.clearCache()
If you disabled the cache globally, the
enabled
property will returnFalse
on every instance, even if you set it toTrue
.
Customize Scheme
The scheme object is located in the psypher.cipher
module. A scheme is consisted of two parts - the key pair and the symmetric encryptor. You could customize these parts.
The module provides two built-in schemes: Curve15519ChaCha20Poly1305Scheme
, which is the default, and Secp256k1AesGcmScheme
, which is recommended to use in commercial circumstances. These schemes produces the ciphertext with similar structure:
Curve25519ChaCha20Poly1305
Input: plain text (X bytes)
Output:
EphKey | HkdfSalt | AeadNonce | Ciphertext | AeadTag | Total |
---|---|---|---|---|---|
32 bytes | 16 bytes | 12 bytes | X bytes | 16 bytes | 76+X bytes |
Secp256k1AesGcm:
Input: plain text (X bytes)
Output:
EphKey | HkdfSalt | AeadNonce | Ciphertext | AeadTag | Total |
---|---|---|---|---|---|
65 bytes | 16 bytes | 12 bytes | X bytes | 16 bytes | 109+X bytes |
These schemes can be found in the psypher.scheme
module:
>>> from psypher.scheme import Secp256k1AesGcmScheme
>>> s1 = Secp256k1AesGcmScheme.generate()
You can also customize the schemes:
>>> from psypher.cipher import AesGcmEncryptor
>>> from psypher.secret import Curve25519KeyPair
>>> from psypher.scheme import Scheme
>>> s1 = Scheme(Curve25519KeyPair.generate(), AesGcmEncryptor)
To fully build your own customized scheme, you may want to inherit from the IKeyPair
class. You must implement the IPrivateKey
and IPublicKey
interfaces too. The IEncryptor
interface however, is a static interface, only containing static methods. For more details, please see the source code.
Support & License
This module is built on the pyca/cryptography
library. See their Github Repository.
This software is licensed under the MIT License. For more information, see the License Text.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
File details
Details for the file psypher-1.0.0.tar.gz
.
File metadata
- Download URL: psypher-1.0.0.tar.gz
- Upload date:
- Size: 12.3 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/3.3.0 pkginfo/1.6.1 requests/2.24.0 setuptools/51.1.2 requests-toolbelt/0.9.1 tqdm/4.56.0 CPython/3.8.5
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | 17f956c9c03fb2d441bb716a14b108302ebf03b66c58dc7bebfda8d98fdbdbcc |
|
MD5 | 9731b216a8dcfad7a18701ecf8a0d056 |
|
BLAKE2b-256 | 28d832de33d68213320eaca5543a093e960dbe4dca6e28f634a4ecc320191eca |
File details
Details for the file psypher-1.0.0-py3-none-any.whl
.
File metadata
- Download URL: psypher-1.0.0-py3-none-any.whl
- Upload date:
- Size: 11.8 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/3.3.0 pkginfo/1.6.1 requests/2.24.0 setuptools/51.1.2 requests-toolbelt/0.9.1 tqdm/4.56.0 CPython/3.8.5
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | 5a8695ecdf23476bc20de36db8b1be1d22b15721d91cfe93f4a7d4426749ec4a |
|
MD5 | c81dc33be06406982832625610bd2875 |
|
BLAKE2b-256 | f59c8e1f9f4e9c02d659a7572e513cc242096bf9ea053aa906641314957f6751 |