Skip to content

Commit 662865f

Browse files
committed
prototype calling sodium c functions from python via cython
1 parent 94dc80e commit 662865f

File tree

7 files changed

+163
-1
lines changed

7 files changed

+163
-1
lines changed

build/.gitkeep

Whitespace-only changes.

paseto/crypto/.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
libsodium.c

paseto/crypto/libsodium.pyx

+133
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
# cython: language_level=3
2+
3+
# Cython wrapper for libsodium
4+
5+
# libsodium C API definitions for Cython
6+
7+
cdef extern from "../../submodules/libsodium/src/libsodium/include/sodium/crypto_aead_xchacha20poly1305.h":
8+
int crypto_aead_xchacha20poly1305_ietf_encrypt(
9+
unsigned char *c,
10+
unsigned long long *clen_p,
11+
const unsigned char *m,
12+
unsigned long long mlen,
13+
const unsigned char *ad,
14+
unsigned long long adlen,
15+
const unsigned char *nsec,
16+
const unsigned char *npub,
17+
const unsigned char *k
18+
)
19+
20+
int crypto_aead_xchacha20poly1305_ietf_decrypt(
21+
unsigned char *m,
22+
unsigned long long *mlen_p,
23+
unsigned char *nsec,
24+
const unsigned char *c,
25+
unsigned long long clen,
26+
const unsigned char *ad,
27+
unsigned long long adlen,
28+
const unsigned char *npub,
29+
const unsigned char *k)
30+
31+
32+
cdef extern from "../../submodules/libsodium/src/libsodium/include/sodium/crypto_sign.h":
33+
int crypto_sign_detached(
34+
unsigned char *sig,
35+
unsigned long long *siglen_p,
36+
const unsigned char *m,
37+
unsigned long long mlen,
38+
const unsigned char *sk
39+
)
40+
41+
int crypto_sign_verify_detached(
42+
const unsigned char *sig,
43+
const unsigned char *m,
44+
unsigned long long mlen,
45+
const unsigned char *pk
46+
)
47+
48+
cdef extern from "../../submodules/libsodium/src/libsodium/include/sodium/crypto_sign.h":
49+
size_t crypto_sign_bytes()
50+
size_t crypto_sign_secretkeybytes()
51+
size_t crypto_sign_publickeybytes()
52+
53+
cdef extern from "../../submodules/libsodium/src/libsodium/include/sodium/crypto_aead_xchacha20poly1305.h":
54+
size_t crypto_aead_xchacha20poly1305_ietf_abytes()
55+
size_t crypto_aead_xchacha20poly1305_ietf_npubbytes()
56+
size_t crypto_aead_xchacha20poly1305_ietf_keybytes()
57+
58+
NONCE_SIZE = 'Invalid nonce length'
59+
KEY_SIZE = 'Invalid key length'
60+
PUBLIC_KEY_SIZE = 'Invalid public key length'
61+
SECRET_KEY_SIZE = 'Invalid secret key length'
62+
SIGNATURE_SIZE = 'Invalid signature length'
63+
64+
# https://libsodium.gitbook.io/doc/secret-key_cryptography/aead/chacha20-poly1305/xchacha20-poly1305_construction
65+
def encrypt(message: bytes, ad: bytes, nonce: bytes, key: bytes):
66+
67+
check_nonce_size(len(nonce))
68+
check_key_size(len(key))
69+
70+
cipher_text = b' ' * (len(message) + crypto_aead_xchacha20poly1305_ietf_abytes())
71+
72+
cdef unsigned long long ciphertext_length = len(cipher_text)
73+
74+
crypto_aead_xchacha20poly1305_ietf_encrypt(cipher_text, &ciphertext_length, message, len(message), ad, len(ad), NULL, nonce, key)
75+
76+
return cipher_text
77+
78+
def decrypt(cipher_text: bytes, aad: bytes, nonce: bytes, key: bytes):
79+
80+
check_nonce_size(len(nonce))
81+
check_key_size(len(key))
82+
83+
cdef size_t cipher_text_length = len(cipher_text)
84+
85+
message = b' ' * (cipher_text_length - crypto_aead_xchacha20poly1305_ietf_abytes())
86+
cdef unsigned long long message_length
87+
88+
res = crypto_aead_xchacha20poly1305_ietf_decrypt(message, &message_length, NULL, cipher_text, cipher_text_length, aad, len(aad), nonce, key)
89+
90+
if res != 0:
91+
raise Exception('Decryption failed')
92+
93+
return message
94+
95+
def sign(message: bytes, secret_key: bytes):
96+
97+
check_secret_key_size(len(secret_key))
98+
99+
signature = b' ' * crypto_sign_bytes()
100+
cdef unsigned long long signature_length = len(signature)
101+
102+
crypto_sign_detached(signature, &signature_length, message, len(message), secret_key)
103+
104+
return signature
105+
106+
def verify(signature: bytes, message: bytes, public_key: bytes):
107+
108+
check_signature_size(len(signature))
109+
check_public_key_size(len(public_key))
110+
111+
crypto_sign_verify_detached(signature, message, len(message), public_key)
112+
113+
def check_size(actual_size, expected_size, exception_message):
114+
""" Helper method to verify length of method call arguments """
115+
if actual_size != expected_size:
116+
raise ValueError(exception_message)
117+
118+
def check_key_size(key_length: int):
119+
check_size(key_length, crypto_aead_xchacha20poly1305_ietf_keybytes(), KEY_SIZE)
120+
121+
def check_nonce_size(nonce_length: int):
122+
check_size(nonce_length, crypto_aead_xchacha20poly1305_ietf_npubbytes(), NONCE_SIZE)
123+
124+
def check_public_key_size(public_key_length: int):
125+
check_size(public_key_length, crypto_sign_publickeybytes(), PUBLIC_KEY_SIZE)
126+
127+
def check_secret_key_size(secret_key_length: int):
128+
check_size(secret_key_length, crypto_sign_secretkeybytes(), SECRET_KEY_SIZE)
129+
130+
def check_signature_size(signature_length: int):
131+
check_size(signature_length, crypto_sign_bytes(), SIGNATURE_SIZE)
132+
133+
__all__ = ['encrypt', 'decrypt', 'sign', 'verify']

paseto/crypto/primitives.py

+6
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,12 @@
11
from nacl.bindings import crypto_aead_xchacha20poly1305_ietf_encrypt as encrypt
22
from nacl.bindings import crypto_aead_xchacha20poly1305_ietf_decrypt as decrypt
3+
4+
# from pysodium import crypto_aead_xchacha20poly1305_ietf_encrypt as encrypt
5+
# from pysodium import crypto_aead_xchacha20poly1305_ietf_decrypt as decrypt
6+
37
from pysodium import crypto_sign_detached as sign
48
from pysodium import crypto_sign_verify_detached as verify
59

10+
# from libsodium import sign, verify, decrypt, encrypt
11+
612
__all__ = ["encrypt", "decrypt", "sign", "verify"]

poetry.lock

+10-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pyproject.toml

+1
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ license = "MIT"
99
python = "^3.6 || ^3.7"
1010
pynacl = "^1.3"
1111
pysodium = "^0.7.0"
12+
cython = "^0.29.1"
1213

1314
[tool.poetry.dev-dependencies]
1415
pytest = "^3.9"

setup.py

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
from distutils.core import setup
2+
from distutils.extension import Extension
3+
from Cython.Build import cythonize
4+
5+
6+
libsodium = Extension(
7+
name="libsodium",
8+
sources=["paseto/crypto/libsodium.pyx"],
9+
libraries=["sodium"],
10+
)
11+
12+
setup(name="python-paseto", ext_modules=cythonize([libsodium]))

0 commit comments

Comments
 (0)