Initial commit.
[BoarSSL] / Crypto / BlockCipherCore.cs
1 /*
2 * Copyright (c) 2017 Thomas Pornin <pornin@bolet.org>
3 *
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:
11 *
12 * The above copyright notice and this permission notice shall be
13 * included in all copies or substantial portions of the Software.
14 *
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
22 * SOFTWARE.
23 */
24
25 using System;
26
27 namespace Crypto {
28
29 /*
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)
36 *
37 * Note that 'BlockSize' is invoked from the constructor of this class.
38 *
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 * Note that CBCEncrypt(byte[],byte[]) (respectively
47 * CBCDecrypt(byte[],byte[]) and CTRRun(byte[],uint,byte[])) simply
48 * calls CBCEncrypt(byte[],byte[],int,int) (respectively
49 * CBCDecrypt(byte[],byte[],int,int) and
50 * CTRRun(byte[],uint,byte[],int,int)) so implementations who wish to
51 * override these methods may content themselves with overriding the two
52 * methods with the "off" and "len" extra parameters.
53 */
54
55 public abstract class BlockCipherCore : IBlockCipher {
56
57 byte[] tmp;
58
59 /*
60 * This constructor invokes 'BlockSize'.
61 */
62 public BlockCipherCore()
63 {
64 tmp = new byte[BlockSize];
65 }
66
67 /* see IBlockCipher */
68 public abstract int BlockSize { get; }
69
70 /*
71 * This method is implemented by calling SetKey(byte[],int,int).
72 */
73 public virtual void SetKey(byte[] key)
74 {
75 SetKey(key, 0, key.Length);
76 }
77
78 /* see IBlockCipher */
79 public abstract void SetKey(byte[] key, int off, int len);
80
81 /*
82 * This method is implemented by calling BlockEncrypt(byte[],int).
83 */
84 public virtual void BlockEncrypt(byte[] buf)
85 {
86 BlockEncrypt(buf, 0);
87 }
88
89 /* see IBlockCipher */
90 public abstract void BlockEncrypt(byte[] data, int off);
91
92 /*
93 * This method is implemented by calling BlockDecrypt(byte[],int).
94 */
95 public virtual void BlockDecrypt(byte[] buf)
96 {
97 BlockDecrypt(buf, 0);
98 }
99
100 /* see IBlockCipher */
101 public abstract void BlockDecrypt(byte[] data, int off);
102
103 /*
104 * This method is implemented by calling
105 * CBCEncrypt(byte[],byte[],int,int).
106 */
107 public virtual void CBCEncrypt(byte[] iv, byte[] data)
108 {
109 CBCEncrypt(iv, data, 0, data.Length);
110 }
111
112 /* see IBlockCipher */
113 public virtual void CBCEncrypt(
114 byte[] iv, byte[] data, int off, int len)
115 {
116 int blen = BlockSize;
117 if (iv.Length != blen) {
118 throw new CryptoException("wrong IV length");
119 }
120 if (len >= blen) {
121 for (int i = 0; i < blen; i ++) {
122 data[off + i] ^= iv[i];
123 }
124 BlockEncrypt(data, off);
125 off += blen;
126 len -= blen;
127 while (len >= blen) {
128 for (int i = 0; i < blen; i ++) {
129 data[off + i] ^= data[off + i - blen];
130 }
131 BlockEncrypt(data, off);
132 off += blen;
133 len -= blen;
134 }
135 }
136 if (len != 0) {
137 throw new CryptoException("data length is not"
138 + " multiple of the block size");
139 }
140 }
141
142 /*
143 * This method is implemented by calling
144 * CBCDecrypt(byte[],byte[],int,int).
145 */
146 public virtual void CBCDecrypt(byte[] iv, byte[] data)
147 {
148 CBCDecrypt(iv, data, 0, data.Length);
149 }
150
151 /* see IBlockCipher */
152 public virtual void CBCDecrypt(
153 byte[] iv, byte[] data, int off, int len)
154 {
155 int blen = BlockSize;
156 if (iv.Length != blen) {
157 throw new CryptoException("wrong IV length");
158 }
159 int dblen = blen << 1;
160 off += len;
161 while (len >= dblen) {
162 off -= blen;
163 BlockDecrypt(data, off);
164 for (int i = 0; i < blen; i ++) {
165 data[off + i] ^= data[off + i - blen];
166 }
167 len -= blen;
168 }
169 if (len >= blen) {
170 off -= blen;
171 BlockDecrypt(data, off);
172 for (int i = 0; i < blen; i ++) {
173 data[off + i] ^= iv[i];
174 }
175 len -= blen;
176 }
177 if (len != 0) {
178 throw new CryptoException("data length is not"
179 + " multiple of the block size");
180 }
181 }
182
183 /*
184 * This method is implemented by calling
185 * CTRRun(byte[],uint,byte[],int,int).
186 */
187 public virtual uint CTRRun(byte[] iv, uint cc, byte[] data)
188 {
189 return CTRRun(iv, cc, data, 0, data.Length);
190 }
191
192 /* see IBlockCipher */
193 public virtual uint CTRRun(
194 byte[] iv, uint cc, byte[] data, int off, int len)
195 {
196 int blen = BlockSize;
197 if (iv.Length != blen - 4) {
198 throw new CryptoException("wrong IV length");
199 }
200 while (len > 0) {
201 Array.Copy(iv, 0, tmp, 0, blen - 4);
202 tmp[blen - 4] = (byte)(cc >> 24);
203 tmp[blen - 3] = (byte)(cc >> 16);
204 tmp[blen - 2] = (byte)(cc >> 8);
205 tmp[blen - 1] = (byte)cc;
206 BlockEncrypt(tmp, 0);
207 int clen = Math.Min(blen, len);
208 for (int i = 0; i < clen; i ++) {
209 data[off + i] ^= tmp[i];
210 }
211 off += clen;
212 len -= clen;
213 cc ++;
214 }
215 return cc;
216 }
217
218 /* see IBlockCipher */
219 public abstract IBlockCipher Dup();
220 }
221
222 }