Package: ediss
EDISS - Curve25519 Security SchemeRepository:https://gitee.com/origamizyt/ediss.gitLike 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.InstallationThis module is available via pip:$ pip install edissYou can also clone the repository and install yourself:$ git clone https://gitee.com/origamizyt/ediss.git
$ cd ediss
$ python setup.py installIf you want to use the source code, you should download the cryptography module as a dependency.$ pip install cryptographyBasic UsageFor the most basic usage, the public apis are defined in theEdsSchemeclass. Use thegeneratestatic method to initialize schemes with generated keys. Use theprivateKeyandpublicKeyattributes to access keys.>>>fromedissimportEdsScheme>>>es1=EdsScheme.generate()>>>es2=EdsScheme.generate()For private and public keys, you can create an key export using theexportKey,exportJsonandexportBinarymethod. 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 correspondingreceiveKey,receiveJson, andreceiveBinarymethods. 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 theRemoteKeyExistserror.After receiving the remote keys, the signature and encipherment methods should now be available.NOTE: To be more accurate, thesignanddecryptmethod is always available, as they only uses the private key.Use thesharedSecretproperty to acquire the negotiated secret between two schemes:>>>es1.sharedSecret==es2.sharedSecretTrueYou can use the shared secret to perform HMAC or other symmetric operations. To sign a message, simply use thesignmethod. Callverifyon 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!')FalseTo encrypt the message, use theencryptmethod and decrypt via thedecryptmethod. The enciphered length is the original length + 80.>>>message=es2.encrypt(b'dark secrets')>>>es1.decrypt(message)b'dark secrets'>>>fromedissimportError>>>try:...es1.decrypt(b'We are under attack!')...exceptErrorase:...print('malformed!')...malformed!NOTE: Actually, the method raises aediss.cipher.MalformedCiphertexterror, which is a subclass ofediss.Error.More UsageLocal schemeTo use EDISS locally rather than remotely, use theLocalSchemeclass.>>>fromedissimportLocalScheme>>>s=LocalScheme.generate()The public apis are the same asEdsSchemewithout key receiving methods. The only difference is that theverifyanddecryptmethod now works on signature and ciphertext generated by yourself rather than the other side.To load schemes from private key exports, use thefromPrivateKey,fromPrivateJsonandfromPrivateBinarystatic methods.>>>s2=LocalScheme.fromPrivateKey(s.privateKey.exportKey())>>>s.privateKey.exportBinary()==s2.privateKey.exportBinary()TrueNOTE: If you want to store the scheme in your local disk, make sure you encrypt the keys properly.Incremental signers / verifiersIf your data is too large to sign in one chunk, you can use thegetSignermethod to acquire an incremental signer.>>>fromedissimportEdsScheme>>>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)TrueThese two methods also work onLocalScheme.Socket patchingAs most users take advantage of this module to secure their socket connections, there's an special submodule calledediss.patchfor you to conveniently wrap your socket with the security scheme.Their are four patch approaches as listed below:Method NameMethod DescriptionPmHmacUse shared secret to generate mac code, send along with messagePmSignUse ed25519 to generate digital signature, send along with messagePmCiphUse shared secret to encrypt the messagePmFullPmSign combined with PmCiphTo patch your socket, simply pass it as an argument toSocketPatch. Specify one method as the second argument. Call thenegotiatemethod to perform key agreement:Client:>>>fromediss.patchimport*>>>importsocket>>>s=socket.socket()>>># initialize the socket>>>s=SocketPatch(s,PatchMethod.PmSign)>>>s.negotiate(True)Server:>>>fromediss.patchimport*>>>importsocket>>>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 thesendandrecvmethod with patch enabled. Make sure you catches thePacketDroppedexception when unauthorized packet is received.s.send(b'some data to be signed')try:d=s.recv(1024)print(d)exceptPacketDropped:print('received unauthorized packet')Onlysendandrecvare patched. Other attribute acquisition requests are directly propagated to the socket object itself.MechanismThe 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 agreementThe 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 theCONCATKDF-SHA512algorithm specified in the NIST document.Message EnciphermentAs curve25519 does not provide a encryption scheme, the module usesAES-256-GCMto encrypt the message. The symmetric key is derived usingHKDF-SHA512with 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 theHKDF-SHA512algorithm 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.EphemeralKeyHKDFSaltGcmNonceCiphertextGcmTagTotal32 bytes16 bytes16 bytesN bytes16 bytes80+N bytesNOTE: This mechanism doesNOTprevent you from MITM attacks. You need to certificate your server.Digital SignatureThe 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.BackendThis module uses thepyca/cryptographymodule as backend. It is a package designed to expose cryptographic primitives and recipes to Python developers.