1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
|
/*
* Block Cipher Cascade
* (C) 2010 Jack Lloyd
*
* Botan is released under the Simplified BSD License (see license.txt)
*/
#include <botan/internal/block_utils.h>
#include <botan/algo_registry.h>
#include <botan/cascade.h>
namespace Botan {
namespace {
Cascade_Cipher* make_cascade(const BlockCipher::Spec& spec)
{
auto& block_cipher = Algo_Registry<BlockCipher>::global_registry();
std::unique_ptr<BlockCipher> c1(block_cipher.make(spec.arg(0)));
std::unique_ptr<BlockCipher> c2(block_cipher.make(spec.arg(1)));
if(c1 && c2)
return new Cascade_Cipher(c1.release(), c2.release());
return nullptr;
}
}
BOTAN_REGISTER_NAMED_T(BlockCipher, "Cascade", Cascade_Cipher, make_cascade);
void Cascade_Cipher::encrypt_n(const byte in[], byte out[],
size_t blocks) const
{
size_t c1_blocks = blocks * (block_size() / m_cipher1->block_size());
size_t c2_blocks = blocks * (block_size() / m_cipher2->block_size());
m_cipher1->encrypt_n(in, out, c1_blocks);
m_cipher2->encrypt_n(out, out, c2_blocks);
}
void Cascade_Cipher::decrypt_n(const byte in[], byte out[],
size_t blocks) const
{
size_t c1_blocks = blocks * (block_size() / m_cipher1->block_size());
size_t c2_blocks = blocks * (block_size() / m_cipher2->block_size());
m_cipher2->decrypt_n(in, out, c2_blocks);
m_cipher1->decrypt_n(out, out, c1_blocks);
}
void Cascade_Cipher::key_schedule(const byte key[], size_t)
{
const byte* key2 = key + m_cipher1->maximum_keylength();
m_cipher1->set_key(key , m_cipher1->maximum_keylength());
m_cipher2->set_key(key2, m_cipher2->maximum_keylength());
}
void Cascade_Cipher::clear()
{
m_cipher1->clear();
m_cipher2->clear();
}
std::string Cascade_Cipher::name() const
{
return "Cascade(" + m_cipher1->name() + "," + m_cipher2->name() + ")";
}
BlockCipher* Cascade_Cipher::clone() const
{
return new Cascade_Cipher(m_cipher1->clone(),
m_cipher2->clone());
}
namespace {
size_t euclids_algorithm(size_t a, size_t b)
{
while(b != 0) // gcd
{
size_t t = b;
b = a % b;
a = t;
}
return a;
}
size_t block_size_for_cascade(size_t bs, size_t bs2)
{
if(bs == bs2)
return bs;
size_t gcd = euclids_algorithm(bs, bs2);
return (bs * bs2) / gcd;
}
}
Cascade_Cipher::Cascade_Cipher(BlockCipher* c1, BlockCipher* c2) :
m_cipher1(c1), m_cipher2(c2)
{
m_block = block_size_for_cascade(c1->block_size(), c2->block_size());
if(block_size() % c1->block_size() || block_size() % c2->block_size())
throw Internal_Error("Failure in " + name() + " constructor");
}
}
|