aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJack Lloyd <[email protected]>2015-10-20 16:19:11 -0400
committerJack Lloyd <[email protected]>2015-10-20 16:19:11 -0400
commit514474b98ccdfa6c0f76576c0ebfbec2af637d81 (patch)
treed911b1e8294fad454dd8891aa9dcd25939f85a4f
parent194d7d3682bddbd534e211357dd5f817d01ab7ed (diff)
Fix botan.py for Python3
Remove any need for callers to do version checks or encode values specially to handle Python2 vs Python3 ctypes differences. API users shouldn't have to care about that - encapsulate the differences in a few functions for handling the conversions. Add botan_cipher_query_keylen to ffi
-rw-r--r--src/lib/ffi/ffi.cpp10
-rw-r--r--src/lib/ffi/ffi.h4
-rw-r--r--src/lib/ffi/info.txt2
-rwxr-xr-xsrc/python/botan.py500
4 files changed, 270 insertions, 246 deletions
diff --git a/src/lib/ffi/ffi.cpp b/src/lib/ffi/ffi.cpp
index eb30b4831..7ed279bbd 100644
--- a/src/lib/ffi/ffi.cpp
+++ b/src/lib/ffi/ffi.cpp
@@ -429,6 +429,16 @@ int botan_cipher_clear(botan_cipher_t cipher)
return BOTAN_FFI_DO(Botan::Cipher_Mode, cipher, { cipher.clear(); });
}
+int botan_cipher_query_keylen(botan_cipher_t cipher,
+ size_t* out_minimum_keylength,
+ size_t* out_maximum_keylength)
+ {
+ return BOTAN_FFI_DO(Botan::Cipher_Mode, cipher, {
+ *out_minimum_keylength = cipher.key_spec().minimum_keylength();
+ *out_maximum_keylength = cipher.key_spec().maximum_keylength();
+ });
+ }
+
int botan_cipher_set_key(botan_cipher_t cipher,
const uint8_t* key, size_t key_len)
{
diff --git a/src/lib/ffi/ffi.h b/src/lib/ffi/ffi.h
index ce2253725..2def4f4d5 100644
--- a/src/lib/ffi/ffi.h
+++ b/src/lib/ffi/ffi.h
@@ -220,6 +220,10 @@ BOTAN_DLL int botan_cipher_get_tag_length(botan_cipher_t cipher, size_t* tag_siz
BOTAN_DLL int botan_cipher_get_default_nonce_length(botan_cipher_t cipher, size_t* nl);
BOTAN_DLL int botan_cipher_get_update_granularity(botan_cipher_t cipher, size_t* ug);
+BOTAN_DLL int botan_cipher_query_keylen(botan_cipher_t,
+ size_t* out_minimum_keylength,
+ size_t* out_maximum_keylength);
+
BOTAN_DLL int botan_cipher_set_key(botan_cipher_t cipher,
const uint8_t* key, size_t key_len);
diff --git a/src/lib/ffi/info.txt b/src/lib/ffi/info.txt
index 4018e4064..7c8968ff0 100644
--- a/src/lib/ffi/info.txt
+++ b/src/lib/ffi/info.txt
@@ -1,4 +1,4 @@
-define FFI 20151001
+define FFI 20151015
<requires>
aead
diff --git a/src/python/botan.py b/src/python/botan.py
index 04e574746..f15d892c6 100755
--- a/src/python/botan.py
+++ b/src/python/botan.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python2
+#!/usr/bin/env python
"""
Python wrapper of the botan crypto library
@@ -14,7 +14,6 @@ import sys
from ctypes import *
from binascii import hexlify, unhexlify
-
"""
Module initialization
"""
@@ -23,14 +22,14 @@ if sys.platform == 'darwin':
else:
botan = CDLL('libbotan-1.11.so')
-expected_api_rev = 20150210
+expected_api_rev = 20151015
botan_api_rev = botan.botan_ffi_api_version()
if botan_api_rev != expected_api_rev:
raise Exception("Bad botan API rev got %d expected %d" % (botan_api_rev, expected_api_rev))
# Internal utilities
-def _call_fn_returning_string(guess, fn):
+def _call_fn_returning_vec(guess, fn):
buf = create_string_buffer(guess)
buf_len = c_size_t(len(buf))
@@ -39,29 +38,49 @@ def _call_fn_returning_string(guess, fn):
if rc < 0:
if buf_len.value > len(buf):
#print("Calling again with %d" % (buf_len.value))
- return _call_fn_returning_string(buf_len.value, fn)
+ return _call_fn_returning_vec(buf_len.value, fn)
else:
raise Exception("Call failed: %d" % (rc))
assert buf_len.value <= len(buf)
- return str(buf.raw[0:buf_len.value])
-
-def _call_fn_returning_vec(guess, fn):
+ return buf.raw[0:buf_len.value]
- buf = create_string_buffer(guess)
- buf_len = c_size_t(len(buf))
+def _call_fn_returning_string(guess, fn):
+ # Assumes that anything called with this is returning plain ASCII strings
+ # (base64 data, algorithm names, etc)
+ v = _call_fn_returning_vec(guess, fn)
+ return v.decode('ascii')[:-1]
+
+def _ctype_str(s):
+ assert(type(s) == type(""))
+ if sys.version_info[0] < 3:
+ return s
+ else:
+ return s.encode('utf-8')
- rc = fn(buf, byref(buf_len))
- if rc < 0:
- if buf_len.value > len(buf):
- #print("Calling again with %d" % (buf_len.value))
- return _call_fn_returning_vec(buf_len.value, fn)
+def _ctype_bits(s):
+ # TODO typecheck for bytes in python3?
+ if sys.version_info[0] < 3:
+ return s
+ else:
+ if isinstance(s, bytes):
+ return s
+ elif isinstance(s, str):
+ return s.encode('utf-8') # FIXME
else:
- raise Exception("Call failed: %d" % (rc))
+ assert False
- assert buf_len.value <= len(buf)
- return buf.raw[0:buf_len.value]
+def _ctype_bufout(buf):
+ if sys.version_info[0] < 3:
+ return str(buf.raw)
+ else:
+ return buf.raw
+
+def hex_encode(buf):
+ return hexlify(buf).decode('ascii')
+def hex_decode(buf):
+ return unhexlify(buf)
"""
Versions
@@ -77,7 +96,7 @@ def version_patch():
def version_string():
botan.botan_version_string.restype = c_char_p
- return botan.botan_version_string()
+ return botan.botan_version_string().decode('ascii')
"""
RNG
@@ -87,11 +106,7 @@ class rng(object):
def __init__(self, rng_type = 'system'):
botan.botan_rng_init.argtypes = [c_void_p, c_char_p]
self.rng = c_void_p(0)
- if sys.version_info[0] < 3:
- rc = botan.botan_rng_init(byref(self.rng), rng_type)
- else:
- rc = botan.botan_rng_init(byref(self.rng), rng_type.encode('ascii'))
-
+ rc = botan.botan_rng_init(byref(self.rng), _ctype_str(rng_type))
if rc != 0 or self.rng is None:
raise Exception("No rng " + algo + " for you!")
@@ -108,10 +123,7 @@ class rng(object):
out = create_string_buffer(length)
l = c_size_t(length)
rc = botan.botan_rng_get(self.rng, out, l)
- if sys.version_info[0] < 3:
- return str(out.raw)
- else:
- return out.raw
+ return _ctype_bufout(out)
"""
Hash function
@@ -121,10 +133,7 @@ class hash_function(object):
botan.botan_hash_init.argtypes = [c_void_p, c_char_p, c_uint32]
flags = c_uint32(0) # always zero in this API version
self.hash = c_void_p(0)
- if sys.version_info[0] < 3:
- rc = botan.botan_hash_init(byref(self.hash), algo, flags)
- else:
- rc = botan.botan_hash_init(byref(self.hash), algo.encode('utf-8'), flags)
+ rc = botan.botan_hash_init(byref(self.hash), _ctype_str(algo), flags)
if rc != 0 or self.hash is None:
raise Exception("No hash " + algo + " for you!")
@@ -144,16 +153,13 @@ class hash_function(object):
def update(self, x):
botan.botan_hash_update.argtypes = [c_void_p, POINTER(c_char), c_size_t]
- botan.botan_hash_update(self.hash, x, len(x))
+ botan.botan_hash_update(self.hash, _ctype_bits(x), len(x))
def final(self):
botan.botan_hash_final.argtypes = [c_void_p, POINTER(c_char)]
out = create_string_buffer(self.output_length())
botan.botan_hash_final(self.hash, out)
- if sys.version_info[0] < 3:
- return str(out.raw)
- else:
- return out.raw
+ return _ctype_bufout(out)
"""
Message authentication codes
@@ -163,7 +169,7 @@ class message_authentication_code(object):
botan.botan_mac_init.argtypes = [c_void_p, c_char_p, c_uint32]
flags = c_uint32(0) # always zero in this API version
self.mac = c_void_p(0)
- rc = botan.botan_mac_init(byref(self.mac), algo, flags)
+ rc = botan.botan_mac_init(byref(self.mac), _ctype_str(algo), flags)
if rc != 0 or self.mac is None:
raise Exception("No mac " + algo + " for you!")
@@ -193,20 +199,14 @@ class message_authentication_code(object):
botan.botan_mac_final.argtypes = [c_void_p, POINTER(c_char)]
out = create_string_buffer(self.output_length())
botan.botan_mac_final(self.mac, out)
- if sys.version_info[0] < 3:
- return str(out.raw)
- else:
- return out.raw
+ return _ctype_bufout(out)
class cipher(object):
def __init__(self, algo, encrypt = True):
botan.botan_cipher_init.argtypes = [c_void_p,c_char_p, c_uint32]
flags = 0 if encrypt else 1
self.cipher = c_void_p(0)
- if sys.version_info[0] < 3:
- rc = botan.botan_cipher_init(byref(self.cipher), algo, flags)
- else:
- rc = botan.botan_cipher_init(byref(self.cipher), algo.encode('utf-8'), flags)
+ rc = botan.botan_cipher_init(byref(self.cipher), _ctype_str(algo), flags)
if rc != 0 or self.cipher is None:
raise Exception("No cipher " + algo + " for you!")
@@ -226,6 +226,12 @@ class cipher(object):
botan.botan_cipher_get_update_granularity(self.cipher, byref(l))
return l.value
+ def key_length(self):
+ kmin = c_size_t(0)
+ kmax = c_size_t(0)
+ botan.botan_cipher_query_keylen(self.cipher, byref(kmin), byref(kmax))
+ return kmin.value, kmax.value
+
def tag_length(self):
botan.botan_cipher_get_tag_length.argtypes = [c_void_p, POINTER(c_size_t)]
l = c_size_t(0)
@@ -265,8 +271,6 @@ class cipher(object):
inp = txt if txt else ''
inp_sz = c_size_t(len(inp))
- if sys.version_info[0] >= 3:
- inp = cast(inp, c_char_p)
inp_consumed = c_size_t(0)
out = create_string_buffer(inp_sz.value + (self.tag_length() if final else 0))
out_sz = c_size_t(len(out))
@@ -275,7 +279,7 @@ class cipher(object):
botan.botan_cipher_update(self.cipher, flags,
out, out_sz, byref(out_written),
- inp, inp_sz, byref(inp_consumed))
+ cast(inp, c_char_p), inp_sz, byref(inp_consumed))
# buffering not supported yet
assert inp_consumed.value == inp_sz.value
@@ -315,7 +319,7 @@ PBKDF
def pbkdf(algo, password, out_len, iterations = 10000, salt = rng().get(12)):
botan.botan_pbkdf.argtypes = [c_char_p, POINTER(c_char), c_size_t, c_char_p, c_void_p, c_size_t, c_size_t]
out_buf = create_string_buffer(out_len)
- botan.botan_pbkdf(algo, out_buf, out_len, password, salt, len(salt), iterations)
+ botan.botan_pbkdf(_ctype_str(algo), out_buf, out_len, _ctype_str(password), salt, len(salt), iterations)
return (salt,iterations,out_buf.raw)
def pbkdf_timed(algo, password, out_len, ms_to_run = 300, salt = rng().get(12)):
@@ -323,7 +327,7 @@ def pbkdf_timed(algo, password, out_len, ms_to_run = 300, salt = rng().get(12)):
c_void_p, c_size_t, c_size_t, POINTER(c_size_t)]
out_buf = create_string_buffer(out_len)
iterations = c_size_t(0)
- botan.botan_pbkdf_timed(algo, out_buf, out_len, password, salt, len(salt), ms_to_run, byref(iterations))
+ botan.botan_pbkdf_timed(_ctype_str(algo), out_buf, out_len, _ctype_str(password), salt, len(salt), ms_to_run, byref(iterations))
return (salt,iterations.value,out_buf.raw)
"""
@@ -333,7 +337,7 @@ def kdf(algo, secret, out_len, salt):
botan.botan_kdf.argtypes = [c_char_p, POINTER(c_char), c_size_t, POINTER(c_char), c_size_t, POINTER(c_char), c_size_t]
out_buf = create_string_buffer(out_len)
out_sz = c_size_t(out_len)
- botan.botan_kdf(algo, out_buf, out_sz, secret, len(secret), salt, len(salt))
+ botan.botan_kdf(_ctype_str(algo), out_buf, out_sz, secret, len(secret), salt, len(salt))
return out_buf.raw[0:out_sz.value]
"""
@@ -359,13 +363,8 @@ class public_key(object):
def encoding(self, pem = False):
botan.botan_pubkey_export.argtypes = [c_void_p, POINTER(c_char), POINTER(c_size_t), c_uint32]
-
flag = 1 if pem else 0
-
- if pem:
- return _call_fn_returning_string(0, lambda b,bl: botan.botan_pubkey_export(self.pubkey, b, bl, 1))
- else:
- return _call_fn_returning_string(0, lambda b,bl: botan.botan_pubkey_export(self.pubkey, b, bl, 0))
+ return _call_fn_returning_vec(0, lambda b,bl: botan.botan_pubkey_export(self.pubkey, b, bl, flag))
def fingerprint(self, hash = 'SHA-256'):
botan.botan_pubkey_fingerprint.argtypes = [c_void_p, c_char_p,
@@ -374,11 +373,9 @@ class public_key(object):
n = hash_function(hash).output_length()
buf = create_string_buffer(n)
buf_len = c_size_t(n)
- if sys.version_info[0] > 2:
- hash = hash.encode('utf-8')
- botan.botan_pubkey_fingerprint(self.pubkey, hash, buf, byref(buf_len))
- return hexlify(buf[0:buf_len.value])
+ botan.botan_pubkey_fingerprint(self.pubkey, _ctype_str(hash), buf, byref(buf_len))
+ return hex_encode(buf[0:buf_len.value])
class private_key(object):
def __init__(self, alg, param, rng):
@@ -388,12 +385,13 @@ class private_key(object):
botan.botan_privkey_create_mceliece.argtypes = [c_void_p, c_void_p, c_size_t, c_size_t]
self.privkey = c_void_p(0)
+
if alg == 'rsa':
botan.botan_privkey_create_rsa(byref(self.privkey), rng.rng, param)
elif alg == 'ecdsa':
- botan.botan_privkey_create_ecdsa(byref(self.privkey), rng.rng, param)
+ botan.botan_privkey_create_ecdsa(byref(self.privkey), rng.rng, _ctype_str(param))
elif alg == 'ecdh':
- botan.botan_privkey_create_ecdh(byref(self.privkey), rng.rng, param)
+ botan.botan_privkey_create_ecdh(byref(self.privkey), rng.rng, _ctype_str(param))
elif alg in ['mce', 'mceliece']:
botan.botan_privkey_create_mceliece(byref(self.privkey), rng.rng, param[0], param[1])
else:
@@ -431,9 +429,8 @@ class pk_op_encrypt(object):
botan.botan_pk_op_encrypt_create.argtypes = [c_void_p, c_void_p, c_char_p, c_uint32]
self.op = c_void_p(0)
flags = c_uint32(0) # always zero in this ABI
- if sys.version_info[0] > 2:
- padding = cast(padding, c_char_p)
- botan.botan_pk_op_encrypt_create(byref(self.op), key.pubkey, padding, flags)
+ print("Padding is ", padding)
+ botan.botan_pk_op_encrypt_create(byref(self.op), key.pubkey, _ctype_str(padding), flags)
if not self.op:
raise Exception("No pk op for you")
@@ -450,9 +447,9 @@ class pk_op_encrypt(object):
outbuf = create_string_buffer(outbuf_sz.value)
ll = len(msg)
#print("encrypt: len=%d" % ll)
- if sys.version_info[0] > 2:
- msg = cast(msg, c_char_p)
- ll = c_size_t(ll)
+ #if sys.version_info[0] > 2:
+ # msg = cast(msg, c_char_p)
+ # ll = c_size_t(ll)
botan.botan_pk_op_encrypt(self.op, rng.rng, outbuf, byref(outbuf_sz), msg, ll)
#print("encrypt: outbuf_sz.value=%d" % outbuf_sz.value)
return outbuf.raw[0:outbuf_sz.value]
@@ -463,9 +460,7 @@ class pk_op_decrypt(object):
botan.botan_pk_op_decrypt_create.argtypes = [c_void_p, c_void_p, c_char_p, c_uint32]
self.op = c_void_p(0)
flags = c_uint32(0) # always zero in this ABI
- if sys.version_info[0] > 2:
- padding = cast(padding, c_char_p)
- botan.botan_pk_op_decrypt_create(byref(self.op), key.privkey, padding, flags)
+ botan.botan_pk_op_decrypt_create(byref(self.op), key.privkey, _ctype_str(padding), flags)
if not self.op:
raise Exception("No pk op for you")
@@ -481,10 +476,7 @@ class pk_op_decrypt(object):
outbuf_sz = c_size_t(4096) #?!?!
outbuf = create_string_buffer(outbuf_sz.value)
ll = len(msg)
- if sys.version_info[0] > 2:
- msg = cast(msg, c_char_p)
- ll = c_size_t(ll)
- botan.botan_pk_op_decrypt(self.op, outbuf, byref(outbuf_sz), msg, ll)
+ botan.botan_pk_op_decrypt(self.op, outbuf, byref(outbuf_sz), _ctype_bits(msg), ll)
return outbuf.raw[0:outbuf_sz.value]
class pk_op_sign(object):
@@ -492,9 +484,7 @@ class pk_op_sign(object):
botan.botan_pk_op_sign_create.argtypes = [c_void_p, c_void_p, c_char_p, c_uint32]
self.op = c_void_p(0)
flags = c_uint32(0) # always zero in this ABI
- if sys.version_info[0] > 2:
- padding = cast(padding, c_char_p)
- botan.botan_pk_op_sign_create(byref(self.op), key.privkey, padding, flags)
+ botan.botan_pk_op_sign_create(byref(self.op), key.privkey, _ctype_str(padding), flags)
if not self.op:
raise Exception("No pk op for you")
@@ -504,7 +494,7 @@ class pk_op_sign(object):
def update(self, msg):
botan.botan_pk_op_sign_update.argtypes = [c_void_p, POINTER(c_char), c_size_t]
- botan.botan_pk_op_sign_update(self.op, msg, len(msg))
+ botan.botan_pk_op_sign_update(self.op, _ctype_str(msg), len(msg))
def finish(self, rng):
botan.botan_pk_op_sign_finish.argtypes = [c_void_p, c_void_p, POINTER(c_char), POINTER(c_size_t)]
@@ -518,7 +508,7 @@ class pk_op_verify(object):
botan.botan_pk_op_verify_create.argtypes = [c_void_p, c_void_p, c_char_p, c_uint32]
self.op = c_void_p(0)
flags = c_uint32(0) # always zero in this ABI
- botan.botan_pk_op_verify_create(byref(self.op), key.pubkey, padding, flags)
+ botan.botan_pk_op_verify_create(byref(self.op), key.pubkey, _ctype_str(padding), flags)
if not self.op:
raise Exception("No pk op for you")
@@ -528,11 +518,11 @@ class pk_op_verify(object):
def update(self, msg):
botan.botan_pk_op_verify_update.argtypes = [c_void_p, POINTER(c_char), c_size_t]
- botan.botan_pk_op_verify_update(self.op, msg, len(msg))
+ botan.botan_pk_op_verify_update(self.op, _ctype_bits(msg), len(msg))
def check_signature(self, signature):
botan.botan_pk_op_verify_finish.argtypes = [c_void_p, POINTER(c_char), c_size_t]
- rc = botan.botan_pk_op_verify_finish(self.op, signature, len(signature))
+ rc = botan.botan_pk_op_verify_finish(self.op, _ctype_bits(signature), len(signature))
if rc == 0:
return True
return False
@@ -545,15 +535,31 @@ def mceies_encrypt(mce, rng, aead, pt, ad):
botan.botan_mceies_encrypt.argtypes = [c_void_p, c_void_p, c_char_p, POINTER(c_char), c_size_t,
POINTER(c_char), c_size_t, POINTER(c_char), POINTER(c_size_t)]
- return _call_fn_returning_string(0, lambda b,bl:
- botan.botan_mceies_encrypt(mce.pubkey, rng.rng, aead, pt, len(pt), ad, len(ad), b, bl))
+ return _call_fn_returning_vec(0, lambda b,bl:
+ botan.botan_mceies_encrypt(mce.pubkey,
+ rng.rng,
+ _ctype_str(aead),
+ _ctype_bits(pt),
+ len(pt),
+ _ctype_bits(ad),
+ len(ad),
+ b, bl))
def mceies_decrypt(mce, aead, pt, ad):
botan.botan_mceies_decrypt.argtypes = [c_void_p, c_char_p, POINTER(c_char), c_size_t,
POINTER(c_char), c_size_t, POINTER(c_char), POINTER(c_size_t)]
- return _call_fn_returning_string(0, lambda b,bl:
- botan.botan_mceies_decrypt(mce.privkey, aead, pt, len(pt), ad, len(ad), b, bl))
+ #msg = cast(msg, c_char_p)
+ #ll = c_size_t(ll)
+
+ return _call_fn_returning_vec(0, lambda b,bl:
+ botan.botan_mceies_decrypt(mce.privkey,
+ _ctype_str(aead),
+ _ctype_bits(pt),
+ len(pt),
+ _ctype_bits(ad),
+ len(ad),
+ b, bl))
class pk_op_key_agreement(object):
def __init__(self, key, kdf):
@@ -565,7 +571,7 @@ class pk_op_key_agreement(object):
if not self.op:
raise Exception("No key agreement for you")
- self.m_public_value = _call_fn_returning_string(0, lambda b, bl: botan.botan_pk_op_key_agreement_export_public(key.privkey, b, bl))
+ self.m_public_value = _call_fn_returning_vec(0, lambda b, bl: botan.botan_pk_op_key_agreement_export_public(key.privkey, b, bl))
def __del__(self):
botan.botan_pk_op_key_agreement_destroy.argtypes = [c_void_p]
@@ -578,18 +584,16 @@ class pk_op_key_agreement(object):
botan.botan_pk_op_key_agreement.argtypes = [c_void_p, POINTER(c_char), POINTER(c_size_t),
POINTER(c_char), c_size_t, POINTER(c_char), c_size_t]
- return _call_fn_returning_string(key_len,
- lambda b,bl: botan.botan_pk_op_key_agreement(self.op, b, bl,
- other, len(other),
- salt, len(salt)))
+ return _call_fn_returning_vec(key_len,
+ lambda b,bl: botan.botan_pk_op_key_agreement(self.op, b, bl,
+ other, len(other),
+ salt, len(salt)))
class x509_cert(object):
def __init__(self, filename):
botan.botan_x509_cert_load_file.argtypes = [POINTER(c_void_p), c_char_p]
self.x509_cert = c_void_p(0)
- if sys.version_info[0] > 2:
- filename = cast(filename, c_char_p)
- botan.botan_x509_cert_load_file(byref(self.x509_cert), filename)
+ botan.botan_x509_cert_load_file(byref(self.x509_cert), _ctype_str(filename))
def __del__(self):
botan.botan_x509_cert_destroy.argtypes = [c_void_p]
@@ -613,10 +617,7 @@ class x509_cert(object):
POINTER(c_char), POINTER(c_size_t)]
n = hash_function(hash_algo).output_length() * 3
- if sys.version_info[0] > 2:
- hash_algo = hash_algo.encode('utf-8')
-
- return _call_fn_returning_string(n, lambda b,bl: botan.botan_x509_cert_get_fingerprint(self.x509_cert, hash_algo, b, bl))
+ return _call_fn_returning_string(n, lambda b,bl: botan.botan_x509_cert_get_fingerprint(self.x509_cert, _ctype_str(hash_algo), b, bl))
def serial_number(self):
botan.botan_x509_cert_get_serial_number.argtypes = [c_void_p, POINTER(c_char), POINTER(c_size_t)]
@@ -640,199 +641,208 @@ Tests and examples
"""
def test():
- r = rng("user")
+ def test_version():
+ print("\n%s" % version_string())
+ print("v%d.%d.%d\n" % (version_major(), version_minor(), version_patch()))
- print("\n%s" % version_string().decode('utf-8'))
- print("v%d.%d.%d\n" % (version_major(), version_minor(), version_patch()))
+ def test_kdf():
+ print("KDF2(SHA-1) %s" %
+ hex_encode(kdf('KDF2(SHA-1)', hex_decode('701F3480DFE95F57941F804B1B2413EF'), 7,
+ hex_decode('55A4E9DD5F4CA2EF82'))))
- print("KDF2(SHA-1) %s" %
- hexlify(kdf('KDF2(SHA-1)'.encode('ascii'), unhexlify('701F3480DFE95F57941F804B1B2413EF'), 7,
- unhexlify('55A4E9DD5F4CA2EF82'))
- ).decode('ascii')
- )
+ def test_pbkdf():
+ print("PBKDF2(SHA-1) %s" %
+ hex_encode(pbkdf('PBKDF2(SHA-1)', '', 32, 10000, hex_decode('0001020304050607'))[2]))
+ print("good output %s\n" %
+ '59B2B1143B4CB1059EC58D9722FB1C72471E0D85C6F7543BA5228526375B0127')
- print("PBKDF2(SHA-1) %s" %
- hexlify(pbkdf('PBKDF2(SHA-1)'.encode('ascii'), ''.encode('ascii'), 32, 10000,
- unhexlify('0001020304050607'))
- [2]
- ).upper().decode('ascii'))
- print("good output %s\n" %
- '59B2B1143B4CB1059EC58D9722FB1C72471E0D85C6F7543BA5228526375B0127')
+ (salt,iterations,psk) = pbkdf_timed('PBKDF2(SHA-256)', 'xyz', 32, 200)
- (salt,iterations,psk) = pbkdf_timed('PBKDF2(SHA-256)'.encode('ascii'),
- 'xyz'.encode('utf-8'), 32, 200)
+ print("PBKDF2(SHA-256) x=timed, y=iterated; salt = %s (len=%d) #iterations = %d\n" %
+ (hex_encode(salt), len(salt), iterations))
- print("PBKDF2(SHA-256) x=timed, y=iterated; salt = %s (len=%d) #iterations = %d\n" %
- (hexlify(salt).decode('ascii'), len(salt), iterations))
+ print('x %s' % hex_encode(psk))
+ print('y %s\n' % (hex_encode(pbkdf('PBKDF2(SHA-256)', 'xyz', 32, iterations, salt)[2])))
- print('x %s' % hexlify(psk).decode('utf-8'))
- print('y %s\n' %
- (hexlify(pbkdf('PBKDF2(SHA-256)'.encode('utf-8'),
- 'xyz'.encode('ascii'), 32, iterations, salt)[2]).decode('utf-8')))
+ def test_hmac():
- hmac = message_authentication_code('HMAC(SHA-256)'.encode('ascii'))
- hmac.set_key(unhexlify('0102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F20'))
- hmac.update(unhexlify('616263'))
+ hmac = message_authentication_code('HMAC(SHA-256)')
+ hmac.set_key(hex_decode('0102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F20'))
+ hmac.update(hex_decode('616263'))
- hmac_output = hmac.final()
+ hmac_vec = hex_decode('A21B1F5D4CF4F73A4DD939750F7A066A7F98CC131CB16A6692759021CFAB8181')
+ hmac_output = hmac.final()
- if hmac_output != unhexlify('A21B1F5D4CF4F73A4DD939750F7A066A7F98CC131CB16A6692759021CFAB8181'):
- print("Bad HMAC:\t%s" % hexlify(bytes(hmac_output, 'utf-8')).decode('utf-8'))
- print("vs good: \tA21B1F5D4CF4F73A4DD939750F7A066A7F98CC131CB16A6692759021CFAB8181");
- else:
- print("HMAC output (good): %s\n" % hexlify(hmac_output).decode('utf-8'))
+ if hmac_output != hmac_vec:
+ print("Bad HMAC:\t%s" % hex_encode(hmac_output))
+ print("vs good: \t%s" % hex_encode(hmac_vec))
+ else:
+ print("HMAC output correct: %s\n" % hex_encode(hmac_output))
+
+ def test_rng():
+ user_rng = rng("user")
- print("rng output:\n\t%s\n\t%s\n\t%s\n" %
- (hexlify(r.get(42)).decode('utf-8'),
- hexlify(r.get(13)).decode('utf-8'),
- hexlify(r.get(9)).decode('utf-8')
- )
- )
+ print("rng output:\n\t%s\n\t%s\n\t%s\n" %
+ (hex_encode(user_rng.get(42)),
+ hex_encode(user_rng.get(13)),
+ hex_encode(user_rng.get(9))))
- h = hash_function('MD5')
- assert h.output_length() == 16
- h.update('h'.encode('utf-8'))
- h.update('i'.encode('utf-8'))
- print("md5 hash: %s\n" % (hexlify(h.final())).decode('utf-8'))
+ def test_hash():
+ md5 = hash_function('MD5')
+ assert md5.output_length() == 16
+ md5.update('h')
+ md5.update('i')
+ h1 = md5.final()
+ print("md5 hash: %s (%s)\n" % (hex_encode(h1), '49f68a5c8493ec2c0bf489821c21fc3b'))
+ md5.update(hex_decode('f468025b'))
+ h2 = md5.final()
+ print("md5 hash: %s (%s)\n" % (hex_encode(h2), '47efd2be302a937775e93dea281b6751'))
- gcm = cipher('AES-128/GCM')
- print("AES-128/GCM: default nonce=%d update_size=%d" %
- (gcm.default_nonce_length(), gcm.update_granularity()))
- gcm_dec = cipher('AES-128/GCM', encrypt=False)
+ def test_cipher():
+ for mode in ['AES-128/CTR-BE', 'Serpent/GCM', 'ChaCha20Poly1305']:
+ enc = cipher(mode, encrypt=True)
- iv = r.get(12)
- key = r.get(16)
- pt = r.get(21)
- gcm.set_key(key)
- gcm.start(iv)
- assert len(gcm.update('')) == 0
- ct = gcm.finish(pt)
- print("GCM ct %s" % hexlify(ct).decode('utf-8'))
+ (kmin,kmax) = enc.key_length()
+ print("%s: default nonce=%d update_size=%d key_min=%d key_max=%d" %
+ (mode, enc.default_nonce_length(), enc.update_granularity(), kmin, kmax))
+ iv = rng().get(enc.default_nonce_length())
+ key = rng().get(kmax)
+ pt = rng().get(21)
- gcm_dec.set_key(key)
- gcm_dec.start(iv)
- dec = gcm_dec.finish(ct)
- print("GCM pt %s %d" % (hexlify(pt).decode('utf-8'), len(pt)))
- print("GCM de %s %d\n" % (hexlify(dec).decode('utf-8'), len(dec)))
+ print(" plaintext %s %d" % (hex_encode(pt), len(pt)))
- ocb = cipher('AES-128/OCB')
- print("AES-128/OCB: default nonce=%d update_size=%d" %
- (ocb.default_nonce_length(), ocb.update_granularity()))
- ocb_dec = cipher('AES-128/OCB', encrypt=False)
+ enc.set_key(key)
+ enc.start(iv)
+ assert len(enc.update('')) == 0
+ ct = enc.finish(pt)
+ print(" ciphertext %s %d" % (hex_encode(ct), len(ct)))
- iv = r.get(12)
- key = r.get(16)
- pt = r.get(21)
- ocb.set_key(key)
- ocb.start(iv)
- assert len(ocb.update('')) == 0
- ct = ocb.finish(pt)
- print("OCB ct %s" % hexlify(ct).decode('utf-8'))
+ dec = cipher(mode, encrypt=False)
+ dec.set_key(key)
+ dec.start(iv)
+ decrypted = dec.finish(ct)
- ocb_dec.set_key(key)
- ocb_dec.start(iv)
- dec = ocb_dec.finish(ct)
- print("OCB pt %s %d" % (hexlify(pt).decode('utf-8'), len(pt)))
- print("OCB de %s %d\n" % (hexlify(dec).decode('utf-8'), len(dec)))
+ print(" decrypted %s %d\n" % (hex_encode(decrypted), len(decrypted)))
- mce_priv = private_key('mce', [2960,57], r)
- mce_pub = mce_priv.get_public_key()
+ def test_mceliece():
+ mce_priv = private_key('mce', [2960,57], rng())
+ mce_pub = mce_priv.get_public_key()
- mce_plaintext = 'mce plaintext'
- mce_ad = 'mce AD'
- mce_ciphertext = mceies_encrypt(mce_pub, r, 'ChaCha20Poly1305', mce_plaintext, mce_ad)
+ mce_plaintext = 'mce plaintext'
+ mce_ad = 'mce AD'
+ mce_ciphertext = mceies_encrypt(mce_pub, rng(), 'ChaCha20Poly1305', mce_plaintext, mce_ad)
- print "mce", len(mce_plaintext), len(mce_ciphertext)
+ print("mce", len(mce_plaintext), len(mce_ciphertext))
- mce_decrypt = mceies_decrypt(mce_priv, 'ChaCha20Poly1305', mce_ciphertext, mce_ad)
+ mce_decrypt = mceies_decrypt(mce_priv, 'ChaCha20Poly1305', mce_ciphertext, mce_ad)
- print("mce_pub %s/SHA-1 fingerprint: %s (estimated strength %s) (len %d)" %
- (mce_pub.algo_name().decode('utf-8'), mce_pub.fingerprint("SHA-1").decode('utf-8'),
- mce_pub.estimated_strength(), len(mce_pub.encoding())
- )
- )
+ print("mce_pub %s/SHA-1 fingerprint: %s (estimated strength %s) (len %d)" %
+ (mce_pub.algo_name(), mce_pub.fingerprint("SHA-1"),
+ mce_pub.estimated_strength(), len(mce_pub.encoding())
+ )
+ )
- rsapriv = private_key('rsa', 1536, r)
+ def test_rsa():
+ rsapriv = private_key('rsa', 1536, rng())
- rsapub = rsapriv.get_public_key()
+ rsapub = rsapriv.get_public_key()
- print("rsapub %s SHA-1 fingerprint: %s estimated strength %d len %d" %
- (rsapub.algo_name().decode('utf-8'), rsapub.fingerprint("SHA-1").decode('utf-8'),
- rsapub.estimated_strength(), len(rsapub.encoding())
- )
- )
+ print("rsapub %s SHA-1 fingerprint: %s estimated strength %d len %d" %
+ (rsapub.algo_name(), rsapub.fingerprint("SHA-1"),
+ rsapub.estimated_strength(), len(rsapub.encoding())
+ )
+ )
- dec = pk_op_decrypt(rsapriv, "EME1(SHA-256)".encode('utf-8'))
- enc = pk_op_encrypt(rsapub, "EME1(SHA-256)".encode('utf-8'))
+ dec = pk_op_decrypt(rsapriv, "EME1(SHA-256)")
+ enc = pk_op_encrypt(rsapub, "EME1(SHA-256)")
- ctext = enc.encrypt('foof'.encode('utf-8'), r)
- print("ptext \'%s\'" % 'foof')
- print("ctext \'%s\'" % hexlify(ctext).decode('utf-8'))
- print("decrypt \'%s\'\n" % dec.decrypt(ctext).decode('utf-8'))
+ sys_rng = rng()
+ symkey = sys_rng.get(32)
+ ctext = enc.encrypt(symkey, sys_rng)
+ print("ptext \'%s\'" % hex_encode(symkey))
+ print("ctext \'%s\'" % hex_encode(ctext))
+ print("decrypt \'%s\'\n" % hex_encode(dec.decrypt(ctext)))
- signer = pk_op_sign(rsapriv, 'EMSA4(SHA-384)'.encode('utf-8'))
+ signer = pk_op_sign(rsapriv, 'EMSA4(SHA-384)')
- signer.update('messa'.encode('utf-8'))
- signer.update('ge'.encode('utf-8'))
- sig = signer.finish(r)
+ signer.update('messa')
+ signer.update('ge')
+ sig = signer.finish(rng())
- r.reseed(200)
- print("EMSA4(SHA-384) signature: %s" % hexlify(sig).decode('utf-8'))
+ print("EMSA4(SHA-384) signature: %s" % hex_encode(sig))
+ verify = pk_op_verify(rsapub, 'EMSA4(SHA-384)')
- verify = pk_op_verify(rsapub, 'EMSA4(SHA-384)'.encode('utf-8'))
+ verify.update('mess')
+ verify.update('age')
+ print("good sig accepted? %s" % verify.check_signature(sig))
- verify.update('mess'.encode('utf-8'))
- verify.update('age'.encode('utf-8'))
- print("good sig accepted? %s" % verify.check_signature(sig))
+ verify.update('mess of things')
+ verify.update('age')
+ print("bad sig accepted? %s" % verify.check_signature(sig))
+
+ verify.update('message')
+ print("good sig accepted? %s\n" % verify.check_signature(sig))
- verify.update('mess of things'.encode('utf-8'))
- verify.update('age'.encode('utf-8'))
- print("bad sig accepted? %s" % verify.check_signature(sig))
+ def test_dh():
+ a_rng = rng('user')
+ b_rng = rng('user')
- verify.update('message'.encode('utf-8'))
- print("good sig accepted? %s\n" % verify.check_signature(sig))
+ for dh_grp in ['secp256r1', 'curve25519']:
+ dh_kdf = 'KDF2(SHA-384)'.encode('utf-8')
+ a_dh_priv = private_key('ecdh', dh_grp, rng())
+ a_dh_pub = a_dh_priv.get_public_key()
- for dh_grps in ['secp256r1', 'curve25519']:
- dh_grp = dh_grps.encode('utf-8')
- dh_kdf = 'KDF2(SHA-384)'.encode('utf-8')
- a_dh_priv = private_key('ecdh', dh_grp, r)
- a_dh_pub = a_dh_priv.get_public_key()
+ b_dh_priv = private_key('ecdh', dh_grp, rng())
+ b_dh_pub = b_dh_priv.get_public_key()
- b_dh_priv = private_key('ecdh', dh_grp, r)
- b_dh_pub = b_dh_priv.get_public_key()
+ a_dh = pk_op_key_agreement(a_dh_priv, dh_kdf)
+ b_dh = pk_op_key_agreement(b_dh_priv, dh_kdf)
- a_dh = pk_op_key_agreement(a_dh_priv, dh_kdf)
- b_dh = pk_op_key_agreement(b_dh_priv, dh_kdf)
+ a_salt = a_rng.get(8)
+ b_salt = b_rng.get(8)
- print("ecdh %s pubs:\n %s\n %s\n" %
- (dh_grps,
- hexlify(a_dh.public_value()).decode('utf-8'),
- hexlify(b_dh.public_value()).decode('utf-8')))
+ print("ecdh %s pubs:\n %s (salt %s)\n %s (salt %s)\n" %
+ (dh_grp,
+ hex_encode(a_dh.public_value()),
+ hex_encode(a_salt),
+ hex_encode(b_dh.public_value()),
+ hex_encode(b_salt)))
- a_key = a_dh.agree(b_dh.public_value(), 20, 'salt'.encode('utf-8'))
- b_key = b_dh.agree(a_dh.public_value(), 20, 'salt'.encode('utf-8'))
+ a_key = a_dh.agree(b_dh.public_value(), 32, a_salt + b_salt)
+ b_key = b_dh.agree(a_dh.public_value(), 32, a_salt + b_salt)
- print("ecdh %s shared:\n %s\n %s\n" %
- (dh_grps, hexlify(a_key).decode('utf-8'), hexlify(b_key).decode('utf-8')))
+ print("ecdh %s shared:\n %s\n %s\n" %
+ (dh_grp, hex_encode(a_key), hex_encode(b_key)))
- cert = x509_cert("src/tests/data/ecc/CSCA.CSCA.csca-germany.1.crt")
- print(cert.fingerprint("SHA-1"))
- print("32:42:1C:C3:EC:54:D7:E9:43:EC:51:F0:19:23:BD:85:1D:F2:1B:B9")
+ def test_certs():
+ cert = x509_cert("src/tests/data/ecc/CSCA.CSCA.csca-germany.1.crt")
+ print(cert.fingerprint("SHA-1"))
+ print("32:42:1C:C3:EC:54:D7:E9:43:EC:51:F0:19:23:BD:85:1D:F2:1B:B9")
- print(cert.time_starts())
- print(cert.time_expires())
+ print(cert.time_starts())
+ print(cert.time_expires())
- print(hexlify(cert.serial_number()))
- print(hexlify(cert.authority_key_id()))
- print(hexlify(cert.subject_key_id()))
- print(hexlify(cert.subject_public_key_bits()))
+ print(hex_encode(cert.serial_number()))
+ print(hex_encode(cert.authority_key_id()))
+ print(hex_encode(cert.subject_key_id()))
+ print(hex_encode(cert.subject_public_key_bits()))
- print(cert.to_string())
+ print(cert.to_string())
- return
+ test_version()
+ test_kdf()
+ test_pbkdf()
+ test_hmac()
+ test_rng()
+ test_hash()
+ test_cipher()
+ test_mceliece()
+ test_rsa()
+ test_dh()
+ test_certs()
def main(args = None):