1 /**
2 * CTR-BE Mode
3 * 
4 * Copyright:
5 * (C) 1999-2007 Jack Lloyd
6 * (C) 2014-2015 Etienne Cimon
7 *
8 * License:
9 * Botan is released under the Simplified BSD License (see LICENSE.md)
10 */
11 module botan.stream.ctr;
12 
13 import botan.constants;
14 static if (BOTAN_HAS_CTR_BE):
15 
16 import botan.block.block_cipher;
17 import botan.stream.stream_cipher;
18 import botan.utils.xor_buf;
19 import botan.utils.types;
20 import botan.utils.mem_ops;
21 
22 /**
23 * CTR-BE (Counter mode, big-endian)
24 */
25 final class CTRBE : StreamCipher, SymmetricAlgorithm
26 {
27 public:
28     override void cipher(const(ubyte)* input, ubyte* output, size_t length)
29     {
30         while (length >= m_pad.length - m_pad_pos)
31         {
32             xorBuf(output, input, &m_pad[m_pad_pos], m_pad.length - m_pad_pos);
33             length -= (m_pad.length - m_pad_pos);
34             input += (m_pad.length - m_pad_pos);
35             output += (m_pad.length - m_pad_pos);
36             increment_counter();
37         }
38         xorBuf(output, input, &m_pad[m_pad_pos], length);
39         m_pad_pos += length;
40     }
41 
42 
43     override void setIv(const(ubyte)* iv, size_t iv_len)
44     {
45         if (!validIvLength(iv_len))
46             throw new InvalidIVLength(name, iv_len);
47         
48         const size_t bs = m_cipher.blockSize();
49         
50         zeroise(m_counter);
51         
52         bufferInsert(m_counter, 0, iv, iv_len);
53         
54         // Set m_counter blocks to IV, IV + 1, ... IV + 255
55         foreach (size_t i; 1 .. 256)
56         {
57             bufferInsert(m_counter, i*bs, &m_counter[(i-1)*bs], bs);
58             
59             foreach (size_t j; 0 .. bs)
60                 if (++(m_counter[i*bs + (bs - 1 - j)]))
61                     break;
62         }
63         
64         m_cipher.encryptN(m_counter.ptr, m_pad.ptr, 256);
65         m_pad_pos = 0;
66     }
67 
68     override bool validIvLength(size_t iv_len) const
69     { return (iv_len <= m_cipher.blockSize()); }
70 
71     KeyLengthSpecification keySpec() const
72     {
73         return m_cipher.keySpec();
74     }
75 
76     @property string name() const
77     {
78         return ("CTR-BE(" ~ m_cipher.name ~ ")");
79     }
80 
81     override CTRBE clone() const
82     { return new CTRBE(m_cipher.clone()); }
83 
84     override void clear()
85     {
86         m_cipher.clear();
87         zeroise(m_pad);
88         zeroise(m_counter);
89         m_pad_pos = 0;
90     }
91 
92     /**
93     * Params:
94     *  ciph = the underlying block cipher to use
95     */
96     this(BlockCipher ciph)
97     {
98         m_cipher = ciph;
99         m_counter = 256 * m_cipher.blockSize();
100         m_pad = m_counter.length;
101         m_pad_pos = 0;
102     }
103 protected:
104     override void keySchedule(const(ubyte)* key, size_t length)
105     {
106         m_cipher.setKey(key, length);
107         
108         // Set a default all-zeros IV
109         setIv(null, 0);
110     }
111 
112     /*
113     * Increment the counter and update the buffer
114     */
115     void increment_counter()
116     {
117         const size_t bs = m_cipher.blockSize();
118         
119         /*
120         * Each counter value always needs to be incremented by 256,
121         * so we don't touch the lowest ubyte and instead treat it as
122         * an increment of one starting with the next ubyte.
123         */
124         foreach (size_t i; 0 .. 256)
125         {
126             foreach (size_t j; 1 .. bs)
127                 if (++(m_counter[i*bs + (bs - 1 - j)]))
128                     break;
129         }
130         
131         m_cipher.encryptN(m_counter.ptr, m_pad.ptr, 256);
132         m_pad_pos = 0;
133     }
134 
135     Unique!BlockCipher m_cipher;
136     SecureVector!ubyte m_counter, m_pad;
137     size_t m_pad_pos;
138 }