From eecb91038ff27db8b1c71103a2bc3711e2a0b00d Mon Sep 17 00:00:00 2001 From: Matěj Cepl Date: Sun, 3 Jun 2018 16:37:42 +0200 Subject: More cffi beauty, some tests --- cffi_random.py | 82 ------------------------------------------------------- rand.py | 78 ++++++++++++++++++++++++++++++++++++++++++++++++++++ test/__init__.py | 0 test/test_rand.py | 31 +++++++++++++++++++++ 4 files changed, 109 insertions(+), 82 deletions(-) delete mode 100644 cffi_random.py create mode 100644 rand.py create mode 100644 test/__init__.py create mode 100644 test/test_rand.py diff --git a/cffi_random.py b/cffi_random.py deleted file mode 100644 index 5f62e43..0000000 --- a/cffi_random.py +++ /dev/null @@ -1,82 +0,0 @@ -#!/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/rand.py b/rand.py new file mode 100644 index 0000000..285eb98 --- /dev/null +++ b/rand.py @@ -0,0 +1,78 @@ +#!/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 (bytes(blob), ret) + else: + RandError("Unknown error in RAND_pseudo_bytes") diff --git a/test/__init__.py b/test/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/test/test_rand.py b/test/test_rand.py new file mode 100644 index 0000000..76b4d24 --- /dev/null +++ b/test/test_rand.py @@ -0,0 +1,31 @@ +import sys +import unittest + +import rand + + +class RandTestCase(unittest.TestCase): + def test_rand_status(self): + self.assertEqual(rand.rand_status(), 1) + + def test_rand_event(self): + if sys.platform == 'win32': + self.assertIsNotNone(rand.rand_event(1, 1, 1)) + else: + self.assertIsNone(rand.rand_event(1, 1, 1)) + + def test_rand_bytes(self): + exp_length = 15 + r = rand.rand_bytes(exp_length) + self.assertIsInstance(r, bytes) + self.assertEqual(len(r), exp_length) + + def test_rand_pseudo_bytes(self): + exp_length = 15 + r = rand.rand_pseudo_bytes(exp_length) + self.assertIsInstance(r[0], bytes) + self.assertEqual(len(r[0]), exp_length) + self.assertEqual(r[1], 1) + +if __name__ == '__main__': + unittest.main() -- cgit