aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJack Lloyd <[email protected]>2017-10-20 20:15:16 -0400
committerJack Lloyd <[email protected]>2017-10-20 20:15:16 -0400
commitcba904d7a474ef4151654c762d110ffd19841b33 (patch)
treec49b12f2017607c43723465c2965b11a271e23e9
parenta6e051bea6e7341f8f7b8ab40e042e1e099b9b8b (diff)
Allow setting CTR width via string
Prohibit very small counter widths (under 4 bytes), since they lead to trivial keystream reuse. Add tests. Fix clone which always returned an object with a block-wide counter.
-rw-r--r--news.rst7
-rw-r--r--src/lib/stream/ctr/ctr.cpp8
-rw-r--r--src/lib/stream/ctr/ctr.h2
-rw-r--r--src/lib/stream/stream_cipher.cpp10
-rw-r--r--src/tests/data/stream/ctr.vec18
5 files changed, 39 insertions, 6 deletions
diff --git a/news.rst b/news.rst
index eac8422be..118c41d14 100644
--- a/news.rst
+++ b/news.rst
@@ -13,6 +13,13 @@ Version 2.4.0, Not Yet Released
They have been changed to use the correct encoding, and a test added
to ensure such errors do not recur.
+* Counter mode allows setting a configurable width of the counter.
+ Previously it was allowed for a counter of even 8 bits wide, which
+ would mean the keystream would repeat after just 256 blocks. Now it
+ requires the width be at least 32 bits. The only way this feature
+ could be used was by manually constructing a ``CTR_BE`` object and
+ setting the second parameter to something in the range of 1 to 3.
+
* Add an OID for RIPEMD-160
Version 2.3.0, 2017-10-02
diff --git a/src/lib/stream/ctr/ctr.cpp b/src/lib/stream/ctr/ctr.cpp
index d0b44589b..99a589bb9 100644
--- a/src/lib/stream/ctr/ctr.cpp
+++ b/src/lib/stream/ctr/ctr.cpp
@@ -32,7 +32,7 @@ CTR_BE::CTR_BE(BlockCipher* cipher, size_t ctr_size) :
m_iv(m_cipher->block_size()),
m_pad_pos(0)
{
- if(m_ctr_size == 0 || m_ctr_size > m_block_size)
+ if(m_ctr_size < 4 || m_ctr_size > m_block_size)
throw Invalid_Argument("Invalid CTR-BE counter size");
}
@@ -55,7 +55,11 @@ void CTR_BE::key_schedule(const uint8_t key[], size_t key_len)
std::string CTR_BE::name() const
{
- return ("CTR-BE(" + m_cipher->name() + ")");
+ if(m_ctr_size == m_block_size)
+ return ("CTR-BE(" + m_cipher->name() + ")");
+ else
+ return ("CTR-BE(" + m_cipher->name() + "," + std::to_string(m_ctr_size) + ")");
+
}
void CTR_BE::cipher(const uint8_t in[], uint8_t out[], size_t length)
diff --git a/src/lib/stream/ctr/ctr.h b/src/lib/stream/ctr/ctr.h
index 3ff63b8e5..c4c598161 100644
--- a/src/lib/stream/ctr/ctr.h
+++ b/src/lib/stream/ctr/ctr.h
@@ -34,7 +34,7 @@ class BOTAN_PUBLIC_API(2,0) CTR_BE final : public StreamCipher
std::string name() const override;
CTR_BE* clone() const override
- { return new CTR_BE(m_cipher->clone()); }
+ { return new CTR_BE(m_cipher->clone(), m_ctr_size); }
void clear() override;
diff --git a/src/lib/stream/stream_cipher.cpp b/src/lib/stream/stream_cipher.cpp
index f33d68296..c0e75c0a8 100644
--- a/src/lib/stream/stream_cipher.cpp
+++ b/src/lib/stream/stream_cipher.cpp
@@ -44,12 +44,16 @@ std::unique_ptr<StreamCipher> StreamCipher::create(const std::string& algo_spec,
const SCAN_Name req(algo_spec);
#if defined(BOTAN_HAS_CTR_BE)
- if(req.algo_name() == "CTR-BE" && req.arg_count() == 1)
+ if((req.algo_name() == "CTR-BE" || req.algo_name() == "CTR") && req.arg_count_between(1,2))
{
if(provider.empty() || provider == "base")
{
- if(auto c = BlockCipher::create(req.arg(0)))
- return std::unique_ptr<StreamCipher>(new CTR_BE(c.release()));
+ auto cipher = BlockCipher::create(req.arg(0));
+ if(cipher)
+ {
+ size_t ctr_size = req.arg_as_integer(1, cipher->block_size());
+ return std::unique_ptr<StreamCipher>(new CTR_BE(cipher.release(), ctr_size));
+ }
}
}
#endif
diff --git a/src/tests/data/stream/ctr.vec b/src/tests/data/stream/ctr.vec
index 9fddf1cfc..3eccc3cf6 100644
--- a/src/tests/data/stream/ctr.vec
+++ b/src/tests/data/stream/ctr.vec
@@ -280,6 +280,24 @@ Nonce = 88D9C46E992B27AE
In = CD
Out = 9D
+[CTR-BE(AES-128,4)]
+Key = 2B7E151628AED2A6ABF7158809CF4F3C
+Nonce = FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+In = 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+Out = 8AF2860142F786F409307C1A3F7EAAAC597D5761063D8BAD232CB0136888AABB90B8CF63F44412CEEE802A522AB6566313C5E10652749056AD2F02CE3BBF5BEC
+
+[CTR-BE(AES-128,5)]
+Key = 2B7E151628AED2A6ABF7158809CF4F3C
+Nonce = FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+In = 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+Out = 8AF2860142F786F409307C1A3F7EAAACE0828A20E49595A19191201820125CC1B976913097C4A3245CAB186AE3B581F173DFEE01730EBB880CB63C673CBD4FC1
+
+[CTR-BE(AES-128,6)]
+Key = 2B7E151628AED2A6ABF7158809CF4F3C
+Nonce = FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+In = 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+Out = 8AF2860142F786F409307C1A3F7EAAAC33E25A114853DFEA903DB7B182593CB439E12B65EBFE27B2C1557F1EAD7AB52F0D42E2BB9772747085DD8C2AF5F357BB
+
[CTR-BE(AES-128)]
Key = 2B7E151628AED2A6ABF7158809CF4F3C
Nonce = F0F1F2F3F4F5F6F7F8F9FAFBFCFDFEFF