CryptoSys Home > PKI > A Python interface to CryptoSys PKI Pro

A Python interface to CryptoSys PKI Pro

This page describes the Python3 interface to the core CryptoSys PKI Pro library. Latest version 22.0.0 released 2023-10-23.

Introduction | Installation | System requirements | Using in the Python REPL | Documentation | Classes and methods X-ref | Test files and examples | Another example | A further example | Running the tests | Revision history | Contact


We really like using Python because you can easily do calculations in its REPL environment (read-eval-print loop) without having to compile each time.

For a handy quick guide to the methods available see the Python CryptoSys PKI Cross Reference.


Automatic install from PyPi (recommended)

> pip install cryptosyspki
Collecting cryptosyspki
Installing collected packages: cryptosyspki
Successfully installed cryptosyspki-22.0.0

Note: You can safely ignore the message "Using legacy ' install' for cryptosyspki, since package 'wheel' is not installed". The pypi/pip people are getting their knickers in a twist about this. We'll look into it further when the situation is clearer.

To upgrade if an older version is already installed:

> pip install --upgrade cryptosyspki

Manual install

  1. Download the distribution file from the Python Package Index (PyPi).
  2. Open a command line console in the same directory as the zip file, then type
    pip install
    where "x.x.x" is the current version number.

System requirements

Windows only. Python 3 must be installed on your system. CryptoSys PKI Pro v22.0.0 or above must also be installed. This is available from

Using in the Python REPL

Here are some simple examples calling CryptoSys PKI Pro functions from the Python REPL.

>>> from cryptosyspki import *
>>> Gen.version() # "hello world!" for CryptoSys PKI
>>> Hash.hex_from_data(b'abc') # compute SHA-1 hash in hex of 'abc' as bytes
>>> Hash.hex_from_string('abc', Hash.Alg.SHA256)   # same but over a string and using SHA-256
>>> h ='abc')   # h is a byte array (bytes->bytes)
>>> print(Cnv.tohex(h))     # display the byte array in hex

If you don't like import * and find cryptosyspki a bit long to type each time, try

>>> import cryptosyspki as pki
>>> pki.Gen.version() #  Underlying core PKI dll
>>> pki.__version__   # package

Note that pki.Gen.version() gives the version number of the underlying core CryptoSys PKI DLL, and pki.__version__ gives the version of the Python cryptosyspki package.

Caution: the change from Python 2 to Python 3 means we have to be careful and differentiate between arguments expected to be byte arrays and arguments expected as strings. In old Python 2 we could get away with the ambiguity. In Python 3 you will get an exception if you use the wrong type.
>>> Hash.hex_from_data('abc')  # Woops! String type is not a bytes array in py 3
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "C:\Python38\lib\site-packages\", line 1876, in hex_from_data
    nc = _dipki.HASH_HexFromBytes(None, 0, bytes(data), len(data), alg)
TypeError: string argument without an encoding
>>> Hash.hex_from_data('abc'.encode())  # OK - string encoded into bytes array
>>> Hash.hex_from_data(b'abc')  # Or simply write directly as a byte array

Test files and examples

There is set of examples in the test script test/ provided with the latest download from PyPi (download the file and unzip it to get the files and test directory structure). Here are the latest required test files for the tests.

You can cut and paste the parts you want to get started writing your own code.

Here are some of the most interesting examples.

Another example


# Encrypt a string with a random IV in CBC mode using AES-128
# Output result as base64-encoding of IV+CT.
# Then parse the result and decrypt.

# [2019-12-28] v12.2 Updated for Python 3.
# [2017-08-12] v11.2 Changed ``Rng.bytes`` to ``Rng.bytestring``

from cryptosyspki import *

# Shared secret key
k = Cnv.fromhex("112233445566778899aabbccddeeff00")
print("KEY:", Cnv.tohex(k))

# Message to encrypt (bytes)
m = b"Feather-footed through the plashy fen passes the questing vole."
print("PT:", m)
print("PT:", Cnv.tohex(m))

# Block length in bytes for AES-128
blen = Cipher.blockbytes(Cipher.Alg.AES128)

# Generate a random IV of the correct length (NB different each time)
iv = Rng.bytestring(blen)
print("IV:", Cnv.tohex(iv))

# Do the business - Encrypt it.
ct = Cipher.encrypt(m, k, alg=Cipher.Alg.AES128, mode=Cipher.Mode.CBC, iv=iv)
print("CT:", Cnv.tohex(ct))

# Concatenate IV+ciphertext bytearrays
cto = iv + ct
print("IV|CT:", Cnv.tohex(cto))

# Output in base64
ct64 = Cnv.tobase64(cto)
print("OUTPUT:", ct64)

# Send output to recipient...
print("Send to recipient...")
print("\nRecipient receives input...")
print("INPUT:", ct64)
# Recipient receives encoded data as input.
# Recipient knows a) the shared secret key,
#  b) the algorithm is AES-128-CBC and
#  c) the data is in the form IV|CT.

# Decode the base64 input to a byte array
cto = Cnv.frombase64(ct64)

# Parse the message - the first blocklen bytes are the IV
iv = cto[:Cipher.blockbytes(Cipher.Alg.AES128)]
ct = cto[Cipher.blockbytes(Cipher.Alg.AES128):]
print("IV:", Cnv.tohex(iv))
print("CT:", Cnv.tohex(ct))

# Decrypt
pt = Cipher.decrypt(ct, k, iv=iv, algmodepad="aes128/cbc/pkcs5")
print("PT:", Cnv.tohex(pt))

# Display as text
print("PT:", pt)

Typical output (IV and ciphertext will be different each time).

KEY: 112233445566778899AABBCCDDEEFF00
PT: b'Feather-footed through the plashy fen passes the questing vole.'
PT: 466561746865722D666F6F746564207468726F7567682074686520706C617368792066656E2070617373657320746865207175657374696E6720766F6C652E
IV: F63A311A9354D3C1B8B0A5DB1C1341DC
CT: BA7606992B93B638EDC4C93EBC06C67894B395EF39F7086D0D4CBDE44FC5103B398788F6885FDE676CE370389E7F132529C9041D2C6857B89767F544542EB147
IV|CT: F63A311A9354D3C1B8B0A5DB1C1341DCBA7606992B93B638EDC4C93EBC06C67894B395EF39F7086D0D4CBDE44FC5103B398788F6885FDE676CE370389E7F132529C9041D2C6857B89767F544542EB147
OUTPUT: 9joxGpNU08G4sKXbHBNB3Lp2Bpkrk7Y47cTJPrwGxniUs5XvOfcIbQ1MveRPxRA7OYeI9ohf3mds43A4nn8TJSnJBB0saFe4l2f1RFQusUc=
Send to recipient...

Recipient receives input...
INPUT: 9joxGpNU08G4sKXbHBNB3Lp2Bpkrk7Y47cTJPrwGxniUs5XvOfcIbQ1MveRPxRA7OYeI9ohf3mds43A4nn8TJSnJBB0saFe4l2f1RFQusUc=
IV: F63A311A9354D3C1B8B0A5DB1C1341DC
CT: BA7606992B93B638EDC4C93EBC06C67894B395EF39F7086D0D4CBDE44FC5103B398788F6885FDE676CE370389E7F132529C9041D2C6857B89767F544542EB147
PT: 466561746865722D666F6F746564207468726F7567682074686520706C617368792066656E2070617373657320746865207175657374696E6720766F6C652E
PT: b'Feather-footed through the plashy fen passes the questing vole.'

A further example

See Create a SignatureValue from a DigestValue which shows how to create a base64-encoded signature suitable for a <SignatureValue> element from the base64-encoded digest value and the signer's private key.

Running the tests

The tests in test/ demonstrate the use of each of the classes and methods using known test vectors where possible. The script and test files are available in the download from PyPi. The output should look something similar to this.

This particular test code requires a directory structure with a subdirectory work/ in the same folder as the file which should contain all the required test files. The test function then creates a temporary subdirectory which is deleted automatically. (If you lose the test files, copies are available separately in the file

test/  # this module
    work/        # this _must_ exist
        <all required test files>
        pki.tmp.XXXXXXXX/    # created by `setup_temp_dir()`
            <copy of all required test files>
            <files created by tests>

This structure is already setup in the distribution file, so unzip the file and open a command line prompt in the test sub-directory. Then do one of the following.

  1. python
  2. py.test -v
    See †
  3. Open the file using IDLE and select Run > Run Module (F5).

[Go to top]

Revision History

See Revision History

[Go to top]


For more information, or to comment on this page, please send us a message.

This page last updated 23 October 2023

[Go to top]