303 lines
9.7 KiB
Plaintext
303 lines
9.7 KiB
Plaintext
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.
|