aboutsummaryrefslogtreecommitdiffstats
path: root/src/lib/ffi/ffi_cipher.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/ffi/ffi_cipher.cpp')
-rw-r--r--src/lib/ffi/ffi_cipher.cpp196
1 files changed, 196 insertions, 0 deletions
diff --git a/src/lib/ffi/ffi_cipher.cpp b/src/lib/ffi/ffi_cipher.cpp
new file mode 100644
index 000000000..6bb45dec8
--- /dev/null
+++ b/src/lib/ffi/ffi_cipher.cpp
@@ -0,0 +1,196 @@
+/*
+* (C) 2015,2017 Jack Lloyd
+*
+* Botan is released under the Simplified BSD License (see license.txt)
+*/
+
+#include <botan/ffi.h>
+#include <botan/internal/ffi_util.h>
+#include <botan/aead.h>
+
+extern "C" {
+
+using namespace Botan_FFI;
+
+struct botan_cipher_struct : public botan_struct<Botan::Cipher_Mode, 0xB4A2BF9C>
+ {
+ explicit botan_cipher_struct(Botan::Cipher_Mode* x) : botan_struct(x) {}
+ Botan::secure_vector<uint8_t> m_buf;
+ };
+
+int botan_cipher_init(botan_cipher_t* cipher, const char* cipher_name, uint32_t flags)
+ {
+ return ffi_guard_thunk(BOTAN_CURRENT_FUNCTION, [=]() {
+ const bool encrypt_p = ((flags & BOTAN_CIPHER_INIT_FLAG_MASK_DIRECTION) == BOTAN_CIPHER_INIT_FLAG_ENCRYPT);
+ const Botan::Cipher_Dir dir = encrypt_p ? Botan::ENCRYPTION : Botan::DECRYPTION;
+ std::unique_ptr<Botan::Cipher_Mode> mode(Botan::get_cipher_mode(cipher_name, dir));
+ if(!mode)
+ return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
+ *cipher = new botan_cipher_struct(mode.release());
+ return BOTAN_FFI_SUCCESS;
+ });
+ }
+
+int botan_cipher_destroy(botan_cipher_t cipher)
+ {
+ return BOTAN_FFI_CHECKED_DELETE(cipher);
+ }
+
+int botan_cipher_clear(botan_cipher_t cipher)
+ {
+ return BOTAN_FFI_DO(Botan::Cipher_Mode, cipher, c, { c.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, c, {
+ *out_minimum_keylength = c.key_spec().minimum_keylength();
+ *out_maximum_keylength = c.key_spec().maximum_keylength();
+ });
+ }
+
+int botan_cipher_set_key(botan_cipher_t cipher,
+ const uint8_t* key, size_t key_len)
+ {
+ return BOTAN_FFI_DO(Botan::Cipher_Mode, cipher, c, { c.set_key(key, key_len); });
+ }
+
+int botan_cipher_start(botan_cipher_t cipher_obj,
+ const uint8_t* nonce, size_t nonce_len)
+ {
+ return ffi_guard_thunk(BOTAN_CURRENT_FUNCTION, [=]() {
+ Botan::Cipher_Mode& cipher = safe_get(cipher_obj);
+ cipher.start(nonce, nonce_len);
+ cipher_obj->m_buf.reserve(cipher.update_granularity());
+ return BOTAN_FFI_SUCCESS;
+ });
+ }
+
+int botan_cipher_update(botan_cipher_t cipher_obj,
+ uint32_t flags,
+ uint8_t output_ptr[],
+ size_t orig_output_size,
+ size_t* output_written,
+ const uint8_t input_ptr[],
+ size_t orig_input_size,
+ size_t* input_consumed)
+ {
+ return ffi_guard_thunk(BOTAN_CURRENT_FUNCTION, [=]() {
+
+ size_t input_size = orig_input_size;
+ size_t output_size = orig_output_size;
+ const uint8_t* input = input_ptr;
+ uint8_t* output = output_ptr;
+
+ using namespace Botan;
+ Cipher_Mode& cipher = safe_get(cipher_obj);
+ secure_vector<uint8_t>& mbuf = cipher_obj->m_buf;
+
+ const bool final_input = (flags & BOTAN_CIPHER_UPDATE_FLAG_FINAL);
+
+ if(final_input)
+ {
+ mbuf.assign(input, input + input_size);
+ *input_consumed = input_size;
+ *output_written = 0;
+
+ try
+ {
+ cipher.finish(mbuf);
+ }
+ catch(Integrity_Failure& e)
+ {
+ return BOTAN_FFI_ERROR_BAD_MAC;
+ }
+
+ *output_written = mbuf.size();
+
+ if(mbuf.size() <= output_size)
+ {
+ copy_mem(output, mbuf.data(), mbuf.size());
+ mbuf.clear();
+ return BOTAN_FFI_SUCCESS;
+ }
+
+ return -1;
+ }
+
+ if(input_size == 0)
+ {
+ // Currently must take entire buffer in this case
+ *output_written = mbuf.size();
+ if(output_size >= mbuf.size())
+ {
+ copy_mem(output, mbuf.data(), mbuf.size());
+ mbuf.clear();
+ return BOTAN_FFI_SUCCESS;
+ }
+
+ return -1;
+ }
+
+ const size_t ud = cipher.update_granularity();
+ BOTAN_ASSERT(cipher.update_granularity() > cipher.minimum_final_size(), "logic error");
+
+ mbuf.resize(ud);
+ size_t taken = 0, written = 0;
+
+ while(input_size >= ud && output_size >= ud)
+ {
+ copy_mem(mbuf.data(), input, ud);
+ cipher.update(mbuf);
+
+ input_size -= ud;
+ copy_mem(output, mbuf.data(), ud);
+ input += ud;
+ taken += ud;
+
+ output_size -= ud;
+ output += ud;
+ written += ud;
+ }
+
+ *output_written = written;
+ *input_consumed = taken;
+
+ return BOTAN_FFI_SUCCESS;
+ });
+ }
+
+int botan_cipher_set_associated_data(botan_cipher_t cipher,
+ const uint8_t* ad,
+ size_t ad_len)
+ {
+ return BOTAN_FFI_DO(Botan::Cipher_Mode, cipher, c, {
+ if(Botan::AEAD_Mode* aead = dynamic_cast<Botan::AEAD_Mode*>(&c))
+ {
+ aead->set_associated_data(ad, ad_len);
+ return BOTAN_FFI_SUCCESS;
+ }
+ return BOTAN_FFI_ERROR_BAD_PARAMETER;
+ });
+ }
+
+int botan_cipher_valid_nonce_length(botan_cipher_t cipher, size_t nl)
+ {
+ return BOTAN_FFI_DO(Botan::Cipher_Mode, cipher, c, { return c.valid_nonce_length(nl) ? 1 : 0; });
+ }
+
+int botan_cipher_get_default_nonce_length(botan_cipher_t cipher, size_t* nl)
+ {
+ return BOTAN_FFI_DO(Botan::Cipher_Mode, cipher, c, { *nl = c.default_nonce_length(); });
+ }
+
+int botan_cipher_get_update_granularity(botan_cipher_t cipher, size_t* ug)
+ {
+ return BOTAN_FFI_DO(Botan::Cipher_Mode, cipher, c, { *ug = c.update_granularity(); });
+ }
+
+int botan_cipher_get_tag_length(botan_cipher_t cipher, size_t* tl)
+ {
+ return BOTAN_FFI_DO(Botan::Cipher_Mode, cipher, c, { *tl = c.tag_size(); });
+ }
+
+}