aboutsummaryrefslogtreecommitdiff
path: root/python
diff options
context:
space:
mode:
authorHubert Chathi <hubert@uhoreg.ca>2019-04-08 17:19:47 -0400
committerHubert Chathi <hubert@uhoreg.ca>2019-04-08 17:19:47 -0400
commit74e9300daf0b5537749d5bbe6500281ba19d6e88 (patch)
tree4a1d2645268b2c2ed7294d4892e7724fa04d68d8 /python
parentebc156e7c272e08e375c3e704651b179541e078b (diff)
add python bindings for PK signing
Diffstat (limited to 'python')
-rw-r--r--python/olm/__init__.py4
-rw-r--r--python/olm/pk.py108
-rw-r--r--python/tests/pk_test.py15
3 files changed, 124 insertions, 3 deletions
diff --git a/python/olm/__init__.py b/python/olm/__init__.py
index 7b7423b..1168886 100644
--- a/python/olm/__init__.py
+++ b/python/olm/__init__.py
@@ -40,6 +40,8 @@ from .pk import (
PkMessage,
PkEncryption,
PkDecryption,
+ PkSigning,
PkEncryptionError,
- PkDecryptionError
+ PkDecryptionError,
+ PkSigningError
)
diff --git a/python/olm/pk.py b/python/olm/pk.py
index b67d5a4..6c91b98 100644
--- a/python/olm/pk.py
+++ b/python/olm/pk.py
@@ -17,7 +17,8 @@
This module contains bindings to the PK part of the Olm library.
It contains two classes PkDecryption and PkEncryption that are used to
-establish an encrypted communication channel using public key encryption.
+establish an encrypted communication channel using public key encryption,
+as well as a class PkSigning that is used to sign a message.
Examples:
>>> decryption = PkDecryption()
@@ -25,6 +26,10 @@ Examples:
>>> plaintext = "It's a secret to everybody."
>>> message = encryption.encrypt(plaintext)
>>> decrypted_plaintext = decryption.decrypt(message)
+ >>> seed = PkSigning.generate_seed()
+ >>> signing = PkSigning(seed)
+ >>> signature = signing.sign(plaintext)
+ >>> ed25519_verify(signing.public_key, plaintext, signature)
"""
@@ -45,6 +50,10 @@ class PkDecryptionError(Exception):
"""libolm Pk decryption exception."""
+class PkSigningError(Exception):
+ """libolm Pk signing exception."""
+
+
def _clear_pk_encryption(pk_struct):
lib.olm_clear_pk_encryption(pk_struct)
@@ -344,3 +353,100 @@ class PkDecryption(object):
lib.memset(plaintext_buffer, 0, max_plaintext_length)
return bytes_to_native_str(plaintext)
+
+
+def _clear_pk_signing(pk_struct):
+ lib.olm_clear_pk_signing(pk_struct)
+
+
+class PkSigning(object):
+ """PkSigning class.
+
+ Signs messages using public key cryptography.
+
+ Attributes:
+ public_key (str): The public key of the PkSigning object, can be
+ shared and used to verify using Utility.ed25519_verify.
+
+ """
+
+ def __init__(self, seed):
+ # type: (bytes) -> None
+ """Create a new signing object.
+
+ Args:
+ seed(bytes): the seed to use as the private key for signing. The
+ seed must have the same length as the seeds generated by
+ PkSigning.generate_seed().
+ """
+ if not seed:
+ raise ValueError("seed can't be empty")
+
+ self._buf = ffi.new("char[]", lib.olm_pk_signing_size())
+ self._pk_signing = lib.olm_pk_signing(self._buf)
+ track_for_finalization(self, self._pk_signing, _clear_pk_signing)
+
+ seed_buffer = ffi.new("char[]", seed)
+
+ pubkey_length = lib.olm_pk_signing_public_key_length()
+ pubkey_buffer = ffi.new("char[]", pubkey_length)
+
+ ret = lib.olm_pk_signing_key_from_seed(
+ self._pk_signing,
+ pubkey_buffer, pubkey_length,
+ seed_buffer, len(seed)
+ )
+
+ # zero out copies of the seed
+ lib.memset(seed_buffer, 0, len(seed))
+
+ self._check_error(ret)
+
+ self.public_key = bytes_to_native_str(
+ ffi.unpack(pubkey_buffer, pubkey_length)
+ )
+
+ def _check_error(self, ret):
+ # type: (int) -> None
+ if ret != lib.olm_error():
+ return
+
+ last_error = bytes_to_native_str(
+ ffi.string(lib.olm_pk_signing_last_error(self._pk_signing)))
+
+ raise PkSigningError(last_error)
+
+ @classmethod
+ def generate_seed(cls):
+ # type: () -> bytes
+ """Generate a random seed.
+ """
+ random_length = lib.olm_pk_signing_seed_length()
+ random = URANDOM(random_length)
+
+ return random
+
+ def sign(self, message):
+ # type: (AnyStr) -> str
+ """Sign a message
+
+ Returns the signature.
+ Raises PkSigningError on failure.
+
+ Args:
+ message(str): the message to sign.
+ """
+ bytes_message = to_bytearray(message)
+
+ signature_length = lib.olm_pk_signature_length()
+ signature_buffer = ffi.new("char[]", signature_length)
+
+ ret = lib.olm_pk_sign(
+ self._pk_signing,
+ ffi.from_buffer(bytes_message), len(bytes_message),
+ signature_buffer, signature_length)
+ self._check_error(ret)
+
+ return bytes_to_native_str(
+ ffi.unpack(signature_buffer, signature_length)
+ )
diff --git a/python/tests/pk_test.py b/python/tests/pk_test.py
index f2aa147..096b6a8 100644
--- a/python/tests/pk_test.py
+++ b/python/tests/pk_test.py
@@ -1,6 +1,12 @@
import pytest
-from olm import PkDecryption, PkDecryptionError, PkEncryption
+from olm import (
+ ed25519_verify,
+ PkDecryption,
+ PkDecryptionError,
+ PkEncryption,
+ PkSigning
+)
class TestClass(object):
@@ -47,3 +53,10 @@ class TestClass(object):
with pytest.raises(PkDecryptionError):
PkDecryption.from_pickle(pickle, "Not secret")
+
+ def test_signing(self):
+ seed = PkSigning.generate_seed()
+ signing = PkSigning(seed)
+ message = "This statement is true"
+ signature = signing.sign(message)
+ ed25519_verify(signing.public_key, message, signature)