diff --git a/src/wolfcrypt/_build_ffi.py b/src/wolfcrypt/_build_ffi.py index a9eb210..532c180 100644 --- a/src/wolfcrypt/_build_ffi.py +++ b/src/wolfcrypt/_build_ffi.py @@ -61,6 +61,7 @@ ECC_ENABLED = 1 ED25519_ENABLED = 1 KEYGEN_ENABLED = 1 CHACHA_ENABLED = 1 +PWDBASED_ENABLED = 0 # detect native features based on options.h defines if featureDetection == 1: @@ -134,6 +135,8 @@ if featureDetection == 1: else: KEYGEN_ENABLED = 0 + PWDBASED_ENABLED = 0 if '#define NO_PWDBASED' in optionsHeaderStr else 1 + # build cffi module, wrapping native wolfSSL ffibuilder = FFI() @@ -177,7 +180,7 @@ ffibuilder.set_source( int ECC_ENABLED = """ + str(ECC_ENABLED) + """; int ED25519_ENABLED = """ + str(ED25519_ENABLED) + """; int KEYGEN_ENABLED = """ + str(KEYGEN_ENABLED) + """; - + int PWDBASED_ENABLED = """ + str(PWDBASED_ENABLED) + """; """, include_dirs=[wolfssl_inc_path()], library_dirs=[wolfssl_lib_path()], @@ -199,6 +202,7 @@ _cdef = """ int ECC_ENABLED; int ED25519_ENABLED; int KEYGEN_ENABLED; + int PWDBASED_ENABLED; typedef unsigned char byte; typedef unsigned int word32; @@ -417,6 +421,13 @@ if (ED25519_ENABLED == 1): int wc_ed25519_priv_size(ed25519_key* key); """ +if PWDBASED_ENABLED: + _cdef += """ + int wc_PBKDF2(byte* output, const byte* passwd, int pLen, + const byte* salt, int sLen, int iterations, int kLen, + int typeH); + """ + ffibuilder.cdef(_cdef) if __name__ == "__main__": diff --git a/src/wolfcrypt/pwdbased.py b/src/wolfcrypt/pwdbased.py new file mode 100644 index 0000000..5d536a9 --- /dev/null +++ b/src/wolfcrypt/pwdbased.py @@ -0,0 +1,43 @@ +# pwdbased.py +# +# Copyright (C) 2006-2020 wolfSSL Inc. +# +# This file is part of wolfSSL. (formerly known as CyaSSL) +# +# wolfSSL is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# wolfSSL is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + +# pylint: disable=no-member,no-name-in-module + +from wolfcrypt._ffi import ffi as _ffi +from wolfcrypt._ffi import lib as _lib + +from wolfcrypt.exceptions import WolfCryptError + +if _lib.PWDBASED_ENABLED: + def PBKDF2(password, salt, iterations, key_length, hash_type): + if isinstance(salt, str): + salt = str.encode(salt) + + if isinstance(password, str): + password = str.encode(password) + + key = _ffi.new("byte[%d]" %key_length) + ret = _lib.wc_PBKDF2(key, password, len(password), salt, len(salt), + iterations, key_length, hash_type) + + if ret != 0: + raise WolfCryptError("PBKDF2 error (%d)" % ret) + + return _ffi.buffer(key, key_length)[:] diff --git a/tests/test_pwdbased.py b/tests/test_pwdbased.py new file mode 100644 index 0000000..9cb8372 --- /dev/null +++ b/tests/test_pwdbased.py @@ -0,0 +1,36 @@ +from collections import namedtuple +import pytest +from wolfcrypt._ffi import lib as _lib + +if _lib.PWDBASED_ENABLED: + from wolfcrypt.pwdbased import PBKDF2 + +if _lib.SHA_ENABLED: + from wolfcrypt.hashes import Sha + if _lib.HMAC_ENABLED: + from wolfcrypt.hashes import HmacSha + +@pytest.fixture +def pbkdf2_vectors(): + TestVector = namedtuple("TestVector", """password salt iterations key_length + hash_type""") + TestVector.__new__.__defaults__ = (None,) * len(TestVector._fields) + + vectors = [] + + if _lib.PWDBASED_ENABLED and _lib.SHA_ENABLED and _lib.HMAC_ENABLED: + vectors.append(TestVector( + password="pass1234", + salt="salt1234", + iterations=1000, + key_length=Sha.digest_size, + hash_type=HmacSha._type + )) + + return vectors + +def test_pbkdf2(pbkdf2_vectors): + for vector in pbkdf2_vectors: + key = PBKDF2(vector.password, vector.salt, vector.iterations, + vector.key_length, vector.hash_type) + assert len(key) == vector.key_length