Python3 bindings for YACA 14/161314/8
authorLukasz Pawelczyk <l.pawelczyk@samsung.com>
Fri, 17 Nov 2017 13:51:46 +0000 (14:51 +0100)
committerLukasz Pawelczyk <l.pawelczyk@samsung.com>
Thu, 5 Apr 2018 10:39:36 +0000 (12:39 +0200)
Change-Id: Ia7e7bf329d6b2e87c6587481dfe5c870ef482e54

CMakeLists.txt
packaging/yaca.spec
python/CMakeLists.txt [new file with mode: 0644]
python/run_all_tests.py [new file with mode: 0755]
python/yaca/__init__.py [new file with mode: 0755]
python/yaca/error.py [new file with mode: 0644]
python/yaca/library.py [new file with mode: 0644]
python/yaca/tests.py [new file with mode: 0644]

index 8596ea7..51d28e7 100644 (file)
@@ -74,6 +74,7 @@ ENDIF()
 SET(API_FOLDER ${PROJECT_SOURCE_DIR}/api/yaca)
 SET(EXAMPLES_FOLDER ${PROJECT_SOURCE_DIR}/examples)
 SET(SRC_FOLDER ${PROJECT_SOURCE_DIR}/src)
+SET(PYTHON_FOLDER ${PROJECT_SOURCE_DIR}/python)
 
 IF(NOT DEFINED LIB_INSTALL_DIR)
        SET(LIB_INSTALL_DIR "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}")
@@ -99,3 +100,6 @@ CONFIGURE_FILE(packaging/yaca.manifest.in yaca.manifest @ONLY)
 
 ADD_SUBDIRECTORY(${SRC_FOLDER})
 ADD_SUBDIRECTORY(${EXAMPLES_FOLDER})
+IF(NOT WITHOUT_PYTHON)
+       ADD_SUBDIRECTORY(${PYTHON_FOLDER})
+ENDIF(NOT WITHOUT_PYTHON)
index a1484d1..5135774 100644 (file)
@@ -6,6 +6,7 @@ License:            Apache-2.0
 Group:              Security/Other
 Summary:            Yet Another Crypto API
 BuildRequires:      cmake
+BuildRequires:      python3 >= 3.4
 BuildRequires:      pkgconfig(capi-base-common)
 BuildRequires:      pkgconfig(openssl)
 Requires(post):     /sbin/ldconfig
@@ -35,6 +36,7 @@ make -k %{?jobs:-j%jobs}
 
 %install
 %make_install
+%py3_compile %{buildroot}/%{python3_sitelib}
 
 %clean
 rm -rf %{buildroot}
@@ -65,3 +67,15 @@ The package provides Yet Another Crypto API example files.
 %files examples
 %{_bindir}/yaca-example*
 %{_datadir}/%{name}/examples
+
+## Python3 Package ############################################################
+%package -n python3-yaca
+Summary:        Yet Another Crypto API Python3 bindings
+Group:          Security/Other
+Requires:       yaca = %{version}-%{release}
+
+%description -n python3-yaca
+The package provides Yet Another Crypto API bindings for Python3.
+
+%files -n python3-yaca
+%{python3_sitelib}/%{name}
diff --git a/python/CMakeLists.txt b/python/CMakeLists.txt
new file mode 100644 (file)
index 0000000..bb65b0c
--- /dev/null
@@ -0,0 +1,8 @@
+FIND_PACKAGE(PythonInterp 3.4 REQUIRED)
+
+EXECUTE_PROCESS(COMMAND ${PYTHON_EXECUTABLE} -c "from sys import stdout; from distutils import sysconfig; stdout.write(sysconfig.get_python_lib())" OUTPUT_VARIABLE PYTHON_INSTALL_DIR)
+MESSAGE(STATUS "Python install dir is ${PYTHON_INSTALL_DIR}")
+MESSAGE(STATUS "Python version is ${PYTHON_VERSION_STRING}")
+
+FILE(GLOB yaca_SRCS yaca/*.py)
+INSTALL (FILES ${yaca_SRCS} DESTINATION ${PYTHON_INSTALL_DIR}/${PROJECT_NAME})
diff --git a/python/run_all_tests.py b/python/run_all_tests.py
new file mode 100755 (executable)
index 0000000..4877820
--- /dev/null
@@ -0,0 +1,23 @@
+#!/usr/bin/env python3
+
+# Copyright (c) 2017-2018 Samsung Electronics Co., Ltd All Rights Reserved
+#
+# Contact: Lukasz Pawelczyk <l.pawelczyk@samsung.com>
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License
+
+
+import yaca
+import yaca.tests
+
+yaca.tests.run_all_tests()
diff --git a/python/yaca/__init__.py b/python/yaca/__init__.py
new file mode 100755 (executable)
index 0000000..38e8648
--- /dev/null
@@ -0,0 +1,817 @@
+#!/usr/bin/env python3
+
+# Copyright (c) 2017-2018 Samsung Electronics Co., Ltd All Rights Reserved
+#
+# Contact: Lukasz Pawelczyk <l.pawelczyk@samsung.com>
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License
+
+
+"""
+Python3 bindings for YACA.
+
+Usage is almost the same as in the C API. All the functions that made
+sense in Python were implemented. Memory allocations and functions for
+getting length of the buffers were ommited as all those things are
+handled automatically for both input and output.
+
+All the parameters for strings/data expect python's bytes type. All
+the parameters are named the same as in the C API and their meaning is
+exactly the same.
+
+The major exception being encrypt/decrypt update where second
+parameter can have 2 meanings. This is only used for CCM_AAD. See
+examples.
+
+Some parameters now have default values for ease of use.
+
+For details please refer to the C API doxygen documentation.
+
+For examples see tests/examples in yaca.tests module.
+"""
+
+import enum as _enum
+import ctypes as _ctypes
+import yaca.library
+from yaca.error import *
+del yaca.error
+
+# Initialization
+
+_lib = yaca.library.get_yaca()
+del yaca.library
+
+
+# Helpers
+
+def _get_char_param_nullify_if_zero(param):
+    return None if len(param) == 0 else param
+
+
+def _context_get_output_length(ctx, input_length):
+    output_length = _ctypes.c_size_t()
+    _lib.yaca_context_get_output_length(ctx,
+                                        input_length,
+                                        _ctypes.byref(output_length))
+    return output_length.value
+
+
+# Types
+
+class Context():
+    def __init__(self, ptr):
+        if not isinstance(ptr, _ctypes.c_void_p):
+            raise TypeError('Invalid type')
+        self._as_parameter_ = ptr
+
+    def __del__(self):
+        _lib.yaca_context_destroy(self._as_parameter_)
+
+
+class Key():
+    def __init__(self, ptr):
+        if not isinstance(ptr, _ctypes.c_void_p):
+            raise TypeError('Invalid type')
+        self._as_parameter_ = ptr
+
+    def __del__(self):
+        _lib.yaca_key_destroy(self._as_parameter_)
+
+    def __repr__(self):
+        if self._as_parameter_.value is None:
+            return '<yaca.Key: KEY_NULL>'
+        return '<yaca.Key: ' + str(self.get_type()) + ', ' + \
+            str(self.get_bit_length()) + ' bits at ' + str(hex(id(self))) + '>'
+
+    def get_type(self):
+        return key_get_type(self)
+
+    def get_bit_length(self):
+        return key_get_bit_length(self)
+
+
+KEY_NULL = Key(_ctypes.c_void_p())
+
+
+# Enums
+
+@_enum.unique
+class KEY_FORMAT(_enum.Enum):
+    DEFAULT = 0
+    PKCS8 = 1
+
+
+@_enum.unique
+class KEY_FILE_FORMAT(_enum.Enum):
+    RAW = 0
+    BASE64 = 1
+    PEM = 2
+    DER = 3
+
+
+@_enum.unique
+class KEY_TYPE(_enum.Enum):
+    SYMMETRIC = 0
+    DES = 1
+    IV = 2
+    RSA_PUB = 3
+    RSA_PRIV = 4
+    DSA_PUB = 5
+    DSA_PRIV = 6
+    DH_PUB = 7
+    DH_PRIV = 8
+    EC_PUB = 9
+    EC_PRIV = 10
+    DSA_PARAMS = 11
+    DH_PARAMS = 12
+    EC_PARAMS = 13
+
+
+class KEY_BIT_LENGTH(_enum.IntEnum):
+    IV_64BIT = 64
+    IV_128BIT = 128
+    UNSAFE_8BIT = 8
+    UNSAFE_40BIT = 40
+    UNSAFE_64BIT = 64
+    UNSAFE_80BIT = 80
+    UNSAFE_128BIT = 128
+    L192BIT = 192
+    L256BIT = 256
+    L512BIT = 512
+    L1024BIT = 1024
+    L2048BIT = 2048
+    L3072BIT = 3072
+    L4096BIT = 4096
+
+
+@_enum.unique
+class KEY_BIT_LENGTH_EC(_enum.IntEnum):
+    PRIME192V1 = 0x300000C0
+    PRIME256V1 = 0x30000100
+    SECP256K1 = 0x31200100
+    SECP384R1 = 0x31100180
+    SECP521R1 = 0x31100209
+
+
+KEY_LENGTH_DH_GENERATOR_2 = 0x10000000
+KEY_LENGTH_DH_GENERATOR_5 = 0x11000000
+
+
+@_enum.unique
+class KEY_BIT_LENGTH_DH_RFC(_enum.IntEnum):
+    L1024_160 = 0x20000400
+    L2048_224 = 0x21000800
+    L2048_256 = 0x22000800
+
+
+@_enum.unique
+class DIGEST_ALGORITHM(_enum.Enum):
+    MD5 = 0
+    SHA1 = 1
+    SHA224 = 2
+    SHA256 = 3
+    SHA384 = 4
+    SHA512 = 5
+
+
+@_enum.unique
+class ENCRYPT_ALGORITHM(_enum.Enum):
+    AES = 0
+    UNSAFE_DES = 1
+    UNSAFE_TRIPPLE_DES_2TDEA = 2
+    TRIPPLE_DES_3TDEA = 3
+    UNSAFE_RC2 = 4
+    UNSAFE_RC4 = 5
+    CAST5 = 6
+
+
+@_enum.unique
+class BLOCK_CIPHER_MODE(_enum.Enum):
+    NONE = 0
+    ECB = 1
+    CTR = 2
+    CBC = 3
+    GCM = 4
+    CFB = 5
+    CFB1 = 6
+    CFB8 = 7
+    OFB = 8
+    CCM = 9
+    WRAP = 10
+
+
+@_enum.unique
+class PROPERTY(_enum.Enum):
+    PADDING = 0
+    GCM_AAD = 1
+    GCM_TAG = 2
+    GCM_TAG_LEN = 3
+    CCM_AAD = 4
+    CCM_TAG = 5
+    CCM_TAG_LEN = 6
+    RC2_EFFECTIVE_KEY_BITS = 7
+
+
+@_enum.unique
+class PADDING(_enum.Enum):
+    NONE = 0
+    X931 = 1
+    PKCS1 = 2
+    PKCS1_PSS = 3
+    PKCS1_OAEP = 4
+    PKCS1_SSLV23 = 5
+    PKCS7 = 6
+
+
+@_enum.unique
+class KDF(_enum.Enum):
+    X942 = 0
+    X962 = 1
+
+
+# Implementation crypto
+
+def initialize():
+    """Initializes the library. Must be called before any other crypto
+    function. Should be called once in each thread that uses yaca."""
+    _lib.yaca_initialize()
+
+
+def cleanup():
+    """Cleans up the library.
+    Must be called before exiting the thread that called yaca_initialize()."""
+    _lib.yaca_cleanup()
+
+
+def memcmp(first, second, length):
+    """Safely compares first length bytes of two buffers."""
+    l = _ctypes.c_size_t(length)
+    return _lib.yaca_memcmp(first, second, l)
+
+
+def random_bytes(length):
+    """Generates random data."""
+    data = _ctypes.create_string_buffer(length)
+    _lib.yaca_randomize_bytes(data, length)
+    return bytes(data)
+
+
+def context_set_property(ctx, prop, prop_val):
+    """Sets the non-standard context properties.
+    Can only be called on an initialized context."""
+    if prop == PROPERTY.PADDING:
+        value = _ctypes.c_int(prop_val.value)
+        value_length = _ctypes.sizeof(value)
+        _lib.yaca_context_set_property(ctx,
+                                       prop.value,
+                                       _ctypes.byref(value),
+                                       value_length)
+    elif (prop == PROPERTY.GCM_AAD) or (prop == PROPERTY.CCM_AAD) or \
+         (prop == PROPERTY.GCM_TAG) or (prop == PROPERTY.CCM_TAG):
+        value = prop_val
+        value_length = len(prop_val)
+        _lib.yaca_context_set_property(ctx, prop.value,
+                                       value, value_length)
+    elif (prop == PROPERTY.GCM_TAG_LEN) or (prop == PROPERTY.CCM_TAG_LEN) or \
+         (prop == PROPERTY.RC2_EFFECTIVE_KEY_BITS):
+        value = _ctypes.c_size_t(prop_val)
+        value_length = _ctypes.sizeof(value)
+        _lib.yaca_context_set_property(
+            ctx, prop.value, _ctypes.byref(value), value_length)
+    else:
+        raise InvalidParameterError('Wrong property passed')
+
+
+def context_get_property(ctx, prop):
+    """Returns the non-standard context properties.
+    Can only be called on an initialized context."""
+    value = _ctypes.c_void_p()
+    value_length = _ctypes.c_size_t()
+    _lib.yaca_context_get_property(ctx, prop.value, _ctypes.byref(value),
+                                   _ctypes.byref(value_length))
+    if prop == PROPERTY.PADDING:
+        value_cast = _ctypes.cast(value, _ctypes.POINTER(_ctypes.c_int))
+        value_proper = value_cast.contents.value
+        assert value_length.value == _ctypes.sizeof(value_cast.contents)
+    elif (prop == PROPERTY.GCM_AAD) or (prop == PROPERTY.CCM_AAD) or \
+         (prop == PROPERTY.GCM_TAG) or (prop == PROPERTY.CCM_TAG):
+        value_cast = _ctypes.cast(value, _ctypes.POINTER(_ctypes.c_char))
+        value_proper = value_cast[:value_length.value]
+        assert value_length.value == len(value_proper)
+    elif (prop == PROPERTY.GCM_TAG_LEN) or \
+         (prop == PROPERTY.CCM_TAG_LEN) or \
+         (prop == PROPERTY.RC2_EFFECTIVE_KEY_BITS):
+        value_cast = _ctypes.cast(value, _ctypes.POINTER(_ctypes.c_size_t))
+        value_proper = value_cast.contents.value
+        assert value_length.value == _ctypes.sizeof(value_cast.contents)
+    else:
+        raise InvalidParameterError('Wrong property passed')
+    _lib.yaca_free(value)
+    return value_proper
+
+
+# Implementation key
+
+def key_get_type(key):
+    """Gets key's type"""
+    key_type = _ctypes.c_int()
+    _lib.yaca_key_get_type(key, _ctypes.byref(key_type))
+    return KEY_TYPE(key_type.value)
+
+
+def key_get_bit_length(key):
+    """Gets key's length (in bits)."""
+    key_bit_length = _ctypes.c_size_t()
+    _lib.yaca_key_get_bit_length(key, _ctypes.byref(key_bit_length))
+    return key_bit_length.value
+
+
+def key_import(data, key_type=KEY_TYPE.SYMMETRIC, password=b''):
+    """Imports a key or key generation parameters."""
+    key = _ctypes.c_void_p()
+    _lib.yaca_key_import(key_type.value, _ctypes.c_char_p(password),
+                         data, len(data), _ctypes.byref(key))
+    return Key(key)
+
+
+def key_export(key, key_file_fmt=KEY_FILE_FORMAT.BASE64,
+               key_fmt=KEY_FORMAT.DEFAULT, password=b''):
+    """Exports a key or key generation parameters to arbitrary format."""
+    data = _ctypes.POINTER(_ctypes.c_char)()
+    data_length = _ctypes.c_size_t()
+    _lib.yaca_key_export(key, key_fmt.value, key_file_fmt.value,
+                         _ctypes.c_char_p(password), _ctypes.byref(data),
+                         _ctypes.byref(data_length))
+    data_bytes = data[:data_length.value]
+    _lib.yaca_free(data)
+    return data_bytes
+
+
+def key_generate(key_type=KEY_TYPE.SYMMETRIC,
+                 key_bit_length=KEY_BIT_LENGTH.L256BIT):
+    """Generates a secure key or key generation parameters
+    (or an Initialization Vector)."""
+    key = _ctypes.c_void_p()
+    _lib.yaca_key_generate(key_type.value, key_bit_length,
+                           _ctypes.byref(key))
+    return Key(key)
+
+
+def key_generate_from_parameters(params):
+    """Generates a secure private asymmetric key from parameters."""
+    prv_key = _ctypes.c_void_p()
+    _lib.yaca_key_generate_from_parameters(params,
+                                           _ctypes.byref(prv_key))
+    return Key(prv_key)
+
+
+def key_extract_public(prv_key):
+    """Extracts public key from a private one."""
+    pub_key = _ctypes.c_void_p()
+    _lib.yaca_key_extract_public(prv_key, _ctypes.byref(pub_key))
+    return Key(pub_key)
+
+
+def key_extract_parameters(key):
+    """Extracts parameters from a private or a public key."""
+    params = _ctypes.c_void_p()
+    _lib.yaca_key_extract_parameters(key, _ctypes.byref(params))
+    return Key(params)
+
+
+def key_derive_dh(prv_key, pub_key):
+    """Derives a shared secret using Diffie-Helmann or EC Diffie-Helmann
+    key exchange protocol."""
+    secret = _ctypes.POINTER(_ctypes.c_char)()
+    secret_length = _ctypes.c_size_t()
+    _lib.yaca_key_derive_dh(prv_key, pub_key, _ctypes.byref(secret),
+                            _ctypes.byref(secret_length))
+    secret_bytes = secret[:secret_length.value]
+    _lib.yaca_free(secret)
+    return secret_bytes
+
+
+def key_derive_kdf(secret, key_material_length, info=b'',
+                   kdf=KDF.X942, digest_algo=DIGEST_ALGORITHM.SHA256):
+    """Derives a key material from shared secret."""
+    info_param = _get_char_param_nullify_if_zero(info)
+    key_material = _ctypes.POINTER(_ctypes.c_char)()
+    _lib.yaca_key_derive_kdf(kdf.value, digest_algo.value,
+                             secret, len(secret),
+                             info_param, len(info), key_material_length,
+                             _ctypes.byref(key_material))
+    key_material_bytes = key_material[:key_material_length]
+    _lib.yaca_free(key_material)
+    return key_material_bytes
+
+
+def key_derive_pbkdf2(password, key_bit_length=KEY_BIT_LENGTH.L256BIT,
+                      salt=b'', digest_algo=DIGEST_ALGORITHM.SHA256,
+                      iterations=50000):
+    """Derives a key from user password (PKCS #5 a.k.a. pbkdf2 algorithm)."""
+    salt_param = _get_char_param_nullify_if_zero(salt)
+    key = _ctypes.c_void_p()
+    _lib.yaca_key_derive_pbkdf2(_ctypes.c_char_p(password), salt_param,
+                                len(salt), iterations, digest_algo.value,
+                                key_bit_length, _ctypes.byref(key))
+    return Key(key)
+
+
+# Implementation simple
+
+def simple_encrypt(sym_key, plaintext, encrypt_algo=ENCRYPT_ALGORITHM.AES,
+                   bcm=BLOCK_CIPHER_MODE.ECB, iv=KEY_NULL):
+    """Encrypts data using a symmetric cipher."""
+    plaintext_param = _get_char_param_nullify_if_zero(plaintext)
+    ciphertext = _ctypes.POINTER(_ctypes.c_char)()
+    ciphertext_length = _ctypes.c_size_t()
+    _lib.yaca_simple_encrypt(encrypt_algo.value, bcm.value, sym_key, iv,
+                             plaintext_param, len(plaintext),
+                             _ctypes.byref(ciphertext),
+                             _ctypes.byref(ciphertext_length))
+    ciphertext_bytes = ciphertext[:ciphertext_length.value]
+    _lib.yaca_free(ciphertext)
+    return ciphertext_bytes
+
+
+def simple_decrypt(sym_key, ciphertext, encrypt_algo=ENCRYPT_ALGORITHM.AES,
+                   bcm=BLOCK_CIPHER_MODE.ECB, iv=KEY_NULL):
+    """Decrypts data using a symmetric cipher."""
+    ciphertext_param = _get_char_param_nullify_if_zero(ciphertext)
+    plaintext = _ctypes.POINTER(_ctypes.c_char)()
+    plaintext_length = _ctypes.c_size_t()
+    _lib.yaca_simple_decrypt(encrypt_algo.value, bcm.value, sym_key, iv,
+                             ciphertext_param, len(ciphertext),
+                             _ctypes.byref(plaintext),
+                             _ctypes.byref(plaintext_length))
+    plaintext_bytes = plaintext[:plaintext_length.value]
+    _lib.yaca_free(plaintext)
+    return plaintext_bytes
+
+
+def simple_calculate_digest(message, digest_algo=DIGEST_ALGORITHM.SHA256):
+    """Calculates a digest of a message."""
+    message_param = _get_char_param_nullify_if_zero(message)
+    digest = _ctypes.POINTER(_ctypes.c_char)()
+    digest_length = _ctypes.c_size_t()
+    _lib.yaca_simple_calculate_digest(digest_algo.value, message_param,
+                                      len(message),
+                                      _ctypes.byref(digest),
+                                      _ctypes.byref(digest_length))
+    digest_bytes = digest[:digest_length.value]
+    _lib.yaca_free(digest)
+    return digest_bytes
+
+
+def simple_calculate_signature(prv_key, message,
+                               digest_algo=DIGEST_ALGORITHM.SHA256):
+    """Creates a signature using asymmetric private key."""
+    message_param = _get_char_param_nullify_if_zero(message)
+    signature = _ctypes.POINTER(_ctypes.c_char)()
+    signature_length = _ctypes.c_size_t()
+    _lib.yaca_simple_calculate_signature(digest_algo.value, prv_key,
+                                         message_param, len(message),
+                                         _ctypes.byref(signature),
+                                         _ctypes.byref(signature_length))
+    signature_bytes = signature[:signature_length.value]
+    _lib.yaca_free(signature)
+    return signature_bytes
+
+
+def simple_verify_signature(pub_key, message, signature,
+                            digest_algo=DIGEST_ALGORITHM.SHA256):
+    """Verifies a signature using asymmetric public key."""
+    return _lib.yaca_simple_verify_signature(digest_algo.value, pub_key,
+                                             message, len(message),
+                                             signature, len(signature))
+
+
+def simple_calculate_hmac(sym_key, message,
+                          digest_algo=DIGEST_ALGORITHM.SHA256):
+    """Calculates a HMAC of given message using symmetric key."""
+    message_param = _get_char_param_nullify_if_zero(message)
+    mac = _ctypes.POINTER(_ctypes.c_char)()
+    mac_length = _ctypes.c_size_t()
+    _lib.yaca_simple_calculate_hmac(digest_algo.value, sym_key,
+                                    message_param, len(message),
+                                    _ctypes.byref(mac),
+                                    _ctypes.byref(mac_length))
+    mac_bytes = mac[:mac_length.value]
+    _lib.yaca_free(mac)
+    return mac_bytes
+
+
+def simple_calculate_cmac(sym_key, message,
+                          encrypt_algo=ENCRYPT_ALGORITHM.AES):
+    """Calculates a CMAC of given message using symmetric key."""
+    message_param = _get_char_param_nullify_if_zero(message)
+    mac = _ctypes.POINTER(_ctypes.c_char)()
+    mac_length = _ctypes.c_size_t()
+    _lib.yaca_simple_calculate_cmac(encrypt_algo.value, sym_key,
+                                    message_param, len(message),
+                                    _ctypes.byref(mac),
+                                    _ctypes.byref(mac_length))
+    mac_bytes = mac[:mac_length.value]
+    _lib.yaca_free(mac)
+    return mac_bytes
+
+
+# Implementation digest
+
+def digest_initialize(digest_algo=DIGEST_ALGORITHM.SHA256):
+    """Initializes a digest context."""
+    ctx = _ctypes.c_void_p()
+    _lib.yaca_digest_initialize(_ctypes.byref(ctx), digest_algo.value)
+    return Context(ctx)
+
+
+def digest_update(ctx, message):
+    """Feeds the message into the message digest algorithm."""
+    _lib.yaca_digest_update(ctx, message, len(message))
+
+
+def digest_finalize(ctx):
+    """Calculates the final digest."""
+    output_length = _context_get_output_length(ctx, 0)
+    digest = _ctypes.create_string_buffer(output_length)
+    digest_length = _ctypes.c_size_t()
+    _lib.yaca_digest_finalize(ctx, digest, _ctypes.byref(digest_length))
+    return bytes(digest[:digest_length.value])
+
+
+# Implementation encrypt
+
+def encrypt_get_iv_bit_length(encrypt_algo, bcm, key_bin_length):
+    """Returns the recommended/default length of the Initialization Vector
+    for a given encryption configuration."""
+    iv_bit_length = _ctypes.c_size_t()
+    _lib.yaca_encrypt_get_iv_bit_length(encrypt_algo.value, bcm.value,
+                                        key_bin_length,
+                                        _ctypes.byref(iv_bit_length))
+    return iv_bit_length.value
+
+
+def encrypt_initialize(sym_key, encrypt_algo=ENCRYPT_ALGORITHM.AES,
+                       bcm=BLOCK_CIPHER_MODE.ECB, iv=KEY_NULL):
+    """Initializes an encryption context."""
+    ctx = _ctypes.c_void_p()
+    _lib.yaca_encrypt_initialize(_ctypes.byref(ctx), encrypt_algo.value,
+                                 bcm.value, sym_key, iv)
+    return Context(ctx)
+
+
+def encrypt_update(ctx, plaintext):
+    """Encrypts chunk of the data.
+    Alternatively plaintext can be the total length of the input (int).
+    This is used for CCM_AAD."""
+    if isinstance(plaintext, int):  # the case of using AAD in CCM
+        _lib.yaca_encrypt_update(ctx, None, plaintext, None,
+                                 _ctypes.byref(_ctypes.c_size_t()))
+        return
+
+    output_length = _context_get_output_length(ctx, len(plaintext))
+    ciphertext = _ctypes.create_string_buffer(output_length)
+    ciphertext_length = _ctypes.c_size_t()
+    _lib.yaca_encrypt_update(ctx, plaintext, len(plaintext),
+                             ciphertext, _ctypes.byref(ciphertext_length))
+    return bytes(ciphertext[:ciphertext_length.value])
+
+
+def encrypt_finalize(ctx):
+    """Encrypts the final chunk of the data."""
+    output_length = _context_get_output_length(ctx, 0)
+    ciphertext = _ctypes.create_string_buffer(output_length)
+    ciphertext_length = _ctypes.c_size_t()
+    _lib.yaca_encrypt_finalize(ctx, ciphertext,
+                               _ctypes.byref(ciphertext_length))
+    return bytes(ciphertext[:ciphertext_length.value])
+
+
+def decrypt_initialize(sym_key, encrypt_algo=ENCRYPT_ALGORITHM.AES,
+                       bcm=BLOCK_CIPHER_MODE.ECB, iv=KEY_NULL):
+    """Initializes an decryption context."""
+    ctx = _ctypes.c_void_p()
+    _lib.yaca_decrypt_initialize(_ctypes.byref(ctx), encrypt_algo.value,
+                                 bcm.value, sym_key, iv)
+    return Context(ctx)
+
+
+def decrypt_update(ctx, ciphertext):
+    """Decrypts chunk of the data.
+    Alternatively ciphertext can be the total length of the input (int).
+    This is used for CCM_AAD."""
+    if isinstance(ciphertext, int):  # the case of using AAD in CCM
+        _lib.yaca_decrypt_update(ctx, None, ciphertext, None,
+                                 _ctypes.byref(_ctypes.c_size_t()))
+        return
+
+    output_length = _context_get_output_length(ctx, len(ciphertext))
+    plaintext = _ctypes.create_string_buffer(output_length)
+    plaintext_length = _ctypes.c_size_t()
+    _lib.yaca_decrypt_update(ctx, ciphertext, len(ciphertext),
+                             plaintext, _ctypes.byref(plaintext_length))
+    return bytes(plaintext[:plaintext_length.value])
+
+
+def decrypt_finalize(ctx):
+    """Encrypts the final chunk of the data."""
+    output_length = _context_get_output_length(ctx, 0)
+    plaintext = _ctypes.create_string_buffer(output_length)
+    plaintext_length = _ctypes.c_size_t()
+    _lib.yaca_decrypt_finalize(ctx, plaintext,
+                               _ctypes.byref(plaintext_length))
+    return bytes(plaintext[:plaintext_length.value])
+
+
+# Implementation sign
+
+def sign_initialize(prv_key, digest_algo=DIGEST_ALGORITHM.SHA256):
+    """Initializes a signature context for asymmetric signatures."""
+    ctx = _ctypes.c_void_p()
+    _lib.yaca_sign_initialize(_ctypes.byref(ctx), digest_algo.value,
+                              prv_key)
+    return Context(ctx)
+
+
+def sign_initialize_hmac(sym_key, digest_algo=DIGEST_ALGORITHM.SHA256):
+    """Initializes a signature context for HMAC."""
+    ctx = _ctypes.c_void_p()
+    _lib.yaca_sign_initialize_hmac(_ctypes.byref(ctx),
+                                   digest_algo.value, sym_key)
+    return Context(ctx)
+
+
+def sign_initialize_cmac(sym_key, encrypt_algo=ENCRYPT_ALGORITHM.AES):
+    """Initializes a signature context for CMAC."""
+    ctx = _ctypes.c_void_p()
+    _lib.yaca_sign_initialize_cmac(_ctypes.byref(ctx),
+                                   encrypt_algo.value, sym_key)
+    return Context(ctx)
+
+
+def sign_update(ctx, message):
+    """Feeds the message into the digital signature or MAC algorithm."""
+    _lib.yaca_sign_update(ctx, message, len(message))
+
+
+def sign_finalize(ctx):
+    """Calculates the final signature or MAC."""
+    output_length = _context_get_output_length(ctx, 0)
+    signature = _ctypes.create_string_buffer(output_length)
+    signature_len = _ctypes.c_size_t()
+    _lib.yaca_sign_finalize(ctx, signature, _ctypes.byref(signature_len))
+    return bytes(signature[:signature_len.value])
+
+
+def verify_initialize(pub_key, digest_algo=DIGEST_ALGORITHM.SHA256):
+    """Initializes a signature verification context for asymmetric signatures.
+    """
+    ctx = _ctypes.c_void_p()
+    _lib.yaca_verify_initialize(_ctypes.byref(ctx), digest_algo.value,
+                                pub_key)
+    return Context(ctx)
+
+
+def verify_update(ctx, message):
+    """Feeds the message into the digital signature verification algorithm."""
+    _lib.yaca_verify_update(ctx, message, len(message))
+
+
+def verify_finalize(ctx, signature):
+    """Performs the verification."""
+    return _lib.yaca_verify_finalize(ctx, signature, len(signature))
+
+
+# Implementation seal
+
+def seal_initialize(pub_key, sym_key_bit_length=KEY_BIT_LENGTH.L256BIT,
+                    encrypt_algo=ENCRYPT_ALGORITHM.AES,
+                    bcm=BLOCK_CIPHER_MODE.ECB):
+    ctx = _ctypes.c_void_p()
+    sym_key = _ctypes.c_void_p()
+    iv = _ctypes.c_void_p()
+    _lib.yaca_seal_initialize(_ctypes.byref(ctx), pub_key,
+                              encrypt_algo.value, bcm.value,
+                              sym_key_bit_length, _ctypes.byref(sym_key),
+                              _ctypes.byref(iv))
+    return Context(ctx), Key(sym_key), Key(iv)
+
+
+def seal_update(ctx, plaintext):
+    """Encrypts piece of the data."""
+    output_length = _context_get_output_length(ctx, len(plaintext))
+    ciphertext = _ctypes.create_string_buffer(output_length)
+    ciphertext_length = _ctypes.c_size_t()
+    _lib.yaca_seal_update(ctx, plaintext, len(plaintext),
+                          ciphertext, _ctypes.byref(ciphertext_length))
+    return bytes(ciphertext[:ciphertext_length.value])
+
+
+def seal_finalize(ctx):
+    """Encrypts the final piece of the data."""
+    output_length = _context_get_output_length(ctx, 0)
+    ciphertext = _ctypes.create_string_buffer(output_length)
+    ciphertext_length = _ctypes.c_size_t()
+    _lib.yaca_seal_finalize(ctx, ciphertext,
+                            _ctypes.byref(ciphertext_length))
+    return bytes(ciphertext[:ciphertext_length.value])
+
+
+def open_initialize(prv_key, sym_key, iv=KEY_NULL,
+                    sym_key_bit_length=KEY_BIT_LENGTH.L256BIT,
+                    encrypt_algo=ENCRYPT_ALGORITHM.AES,
+                    bcm=BLOCK_CIPHER_MODE.ECB):
+    """Initializes an asymmetric decryption context."""
+    ctx = _ctypes.c_void_p()
+    _lib.yaca_open_initialize(_ctypes.byref(ctx), prv_key,
+                              encrypt_algo.value, bcm.value,
+                              sym_key_bit_length, sym_key, iv)
+    return Context(ctx)
+
+
+def open_update(ctx, ciphertext):
+    """Decrypts piece of the data."""
+    output_length = _context_get_output_length(ctx, len(ciphertext))
+    plaintext = _ctypes.create_string_buffer(output_length)
+    plaintext_length = _ctypes.c_size_t()
+    _lib.yaca_open_update(ctx, ciphertext, len(ciphertext),
+                          plaintext, _ctypes.byref(plaintext_length))
+    return bytes(plaintext[:plaintext_length.value])
+
+
+def open_finalize(ctx):
+    """Decrypts last chunk of sealed message."""
+    output_length = _context_get_output_length(ctx, 0)
+    plaintext = _ctypes.create_string_buffer(output_length)
+    plaintext_length = _ctypes.c_size_t()
+    _lib.yaca_open_finalize(ctx, plaintext,
+                            _ctypes.byref(plaintext_length))
+    return bytes(plaintext[:plaintext_length.value])
+
+
+# Implementation rsa
+
+def rsa_public_encrypt(pub_key, plaintext, padding=PADDING.PKCS1):
+    """Encrypts data using a RSA public key (low-level encrypt equivalent)."""
+    ciphertext = _ctypes.POINTER(_ctypes.c_char)()
+    ciphertext_length = _ctypes.c_size_t()
+    plaintext_param = _get_char_param_nullify_if_zero(plaintext)
+    _lib.yaca_rsa_public_encrypt(padding.value, pub_key, plaintext_param,
+                                 len(plaintext),
+                                 _ctypes.byref(ciphertext),
+                                 _ctypes.byref(ciphertext_length))
+    ciphertext_bytes = ciphertext[:ciphertext_length.value]
+    _lib.yaca_free(ciphertext)
+    return ciphertext_bytes
+
+
+def rsa_private_decrypt(prv_key, ciphertext, padding=PADDING.PKCS1):
+    """Decrypts data using a RSA private key (low-level decrypt equivalent)."""
+    plaintext = _ctypes.POINTER(_ctypes.c_char)()
+    plaintext_length = _ctypes.c_size_t()
+    ciphertext_param = _get_char_param_nullify_if_zero(ciphertext)
+    _lib.yaca_rsa_private_decrypt(padding.value, prv_key,
+                                  ciphertext_param, len(ciphertext),
+                                  _ctypes.byref(plaintext),
+                                  _ctypes.byref(plaintext_length))
+    plaintext_bytes = plaintext[:plaintext_length.value]
+    _lib.yaca_free(plaintext)
+    return plaintext_bytes
+
+
+def rsa_private_encrypt(prv_key, plaintext, padding=PADDING.PKCS1):
+    """Encrypts data using a RSA private key (low-level sign equivalent)."""
+    ciphertext = _ctypes.POINTER(_ctypes.c_char)()
+    ciphertext_length = _ctypes.c_size_t()
+    plaintext_param = _get_char_param_nullify_if_zero(plaintext)
+    _lib.yaca_rsa_private_encrypt(padding.value, prv_key,
+                                  plaintext_param, len(plaintext),
+                                  _ctypes.byref(ciphertext),
+                                  _ctypes.byref(ciphertext_length))
+    ciphertext_bytes = ciphertext[:ciphertext_length.value]
+    _lib.yaca_free(ciphertext)
+    return ciphertext_bytes
+
+
+def rsa_public_decrypt(pub_key, ciphertext, padding=PADDING.PKCS1):
+    """Decrypts data using a RSA public key (low-level verify equivalent)."""
+    plaintext = _ctypes.POINTER(_ctypes.c_char)()
+    plaintext_length = _ctypes.c_size_t()
+    ciphertext_param = _get_char_param_nullify_if_zero(ciphertext)
+    _lib.yaca_rsa_public_decrypt(padding.value, pub_key,
+                                 ciphertext_param, len(ciphertext),
+                                 _ctypes.byref(plaintext),
+                                 _ctypes.byref(plaintext_length))
+    plaintext_bytes = plaintext[:plaintext_length.value]
+    _lib.yaca_free(plaintext)
+    return plaintext_bytes
diff --git a/python/yaca/error.py b/python/yaca/error.py
new file mode 100644 (file)
index 0000000..8d691a8
--- /dev/null
@@ -0,0 +1,48 @@
+# Copyright (c) 2017-2018 Samsung Electronics Co., Ltd All Rights Reserved
+#
+# Contact: Lukasz Pawelczyk <l.pawelczyk@samsung.com>
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License
+
+
+class YacaError(Exception):
+    """Base class for YACA exceptions."""
+    pass
+
+
+class InvalidParameterError(YacaError):
+    """Invalid parameter exception"""
+    def __init__(self, message):
+        YacaError.__init__(self, message)
+        self.message = message
+
+
+class OutOfMemoryError(YacaError):
+    """Out of memory exception"""
+    def __init__(self, message):
+        YacaError.__init__(self, message)
+        self.message = message
+
+
+class InternalError(YacaError):
+    """Internal exception"""
+    def __init__(self, message):
+        YacaError.__init__(self, message)
+        self.message = message
+
+
+class InvalidPasswordError(YacaError):
+    """Invalid password exception"""
+    def __init__(self, message):
+        YacaError.__init__(self, message)
+        self.message = message
diff --git a/python/yaca/library.py b/python/yaca/library.py
new file mode 100644 (file)
index 0000000..5f68d64
--- /dev/null
@@ -0,0 +1,298 @@
+# Copyright (c) 2017-2018 Samsung Electronics Co., Ltd All Rights Reserved
+
+# Contact: Lukasz Pawelczyk <l.pawelczyk@samsung.com>
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License
+
+
+import ctypes as _ctypes
+import enum as _enum
+import yaca.error as _err
+
+
+@_enum.unique
+class _Error(_enum.Enum):
+    __TIZEN_YACA_BASE = -0x01E30000
+    NONE = 0
+    INVALID_PARAMETER = -22
+    OUT_OF_MEMORY = -12
+    INTERNAL = __TIZEN_YACA_BASE | 0x01
+    DATA_MISMATCH = __TIZEN_YACA_BASE | 0x02
+    INVALID_PASSWORD = __TIZEN_YACA_BASE | 0x03
+
+
+def _errcheck(ret, func, arguments):
+    if ret == _Error.NONE.value:
+        return True
+    elif ret == _Error.DATA_MISMATCH.value:
+        return False
+    elif ret == _Error.INVALID_PARAMETER.value:
+        raise _err.InvalidParameterError(
+            'Invalid Parameter error returned from YACA')
+    elif ret == _Error.OUT_OF_MEMORY.value:
+        raise _err.OutOfMemoryError('Out Of Memory error returned from YACA')
+    elif ret == _Error.INTERNAL.value:
+        raise _err.InternalError('Internal error returned from YACA')
+    elif ret == _Error.INVALID_PASSWORD.value:
+        raise _err.InvalidPasswordError(
+            'Invalid Password error returned from YACA')
+    else:
+        raise RuntimeError('Unknown error returned from YACA')
+
+
+def get_yaca():
+    """Get C library and set argtypes"""
+
+    lib = _ctypes.CDLL("libyaca.so.0")
+
+    # crypto
+    lib.yaca_initialize.argtypes = []
+    lib.yaca_initialize.errcheck = _errcheck
+    lib.yaca_cleanup.argtypes = []
+    lib.yaca_cleanup.restype = None
+    lib.yaca_malloc.argtypes = \
+        [_ctypes.c_size_t, _ctypes.POINTER(_ctypes.c_void_p)]
+    lib.yaca_malloc.errcheck = _errcheck
+    lib.yaca_zalloc.argtypes = \
+        [_ctypes.c_size_t, _ctypes.POINTER(_ctypes.c_void_p)]
+    lib.yaca_zalloc.errcheck = _errcheck
+    lib.yaca_realloc.argtypes = \
+        [_ctypes.c_size_t, _ctypes.POINTER(_ctypes.c_void_p)]
+    lib.yaca_realloc.errcheck = _errcheck
+    lib.yaca_free.argtypes = [_ctypes.c_void_p]
+    lib.yaca_free.restype = None
+    lib.yaca_memcmp.argtypes = \
+        [_ctypes.POINTER(_ctypes.c_char), _ctypes.POINTER(_ctypes.c_char),
+         _ctypes.c_size_t]
+    lib.yaca_memcmp.errcheck = _errcheck
+    lib.yaca_randomize_bytes.argtypes = \
+        [_ctypes.POINTER(_ctypes.c_char), _ctypes.c_size_t]
+    lib.yaca_randomize_bytes.errcheck = _errcheck
+    lib.yaca_context_set_property.argtypes = \
+        [_ctypes.c_void_p, _ctypes.c_int, _ctypes.c_void_p, _ctypes.c_size_t]
+    lib.yaca_context_set_property.errcheck = _errcheck
+    lib.yaca_context_get_property.argtypes = \
+        [_ctypes.c_void_p, _ctypes.c_int, _ctypes.POINTER(_ctypes.c_void_p),
+         _ctypes.POINTER(_ctypes.c_size_t)]
+    lib.yaca_context_get_property.errcheck = _errcheck
+    lib.yaca_context_get_output_length.argtypes = \
+        [_ctypes.c_void_p, _ctypes.c_size_t, _ctypes.POINTER(_ctypes.c_size_t)]
+    lib.yaca_context_get_output_length.errcheck = _errcheck
+    lib.yaca_context_destroy.argtypes = [_ctypes.c_void_p]
+    lib.yaca_context_destroy.restype = None
+
+    # simple
+    lib.yaca_simple_encrypt.argtypes = \
+        [_ctypes.c_int, _ctypes.c_int, _ctypes.c_void_p, _ctypes.c_void_p,
+         _ctypes.POINTER(_ctypes.c_char), _ctypes.c_size_t,
+         _ctypes.POINTER(_ctypes.POINTER(_ctypes.c_char)),
+         _ctypes.POINTER(_ctypes.c_size_t)]
+    lib.yaca_simple_encrypt.errcheck = _errcheck
+    lib.yaca_simple_decrypt.argtypes = \
+        [_ctypes.c_int, _ctypes.c_int, _ctypes.c_void_p, _ctypes.c_void_p,
+         _ctypes.POINTER(_ctypes.c_char), _ctypes.c_size_t,
+         _ctypes.POINTER(_ctypes.POINTER(_ctypes.c_char)),
+         _ctypes.POINTER(_ctypes.c_size_t)]
+    lib.yaca_simple_decrypt.errcheck = _errcheck
+    lib.yaca_simple_calculate_digest.argtypes = \
+        [_ctypes.c_int, _ctypes.POINTER(_ctypes.c_char), _ctypes.c_size_t,
+         _ctypes.POINTER(_ctypes.POINTER(_ctypes.c_char)),
+         _ctypes.POINTER(_ctypes.c_size_t)]
+    lib.yaca_simple_calculate_digest.errcheck = _errcheck
+    lib.yaca_simple_calculate_signature.argtypes = \
+        [_ctypes.c_int, _ctypes.c_void_p,
+         _ctypes.POINTER(_ctypes.c_char), _ctypes.c_size_t,
+         _ctypes.POINTER(_ctypes.POINTER(_ctypes.c_char)),
+         _ctypes.POINTER(_ctypes.c_size_t)]
+    lib.yaca_simple_calculate_signature.errcheck = _errcheck
+    lib.yaca_simple_verify_signature.argtypes = \
+        [_ctypes.c_int, _ctypes.c_void_p,
+         _ctypes.POINTER(_ctypes.c_char), _ctypes.c_size_t,
+         _ctypes.POINTER(_ctypes.c_char), _ctypes.c_size_t]
+    lib.yaca_simple_verify_signature.errcheck = _errcheck
+    lib.yaca_simple_calculate_hmac.argtypes = \
+        [_ctypes.c_int, _ctypes.c_void_p,
+         _ctypes.POINTER(_ctypes.c_char), _ctypes.c_size_t,
+         _ctypes.POINTER(_ctypes.POINTER(_ctypes.c_char)),
+         _ctypes.POINTER(_ctypes.c_size_t)]
+    lib.yaca_simple_calculate_hmac.errcheck = _errcheck
+    lib.yaca_simple_calculate_cmac.argtypes = \
+        [_ctypes.c_int, _ctypes.c_void_p,
+         _ctypes.POINTER(_ctypes.c_char), _ctypes.c_size_t,
+         _ctypes.POINTER(_ctypes.POINTER(_ctypes.c_char)),
+         _ctypes.POINTER(_ctypes.c_size_t)]
+    lib.yaca_simple_calculate_cmac.errcheck = _errcheck
+
+    # key
+    lib.yaca_key_get_type.argtypes = \
+        [_ctypes.c_void_p, _ctypes.POINTER(_ctypes.c_int)]
+    lib.yaca_key_get_type.errcheck = _errcheck
+    lib.yaca_key_get_bit_length.argtypes = \
+        [_ctypes.c_void_p, _ctypes.POINTER(_ctypes.c_size_t)]
+    lib.yaca_key_get_bit_length.errcheck = _errcheck
+    lib.yaca_key_import.argtypes = \
+        [_ctypes.c_int, _ctypes.c_char_p,
+         _ctypes.POINTER(_ctypes.c_char), _ctypes.c_size_t,
+         _ctypes.POINTER(_ctypes.c_void_p)]
+    lib.yaca_key_import.errcheck = _errcheck
+    lib.yaca_key_export.argtypes = \
+        [_ctypes.c_void_p, _ctypes.c_int, _ctypes.c_int, _ctypes.c_char_p,
+         _ctypes.POINTER(_ctypes.POINTER(_ctypes.c_char)),
+         _ctypes.POINTER(_ctypes.c_size_t)]
+    lib.yaca_key_export.errcheck = _errcheck
+    lib.yaca_key_generate.argtypes = \
+        [_ctypes.c_void_p, _ctypes.c_size_t, _ctypes.POINTER(_ctypes.c_void_p)]
+    lib.yaca_key_generate.errcheck = _errcheck
+    lib.yaca_key_generate_from_parameters.argtypes = \
+        [_ctypes.c_void_p, _ctypes.POINTER(_ctypes.c_void_p)]
+    lib.yaca_key_generate_from_parameters.errcheck = _errcheck
+    lib.yaca_key_extract_public.argtypes = \
+        [_ctypes.c_void_p, _ctypes.POINTER(_ctypes.c_void_p)]
+    lib.yaca_key_extract_public.errcheck = _errcheck
+    lib.yaca_key_extract_parameters.argtypes = \
+        [_ctypes.c_void_p, _ctypes.POINTER(_ctypes.c_void_p)]
+    lib.yaca_key_extract_parameters.errcheck = _errcheck
+    lib.yaca_key_derive_dh.argtypes = \
+        [_ctypes.c_void_p, _ctypes.c_void_p,
+         _ctypes.POINTER(_ctypes.POINTER(_ctypes.c_char)),
+         _ctypes.POINTER(_ctypes.c_size_t)]
+    lib.yaca_key_derive_dh.errcheck = _errcheck
+    lib.yaca_key_derive_kdf.argtypes = \
+        [_ctypes.c_int, _ctypes.c_int,
+         _ctypes.POINTER(_ctypes.c_char), _ctypes.c_size_t,
+         _ctypes.POINTER(_ctypes.c_char), _ctypes.c_size_t,
+         _ctypes.c_size_t, _ctypes.POINTER(_ctypes.POINTER(_ctypes.c_char))]
+    lib.yaca_key_derive_kdf.errcheck = _errcheck
+    lib.yaca_key_derive_pbkdf2.argtypes = \
+        [_ctypes.c_char_p, _ctypes.POINTER(_ctypes.c_char), _ctypes.c_size_t,
+         _ctypes.c_size_t, _ctypes.c_int,
+         _ctypes.c_size_t, _ctypes.POINTER(_ctypes.c_void_p)]
+    lib.yaca_key_derive_pbkdf2.errcheck = _errcheck
+    lib.yaca_key_destroy.argtypes = [_ctypes.c_void_p]
+    lib.yaca_key_destroy.restype = None
+
+    # digest
+    lib.yaca_digest_initialize.argtypes = \
+        [_ctypes.POINTER(_ctypes.c_void_p), _ctypes.c_int]
+    lib.yaca_digest_initialize.errcheck = _errcheck
+    lib.yaca_digest_update.argtypes = \
+        [_ctypes.c_void_p, _ctypes.POINTER(_ctypes.c_char), _ctypes.c_size_t]
+    lib.yaca_digest_update.errcheck = _errcheck
+    lib.yaca_digest_finalize.argtypes = \
+        [_ctypes.c_void_p,
+         _ctypes.POINTER(_ctypes.c_char), _ctypes.POINTER(_ctypes.c_size_t)]
+    lib.yaca_digest_finalize.errcheck = _errcheck
+
+    # encrypt
+    lib.yaca_encrypt_get_iv_bit_length.argtypes = \
+        [_ctypes.c_int, _ctypes.c_int, _ctypes.c_size_t,
+         _ctypes.POINTER(_ctypes.c_size_t)]
+    lib.yaca_encrypt_get_iv_bit_length.errcheck = _errcheck
+    lib.yaca_encrypt_initialize.argtypes = \
+        [_ctypes.POINTER(_ctypes.c_void_p), _ctypes.c_int, _ctypes.c_int,
+         _ctypes.c_void_p, _ctypes.c_void_p]
+    lib.yaca_encrypt_initialize.errcheck = _errcheck
+    lib.yaca_encrypt_update.argtypes = \
+        [_ctypes.c_void_p,
+         _ctypes.POINTER(_ctypes.c_char), _ctypes.c_size_t,
+         _ctypes.POINTER(_ctypes.c_char), _ctypes.POINTER(_ctypes.c_size_t)]
+    lib.yaca_encrypt_update.errcheck = _errcheck
+    lib.yaca_encrypt_finalize.argtypes = \
+        [_ctypes.c_void_p,
+         _ctypes.POINTER(_ctypes.c_char), _ctypes.POINTER(_ctypes.c_size_t)]
+    lib.yaca_encrypt_finalize.errcheck = _errcheck
+    lib.yaca_decrypt_initialize.argtypes = \
+        [_ctypes.POINTER(_ctypes.c_void_p), _ctypes.c_int, _ctypes.c_int,
+         _ctypes.c_void_p, _ctypes.c_void_p]
+    lib.yaca_decrypt_initialize.errcheck = _errcheck
+    lib.yaca_decrypt_update.argtypes = \
+        [_ctypes.c_void_p,
+         _ctypes.POINTER(_ctypes.c_char), _ctypes.c_size_t,
+         _ctypes.POINTER(_ctypes.c_char), _ctypes.POINTER(_ctypes.c_size_t)]
+    lib.yaca_decrypt_update.errcheck = _errcheck
+    lib.yaca_decrypt_finalize.argtypes = \
+        [_ctypes.c_void_p,
+         _ctypes.POINTER(_ctypes.c_char), _ctypes.POINTER(_ctypes.c_size_t)]
+    lib.yaca_decrypt_finalize.errcheck = _errcheck
+
+    # sign
+    lib.yaca_sign_initialize.argtypes = \
+        [_ctypes.POINTER(_ctypes.c_void_p), _ctypes.c_int, _ctypes.c_void_p]
+    lib.yaca_sign_initialize.errcheck = _errcheck
+    lib.yaca_sign_initialize_hmac.argtypes = \
+        [_ctypes.POINTER(_ctypes.c_void_p), _ctypes.c_int, _ctypes.c_void_p]
+    lib.yaca_sign_initialize_hmac.errcheck = _errcheck
+    lib.yaca_sign_initialize_cmac.argtypes = \
+        [_ctypes.POINTER(_ctypes.c_void_p), _ctypes.c_int, _ctypes.c_void_p]
+    lib.yaca_sign_initialize_cmac.errcheck = _errcheck
+    lib.yaca_sign_update.argtypes = \
+        [_ctypes.c_void_p, _ctypes.POINTER(_ctypes.c_char), _ctypes.c_size_t]
+    lib.yaca_sign_update.errcheck = _errcheck
+    lib.yaca_sign_finalize.argtypes = \
+        [_ctypes.c_void_p,
+         _ctypes.POINTER(_ctypes.c_char), _ctypes.POINTER(_ctypes.c_size_t)]
+    lib.yaca_sign_finalize.errcheck = _errcheck
+    lib.yaca_verify_initialize.argtypes = \
+        [_ctypes.POINTER(_ctypes.c_void_p), _ctypes.c_int, _ctypes.c_void_p]
+    lib.yaca_verify_initialize.errcheck = _errcheck
+    lib.yaca_verify_update.argtypes = \
+        [_ctypes.c_void_p, _ctypes.POINTER(_ctypes.c_char), _ctypes.c_size_t]
+    lib.yaca_verify_update.errcheck = _errcheck
+    lib.yaca_verify_finalize.argtypes = \
+        [_ctypes.c_void_p, _ctypes.POINTER(_ctypes.c_char), _ctypes.c_size_t]
+    lib.yaca_verify_finalize.errcheck = _errcheck
+
+    # seal
+    lib.yaca_seal_initialize.argtypes = \
+        [_ctypes.POINTER(_ctypes.c_void_p), _ctypes.c_void_p, _ctypes.c_int,
+         _ctypes.c_int, _ctypes.c_size_t, _ctypes.POINTER(_ctypes.c_void_p),
+         _ctypes.POINTER(_ctypes.c_void_p)]
+    lib.yaca_seal_initialize.errcheck = _errcheck
+    lib.yaca_seal_update.argtypes = \
+        [_ctypes.c_void_p, _ctypes.POINTER(_ctypes.c_char), _ctypes.c_size_t,
+         _ctypes.POINTER(_ctypes.c_char), _ctypes.POINTER(_ctypes.c_size_t)]
+    lib.yaca_seal_update.errcheck = _errcheck
+    lib.yaca_seal_finalize.argtypes = \
+        [_ctypes.c_void_p,
+         _ctypes.POINTER(_ctypes.c_char), _ctypes.POINTER(_ctypes.c_size_t)]
+    lib.yaca_seal_finalize.errcheck = _errcheck
+    lib.yaca_open_initialize.argtypes = \
+        [_ctypes.POINTER(_ctypes.c_void_p), _ctypes.c_void_p, _ctypes.c_int,
+         _ctypes.c_int, _ctypes.c_size_t, _ctypes.c_void_p, _ctypes.c_void_p]
+    lib.yaca_open_initialize.errcheck = _errcheck
+    lib.yaca_open_update.argtypes = \
+        [_ctypes.c_void_p,
+         _ctypes.POINTER(_ctypes.c_char), _ctypes.c_size_t,
+         _ctypes.POINTER(_ctypes.c_char), _ctypes.POINTER(_ctypes.c_size_t)]
+    lib.yaca_open_update.errcheck = _errcheck
+    lib.yaca_open_finalize.argtypes = \
+        [_ctypes.c_void_p,
+         _ctypes.POINTER(_ctypes.c_char), _ctypes.POINTER(_ctypes.c_size_t)]
+    lib.yaca_open_finalize.errcheck = _errcheck
+
+    # rsa
+    rsa_argtypes = \
+        [_ctypes.c_int, _ctypes.c_void_p,
+         _ctypes.POINTER(_ctypes.c_char), _ctypes.c_size_t,
+         _ctypes.POINTER(_ctypes.POINTER(_ctypes.c_char)),
+         _ctypes.POINTER(_ctypes.c_size_t)]
+    lib.yaca_rsa_public_encrypt.argtypes = rsa_argtypes
+    lib.yaca_rsa_public_encrypt.errcheck = _errcheck
+    lib.yaca_rsa_private_decrypt.argtypes = rsa_argtypes
+    lib.yaca_rsa_private_decrypt.errcheck = _errcheck
+    lib.yaca_rsa_private_encrypt.argtypes = rsa_argtypes
+    lib.yaca_rsa_private_encrypt.errcheck = _errcheck
+    lib.yaca_rsa_public_decrypt.argtypes = rsa_argtypes
+    lib.yaca_rsa_public_decrypt.errcheck = _errcheck
+
+    return lib
diff --git a/python/yaca/tests.py b/python/yaca/tests.py
new file mode 100644 (file)
index 0000000..a256419
--- /dev/null
@@ -0,0 +1,473 @@
+# Copyright (c) 2017-2018 Samsung Electronics Co., Ltd All Rights Reserved
+
+# Contact: Lukasz Pawelczyk <l.pawelczyk@samsung.com>
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License
+
+
+"""
+These tests are not to test yaca itself. They are more of a
+syntax test to see that no stupid mistakes has been made in the
+python binding. To check whether the code runs properly and
+returns expected things.
+
+They can also be used as examples.
+"""
+
+import yaca
+
+
+def split_into_parts(data, l):
+    return [data[i:i + l] for i in range(0, len(data), l)]
+
+
+msg = b'Lorem ipsum dolor sit amet, consectetuer adipiscing elit. \
+Donec hendrerit tempor tellus.  Donec pretium posuere tellus.  Proin \
+quam nisl, tincidunt et, mattis eget, convallis nec, purus.  Cum \
+sociis natoque penatibus et magnis dis parturient montes, nascetur \
+ridiculus mus.  Nulla posuere.  Donec vitae dolor.  Nullam tristique \
+diam non turpis.  Cras placerat accumsan nulla.  Nullam rutrum.  Nam \
+vestibulum accumsan nisl.'
+
+msg_parts = split_into_parts(msg, 5)
+
+
+def run_all_tests():
+    """Runs all YACA tests/examples. No exceptions means success."""
+
+    yaca.initialize()
+
+    crypto()
+    key_gen()
+    key_exp_imp()
+    key_derive()
+    simple()
+    digest()
+    encrypt_basic()
+    encrypt_rc2_property()
+    encrypt_gcm_property()
+    encrypt_ccm_property()
+    sign()
+    seal()
+    rsa()
+
+    yaca.cleanup()
+
+
+def crypto():
+
+    msg_whole = b''
+    for part in msg_parts:
+        msg_whole += part
+
+    assert yaca.memcmp(msg, msg_whole, len(msg))
+
+    rand_bytes = yaca.random_bytes(50)
+    assert len(rand_bytes) == 50
+
+
+def key_gen():
+
+    key_iv_64 = yaca.key_generate(yaca.KEY_TYPE.IV,
+                                  yaca.KEY_BIT_LENGTH.IV_64BIT)
+    assert key_iv_64.get_type() == yaca.KEY_TYPE.IV
+    assert key_iv_64.get_bit_length() == yaca.KEY_BIT_LENGTH.IV_64BIT
+
+    key_iv_128 = yaca.key_generate(yaca.KEY_TYPE.IV,
+                                   yaca.KEY_BIT_LENGTH.IV_128BIT)
+    assert key_iv_128.get_type() == yaca.KEY_TYPE.IV
+    assert key_iv_128.get_bit_length() == yaca.KEY_BIT_LENGTH.IV_128BIT
+
+    key_sym = yaca.key_generate()
+    assert key_sym.get_type() == yaca.KEY_TYPE.SYMMETRIC
+    assert key_sym.get_bit_length() == yaca.KEY_BIT_LENGTH.L256BIT
+
+    key_rsa_prv = yaca.key_generate(yaca.KEY_TYPE.RSA_PRIV,
+                                    yaca.KEY_BIT_LENGTH.L2048BIT)
+    assert key_rsa_prv.get_type() == yaca.KEY_TYPE.RSA_PRIV
+    assert key_rsa_prv.get_bit_length() == yaca.KEY_BIT_LENGTH.L2048BIT
+
+    key_rsa_pub = yaca.key_extract_public(key_rsa_prv)
+    assert key_rsa_pub.get_type() == yaca.KEY_TYPE.RSA_PUB
+    assert key_rsa_pub.get_bit_length() == yaca.KEY_BIT_LENGTH.L2048BIT
+
+    key_dsa_prv = yaca.key_generate(yaca.KEY_TYPE.DSA_PRIV,
+                                    yaca.KEY_BIT_LENGTH.L2048BIT)
+    assert key_dsa_prv.get_type() == yaca.KEY_TYPE.DSA_PRIV
+    assert key_dsa_prv.get_bit_length() == yaca.KEY_BIT_LENGTH.L2048BIT
+
+    key_dsa_pub = yaca.key_extract_public(key_dsa_prv)
+    assert key_dsa_pub.get_type() == yaca.KEY_TYPE.DSA_PUB
+    assert key_dsa_pub.get_bit_length() == yaca.KEY_BIT_LENGTH.L2048BIT
+
+    key_dh_prv = yaca.key_generate(yaca.KEY_TYPE.DH_PRIV,
+                                   yaca.KEY_BIT_LENGTH_DH_RFC.L2048_256)
+    assert key_dh_prv.get_type() == yaca.KEY_TYPE.DH_PRIV
+    assert key_dh_prv.get_bit_length() == 2048
+
+    key_dh_pub = yaca.key_extract_public(key_dh_prv)
+    assert key_dh_pub.get_type() == yaca.KEY_TYPE.DH_PUB
+    assert key_dh_pub.get_bit_length() == 2048
+
+    key_dh_params = yaca.key_extract_parameters(key_dh_prv)
+    key_dh_prv_2 = yaca.key_generate_from_parameters(key_dh_params)
+    assert key_dh_prv_2.get_type() == key_dh_prv.get_type()
+    assert key_dh_prv_2.get_bit_length() == key_dh_prv.get_bit_length()
+
+    key_dh_prv_3 = yaca.key_generate(yaca.KEY_TYPE.DH_PRIV,
+                                     yaca.KEY_LENGTH_DH_GENERATOR_5 | 256)
+    assert key_dh_prv_3.get_type() == yaca.KEY_TYPE.DH_PRIV
+    assert key_dh_prv_3.get_bit_length() == 256
+
+    key_ec_prv = yaca.key_generate(yaca.KEY_TYPE.EC_PRIV,
+                                   yaca.KEY_BIT_LENGTH_EC.PRIME256V1)
+    assert key_ec_prv.get_type() == yaca.KEY_TYPE.EC_PRIV
+    assert key_ec_prv.get_bit_length() == yaca.KEY_BIT_LENGTH_EC.PRIME256V1
+
+    key_ec_pub = yaca.key_extract_public(key_ec_prv)
+    assert key_ec_pub.get_type() == yaca.KEY_TYPE.EC_PUB
+    assert key_ec_pub.get_bit_length() == yaca.KEY_BIT_LENGTH_EC.PRIME256V1
+
+
+def key_exp_imp():
+    # prepare:
+    key_sym = yaca.key_generate()
+    key_rsa_prv = yaca.key_generate(yaca.KEY_TYPE.RSA_PRIV,
+                                    yaca.KEY_BIT_LENGTH.L2048BIT)
+    # end prepare
+
+    key_sym_exp = yaca.key_export(key_sym)
+    key_sym_imp = yaca.key_import(key_sym_exp)
+    assert key_sym.get_type() == key_sym_imp.get_type()
+    assert key_sym.get_bit_length() == key_sym_imp.get_bit_length()
+
+    key_rsa_prv_exp = yaca.key_export(key_rsa_prv, yaca.KEY_FILE_FORMAT.PEM)
+    key_rsa_prv_imp = yaca.key_import(key_rsa_prv_exp, yaca.KEY_TYPE.RSA_PRIV)
+    assert key_rsa_prv.get_type() == key_rsa_prv_imp.get_type()
+    assert key_rsa_prv.get_bit_length() == key_rsa_prv_imp.get_bit_length()
+
+    key_rsa_prv_exp = yaca.key_export(key_rsa_prv, yaca.KEY_FILE_FORMAT.PEM,
+                                      yaca.KEY_FORMAT.PKCS8, b"password")
+    key_rsa_prv_imp = yaca.key_import(key_rsa_prv_exp, yaca.KEY_TYPE.RSA_PRIV,
+                                      b"password")
+    assert key_rsa_prv.get_type() == key_rsa_prv_imp.get_type()
+    assert key_rsa_prv.get_bit_length() == key_rsa_prv_imp.get_bit_length()
+
+
+def key_derive():
+    # prepare:
+    key_dh_prv = yaca.key_generate(yaca.KEY_TYPE.DH_PRIV,
+                                   yaca.KEY_BIT_LENGTH_DH_RFC.L2048_256)
+    key_dh_pub = yaca.key_extract_public(key_dh_prv)
+    key_dh_params = yaca.key_extract_parameters(key_dh_prv)
+    key_dh_prv_2 = yaca.key_generate_from_parameters(key_dh_params)
+    key_dh_pub_2 = yaca.key_extract_public(key_dh_prv_2)
+    # end prepare
+
+    secret = yaca.key_derive_dh(key_dh_prv_2, key_dh_pub)
+    assert len(secret) == 256
+
+    secret_2 = yaca.key_derive_dh(key_dh_prv, key_dh_pub_2)
+    assert secret == secret_2
+
+    key_material = yaca.key_derive_kdf(secret, 128)
+    assert len(key_material) == 128
+
+    key_derived = yaca.key_derive_pbkdf2(b'password')
+    assert key_derived.get_type() == yaca.KEY_TYPE.SYMMETRIC
+    assert key_derived.get_bit_length() == yaca.KEY_BIT_LENGTH.L256BIT
+
+
+def simple():
+    # prepare:
+    key_sym = yaca.key_generate()
+    key_iv_128 = yaca.key_generate(yaca.KEY_TYPE.IV,
+                                   yaca.KEY_BIT_LENGTH.IV_128BIT)
+    key_rsa_prv = yaca.key_generate(yaca.KEY_TYPE.RSA_PRIV,
+                                    yaca.KEY_BIT_LENGTH.L2048BIT)
+    key_rsa_pub = yaca.key_extract_public(key_rsa_prv)
+    # end prepare
+
+    enc_simple = yaca.simple_encrypt(key_sym, msg,
+                                     yaca.ENCRYPT_ALGORITHM.AES,
+                                     yaca.BLOCK_CIPHER_MODE.CBC, key_iv_128)
+    dec_simple = yaca.simple_decrypt(key_sym, enc_simple,
+                                     yaca.ENCRYPT_ALGORITHM.AES,
+                                     yaca.BLOCK_CIPHER_MODE.CBC, key_iv_128)
+    assert msg == dec_simple
+
+    dgst_simple = yaca.simple_calculate_digest(msg,
+                                               yaca.DIGEST_ALGORITHM.SHA512)
+    assert len(dgst_simple) == 64
+
+    hmac_simple = yaca.simple_calculate_hmac(key_sym, msg,
+                                             yaca.DIGEST_ALGORITHM.SHA512)
+    assert len(hmac_simple) == 64
+
+    cmac_simple = yaca.simple_calculate_cmac(key_sym, msg,
+                                             yaca.ENCRYPT_ALGORITHM.AES)
+    assert len(cmac_simple) == 16
+
+    sig_simple = yaca.simple_calculate_signature(key_rsa_prv, msg,
+                                                 yaca.DIGEST_ALGORITHM.SHA512)
+    assert yaca.simple_verify_signature(key_rsa_pub, msg, sig_simple,
+                                        yaca.DIGEST_ALGORITHM.SHA512)
+
+
+def digest():
+    # prepare:
+    dgst_simple = yaca.simple_calculate_digest(msg,
+                                               yaca.DIGEST_ALGORITHM.SHA512)
+    # end prepare
+
+    ctx = yaca.digest_initialize(yaca.DIGEST_ALGORITHM.SHA512)
+    for part in msg_parts:
+        yaca.digest_update(ctx, part)
+    dgst = yaca.digest_finalize(ctx)
+
+    assert dgst == dgst_simple
+
+
+def encrypt_basic():
+    # prepare:
+    key_sym = yaca.key_generate()
+    key_iv_128 = yaca.key_generate(yaca.KEY_TYPE.IV,
+                                   yaca.KEY_BIT_LENGTH.IV_128BIT)
+    enc_simple = yaca.simple_encrypt(key_sym, msg,
+                                     yaca.ENCRYPT_ALGORITHM.AES,
+                                     yaca.BLOCK_CIPHER_MODE.CBC, key_iv_128)
+    # end prepare
+
+    len_iv = yaca.encrypt_get_iv_bit_length(yaca.ENCRYPT_ALGORITHM.AES,
+                                            yaca.BLOCK_CIPHER_MODE.CBC,
+                                            yaca.KEY_BIT_LENGTH.L256BIT)
+    assert len_iv == 128
+
+    ctx = yaca.encrypt_initialize(key_sym, bcm=yaca.BLOCK_CIPHER_MODE.CBC,
+                                  iv=key_iv_128)
+    enc = b''
+    for part in msg_parts:
+        enc += yaca.encrypt_update(ctx, part)
+    enc += yaca.encrypt_finalize(ctx)
+
+    assert enc == enc_simple
+
+    enc_parts = split_into_parts(enc, 5)
+
+    ctx = yaca.decrypt_initialize(key_sym, bcm=yaca.BLOCK_CIPHER_MODE.CBC,
+                                  iv=key_iv_128)
+    dec = b''
+    for part in enc_parts:
+        dec += yaca.decrypt_update(ctx, part)
+    dec += yaca.decrypt_finalize(ctx)
+
+    assert msg == dec
+
+
+def encrypt_rc2_property():
+    # prepare:
+    key_sym = yaca.key_generate()
+    # end prepare
+
+    len_iv = yaca.encrypt_get_iv_bit_length(yaca.ENCRYPT_ALGORITHM.UNSAFE_RC2,
+                                            yaca.BLOCK_CIPHER_MODE.ECB,
+                                            yaca.KEY_BIT_LENGTH.L256BIT)
+    assert len_iv == 0
+
+    ctx = yaca.encrypt_initialize(key_sym, yaca.ENCRYPT_ALGORITHM.UNSAFE_RC2,
+                                  yaca.BLOCK_CIPHER_MODE.ECB)
+    yaca.context_set_property(ctx, yaca.PROPERTY.RC2_EFFECTIVE_KEY_BITS, 192)
+    enc = b''
+    for part in msg_parts:
+        enc += yaca.encrypt_update(ctx, part)
+    enc += yaca.encrypt_finalize(ctx)
+
+    enc_parts = split_into_parts(enc, 5)
+
+    ctx = yaca.decrypt_initialize(key_sym, yaca.ENCRYPT_ALGORITHM.UNSAFE_RC2,
+                                  yaca.BLOCK_CIPHER_MODE.ECB)
+    yaca.context_set_property(ctx, yaca.PROPERTY.RC2_EFFECTIVE_KEY_BITS, 192)
+    dec = b''
+    for part in enc_parts:
+        dec += yaca.decrypt_update(ctx, part)
+    dec += yaca.decrypt_finalize(ctx)
+
+    assert msg == dec
+
+
+def encrypt_gcm_property():
+    # prepare:
+    key_sym = yaca.key_generate()
+    key_iv_128 = yaca.key_generate(yaca.KEY_TYPE.IV,
+                                   yaca.KEY_BIT_LENGTH.IV_128BIT)
+    # end prepare
+
+    tag_len = 16
+    aad = yaca.random_bytes(16)
+    ctx = yaca.encrypt_initialize(key_sym, bcm=yaca.BLOCK_CIPHER_MODE.GCM,
+                                  iv=key_iv_128)
+    yaca.context_set_property(ctx, yaca.PROPERTY.GCM_AAD, aad)
+    enc = b''
+    for part in msg_parts:
+        enc += yaca.encrypt_update(ctx, part)
+    enc += yaca.encrypt_finalize(ctx)
+    yaca.context_set_property(ctx, yaca.PROPERTY.GCM_TAG_LEN, tag_len)
+    tag = yaca.context_get_property(ctx, yaca.PROPERTY.GCM_TAG)
+    assert len(tag) == tag_len
+
+    enc_parts = split_into_parts(enc, 5)
+
+    ctx = yaca.decrypt_initialize(key_sym, bcm=yaca.BLOCK_CIPHER_MODE.GCM,
+                                  iv=key_iv_128)
+    yaca.context_set_property(ctx, yaca.PROPERTY.GCM_AAD, aad)
+    dec = b''
+    for part in enc_parts:
+        dec += yaca.decrypt_update(ctx, part)
+    yaca.context_set_property(ctx, yaca.PROPERTY.GCM_TAG, tag)
+    dec += yaca.decrypt_finalize(ctx)
+
+    assert msg == dec
+
+
+def encrypt_ccm_property():
+    # prepare:
+    key_sym = yaca.key_generate()
+    key_iv_64 = yaca.key_generate(yaca.KEY_TYPE.IV,
+                                  yaca.KEY_BIT_LENGTH.IV_64BIT)
+    # end prepare
+
+    tag_len = 12
+    aad = yaca.random_bytes(16)
+    ctx = yaca.encrypt_initialize(key_sym, bcm=yaca.BLOCK_CIPHER_MODE.CCM,
+                                  iv=key_iv_64)
+    yaca.context_set_property(ctx, yaca.PROPERTY.CCM_TAG_LEN, tag_len)
+    yaca.encrypt_update(ctx, len(msg))  # encrypt_update second type of usage
+    yaca.context_set_property(ctx, yaca.PROPERTY.CCM_AAD, aad)
+    enc = yaca.encrypt_update(ctx, msg)
+    enc += yaca.encrypt_finalize(ctx)
+    tag = yaca.context_get_property(ctx, yaca.PROPERTY.CCM_TAG)
+    assert len(tag) == tag_len
+
+    ctx = yaca.decrypt_initialize(key_sym, bcm=yaca.BLOCK_CIPHER_MODE.CCM,
+                                  iv=key_iv_64)
+    yaca.context_set_property(ctx, yaca.PROPERTY.CCM_TAG, tag)
+    yaca.decrypt_update(ctx, len(enc))  # decrypt_update second type of usage
+    yaca.context_set_property(ctx, yaca.PROPERTY.CCM_AAD, aad)
+    dec = yaca.decrypt_update(ctx, enc)
+    dec += yaca.decrypt_finalize(ctx)
+
+    assert msg == dec
+
+
+def sign():
+    # prepare:
+    key_sym = yaca.key_generate()
+    key_rsa_prv = yaca.key_generate(yaca.KEY_TYPE.RSA_PRIV,
+                                    yaca.KEY_BIT_LENGTH.L2048BIT)
+    key_rsa_pub = yaca.key_extract_public(key_rsa_prv)
+    hmac_simple = yaca.simple_calculate_hmac(key_sym, msg,
+                                             yaca.DIGEST_ALGORITHM.SHA512)
+    cmac_simple = yaca.simple_calculate_cmac(key_sym, msg,
+                                             yaca.ENCRYPT_ALGORITHM.AES)
+    sign_simple = yaca.simple_calculate_signature(key_rsa_prv, msg,
+                                                  yaca.DIGEST_ALGORITHM.SHA512)
+    # end prepare
+
+    ctx = yaca.sign_initialize_hmac(key_sym, yaca.DIGEST_ALGORITHM.SHA512)
+    for part in msg_parts:
+        yaca.sign_update(ctx, part)
+    hmac = yaca.sign_finalize(ctx)
+
+    assert hmac == hmac_simple
+
+    ctx = yaca.sign_initialize_cmac(key_sym, yaca.ENCRYPT_ALGORITHM.AES)
+    for part in msg_parts:
+        yaca.sign_update(ctx, part)
+    cmac = yaca.sign_finalize(ctx)
+
+    assert cmac == cmac_simple
+
+    ctx = yaca.sign_initialize(key_rsa_prv, yaca.DIGEST_ALGORITHM.SHA512)
+    for part in msg_parts:
+        yaca.sign_update(ctx, part)
+    sig = yaca.sign_finalize(ctx)
+
+    assert sig == sign_simple  # won't work for DSA
+
+    ctx = yaca.verify_initialize(key_rsa_pub, yaca.DIGEST_ALGORITHM.SHA512)
+    for part in msg_parts:
+        yaca.verify_update(ctx, part)
+    assert yaca.verify_finalize(ctx, sig)
+
+    # SIGN + SET PADDING
+
+    ctx = yaca.sign_initialize(key_rsa_prv)
+    for part in msg_parts:
+        yaca.sign_update(ctx, part)
+    yaca.context_set_property(ctx, yaca.PROPERTY.PADDING,
+                              yaca.PADDING.PKCS1_PSS)
+    sig = yaca.sign_finalize(ctx)
+
+    ctx = yaca.verify_initialize(key_rsa_pub)
+    for part in msg_parts:
+        yaca.verify_update(ctx, part)
+    yaca.context_set_property(ctx, yaca.PROPERTY.PADDING,
+                              yaca.PADDING.PKCS1_PSS)
+    assert yaca.verify_finalize(ctx, sig)
+
+
+def seal():
+    # prepare:
+    key_rsa_prv = yaca.key_generate(yaca.KEY_TYPE.RSA_PRIV,
+                                    yaca.KEY_BIT_LENGTH.L2048BIT)
+    key_rsa_pub = yaca.key_extract_public(key_rsa_prv)
+    # end prepare
+
+    ctx, key_seal, iv = yaca.seal_initialize(key_rsa_pub,
+                                             bcm=yaca.BLOCK_CIPHER_MODE.CBC)
+    sealed = b''
+    for part in msg_parts:
+        sealed += yaca.seal_update(ctx, part)
+    sealed += yaca.seal_finalize(ctx)
+
+    sealed_parts = split_into_parts(sealed, 5)
+
+    ctx = yaca.open_initialize(key_rsa_prv, key_seal, iv,
+                               bcm=yaca.BLOCK_CIPHER_MODE.CBC)
+    opened = b''
+    for part in sealed_parts:
+        opened += yaca.open_update(ctx, part)
+    opened += yaca.open_finalize(ctx)
+
+    assert opened == msg
+
+
+def rsa():
+    # prepare:
+    key_rsa_prv = yaca.key_generate(yaca.KEY_TYPE.RSA_PRIV,
+                                    yaca.KEY_BIT_LENGTH.L2048BIT)
+    key_rsa_pub = yaca.key_extract_public(key_rsa_prv)
+    # end prepare
+
+    msg_short_max = int(2048 / 8 - 11)
+    msg_short = msg[:msg_short_max]
+
+    enc_rsa = yaca.rsa_public_encrypt(key_rsa_pub, msg_short)
+    dec_rsa = yaca.rsa_private_decrypt(key_rsa_prv, enc_rsa)
+
+    assert dec_rsa == msg_short
+
+    enc_rsa = yaca.rsa_private_encrypt(key_rsa_prv, msg_short)
+    dec_rsa = yaca.rsa_public_decrypt(key_rsa_pub, enc_rsa)
+
+    assert dec_rsa == msg_short