diff options
author | Jack Lloyd <[email protected]> | 2018-08-15 12:18:57 -0400 |
---|---|---|
committer | Jack Lloyd <[email protected]> | 2018-08-15 12:23:50 -0400 |
commit | 2a8ef82de490dba1cf4dcd34c6c97022a5d18b1a (patch) | |
tree | 70e1fd657617b5bb57a6b5dc2819f859d02dd6ae | |
parent | 5ccc9e45f7d4a3a68416ed93de31105fc9ff9e08 (diff) |
Expose HOTP to FFI
-rw-r--r-- | doc/todo.rst | 2 | ||||
-rw-r--r-- | src/lib/ffi/ffi.h | 36 | ||||
-rw-r--r-- | src/lib/ffi/ffi_hotp.cpp | 100 | ||||
-rw-r--r-- | src/lib/misc/hotp/hotp.cpp | 4 | ||||
-rw-r--r-- | src/tests/test_ffi.cpp | 37 |
5 files changed, 174 insertions, 5 deletions
diff --git a/doc/todo.rst b/doc/todo.rst index 08beda1e9..25561c6ab 100644 --- a/doc/todo.rst +++ b/doc/todo.rst @@ -137,7 +137,7 @@ FFI and Bindings * Expose compression * Expose more of X.509 (CRLs, PKCS10, OCSP, cert signing, etc) * Expose TLS -* Expose TOTP/HOTP +* Expose TOTP * Expose NIST key wrap with padding * Expose secret sharing * Expose deterministic PRNG diff --git a/src/lib/ffi/ffi.h b/src/lib/ffi/ffi.h index 54c01174c..8a4570c52 100644 --- a/src/lib/ffi/ffi.h +++ b/src/lib/ffi/ffi.h @@ -1440,6 +1440,42 @@ int botan_key_unwrap3394(const uint8_t wrapped_key[], size_t wrapped_key_len, uint8_t key[], size_t *key_len); /** +* HOTP +*/ + +typedef struct botan_hotp_struct* botan_hotp_t; + +/** +* Initialize an HOTP instance +*/ +int botan_hotp_init(botan_hotp_t* hotp, + const uint8_t key[], size_t key_len, + const char* hash_algo, + size_t digits); + +/** +* Destroy a HOTP instance +*/ +int botan_hotp_destroy(botan_hotp_t hotp); + +/** +* Generate an HOTP code for the provided counter +*/ +int botan_hotp_generate(botan_hotp_t hotp, + uint32_t* hotp_code, + uint64_t hotp_counter); + +/** +* Verify an HOTP code +*/ +int botan_hotp_check(botan_hotp_t hotp, + uint64_t* next_hotp_counter, + uint32_t hotp_code, + uint64_t hotp_counter, + size_t resync_range); + + +/** * Format Preserving Encryption */ diff --git a/src/lib/ffi/ffi_hotp.cpp b/src/lib/ffi/ffi_hotp.cpp new file mode 100644 index 000000000..ae761450f --- /dev/null +++ b/src/lib/ffi/ffi_hotp.cpp @@ -0,0 +1,100 @@ +/* +* (C) 2018 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include <botan/ffi.h> +#include <botan/internal/ffi_util.h> + +#if defined(BOTAN_HAS_HOTP) + #include <botan/hotp.h> +#endif + +extern "C" { + +using namespace Botan_FFI; + +#if defined(BOTAN_HAS_HOTP) + +BOTAN_FFI_DECLARE_STRUCT(botan_hotp_struct, Botan::HOTP, 0x89CBF191); + +#endif + +int botan_hotp_init(botan_hotp_t* hotp, + const uint8_t key[], size_t key_len, + const char* hash_algo, + size_t digits) + { + if(hotp == nullptr || key == nullptr || hash_algo == nullptr) + return BOTAN_FFI_ERROR_NULL_POINTER; + + *hotp = nullptr; + +#if defined(BOTAN_HAS_HOTP) + return ffi_guard_thunk(BOTAN_CURRENT_FUNCTION, [=]() -> int { + + *hotp = new botan_hotp_struct(new Botan::HOTP( + Botan::SymmetricKey(key, key_len), + hash_algo, + digits)); + return BOTAN_FFI_SUCCESS; + }); +#else + BOTAN_UNUSED(hotp, key, key_len, hash_algo, digits); + return BOTAN_FFI_ERROR_NOT_IMPLEMENTED; +#endif + } + +int botan_hotp_destroy(botan_hotp_t hotp) + { +#if defined(BOTAN_HAS_HOTP) + return BOTAN_FFI_CHECKED_DELETE(hotp); +#else + BOTAN_UNUSED(hotp); + return BOTAN_FFI_ERROR_NOT_IMPLEMENTED; +#endif + } + +int botan_hotp_generate(botan_hotp_t hotp, + uint32_t* hotp_code, + uint64_t hotp_counter) + { +#if defined(BOTAN_HAS_HOTP) + if(hotp == nullptr || hotp_code == nullptr) + return BOTAN_FFI_ERROR_NULL_POINTER; + + return BOTAN_FFI_DO(Botan::HOTP, hotp, h, { + *hotp_code = h.generate_hotp(hotp_counter); + }); + +#else + BOTAN_UNUSED(hotp, hotp_code, hotp_counter); + return BOTAN_FFI_ERROR_NOT_IMPLEMENTED; +#endif + } + +int botan_hotp_check(botan_hotp_t hotp, + uint64_t* next_hotp_counter, + uint32_t hotp_code, + uint64_t hotp_counter, + size_t resync_range) + { +#if defined(BOTAN_HAS_HOTP) + return BOTAN_FFI_DO(Botan::HOTP, hotp, h, { + + auto resp = h.verify_hotp(hotp_code, hotp_counter, resync_range); + + if(next_hotp_counter) + *next_hotp_counter = resp.second; + + return (resp.first == true) ? BOTAN_FFI_SUCCESS : BOTAN_FFI_INVALID_VERIFIER; + }); + +#else + BOTAN_UNUSED(hotp, next_hotp_counter, hotp_code, hotp_counter, resync_range); + return BOTAN_FFI_ERROR_NOT_IMPLEMENTED; +#endif + } + +} diff --git a/src/lib/misc/hotp/hotp.cpp b/src/lib/misc/hotp/hotp.cpp index e4dc6e5e3..c4c0c7770 100644 --- a/src/lib/misc/hotp/hotp.cpp +++ b/src/lib/misc/hotp/hotp.cpp @@ -39,9 +39,7 @@ HOTP::HOTP(const SymmetricKey& key, const std::string& hash_algo, size_t digits) uint32_t HOTP::generate_hotp(uint64_t counter) { - uint8_t counter8[8] = { 0 }; - store_be(counter, counter8); - m_mac->update(counter8, sizeof(counter8)); + m_mac->update_be(counter); const secure_vector<uint8_t> mac = m_mac->final(); const size_t offset = mac[mac.size()-1] & 0x0F; diff --git a/src/tests/test_ffi.cpp b/src/tests/test_ffi.cpp index 14eb28875..52dbe7348 100644 --- a/src/tests/test_ffi.cpp +++ b/src/tests/test_ffi.cpp @@ -1520,6 +1520,41 @@ class FFI_Unit_Tests final : public Test return result; } + Test::Result ffi_test_hotp() + { + Test::Result result("FFI HOTP"); + + const std::vector<uint8_t> key = Botan::hex_decode("3132333435363738393031323334353637383930"); + const size_t digits = 6; + + botan_hotp_t hotp; + uint32_t hotp_val; + + TEST_FFI_OK(botan_hotp_init, (&hotp, key.data(), key.size(), "SHA-1", digits)); + + TEST_FFI_OK(botan_hotp_generate, (hotp, &hotp_val, 0)); + result.confirm("Valid value for counter 0", hotp_val == 755224); + TEST_FFI_OK(botan_hotp_generate, (hotp, &hotp_val, 1)); + result.confirm("Valid value for counter 0", hotp_val == 287082); + TEST_FFI_OK(botan_hotp_generate, (hotp, &hotp_val, 2)); + result.confirm("Valid value for counter 0", hotp_val == 359152); + TEST_FFI_OK(botan_hotp_generate, (hotp, &hotp_val, 0)); + result.confirm("Valid value for counter 0", hotp_val == 755224); + + uint64_t next_ctr = 0; + + TEST_FFI_OK(botan_hotp_check, (hotp, &next_ctr, 755224, 0, 0)); + result.confirm("HOTP resync", next_ctr == 1); + TEST_FFI_OK(botan_hotp_check, (hotp, nullptr, 359152, 2, 0)); + TEST_FFI_RC(1, botan_hotp_check, (hotp, nullptr, 359152, 1, 0)); + TEST_FFI_RC(1, botan_hotp_check, (hotp, &next_ctr, 359152, 0, 2)); + result.confirm("HOTP resync", next_ctr == 3); + + TEST_FFI_OK(botan_hotp_destroy, (hotp)); + + return result; + } + Test::Result ffi_test_keywrap() { Test::Result result("FFI keywrap"); @@ -2377,7 +2412,7 @@ class FFI_Unit_Tests final : public Test Test::Result ffi_test_elgamal(botan_rng_t rng) { - Test::Result result("FFI ELGAMAL"); + Test::Result result("FFI ElGamal"); botan_privkey_t priv; |