aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/lib/ffi/ffi.h73
-rw-r--r--src/lib/ffi/ffi_pkey.cpp4
-rwxr-xr-xsrc/python/botan2.py208
-rw-r--r--src/scripts/test_python.py116
-rw-r--r--src/tests/test_ffi.cpp2
5 files changed, 350 insertions, 53 deletions
diff --git a/src/lib/ffi/ffi.h b/src/lib/ffi/ffi.h
index 6345acf2c..323f47557 100644
--- a/src/lib/ffi/ffi.h
+++ b/src/lib/ffi/ffi.h
@@ -794,9 +794,9 @@ BOTAN_PUBLIC_API(2,1) int botan_mp_from_bin(const botan_mp_t mp, const uint8_t v
BOTAN_PUBLIC_API(2,1) int botan_mp_to_uint32(const botan_mp_t mp, uint32_t* val);
/**
-* This function is not well named. Returns 1 iff mp is greater than
-* *or equal to* zero. Use botan_mp_is_negative to detect negative
-* numbers, botan_mp_is_zero to check for zero.
+* This function should have been named mp_is_non_negative. Returns 1
+* iff mp is greater than *or equal to* zero. Use botan_mp_is_negative
+* to detect negative numbers, botan_mp_is_zero to check for zero.
*/
BOTAN_PUBLIC_API(2,1) int botan_mp_is_positive(const botan_mp_t mp);
@@ -808,8 +808,11 @@ BOTAN_PUBLIC_API(2,1) int botan_mp_is_negative(const botan_mp_t mp);
BOTAN_PUBLIC_API(2,1) int botan_mp_flip_sign(botan_mp_t mp);
BOTAN_PUBLIC_API(2,1) int botan_mp_is_zero(const botan_mp_t mp);
-BOTAN_PUBLIC_API(2,1) int botan_mp_is_odd(const botan_mp_t mp);
-BOTAN_PUBLIC_API(2,1) int botan_mp_is_even(const botan_mp_t mp);
+
+BOTAN_PUBLIC_API(2,1) BOTAN_DEPRECATED("Use botan_mp_get_bit(0)")
+int botan_mp_is_odd(const botan_mp_t mp);
+BOTAN_PUBLIC_API(2,1) BOTAN_DEPRECATED("Use botan_mp_get_bit(0)")
+int botan_mp_is_even(const botan_mp_t mp);
BOTAN_PUBLIC_API(2,8) int botan_mp_add_u32(botan_mp_t result, const botan_mp_t x, uint32_t y);
BOTAN_PUBLIC_API(2,8) int botan_mp_sub_u32(botan_mp_t result, const botan_mp_t x, uint32_t y);
@@ -936,12 +939,16 @@ BOTAN_PUBLIC_API(2,0) int botan_privkey_create(botan_privkey_t* key,
BOTAN_PUBLIC_API(2,0) int botan_privkey_check_key(botan_privkey_t key, botan_rng_t rng, uint32_t flags);
-BOTAN_PUBLIC_API(2,0) int botan_privkey_create_rsa(botan_privkey_t* key, botan_rng_t rng, size_t n_bits);
-BOTAN_PUBLIC_API(2,0) int botan_privkey_create_ecdsa(botan_privkey_t* key, botan_rng_t rng, const char* params);
-BOTAN_PUBLIC_API(2,0) int botan_privkey_create_ecdh(botan_privkey_t* key, botan_rng_t rng, const char* params);
-BOTAN_PUBLIC_API(2,0) int botan_privkey_create_mceliece(botan_privkey_t* key, botan_rng_t rng, size_t n, size_t t);
-BOTAN_PUBLIC_API(2,0) int botan_privkey_create_dh(botan_privkey_t* key, botan_rng_t rng, const char* param);
-
+BOTAN_PUBLIC_API(2,0) BOTAN_DEPRECATED("Use botan_privkey_create")
+int botan_privkey_create_rsa(botan_privkey_t* key, botan_rng_t rng, size_t n_bits);
+BOTAN_PUBLIC_API(2,0) BOTAN_DEPRECATED("Use botan_privkey_create")
+int botan_privkey_create_ecdsa(botan_privkey_t* key, botan_rng_t rng, const char* params);
+BOTAN_PUBLIC_API(2,0) BOTAN_DEPRECATED("Use botan_privkey_create")
+int botan_privkey_create_ecdh(botan_privkey_t* key, botan_rng_t rng, const char* params);
+BOTAN_PUBLIC_API(2,0) BOTAN_DEPRECATED("Use botan_privkey_create")
+int botan_privkey_create_mceliece(botan_privkey_t* key, botan_rng_t rng, size_t n, size_t t);
+BOTAN_PUBLIC_API(2,0) BOTAN_DEPRECATED("Use botan_privkey_create")
+int botan_privkey_create_dh(botan_privkey_t* key, botan_rng_t rng, const char* param);
/**
* Generates DSA key pair. Gives to a caller control over key length
@@ -1102,11 +1109,16 @@ BOTAN_PUBLIC_API(2,8) int botan_privkey_load_rsa_pkcs1(botan_privkey_t* key,
const uint8_t bits[],
size_t len);
-BOTAN_PUBLIC_API(2,0) int botan_privkey_rsa_get_p(botan_mp_t p, botan_privkey_t rsa_key);
-BOTAN_PUBLIC_API(2,0) int botan_privkey_rsa_get_q(botan_mp_t q, botan_privkey_t rsa_key);
-BOTAN_PUBLIC_API(2,0) int botan_privkey_rsa_get_d(botan_mp_t d, botan_privkey_t rsa_key);
-BOTAN_PUBLIC_API(2,0) int botan_privkey_rsa_get_n(botan_mp_t n, botan_privkey_t rsa_key);
-BOTAN_PUBLIC_API(2,0) int botan_privkey_rsa_get_e(botan_mp_t e, botan_privkey_t rsa_key);
+BOTAN_PUBLIC_API(2,0) BOTAN_DEPRECATED("Use botan_privkey_get_field")
+int botan_privkey_rsa_get_p(botan_mp_t p, botan_privkey_t rsa_key);
+BOTAN_PUBLIC_API(2,0) BOTAN_DEPRECATED("Use botan_privkey_get_field")
+int botan_privkey_rsa_get_q(botan_mp_t q, botan_privkey_t rsa_key);
+BOTAN_PUBLIC_API(2,0) BOTAN_DEPRECATED("Use botan_privkey_get_field")
+int botan_privkey_rsa_get_d(botan_mp_t d, botan_privkey_t rsa_key);
+BOTAN_PUBLIC_API(2,0) BOTAN_DEPRECATED("Use botan_privkey_get_field")
+int botan_privkey_rsa_get_n(botan_mp_t n, botan_privkey_t rsa_key);
+BOTAN_PUBLIC_API(2,0) BOTAN_DEPRECATED("Use botan_privkey_get_field")
+int botan_privkey_rsa_get_e(botan_mp_t e, botan_privkey_t rsa_key);
BOTAN_PUBLIC_API(2,8) int botan_privkey_rsa_get_privkey(botan_privkey_t rsa_key,
uint8_t out[], size_t* out_len,
@@ -1116,8 +1128,10 @@ BOTAN_PUBLIC_API(2,0) int botan_pubkey_load_rsa(botan_pubkey_t* key,
botan_mp_t n,
botan_mp_t e);
-BOTAN_PUBLIC_API(2,0) int botan_pubkey_rsa_get_e(botan_mp_t e, botan_pubkey_t rsa_key);
-BOTAN_PUBLIC_API(2,0) int botan_pubkey_rsa_get_n(botan_mp_t n, botan_pubkey_t rsa_key);
+BOTAN_PUBLIC_API(2,0) BOTAN_DEPRECATED("Use botan_pubkey_get_field")
+int botan_pubkey_rsa_get_e(botan_mp_t e, botan_pubkey_t rsa_key);
+BOTAN_PUBLIC_API(2,0) BOTAN_DEPRECATED("Use botan_pubkey_get_field")
+int botan_pubkey_rsa_get_n(botan_mp_t n, botan_pubkey_t rsa_key);
/*
* Algorithm specific key operations: DSA
@@ -1134,12 +1148,17 @@ BOTAN_PUBLIC_API(2,0) int botan_pubkey_load_dsa(botan_pubkey_t* key,
botan_mp_t g,
botan_mp_t y);
-BOTAN_PUBLIC_API(2,0) int botan_privkey_dsa_get_x(botan_mp_t n, botan_privkey_t key);
+BOTAN_PUBLIC_API(2,0) BOTAN_DEPRECATED("Use botan_privkey_get_field")
+int botan_privkey_dsa_get_x(botan_mp_t n, botan_privkey_t key);
-BOTAN_PUBLIC_API(2,0) int botan_pubkey_dsa_get_p(botan_mp_t p, botan_pubkey_t key);
-BOTAN_PUBLIC_API(2,0) int botan_pubkey_dsa_get_q(botan_mp_t q, botan_pubkey_t key);
-BOTAN_PUBLIC_API(2,0) int botan_pubkey_dsa_get_g(botan_mp_t d, botan_pubkey_t key);
-BOTAN_PUBLIC_API(2,0) int botan_pubkey_dsa_get_y(botan_mp_t y, botan_pubkey_t key);
+BOTAN_PUBLIC_API(2,0) BOTAN_DEPRECATED("Use botan_pubkey_get_field")
+int botan_pubkey_dsa_get_p(botan_mp_t p, botan_pubkey_t key);
+BOTAN_PUBLIC_API(2,0) BOTAN_DEPRECATED("Use botan_pubkey_get_field")
+int botan_pubkey_dsa_get_q(botan_mp_t q, botan_pubkey_t key);
+BOTAN_PUBLIC_API(2,0) BOTAN_DEPRECATED("Use botan_pubkey_get_field")
+int botan_pubkey_dsa_get_g(botan_mp_t d, botan_pubkey_t key);
+BOTAN_PUBLIC_API(2,0) BOTAN_DEPRECATED("Use botan_pubkey_get_field")
+int botan_pubkey_dsa_get_y(botan_mp_t y, botan_pubkey_t key);
/*
* Loads Diffie Hellman private key
@@ -1283,13 +1302,13 @@ int botan_privkey_load_sm2(botan_privkey_t* key,
const botan_mp_t scalar,
const char* curve_name);
-BOTAN_PUBLIC_API(2,2)
+BOTAN_PUBLIC_API(2,2) BOTAN_DEPRECATED("Use botan_pubkey_load_sm2")
int botan_pubkey_load_sm2_enc(botan_pubkey_t* key,
const botan_mp_t public_x,
const botan_mp_t public_y,
const char* curve_name);
-BOTAN_PUBLIC_API(2,2)
+BOTAN_PUBLIC_API(2,2) BOTAN_DEPRECATED("Use botan_privkey_load_sm2")
int botan_privkey_load_sm2_enc(botan_privkey_t* key,
const botan_mp_t scalar,
const char* curve_name);
@@ -1412,7 +1431,7 @@ BOTAN_PUBLIC_API(2,0) int botan_pkcs_hash_id(const char* hash_name, uint8_t pkcs
* @param mce_key must be a McEliece key
* ct_len should be pt_len + n/8 + a few?
*/
-BOTAN_PUBLIC_API(2,0)
+BOTAN_PUBLIC_API(2,0) BOTAN_DEPRECATED("Poorly specified, avoid in new code")
int botan_mceies_encrypt(botan_pubkey_t mce_key,
botan_rng_t rng,
const char* aead,
@@ -1420,7 +1439,7 @@ int botan_mceies_encrypt(botan_pubkey_t mce_key,
const uint8_t ad[], size_t ad_len,
uint8_t ct[], size_t* ct_len);
-BOTAN_PUBLIC_API(2,0)
+BOTAN_PUBLIC_API(2,0) BOTAN_DEPRECATED("Poorly specified, avoid in new code")
int botan_mceies_decrypt(botan_privkey_t mce_key,
const char* aead,
const uint8_t ct[], size_t ct_len,
diff --git a/src/lib/ffi/ffi_pkey.cpp b/src/lib/ffi/ffi_pkey.cpp
index 24bc96758..e0ba2380a 100644
--- a/src/lib/ffi/ffi_pkey.cpp
+++ b/src/lib/ffi/ffi_pkey.cpp
@@ -138,14 +138,14 @@ int botan_pubkey_check_key(botan_pubkey_t key, botan_rng_t rng, uint32_t flags)
const bool strong = (flags & BOTAN_CHECK_KEY_EXPENSIVE_TESTS);
return BOTAN_FFI_DO(Botan::Public_Key, key, k,
- { return (k.check_key(safe_get(rng), strong) == true) ? 0 : -1; });
+ { return (k.check_key(safe_get(rng), strong) == true) ? 0 : BOTAN_FFI_ERROR_INVALID_INPUT; });
}
int botan_privkey_check_key(botan_privkey_t key, botan_rng_t rng, uint32_t flags)
{
const bool strong = (flags & BOTAN_CHECK_KEY_EXPENSIVE_TESTS);
return BOTAN_FFI_DO(Botan::Private_Key, key, k,
- { return (k.check_key(safe_get(rng), strong) == true) ? 0 : -1; });
+ { return (k.check_key(safe_get(rng), strong) == true) ? 0 : BOTAN_FFI_ERROR_INVALID_INPUT; });
}
int botan_pubkey_export(botan_pubkey_t key, uint8_t out[], size_t* out_len, uint32_t flags)
diff --git a/src/python/botan2.py b/src/python/botan2.py
index 73f4e73d7..d92fd029b 100755
--- a/src/python/botan2.py
+++ b/src/python/botan2.py
@@ -71,18 +71,17 @@ def _errcheck(rc, fn, _args):
# This errcheck should only be used for int-returning functions
assert isinstance(rc, int)
- if rc >= 0:
- return rc
- if rc == -10: # insufficient buffer space, pass up to caller
+ if rc >= 0 or rc in fn.allowed_errors:
return rc
raise BotanException('%s failed' % (fn.__name__), rc)
def _set_prototypes(dll):
# pylint: disable=too-many-statements,line-too-long
- def ffi_api(fn, args):
+ def ffi_api(fn, args, allowed_errors = [-10]):
fn.argtypes = args
fn.restype = c_int
fn.errcheck = _errcheck
+ fn.allowed_errors = allowed_errors
dll.botan_version_string.argtypes = []
dll.botan_version_string.restype = c_char_p
@@ -99,11 +98,14 @@ def _set_prototypes(dll):
dll.botan_version_patch.argtypes = []
dll.botan_version_patch.restype = c_uint32
+ dll.botan_ffi_api_version.argtypes = []
+ dll.botan_ffi_api_version.restype = c_uint32
+
dll.botan_error_description.argtypes = [c_int]
dll.botan_error_description.restype = c_char_p
# These are generated using src/scripts/ffi_decls.py:
- ffi_api(dll.botan_constant_time_compare, [c_char_p, c_char_p, c_size_t])
+ ffi_api(dll.botan_constant_time_compare, [c_void_p, c_void_p, c_size_t], [-1])
ffi_api(dll.botan_scrub_mem, [c_void_p, c_size_t])
ffi_api(dll.botan_hex_encode, [c_char_p, c_size_t, c_char_p, c_uint32])
@@ -237,7 +239,7 @@ def _set_prototypes(dll):
# PUBKEY
ffi_api(dll.botan_privkey_create, [c_void_p, c_char_p, c_char_p, c_void_p])
- ffi_api(dll.botan_privkey_check_key, [c_void_p, c_void_p, c_uint32])
+ ffi_api(dll.botan_privkey_check_key, [c_void_p, c_void_p, c_uint32], [-1])
ffi_api(dll.botan_privkey_create_rsa, [c_void_p, c_void_p, c_size_t])
ffi_api(dll.botan_privkey_create_ecdsa, [c_void_p, c_void_p, c_char_p])
ffi_api(dll.botan_privkey_create_ecdh, [c_void_p, c_void_p, c_char_p])
@@ -260,7 +262,7 @@ def _set_prototypes(dll):
ffi_api(dll.botan_pubkey_load, [c_void_p, c_char_p, c_size_t])
ffi_api(dll.botan_pubkey_export, [c_void_p, c_char_p, POINTER(c_size_t), c_uint32])
ffi_api(dll.botan_pubkey_algo_name, [c_void_p, c_char_p, POINTER(c_size_t)])
- ffi_api(dll.botan_pubkey_check_key, [c_void_p, c_void_p, c_uint32])
+ ffi_api(dll.botan_pubkey_check_key, [c_void_p, c_void_p, c_uint32], [-1])
ffi_api(dll.botan_pubkey_estimated_strength, [c_void_p, POINTER(c_size_t)])
ffi_api(dll.botan_pubkey_fingerprint, [c_void_p, c_char_p, c_char_p, POINTER(c_size_t)])
ffi_api(dll.botan_pubkey_destroy, [c_void_p])
@@ -432,6 +434,8 @@ def _call_fn_returning_str(guess, fn):
return v.decode('ascii')[:-1]
def _ctype_str(s):
+ if s is None:
+ return None
assert isinstance(s, str)
if version_info[0] < 3:
return s
@@ -468,7 +472,7 @@ def _hex_encode(buf):
return hexlify(buf).decode('ascii')
#
-# Versions
+# Versioning
#
def version_major():
return int(_DLL.botan_version_major())
@@ -479,10 +483,24 @@ def version_minor():
def version_patch():
return int(_DLL.botan_version_patch())
+def ffi_api_version():
+ return int(_DLL.botan_ffi_api_version())
+
def version_string():
return _DLL.botan_version_string().decode('ascii')
#
+# Utilities
+#
+def const_time_compare(x, y):
+ len_x = len(x)
+ len_y = len(y)
+ if len_x != len_y:
+ return False
+ rc = _DLL.botan_constant_time_compare(_ctype_bits(x), _ctype_bits(y), c_size_t(len_x))
+ return (rc == 0)
+
+#
# RNG
#
class RandomNumberGenerator(object):
@@ -836,12 +854,78 @@ class PublicKey(object): # pylint: disable=invalid-name
_DLL.botan_pubkey_load(byref(obj), _ctype_bits(val), len(val))
return PublicKey(obj)
+ @classmethod
+ def load_rsa(cls, n, e):
+ obj = c_void_p(0)
+ n = MPI(n)
+ e = MPI(e)
+ _DLL.botan_pubkey_load_rsa(byref(obj), n.handle_(), e.handle_())
+ return PublicKey(obj)
+
+ @classmethod
+ def load_dsa(cls, p, q, g, y):
+ obj = c_void_p(0)
+ p = MPI(p)
+ q = MPI(q)
+ g = MPI(g)
+ y = MPI(y)
+ _DLL.botan_pubkey_load_dsa(byref(obj), p.handle_(), q.handle_(), g.handle_(), y.handle_())
+ return PublicKey(obj)
+
+ @classmethod
+ def load_dh(cls, p, g, y):
+ obj = c_void_p(0)
+ p = MPI(p)
+ g = MPI(g)
+ y = MPI(y)
+ _DLL.botan_pubkey_load_dh(byref(obj), p.handle_(), g.handle_(), y.handle_())
+ return PublicKey(obj)
+
+ @classmethod
+ def load_elgamal(cls, p, q, g, y):
+ obj = c_void_p(0)
+ p = MPI(p)
+ q = MPI(q)
+ g = MPI(g)
+ y = MPI(y)
+ _DLL.botan_pubkey_load_elgamal(byref(obj), p.handle_(), q.handle_(), g.handle_(), y.handle_())
+ return PublicKey(obj)
+
+ @classmethod
+ def load_ecdsa(cls, curve, pub_x, pub_y):
+ obj = c_void_p(0)
+ pub_x = MPI(pub_x)
+ pub_y = MPI(pub_y)
+ _DLL.botan_pubkey_load_ecdsa(byref(obj), pub_x.handle_(), pub_y.handle_(), _ctype_str(curve))
+ return PublicKey(obj)
+
+ @classmethod
+ def load_ecdh(cls, curve, pub_x, pub_y):
+ obj = c_void_p(0)
+ pub_x = MPI(pub_x)
+ pub_y = MPI(pub_y)
+ _DLL.botan_pubkey_load_ecdh(byref(obj), pub_x.handle_(), pub_y.handle_(), _ctype_str(curve))
+ return PublicKey(obj)
+
+ @classmethod
+ def load_sm2(cls, curve, pub_x, pub_y):
+ obj = c_void_p(0)
+ pub_x = MPI(pub_x)
+ pub_y = MPI(pub_y)
+ _DLL.botan_pubkey_load_sm2(byref(obj), pub_x.handle_(), pub_y.handle_(), _ctype_str(curve))
+ return PublicKey(obj)
+
def __del__(self):
_DLL.botan_pubkey_destroy(self.__obj)
def handle_(self):
return self.__obj
+ def check_key(self, rng_obj, strong=True):
+ flags = 1 if strong else 0
+ rc = _DLL.botan_pubkey_check_key(self.__obj, rng_obj.handle_(), flags)
+ return rc == 0
+
def estimated_strength(self):
r = c_size_t(0)
_DLL.botan_pubkey_estimated_strength(self.__obj, byref(r))
@@ -866,7 +950,6 @@ class PublicKey(object): # pylint: disable=invalid-name
return self.export(True)
def fingerprint(self, hash_algorithm='SHA-256'):
-
n = HashFunction(hash_algorithm).output_length()
buf = create_string_buffer(n)
buf_len = c_size_t(n)
@@ -874,6 +957,11 @@ class PublicKey(object): # pylint: disable=invalid-name
_DLL.botan_pubkey_fingerprint(self.__obj, _ctype_str(hash_algorithm), buf, byref(buf_len))
return _hex_encode(buf[0:int(buf_len.value)])
+ def get_field(self, field_name):
+ v = MPI()
+ _DLL.botan_pubkey_get_field(v.handle_(), self.__obj, _ctype_str(field_name))
+ return int(v)
+
#
# Private Key
#
@@ -896,14 +984,12 @@ class PrivateKey(object):
params = "%d" % (params)
elif algo == 'ecdsa':
algo = 'ECDSA'
- elif algo == 'ecdh':
-
+ elif algo in ['ecdh', 'ECDH']:
if params == 'curve25519':
algo = 'Curve25519'
params = ''
else:
algo = 'ECDH'
-
elif algo in ['mce', 'mceliece']:
algo = 'McEliece'
params = "%d,%d" % (params[0], params[1])
@@ -912,12 +998,76 @@ class PrivateKey(object):
_DLL.botan_privkey_create(byref(obj), _ctype_str(algo), _ctype_str(params), rng_obj.handle_())
return PrivateKey(obj)
+ @classmethod
+ def load_rsa(cls, p, q, e):
+ obj = c_void_p(0)
+ p = MPI(p)
+ q = MPI(q)
+ e = MPI(e)
+ _DLL.botan_privkey_load_rsa(byref(obj), p.handle_(), q.handle_(), e.handle_())
+ return PrivateKey(obj)
+
+ @classmethod
+ def load_dsa(cls, p, q, g, x):
+ obj = c_void_p(0)
+ p = MPI(p)
+ q = MPI(q)
+ g = MPI(g)
+ x = MPI(x)
+ _DLL.botan_privkey_load_dsa(byref(obj), p.handle_(), q.handle_(), g.handle_(), x.handle_())
+ return PrivateKey(obj)
+
+ @classmethod
+ def load_dh(cls, p, g, x):
+ obj = c_void_p(0)
+ p = MPI(p)
+ g = MPI(g)
+ x = MPI(x)
+ _DLL.botan_privkey_load_dh(byref(obj), p.handle_(), g.handle_(), x.handle_())
+ return PrivateKey(obj)
+
+ @classmethod
+ def load_elgamal(cls, p, q, g, x):
+ obj = c_void_p(0)
+ p = MPI(p)
+ q = MPI(q)
+ g = MPI(g)
+ x = MPI(x)
+ _DLL.botan_privkey_load_elgamal(byref(obj), p.handle_(), q.handle_(), g.handle_(), x.handle_())
+ return PrivateKey(obj)
+
+ @classmethod
+ def load_ecdsa(cls, curve, x):
+ obj = c_void_p(0)
+ x = MPI(x)
+ _DLL.botan_privkey_load_ecdsa(byref(obj), x.handle_(), _ctype_str(curve))
+ return PrivateKey(obj)
+
+ @classmethod
+ def load_ecdh(cls, curve, x):
+ obj = c_void_p(0)
+ x = MPI(x)
+ _DLL.botan_privkey_load_ecdh(byref(obj), x.handle_(), _ctype_str(curve))
+ return PrivateKey(obj)
+
+ @classmethod
+ def load_sm2(cls, curve, x):
+ obj = c_void_p(0)
+ x = MPI(x)
+ _DLL.botan_privkey_load_sm2(byref(obj), x.handle_(), _ctype_str(curve))
+ return PrivateKey(obj)
+
def __del__(self):
_DLL.botan_privkey_destroy(self.__obj)
def handle_(self):
return self.__obj
+ def check_key(self, rng_obj, strong=True):
+ flags = 1 if strong else 0
+ rc = _DLL.botan_privkey_check_key(self.__obj, rng_obj.handle_(), flags)
+ return rc == 0
+
def algo_name(self):
return _call_fn_returning_str(32, lambda b, bl: _DLL.botan_privkey_algo_name(self.__obj, b, bl))
@@ -938,6 +1088,25 @@ class PrivateKey(object):
else:
return _call_fn_returning_vec(4096, lambda b, bl: _DLL.botan_privkey_export(self.__obj, b, bl, 0))
+ def export_encrypted(self, passphrase, rng_obj, pem=False, msec=300, cipher=None, pbkdf=None):
+ flags = 1 if pem else 0
+ msec = c_uint32(msec)
+ _iters = c_size_t(0)
+
+ cb = lambda b, bl: _DLL.botan_privkey_export_encrypted_pbkdf_msec(
+ self.__obj, b, bl, rng_obj.handle_(), _ctype_str(passphrase),
+ msec, byref(_iters), _ctype_str(cipher), _ctype_str(pbkdf), flags)
+
+ if pem:
+ return _call_fn_returning_str(8192, cb)
+ else:
+ return _call_fn_returning_vec(4096, cb)
+
+ def get_field(self, field_name):
+ v = MPI()
+ _DLL.botan_privkey_get_field(v.handle_(), self.__obj, _ctype_str(field_name))
+ return int(v)
+
class PKEncrypt(object):
def __init__(self, key, padding):
self.__obj = c_void_p(0)
@@ -1023,7 +1192,14 @@ class PKKeyAgreement(object):
def public_value(self):
return self.m_public_value
+ def underlying_output_length(self):
+ out_len = c_size_t(0)
+ _DLL.botan_pk_op_key_agreement_size(self.__obj, byref(out_len))
+ return out_len.value
+
def agree(self, other, key_len, salt):
+ if key_len == 0:
+ key_len = self.underlying_output_length()
return _call_fn_returning_vec(key_len, lambda b, bl:
_DLL.botan_pk_op_key_agreement(self.__obj, b, bl,
other, len(other),
@@ -1201,6 +1377,14 @@ class MPI(object):
else:
return s
+ def to_bytes(self):
+ byte_count = self.byte_count()
+ out_len = c_size_t(byte_count)
+ out = create_string_buffer(out_len.value)
+ _DLL.botan_mp_to_bin(self.__obj, out, byref(out_len))
+ assert out_len.value == byte_count
+ return out
+
def is_negative(self):
rc = _DLL.botan_mp_is_negative(self.__obj)
return rc == 1
diff --git a/src/scripts/test_python.py b/src/scripts/test_python.py
index 1ba21f570..9cba9a4ea 100644
--- a/src/scripts/test_python.py
+++ b/src/scripts/test_python.py
@@ -25,6 +25,17 @@ class BotanPythonTests(unittest.TestCase):
self.assertEqual(botan2.version_major(), 2)
self.assertTrue(botan2.version_minor() >= 8)
+ self.assertTrue(botan2.ffi_api_version() >= 20180713)
+
+ def test_compare(self):
+
+ x = "1234"
+ y = "1234"
+ z = "1233"
+ self.assertTrue(botan2.const_time_compare(x, y))
+ self.assertFalse(botan2.const_time_compare(x, z))
+ self.assertFalse(botan2.const_time_compare(x, x + z))
+
def test_block_cipher(self):
aes = botan2.BlockCipher("AES-128")
self.assertEqual(aes.algo_name(), "AES-128")
@@ -181,7 +192,7 @@ class BotanPythonTests(unittest.TestCase):
def test_mceliece(self):
rng = botan2.RandomNumberGenerator()
- mce_priv = botan2.PrivateKey.create('mce', [2960, 57], rng)
+ mce_priv = botan2.PrivateKey.create('McEliece', '2960,57', rng)
mce_pub = mce_priv.get_public_key()
self.assertEqual(mce_pub.estimated_strength(), 128)
@@ -231,6 +242,38 @@ ofvkP1EDmpx50fHLawIDAQAB
rsapub = botan2.PublicKey.load(rsa_pub_pem)
self.assertEqual(rsapub.to_pem(), rsa_pub_pem)
+ n = 0xB5AD8818DCA1F256FF8FAB0888D0667D95DF2098B0D201A4C75590D3EBDFA159DD91C64AFDA082609EF885B2D1F4DC055C8FF9FA371C2F3398E0B612C603151131C81DB322C8D15E53EB56B4DF7325F05046889CB25021DE4282E16B9B28F5CBB2B8DDECE0F8E4E8A77F674F26AE92B7220920A1FBE43F51039A9C79D1F1CB6B
+ e = 0x10001
+
+ rsapub2 = botan2.PublicKey.load_rsa(n, e)
+ self.assertEqual(rsapub2.to_pem(), rsa_pub_pem)
+
+ self.assertEqual(rsapub2.get_field("n"), n)
+ self.assertEqual(rsapub2.get_field("e"), e)
+
+ def test_key_crypto(self):
+ rng = botan2.RandomNumberGenerator()
+ rsapriv = botan2.PrivateKey.create('RSA', '1024', rng)
+ passphrase = "super secret tell noone"
+
+ pem = rsapriv.export_encrypted(passphrase, rng, True, msec=10)
+ pem2 = rsapriv.export_encrypted(passphrase, rng, True, msec=10, cipher="AES-128/SIV")
+ pem3 = rsapriv.export_encrypted(passphrase, rng, True, msec=10, cipher="AES-128/SIV", pbkdf="Scrypt")
+
+ def test_check_key(self):
+ # valid (if rather small) RSA key
+ n = 273279220906618527352827457840955116141
+ e = 0x10001
+
+ rng = botan2.RandomNumberGenerator()
+
+ rsapub = botan2.PublicKey.load_rsa(n, e)
+ self.assertTrue(rsapub.check_key(rng))
+
+ # invalid
+ rsapub = botan2.PublicKey.load_rsa(n - 1, e)
+ self.assertFalse(rsapub.check_key(rng))
+
def test_rsa(self):
# pylint: disable=too-many-locals
rng = botan2.RandomNumberGenerator()
@@ -282,28 +325,74 @@ ofvkP1EDmpx50fHLawIDAQAB
verify.update('message')
self.assertTrue(verify.check_signature(sig))
- def test_dh(self):
+ def test_ecdsa(self):
+ rng = botan2.RandomNumberGenerator()
+
+ hash = 'EMSA1(SHA-256)'
+ group = 'secp256r1'
+ msg = 'test message'
+
+ priv = botan2.PrivateKey.create('ECDSA', group, rng)
+ pub = priv.get_public_key()
+ self.assertEqual(pub.get_field('public_x'), priv.get_field('public_x'))
+ self.assertEqual(pub.get_field('public_y'), priv.get_field('public_y'))
+
+ signer = botan2.PKSign(priv, hash)
+ signer.update(msg)
+ signature = signer.finish(rng)
+
+ verifier = botan2.PKVerify(pub, hash)
+ verifier.update(msg)
+ self.assertTrue(verifier.check_signature(signature))
+
+ pub_x = pub.get_field('public_x')
+ pub_y = priv.get_field('public_y')
+ pub2 = botan2.PublicKey.load_ecdsa(group, pub_x, pub_y)
+ verifier = botan2.PKVerify(pub2, hash)
+ verifier.update(msg)
+ self.assertTrue(verifier.check_signature(signature))
+
+ priv2 = botan2.PrivateKey.load_ecdsa(group, priv.get_field('x'))
+ signer = botan2.PKSign(priv2, hash)
+ # sign empty message
+ signature = signer.finish(rng)
+
+ # verify empty message
+ self.assertTrue(verifier.check_signature(signature))
+
+
+ def test_ecdh(self):
a_rng = botan2.RandomNumberGenerator('user')
b_rng = botan2.RandomNumberGenerator('user')
- for dh_grp in ['secp256r1', 'curve25519']:
- dh_kdf = 'KDF2(SHA-384)'.encode('utf-8')
- a_dh_priv = botan2.PrivateKey.create('ecdh', dh_grp, a_rng)
- b_dh_priv = botan2.PrivateKey.create('ecdh', dh_grp, b_rng)
+ # XXX why need the encode here?? should be handled in wrapper
+ kdf = 'KDF2(SHA-384)'.encode('utf-8')
+
+ for grp in ['secp256r1', 'secp384r1', 'brainpool256r1']:
+ a_priv = botan2.PrivateKey.create('ECDH', grp, a_rng)
+ b_priv = botan2.PrivateKey.create('ECDH', grp, b_rng)
- a_dh = botan2.PKKeyAgreement(a_dh_priv, dh_kdf)
- b_dh = botan2.PKKeyAgreement(b_dh_priv, dh_kdf)
+ a_op = botan2.PKKeyAgreement(a_priv, kdf)
+ b_op = botan2.PKKeyAgreement(b_priv, kdf)
- a_dh_pub = a_dh.public_value()
- b_dh_pub = b_dh.public_value()
+ a_pub = a_op.public_value()
+ b_pub = b_op.public_value()
salt = a_rng.get(8) + b_rng.get(8)
- a_key = a_dh.agree(b_dh_pub, 32, salt)
- b_key = b_dh.agree(a_dh_pub, 32, salt)
+ a_key = a_op.agree(b_pub, 32, salt)
+ b_key = b_op.agree(a_pub, 32, salt)
self.assertEqual(a_key, b_key)
+ a_pem = a_priv.to_pem()
+
+ a_priv_x = a_priv.get_field('x')
+
+ new_a = botan2.PrivateKey.load_ecdh(grp, a_priv_x)
+
+ self.assertEqual(a_pem, new_a.to_pem())
+
def test_certs(self):
cert = botan2.X509Cert(filename="src/tests/data/x509/ecc/CSCA.CSCA.csca-germany.1.crt")
pubkey = cert.subject_public_key()
@@ -336,6 +425,9 @@ ofvkP1EDmpx50fHLawIDAQAB
self.assertEqual(big.bit_count(), 104)
small = botan2.MPI(0xDEADBEEF)
+ self.assertEqual(hex_encode(small.to_bytes()), "deadbeef")
+ self.assertEqual(hex_encode(big.to_bytes()), "85839682368923476892367235")
+
self.assertEqual(int(small), 0xDEADBEEF)
self.assertEqual(int(small >> 16), 0xDEAD)
diff --git a/src/tests/test_ffi.cpp b/src/tests/test_ffi.cpp
index f2926d777..6263999d9 100644
--- a/src/tests/test_ffi.cpp
+++ b/src/tests/test_ffi.cpp
@@ -7,6 +7,8 @@
* Botan is released under the Simplified BSD License (see license.txt)
*/
+#define BOTAN_NO_DEPRECATED_WARNINGS
+
#include "tests.h"
#include <botan/version.h>