BSOne.SFC/Tocsg.Lib/VCL/EncLib/AES/aes_xts.pas

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.