aboutsummaryrefslogtreecommitdiffstats
path: root/src/block/cascade/cascade.cpp
blob: e93e81d33f65312531466f310cbc0b3c5ac2090e (plain)
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
/*
* Block Cipher Cascade
* (C) 2010 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/

#include <botan/cascade.h>

namespace Botan {

void Cascade_Cipher::encrypt_n(const byte in[], byte out[],
                               size_t blocks) const
   {
   size_t c1_blocks = blocks * (BLOCK_SIZE / cipher1->BLOCK_SIZE);
   size_t c2_blocks = blocks * (BLOCK_SIZE / cipher2->BLOCK_SIZE);

   cipher1->encrypt_n(in, out, c1_blocks);
   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 / cipher1->BLOCK_SIZE);
   size_t c2_blocks = blocks * (BLOCK_SIZE / cipher2->BLOCK_SIZE);

   cipher2->decrypt_n(in, out, c2_blocks);
   cipher1->decrypt_n(out, out, c1_blocks);
   }

void Cascade_Cipher::key_schedule(const byte key[], u32bit)
   {
   const byte* key2 = key + cipher1->MAXIMUM_KEYLENGTH;

   cipher1->set_key(key , cipher1->MAXIMUM_KEYLENGTH);
   cipher2->set_key(key2, cipher2->MAXIMUM_KEYLENGTH);
   }

void Cascade_Cipher::clear()
   {
   cipher1->clear();
   cipher2->clear();
   }

std::string Cascade_Cipher::name() const
   {
   return "Cascade(" + cipher1->name() + "," + cipher2->name() + ")";
   }

BlockCipher* Cascade_Cipher::clone() const
   {
   return new Cascade_Cipher(cipher1->clone(),
                             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) :
   BlockCipher(block_size_for_cascade(c1->BLOCK_SIZE, c2->BLOCK_SIZE),
               c1->MAXIMUM_KEYLENGTH + c2->MAXIMUM_KEYLENGTH),
   cipher1(c1), cipher2(c2)
   {
   if(BLOCK_SIZE % c1->BLOCK_SIZE || BLOCK_SIZE % c2->BLOCK_SIZE)
      throw Internal_Error("Failure in " + name() + " constructor");
   }

Cascade_Cipher::~Cascade_Cipher()
   {
   delete cipher1;
   delete cipher2;
   }

}