aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJack Lloyd <[email protected]>2017-04-04 16:44:23 -0400
committerJack Lloyd <[email protected]>2017-04-04 16:44:23 -0400
commit542c6cb7338530b4a8f7d93f2410567815d993ef (patch)
tree76718dd137e433b6be08403cad6a6d72f7e6129b
parentf998cf9ae48ee5d4220fc6f5f54563e3c2cab6d1 (diff)
parent686371913aeb6ad823320dfc6caf3a8e7d24e01e (diff)
Merge GH #977 Add block cipher interface to C API
-rw-r--r--doc/manual/ffi.rst44
-rw-r--r--doc/todo.rst7
-rw-r--r--src/lib/ffi/ffi.cpp77
-rw-r--r--src/lib/ffi/ffi.h45
-rw-r--r--src/tests/test_ffi.cpp37
5 files changed, 208 insertions, 2 deletions
diff --git a/doc/manual/ffi.rst b/doc/manual/ffi.rst
index 5cf0dbac5..8acbf225a 100644
--- a/doc/manual/ffi.rst
+++ b/doc/manual/ffi.rst
@@ -89,6 +89,50 @@ Random Number Generators
Destroy the object created by :cpp:func:`botan_rng_init`.
+Block Ciphers
+----------------------------------------
+
+This is a 'raw' interface to ECB mode block ciphers. Most applications
+want the higher level cipher API which provides authenticated
+encryption. This API exists as an escape hatch for applications which
+need to implement custom primitives using a PRP.
+
+.. cpp:type:: opaque* botan_block_cipher_t
+
+ An opauqe data type for a block cipher. Don't mess with it.
+
+.. cpp:function:: int botan_block_cipher_init(botan_block_cipher_t* bc, const char* cipher_name)
+
+ Create a new cipher mode object, `cipher_name` should be for example "AES-128" or "Threefish-512"
+
+.. cpp:function:: int botan_block_cipher_block_size(botan_block_cipher_t bc)
+
+ Return the block size of this cipher.
+
+.. cpp:function:: int botan_block_cipher_clear(botan_block_cipher_t bc)
+
+ Clear the internal state (such as keys) of this cipher object, but do not deallocate it.
+
+.. cpp:function:: int botan_block_cipher_set_key(botan_block_cipher_t bc, const uint8_t key[], size_t key_len)
+
+ Set the cipher key, which is required before encrypting or decrypting.
+
+.. cpp:function:: int botan_block_cipher_encrypt_blocks(botan_block_cipher_t bc, const uint8_t in[], uint8_t out[], size_t blocks)
+
+ The key must have been set first with
+ Encrypt *blocks* blocks of data stored in *in* and place the ciphertext into *out*.
+ The two parameters may be the same buffer, but must not overlap.
+
+.. cpp:function:: int botan_block_cipher_decrypt_blocks(botan_block_cipher_t bc, const uint8_t in[], uint8_t out[], size_t blocks)
+
+ Decrypt *blocks* blocks of data stored in *in* and place the ciphertext into *out*.
+ The two parameters may be the same buffer, but must not overlap.
+
+.. cpp:function:: int botan_block_cipher_destroy(botan_block_cipher_t rng)
+
+ Destroy the object created by :cpp:func:`botan_block_cipher_init`.
+
+
Hash Functions
----------------------------------------
diff --git a/doc/todo.rst b/doc/todo.rst
index b3ad697e8..4a7d60191 100644
--- a/doc/todo.rst
+++ b/doc/todo.rst
@@ -108,6 +108,11 @@ New Protocols / Formats
- Subset #2: Process OpenPGP public keys
- Subset #3: Verification of OpenPGP signatures
+Cleanups
+-----------
+
+* Split ffi.cpp and test_ffi.cpp into multiple files
+
Compat Headers
----------------
@@ -119,9 +124,7 @@ Compat Headers
FFI and Bindings
----------------------------------------
-* Expose BigInt
* Expose compression
-* Expose a raw block cipher interface
* Expose more of X.509 (CRLs, OCSP, cert signing, etc)
* Expose TLS
* Write a CLI or HTTPS client in Python
diff --git a/src/lib/ffi/ffi.cpp b/src/lib/ffi/ffi.cpp
index 945eacaf8..b4f0412d6 100644
--- a/src/lib/ffi/ffi.cpp
+++ b/src/lib/ffi/ffi.cpp
@@ -9,6 +9,7 @@
#include <botan/exceptn.h>
#include <botan/auto_rng.h>
#include <botan/aead.h>
+#include <botan/block_cipher.h>
#include <botan/hash.h>
#include <botan/mac.h>
#include <botan/pbkdf.h>
@@ -217,6 +218,7 @@ struct botan_cipher_struct : public botan_struct<Botan::Cipher_Mode, 0xB4A2BF9C>
BOTAN_FFI_DECLARE_STRUCT(botan_rng_struct, Botan::RandomNumberGenerator, 0x4901F9C1);
BOTAN_FFI_DECLARE_STRUCT(botan_mp_struct, Botan::BigInt, 0xC828B9D2);
+BOTAN_FFI_DECLARE_STRUCT(botan_block_cipher_struct, Botan::BlockCipher, 0x64C29716);
BOTAN_FFI_DECLARE_STRUCT(botan_hash_struct, Botan::HashFunction, 0x1F0A4F84);
BOTAN_FFI_DECLARE_STRUCT(botan_mac_struct, Botan::MessageAuthenticationCode, 0xA06E8FC1);
BOTAN_FFI_DECLARE_STRUCT(botan_pubkey_struct, Botan::Public_Key, 0x2C286519);
@@ -593,6 +595,81 @@ int botan_mp_num_bytes(const botan_mp_t mp, size_t* bytes)
return BOTAN_FFI_DO(Botan::BigInt, mp, n, { *bytes = n.bytes(); });
}
+int botan_block_cipher_init(botan_block_cipher_t* bc, const char* bc_name)
+ {
+ try
+ {
+ if(bc == nullptr || bc_name == nullptr || *bc_name == 0)
+ return BOTAN_FFI_ERROR_NULL_POINTER;
+
+ std::unique_ptr<Botan::BlockCipher> cipher(Botan::BlockCipher::create(bc_name));
+ if(cipher)
+ {
+ *bc = new botan_block_cipher_struct(cipher.release());
+ return 0;
+ }
+ }
+ catch(std::exception& e)
+ {
+ log_exception(BOTAN_CURRENT_FUNCTION, e.what());
+ }
+ catch(...)
+ {
+ log_exception(BOTAN_CURRENT_FUNCTION, "unknown");
+ }
+
+ return BOTAN_FFI_ERROR_EXCEPTION_THROWN;
+
+ }
+
+/**
+* Destroy a block cipher object
+*/
+int botan_block_cipher_destroy(botan_block_cipher_t bc)
+ {
+ delete bc;
+ return 0;
+ }
+
+int botan_block_cipher_clear(botan_block_cipher_t bc)
+ {
+ return BOTAN_FFI_DO(Botan::BlockCipher, bc, b, { b.clear(); });
+ }
+
+/**
+* Set the key for a block cipher instance
+*/
+int botan_block_cipher_set_key(botan_block_cipher_t bc,
+ const uint8_t key[], size_t len)
+ {
+ return BOTAN_FFI_DO(Botan::BlockCipher, bc, b, { b.set_key(key, len); });
+ }
+
+/**
+* Return the positive block size of this block cipher, or negative to
+* indicate an error
+*/
+int botan_block_cipher_block_size(botan_block_cipher_t bc)
+ {
+ return BOTAN_FFI_DO(Botan::BlockCipher, bc, b, { return b.block_size(); });
+ }
+
+int botan_block_cipher_encrypt_blocks(botan_block_cipher_t bc,
+ const uint8_t in[],
+ uint8_t out[],
+ size_t blocks)
+ {
+ return BOTAN_FFI_DO(Botan::BlockCipher, bc, b, { b.encrypt_n(in, out, blocks); });
+ }
+
+int botan_block_cipher_decrypt_blocks(botan_block_cipher_t bc,
+ const uint8_t in[],
+ uint8_t out[],
+ size_t blocks)
+ {
+ return BOTAN_FFI_DO(Botan::BlockCipher, bc, b, { b.decrypt_n(in, out, blocks); });
+ }
+
int botan_hash_init(botan_hash_t* hash, const char* hash_name, uint32_t flags)
{
try
diff --git a/src/lib/ffi/ffi.h b/src/lib/ffi/ffi.h
index 0901c4d4d..76cdaa145 100644
--- a/src/lib/ffi/ffi.h
+++ b/src/lib/ffi/ffi.h
@@ -456,6 +456,51 @@ BOTAN_DLL int botan_bcrypt_generate(uint8_t* out, size_t* out_len,
uint32_t flags);
/*
+* Raw Block Cipher (PRP) interface
+*/
+typedef struct botan_block_cipher_struct* botan_block_cipher_t;
+
+/**
+* Initialize a block cipher object
+*/
+BOTAN_DLL int botan_block_cipher_init(botan_block_cipher_t* bc,
+ const char* cipher_name);
+
+/**
+* Destroy a block cipher object
+*/
+BOTAN_DLL int botan_block_cipher_destroy(botan_block_cipher_t bc);
+
+/**
+* Reinitializes the block cipher
+* @return 0 on success, a negative value on failure
+*/
+BOTAN_DLL int botan_block_cipher_clear(botan_block_cipher_t bc);
+
+/**
+* Set the key for a block cipher instance
+*/
+BOTAN_DLL int botan_block_cipher_set_key(botan_block_cipher_t bc,
+ const uint8_t key[], size_t len);
+
+/**
+* Return the positive block size of this block cipher, or negative to
+* indicate an error
+*/
+BOTAN_DLL int botan_block_cipher_block_size(botan_block_cipher_t bc);
+
+BOTAN_DLL int botan_block_cipher_encrypt_blocks(botan_block_cipher_t bc,
+ const uint8_t in[],
+ uint8_t out[],
+ size_t blocks);
+
+BOTAN_DLL int botan_block_cipher_decrypt_blocks(botan_block_cipher_t bc,
+ const uint8_t in[],
+ uint8_t out[],
+ size_t blocks);
+
+
+/*
* Multiple precision integers
*/
typedef struct botan_mp_struct* botan_mp_t;
diff --git a/src/tests/test_ffi.cpp b/src/tests/test_ffi.cpp
index eee5fc39d..c84dfd224 100644
--- a/src/tests/test_ffi.cpp
+++ b/src/tests/test_ffi.cpp
@@ -387,6 +387,7 @@ class FFI_Unit_Tests : public Test
std::vector<Test::Result> results;
results.push_back(ffi_test_mp(rng));
+ results.push_back(ffi_test_block_ciphers());
#if defined(BOTAN_HAS_RSA)
results.push_back(ffi_test_rsa(rng));
@@ -415,6 +416,42 @@ class FFI_Unit_Tests : public Test
}
private:
+ Test::Result ffi_test_block_ciphers()
+ {
+ Test::Result result("FFI block ciphers");
+
+ botan_block_cipher_t cipher;
+
+ if(TEST_FFI_OK(botan_block_cipher_init, (&cipher, "AES-128")))
+ {
+ const std::vector<uint8_t> zero16(16, 0);
+ std::vector<uint8_t> block(16, 0);
+
+ TEST_FFI_OK(botan_block_cipher_clear, (cipher));
+
+ TEST_FFI_RC(16, botan_block_cipher_block_size, (cipher));
+
+ TEST_FFI_OK(botan_block_cipher_set_key, (cipher, zero16.data(), zero16.size()));
+
+ TEST_FFI_OK(botan_block_cipher_encrypt_blocks, (cipher, block.data(), block.data(), 1));
+ result.test_eq("AES-128 encryption works", block, "66E94BD4EF8A2C3B884CFA59CA342B2E");
+
+ TEST_FFI_OK(botan_block_cipher_encrypt_blocks, (cipher, block.data(), block.data(), 1));
+ result.test_eq("AES-128 encryption works", block, "F795BD4A52E29ED713D313FA20E98DBC");
+
+ TEST_FFI_OK(botan_block_cipher_decrypt_blocks, (cipher, block.data(), block.data(), 1));
+ result.test_eq("AES-128 decryption works", block, "66E94BD4EF8A2C3B884CFA59CA342B2E");
+
+ TEST_FFI_OK(botan_block_cipher_decrypt_blocks, (cipher, block.data(), block.data(), 1));
+ result.test_eq("AES-128 decryption works", block, "00000000000000000000000000000000");
+
+ TEST_FFI_OK(botan_block_cipher_clear, (cipher));
+ botan_block_cipher_destroy(cipher);
+ }
+
+ return result;
+ }
+
Test::Result ffi_test_mp(botan_rng_t rng)
{
Test::Result result("FFI MP");