再次修改了一下AES单元文件,使得使用起来更加简单了。增加了两个封装函数:
procedure aesEncBlock(buffer: PByteArray; key:PByteArray; Len: Integer; mode: Integer="128");
procedure aesDecBlock(buffer: PByteArray; key:PByteArray; Len: Integer; mode: Integer="128");
一般情况下,只要使用这两个函数就可以了。每次调用时,自动进行初始化处理。下面是这个单元文件的源码。
(*
AES crypt algorithm pascal unit
base on AVR231's aes code
EMAIL: Shaoziyang@gmail.com
Web: http://avrubd.googlepages.com
by Shaoziyang 2008.6
*)
unit aes;
interface
uses
SysUtils;
procedure aesMode(key: Integer);
procedure aesKey(key: PByteArray);
procedure aesEncInit;
procedure aesEncrypt(buffer, chainBlock: PByteArray);
procedure aesDecInit;
procedure aesDecrypt(buffer, chainBlock: PByteArray);
procedure aesEncBlock(buffer: PByteArray; key:PByteArray; Len: Integer; mode: Integer="128");
procedure aesDecBlock(buffer: PByteArray; key:PByteArray; Len: Integer; mode: Integer="128");
implementation
const
//!< Lower 8 bits of (x^8+x^4+x^3+x+1), ie. (x^4+x^3+x+1).
BPOLY = $1B;
//!< Block size in number of bytes.
BLOCKSIZE = 16;
var
kTable: array[0..31] of Byte =
(
$D0, $94, $3F, $8C, $29, $76, $15, $D8,
$20, $40, $E3, $27, $45, $D8, $48, $AD,
$EA, $8B, $2A, $73, $16, $E9, $B0, $49,
$45, $B3, $39, $28, $0A, $C3, $28, $3C
);
block1: array[0..255] of Byte; //!< Workspace 1.
block2: array[0..255] of Byte; //!< Worksapce 2.
tempbuf: array[0..255] of Byte;
chainCipherBlock: array[0..15] of Byte;
powTbl: PByteArray; //!< Final location of exponentiation lookup table.
logTbl: PByteArray; //!< Final location of logarithm lookup table.
sBox: PByteArray; //!< Final location of s-box.
sBoxInv: PByteArray; //!< Final location of inverse s-box.
expandedKey: PByteArray; //!< Final location of expanded key.
ROUNDS: Byte = 10; //!< Number of rounds.
KEYLENGTH: Byte = 16; //!< Key length in number of bytes.
procedure aesMode(key: Integer);
begin
if key <= 128 then
begin
ROUNDS := 10;
KEYLENGTH := 16;
end
else
begin
ROUNDS := 14;
KEYLENGTH := 32;
end;
end;
procedure aesKey(key: PByteArray);
var
i: Integer;
begin
for i := 0 to KEYLENGTH - 1 do
kTable := key^;
end;
function CalcDat(t: Byte): Byte;
begin
if (t and $80) = $80 then
Result := ((t * 2) xor BPOLY)
else
Result := (t * 2);
end;
procedure CalcPowLog(powTbl, logTbl: PByteArray);
var
i, t: Byte;
begin
i := 0;
t := 1;
repeat
// Use 0x03 as root for exponentiation and logarithms.
powTbl^ := t;
logTbl^[t] := i;
i := i + 1;
// Muliply t by 3 in GF(2^8).
t := t xor CalcDat(t);
until (t = 1); // Cyclic properties ensure that i < 255.
powTbl^[255] := powTbl^[0]; // 255 = '-0', 254 = -1, etc.
end;
procedure CalcSBox(sBox: PByteArray);
var
i, rot: Byte;
temp: Byte;
Result: Byte;
begin
// Fill all entries of sBox[].
i := 0;
repeat
//Inverse in GF(2^8).
if (i > 0) then
begin
temp := powTbl^[255 - logTbl^];
end
else
begin
temp := 0;
end;
// Affine transformation in GF(2).
Result := temp xor $63; // Start with adding a vector in GF(2).
for rot := 1 to 4 do
begin
// Rotate left.
temp := (temp shl 1) or (temp shr 7);
// Add rotated byte in GF(2).
Result := Result xor temp;
end;
// Put result in table.
sBox^ := Result;
i := i + 1;
until (i = 0);
end;
procedure CalcSBoxInv(sBox, sBoxInv: PByteArray);
var
i, j: Byte;
begin
i := 0;
j := 0;
// Iterate through all elements in sBoxInv using i.
repeat
// Search through sBox using j.
repeat
// Check if current j is the inverse of current i.
if (sBox^[j] = i) then
begin
// If so, set sBoxInc and indicate search finished.
sBoxInv^ := j;
j := 255;
end;
j := j + 1;
until (j = 0);
i := i + 1;
until (i = 0);
end;
procedure CycleLeft(row: PByteArray);
var
temp: Byte;
begin
// Cycle 4 bytes in an array left once.
temp := row^[0];
row^[0] := row^[1];
row^[1] := row^[2];
row^[2] := row^[3];
row^[3] := temp;
end;
procedure InvMixColumn(column: PByteArray);
var
r0, r1, r2, r3: Byte;
begin
r0 := column^[1] xor column^[2] xor column^[3];
r1 := column^[0] xor column^[2] xor column^[3];
r2 := column^[0] xor column^[1] xor column^[3];
r3 := column^[0] xor column^[1] xor column^[2];
column^[0] := CalcDat(column^[0]);
column^[1] := CalcDat(column^[1]);
column^[2] := CalcDat(column^[2]);
column^[3] := CalcDat(column^[3]);
r0 := r0 xor column^[0] xor column^[1];
r1 := r1 xor column^[1] xor column^[2];
r2 := r2 xor column^[2] xor column^[3];
r3 := r3 xor column^[0] xor column^[3];
column^[0] := CalcDat(column^[0]);
column^[1] := CalcDat(column^[1]);
column^[2] := CalcDat(column^[2]);
column^[3] := CalcDat(column^[3]);
r0 := r0 xor column^[0] xor column^[2];
r1 := r1 xor column^[1] xor column^[3];
r2 := r2 xor column^[0] xor column^[2];
r3 := r3 xor column^[1] xor column^[3];
column^[0] := CalcDat(column^[0]);
column^[1] := CalcDat(column^[1]);
column^[2] := CalcDat(column^[2]);
column^[3] := CalcDat(column^[3]);
column^[0] := column^[0] xor column^[1] xor column^[2] xor column^[3];
r0 := r0 xor column^[0];
r1 := r1 xor column^[0];
r2 := r2 xor column^[0];
r3 := r3 xor column^[0];
column^[0] := r0;
column^[1] := r1;
column^[2] := r2;
column^[3] := r3;
end;
procedure SubBytes(bytes: PByteArray; count: Byte);
var
i: Byte;
begin
i := 0;
repeat
bytes^ := sBox^[bytes^]; // Substitute every byte in state.
i := i + 1;
count := count - 1;
until (count = 0);
end;
procedure InvSubBytesAndXOR(bytes, key: PByteArray; count: Byte);
var
i: Byte;
begin
i := 0;
repeat
// *bytes = sBoxInv[ *bytes ] ^ *key; // Inverse substitute every byte in state and add key.
bytes^ := block2[bytes^] xor key^; // Use block2 directly. Increases speed.
i := i + 1;
count := count - 1;
until (count = 0);
end;
procedure InvShiftRows(state: PByteArray);
var
temp: Byte;
begin
// Note: State is arranged column by column.
// Cycle second row right one time.
temp := state^[1 + 3 * 4];
state^[1 + 3 * 4] := state^[1 + 2 * 4];
state^[1 + 2 * 4] := state^[1 + 1 * 4];
state^[1 + 1 * 4] := state^[1 + 0 * 4];
state^[1 + 0 * 4] := temp;
// Cycle third row right two times.
temp := state^[2 + 0 * 4];
state^[2 + 0 * 4] := state^[2 + 2 * 4];
state^[2 + 2 * 4] := temp;
temp := state^[2 + 1 * 4];
state^[2 + 1 * 4] := state^[2 + 3 * 4];
state^[2 + 3 * 4] := temp;
// Cycle fourth row right three times, ie. left once.
temp := state^[3 + 0 * 4];
state^[3 + 0 * 4] := state^[3 + 1 * 4];
state^[3 + 1 * 4] := state^[3 + 2 * 4];
state^[3 + 2 * 4] := state^[3 + 3 * 4];
state^[3 + 3 * 4] := temp;
end;
procedure InvMixColumns(state: PByteArray);
begin
InvMixColumn(@state[0 * 4]);
InvMixColumn(@state[1 * 4]);
InvMixColumn(@state[2 * 4]);
InvMixColumn(@state[3 * 4]);
end;
procedure XORBytes(bytes1, bytes2: PByteArray; count: Byte);
var
i: Integer;
begin
i := 0;
repeat
bytes1^ := bytes1^ xor bytes2^; // Add in GF(2), ie. XOR.
i := i + 1;
count := count - 1;
until (count = 0);
end;
procedure CopyBytes(a, b: PByteArray; count: Byte);
var
i: Byte;
begin
i := 0;
repeat
a^ := b^;
i := i + 1;
count := count - 1;
until (count = 0);
end;
procedure KeyExpansion(expandedKey: PByteArray);
var
temp: array[0..3] of Byte;
i: Byte;
Rcon: array[0..3] of Byte; // Round constant.
key: PByte;
begin
Rcon[0] := 1;
Rcon[1] := 0;
Rcon[2] := 0;
Rcon[3] := 0;
key := @kTable;
// Copy key to start of expanded key.
{i := KEYLENGTH;
repeat
expandedKey^[0] := key^;
inc(PByte(expandedKey), 1);
inc(key, 1);
i := i - 1;
until (i = 0);}
CopyBytes(expandedKey, PByteArray(key), KEYLENGTH);
Inc(PByte(expandedKey), KEYLENGTH);
// Prepare last 4 bytes of key in temp.
dec(PByte(expandedKey), 4);
temp[0] := expandedKey^[0];
temp[1] := expandedKey^[1];
temp[2] := expandedKey^[2];
temp[3] := expandedKey^[3];
Inc(PByte(expandedKey), 4);
// Expand key.
i := KEYLENGTH;
while (i < BLOCKSIZE * (ROUNDS + 1)) do
begin
if KEYLENGTH > 24 then
begin
// Are we at the start of a multiple of the key size?
if ((i mod KEYLENGTH) = 0) then
begin
CycleLeft(@temp); // Cycle left once.
SubBytes(@temp, 4); // Substitute each byte.
XORBytes(@temp, @Rcon, 4); // Add constant in GF(2).
Rcon[0] := CalcDat(Rcon[0]);
// Keysize larger than 24 bytes, ie. larger that 192 bits?
end
// Are we right past a block size?
else
if ((i mod KEYLENGTH) = BLOCKSIZE) then
SubBytes(@temp, 4); // Substitute each byte.
end
else
begin
if ((i mod KEYLENGTH) = 0) then
begin
CycleLeft(@temp); // Cycle left once.
SubBytes(@temp, 4); // Substitute each byte.
XORBytes(@temp, @Rcon, 4); // Add constant in GF(2).
Rcon[0] := CalcDat(Rcon[0]);
end;
end;
// Add bytes in GF(2) one KEYLENGTH away.
dec(PByte(expandedKey), KEYLENGTH);
XORBytes(@temp, expandedKey, 4);
Inc(PByte(expandedKey), KEYLENGTH);
// Copy result to current 4 bytes.
{expandedKey[0] := temp[0];
expandedKey[1] := temp[1];
expandedKey[2] := temp[2];
expandedKey[3] := temp[3];}
CopyBytes(expandedKey, @temp, 4);
Inc(PByte(expandedKey), 4);
i := i + 4; // Next 4 bytes.
end;
end;
procedure InvCipher(block, expandedKey: PByteArray);
var
round: Byte;
begin
round := ROUNDS - 1;
Inc(PByte(expandedKey), BLOCKSIZE * ROUNDS);
XORBytes(block, expandedKey, 16);
dec(PByte(expandedKey), BLOCKSIZE);
repeat
InvShiftRows(block);
InvSubBytesAndXOR(block, expandedKey, 16);
dec(PByte(expandedKey), BLOCKSIZE);
InvMixColumns(block);
round := round - 1;
until (round = 0);
InvShiftRows(block);
InvSubBytesAndXOR(block, expandedKey, 16);
end;
procedure aesDecInit;
var
i: Integer;
begin
powTbl := @block1;
logTbl := @block2;
CalcPowLog(powTbl, logTbl);
sBox := @tempbuf;
CalcSBox(sBox);
expandedKey := @block1;
KeyExpansion(expandedKey);
sBoxInv := @block2; // Must be block2.
CalcSBoxInv(sBox, sBoxInv);
for i := 0 to 15 do
chainCipherBlock := 0;
end;
procedure aesDecrypt(buffer, chainBlock: PByteArray);
var
temp: array[0..BLOCKSIZE - 1] of Byte;
begin
CopyBytes(@temp, buffer, BLOCKSIZE);
InvCipher(buffer, expandedKey);
XORBytes(buffer, chainBlock, BLOCKSIZE);
CopyBytes(chainBlock, @temp, BLOCKSIZE);
end;
function Multiply(num, factor: Byte): Byte;
var
mask: Byte;
begin
mask := 1;
Result := 0;
while (mask <> 0) do
begin
// Check bit of factor given by mask.
if ((mask and factor) <> 0) then
begin
// Add current multiple of num in GF(2).
Result := Result xor num;
end;
// Shift mask to indicate next bit.
mask := mask shl 1;
// Double num.
num := CalcDat(num);
end;
end;
function DotProduct(vector1, vector2: PByteArray): Byte;
begin
Result := 0;
Result := Result xor Multiply(vector1^[0], vector2^[0]);
Inc(PByte(vector1));
Inc(PByte(vector2));
Result := Result xor Multiply(vector1^[0], vector2^[0]);
Inc(PByte(vector1));
Inc(PByte(vector2));
Result := Result xor Multiply(vector1^[0], vector2^[0]);
Inc(PByte(vector1));
Inc(PByte(vector2));
Result := Result xor Multiply(vector1^[0], vector2^[0]);
end;
procedure MixColumn(column: PByteArray);
var
// Prepare first row of matrix twice, to eliminate need for cycling.
row: array[0..7] of Byte;
Result: array[0..3] of Byte;
begin
row[0] := $02;
row[1] := $03;
row[2] := $01;
row[3] := $01;
row[4] := $02;
row[5] := $03;
row[6] := $01;
row[7] := $01;
// Take dot products of each matrix row and the column vector.
Result[0] := DotProduct(@row[0], column);
Result[1] := DotProduct(@row[3], column);
Result[2] := DotProduct(@row[2], column);
Result[3] := DotProduct(@row[1], column);
// Copy temporary result to original column.
column^[0] := Result[0];
column^[1] := Result[1];
column^[2] := Result[2];
column^[3] := Result[3];
end;
procedure MixColumns(state: PByteArray);
begin
MixColumn(@state[0 * 4]);
MixColumn(@state[1 * 4]);
MixColumn(@state[2 * 4]);
MixColumn(@state[3 * 4]);
end;
procedure ShiftRows(state: PByteArray);
var
temp: Byte;
begin
// Note: State is arranged column by column.
// Cycle second row left one time.
temp := state^[1 + 0 * 4];
state^[1 + 0 * 4] := state^[1 + 1 * 4];
state^[1 + 1 * 4] := state^[1 + 2 * 4];
state^[1 + 2 * 4] := state^[1 + 3 * 4];
state^[1 + 3 * 4] := temp;
// Cycle third row left two times.
temp := state^[2 + 0 * 4];
state^[2 + 0 * 4] := state^[2 + 2 * 4];
state^[2 + 2 * 4] := temp;
temp := state^[2 + 1 * 4];
state^[2 + 1 * 4] := state^[2 + 3 * 4];
state^[2 + 3 * 4] := temp;
// Cycle fourth row left three times, ie. right once.
temp := state^[3 + 3 * 4];
state^[3 + 3 * 4] := state^[3 + 2 * 4];
state^[3 + 2 * 4] := state^[3 + 1 * 4];
state^[3 + 1 * 4] := state^[3 + 0 * 4];
state^[3 + 0 * 4] := temp;
end;
procedure Cipher(block, expandedKey: PByteArray);
var
round: Byte;
begin
round := ROUNDS - 1;
XORBytes(block, expandedKey, 16);
Inc(PByte(expandedKey), BLOCKSIZE);
repeat
SubBytes(block, 16);
ShiftRows(block);
MixColumns(block);
XORBytes(block, expandedKey, 16);
Inc(PByte(expandedKey), BLOCKSIZE);
round := round - 1;
until (round = 0);
SubBytes(block, 16);
ShiftRows(block);
XORBytes(block, expandedKey, 16);
end;
procedure aesEncInit;
var
i: Integer;
begin
powTbl := @block1;
logTbl := @tempbuf;
CalcPowLog(powTbl, logTbl);
sBox := @block2;
CalcSBox(sBox);
expandedKey := @block1;
KeyExpansion(expandedKey);
for i := 0 to 15 do
chainCipherBlock := 0;
end;
procedure aesEncrypt(buffer, chainBlock: PByteArray);
begin
XORBytes(buffer, chainBlock, BLOCKSIZE);
Cipher(buffer, expandedKey);
CopyBytes(chainBlock, buffer, BLOCKSIZE);
end;
procedure aesEncBlock(buffer: PByteArray; key:PByteArray; Len: Integer; mode: Integer);
var
i: Integer;
begin
aesMode(mode);
aesKey(key);
aesEncInit;
i := 0;
while i <= (Len - 16) do
begin
aesEncrypt(@buffer^, @chainCipherBlock);
i := i + 16;
end;
end;
procedure aesDecBlock(buffer: PByteArray; key:PByteArray; Len: Integer; mode: Integer);
var
i: Integer;
begin
aesMode(mode);
aesKey(key);
aesDecInit;
i := 0;
while i <= (Len - 16) do
begin
aesDecrypt(@buffer^, @chainCipherBlock);
i := i + 16;
end;
end;
initialization
aesMode(128);
finalization
end.
文章评论(0条评论)
登录后参与讨论