2 * Copyright (c) 2017 Thomas Pornin <pornin@bolet.org>
4 * Permission is hereby granted, free of charge, to any person obtaining
5 * a copy of this software and associated documentation files (the
6 * "Software"), to deal in the Software without restriction, including
7 * without limitation the rights to use, copy, modify, merge, publish,
8 * distribute, sublicense, and/or sell copies of the Software, and to
9 * permit persons to whom the Software is furnished to do so, subject to
10 * the following conditions:
12 * The above copyright notice and this permission notice shall be
13 * included in all copies or substantial portions of the Software.
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
19 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
20 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
21 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
30 * This class is a convenient base class for implementations of
31 * IBlockCipher. Block cipher implementations must implement:
32 * int BlockSize { get; }
33 * void SetKey(byte[] key, int off, int len)
34 * void BlockEncrypt(byte[] data, int off)
35 * void BlockDecrypt(byte[] data, int off)
37 * Note that 'BlockSize' is invoked from the constructor of this class.
39 * Implementations MAY also override the default implementations of:
40 * void CBCEncrypt(byte[] iv, byte[] data)
41 * void CBCEncrypt(byte[] iv, byte[] data, int off, int len)
42 * void CBCDecrypt(byte[] iv, byte[] data)
43 * void CBCDecrypt(byte[] iv, byte[] data, int off, int len)
44 * uint CTRRun(byte[] iv, uint cc, byte[] data)
45 * uint CTRRun(byte[] iv, uint cc, byte[] data, int off, int len)
46 * void CTRCBCRun(byte[] ctr, byte[] cbcmac, bool encrypt, byte[] data)
47 * void CTRCBCRun(byte[] ctr, byte[] cbcmac, bool encrypt,
48 * byte[] data, int off, int len)
49 * Note that CBCEncrypt(byte[],byte[]) (respectively
50 * CBCDecrypt(byte[],byte[]), CTRRun(byte[],uint,byte[]) and
51 * CTRCBCRun(byte[],byte[],bool,byte[])) simply calls
52 * CBCEncrypt(byte[],byte[],int,int) (respectively
53 * CBCDecrypt(byte[],byte[],int,int), CTRRun(byte[],uint,byte[],int,int)
54 * and CTRCBCRun(byte[],byte[],bool,byte[],int,int)) so implementations
55 * who wish to override these methods may content themselves with
56 * overriding the four methods with the "off" and "len" extra parameters.
59 public abstract class BlockCipherCore : IBlockCipher {
64 * This constructor invokes 'BlockSize'.
66 public BlockCipherCore()
68 tmp = new byte[BlockSize];
71 /* see IBlockCipher */
72 public abstract int BlockSize { get; }
75 * This method is implemented by calling SetKey(byte[],int,int).
77 public virtual void SetKey(byte[] key)
79 SetKey(key, 0, key.Length);
82 /* see IBlockCipher */
83 public abstract void SetKey(byte[] key, int off, int len);
86 * This method is implemented by calling BlockEncrypt(byte[],int).
88 public virtual void BlockEncrypt(byte[] buf)
93 /* see IBlockCipher */
94 public abstract void BlockEncrypt(byte[] data, int off);
97 * This method is implemented by calling BlockDecrypt(byte[],int).
99 public virtual void BlockDecrypt(byte[] buf)
101 BlockDecrypt(buf, 0);
104 /* see IBlockCipher */
105 public abstract void BlockDecrypt(byte[] data, int off);
108 * This method is implemented by calling
109 * CBCEncrypt(byte[],byte[],int,int).
111 public virtual void CBCEncrypt(byte[] iv, byte[] data)
113 CBCEncrypt(iv, data, 0, data.Length);
116 /* see IBlockCipher */
117 public virtual void CBCEncrypt(
118 byte[] iv, byte[] data, int off, int len)
120 int blen = BlockSize;
121 if (iv.Length != blen) {
122 throw new CryptoException("wrong IV length");
125 for (int i = 0; i < blen; i ++) {
126 data[off + i] ^= iv[i];
128 BlockEncrypt(data, off);
131 while (len >= blen) {
132 for (int i = 0; i < blen; i ++) {
133 data[off + i] ^= data[off + i - blen];
135 BlockEncrypt(data, off);
141 throw new CryptoException("data length is not"
142 + " multiple of the block size");
147 * This method is implemented by calling
148 * CBCDecrypt(byte[],byte[],int,int).
150 public virtual void CBCDecrypt(byte[] iv, byte[] data)
152 CBCDecrypt(iv, data, 0, data.Length);
155 /* see IBlockCipher */
156 public virtual void CBCDecrypt(
157 byte[] iv, byte[] data, int off, int len)
159 int blen = BlockSize;
160 if (iv.Length != blen) {
161 throw new CryptoException("wrong IV length");
163 int dblen = blen << 1;
165 while (len >= dblen) {
167 BlockDecrypt(data, off);
168 for (int i = 0; i < blen; i ++) {
169 data[off + i] ^= data[off + i - blen];
175 BlockDecrypt(data, off);
176 for (int i = 0; i < blen; i ++) {
177 data[off + i] ^= iv[i];
182 throw new CryptoException("data length is not"
183 + " multiple of the block size");
188 * This method is implemented by calling
189 * CTRRun(byte[],uint,byte[],int,int).
191 public virtual uint CTRRun(byte[] iv, uint cc, byte[] data)
193 return CTRRun(iv, cc, data, 0, data.Length);
196 /* see IBlockCipher */
197 public virtual uint CTRRun(
198 byte[] iv, uint cc, byte[] data, int off, int len)
200 int blen = BlockSize;
201 if (iv.Length != blen - 4) {
202 throw new CryptoException("wrong IV length");
205 Array.Copy(iv, 0, tmp, 0, blen - 4);
206 tmp[blen - 4] = (byte)(cc >> 24);
207 tmp[blen - 3] = (byte)(cc >> 16);
208 tmp[blen - 2] = (byte)(cc >> 8);
209 tmp[blen - 1] = (byte)cc;
210 BlockEncrypt(tmp, 0);
211 int clen = Math.Min(blen, len);
212 for (int i = 0; i < clen; i ++) {
213 data[off + i] ^= tmp[i];
223 * This method is implemented by calling
224 * CTRCBCRun(byte[],byte[],bool,byte[],int,int).
226 public virtual void CTRCBCRun(byte[] ctr, byte[] cbcmac,
227 bool encrypt, byte[] data)
229 CTRCBCRun(ctr, cbcmac, encrypt, data, 0, data.Length);
232 /* see IBlockCipher */
233 public virtual void CTRCBCRun(byte[] ctr, byte[] cbcmac,
234 bool encrypt, byte[] data, int off, int len)
237 CBCMac(cbcmac, data, off, len);
239 DoCTRFull(ctr, data, off, len);
241 CBCMac(cbcmac, data, off, len);
245 void DoCTRFull(byte[] ctr, byte[] data, int off, int len)
247 int blen = BlockSize;
248 if (ctr.Length != blen) {
249 throw new CryptoException("wrong counter length");
252 Array.Copy(ctr, 0, tmp, 0, blen);
254 for (int i = blen - 1; i >= 0; i --) {
255 uint x = ctr[i] + cc;
259 BlockEncrypt(tmp, 0);
260 int clen = Math.Min(blen, len);
261 for (int i = 0; i < clen; i ++) {
262 data[off + i] ^= tmp[i];
269 /* see IBlockCipher */
270 public void CBCMac(byte[] cbcmac, byte[] data, int off, int len)
272 int blen = BlockSize;
273 if (cbcmac.Length != blen) {
274 throw new CryptoException("wrong MAC length");
277 for (int i = 0; i < blen; i ++) {
278 cbcmac[i] ^= data[off + i];
280 BlockEncrypt(cbcmac, 0);
286 /* see IBlockCipher */
287 public abstract IBlockCipher Dup();