1 unit AES_CBC;
2 
3 (*************************************************************************
4 
5  DESCRIPTION     :  AES CBC functions
6 
7  REQUIREMENTS    :  TP5-7, D1-D7/D9-D10/D12, FPC, VP
8 
9  EXTERNAL DATA   :  ---
10 
11  MEMORY USAGE    :  ---
12 
13  DISPLAY MODE    :  ---
14 
15  REFERENCES      :  [3] http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf
16                     [1] http://csrc.nist.gov/fips/fips-197.pdf
17                     [4] Cipher text stealing: Schneier, Applied Cryptography 2.ed, ch.9.3
18 
19 
20  Version  Date      Author      Modification
21  -------  --------  -------     ------------------------------------------
22  0.10     20.09.03  we          initial version
23  0.20     21.09.03  we          Cipher text stealing
24  0.21     21.09.03  we          with Flag, functions, error codes
25  0.22     27.09.03  we          FPC/go32v2
26  0.23     03.10.03  we          3-para encr/decr
27  0.24     03.10.03  we          Fix overwrite source bug for decrypt
28  0.25     05.10.03  we          STD.INC, TP5-6
29  0.26     12.06.04  we          uses BLKSIZE constant
30  0.27     12.06.04  we          check for nil pointers
31  0.28     02.07.04  we          {$ifdef DLL} stdcall; {$endif}
32  0.29     30.11.04  we          AES_XorBlock, AESBLKSIZE
33  0.30     01.12.04  we          No more processing after short block
34  0.31     09.07.06  we          Checked: D9-D10
35  0.34     16.11.08  we          Use Ptr2Inc from BTypes
36  0.35     27.07.10  we          Longint ILen in AES_CBC_En/Decrypt
37 **************************************************************************)
38 
39 
40 (*-------------------------------------------------------------------------
41  (C) Copyright 2002-2010 Wolfgang Ehrhardt
42 
43  This software is provided 'as-is', without any express or implied warranty.
44  In no event will the authors be held liable for any damages arising from
45  the use of this software.
46 
47  Permission is granted to anyone to use this software for any purpose,
48  including commercial applications, and to alter it and redistribute it
49  freely, subject to the following restrictions:
50 
51  1. The origin of this software must not be misrepresented; you must not
52     claim that you wrote the original software. If you use this software in
53     a product, an acknowledgment in the product documentation would be
54     appreciated but is not required.
55 
56  2. Altered source versions must be plainly marked as such, and must not be
57     misrepresented as being the original software.
58 
59  3. This notice may not be removed or altered from any source distribution.
60 ----------------------------------------------------------------------------*)
61 
62 {$i STD.INC}
63 
64 interface
65 
66 
67 uses
68   BTypes, AES_Type, AES_Base, AES_Encr, AES_Decr;
69 
70 {$ifdef CONST}
71 
AES_CBC_Init_Encrnull72 function AES_CBC_Init_Encr(const Key; KeyBits: word; const IV: TAESBlock; var ctx: TAESContext): integer;
73   {-AES key expansion, error if invalid key size, encrypt IV}
74   {$ifdef DLL} stdcall; {$endif}
75 
AES_CBC_Init_Decrnull76 function AES_CBC_Init_Decr(const Key; KeyBits: word; const IV: TAESBlock; var ctx: TAESContext): integer;
77   {-AES key expansion, error if invalid key size, encrypt IV}
78   {$ifdef DLL} stdcall; {$endif}
79 
80 {$else}
81 
AES_CBC_Init_Encrnull82 function AES_CBC_Init_Encr(var Key; KeyBits: word; var IV: TAESBlock; var ctx: TAESContext): integer;
83   {-AES key expansion, error if invalid key size, encrypt IV}
84 
AES_CBC_Init_Decrnull85 function AES_CBC_Init_Decr(var Key; KeyBits: word; var IV: TAESBlock; var ctx: TAESContext): integer;
86   {-AES key expansion, error if invalid key size, encrypt IV}
87 
88 {$endif}
89 
90 
AES_CBC_Encryptnull91 function AES_CBC_Encrypt(ptp, ctp: Pointer; ILen: longint; var ctx: TAESContext): integer;
92   {-Encrypt ILen bytes from ptp^ to ctp^ in CBC mode}
93   {$ifdef DLL} stdcall; {$endif}
94 
AES_CBC_Decryptnull95 function AES_CBC_Decrypt(ctp, ptp: Pointer; ILen: longint; var ctx: TAESContext): integer;
96   {-Decrypt ILen bytes from ctp^ to ptp^ in CBC mode}
97   {$ifdef DLL} stdcall; {$endif}
98 
99 
100 implementation
101 
102 
103 {---------------------------------------------------------------------------}
104 {$ifdef CONST}
AES_CBC_Init_Encrnull105   function AES_CBC_Init_Encr(const Key; KeyBits: word; const IV: TAESBlock; var ctx: TAESContext): integer;
106 {$else}
AES_CBC_Init_Encrnull107   function AES_CBC_Init_Encr(var Key; KeyBits: word; var IV: TAESBlock; var ctx: TAESContext): integer;
108 {$endif}
109   {-AES key expansion, error if invalid key size, encrypt IV}
110 begin
111   {-AES key expansion, error if invalid key size}
112   AES_CBC_Init_Encr := AES_Init_Encr(Key, KeyBits, ctx);
113   ctx.IV := IV;
114 end;
115 
116 
117 {---------------------------------------------------------------------------}
118 {$ifdef CONST}
AES_CBC_Init_Decrnull119 function AES_CBC_Init_Decr(const Key; KeyBits: word; const IV: TAESBlock; var ctx: TAESContext): integer;
120 {$else}
AES_CBC_Init_Decrnull121 function AES_CBC_Init_Decr(var Key; KeyBits: word; var IV: TAESBlock; var ctx: TAESContext): integer;
122 {$endif}
123   {-AES key expansion, error if invalid key size, encrypt IV}
124 begin
125   {-AES key expansion, error if invalid key size}
126   AES_CBC_Init_Decr := AES_Init_Decr(Key, KeyBits, ctx);
127   ctx.IV := IV;
128 end;
129 
130 
131 {---------------------------------------------------------------------------}
AES_CBC_Encryptnull132 function AES_CBC_Encrypt(ptp, ctp: Pointer; ILen: longint; var ctx: TAESContext): integer;
133   {-Encrypt ILen bytes from ptp^ to ctp^ in CBC mode}
134 var
135   i,n: longint;
136   m: word;
137 begin
138 
139   AES_CBC_Encrypt := 0;
140   if ILen<0 then ILen := 0;
141 
142   if ctx.Decrypt<>0 then begin
143     AES_CBC_Encrypt := AES_Err_Invalid_Mode;
144     exit;
145   end;
146 
147   if (ptp=nil) or (ctp=nil) then begin
148     if ILen>0 then begin
149       AES_CBC_Encrypt := AES_Err_NIL_Pointer;
150       exit;
151     end;
152   end;
153 
154   {$ifdef BIT16}
155     if (ofs(ptp^)+ILen>$FFFF) or (ofs(ctp^)+ILen>$FFFF) then begin
156       AES_CBC_Encrypt := AES_Err_Invalid_16Bit_Length;
157       exit;
158     end;
159   {$endif}
160 
161   n := ILen div AESBLKSIZE; {Full blocks}
162   m := ILen mod AESBLKSIZE; {Remaining bytes in short block}
163   if m<>0 then begin
164     if n=0 then begin
165       AES_CBC_Encrypt := AES_Err_Invalid_Length;
166       exit;
167     end;
168     dec(n);           {CTS: special treatment of last TWO blocks}
169   end;
170 
171   {Short block must be last, no more processing allowed}
172   if ctx.Flag and 1 <> 0 then begin
173     AES_CBC_Encrypt := AES_Err_Data_After_Short_Block;
174     exit;
175   end;
176 
177   with ctx do begin
178     for i:=1 to n do begin
179       {ct[i] = encr(ct[i-1] xor pt[i]), cf. [3] 6.2}
180       AES_XorBlock(PAESBlock(ptp)^, IV, IV);
181       AES_Encrypt(ctx, IV, IV);
182       PAESBlock(ctp)^ := IV;
183       inc(Ptr2Inc(ptp),AESBLKSIZE);
184       inc(Ptr2Inc(ctp),AESBLKSIZE);
185     end;
186     if m<>0 then begin
187       {Cipher text stealing}
188       AES_XorBlock(PAESBlock(ptp)^, IV, IV);
189       AES_Encrypt(ctx, IV, IV);
190       buf := IV;
191       inc(Ptr2Inc(ptp),AESBLKSIZE);
192       for i:=0 to m-1 do IV[i] := IV[i] xor PAESBlock(ptp)^[i];
193       AES_Encrypt(ctx, IV, PAESBlock(ctp)^);
194       inc(Ptr2Inc(ctp),AESBLKSIZE);
195       move(buf,PAESBlock(ctp)^,m);
196       {Set short block flag}
197       Flag := Flag or 1;
198     end;
199   end;
200 end;
201 
202 
203 {---------------------------------------------------------------------------}
AES_CBC_Decryptnull204 function AES_CBC_Decrypt(ctp, ptp: Pointer; ILen: longint; var ctx: TAESContext): integer;
205   {-Decrypt ILen bytes from ctp^ to ptp^ in CBC mode}
206 var
207   i,n: longint;
208   m: word;
209   tmp: TAESBlock;
210 begin
211 
212   AES_CBC_Decrypt := 0;
213   if ILen<0 then ILen := 0;
214 
215   if ctx.Decrypt=0 then begin
216     AES_CBC_Decrypt := AES_Err_Invalid_Mode;
217     exit;
218   end;
219 
220   if (ptp=nil) or (ctp=nil) then begin
221     if ILen>0 then begin
222       AES_CBC_Decrypt := AES_Err_NIL_Pointer;
223       exit;
224     end;
225   end;
226 
227   {$ifdef BIT16}
228     if (ofs(ptp^)+ILen>$FFFF) or (ofs(ctp^)+ILen>$FFFF) then begin
229       AES_CBC_Decrypt := AES_Err_Invalid_16Bit_Length;
230       exit;
231     end;
232   {$endif}
233 
234   n := ILen div AESBLKSIZE; {Full blocks}
235   m := ILen mod AESBLKSIZE; {Remaining bytes in short block}
236   if m<>0 then begin
237     if n=0 then begin
238       AES_CBC_Decrypt := AES_Err_Invalid_Length;
239       exit;
240     end;
241     dec(n);           {CTS: special treatment of last TWO blocks}
242   end;
243 
244   {Short block must be last, no more processing allowed}
245   if ctx.Flag and 1 <> 0 then begin
246     AES_CBC_Decrypt := AES_Err_Data_After_Short_Block;
247     exit;
248   end;
249 
250   with ctx do begin
251     for i:=1 to n do begin
252       {pt[i] = decr(ct[i]) xor ct[i-1]), cf. [3] 6.2}
253       buf := IV;
254       IV  := PAESBlock(ctp)^;
255       AES_Decrypt(ctx, IV, PAESBlock(ptp)^);
256       AES_XorBlock(PAESBlock(ptp)^, buf, PAESBlock(ptp)^);
257       inc(Ptr2Inc(ptp),AESBLKSIZE);
258       inc(Ptr2Inc(ctp),AESBLKSIZE);
259     end;
260     if m<>0 then begin
261       {Cipher text stealing, L=ILen (Schneier's n)}
262       buf := IV;                       {C(L-2)}
263       AES_Decrypt(ctx, PAESBlock(ctp)^, IV);
264       inc(Ptr2Inc(ctp),AESBLKSIZE);
265       fillchar(tmp,sizeof(tmp),0);
266       move(PAESBlock(ctp)^,tmp,m);     {c[L]|0}
267       AES_XorBlock(tmp,IV,IV);
268       tmp := IV;
269       move(PAESBlock(ctp)^,tmp,m);     {c[L]| C'}
270       AES_Decrypt(ctx,tmp,tmp);
271       AES_XorBlock(tmp, buf, PAESBlock(ptp)^);
272       inc(Ptr2Inc(ptp),AESBLKSIZE);
273       move(IV,PAESBlock(ptp)^,m);
274       {Set short block flag}
275       Flag := Flag or 1;
276     end;
277   end;
278 end;
279 
280 end.
281