Skip to main content

Integrated security scheme for curve25519.

Project description

EDISS - Curve25519 Security Scheme

Repository: https://gitee.com/origamizyt/ediss.git

Like ECIES (Elliptic-curve integrated encryption scheme), EDISS (Edwards-curve integrated security scheme) provides public interfaces for key agreement, message authentication, digital signature and symmetric encryption using curve25519.

Installation

This module is available via pip:

$ pip install ediss

You can also clone the repository and install yourself:

$ git clone https://gitee.com/origamizyt/ediss.git
$ cd ediss
$ python setup.py install

If you want to use the source code, you should download the cryptography module as a dependency.

$ pip install cryptography

Basic Usage

For the most basic usage, the public apis are defined in the EdsScheme class. Use the generate static method to initialize schemes with generated keys. Use the privateKey and publicKey attributes to access keys.

>>> from ediss import EdsScheme
>>> es1 = EdsScheme.generate()
>>> es2 = EdsScheme.generate()

For private and public keys, you can create an key export using the exportKey, exportJson and exportBinary method. Each of them receives an optional password as the material to derive the key used for wrapping.

>>> es1.privateKey.exportKey() # no wrapping
{'salt': None, 'x25519': b'...', 'ed25519': b'...'}
>>> es1.publicKey.exportJson()
'{"salt": null, "x25519": "...", "ed25519": "..."}'
>>> es2.publicKey.exportBinary()
b'...'
>>> es2.privateKey.exportKey(b'password') # PBKDF2 + AES
{'salt': b'...', 'x25519': b'...', 'ed25519': b'...'}

NOTE: The key export is incompatible with other serialization formats, such as DER or PEM.

To receive public keys from peer, use the corresponding receiveKey, receiveJson, and receiveBinary methods. If you specified password during key export, you need to specify it as a parameter during receiving too.

>>> es2.receiveBinary(es1.exportBinary())
>>> es1.receiveJson(es2.exportJson(b'MyPassword'), b'MyPassword')

NOTE: You cannot receive public key more than once. Attempts to call receiving methods twice will raise the RemoteKeyExists error.

After receiving the remote keys, the signature and encipherment methods should now be available.

NOTE: To be more accurate, the sign and decrypt method is always available, as they only uses the private key.

Use the sharedSecret property to acquire the negotiated secret between two schemes:

>>> es1.sharedSecret == es2.sharedSecret
True

You can use the shared secret to perform HMAC or other symmetric operations. To sign a message, simply use the sign method. Call verify on the other side to verify the message. The generated signature is 64 bytes long.

>>> data = b'my secret message'
>>> signature = es1.sign(data)
>>> es2.verify(data, signature)
True
>>> es2.verify(data, b'We are under attack!')
False

To encrypt the message, use the encrypt method and decrypt via the decrypt method. The enciphered length is the original length + 80.

>>> message = es2.encrypt(b'dark secrets')
>>> es1.decrypt(message)
b'dark secrets'
>>> from ediss import Error
>>> try:
...     es1.decrypt(b'We are under attack!')
... except Error as e:
...     print('malformed!')
...
malformed!

NOTE: Actually, the method raises a ediss.cipher.MalformedCiphertext error, which is a subclass of ediss.Error.

More Usage

Local scheme

To use EDISS locally rather than remotely, use the LocalScheme class.

>>> from ediss import LocalScheme
>>> s = LocalScheme.generate()

The public apis are the same as EdsScheme without key receiving methods. The only difference is that the verify and decrypt method now works on signature and ciphertext generated by yourself rather than the other side.

To load schemes from private key exports, use the fromPrivateKey, fromPrivateJson and fromPrivateBinary static methods.

>>> s2 = LocalScheme.fromPrivateKey(s.privateKey.exportKey())
>>> s.privateKey.exportBinary() == s2.privateKey.exportBinary()
True

NOTE: If you want to store the scheme in your local disk, make sure you encrypt the keys properly.

Incremental signers / verifiers

If your data is too large to sign in one chunk, you can use the getSigner method to acquire an incremental signer.

>>> from ediss import EdsScheme
>>> e = EdsScheme.generate()
>>> s = e.getSigner()
>>> s.update(b'A chunk of data')
>>> s.update(b'Another chunk of data')
>>> signature = s.finalize()

Incremental verifiers are also available:

>>> e2 = EdsScheme.generate()
>>> e2.receiveKey(e.exportKey())
>>> v = e2.getVerifier()
>>> v.update(b'A chunk of data')
>>> v.update(b'Another chunk of data')
>>> v.finalize(signature)
True

These two methods also work on LocalScheme.

Socket patching

As most users take advantage of this module to secure their socket connections, there's an special submodule called ediss.patch for you to conveniently wrap your socket with the security scheme.

Their are four patch approaches as listed below:

Method Name Method Description
PmHmac Use shared secret to generate mac code, send along with message
PmSign Use ed25519 to generate digital signature, send along with message
PmCiph Use shared secret to encrypt the message
PmFull PmSign combined with PmCiph

To patch your socket, simply pass it as an argument to SocketPatch. Specify one method as the second argument. Call the negotiate method to perform key agreement:

Client:

>>> from ediss.patch import *
>>> import socket
>>> s = socket.socket()
>>> # initialize the socket
>>> s = SocketPatch(s, PatchMethod.PmSign)
>>> s.negotiate(True)

Server:

>>> from ediss.patch import *
>>> import socket
>>> s = socket.socket()
>>> # initializes the socket
>>> c = SocketPatch(s.accept()[0], PatchMethod.PmSign)
>>> c.negotiate(False)

NOTE: You certainly can specify true for server and false for client, as long as they are different.

Now you can use the send and recv method with patch enabled. Make sure you catches the PacketDropped exception when unauthorized packet is received.

s.send(b'some data to be signed')
try:
    d = s.recv(1024)
    print(d)
except PacketDropped:
    print('received unauthorized packet')

Only send and recv are patched. Other attribute acquisition requests are directly propagated to the socket object itself.

Mechanism

The curve25519 consists of two different deriviations - x25519 and ed25519. Each of the private and public keys contains two components - the x25519 key and ed25519 key. The x25519 key is used for key agreement, symmetric encryption, while the ed25519 key is used for EdDSA (Edwards-curve Digital Signature Algorithm).

Key agreement

The x25519 diffie-hellman is similar with ECDH (Elliptic-curve Diffie-Hellman), when two parties calculates the same shared secret according to the base point and their private keys. After agreeing with the same key, the module then derives a new key using the CONCATKDF-SHA512 algorithm specified in the NIST document.

Message Encipherment

As curve25519 does not provide a encryption scheme, the module uses AES-256-GCM to encrypt the message. The symmetric key is derived using HKDF-SHA512 with the shared secret. As the shared secret generated by the keys is a constant value, it does not provide enough forward secrecy. To solve this, the module uses ephemeral keys, which means every time when a message is encrypted, a new random key is generated and performed DH with remote key. Then the public bytes of the ephemeral key is sent with the message and negotiates with the remote private key to produce the same shared secret. As the HKDF-SHA512 algorithm uses a random salt, the message has two random elements, making it difficult to crack. The encrypted message is 80 bytes longer than the plain text.

EphemeralKey HKDFSalt GcmNonce Ciphertext GcmTag Total
32 bytes 16 bytes 16 bytes N bytes 16 bytes 80+N bytes

NOTE: This mechanism does NOT prevent you from MITM attacks. You need to certificate your server.

Digital Signature

The ed25519 curve provides a signature scheme called EdDSA (Edwards-curve Digital Signature Algorithm). The module signs the SHA-384 result of the message, producing a signature of 64 bytes. To crack the signature you'll need to find an efficient way to solve the DLP (Discrete Logarithm Problem) on curve25519.

Backend

This module uses the pyca/cryptography module as backend. It is a package designed to expose cryptographic primitives and recipes to Python developers.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

ediss-1.0.0.tar.gz (13.4 kB view details)

Uploaded Source

Built Distribution

ediss-1.0.0-py3-none-any.whl (12.1 kB view details)

Uploaded Python 3

File details

Details for the file ediss-1.0.0.tar.gz.

File metadata

  • Download URL: ediss-1.0.0.tar.gz
  • Upload date:
  • Size: 13.4 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

Hashes for ediss-1.0.0.tar.gz
Algorithm Hash digest
SHA256 4d1147141d3672251d4e559f8dfe147bda126cd06226b96ce6775c0441bacccf
MD5 7fcfbac5f25fd57d416c53d44b641d07
BLAKE2b-256 399606532a4b596c82d6cd7178ad215771816bf598280b357acd0721c5e4da20

See more details on using hashes here.

File details

Details for the file ediss-1.0.0-py3-none-any.whl.

File metadata

  • Download URL: ediss-1.0.0-py3-none-any.whl
  • Upload date:
  • Size: 12.1 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

Hashes for ediss-1.0.0-py3-none-any.whl
Algorithm Hash digest
SHA256 5ba1622627986eeb728cfdbe275aed85873bafc7e9db3b94cdc579c00d5d2697
MD5 7954c59ee7558829faa477fec1c8f93d
BLAKE2b-256 f0ab8a758c0a1319447cbb70f67f8e453bb9788578425c7d2e55924f55cf7129

See more details on using hashes here.

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page