aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJose Pereira <[email protected]>2018-09-09 14:59:35 -0700
committerJose Pereira <[email protected]>2018-09-10 13:03:56 -0700
commit364119259ca7dc091f437a72d16cb575d0c48db3 (patch)
treeab673063048ddb54fa27faeae67c34e36e1cd962
parent7ab32d49da6b0e951a3740ee0e6614d3147642c2 (diff)
Add CommonCrypto block cipher support
-rw-r--r--doc/authors.txt1
-rw-r--r--src/lib/block/block_cipher.cpp18
-rw-r--r--src/lib/prov/commoncrypto/commoncrypto.h6
-rw-r--r--src/lib/prov/commoncrypto/commoncrypto_block.cpp152
-rw-r--r--src/lib/prov/commoncrypto/commoncrypto_utils.cpp44
-rw-r--r--src/lib/prov/commoncrypto/commoncrypto_utils.h4
-rw-r--r--src/lib/prov/commoncrypto/info.txt1
7 files changed, 221 insertions, 5 deletions
diff --git a/doc/authors.txt b/doc/authors.txt
index bd5c52d78..954081b55 100644
--- a/doc/authors.txt
+++ b/doc/authors.txt
@@ -44,6 +44,7 @@ Jack Lloyd
Jeffrey Walton
Joel Low
joerg
+Jose Luis Pereira (Fyde Inc.)
Juraj Somorovsky (Hackmanit GmbH)
Justin Karneges
Kai Michaelis (Rohde & Schwarz Cybersecurity)
diff --git a/src/lib/block/block_cipher.cpp b/src/lib/block/block_cipher.cpp
index 3ace6cd4f..fb0564646 100644
--- a/src/lib/block/block_cipher.cpp
+++ b/src/lib/block/block_cipher.cpp
@@ -98,12 +98,27 @@
#include <botan/internal/openssl.h>
#endif
+#if defined(BOTAN_HAS_COMMONCRYPTO)
+ #include <botan/internal/commoncrypto.h>
+#endif
+
namespace Botan {
std::unique_ptr<BlockCipher>
BlockCipher::create(const std::string& algo,
const std::string& provider)
{
+#if defined(BOTAN_HAS_COMMONCRYPTO)
+ if(provider.empty() || provider == "commoncrypto")
+ {
+ if(auto bc = make_commoncrypto_block_cipher(algo))
+ return bc;
+
+ if(!provider.empty())
+ return nullptr;
+ }
+#endif
+
#if defined(BOTAN_HAS_OPENSSL)
if(provider.empty() || provider == "openssl")
{
@@ -115,7 +130,6 @@ BlockCipher::create(const std::string& algo,
}
#endif
- // TODO: CommonCrypto
// TODO: CryptoAPI
// TODO: /dev/crypto
@@ -343,7 +357,7 @@ BlockCipher::create_or_throw(const std::string& algo,
std::vector<std::string> BlockCipher::providers(const std::string& algo)
{
- return probe_providers_of<BlockCipher>(algo, { "base", "openssl" });
+ return probe_providers_of<BlockCipher>(algo, { "base", "openssl", "commoncrypto" });
}
}
diff --git a/src/lib/prov/commoncrypto/commoncrypto.h b/src/lib/prov/commoncrypto/commoncrypto.h
index aadccfdca..958cbab7d 100644
--- a/src/lib/prov/commoncrypto/commoncrypto.h
+++ b/src/lib/prov/commoncrypto/commoncrypto.h
@@ -17,6 +17,7 @@
namespace Botan {
class Cipher_Mode;
+class BlockCipher;
class HashFunction;
enum Cipher_Dir : int;
typedef int32_t CCCryptorStatus;
@@ -38,6 +39,11 @@ class BOTAN_PUBLIC_API(2, 0) CommonCrypto_Error final : public Exception
Cipher_Mode*
make_commoncrypto_cipher_mode(const std::string& name, Cipher_Dir direction);
+/* Block Ciphers */
+
+std::unique_ptr<BlockCipher>
+make_commoncrypto_block_cipher(const std::string& name);
+
/* Hash */
std::unique_ptr<HashFunction> make_commoncrypto_hash(const std::string& name);
diff --git a/src/lib/prov/commoncrypto/commoncrypto_block.cpp b/src/lib/prov/commoncrypto/commoncrypto_block.cpp
new file mode 100644
index 000000000..e912ed57e
--- /dev/null
+++ b/src/lib/prov/commoncrypto/commoncrypto_block.cpp
@@ -0,0 +1,152 @@
+/*
+* Block Ciphers via CommonCrypto
+* (C) 2018 Jose Luis Pereira
+*
+* Botan is released under the Simplified BSD License (see license.txt)
+*/
+
+#include <botan/hex.h>
+
+#include <botan/block_cipher.h>
+#include <botan/internal/commoncrypto.h>
+#include <CommonCrypto/CommonCrypto.h>
+
+#include "commoncrypto_utils.h"
+
+namespace Botan {
+
+namespace {
+
+class CommonCrypto_BlockCipher final : public BlockCipher
+ {
+ public:
+ CommonCrypto_BlockCipher(const std::string& name, const CommonCryptor_Opts& opts);
+
+ ~CommonCrypto_BlockCipher();
+
+ void clear() override;
+ std::string provider() const override { return "commoncrypto"; }
+ std::string name() const override { return m_cipher_name; }
+ BlockCipher* clone() const override;
+
+ size_t block_size() const override { return m_opts.block_size; }
+
+ Key_Length_Specification key_spec() const override { return m_opts.key_spec; }
+
+ void encrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const override
+ {
+ verify_key_set(m_key_set);
+ size_t total_len = blocks * m_opts.block_size;
+ size_t out_len = 0;
+
+ CCCryptorStatus status = CCCryptorUpdate(m_encrypt, in, total_len,
+ out, total_len, &out_len);
+ if(status != kCCSuccess)
+ {
+ throw CommonCrypto_Error("CCCryptorUpdate encrypt", status);
+ }
+ }
+
+ void decrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const override
+ {
+ verify_key_set(m_key_set);
+ size_t total_len = blocks * m_opts.block_size;
+ size_t out_len = 0;
+
+ CCCryptorStatus status = CCCryptorUpdate(m_decrypt, in, total_len,
+ out, total_len, &out_len);
+ if(status != kCCSuccess)
+ {
+ throw CommonCrypto_Error("CCCryptorUpdate decrypt", status);
+ }
+ }
+
+ void key_schedule(const uint8_t key[], size_t key_len) override;
+
+ std::string m_cipher_name;
+ CommonCryptor_Opts m_opts;
+
+ CCCryptorRef m_encrypt = nullptr;
+ CCCryptorRef m_decrypt = nullptr;
+ bool m_key_set;
+ };
+
+CommonCrypto_BlockCipher::CommonCrypto_BlockCipher(const std::string& algo_name,
+ const CommonCryptor_Opts& opts) :
+ m_cipher_name(algo_name),
+ m_opts(opts),
+ m_key_set(false)
+ {
+ }
+
+CommonCrypto_BlockCipher::~CommonCrypto_BlockCipher()
+ {
+ if(m_encrypt)
+ {
+ CCCryptorRelease(m_encrypt);
+ }
+ if(m_decrypt)
+ {
+ CCCryptorRelease(m_decrypt);
+ }
+ }
+
+/*
+* Set the key
+*/
+void CommonCrypto_BlockCipher::key_schedule(const uint8_t key[], size_t length)
+ {
+ secure_vector<uint8_t> full_key(key, key + length);
+
+ commoncrypto_adjust_key_size(key, length, m_opts, full_key);
+
+ CCCryptorStatus status;
+ status = CCCryptorCreate(kCCEncrypt, m_opts.algo, kCCOptionECBMode,
+ full_key.data(), full_key.size(), nullptr, &m_encrypt);
+ if(status != kCCSuccess)
+ {
+ throw CommonCrypto_Error("CCCryptorCreate encrypt", status);
+ }
+ status = CCCryptorCreate(kCCDecrypt, m_opts.algo, kCCOptionECBMode,
+ full_key.data(), full_key.size(), nullptr, &m_decrypt);
+ if(status != kCCSuccess)
+ {
+ throw CommonCrypto_Error("CCCryptorCreate decrypt", status);
+ }
+
+ m_key_set = true;
+ }
+
+/*
+* Return a clone of this object
+*/
+BlockCipher* CommonCrypto_BlockCipher::clone() const
+ {
+ return new CommonCrypto_BlockCipher(m_cipher_name, m_opts);
+ }
+
+/*
+* Clear memory of sensitive data
+*/
+void CommonCrypto_BlockCipher::clear()
+ {
+ m_key_set = false;
+ }
+}
+
+std::unique_ptr<BlockCipher>
+make_commoncrypto_block_cipher(const std::string& name)
+ {
+
+ try
+ {
+ CommonCryptor_Opts opts = commoncrypto_opts_from_algo(name);
+ return std::unique_ptr<BlockCipher>(new CommonCrypto_BlockCipher(name, opts));
+ }
+ catch(CommonCrypto_Error e)
+ {
+ return nullptr;
+ }
+ }
+}
+
diff --git a/src/lib/prov/commoncrypto/commoncrypto_utils.cpp b/src/lib/prov/commoncrypto/commoncrypto_utils.cpp
index fc841f45c..62736b88c 100644
--- a/src/lib/prov/commoncrypto/commoncrypto_utils.cpp
+++ b/src/lib/prov/commoncrypto/commoncrypto_utils.cpp
@@ -90,19 +90,21 @@ CommonCryptor_Opts commoncrypto_opts_from_algo(const std::string& algo)
{
opts.algo = kCCAlgorithm3DES;
opts.block_size = kCCBlockSize3DES;
- opts.key_spec = Key_Length_Specification(kCCKeySize3DES);//, 16, 24, 8);
+ opts.key_spec = Key_Length_Specification(16, kCCKeySize3DES, 8);
}
else if(algo_name == "Blowfish")
{
opts.algo = kCCAlgorithmBlowfish;
opts.block_size = kCCBlockSizeBlowfish;
- opts.key_spec = Key_Length_Specification(kCCKeySizeMinBlowfish, kCCKeySizeMaxBlowfish);//, 1, 56, 1);
+ opts.key_spec = Key_Length_Specification(1, kCCKeySizeMaxBlowfish, 1);
}
else if(algo_name == "CAST-128")
{
opts.algo = kCCAlgorithmCAST;
opts.block_size = kCCBlockSizeCAST;
- opts.key_spec = Key_Length_Specification(kCCKeySizeMinCAST, kCCKeySizeMaxCAST);//, 1, 16, 1);
+ // Botan's base implementation of CAST does not support shorter keys
+ // so we limit its minimum key size to 11 here.
+ opts.key_spec = Key_Length_Specification(11, kCCKeySizeMaxCAST, 1);
}
else
{
@@ -146,4 +148,40 @@ CommonCryptor_Opts commoncrypto_opts_from_algo(const std::string& algo)
return opts;
}
+
+
+void commoncrypto_adjust_key_size(const uint8_t key[], size_t length,
+ const CommonCryptor_Opts& opts, secure_vector<uint8_t>& full_key)
+ {
+
+ if(opts.algo == kCCAlgorithmBlowfish && length < 8)
+ {
+ size_t repeat;
+ switch(length)
+ {
+ case 1:
+ repeat = 8;
+ break;
+ case 2:
+ repeat = 4;
+ break;
+ case 3:
+ repeat = 3;
+ break;
+ default:
+ repeat = 2;
+ break;
+ }
+
+ full_key.resize(length * repeat);
+ for(int i=0; i<repeat; i++)
+ {
+ memcpy(full_key.data() + i * length, key, length);
+ }
+ }
+ else if(opts.algo == kCCAlgorithm3DES && length == 16)
+ {
+ full_key += std::make_pair(key, 8);
+ }
+ }
}
diff --git a/src/lib/prov/commoncrypto/commoncrypto_utils.h b/src/lib/prov/commoncrypto/commoncrypto_utils.h
index 9847c292a..f4bdf4e24 100644
--- a/src/lib/prov/commoncrypto/commoncrypto_utils.h
+++ b/src/lib/prov/commoncrypto/commoncrypto_utils.h
@@ -27,6 +27,10 @@ struct CommonCryptor_Opts
CommonCryptor_Opts commoncrypto_opts_from_algo(const std::string& algo);
+void commoncrypto_adjust_key_size(const uint8_t key[], size_t length,
+ const CommonCryptor_Opts& opts, secure_vector<uint8_t>& full_key);
+
+
}
#endif
diff --git a/src/lib/prov/commoncrypto/info.txt b/src/lib/prov/commoncrypto/info.txt
index 8d5e4d50c..d56fe5731 100644
--- a/src/lib/prov/commoncrypto/info.txt
+++ b/src/lib/prov/commoncrypto/info.txt
@@ -14,4 +14,5 @@ commoncrypto
<requires>
modes
+block
</requires>