1 /**
2 * ECB Mode
3 * 
4 * Copyright:
5 * (C) 1999-2009,2013 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.modes.ecb;
12 
13 import botan.constants;
14 static if (BOTAN_HAS_MODE_ECB):
15 
16 import botan.modes.cipher_mode;
17 import botan.block.block_cipher;
18 import botan.modes.mode_pad;
19 import botan.utils.loadstor;
20 import botan.utils.xor_buf;
21 import botan.utils.rounding;
22 import botan.utils.types;
23 
24 /**
25 * ECB mode
26 */
27 abstract class ECBMode : CipherMode, Transformation
28 {
29 public:
30     override SecureVector!ubyte startRaw(const(ubyte)*, size_t nonce_len)
31     {
32         if (!validNonceLength(nonce_len))
33             throw new InvalidIVLength(name(), nonce_len);
34         
35         return SecureVector!ubyte();
36     }
37 
38     override @property string name() const
39     {
40         return cipher().name ~ "/ECB/" ~ padding().name;
41     }
42 
43     override size_t updateGranularity() const
44     {
45         return cipher().parallelBytes();
46     }
47 
48     override KeyLengthSpecification keySpec() const
49     {
50         return cipher().keySpec();
51     }
52 
53     override size_t defaultNonceLength() const
54     {
55         return 0;
56     }
57 
58     override bool validNonceLength(size_t n) const
59     {
60         return (n == 0);
61     }
62 
63     override void clear()
64     {
65         m_cipher.clear();
66     }
67 
68     override bool authenticated() const { return true; }
69 protected:
70     this(BlockCipher cipher, BlockCipherModePaddingMethod padding)
71     {
72         m_cipher = cipher;
73         m_padding = padding;
74         if (!m_padding.validBlocksize(m_cipher.blockSize()))
75             throw new InvalidArgument("Padding " ~ m_padding.name ~ " cannot be used with " ~ m_cipher.name ~ "/ECB");
76     }
77 
78     final BlockCipher cipher() const { return cast()*m_cipher; }
79 
80     final const(BlockCipherModePaddingMethod) padding() const { return *m_padding; }
81 
82 protected:
83     final override void keySchedule(const(ubyte)* key, size_t length)
84     {
85         m_cipher.setKey(key, length);
86     }
87 
88     Unique!BlockCipher m_cipher;
89     Unique!BlockCipherModePaddingMethod m_padding;
90 }
91 
92 /**
93 * ECB Encryption
94 */
95 final class ECBEncryption : ECBMode, Transformation
96 {
97 public:
98     this(BlockCipher cipher, BlockCipherModePaddingMethod padding) 
99     {
100         super(cipher, padding);
101     }
102 
103     override void update(ref SecureVector!ubyte buffer, size_t offset = 0)
104     {
105         assert(buffer.length >= offset, "Offset is sane");
106         const size_t sz = buffer.length - offset;
107         ubyte* buf = buffer.ptr + offset;
108         
109         const size_t BS = cipher().blockSize();
110         
111         assert(sz % BS == 0, "ECB input is full blocks");
112         const size_t blocks = sz / BS;
113         
114         cipher().encryptN(buf, buf, blocks);
115     }
116 
117     override void finish(ref SecureVector!ubyte buffer, size_t offset = 0)
118     {
119         assert(buffer.length >= offset, "Offset is sane");
120         const size_t sz = buffer.length - offset;
121         
122         const size_t BS = cipher().blockSize();
123         
124         const size_t bytes_in_final_block = sz % BS;
125         
126         padding().addPadding(buffer, bytes_in_final_block, BS);
127         
128         if (buffer.length % BS)
129             throw new Exception("Did not pad to full block size in " ~ name);
130         
131         update(buffer, offset);
132     }
133 
134     override size_t outputLength(size_t input_length) const
135     {
136         return roundUp(input_length, cipher().blockSize());
137     }
138 
139     override size_t minimumFinalSize() const
140     {
141         return 0;
142     }
143 
144     // Interface fallthrough
145     override string provider() const { return "core"; }
146     override SecureVector!ubyte startRaw(const(ubyte)* nonce, size_t nonce_len) { return super.startRaw(nonce, nonce_len); }
147     override size_t updateGranularity() const { return super.updateGranularity(); }
148     override size_t defaultNonceLength() const { return super.defaultNonceLength(); }
149     override @property string name() const { return super.name; }
150     override void clear() { return super.clear(); }
151     override bool validNonceLength(size_t n) const {
152         return super.validNonceLength(n);
153     }
154 }
155 
156 /**
157 * ECB Decryption
158 */
159 final class ECBDecryption : ECBMode, Transformation
160 {
161 public:
162     this(BlockCipher cipher, BlockCipherModePaddingMethod padding)
163     {
164         super(cipher, padding);
165     }
166 
167     override void update(ref SecureVector!ubyte buffer, size_t offset = 0)
168     {
169         assert(buffer.length >= offset, "Offset is sane");
170         const size_t sz = buffer.length - offset;
171         ubyte* buf = buffer.ptr + offset;
172         
173         const size_t BS = cipher().blockSize();
174         
175         assert(sz % BS == 0, "Input is full blocks");
176         size_t blocks = sz / BS;
177         
178         cipher().decryptN(buf, buf, blocks);
179     }
180 
181     override void finish(ref SecureVector!ubyte buffer, size_t offset = 0)
182     {
183         assert(buffer.length >= offset, "Offset is sane");
184         const size_t sz = buffer.length - offset;
185         
186         const size_t BS = cipher().blockSize();
187         
188         if (sz == 0 || sz % BS)
189             throw new DecodingError(name ~ ": Ciphertext not a multiple of block size");
190         
191         update(buffer, offset);
192         
193         const size_t pad_bytes = BS - padding().unpad(&buffer[buffer.length-BS], BS);
194         buffer.resize(buffer.length - pad_bytes); // remove padding
195     }
196 
197     override size_t outputLength(size_t input_length) const
198     {
199         return input_length;
200     }
201 
202     override size_t minimumFinalSize() const
203     {
204         return cipher().blockSize();
205     }
206 
207     // Interface fallthrough
208     override string provider() const { return "core"; }
209     override SecureVector!ubyte startRaw(const(ubyte)* nonce, size_t nonce_len) { return super.startRaw(nonce, nonce_len); }
210     override size_t updateGranularity() const { return super.updateGranularity(); }
211     override size_t defaultNonceLength() const { return super.defaultNonceLength(); }
212     override @property string name() const { return super.name; }
213     override void clear() { return super.clear(); }
214     override bool validNonceLength(size_t n) const {
215         return super.validNonceLength(n);
216     }
217 }