diff options
author | Jack Lloyd <[email protected]> | 2017-04-04 16:44:23 -0400 |
---|---|---|
committer | Jack Lloyd <[email protected]> | 2017-04-04 16:44:23 -0400 |
commit | 542c6cb7338530b4a8f7d93f2410567815d993ef (patch) | |
tree | 76718dd137e433b6be08403cad6a6d72f7e6129b | |
parent | f998cf9ae48ee5d4220fc6f5f54563e3c2cab6d1 (diff) | |
parent | 686371913aeb6ad823320dfc6caf3a8e7d24e01e (diff) |
Merge GH #977 Add block cipher interface to C API
-rw-r--r-- | doc/manual/ffi.rst | 44 | ||||
-rw-r--r-- | doc/todo.rst | 7 | ||||
-rw-r--r-- | src/lib/ffi/ffi.cpp | 77 | ||||
-rw-r--r-- | src/lib/ffi/ffi.h | 45 | ||||
-rw-r--r-- | src/tests/test_ffi.cpp | 37 |
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"); |