unit AES_XTS; (************************************************************************* DESCRIPTION : AES XTS mode functions REQUIREMENTS : TP5-7, D1-D7/D9-D10/D12, FPC, VP EXTERNAL DATA : --- MEMORY USAGE : --- DISPLAY MODE : --- REMARKS : 1. The IV and buf fields of the main contexts are used for temparary buffers. Tweak context IV holds enc(tweak)*a^j. 2. Quote from the IEEE Draft: "Attention is called to the possibility that implementation of this standard may require use of subject matter covered by patent rights." Before using this source/mode read the patent section in legal.txt! REFERENCES : [1] IEEE P1619, Draft Standard for Cryptographic Protection of Data on Block-Oriented Storage Devices. Available from http://ieee-p1619.wetpaint.com/page/IEEE+Project+1619+Home Version Date Author Modification ------- -------- ------- ------------------------------------------ 0.10 23.09.07 we Initial version like ECB (BP7+, encrypt) 0.11 24.09.07 we BP7+ decrypt 0.12 24.09.07 we TP5-TP6 0.13 27.09.07 we ILen now longint 0.14 27.09.07 we Check ILen+ofs if BIT16 and $R+ 0.15 16.11.08 we Use Ptr2Inc from BTypes 0.16 27.07.10 we AES_Err_Invalid_16Bit_Length **************************************************************************) (*------------------------------------------------------------------------- (C) Copyright 2007-2010 Wolfgang Ehrhardt This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 3. This notice may not be removed or altered from any source distribution. ----------------------------------------------------------------------------*) {$i STD.INC} interface uses BTypes, AES_Type, AES_Base, AES_Encr, AES_Decr; type TAES_XTSContext = packed record main : TAESContext; {Main context} tweak: TAESContext; {Tweak context} end; function AES_XTS_Init_Encr({$ifdef CONST}const{$else}var{$endif} K1,K2; KBits: word; var ctx: TAES_XTSContext): integer; {-Init XTS encrypt context (key expansion), error if invalid key size} {$ifdef DLL} stdcall; {$endif} function AES_XTS_Encrypt(ptp, ctp: Pointer; ILen: longint; {$ifdef CONST}const{$else}var{$endif} twk: TAESBlock; var ctx: TAES_XTSContext): integer; {-Encrypt data unit of ILen bytes from ptp^ to ctp^ in XTS mode, twk: tweak of data unit} {$ifdef DLL} stdcall; {$endif} function AES_XTS_Init_Decr({$ifdef CONST}const{$else}var{$endif} K1,K2; KBits: word; var ctx: TAES_XTSContext): integer; {-Init XTS decrypt context (key expansion), error if invalid key size} {$ifdef DLL} stdcall; {$endif} function AES_XTS_Decrypt(ctp, ptp: Pointer; ILen: longint; {$ifdef CONST}const{$else}var{$endif} twk: TAESBlock; var ctx: TAES_XTSContext): integer; {-Decrypt data unit of ILen bytes from ptp^ to ctp^ in XTS mode, twk: tweak of data unit} {$ifdef DLL} stdcall; {$endif} implementation {---------------------------------------} procedure mul_a(var T: TAESBlock); {-Multiply tweak block by the primitive element a from GF(2^128)} var i: integer; cin,cout: byte; const masks: array[0..1] of byte = (0,$87); begin cin := 0; {Turn off range checking for byte shifts} {$ifopt R+} {$define SetRPlus} {$else} {$undef SetRPlus} {$endif} {$R-} for i:=0 to AESBLKSIZE-1 do begin cout := T[i] shr 7; T[i] := (T[i] shl 1) or cin; cin := cout; end; T[0] := T[0] xor masks[cin]; {$ifdef SetRPlus} {$R+} {$endif} end; {---------------------------------------------------------------------------} function AES_XTS_Init_Encr({$ifdef CONST}const{$else}var{$endif} K1,K2; KBits: word; var ctx: TAES_XTSContext): integer; {-Init XTS encrypt context (key expansion), error if invalid key size} var err: integer; begin fillchar(ctx, sizeof(ctx), 0); err := AES_Init(K1, KBits, ctx.main); if err=0 then err := AES_Init(K2, KBits, ctx.tweak); AES_XTS_Init_Encr := err; end; {---------------------------------------------------------------------------} function AES_XTS_Init_Decr({$ifdef CONST}const{$else}var{$endif} K1,K2; KBits: word; var ctx: TAES_XTSContext): integer; {-Init XTS decrypt context (key expansion), error if invalid key size} {$ifdef DLL} stdcall; {$endif} var err: integer; begin fillchar(ctx, sizeof(ctx), 0); err := AES_Init_Decr(K1, KBits, ctx.main); if err=0 then err := AES_Init(K2, KBits, ctx.tweak); AES_XTS_Init_Decr := err; end; {---------------------------------------------------------------------------} function AES_XTS_Encrypt(ptp, ctp: Pointer; ILen: longint; {$ifdef CONST}const{$else}var{$endif} twk: TAESBlock; var ctx: TAES_XTSContext): integer; {-Encrypt data unit of ILen bytes from ptp^ to ctp^ in XTS mode, twk: tweak of data unit} var i,n: longint; m: word; begin AES_XTS_Encrypt := 0; if ILen<0 then ILen := 0; if ctx.main.Decrypt<>0 then begin AES_XTS_Encrypt := AES_Err_Invalid_Mode; exit; end; if (ptp=nil) or (ctp=nil) then begin if ILen>0 then begin AES_XTS_Encrypt := AES_Err_NIL_Pointer; exit; end; end; {$ifdef BIT16} if (ILen+ofs(ptp^) > $FFFF) or (ILen+ofs(ctp^) > $FFFF) then begin AES_XTS_Encrypt := AES_Err_Invalid_16Bit_Length; exit; end; {$endif} n := ILen div AESBLKSIZE; {Full blocks} m := ILen mod AESBLKSIZE; {Remaining bytes in short block} if m<>0 then begin if n=0 then begin AES_XTS_Encrypt := AES_Err_Invalid_Length; exit; end; dec(n); {CTS: special treatment of last TWO blocks} end; {encrypt the tweak twk, tweak.IV = enc(twk)} AES_Encrypt(ctx.tweak, twk, ctx.tweak.IV); with ctx.main do begin {process full blocks} for i:=1 to n do begin AES_XorBlock(PAESBlock(ptp)^, ctx.tweak.IV, buf); AES_Encrypt(ctx.main, buf, buf); AES_XorBlock(buf, ctx.tweak.IV, PAESBlock(ctp)^); mul_a(ctx.tweak.IV); inc(Ptr2Inc(ptp),AESBLKSIZE); inc(Ptr2Inc(ctp),AESBLKSIZE); end; if m<>0 then begin {Cipher text stealing, encrypt last full plaintext block} AES_XorBlock(PAESBlock(ptp)^, ctx.tweak.IV, buf); AES_Encrypt(ctx.main, buf, buf); AES_XorBlock(buf, ctx.tweak.IV, buf); mul_a(ctx.tweak.IV); inc(Ptr2Inc(ptp),AESBLKSIZE); {pad and encrypt final short block} IV := buf; move(PAESBlock(ptp)^, IV, m); AES_XorBlock(IV, ctx.tweak.IV, IV); AES_Encrypt(ctx.main, IV, IV); AES_XorBlock(IV, ctx.tweak.IV, PAESBlock(ctp)^); inc(Ptr2Inc(ctp),AESBLKSIZE); move(buf,PAESBlock(ctp)^,m); end; end; end; {---------------------------------------------------------------------------} function AES_XTS_Decrypt(ctp, ptp: Pointer; ILen: longint; {$ifdef CONST}const{$else}var{$endif} twk: TAESBlock; var ctx: TAES_XTSContext): integer; {-Decrypt data unit of ILen bytes from ptp^ to ctp^ in XTS mode, twk: tweak of data unit} var i,n: longint; m: word; begin AES_XTS_Decrypt := 0; if ILen<0 then ILen := 0; if ctx.main.Decrypt=0 then begin AES_XTS_Decrypt := AES_Err_Invalid_Mode; exit; end; if (ptp=nil) or (ctp=nil) then begin if ILen>0 then begin AES_XTS_Decrypt := AES_Err_NIL_Pointer; exit; end; end; {$ifdef BIT16} if (ILen+ofs(ptp^) > $FFFF) or (ILen+ofs(ctp^) > $FFFF) then begin AES_XTS_Decrypt := AES_Err_Invalid_16Bit_Length; exit; end; {$endif} n := ILen div AESBLKSIZE; {Full blocks} m := ILen mod AESBLKSIZE; {Remaining bytes in short block} if m<>0 then begin if n=0 then begin AES_XTS_Decrypt := AES_Err_Invalid_Length; exit; end; dec(n); {CTS: special treatment of last TWO blocks} end; {encrypt the tweak twk, tweak.IV = enc(twk)} AES_Encrypt(ctx.tweak, twk, ctx.tweak.IV); with ctx.main do begin for i:=1 to n do begin AES_XorBlock(PAESBlock(ctp)^, ctx.tweak.IV, buf); AES_Decrypt(ctx.main, buf, buf); AES_XorBlock(buf, ctx.tweak.IV, PAESBlock(ptp)^); mul_a(ctx.tweak.IV); inc(Ptr2Inc(ptp),AESBLKSIZE); inc(Ptr2Inc(ctp),AESBLKSIZE); end; if m<>0 then begin {Cipher text stealing, "increment" tweak because} {final short plaintext is padded in this block} IV := ctx.tweak.IV; mul_a(IV); {Decrypt last full ciphertext block <-> final short plaintext} AES_XorBlock(PAESBlock(ctp)^, IV, buf); AES_Decrypt(ctx.main, buf, buf); AES_XorBlock(buf, IV, buf); inc(Ptr2Inc(ctp),AESBLKSIZE); {pad and decrypt short CT block to last full PT block} IV := buf; move(PAESBlock(ctp)^, IV, m); AES_XorBlock(IV, ctx.tweak.IV, IV); AES_Decrypt(ctx.main, IV, IV); AES_XorBlock(IV, ctx.tweak.IV, PAESBlock(ptp)^); inc(Ptr2Inc(ptp),AESBLKSIZE); move(buf,PAESBlock(ptp)^,m); end; end; end; end.