From f329e17cf7401eb8ab7f9ae1f6a3833af64b011b Mon Sep 17 00:00:00 2001 From: Matěj Cepl Date: Sun, 3 Jun 2018 01:14:45 +0200 Subject: After many attempts libffi seems like the best idea. --- .gitignore | 6 ++--- cffi_random.py | 82 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ helloworld.pyx | 1 - randomize.pyx | 14 ++++++++++ setup.py | 11 ++++++-- 5 files changed, 107 insertions(+), 7 deletions(-) create mode 100644 cffi_random.py delete mode 100644 helloworld.pyx create mode 100644 randomize.pyx diff --git a/.gitignore b/.gitignore index 9021ee4..b2b6d48 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,2 @@ -*.c -*~ -*.so -build/ \ No newline at end of file +__pycache__/ +build/ diff --git a/cffi_random.py b/cffi_random.py new file mode 100644 index 0000000..5f62e43 --- /dev/null +++ b/cffi_random.py @@ -0,0 +1,82 @@ +#!/usr/bin/env python3 + +import sys +from typing import Optional + +from cffi import FFI + +class RandError(RuntimeError): + pass + +ffi = FFI() +ffi.cdef(''' + void RAND_seed(const void *buf, int num); + + void RAND_add(const void *buf, int num, double entropy); + + int RAND_status(void); + + int RAND_event(unsigned int iMsg, void* wParam, void* lParam); + void RAND_screen(void); + + int RAND_bytes(unsigned char *buf, int num); + + int RAND_pseudo_bytes(unsigned char *buf, int num); + + const char *ERR_reason_error_string(unsigned long); + + unsigned long ERR_get_error(void); +''') + +lib = ffi.dlopen('crypto') + +def rand_add(buf: bytes, num: int, entropy: float) -> None: + assert isinstance(entropy, float) + lib.RAND_add(buf, num, entropy) + +def rand_seed(buf: bytes, num: int) -> None: + lib.RAND_seed(buf, num) + +def rand_status() -> int: + return lib.RAND_status() + +def rand_event(iMsg: int, wParam: int, lParam: int) -> Optional[int]: + if sys.platform == 'win32': + return lib.RAND_event(iMsg, wParam, lParam) + else: + return None + +def rand_screen() -> None: + if sys.platform == 'win32': + lib.RAND_screen() + +def rand_bytes(n: int = 8) -> bytes: + buf = ffi.new('unsigned char buf[{:d}]'.format(n)) + ret = lib.RAND_bytes(buf, n) + if ret == 1: + return bytes(buf) + elif ret == 0: + RandError("Not enough randomness.") + elif ret == -1: + RandError("Not supported by the current RAND method.") + else: + err_msg = lib.ERR_reason_error_string(lib.ERR_get_error()) + if err_msg is not None: + RandError(err_msg) + else: + RandError("Unknown error in function RAND_bytes") + +def rand_pseudo_bytes(n: int) -> bytes: + blob = ffi.new('unsigned char buf[{:d}]'.format(n)) + ret = lib.RAND_pseudo_bytes(blob, n) + + if ret == -1: + RandError("Not supported by the current RAND method.") + elif ret in [0, 1]: + return (blob, ret) + else: + RandError("Unknown error in RAND_pseudo_bytes") + + +if __name__=='__main__': + print(rand_bytes()) diff --git a/helloworld.pyx b/helloworld.pyx deleted file mode 100644 index ad35e5a..0000000 --- a/helloworld.pyx +++ /dev/null @@ -1 +0,0 @@ -print("Hello World") diff --git a/randomize.pyx b/randomize.pyx new file mode 100644 index 0000000..99cd0ab --- /dev/null +++ b/randomize.pyx @@ -0,0 +1,14 @@ +cdef extern from "openssl/rand.h": + void RAND_seed( + const void *buf, int num) + void RAND_add(const void *buf, int num, double entropy) + int RAND_status() + void RAND_screen() + +def rand_add(buf: bytes, num: int, entropy: float) -> None: + assert isinstance(entropy, float) + RAND_add(buf, num, entropy) + +def rand_seed(buf: bytes, num: int) -> None: + RAND_seed(buf, num) + diff --git a/setup.py b/setup.py index 7b3ba28..800e1d7 100644 --- a/setup.py +++ b/setup.py @@ -1,5 +1,7 @@ from distutils.core import setup -from Cython.Build import cythonize +from distutils.extension import Extension + +from Cython.Distutils import build_ext setup( name='test_Cython', @@ -8,5 +10,10 @@ setup( platforms=['any'], author='Matej Cepl', author_email='mcepl@cepl.eu', - ext_modules = cythonize("helloworld.pyx") + cmdclass={'build_ext': build_ext}, + ext_modules = [ + Extension("randomize", + ["randomize.pyx"], + libraries=["ssl", "crypto"]) + ] ) -- cgit