{*****************************************************************************
The DEC team (see file NOTICE.txt) licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. A copy of this licence is found in the root directory
of this project in the file LICENCE.txt or alternatively at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
*****************************************************************************}
unit DECCiphers;
interface
{$INCLUDE DECOptions.inc}
uses
DECCipherBase, DECCipherFormats, DECUtil, DECTypes;
type
// Cipher Classes
///
/// Null cipher, doesn't encrypt, only copy
///
TCipher_Null = class;
///
/// A block based encryption algorithm with 32 to 448 bit key length
///
TCipher_Blowfish = class;
///
/// AES Round 2 Final Candidate
///
TCipher_Twofish = class;
///
/// International Data Encryption Algorithm, formerly patentet,
/// now patent free. The algorithm is no longer to be really recommended due
/// to some classes of weak keys and other successfull attacks.
///
TCipher_IDEA = class;
///
/// Carlisle Adams and Stafford Tavares, 256 bit key length
///
TCipher_Cast256 = class;
///
/// AES Round 2 Final Candidate
///
TCipher_Mars = class;
///
/// Streamcipher in as Block Cipher
///
TCipher_RC4 = class;
///
/// AES Round 2 Final Candidate
///
TCipher_RC6 = class;
///
/// AES Round 2 Final Candidate
///
TCipher_Rijndael = class;
///
/// AES winner = TCipher_Rijndael
///
TCipher_AES = class;
///
/// A block cipher invented by Joan Daemen and Vincent Rijmen. The design,
/// published in 1997, is a forerunner to Rijndael, which has been adopted
/// as the Advanced Encryption Standard. Square was introduced together with
/// a new form of cryptanalysis discovered by Lars Knudsen, called the
/// "Square attack".
/// The structure of Square is a substitution-permutation network with eight
/// rounds, operating on 128-bit blocks and using a 128-bit key.
///
///
/// If possible use TCipher_AES instead
///
TCipher_Square = class;
///
/// Stream Cipher in Blockmode (on UInt32), very fast
///
TCipher_SCOP = class;
///
/// Stream Cipher in Blockmode (on UInt32), very fast.
/// Wrong old version from DEC 5.2. Use only for backwards compatibility!
///
TCipher_SCOP_DEC52 = class;
///
/// Stream Cipher, eq. design from German ENIGMA Machine
///
TCipher_Sapphire = class;
///
/// Single DES 8 byte Blocksize, 8 byte Keysize, 56 bits relevant.
/// Considered to be too weak nowadays. Included for compatibility reasons.
///
TCipher_1DES = class;
///
/// Double DES 8 byte Blocksize, 16 byte Keysize, 112 bits relevant
///
TCipher_2DES = class;
///
/// Triple DES 8 byte Blocksize, 24 byte Keysize, 168 bits relevant
///
TCipher_3DES = class;
///
/// Triple DES 16 byte Blocksize, 16 byte Keysize, 112 bits relevant
///
TCipher_2DDES = class;
///
/// Triple DES 16 byte Blocksize, 24 byte Keysize, 168 bits relevant
///
TCipher_3DDES = class;
///
/// Triple DES 24 byte Blocksize, 24 byte Keysize, 168 bits relevant
///
TCipher_3TDES = class;
///
/// A 1994 developed block cipher using a 96 bit key. 3-Way, is vulnerable
/// to related key cryptanalysis.
///
TCipher_3Way = class;
///
/// Carlisle Adams and Stafford Tavares, 128 bit key length
///
TCipher_Cast128 = class;
///
/// Russian Cipher
///
TCipher_Gost = class;
///
/// Alias/new name for Gost cipher
///
TCipher_Magma = class;
///
/// Misty1 is a block cipher developed 1995 by Mitsubishi. It is free only for
/// academical and non-profit works in RFC 2994. it is otherwise patented.
/// In 2015 it got broken via integral cryptoanalysis.
///
TCipher_Misty = class;
///
/// A 1996 block cipher with a key length of 120 bit. It can be broken with
/// a relatively low number of ciphertext/plaintext queries.
///
TCipher_NewDES = class;
///
/// Camelia, a 128 bit block cipher.
/// Specification: https://info.isl.ntt.co.jp/crypt/eng/camellia/dl/01espec.pdf
///
TCipher_Q128 = class;
///
/// Rivest Cipher 2, a 1987 developed cipher with a default keysize of 64 bit
///
TCipher_RC2 = class;
///
/// Rivest Cipher 5, a 1994 developed cipher with emphasis on speed and low
/// size in order to make it efficient on embedded hardware as well. Key sizes
/// of up to 2048 bits are possible but 128 bits are suggested. The algorithm
/// was patented in the US up to 2015.
///
TCipher_RC5 = class;
///
/// SAFER = Secure And Fast Encryption Routine
///
TCipher_SAFER = class;
///
/// A 1996 published block cipher with a key size of 128 bits. It was
/// identified as one of the predecessors of Rijndael
///
TCipher_Shark = class;
///
/// A 1996 published block cipher with a key size of 128 bits. It was
/// identified as one of the predecessors of Rijndael
/// Wrong old version from DEC 5.2. Use only for backwards compatibility!
///
TCipher_Shark_DEC52 = class;
///
/// A NSA developed and 1998 published block cipher with a key length of
/// 80 bit. Soon after publication various weaknesses have been identified.
///
TCipher_Skipjack = class;
///
/// Tiny Encryption Algorithm
///
TCipher_TEA = class;
///
/// Tiny Encryption Algorithm, 1st extended Version
///
TCipher_XTEA = class;
///
/// = TCipher_XTEA (kept for backward compatibility)
///
TCipher_TEAN = class;
///
/// Tiny Encryption Algorithm, 1st extended Version.
/// Wrong old version from DEC 5.2. Use only for backwards compatibility!
///
TCipher_XTEA_DEC52 = class;
// Definitions needed for Skipjack algorithm
PSkipjackTab = ^TSkipjackTab;
TSkipjackTab = array[0..255] of Byte;
///
/// A do nothing cipher, usefull for debugging and development purposes. Do
/// not use it for actual encryption as it will not encrypt anything at all!
///
TCipher_Null = class(TDECFormattedCipher)
protected
procedure DoInit(const Key; Size: Integer); override;
procedure DoEncode(Source, Dest: Pointer; Size: Integer); override;
procedure DoDecode(Source, Dest: Pointer; Size: Integer); override;
public
///
/// Provides meta data about the cipher algorithm used like key size.
///
class function Context: TCipherContext; override;
end;
TCipher_Blowfish = class(TDECFormattedCipher)
protected
///
/// Initialize the key, based on the key passed in
///
///
/// Encryption/Decryption key to be used
///
///
/// Size of the key passed in bytes.
///
procedure DoInit(const Key; Size: Integer); override;
procedure DoEncode(Source, Dest: Pointer; Size: Integer); override;
procedure DoDecode(Source, Dest: Pointer; Size: Integer); override;
public
class function Context: TCipherContext; override;
end;
TCipher_Twofish = class(TDECFormattedCipher)
protected
///
/// Initialize the key, based on the key passed in
///
///
/// Encryption/Decryption key to be used
///
///
/// Size of the key passed in bytes.
///
procedure DoInit(const Key; Size: Integer); override;
procedure DoEncode(Source, Dest: Pointer; Size: Integer); override;
procedure DoDecode(Source, Dest: Pointer; Size: Integer); override;
public
class function Context: TCipherContext; override;
end;
TCipher_IDEA = class(TDECFormattedCipher)
protected
///
/// Initialize the key, based on the key passed in
///
///
/// Encryption/Decryption key to be used
///
///
/// Size of the key passed in bytes.
///
procedure DoInit(const Key; Size: Integer); override;
procedure DoEncode(Source, Dest: Pointer; Size: Integer); override;
procedure DoDecode(Source, Dest: Pointer; Size: Integer); override;
public
class function Context: TCipherContext; override;
end;
TCipher_Cast256 = class(TDECFormattedCipher)
protected
///
/// Initialize the key, based on the key passed in
///
///
/// Encryption/Decryption key to be used
///
///
/// Size of the key passed in bytes.
///
procedure DoInit(const Key; Size: Integer); override;
procedure DoEncode(Source, Dest: Pointer; Size: Integer); override;
procedure DoDecode(Source, Dest: Pointer; Size: Integer); override;
public
class function Context: TCipherContext; override;
end;
TCipher_Mars = class(TDECFormattedCipher)
protected
///
/// Initialize the key, based on the key passed in
///
///
/// Encryption/Decryption key to be used
///
///
/// Size of the key passed in bytes.
///
procedure DoInit(const Key; Size: Integer); override;
procedure DoEncode(Source, Dest: Pointer; Size: Integer); override;
procedure DoDecode(Source, Dest: Pointer; Size: Integer); override;
public
class function Context: TCipherContext; override;
end;
///
/// This is a well known stream cipher. In February 2015 its use in context
/// of TLS has been forbidden due to severe security issues.
///
TCipher_RC4 = class(TDECFormattedCipher)
protected
///
/// Initialize the key, based on the key passed in
///
///
/// Encryption/Decryption key to be used
///
///
/// Size of the key passed in bytes.
///
procedure DoInit(const Key; Size: Integer); override;
procedure DoEncode(Source, Dest: Pointer; Size: Integer); override;
procedure DoDecode(Source, Dest: Pointer; Size: Integer); override;
public
class function Context: TCipherContext; override;
end;
TCipher_RC6 = class(TDECFormattedCipher)
private
FRounds: Integer;
procedure SetRounds(Value: Integer);
///
/// Limits the number of rounds used to a minimum or maximum value,
/// depending on the current value. If FRounds is 0 it will be set to 20.
///
procedure LimitRounds; inline;
protected
///
/// Initialize the key, based on the key passed in
///
///
/// Encryption/Decryption key to be used
///
///
/// Size of the key passed in bytes.
///
procedure DoInit(const Key; Size: Integer); override;
procedure DoEncode(Source, Dest: Pointer; Size: Integer); override;
procedure DoDecode(Source, Dest: Pointer; Size: Integer); override;
public
class function Context: TCipherContext; override;
///
/// Sets the number of rounds/times the algorithm is being applied to the
/// data. Range should be 16-24 and default is 20 rounds.
///
property Rounds: Integer read FRounds write SetRounds;
end;
TCipher_Rijndael = class(TDECFormattedCipher)
private
FRounds: Integer;
protected
///
/// Initialize the key, based on the key passed in
///
///
/// Encryption/Decryption key to be used
///
///
/// Size of the key passed in bytes.
///
procedure DoInit(const Key; Size: Integer); override;
procedure DoEncode(Source, Dest: Pointer; Size: Integer); override;
procedure DoDecode(Source, Dest: Pointer; Size: Integer); override;
public
class function Context: TCipherContext; override;
///
/// Gets the number of rounds/times the algorithm is being applied to the
/// data. The number of rounds depends on the key size.
///
property Rounds: Integer read FRounds;
end;
TCipher_AES = class(TCipher_Rijndael);
TCipher_Square = class(TDECFormattedCipher)
protected
///
/// Initialize the key, based on the key passed in
///
///
/// Encryption/Decryption key to be used
///
///
/// Size of the key passed in bytes.
///
procedure DoInit(const Key; Size: Integer); override;
procedure DoEncode(Source, Dest: Pointer; Size: Integer); override;
procedure DoDecode(Source, Dest: Pointer; Size: Integer); override;
public
class function Context: TCipherContext; override;
end;
TCipher_SCOP = class(TDECFormattedCipher)
protected
///
/// Initialize the key, based on the key passed in
///
///
/// Encryption/Decryption key to be used
///
///
/// Size of the key passed in bytes.
///
procedure DoInit(const Key; Size: Integer); override;
procedure DoEncode(Source, Dest: Pointer; Size: Integer); override;
procedure DoDecode(Source, Dest: Pointer; Size: Integer); override;
public
class function Context: TCipherContext; override;
end;
///
/// Do only use if backwards compatibility with old code is necessary as
/// this implementation is faulty!
///
TCipher_SCOP_DEC52 = class(TDECFormattedCipher)
protected
///
/// Initialize the key, based on the key passed in
///
///
/// Encryption/Decryption key to be used
///
///
/// Size of the key passed in bytes.
///
procedure DoInit(const Key; Size: Integer); override;
procedure DoEncode(Source, Dest: Pointer; Size: Integer); override;
procedure DoDecode(Source, Dest: Pointer; Size: Integer); override;
public
class function Context: TCipherContext; override;
end;
TCipher_Sapphire = class(TDECFormattedCipher)
protected
///
/// Initialize the key, based on the key passed in
///
///
/// Encryption/Decryption key to be used
///
///
/// Size of the key passed in bytes.
///
procedure DoInit(const Key; Size: Integer); override;
procedure DoEncode(Source, Dest: Pointer; Size: Integer); override;
procedure DoDecode(Source, Dest: Pointer; Size: Integer); override;
public
class function Context: TCipherContext; override;
end;
TCipher_1DES = class(TDECFormattedCipher)
protected
///
/// Initialize the key, based on the key passed in
///
///
/// Key for the current block to be encrypted/decrypted?
///
///
/// Encryption/Decryption key to be used
///
///
/// Size of the key passed in bytes.
///
///
/// Defines whether some internal calculation needs to be based from the
/// start index or the highest index (= reverse)
///
procedure DoInitKey(const Data: array of Byte; Key: PUInt32Array; Reverse: Boolean);
procedure DoInit(const Key; Size: Integer); override;
procedure DoEncode(Source, Dest: Pointer; Size: Integer); override;
procedure DoDecode(Source, Dest: Pointer; Size: Integer); override;
public
class function Context: TCipherContext; override;
end;
TCipher_2DES = class(TCipher_1DES)
protected
///
/// Initialize the key, based on the key passed in
///
///
/// Encryption/Decryption key to be used
///
///
/// Size of the key passed in bytes.
///
procedure DoInit(const Key; Size: Integer); override;
procedure DoEncode(Source, Dest: Pointer; Size: Integer); override;
procedure DoDecode(Source, Dest: Pointer; Size: Integer); override;
public
class function Context: TCipherContext; override;
end;
TCipher_3DES = class(TCipher_1DES)
protected
///
/// Initialize the key, based on the key passed in
///
///
/// Encryption/Decryption key to be used
///
///
/// Size of the key passed in bytes.
///
procedure DoInit(const Key; Size: Integer); override;
procedure DoEncode(Source, Dest: Pointer; Size: Integer); override;
procedure DoDecode(Source, Dest: Pointer; Size: Integer); override;
public
class function Context: TCipherContext; override;
end;
TCipher_2DDES = class(TCipher_2DES)
protected
procedure DoEncode(Source, Dest: Pointer; Size: Integer); override;
procedure DoDecode(Source, Dest: Pointer; Size: Integer); override;
public
class function Context: TCipherContext; override;
end;
TCipher_3DDES = class(TCipher_3DES)
protected
procedure DoEncode(Source, Dest: Pointer; Size: Integer); override;
procedure DoDecode(Source, Dest: Pointer; Size: Integer); override;
public
class function Context: TCipherContext; override;
end;
TCipher_3TDES = class(TCipher_3DES)
protected
procedure DoEncode(Source, Dest: Pointer; Size: Integer); override;
procedure DoDecode(Source, Dest: Pointer; Size: Integer); override;
public
class function Context: TCipherContext; override;
end;
TCipher_3Way = class(TDECFormattedCipher)
protected
///
/// Initialize the key, based on the key passed in
///
///
/// Encryption/Decryption key to be used
///
///
/// Size of the key passed in bytes.
///
procedure DoInit(const Key; Size: Integer); override;
procedure DoEncode(Source, Dest: Pointer; Size: Integer); override;
procedure DoDecode(Source, Dest: Pointer; Size: Integer); override;
public
class function Context: TCipherContext; override;
end;
TCipher_Cast128 = class(TDECFormattedCipher)
private
FRounds: Integer;
procedure SetRounds(Value: Integer);
protected
///
/// Initialize the key, based on the key passed in
///
///
/// Encryption/Decryption key to be used
///
///
/// Size of the key passed in bytes.
///
procedure DoInit(const Key; Size: Integer); override;
procedure DoEncode(Source, Dest: Pointer; Size: Integer); override;
procedure DoDecode(Source, Dest: Pointer; Size: Integer); override;
public
class function Context: TCipherContext; override;
///
/// Sets the number of rounds/times the algorithm is being applied to the
/// data. Default value is 16 rounds.
///
property Rounds: Integer read FRounds write SetRounds;
end;
TCipher_Gost = class(TDECFormattedCipher)
protected
///
/// Initialize the key, based on the key passed in
///
///
/// Encryption/Decryption key to be used
///
///
/// Size of the key passed in bytes.
///
procedure DoInit(const Key; Size: Integer); override;
procedure DoEncode(Source, Dest: Pointer; Size: Integer); override;
procedure DoDecode(Source, Dest: Pointer; Size: Integer); override;
public
class function Context: TCipherContext; override;
end;
///
/// Alias for Gost
///
TCipher_Magma = class(TCipher_Gost);
///
/// Do no longer use this algorithm if possible, as it got broken in 2015
/// by crypto analysis.
///
TCipher_Misty = class(TDECFormattedCipher)
protected
///
/// Initialize the key, based on the key passed in
///
///
/// Encryption/Decryption key to be used
///
///
/// Size of the key passed in bytes.
///
procedure DoInit(const Key; Size: Integer); override;
procedure DoEncode(Source, Dest: Pointer; Size: Integer); override;
procedure DoDecode(Source, Dest: Pointer; Size: Integer); override;
public
class function Context: TCipherContext; override;
end;
///
/// While this algorithm resembles the Data Encryption Standard (DES),
/// it is easier to implement in software and is supposed to be more secure.
/// It is not to be confused with another algorithm - known by the same
/// name - which is simply DES without the initial and final permutations.
/// The NewDES here is a completely different algorithm.
///
/// Be aware though that recent crypto analysis shows that this algorithm is
/// less safe than DES and thus not to be recommended for use!
///
TCipher_NewDES = class(TDECFormattedCipher)
protected
///
/// Initialize the key, based on the key passed in
///
///
/// Encryption/Decryption key to be used
///
///
/// Size of the key passed in bytes.
///
procedure DoInit(const Key; Size: Integer); override;
procedure DoEncode(Source, Dest: Pointer; Size: Integer); override;
procedure DoDecode(Source, Dest: Pointer; Size: Integer); override;
public
class function Context: TCipherContext; override;
end;
TCipher_Q128 = class(TDECFormattedCipher)
protected
///
/// Initialize the key, based on the key passed in
///
///
/// Encryption/Decryption key to be used
///
///
/// Size of the key passed in bytes.
///
procedure DoInit(const Key; Size: Integer); override;
procedure DoEncode(Source, Dest: Pointer; Size: Integer); override;
procedure DoDecode(Source, Dest: Pointer; Size: Integer); override;
public
class function Context: TCipherContext; override;
end;
TCipher_RC2 = class(TDECFormattedCipher)
protected
///
/// Initialize the key, based on the key passed in
///
///
/// Encryption/Decryption key to be used
///
///
/// Size of the key passed in bytes.
///
procedure DoInit(const Key; Size: Integer); override;
procedure DoEncode(Source, Dest: Pointer; Size: Integer); override;
procedure DoDecode(Source, Dest: Pointer; Size: Integer); override;
public
class function Context: TCipherContext; override;
end;
TCipher_RC5 = class(TDECFormattedCipher)
private
FRounds: Integer;
procedure SetRounds(Value: Integer);
protected
///
/// Initialize the key, based on the key passed in
///
///
/// Encryption/Decryption key to be used
///
///
/// Size of the key passed in bytes.
///
procedure DoInit(const Key; Size: Integer); override;
procedure DoEncode(Source, Dest: Pointer; Size: Integer); override;
procedure DoDecode(Source, Dest: Pointer; Size: Integer); override;
public
class function Context: TCipherContext; override;
///
/// Sets the number of rounds/times the algorithm is being applied to the
/// data. Range should be 8-16 and default is 12 rounds.
///
property Rounds: Integer read FRounds write SetRounds;
end;
///
/// svK40 SAFER K-40 Keysize is 40bit -> 5 Byte
/// svK64 SAFER K-64 Keysize is 64bit -> 8 Byte
/// svK128 SAFER K-128 KeySize is 128bit -> 16 Byte
/// svSK40 SAFER SK-40 Stronger Version from K-40 with better Key Scheduling
/// svSK64 SAFER SK-64 Stronger Version from K-64 with better Key Scheduling
/// svSK128 SAFER SK-128 Stronger Version from K-128 with better Key Scheduling
///
TSAFERVersion = (svSK128, svSK64, svSK40, svK128, svK64, svK40);
TCipher_SAFER = class(TDECFormattedCipher)
private
FRounds: Integer;
FVersion: TSAFERVersion;
procedure SetRounds(Value: Integer);
procedure SetVersion(Value: TSAFERVersion);
protected
///
/// Initialize the key, based on the key passed in
///
///
/// Encryption/Decryption key to be used
///
///
/// Size of the key passed in bytes.
///
procedure DoInit(const Key; Size: Integer); override;
procedure DoEncode(Source, Dest: Pointer; Size: Integer); override;
procedure DoDecode(Source, Dest: Pointer; Size: Integer); override;
public
class function Context: TCipherContext; override;
///
/// Sets the number of rounds/times the algorithm is being applied to the
/// data. Range should be 4-13 and default is 5, 6, 10 or 8 rounds
/// depending on the version
///
property Rounds: Integer read FRounds write SetRounds;
property Version: TSAFERVersion read FVersion write SetVersion;
end;
{$IFNDEF CPU64BITS}
PLong64 = ^TLong64;
TLong64 = packed record
L, R: UInt32;
end;
PLong64Array = ^TLong64Array;
TLong64Array = array[0..1023] of TLong64;
{$ENDIF}
TLogArray = array[0..255] of Byte;
///
/// Base class for both Shark implementations
///
TCipher_SharkBase = class(TDECFormattedCipher)
strict protected
{$IFNDEF CPU64BITS}
function Transform(A: TLong64; Log, ALog: TLogArray): TLong64;
function Shark(D: TLong64; K: PLong64): TLong64;
{$ELSE}
function Transform(A: UInt64; Log, ALog: TLogArray): UInt64;
{$ENDIF}
end;
TCipher_Shark = class(TCipher_SharkBase)
protected
///
/// Initialize the key, based on the key passed in
///
///
/// Encryption/Decryption key to be used
///
///
/// Size of the key passed in bytes.
///
procedure DoInit(const Key; Size: Integer); override;
procedure DoEncode(Source, Dest: Pointer; Size: Integer); override;
procedure DoDecode(Source, Dest: Pointer; Size: Integer); override;
public
class function Context: TCipherContext; override;
end;
///
/// Do only use if backwards compatibility with old code is necessary as
/// this implementation is faulty!
///
TCipher_Shark_DEC52 = class(TCipher_Shark)
protected
///
/// Initialize the key, based on the key passed in
///
///
/// Encryption/Decryption key to be used
///
///
/// Size of the key passed in bytes.
///
procedure DoInit(const Key; Size: Integer); override;
end;
TCipher_Skipjack = class(TDECFormattedCipher)
strict private
procedure SkipjackIncCheck(var ATab: PSkipjackTab; AMin: PSkipjackTab; AMax: PByte); inline;
procedure SkipjackDecCheck(var ATab: PSkipjackTab; AMin: PByte; AMax: PSkipjackTab); inline;
protected
///
/// Initialize the key, based on the key passed in
///
///
/// Encryption/Decryption key to be used
///
///
/// Size of the key passed in bytes.
///
procedure DoInit(const Key; Size: Integer); override;
procedure DoEncode(Source, Dest: Pointer; Size: Integer); override;
procedure DoDecode(Source, Dest: Pointer; Size: Integer); override;
public
class function Context: TCipherContext; override;
end;
TCipher_TEA = class(TDECFormattedCipher)
private
FRounds: Integer;
procedure SetRounds(Value: Integer);
protected
///
/// Initialize the key, based on the key passed in
///
///
/// Encryption/Decryption key to be used
///
///
/// Size of the key passed in bytes.
///
procedure DoInit(const Key; Size: Integer); override;
procedure DoEncode(Source, Dest: Pointer; Size: Integer); override;
procedure DoDecode(Source, Dest: Pointer; Size: Integer); override;
public
class function Context: TCipherContext; override;
///
/// 16 - 256 Rounds, 16 (default) is sufficient, 64 is the official
/// recommendation. If a value outside the range of 16 to 256 is assigned
/// it will be limited to that range.
///
property Rounds: Integer read FRounds write SetRounds;
end;
///
/// XTEA is an improved version of the TEA algorithm.
///
///
/// In DEC V5.2 at least and in former commits of DEC 6.0 development version
/// this algorithm was broken due to differences in brackets and thus returned
/// a different result. It is unclear why nobody reported this as bug yet
/// but be aware that if you need the old variant for compatibility reasons
/// you need a commit from before 3rd December 2020.
///
TCipher_XTEA = class(TCipher_TEA)
protected
procedure DoEncode(Source, Dest: Pointer; Size: Integer); override;
procedure DoDecode(Source, Dest: Pointer; Size: Integer); override;
end;
TCipher_TEAN = class(TCipher_XTEA);
///
/// XTEA is an improved version of the TEA algorithm. This version is the
/// old faulty one from DEC 5.2. Use only if necessary for compatibility
/// reasons!
///
///
/// In DEC V5.2 at least and in former commits of DEC 6.0 development version
/// this algorithm was broken due to differences in brackets and thus returned
/// a different result. It is unclear why nobody reported this as bug yet
/// but be aware that if you need the old variant for compatibility reasons
/// you need a commit from before 3rd December 2020.
///
TCipher_XTEA_DEC52 = class(TCipher_TEA)
protected
procedure DoEncode(Source, Dest: Pointer; Size: Integer); override;
procedure DoDecode(Source, Dest: Pointer; Size: Integer); override;
end;
implementation
{$IFOPT Q+}{$DEFINE RESTORE_OVERFLOWCHECKS}{$Q-}{$ENDIF}
{$IFOPT R+}{$DEFINE RESTORE_RANGECHECKS}{$R-}{$ENDIF}
uses
{$IFDEF FPC}
SysUtils,
{$ELSE}
System.SysUtils,
{$ENDIF}
DECData, DECDataCipher;
{ TCipher_Null }
class function TCipher_Null.Context: TCipherContext;
begin
Result.KeySize := 0;
Result.BlockSize := 1;
Result.BufferSize := 8;
Result.AdditionalBufferSize := 0;
Result.NeedsAdditionalBufferBackup := False;
Result.MinRounds := 1;
Result.MaxRounds := 1;
Result.CipherType := [ctNull, ctSymmetric];
end;
procedure TCipher_Null.DoInit(const Key; Size: Integer);
begin
// dummy
end;
procedure TCipher_Null.DoEncode(Source, Dest: Pointer; Size: Integer);
begin
if Source <> Dest then
Move(Source^, Dest^, Size);
end;
procedure TCipher_Null.DoDecode(Source, Dest: Pointer; Size: Integer);
begin
if Source <> Dest then
Move(Source^, Dest^, Size);
end;
{ TCipher_Blowfish }
type
PBlowfish = ^TBlowfish;
TBlowfish = array[0..3, 0..255] of UInt32;
class function TCipher_Blowfish.Context: TCipherContext;
begin
Result.KeySize := 56;
Result.BufferSize := 8;
Result.BlockSize := 8;
Result.AdditionalBufferSize := SizeOf(Blowfish_Data) + SizeOf(Blowfish_Key);
Result.NeedsAdditionalBufferBackup := False;
Result.MinRounds := 1;
Result.MaxRounds := 1;
Result.CipherType := [ctSymmetric, ctBlock];
end;
procedure TCipher_Blowfish.DoInit(const Key; Size: Integer);
var
I, J: Integer;
B: array[0..1] of UInt32;
K: PByteArray;
P: PUInt32Array;
S: PBlowfish;
begin
K := @Key;
S := FAdditionalBuffer;
P := Pointer(PByte(FAdditionalBuffer) + SizeOf(Blowfish_Data)); // for Pointer Math
Move(Blowfish_Data, S^, SizeOf(Blowfish_Data));
Move(Blowfish_Key, P^, Sizeof(Blowfish_Key));
J := 0;
if Size > 0 then
for I := 0 to 17 do
begin
P[I] := P[I] xor (K[(J + 0) mod Size] shl 24 +
K[(J + 1) mod Size] shl 16 +
K[(J + 2) mod Size] shl 8 +
K[(J + 3) mod Size] shl 0);
J := (J + 4) mod Size;
end;
FillChar(B, SizeOf(B), 0);
for I := 0 to 8 do
begin
DoEncode(@B, @B, SizeOf(B));
P[I * 2 + 0] := SwapUInt32(B[0]);
P[I * 2 + 1] := SwapUInt32(B[1]);
end;
for I := 0 to 3 do
for J := 0 to 127 do
begin
DoEncode(@B, @B, SizeOf(B));
S[I, J * 2 + 0] := SwapUInt32(B[0]);
S[I, J * 2 + 1] := SwapUInt32(B[1]);
end;
FillChar(B, SizeOf(B), 0);
end;
procedure TCipher_Blowfish.DoEncode(Source, Dest: Pointer; Size: Integer);
{$IFDEF X86ASM}
// Source = EDX, Dest = ECX, Size on Stack
asm
PUSH EDI
PUSH ESI
PUSH EBX
PUSH EBP
PUSH ECX
MOV ESI,[EAX].TCipher_Blowfish.FAdditionalBuffer
MOV EBX,[EDX + 0] // A
MOV EBP,[EDX + 4] // B
BSWAP EBX // CPU >= 486
BSWAP EBP
XOR EBX,[ESI + 4 * 256 * 4]
XOR EDI,EDI
@@1: MOV EAX,EBX
SHR EBX,16
MOVZX ECX,BH
AND EBX,0FFh
MOV ECX,[ESI + ECX * 4 + 1024 * 0]
MOV EBX,[ESI + EBX * 4 + 1024 * 1]
MOVZX EDX,AH
ADD EBX,ECX
MOVZX ECX,AL
MOV EDX,[ESI + EDX * 4 + 1024 * 2]
MOV ECX,[ESI + ECX * 4 + 1024 * 3]
XOR EBX,EDX
XOR EBP,[ESI + 4 * 256 * 4 + 4 + EDI * 4]
ADD EBX,ECX
INC EDI
XOR EBX,EBP
TEST EDI,010h
MOV EBP,EAX
JZ @@1
POP EAX
XOR EBP,[ESI + 4 * 256 * 4 + 17 * 4]
BSWAP EBX
BSWAP EBP
MOV [EAX + 4],EBX
MOV [EAX + 0],EBP
POP EBP
POP EBX
POP ESI
POP EDI
end;
{$ELSE !X86ASM}
var
I, A, B: UInt32;
P: PUInt32Array;
D: PBlowfish;
begin
Assert(Size = Context.BlockSize, 'Size of ' + IntToStr(Size) + ' does not equal '+
'block size of ' + IntToStr(Context.BlockSize));
D := Pointer(FAdditionalBuffer);
P := Pointer(PByte(FAdditionalBuffer) + SizeOf(Blowfish_Data)); // for Pointer Math
A := SwapUInt32(PUInt32Array(Source)[0]) xor P[0]; P := @P[1];
B := SwapUInt32(PUInt32Array(Source)[1]);
for I := 0 to 7 do
begin
B := B xor P[0] xor (D[0, A shr 24 ] +
D[1, A shr 16 and $FF] xor
D[2, A shr 8 and $FF] +
D[3, A and $FF]);
A := A xor P[1] xor (D[0, B shr 24 ] +
D[1, B shr 16 and $FF] xor
D[2, B shr 8 and $FF] +
D[3, B and $FF]);
P := @P[2];
end;
PUInt32Array(Dest)[0] := SwapUInt32(B xor P[0]);
PUInt32Array(Dest)[1] := SwapUInt32(A);
end;
{$ENDIF !X86ASM}
procedure TCipher_Blowfish.DoDecode(Source, Dest: Pointer; Size: Integer);
{$IFDEF X86ASM}
asm
PUSH EDI
PUSH ESI
PUSH EBX
PUSH EBP
PUSH ECX
MOV ESI,[EAX].TCipher_Blowfish.FAdditionalBuffer
MOV EBX,[EDX + 0] // A
MOV EBP,[EDX + 4] // B
BSWAP EBX
BSWAP EBP
XOR EBX,[ESI + 4 * 256 * 4 + 17 * 4]
MOV EDI,16
@@1: MOV EAX,EBX
SHR EBX,16
MOVZX ECX,BH
MOVZX EDX,BL
MOV EBX,[ESI + ECX * 4 + 1024 * 0]
MOV EDX,[ESI + EDX * 4 + 1024 * 1]
MOVZX ECX,AH
LEA EBX,[EBX + EDX]
MOVZX EDX,AL
MOV ECX,[ESI + ECX * 4 + 1024 * 2]
MOV EDX,[ESI + EDX * 4 + 1024 * 3]
XOR EBX,ECX
XOR EBP,[ESI + 4 * 256 * 4 + EDI * 4]
LEA EBX,[EBX + EDX]
XOR EBX,EBP
DEC EDI
MOV EBP,EAX
JNZ @@1
POP EAX
XOR EBP,[ESI + 4 * 256 * 4]
BSWAP EBX
BSWAP EBP
MOV [EAX + 0],EBP
MOV [EAX + 4],EBX
POP EBP
POP EBX
POP ESI
POP EDI
end;
{$ELSE !X86ASM}
var
I, A, B: UInt32;
P: PUInt32Array;
D: PBlowfish;
begin
Assert(Size = Context.BlockSize);
D := Pointer(FAdditionalBuffer);
P := Pointer(PByte(FAdditionalBuffer) + SizeOf(Blowfish_Data) + SizeOf(Blowfish_Key) - SizeOf(Int32));
A := SwapUInt32(PUInt32Array(Source)[0]) xor P[0];
B := SwapUInt32(PUInt32Array(Source)[1]);
for I := 0 to 7 do
begin
Dec(PUInt32(P), 2);
B := B xor P[1] xor (D[0, A shr 24 ] +
D[1, A shr 16 and $FF] xor
D[2, A shr 8 and $FF] +
D[3, A and $FF]);
A := A xor P[0] xor (D[0, B shr 24 ] +
D[1, B shr 16 and $FF] xor
D[2, B shr 8 and $FF] +
D[3, B and $FF]);
end;
Dec(PUInt32(P));
PUInt32Array(Dest)[0] := SwapUInt32(B xor P[0]);
PUInt32Array(Dest)[1] := SwapUInt32(A);
end;
{$ENDIF !X86ASM}
{ TCipher_Twofish }
type
PTwofishBox = ^TTwofishBox;
TTwofishBox = array[0..3, 0..255] of UInt32;
TLongRec = record
case Integer of
0: (L: UInt32);
1: (A, B, C, D: Byte);
end;
class function TCipher_Twofish.Context: TCipherContext;
begin
Result.KeySize := 32;
Result.BufferSize := 16;
Result.BlockSize := 16;
Result.AdditionalBufferSize := 4256;
Result.NeedsAdditionalBufferBackup := False;
Result.MinRounds := 1;
Result.MaxRounds := 1;
Result.CipherType := [ctSymmetric, ctBlock];
end;
procedure TCipher_Twofish.DoInit(const Key; Size: Integer);
var
BoxKey: array[0..3] of TLongRec;
SubKey: PUInt32Array;
Box: PTwofishBox;
procedure SetupKey;
function Encode(K0, K1: Integer): Integer;
var
R, I, J, G2, G3: Integer;
B: byte;
begin
R := 0;
for I := 0 to 1 do
begin
if I <> 0 then
R := R xor K0
else
R := R xor K1;
for J := 0 to 3 do
begin
B := R shr 24;
if B and $80 <> 0 then
G2 := (B shl 1 xor $014D) and $FF
else
G2 := B shl 1 and $FF;
if B and 1 <> 0 then
G3 := (B shr 1 and $7F) xor $014D shr 1 xor G2
else
G3 := (B shr 1 and $7F) xor G2;
R := R shl 8 xor G3 shl 24 xor G2 shl 16 xor G3 shl 8 xor B;
end;
end;
Result := R;
end;
function F32(X: Integer; K: array of Integer): Integer;
var
A, B, C, D: UInt32;
begin
A := X and $FF;
B := X shr 8 and $FF;
C := X shr 16 and $FF;
D := X shr 24;
if Size = 32 then
begin
A := Twofish_8x8[1, A] xor K[3] and $FF;
B := Twofish_8x8[0, B] xor K[3] shr 8 and $FF;
C := Twofish_8x8[0, C] xor K[3] shr 16 and $FF;
D := Twofish_8x8[1, D] xor K[3] shr 24;
end;
if Size >= 24 then
begin
A := Twofish_8x8[1, A] xor K[2] and $FF;
B := Twofish_8x8[1, B] xor K[2] shr 8 and $FF;
C := Twofish_8x8[0, C] xor K[2] shr 16 and $FF;
D := Twofish_8x8[0, D] xor K[2] shr 24;
end;
A := Twofish_8x8[0, A] xor K[1] and $FF;
B := Twofish_8x8[1, B] xor K[1] shr 8 and $FF;
C := Twofish_8x8[0, C] xor K[1] shr 16 and $FF;
D := Twofish_8x8[1, D] xor K[1] shr 24;
A := Twofish_8x8[0, A] xor K[0] and $FF;
B := Twofish_8x8[0, B] xor K[0] shr 8 and $FF;
C := Twofish_8x8[1, C] xor K[0] shr 16 and $FF;
D := Twofish_8x8[1, D] xor K[0] shr 24;
Result := Twofish_Data[0, A] xor Twofish_Data[1, B] xor
Twofish_Data[2, C] xor Twofish_Data[3, D];
end;
var
I, J, A, B: Integer;
E, O: array[0..3] of Integer;
K: array[0..7] of Integer;
begin
FillChar(K, SizeOf(K), 0);
Move(Key, K, Size);
if Size <= 16 then
Size := 16
else
if Size <= 24 then
Size := 24
else
Size := 32;
J := Size shr 3 - 1;
for I := 0 to J do
begin
E[I] := K[I shl 1];
O[I] := K[I shl 1 + 1];
BoxKey[J].L := Encode(E[I], O[I]);
Dec(J);
end;
J := 0;
for I := 0 to 19 do
begin
A := F32(J, E);
B := F32(J + $01010101, O);
B := B shl 8 or B shr 24;
SubKey[I shl 1] := A + B;
B := A + B shl 1; // here buggy instead shr 1 it's correct shl 1
SubKey[I shl 1 + 1] := B shl 9 or B shr 23;
Inc(J, $02020202);
end;
end;
procedure DoXOR(D, S: PUInt32Array; Value: UInt32);
var
I: UInt32;
begin
Value := (Value and $FF) * $01010101;
for I := 0 to 63 do
D[I] := S[I] xor Value;
end;
procedure SetupBox128;
var
L: array[0..255] of Byte;
A, I: Integer;
begin
DoXOR(@L, @Twofish_8x8[0], BoxKey[1].L);
A := BoxKey[0].A;
for I := 0 to 255 do
Box[0, I] := Twofish_Data[0, Twofish_8x8[0, L[I]] xor A];
DoXOR(@L, @Twofish_8x8[1], BoxKey[1].L shr 8);
A := BoxKey[0].B;
for I := 0 to 255 do
Box[1, I] := Twofish_Data[1, Twofish_8x8[0, L[I]] xor A];
DoXOR(@L, @Twofish_8x8[0], BoxKey[1].L shr 16);
A := BoxKey[0].C;
for I := 0 to 255 do
Box[2, I] := Twofish_Data[2, Twofish_8x8[1, L[I]] xor A];
DoXOR(@L, @Twofish_8x8[1], BoxKey[1].L shr 24);
A := BoxKey[0].D;
for I := 0 to 255 do
Box[3, I] := Twofish_Data[3, Twofish_8x8[1, L[I]] xor A];
end;
procedure SetupBox192;
var
L: array[0..255] of Byte;
A, B, I: Integer;
begin
DoXOR(@L, @Twofish_8x8[1], BoxKey[2].L);
A := BoxKey[0].A;
B := BoxKey[1].A;
for I := 0 to 255 do
Box[0, I] := Twofish_Data[0, Twofish_8x8[0, Twofish_8x8[0, L[I]] xor B] xor A];
DoXOR(@L, @Twofish_8x8[1], BoxKey[2].L shr 8);
A := BoxKey[0].B;
B := BoxKey[1].B;
for I := 0 to 255 do
Box[1, I] := Twofish_Data[1, Twofish_8x8[0, Twofish_8x8[1, L[I]] xor B] xor A];
DoXOR(@L, @Twofish_8x8[0], BoxKey[2].L shr 16);
A := BoxKey[0].C;
B := BoxKey[1].C;
for I := 0 to 255 do
Box[2, I] := Twofish_Data[2, Twofish_8x8[1, Twofish_8x8[0, L[I]] xor B] xor A];
DoXOR(@L ,@Twofish_8x8[0], BoxKey[2].L shr 24);
A := BoxKey[0].D;
B := BoxKey[1].D;
for I := 0 to 255 do
Box[3, I] := Twofish_Data[3, Twofish_8x8[1, Twofish_8x8[1, L[I]] xor B] xor A];
end;
procedure SetupBox256;
var
L: array[0..255] of Byte;
K: array[0..255] of Byte;
A, B, I: Integer;
begin
DoXOR(@K, @Twofish_8x8[1], BoxKey[3].L);
for I := 0 to 255 do
L[I] := Twofish_8x8[1, K[I]];
DoXOR(@L, @L, BoxKey[2].L);
A := BoxKey[0].A;
B := BoxKey[1].A;
for I := 0 to 255 do
Box[0, I] := Twofish_Data[0, Twofish_8x8[0, Twofish_8x8[0, L[I]] xor B] xor A];
DoXOR(@K, @Twofish_8x8[0], BoxKey[3].L shr 8);
for I := 0 to 255 do
L[I] := Twofish_8x8[1, K[I]];
DoXOR(@L, @L, BoxKey[2].L shr 8);
A := BoxKey[0].B;
B := BoxKey[1].B;
for I := 0 to 255 do
Box[1, I] := Twofish_Data[1, Twofish_8x8[0, Twofish_8x8[1, L[I]] xor B] xor A];
DoXOR(@K, @Twofish_8x8[0], BoxKey[3].L shr 16);
for I := 0 to 255 do
L[I] := Twofish_8x8[0, K[I]];
DoXOR(@L, @L, BoxKey[2].L shr 16);
A := BoxKey[0].C;
B := BoxKey[1].C;
for I := 0 to 255 do
Box[2, I] := Twofish_Data[2, Twofish_8x8[1, Twofish_8x8[0, L[I]] xor B] xor A];
DoXOR(@K, @Twofish_8x8[1], BoxKey[3].L shr 24);
for I := 0 to 255 do
L[I] := Twofish_8x8[0, K[I]];
DoXOR(@L, @L, BoxKey[2].L shr 24);
A := BoxKey[0].D;
B := BoxKey[1].D;
for I := 0 to 255 do
Box[3, I] := Twofish_Data[3, Twofish_8x8[1, Twofish_8x8[1, L[I]] xor B] xor A];
end;
begin
SubKey := FAdditionalBuffer;
Box := @SubKey[40];
SetupKey;
if Size = 16 then
SetupBox128
else
if Size = 24 then
SetupBox192
else
SetupBox256;
end;
procedure TCipher_Twofish.DoEncode(Source, Dest: Pointer; Size: Integer);
var
S: PUInt32Array;
Box: PTwofishBox;
I, X, Y: UInt32;
A, B, C, D: TLongRec;
begin
Assert(Size = Context.BlockSize);
S := FAdditionalBuffer;
A.L := PUInt32Array(Source)[0] xor S[0];
B.L := PUInt32Array(Source)[1] xor S[1];
C.L := PUInt32Array(Source)[2] xor S[2];
D.L := PUInt32Array(Source)[3] xor S[3];
Box := @S[40];
S := @S[8];
for I := 0 to 7 do
begin
X := Box[0, A.A] xor Box[1, A.B] xor Box[2, A.C] xor Box[3, A.D];
Y := Box[1, B.A] xor Box[2, B.B] xor Box[3, B.C] xor Box[0, B.D];
D.L := D.L shl 1 or D.L shr 31;
C.L := C.L xor (X + Y + S[0]);
D.L := D.L xor (X + Y shl 1 + S[1]);
C.L := C.L shr 1 or C.L shl 31;
X := Box[0, C.A] xor Box[1, C.B] xor Box[2, C.C] xor Box[3, C.D];
Y := Box[1, D.A] xor Box[2, D.B] xor Box[3, D.C] xor Box[0, D.D];
B.L := B.L shl 1 or B.L shr 31;
A.L := A.L xor (X + Y + S[2]);
B.L := B.L xor (X + Y shl 1 + S[3]);
A.L := A.L shr 1 or A.L shl 31;
S := @S[4];
end;
S := FAdditionalBuffer;
PUInt32Array(Dest)[0] := C.L xor S[4];
PUInt32Array(Dest)[1] := D.L xor S[5];
PUInt32Array(Dest)[2] := A.L xor S[6];
PUInt32Array(Dest)[3] := B.L xor S[7];
end;
procedure TCipher_Twofish.DoDecode(Source, Dest: Pointer; Size: Integer);
var
S: PUInt32Array;
Box: PTwofishBox;
I, X, Y: UInt32;
A, B, C, D: TLongRec;
begin
Assert(Size = Context.BlockSize);
S := FAdditionalBuffer;
Box := @S[40];
C.L := PUInt32Array(Source)[0] xor S[4];
D.L := PUInt32Array(Source)[1] xor S[5];
A.L := PUInt32Array(Source)[2] xor S[6];
B.L := PUInt32Array(Source)[3] xor S[7];
S := @S[36];
for I := 0 to 7 do
begin
X := Box[0, C.A] xor Box[1, C.B] xor Box[2, C.C] xor Box[3, C.D];
Y := Box[0, D.D] xor Box[1, D.A] xor Box[2, D.B] xor Box[3, D.C];
A.L := A.L shl 1 or A.L shr 31;
B.L := B.L xor (X + Y shl 1 + S[3]);
A.L := A.L xor (X + Y + S[2]);
B.L := B.L shr 1 or B.L shl 31;
X := Box[0, A.A] xor Box[1, A.B] xor Box[2, A.C] xor Box[3, A.D];
Y := Box[0, B.D] xor Box[1, B.A] xor Box[2, B.B] xor Box[3, B.C];
C.L := C.L shl 1 or C.L shr 31;
D.L := D.L xor (X + Y shl 1 + S[1]);
C.L := C.L xor (X + Y + S[0]);
D.L := D.L shr 1 or D.L shl 31;
Dec(PUInt32(S), 4);
end;
S := FAdditionalBuffer;
PUInt32Array(Dest)[0] := A.L xor S[0];
PUInt32Array(Dest)[1] := B.L xor S[1];
PUInt32Array(Dest)[2] := C.L xor S[2];
PUInt32Array(Dest)[3] := D.L xor S[3];
end;
{ TCipher_IDEA }
class function TCipher_IDEA.Context: TCipherContext;
begin
Result.KeySize := 16;
Result.BufferSize := 8;
Result.BlockSize := 8;
Result.AdditionalBufferSize := 208;
Result.NeedsAdditionalBufferBackup := False;
Result.MinRounds := 1;
Result.MaxRounds := 1;
Result.CipherType := [ctSymmetric, ctBlock];
end;
procedure TCipher_IDEA.DoInit(const Key; Size: Integer);
function IDEAInv(X: Word): Word;
var
A, B, C, D: Word;
begin
if X <= 1 then
begin
Result := X;
Exit;
end;
A := 1;
B := $10001 div X;
C := $10001 mod X;
while C <> 1 do
begin
D := X div C;
X := X mod C;
Inc(A, B * D);
if X = 1 then
begin
Result := A;
Exit;
end;
D := C div X;
C := C mod X;
Inc(B, A * D);
end;
Result := 1 - B;
end;
var
I: Integer;
E: PWordArray;
A, B, C: Word;
K, D: PWordArray;
begin
E := FAdditionalBuffer;
Move(Key, E^, Size);
for I := 0 to 7 do
E[I] := Swap(E[I]);
for I := 0 to 39 do
E[I + 8] := E[I and not 7 + (I + 1) and 7] shl 9 or
E[I and not 7 + (I + 2) and 7] shr 7;
for I := 41 to 44 do
E[I + 7] := E[I] shl 9 or E[I + 1] shr 7;
K := E;
D := @E[100];
A := IDEAInv(K[0]);
B := 0 - K[1];
C := 0 - K[2];
D[3] := IDEAInv(K[3]);
D[2] := C;
D[1] := B;
D[0] := A;
Inc(PWord(K), 4);
for I := 1 to 8 do
begin
Dec(PWord(D), 6);
A := K[0];
D[5] := K[1];
D[4] := A;
A := IDEAInv(K[2]);
B := 0 - K[3];
C := 0 - K[4];
D[3] := IDEAInv(K[5]);
D[2] := B;
D[1] := C;
D[0] := A;
Inc(PWord(K), 6);
end;
A := D[2];
D[2] := D[1];
D[1] := A;
end;
function IDEAMul(X, Y: UInt32): UInt32;
{$IF defined(X86ASM) or defined(X64ASM)}
asm
{$IFDEF X64ASM}
MOV EAX,ECX
{$ENDIF X64ASM}
AND EAX,0FFFFh
JZ @@1
AND EDX,0FFFFh
JZ @@1
MUL EDX
MOV EDX,EAX
MOV ECX,EAX
SHR EDX,16
SUB EAX,EDX
SUB CX,AX
ADC EAX,0
RET
@@1: LEA EAX,[EAX + EDX - 1]
NEG EAX
end;
{$ELSE}
begin
X := X and $FFFF;
if X <> 0 then
begin
Y := Y and $FFFF;
if Y <> 0 then
begin
X := X * Y;
Result := X - (X shr 16);
if Word(X) < Word(Result) then // carry flag check for "sub cx,ax"
Inc(Result);
Exit;
end;
end;
Result := -(X + Y - 1);
end;
{$IFEND}
procedure IDEACipher(Source, Dest: PUInt32Array; Key: PWordArray);
var
I: UInt32;
X, Y, A, B, C, D: UInt32;
begin
I := SwapUInt32(Source[0]);
A := I shr 16;
B := I and $FFFF;
I := SwapUInt32(Source[1]);
C := I shr 16;
D := I and $FFFF;
for I := 0 to 7 do
begin
A := IDEAMul(A, Key[0]);
Inc(B, Key[1]);
Inc(C, Key[2]);
D := IDEAMul(D, Key[3]);
Y := C xor A;
Y := IDEAMul(Y, Key[4]);
X := B xor D + Y;
X := IDEAMul(X, Key[5]);
Inc(Y, X);
A := A xor X;
D := D xor Y;
Y := B xor Y;
B := C xor X;
C := Y;
Key := @Key[6];
end;
Dest[0] := SwapUInt32(IDEAMul(A, Key[0]) shl 16 or (C + Key[1]) and $FFFF);
Dest[1] := SwapUInt32((B + Key[2]) shl 16 or IDEAMul(D, Key[3]) and $FFFF);
end;
procedure TCipher_IDEA.DoEncode(Source, Dest: Pointer; Size: Integer);
begin
Assert(Size = Context.BlockSize);
IDEACipher(Source, Dest, FAdditionalBuffer);
end;
procedure TCipher_IDEA.DoDecode(Source, Dest: Pointer; Size: Integer);
begin
Assert(Size = Context.BlockSize);
IDEACipher(Source, Dest, @PUInt32Array(FAdditionalBuffer)[26]);
end;
{ TCipher_Cast256 }
class function TCipher_Cast256.Context: TCipherContext;
begin
Result.KeySize := 32;
Result.BlockSize := 16;
Result.BufferSize := 16;
Result.AdditionalBufferSize := 384;
Result.NeedsAdditionalBufferBackup := False;
Result.MinRounds := 1;
Result.MaxRounds := 1;
Result.CipherType := [ctSymmetric, ctBlock];
end;
procedure TCipher_Cast256.DoInit(const Key; Size: Integer);
var
X: array[0..7] of UInt32;
M, R, I, J, T: UInt32;
K: PUInt32Array;
begin
FillChar(X, SizeOf(X), 0);
Move(Key, X, Size);
SwapUInt32Buffer(X, X, 8);
K := FAdditionalBuffer;
M := $5A827999;
R := 19;
for I := 0 to 11 do
begin
for J := 0 to 1 do
begin
T := M + X[7];
T := T shl R or T shr (32 - R);
X[6] := X[6] xor (Cast256_Data[0, T shr 24] xor
Cast256_Data[1, T shr 16 and $FF] -
Cast256_Data[2, T shr 8 and $FF] +
Cast256_Data[3, T and $FF]);
Inc(M, $6ED9EBA1);
Inc(R, 17);
T := M xor X[6];
T := T shl R or T shr (32 - R);
X[5] := X[5] xor (Cast256_Data[0, T shr 24] -
Cast256_Data[1, T shr 16 and $FF] +
Cast256_Data[2, T shr 8 and $FF] xor
Cast256_Data[3, T and $FF]);
Inc(M, $6ED9EBA1);
Inc(R, 17);
T := M - X[5];
T := T shl R or T shr (32 - R);
X[4] := X[4] xor (Cast256_Data[0, T shr 24] +
Cast256_Data[1, T shr 16 and $FF] xor
Cast256_Data[2, T shr 8 and $FF] -
Cast256_Data[3, T and $FF]);
Inc(M, $6ED9EBA1);
Inc(R, 17);
T := M + X[4];
T := T shl R or T shr (32 - R);
X[3] := X[3] xor (Cast256_Data[0, T shr 24] xor
Cast256_Data[1, T shr 16 and $FF] -
Cast256_Data[2, T shr 8 and $FF] +
Cast256_Data[3, T and $FF]);
Inc(M, $6ED9EBA1);
Inc(R, 17);
T := M xor X[3];
T := T shl R or T shr (32 - R);
X[2] := X[2] xor (Cast256_Data[0, T shr 24] -
Cast256_Data[1, T shr 16 and $FF] +
Cast256_Data[2, T shr 8 and $FF] xor
Cast256_Data[3, T and $FF]);
Inc(M, $6ED9EBA1);
Inc(R, 17);
T := M - X[2];
T := T shl R or T shr (32 - R);
X[1] := X[1] xor (Cast256_Data[0, T shr 24] +
Cast256_Data[1, T shr 16 and $FF] xor
Cast256_Data[2, T shr 8 and $FF] -
Cast256_Data[3, T and $FF]);
Inc(M, $6ED9EBA1);
Inc(R, 17);
T := M + X[1];
T := T shl R or T shr (32 - R);
X[0] := X[0] xor (Cast256_Data[0, T shr 24] xor
Cast256_Data[1, T shr 16 and $FF] -
Cast256_Data[2, T shr 8 and $FF] +
Cast256_Data[3, T and $FF]);
Inc(M, $6ED9EBA1);
Inc(R, 17);
T := M xor X[0];
T := T shl R or T shr (32 - R);
X[7] := X[7] xor (Cast256_Data[0, T shr 24] -
Cast256_Data[1, T shr 16 and $FF] +
Cast256_Data[2, T shr 8 and $FF] xor
Cast256_Data[3, T and $FF]);
Inc(M, $6ED9EBA1);
Inc(R, 17);
end;
if I < 6 then
begin
K[48] := X[0] and $1F;
K[49] := X[2] and $1F;
K[50] := X[4] and $1F;
K[51] := X[6] and $1F;
K[0] := X[7];
K[1] := X[5];
K[2] := X[3];
K[3] := X[1];
end
else
begin
K[48] := X[6] and $1F;
K[49] := X[4] and $1F;
K[50] := X[2] and $1F;
K[51] := X[0] and $1F;
K[0] := X[1];
K[1] := X[3];
K[2] := X[5];
K[3] := X[7];
end;
K := @K[4];
end;
ProtectBuffer(X, SizeOf(X));
end;
procedure TCipher_Cast256.DoEncode(Source, Dest: Pointer; Size: Integer);
var
I, T, A, B, C, D: UInt32;
K: PUInt32Array;
begin
Assert(Size = Context.BlockSize);
K := FAdditionalBuffer;
SwapUInt32Buffer(Source^, Dest^, 4);
A := PUInt32Array(Dest)[0];
B := PUInt32Array(Dest)[1];
C := PUInt32Array(Dest)[2];
D := PUInt32Array(Dest)[3];
for I := 0 to 5 do
begin
T := K[0] + D;
T := T shl K[48] or T shr (32 - K[48]);
C := C xor (Cast256_Data[0, T shr 24] xor
Cast256_Data[1, T shr 16 and $FF] -
Cast256_Data[2, T shr 8 and $FF] +
Cast256_Data[3, T and $FF]);
T := K[1] xor C;
T := T shl K[49] or T shr (32 - K[49]);
B := B xor (Cast256_Data[0, T shr 24] -
Cast256_Data[1, T shr 16 and $FF] +
Cast256_Data[2, T shr 8 and $FF] xor
Cast256_Data[3, T and $FF]);
T := K[2] - B;
T := T shl K[50] or T shr (32 - K[50]);
A := A xor (Cast256_Data[0, T shr 24] +
Cast256_Data[1, T shr 16 and $FF] xor
Cast256_Data[2, T shr 8 and $FF] -
Cast256_Data[3, T and $FF]);
T := K[3] + A;
T := T shl K[51] or T shr (32 - K[51]);
D := D xor (Cast256_Data[0, T shr 24] xor
Cast256_Data[1, T shr 16 and $FF] -
Cast256_Data[2, T shr 8 and $FF] +
Cast256_Data[3, T and $FF]);
K := @K[4];
end;
for I := 0 to 5 do
begin
T := K[0] + A;
T := T shl K[48] or T shr (32 - K[48]);
D := D xor (Cast256_Data[0, T shr 24] xor
Cast256_Data[1, T shr 16 and $FF] -
Cast256_Data[2, T shr 8 and $FF] +
Cast256_Data[3, T and $FF]);
T := K[1] - B;
T := T shl K[49] or T shr (32 - K[49]);
A := A xor (Cast256_Data[0, T shr 24] +
Cast256_Data[1, T shr 16 and $FF] xor
Cast256_Data[2, T shr 8 and $FF] -
Cast256_Data[3, T and $FF]);
T := K[2] xor C;
T := T shl K[50] or T shr (32 - K[50]);
B := B xor (Cast256_Data[0, T shr 24] -
Cast256_Data[1, T shr 16 and $FF] +
Cast256_Data[2, T shr 8 and $FF] xor
Cast256_Data[3, T and $FF]);
T := K[3] + D;
T := T shl K[51] or T shr (32 - K[51]);
C := C xor (Cast256_Data[0, T shr 24] xor
Cast256_Data[1, T shr 16 and $FF] -
Cast256_Data[2, T shr 8 and $FF] +
Cast256_Data[3, T and $FF]);
K := @K[4];
end;
PUInt32Array(Dest)[0] := A;
PUInt32Array(Dest)[1] := B;
PUInt32Array(Dest)[2] := C;
PUInt32Array(Dest)[3] := D;
SwapUInt32Buffer(Dest^, Dest^, 4);
end;
procedure TCipher_Cast256.DoDecode(Source, Dest: Pointer; Size: Integer);
var
I, T, A, B, C, D: UInt32;
K: PUInt32Array;
begin
Assert(Size = Context.BlockSize);
K := @PUInt32Array(FAdditionalBuffer)[44];
SwapUInt32Buffer(Source^, Dest^, 4);
A := PUInt32Array(Dest)[0];
B := PUInt32Array(Dest)[1];
C := PUInt32Array(Dest)[2];
D := PUInt32Array(Dest)[3];
for I := 0 to 5 do
begin
T := K[3] + D;
T := T shl K[51] or T shr (32 - K[51]);
C := C xor (Cast256_Data[0, T shr 24] xor
Cast256_Data[1, T shr 16 and $FF] -
Cast256_Data[2, T shr 8 and $FF] +
Cast256_Data[3, T and $FF]);
T := K[2] xor C;
T := T shl K[50] or T shr (32 - K[50]);
B := B xor (Cast256_Data[0, T shr 24] -
Cast256_Data[1, T shr 16 and $FF] +
Cast256_Data[2, T shr 8 and $FF] xor
Cast256_Data[3, T and $FF]);
T := K[1] - B;
T := T shl K[49] or T shr (32 - K[49]);
A := A xor (Cast256_Data[0, T shr 24] +
Cast256_Data[1, T shr 16 and $FF] xor
Cast256_Data[2, T shr 8 and $FF] -
Cast256_Data[3, T and $FF]);
T := K[0] + A;
T := T shl K[48] or T shr (32 - K[48]);
D := D xor (Cast256_Data[0, T shr 24] xor
Cast256_Data[1, T shr 16 and $FF] -
Cast256_Data[2, T shr 8 and $FF] +
Cast256_Data[3, T and $FF]);
Dec(PUInt32(K), 4);
end;
for I := 0 to 5 do
begin
T := K[3] + A;
T := T shl K[51] or T shr (32 - K[51]);
D := D xor (Cast256_Data[0, T shr 24] xor
Cast256_Data[1, T shr 16 and $FF] -
Cast256_Data[2, T shr 8 and $FF] +
Cast256_Data[3, T and $FF]);
T := K[2] - B;
T := T shl K[50] or T shr (32 - K[50]);
A := A xor (Cast256_Data[0, T shr 24] +
Cast256_Data[1, T shr 16 and $FF] xor
Cast256_Data[2, T shr 8 and $FF] -
Cast256_Data[3, T and $FF]);
T := K[1] xor C;
T := T shl K[49] or T shr (32 - K[49]);
B := B xor (Cast256_Data[0, T shr 24] -
Cast256_Data[1, T shr 16 and $FF] +
Cast256_Data[2, T shr 8 and $FF] xor
Cast256_Data[3, T and $FF]);
T := K[0] + D;
T := T shl K[48] or T shr (32 - K[48]);
C := C xor (Cast256_Data[0, T shr 24] xor
Cast256_Data[1, T shr 16 and $FF] -
Cast256_Data[2, T shr 8 and $FF] +
Cast256_Data[3, T and $FF]);
Dec(PUInt32(K), 4);
end;
PUInt32Array(Dest)[0] := A;
PUInt32Array(Dest)[1] := B;
PUInt32Array(Dest)[2] := C;
PUInt32Array(Dest)[3] := D;
SwapUInt32Buffer(Dest^, Dest^, 4);
end;
{ TCipher_Mars }
class function TCipher_Mars.Context: TCipherContext;
begin
Result.KeySize := 56;
Result.BlockSize := 16;
Result.BufferSize := 16;
Result.AdditionalBufferSize := 160;
Result.NeedsAdditionalBufferBackup := False;
Result.MinRounds := 1;
Result.MaxRounds := 1;
Result.CipherType := [ctSymmetric, ctBlock];
end;
procedure TCipher_Mars.DoInit(const Key; Size: Integer);
var
B: PUInt32Array;
function FixKey(K, R: UInt32): UInt32;
var
M1, M2: UInt32;
I: UInt32;
begin
I := K and 3;
K := K or 3;
M1 := not K xor (K shl 1);
M2 := M1 and (M1 shl 1);
M2 := M2 and (M2 shl 2);
M2 := M2 and (M2 shl 4);
M2 := M2 and (M1 shl 8);
M2 := M2 and $FFFFFE00;
if M2 = 0 then
begin
Result := K;
Exit;
end;
M1 := M2 or (M2 shr 1);
M1 := M1 or (M1 shr 2);
M1 := M1 or (M2 shr 4);
M1 := M1 or (M1 shr 5);
M1 := M1 and ((not K xor (K shl 1)) and (not K xor (K shr 1)) and $7FFFFFFC);
Result := K xor ((B[265 + I] shl R or B[265 + I] shr (32 - R)) and M1);
end;
var
T: array[0..14] of UInt32;
I, J, L: UInt32;
U: UInt32;
K: PUInt32Array;
begin
K := FAdditionalBuffer;
B := @Mars_Data;
FillChar(T, SizeOf(T), 0);
Move(Key, T, Size);
Size := Size div 4;
T[Size] := Size;
for J := 0 to 3 do
begin
for I := 0 to 14 do
begin
U := T[(I + 8) mod 15] xor T[(I + 13) mod 15];
T[I] := T[I] xor (U shl 3 or U shr 29) xor (I * 4 + J);
end;
for L := 0 to 3 do
begin
for I := 0 to 14 do
begin
Inc(T[I], B[T[(I + 14) mod 15] and $1FF]);
T[I] := T[I] shl 9 or T[I] shr 23;
end;
end;
for I := 0 to 9 do
K[(J * 10) + I] := T[(I * 4) mod 15];
end;
I := 5;
repeat
K[I] := FixKey(K[I], K[I - 1]);
Inc(I, 2);
until I >= 37;
end;
procedure TCipher_Mars.DoEncode(Source, Dest: Pointer; Size: Integer);
var
K: PUInt32Array;
I, L, R, A, B, C, D: UInt32;
begin
Assert(Size = Context.BlockSize);
K := FAdditionalBuffer;
A := PUInt32Array(Source)[0] + K[0];
B := PUInt32Array(Source)[1] + K[1];
C := PUInt32Array(Source)[2] + K[2];
D := PUInt32Array(Source)[3] + K[3];
K := @K[4];
for I := 0 to 1 do
begin
B := B xor Mars_Data[A and $FF] + Mars_Data[A shr 8 and $FF + 256];
Inc(C, Mars_Data[A shr 16 and $FF]);
D := D xor Mars_Data[A shr 24 + 256];
A := (A shr 24 or A shl 8) + D;
C := C xor Mars_Data[B and $FF] + Mars_Data[B shr 8 and $FF + 256];
Inc(D, Mars_Data[B shr 16 and $FF]);
A := A xor Mars_Data[B shr 24 + 256];
B := (B shr 24 or B shl 8) + C;
D := D xor Mars_Data[C and $FF] + Mars_Data[C shr 8 and $FF + 256];
Inc(A, Mars_Data[C shr 16 and $FF]);
B := B xor Mars_Data[C shr 24 + 256];
C := C shr 24 or C shl 8;
A := A xor Mars_Data[D and $FF] + Mars_Data[D shr 8 and $FF + 256];
Inc(B, Mars_Data[D shr 16 and $FF]);
C := C xor Mars_Data[D shr 24 + 256];
D := D shr 24 or D shl 8;
end;
for I := 0 to 3 do
begin
L := A + K[0];
A := A shl 13 or A shr 19;
R := A * K[1];
R := R shl 5 or R shr 27;
Inc(C, L shl R or L shr (32 - R));
L := Mars_Data[L and $1FF] xor R;
R := R shl 5 or R shr 27;
L := L xor R;
L := L shl R or L shr (32 - R);
if I <= 1 then
begin
Inc(B, L);
D := D xor R;
end
else
begin
Inc(D, L);
B := B xor R;
end;
L := B + K[2];
B := B shl 13 or B shr 19;
R := B * K[3];
R := R shl 5 or R shr 27;
Inc(D, L shl R or L shr (32 - R));
L := Mars_Data[L and $1FF] xor R;
R := R shl 5 or R shr 27;
L := L xor R;
L := L shl R or L shr (32 - R);
if I <= 1 then
begin
Inc(C, L);
A := A xor R;
end
else
begin
Inc(A, L);
C := C xor R;
end;
L := C + K[4];
C := C shl 13 or C shr 19;
R := C * K[5];
R := R shl 5 or R shr 27;
Inc(A, L shl R or L shr (32 - R));
L := Mars_Data[L and $1FF] xor R;
R := R shl 5 or R shr 27;
L := L xor R;
L := L shl R or L shr (32 - R);
if I <= 1 then
begin
Inc(D, L);
B := B xor R;
end
else
begin
Inc(B, L);
D := D xor R;
end;
L := D + K[6];
D := D shl 13 or D shr 19;
R := D * K[7];
R := R shl 5 or R shr 27;
Inc(B, L shl R or L shr (32 - R));
L := Mars_Data[L and $1FF] xor R;
R := R shl 5 or R shr 27;
L := L xor R;
L := L shl R or L shr (32 - R);
if I <= 1 then
begin
Inc(A, L);
C := C xor R;
end
else
begin
Inc(C, L);
A := A xor R;
end;
K := @K[8];
end;
for I := 0 to 1 do
begin
B := B xor Mars_Data[A and $FF + 256];
Dec(C, Mars_Data[A shr 24]);
D := D - Mars_Data[A shr 16 and $FF + 256] xor Mars_Data[A shr 8 and $FF];
A := A shl 24 or A shr 8;
C := C xor Mars_Data[B and $FF + 256];
Dec(D, Mars_Data[B shr 24]);
A := A - Mars_Data[B shr 16 and $FF + 256] xor Mars_Data[B shr 8 and $FF];
B := B shl 24 or B shr 8;
Dec(C, B);
D := D xor Mars_Data[C and $FF + 256];
Dec(A, Mars_Data[C shr 24]);
B := B - Mars_Data[C shr 16 and $FF + 256] xor Mars_Data[C shr 8 and $FF];
C := C shl 24 or C shr 8;
Dec(D, A);
A := A xor Mars_Data[D and $FF + 256];
Dec(B, Mars_Data[D shr 24]);
C := C - Mars_Data[D shr 16 and $FF + 256] xor Mars_Data[D shr 8 and $FF];
D := D shl 24 or D shr 8;
end;
PUInt32Array(Dest)[0] := A - K[0];
PUInt32Array(Dest)[1] := B - K[1];
PUInt32Array(Dest)[2] := C - K[2];
PUInt32Array(Dest)[3] := D - K[3];
end;
procedure TCipher_Mars.DoDecode(Source, Dest: Pointer; Size: Integer);
var
K: PUInt32Array;
I, L, R, A, B, C, D: UInt32;
begin
Assert(Size = Context.BlockSize);
K := @PUInt32Array(FAdditionalBuffer)[28];
A := PUInt32Array(Source)[0] + K[8];
B := PUInt32Array(Source)[1] + K[9];
C := PUInt32Array(Source)[2] + K[10];
D := PUInt32Array(Source)[3] + K[11];
for I := 0 to 1 do
begin
D := D shr 24 or D shl 8;
C := C xor Mars_Data[D shr 8 and $FF] + Mars_Data[D shr 16 and $FF + 256];
Inc(B, Mars_Data[D shr 24]);
A := A xor Mars_Data[D and $FF + 256];
Inc(D, A);
C := C shr 24 or C shl 8;
B := B xor Mars_Data[C shr 8 and $FF] + Mars_Data[C shr 16 and $FF + 256];
Inc(A, Mars_Data[C shr 24]);
D := D xor Mars_Data[C and $FF + 256];
Inc(C, B);
B := B shr 24 or B shl 8;
A := A xor Mars_Data[B shr 8 and $FF] + Mars_Data[B shr 16 and $FF + 256];
Inc(D, Mars_Data[B shr 24]);
C := C xor Mars_Data[B and $FF + 256];
A := A shr 24 or A shl 8;
D := D xor Mars_Data[A shr 8 and $FF] + Mars_Data[A shr 16 and $FF + 256];
Inc(C, Mars_Data[A shr 24]);
B := B xor Mars_Data[A and $FF + 256];
end;
for I := 0 to 3 do
begin
R := D * K[7];
R := R shl 5 or R shr 27;
D := D shr 13 or D shl 19;
L := D + K[6];
Dec(B, L shl R or L shr (32 - R));
L := Mars_Data[L and $1FF] xor R;
R := R shl 5 or R shr 27;
L := L xor R;
L := L shl R or L shr (32 - R);
if I <= 1 then
begin
Dec(C, L);
A := A xor R;
end
else
begin
Dec(A, L);
C := C xor R;
end;
R := C * K[5];
R := R shl 5 or R shr 27;
C := C shr 13 or C shl 19;
L := C + K[4];
Dec(A, L shl R or L shr (32 - R));
L := Mars_Data[L and $1FF] xor R;
R := R shl 5 or R shr 27;
L := L xor R;
L := L shl R or L shr (32 - R);
if I <= 1 then
begin
Dec(B, L);
D := D xor R;
end
else
begin
Dec(D, L);
B := B xor R;
end;
R := B * K[3];
R := R shl 5 or R shr 27;
B := B shr 13 or B shl 19;
L := B + K[2];
Dec(D, L shl R or L shr (32 - R));
L := Mars_Data[L and $1FF] xor R;
R := R shl 5 or R shr 27;
L := L xor R;
L := L shl R or L shr (32 - R);
if I <= 1 then
begin
Dec(A, L);
C := C xor R;
end
else
begin
Dec(C, L);
A := A xor R;
end;
R := A * K[1];
R := R shl 5 or R shr 27;
A := A shr 13 or A shl 19;
L := A + K[0];
Dec(C, L shl R or L shr (32 - R));
L := Mars_Data[L and $1FF] xor R;
R := R shl 5 or R shr 27;
L := L xor R;
L := L shl R or L shr (32 - R);
if I <= 1 then
begin
Dec(D, L);
B := B xor R;
end
else
begin
Dec(B, L);
D := D xor R;
end;
Dec(PUInt32(K), 8);
end;
for I := 0 to 1 do
begin
D := D shl 24 or D shr 8;
C := C xor Mars_Data[D shr 24 + 256];
Dec(B, Mars_Data[D shr 16 and $FF]);
A := A - Mars_Data[D shr 8 and $FF + 256] xor Mars_Data[D and $FF];
C := C shl 24 or C shr 8;
B := B xor Mars_Data[C shr 24 + 256];
Dec(A, Mars_Data[C shr 16 and $FF]);
D := D - Mars_Data[C shr 8 and $FF + 256] xor Mars_Data[C and $FF];
Dec(B, C);
B := B shl 24 or B shr 8;
A := A xor Mars_Data[B shr 24 + 256];
Dec(D, Mars_Data[B shr 16 and $FF]);
C := C - Mars_Data[B shr 8 and $FF + 256] xor Mars_Data[B and $FF];
Dec(A, D);
A := A shl 24 or A shr 8;
D := D xor Mars_Data[A shr 24 + 256];
Dec(C, Mars_Data[A shr 16 and $FF]);
B := B - Mars_Data[A shr 8 and $FF + 256] xor Mars_Data[A and $FF];
end;
PUInt32Array(Dest)[0] := A - K[4];
PUInt32Array(Dest)[1] := B - K[5];
PUInt32Array(Dest)[2] := C - K[6];
PUInt32Array(Dest)[3] := D - K[7];
end;
{ TCipher_RC4 }
class function TCipher_RC4.Context: TCipherContext;
begin
Result.KeySize := 256;
Result.BlockSize := 1;
Result.BufferSize := 16;
Result.AdditionalBufferSize := 256 + 2;
Result.NeedsAdditionalBufferBackup := true;
Result.MinRounds := 1;
Result.MaxRounds := 1;
Result.CipherType := [ctSymmetric, ctStream];
end;
procedure TCipher_RC4.DoInit(const Key; Size: Integer);
var
K: array[0..255] of Byte;
D: PByteArray;
I, J, T: Byte;
begin
D := FAdditionalBuffer;
for I := 0 to 255 do
begin
D[I] := I;
if Size > 0 then
K[I] := TByteArray(Key)[I mod Size];
end;
J := 0;
for I := 0 to 255 do
begin
J := J + D[I] + K[I];
T := D[I];
D[I] := D[J];
D[J] := T;
end;
D[256] := 0;
D[257] := 0;
ProtectBuffer(K, SizeOf(K));
end;
procedure TCipher_RC4.DoEncode(Source, Dest: Pointer; Size: Integer);
var
D: PByteArray;
S: Integer;
T, I, J: Byte;
begin
D := FAdditionalBuffer;
I := D[256];
J := D[257];
for S := 0 to Size - 1 do
begin
Inc(I);
T := D[I];
Inc(J, T);
D[I] := D[J];
D[J] := T;
PByteArray(Dest)[S] := PByteArray(Source)[S] xor D[Byte(D[I] + T)];
end;
D[256] := I;
D[257] := J;
end;
procedure TCipher_RC4.DoDecode(Source, Dest: Pointer; Size: Integer);
begin
DoEncode(Source, Dest, Size);
end;
{ TCipher_RC6 }
class function TCipher_RC6.Context: TCipherContext;
begin
Result.KeySize := 256;
Result.BlockSize := 16;
Result.BufferSize := 16;
Result.AdditionalBufferSize := 272;
Result.NeedsAdditionalBufferBackup := False;
Result.MinRounds := 16;
Result.MaxRounds := 24;
Result.CipherType := [ctSymmetric, ctBlock];
end;
procedure TCipher_RC6.SetRounds(Value: Integer);
begin
if Value < Context.MinRounds then
Value := Context.MinRounds
else
if Value > Context.MaxRounds then
Value := Context.MaxRounds;
if Value <> FRounds then
begin
if not (FState in [csNew, csInitialized, csDone]) then
Done;
FRounds := Value;
end;
end;
procedure TCipher_RC6.DoInit(const Key; Size: Integer);
var
K: array[0..63] of UInt32;
D: PUInt32Array;
I, J, L, A, B, Z, T: UInt32;
begin
LimitRounds;
D := FAdditionalBuffer;
FillChar(K, SizeOf(K), 0);
Move(Key, K, Size);
L := Size shr 2;
if Size and 3 <> 0 then
Inc(L);
if L <= 0 then
L := 1;
J := $B7E15163;
for I := 0 to (FRounds + 2) * 2 do
begin
D[I] := J;
Inc(J, $9E3779B9);
end;
if L > UInt32(FRounds + 2) * 2 then
Z := L * 3
else
Z := (FRounds + 2) * 6;
I := 0;
J := 0;
A := 0;
B := 0;
for Z := Z downto 1 do
begin
A := A + B + D[I];
A := A shl 3 or A shr 29;
D[I] := A;
T := A + B;
B := T + K[J];
B := B shl T or B shr (32 - T);
K[J] := B;
I := (I + 1) mod (UInt32(FRounds + 2) * 2);
J := (J + 1) mod L;
end;
ProtectBuffer(K, SizeOf(K));
end;
procedure TCipher_RC6.LimitRounds;
begin
if FRounds = 0 then
FRounds := 20
else
if FRounds < 16 then
FRounds := 16
else
if FRounds > 24 then
FRounds := 24;
end;
procedure TCipher_RC6.DoEncode(Source, Dest: Pointer; Size: Integer);
{$IFDEF X86ASM}
asm
PUSH EBX
PUSH ESI
PUSH EDI
PUSH EBP
PUSH ECX
MOV EBP,[EAX].TCipher_RC6.FRounds // Rounds
MOV ESI,[EAX].TCipher_RC6.FAdditionalBuffer // Key
MOV EAX,[EDX + 0] // A
MOV EBX,[EDX + 4] // B
MOV EDI,[EDX + 8] // C
MOV EDX,[EDX + 12] // D
ADD EBX,[ESI + 0] // Inc(B, K[0])
ADD EDX,[ESI + 4] // Inc(D, K[1])
ADD ESI,8 // Inc(PInteger(K), 2)
@@1: LEA ECX,[EBX * 2 + 1] // ECX := B * 2 + 1
IMUL ECX,EBX // ECX := ECX * B
ROL ECX,5 // T := ROL(B * (B * 2 + 1), 5)
PUSH ECX // save T
XOR EAX,ECX // A := A xor T
LEA ECX,[EDX * 2 + 1] // ECX := D * 2 + 1
IMUL ECX,EDX // ECX := ECX * D
ROL ECX,5 // U := ROL(D * (D * 2 + 1), 5)
XOR EDI,ECX // C := C xor U
ROL EAX,CL // A := ROL(A xor T, U)
POP ECX // restore T
ADD EAX,[ESI + 0] // Inc(A, K[0])
ROL EDI,CL // C := ROL(C xor U, T)
MOV ECX,EAX // T := A
ADD EDI,[ESI + 4] // Inc(C, K[1])
MOV EAX,EBX // A := B
MOV EBX,EDI // B := C
MOV EDI,EDX // C := D
DEC EBP
MOV EDX,ECX // D := T;
LEA ESI,[ESI + 8] // Inc(PInteger(K), 2)
JNZ @@1
ADD EAX,[ESI + 0] // Inc(A, K[0])
ADD EDI,[ESI + 4] // Inc(C, K[1])
POP ECX
MOV [ECX + 0],EAX // A
MOV [ECX + 4],EBX // B
MOV [ECX + 8],EDI // C
MOV [ECX + 12],EDX // D
POP EBP
POP EDI
POP ESI
POP EBX
end;
{$ELSE !X86ASM}
var
K: PUInt32Array;
I, T, U, A, B, C, D: UInt32;
begin
Assert(Size = Context.BlockSize);
K := Pointer(FAdditionalBuffer);
A := PUInt32Array(Source)[0];
B := PUInt32Array(Source)[1] + K[0];
C := PUInt32Array(Source)[2];
D := PUInt32Array(Source)[3] + K[1];
for I := 1 to FRounds do
begin
K := @K[2];
T := B * (B + B + 1);
T := T shl 5 or T shr 27;
U := D * (D + D + 1);
U := U shl 5 or U shr 27;
A := A xor T;
A := A shl U or A shr (32 - U) + K[0];
C := C xor U;
C := C shl T or C shr (32 - T) + K[1];
T := A; A := B; B := C; C := D; D := T;
end;
PUInt32Array(Dest)[0] := A + K[2];
PUInt32Array(Dest)[1] := B;
PUInt32Array(Dest)[2] := C + K[3];
PUInt32Array(Dest)[3] := D;
end;
{$ENDIF !X86ASM}
procedure TCipher_RC6.DoDecode(Source, Dest: Pointer; Size: Integer);
{$IFDEF X86ASM}
asm
PUSH EBX
PUSH ESI
PUSH EDI
PUSH EBP
PUSH ECX
MOV EBP,[EAX].TCipher_RC6.FRounds // Rounds
MOV ESI,[EAX].TCipher_RC6.FAdditionalBuffer // Key
LEA ESI,[ESI + EBP * 8] // Key[FRounds * 2]
MOV EAX,[EDX + 0] // A
MOV EBX,[EDX + 4] // B
MOV EDI,[EDX + 8] // C
MOV EDX,[EDX + 12] // D
SUB EDI,[ESI + 12] // Dec(C, K[3])
SUB EAX,[ESI + 8] // Dec(A, K[2])
@@1: MOV ECX,EAX // T := A
SUB EDX,[ESI + 0] // Dec(A, K[0])
MOV EAX,EDX // A := D
MOV EDX,EDI // D := C
SUB EBX,[ESI + 4] // Dec(C, K[1])
MOV EDI,EBX // C := B
MOV EBX,ECX // B := T;
LEA ECX,[EDX * 2 + 1] // ECX := D * 2 + 1
IMUL ECX,EDX // ECX := ECX * D
ROL ECX,5 // U := ROL(D * (D * 2 + 1), 5)
PUSH ECX // save U
ROR EAX,CL // A := ROR(A - K[0], U)
LEA ECX,[EBX * 2 + 1] // ECX := B * 2 + 1
IMUL ECX,EBX // ECX := ECX * B
ROL ECX,5 // T := ROL(B * (B * 2 + 1), 5)
XOR EAX,ECX // A := A xor T
ROR EDI,CL // C := ROR(C - K[1], T)
POP ECX // restore U
XOR EDI,ECX // C := C xor U
DEC EBP
LEA ESI,[ESI - 8] // Dec(PInteger(K), 2)
JNZ @@1
SUB EBX,[ESI + 0] // Dec(B, K[0])
SUB EDX,[ESI + 4] // Inc(D, K[1])
POP ECX
MOV [ECX + 0],EAX // A
MOV [ECX + 4],EBX // B
MOV [ECX + 8],EDI // C
MOV [ECX + 12],EDX // D
POP EBP
POP EDI
POP ESI
POP EBX
end;
{$ELSE !X86ASM}
var
I, U, T, A, B, C, D: UInt32;
K: PUInt32Array;
begin
Assert(Size = Context.BlockSize);
K := @PUInt32Array(FAdditionalBuffer)[FRounds * 2];
A := PUInt32Array(Source)[0] - K[2];
B := PUInt32Array(Source)[1];
C := PUInt32Array(Source)[2] - K[3];
D := PUInt32Array(Source)[3];
for I := 1 to FRounds do
begin
T := A; A := D; D := C; C := B; B := T;
U := D * (D + D + 1);
U := U shl 5 or U shr 27;
T := B * (B + B + 1);
T := T shl 5 or T shr 27;
C := C - K[1];
C := C shr T or C shl (32 - T) xor U;
A := A - K[0];
A := A shr U or A shl (32 - U) xor T;
Dec(PUInt32(K), 2);
end;
PUInt32Array(Dest)[0] := A;
PUInt32Array(Dest)[1] := B - K[0];
PUInt32Array(Dest)[2] := C;
PUInt32Array(Dest)[3] := D - K[1];
end;
{$ENDIF !X86ASM}
{ TCipher_Rijndael }
class function TCipher_Rijndael.Context: TCipherContext;
const
// don't change this!
Rijndael_Blocks = 4;
Rijndael_Rounds = 14;
begin
Result.KeySize := 32;
Result.BlockSize := Rijndael_Blocks * 4;
Result.BufferSize := Rijndael_Blocks * 4;
Result.AdditionalBufferSize := (Rijndael_Rounds + 1) * Rijndael_Blocks * SizeOf(UInt32) * 2;
Result.NeedsAdditionalBufferBackup := False;
Result.MinRounds := 1;
Result.MaxRounds := 1;
Result.CipherType := [ctSymmetric, ctBlock];
end;
procedure TCipher_Rijndael.DoInit(const Key; Size: Integer);
{$REGION OldKeyShedule}
{
// Old Rijndael Key Scheduling:
procedure BuildEncodeKey;
const
RND_Data: array[0..29] of Byte = (
$01, $02, $04, $08, $10, $20, $40, $80, $1B, $36, $6C, $D8, $AB, $4D, $9A,
$2F, $5E, $BC, $63, $C6, $97, $35, $6A, $D4, $B3, $7D, $FA, $EF, $C5, $91
);
var
T, R: Integer;
procedure NextRounds;
var
J: Integer;
begin
J := 0;
while (J < FRounds - 6) and (R <= FRounds) do
begin
while (J < FRounds - 6) and (T < Rijndael_Blocks) do
begin
PUInt32Array(FBuffer)[R * Rijndael_Blocks + T] := K[J];
Inc(J);
Inc(T);
end;
if T = Rijndael_Blocks then
begin
T := 0;
Inc(R);
end;
end;
end;
var
RND: PByte;
B: PByte;
I: Integer;
begin
R := 0;
T := 0;
RND := @RND_Data;
NextRounds;
while R <= FRounds do
begin
B := @K;
B^ := B^ xor Rijndael_S[0, K[FRounds - 7] shr 8 and $FF] xor RND^; Inc(B);
B^ := B^ xor Rijndael_S[0, K[FRounds - 7] shr 16 and $FF]; Inc(B);
B^ := B^ xor Rijndael_S[0, K[FRounds - 7] shr 24]; Inc(B);
B^ := B^ xor Rijndael_S[0, K[FRounds - 7] and $FF];
Inc(RND);
if FRounds = 14 then
begin
for I := 1 to 7 do
K[I] := K[I] xor K[I - 1];
B := @K[4];
B^ := B^ xor Rijndael_S[0, K[3] and $FF]; Inc(B);
B^ := B^ xor Rijndael_S[0, K[3] shr 8 and $FF]; Inc(B);
B^ := B^ xor Rijndael_S[0, K[3] shr 16 and $FF]; Inc(B);
B^ := B^ xor Rijndael_S[0, K[3] shr 24];
for I := 5 to 7 do
K[I] := K[I] xor K[I - 1];
end
else
for I := 1 to FRounds - 7 do
K[I] := K[I] xor K[I - 1];
NextRounds;
end;
end;
procedure BuildDecodeKey;
var
I: Integer;
D: PUInt32;
begin
D := Pointer(PAnsiChar(FBuffer) + FBufferSize shr 1); // for Pointer Math
Move(FBuffer^, D^, FBufferSize shr 1);
Inc(D, 4);
for I := 0 to FRounds * 4 - 5 do
begin
D^ := Rijndael_Key[D^ and $FF] xor
(Rijndael_Key[D^ shr 8 and $FF] shl 8 or Rijndael_Key[D^ shr 8 and $FF] shr 24) xor
(Rijndael_Key[D^ shr 16 and $FF] shl 16 or Rijndael_Key[D^ shr 16 and $FF] shr 16) xor
(Rijndael_Key[D^ shr 24] shl 24 or Rijndael_Key[D^ shr 24] shr 8);
Inc(D);
end;
end; }
{$ENDREGION}
// New AES conform Key Scheduling
procedure BuildEncodeKey;
const
RCon: array[0..9] of UInt32 = ($01, $02, $04, $08, $10, $20, $40, $80, $1b, $36);
var
I: Integer;
T: UInt32;
P: PUInt32Array;
begin
P := FAdditionalBuffer;
if Size <= 16 then
begin
for I := 0 to 9 do
begin
T := P[3];
P[4] := Rijndael_S[0, T shr 8 and $FF] xor
Rijndael_S[0, T shr 16 and $FF] shl 8 xor
Rijndael_S[0, T shr 24 ] shl 16 xor
Rijndael_S[0, T and $FF] shl 24 xor P[0] xor RCon[I];
P[5] := P[1] xor P[4];
P[6] := P[2] xor P[5];
P[7] := P[3] xor P[6];
P := @P[4];
end;
end
else
if Size <= 24 then
begin
for I := 0 to 7 do
begin
T := P[5];
P[6] := Rijndael_S[0, T shr 8 and $FF] xor
Rijndael_S[0, T shr 16 and $FF] shl 8 xor
Rijndael_S[0, T shr 24 ] shl 16 xor
Rijndael_S[0, T and $FF] shl 24 xor P[0] xor RCon[I];
P[7] := P[1] xor P[6];
P[8] := P[2] xor P[7];
P[9] := P[3] xor P[8];
if I = 7 then
Break;
P[10] := P[4] xor P[9];
P[11] := P[5] xor P[10];
P := @P[6];
end;
end
else
begin
for I :=0 to 6 do
begin
T := P[7];
P[8] := Rijndael_S[0, T shr 8 and $FF] xor
Rijndael_S[0, T shr 16 and $FF] shl 8 xor
Rijndael_S[0, T shr 24 ] shl 16 xor
Rijndael_S[0, T and $FF] shl 24 xor P[0] xor RCon[I];
P[9] := P[1] xor P[8];
P[10] := P[2] xor P[9];
P[11] := P[3] xor P[10];
if I = 6 then
Break;
T := P[11];
P[12] := Rijndael_S[0, T and $FF] xor
Rijndael_S[0, T shr 8 and $FF] shl 8 xor
Rijndael_S[0, T shr 16 and $FF] shl 16 xor
Rijndael_S[0, T shr 24 ] shl 24 xor P[4];
P[13] := P[5] xor P[12];
P[14] := P[6] xor P[13];
P[15] := P[7] xor P[14];
P := @P[8];
end;
end;
end;
procedure BuildDecodeKey;
var
P: PUInt32;
I: Integer;
begin
P := Pointer(PByte(FAdditionalBuffer) + FAdditionalBufferSize shr 1); // for Pointer Math
Move(FAdditionalBuffer^, P^, FAdditionalBufferSize shr 1);
Inc(P, 4);
for I := 0 to FRounds * 4 - 5 do
begin
P^ := Rijndael_T[4, Rijndael_S[0, P^ and $FF]] xor
Rijndael_T[5, Rijndael_S[0, P^ shr 8 and $FF]] xor
Rijndael_T[6, Rijndael_S[0, P^ shr 16 and $FF]] xor
Rijndael_T[7, Rijndael_S[0, P^ shr 24 ]];
Inc(P);
end;
end;
begin
if Size <= 16 then
FRounds := 10
else
if Size <= 24 then
FRounds := 12
else
FRounds := 14;
FillChar(FAdditionalBuffer^, 32, 0);
Move(Key, FAdditionalBuffer^, Size);
BuildEncodeKey;
BuildDecodeKey;
end;
procedure TCipher_Rijndael.DoEncode(Source, Dest: Pointer; Size: Integer);
var
P: PUInt32Array;
I: Integer;
A2, B2, C2, D2: UInt32;
A1, B1, C1, D1: UInt32;
begin
Assert(Size = Context.BlockSize);
P := FAdditionalBuffer;
A1 := PUInt32Array(Source)[0];
B1 := PUInt32Array(Source)[1];
C1 := PUInt32Array(Source)[2];
D1 := PUInt32Array(Source)[3];
for I := 2 to FRounds do
begin
A2 := A1 xor P[0];
B2 := B1 xor P[1];
C2 := C1 xor P[2];
D2 := D1 xor P[3];
A1 := Rijndael_T[0, A2 and $FF] xor
Rijndael_T[1, B2 shr 8 and $FF] xor
Rijndael_T[2, C2 shr 16 and $FF] xor
Rijndael_T[3, D2 shr 24 ];
B1 := Rijndael_T[0, B2 and $FF] xor
Rijndael_T[1, C2 shr 8 and $FF] xor
Rijndael_T[2, D2 shr 16 and $FF] xor
Rijndael_T[3, A2 shr 24 ];
C1 := Rijndael_T[0, C2 and $FF] xor
Rijndael_T[1, D2 shr 8 and $FF] xor
Rijndael_T[2, A2 shr 16 and $FF] xor
Rijndael_T[3, B2 shr 24 ];
D1 := Rijndael_T[0, D2 and $FF] xor
Rijndael_T[1, A2 shr 8 and $FF] xor
Rijndael_T[2, B2 shr 16 and $FF] xor
Rijndael_T[3, C2 shr 24 ];
P := @P[4];
end;
A2 := A1 xor P[0];
B2 := B1 xor P[1];
C2 := C1 xor P[2];
D2 := D1 xor P[3];
PUInt32Array(Dest)[0] := (Rijndael_S[0, A2 and $FF] or
Rijndael_S[0, B2 shr 8 and $FF] shl 8 or
Rijndael_S[0, C2 shr 16 and $FF] shl 16 or
Rijndael_S[0, D2 shr 24 ] shl 24) xor P[4];
PUInt32Array(Dest)[1] := (Rijndael_S[0, B2 and $FF] or
Rijndael_S[0, C2 shr 8 and $FF] shl 8 or
Rijndael_S[0, D2 shr 16 and $FF] shl 16 or
Rijndael_S[0, A2 shr 24 ] shl 24) xor P[5];
PUInt32Array(Dest)[2] := (Rijndael_S[0, C2 and $FF] or
Rijndael_S[0, D2 shr 8 and $FF] shl 8 or
Rijndael_S[0, A2 shr 16 and $FF] shl 16 or
Rijndael_S[0, B2 shr 24 ] shl 24) xor P[6];
PUInt32Array(Dest)[3] := (Rijndael_S[0, D2 and $FF] or
Rijndael_S[0, A2 shr 8 and $FF] shl 8 or
Rijndael_S[0, B2 shr 16 and $FF] shl 16 or
Rijndael_S[0, C2 shr 24 ] shl 24) xor P[7];
end;
procedure TCipher_Rijndael.DoDecode(Source, Dest: Pointer; Size: Integer);
var
P: PUInt32Array;
I: Integer;
A2, B2, C2, D2: UInt32;
A1, B1, C1, D1: UInt32;
begin
Assert(Size = Context.BlockSize);
P := Pointer(PByte(FAdditionalBuffer) + FAdditionalBufferSize shr 1 + FRounds * 16); // for Pointer Math
A1 := PUInt32Array(Source)[0];
B1 := PUInt32Array(Source)[1];
C1 := PUInt32Array(Source)[2];
D1 := PUInt32Array(Source)[3];
for I := 2 to FRounds do
begin
A2 := A1 xor P[0];
B2 := B1 xor P[1];
C2 := C1 xor P[2];
D2 := D1 xor P[3];
A1 := Rijndael_T[4, A2 and $FF] xor
Rijndael_T[5, D2 shr 8 and $FF] xor
Rijndael_T[6, C2 shr 16 and $FF] xor
Rijndael_T[7, B2 shr 24 ];
B1 := Rijndael_T[4, B2 and $FF] xor
Rijndael_T[5, A2 shr 8 and $FF] xor
Rijndael_T[6, D2 shr 16 and $FF] xor
Rijndael_T[7, C2 shr 24 ];
C1 := Rijndael_T[4, C2 and $FF] xor
Rijndael_T[5, B2 shr 8 and $FF] xor
Rijndael_T[6, A2 shr 16 and $FF] xor
Rijndael_T[7, D2 shr 24 ];
D1 := Rijndael_T[4, D2 and $FF] xor
Rijndael_T[5, C2 shr 8 and $FF] xor
Rijndael_T[6, B2 shr 16 and $FF] xor
Rijndael_T[7, A2 shr 24 ];
Dec(PUInt32(P), 4);
end;
A2 := A1 xor P[0];
B2 := B1 xor P[1];
C2 := C1 xor P[2];
D2 := D1 xor P[3];
Dec(PUInt32(P), 4);
PUInt32Array(Dest)[0] := (Rijndael_S[1, A2 and $FF] or
Rijndael_S[1, D2 shr 8 and $FF] shl 8 or
Rijndael_S[1, C2 shr 16 and $FF] shl 16 or
Rijndael_S[1, B2 shr 24] shl 24) xor P[0];
PUInt32Array(Dest)[1] := (Rijndael_S[1, B2 and $FF] or
Rijndael_S[1, A2 shr 8 and $FF] shl 8 or
Rijndael_S[1, D2 shr 16 and $FF] shl 16 or
Rijndael_S[1, C2 shr 24] shl 24) xor P[1];
PUInt32Array(Dest)[2] := (Rijndael_S[1, C2 and $FF] or
Rijndael_S[1, B2 shr 8 and $FF] shl 8 or
Rijndael_S[1, A2 shr 16 and $FF] shl 16 or
Rijndael_S[1, D2 shr 24] shl 24) xor P[2];
PUInt32Array(Dest)[3] := (Rijndael_S[1, D2 and $FF] or
Rijndael_S[1, C2 shr 8 and $FF] shl 8 or
Rijndael_S[1, B2 shr 16 and $FF] shl 16 or
Rijndael_S[1, A2 shr 24] shl 24) xor P[3];
end;
{ TCipher_Square }
class function TCipher_Square.Context: TCipherContext;
begin
Result.KeySize := 16;
Result.BlockSize := 16;
Result.BufferSize := 16;
Result.AdditionalBufferSize := 9 * 4 * 2 * SizeOf(UInt32);
Result.NeedsAdditionalBufferBackup := False;
Result.MinRounds := 1;
Result.MaxRounds := 1;
Result.CipherType := [ctSymmetric, ctBlock];
end;
procedure TCipher_Square.DoInit(const Key; Size: Integer);
type
PSquare_Key = ^TSquare_Key;
TSquare_Key = array[0..8, 0..3] of UInt32;
var
E, D: PSquare_Key;
S, T, R: UInt32;
I, J: Integer;
begin
E := FAdditionalBuffer;
D := FAdditionalBuffer; Inc(D);
Move(Key, E^, Size);
for I := 1 to 8 do
begin
T := E[I - 1, 3];
T := T shr 8 or T shl 24;
E[I, 0] := E[I - 1, 0] xor T xor 1 shl (I - 1);
E[I, 1] := E[I - 1, 1] xor E[I, 0];
E[I, 2] := E[I - 1, 2] xor E[I, 1];
E[I, 3] := E[I - 1, 3] xor E[I, 2];
D[8 - I, 0] := E[I, 0];
D[8 - I, 1] := E[I, 1];
D[8 - I, 2] := E[I, 2];
D[8 - I, 3] := E[I, 3];
for J := 0 to 3 do
begin
R := E[I - 1, J];
S := Square_PHI[R and $FF];
T := Square_PHI[R shr 8 and $FF];
T := T shl 8 or T shr 24;
S := S xor T;
T := Square_PHI[R shr 16 and $FF];
T := T shl 16 or T shr 16;
S := S xor T;
T := Square_PHI[R shr 24];
T := T shl 24 or T shr 8;
S := S xor T;
E[I - 1, J] := S;
end;
end;
D[8] := E[0];
end;
procedure TCipher_Square.DoEncode(Source, Dest: Pointer; Size: Integer);
var
Key: PUInt32Array;
A, B, C, D: UInt32;
AA, BB, CC: UInt32;
I: Integer;
begin
Key := FAdditionalBuffer;
A := PUInt32Array(Source)[0] xor Key[0];
B := PUInt32Array(Source)[1] xor Key[1];
C := PUInt32Array(Source)[2] xor Key[2];
D := PUInt32Array(Source)[3] xor Key[3];
Key := @Key[4];
for I := 0 to 6 do
begin
AA := Square_TE[0, A and $FF] xor
Square_TE[1, B and $FF] xor
Square_TE[2, C and $FF] xor
Square_TE[3, D and $FF] xor Key[0];
BB := Square_TE[0, A shr 8 and $FF] xor
Square_TE[1, B shr 8 and $FF] xor
Square_TE[2, C shr 8 and $FF] xor
Square_TE[3, D shr 8 and $FF] xor Key[1];
CC := Square_TE[0, A shr 16 and $FF] xor
Square_TE[1, B shr 16 and $FF] xor
Square_TE[2, C shr 16 and $FF] xor
Square_TE[3, D shr 16 and $FF] xor Key[2];
D := Square_TE[0, A shr 24 ] xor
Square_TE[1, B shr 24 ] xor
Square_TE[2, C shr 24 ] xor
Square_TE[3, D shr 24 ] xor Key[3];
A := AA; B := BB; C := CC;
Key := @Key[4];
end;
PUInt32Array(Dest)[0] := UInt32(Square_SE[A and $FF]) xor
UInt32(Square_SE[B and $FF]) shl 8 xor
UInt32(Square_SE[C and $FF]) shl 16 xor
UInt32(Square_SE[D and $FF]) shl 24 xor Key[0];
PUInt32Array(Dest)[1] := UInt32(Square_SE[A shr 8 and $FF]) xor
UInt32(Square_SE[B shr 8 and $FF]) shl 8 xor
UInt32(Square_SE[C shr 8 and $FF]) shl 16 xor
UInt32(Square_SE[D shr 8 and $FF]) shl 24 xor Key[1];
PUInt32Array(Dest)[2] := UInt32(Square_SE[A shr 16 and $FF]) xor
UInt32(Square_SE[B shr 16 and $FF]) shl 8 xor
UInt32(Square_SE[C shr 16 and $FF]) shl 16 xor
UInt32(Square_SE[D shr 16 and $FF]) shl 24 xor Key[2];
PUInt32Array(Dest)[3] := UInt32(Square_SE[A shr 24 ]) xor
UInt32(Square_SE[B shr 24 ]) shl 8 xor
UInt32(Square_SE[C shr 24 ]) shl 16 xor
UInt32(Square_SE[D shr 24 ]) shl 24 xor Key[3];
end;
procedure TCipher_Square.DoDecode(Source, Dest: Pointer; Size: Integer);
var
Key: PUInt32Array;
A, B, C, D: UInt32;
AA, BB, CC: UInt32;
I: Integer;
begin
Key := @PUInt32Array(FAdditionalBuffer)[9 * 4];
A := PUInt32Array(Source)[0] xor Key[0];
B := PUInt32Array(Source)[1] xor Key[1];
C := PUInt32Array(Source)[2] xor Key[2];
D := PUInt32Array(Source)[3] xor Key[3];
Key := @Key[4];
for I := 0 to 6 do
begin
AA := Square_TD[0, A and $FF] xor
Square_TD[1, B and $FF] xor
Square_TD[2, C and $FF] xor
Square_TD[3, D and $FF] xor Key[0];
BB := Square_TD[0, A shr 8 and $FF] xor
Square_TD[1, B shr 8 and $FF] xor
Square_TD[2, C shr 8 and $FF] xor
Square_TD[3, D shr 8 and $FF] xor Key[1];
CC := Square_TD[0, A shr 16 and $FF] xor
Square_TD[1, B shr 16 and $FF] xor
Square_TD[2, C shr 16 and $FF] xor
Square_TD[3, D shr 16 and $FF] xor Key[2];
D := Square_TD[0, A shr 24 ] xor
Square_TD[1, B shr 24 ] xor
Square_TD[2, C shr 24 ] xor
Square_TD[3, D shr 24 ] xor Key[3];
A := AA; B := BB; C := CC;
Key := @Key[4];
end;
PUInt32Array(Dest)[0] := UInt32(Square_SD[A and $FF]) xor
UInt32(Square_SD[B and $FF]) shl 8 xor
UInt32(Square_SD[C and $FF]) shl 16 xor
UInt32(Square_SD[D and $FF]) shl 24 xor Key[0];
PUInt32Array(Dest)[1] := UInt32(Square_SD[A shr 8 and $FF]) xor
UInt32(Square_SD[B shr 8 and $FF]) shl 8 xor
UInt32(Square_SD[C shr 8 and $FF]) shl 16 xor
UInt32(Square_SD[D shr 8 and $FF]) shl 24 xor Key[1];
PUInt32Array(Dest)[2] := UInt32(Square_SD[A shr 16 and $FF]) xor
UInt32(Square_SD[B shr 16 and $FF]) shl 8 xor
UInt32(Square_SD[C shr 16 and $FF]) shl 16 xor
UInt32(Square_SD[D shr 16 and $FF]) shl 24 xor Key[2];
PUInt32Array(Dest)[3] := UInt32(Square_SD[A shr 24 ]) xor
UInt32(Square_SD[B shr 24 ]) shl 8 xor
UInt32(Square_SD[C shr 24 ]) shl 16 xor
UInt32(Square_SD[D shr 24 ]) shl 24 xor Key[3];
end;
{ TCipher_SCOP }
class function TCipher_SCOP.Context: TCipherContext;
begin
Result.KeySize := 48;
Result.BlockSize := 4;
Result.BufferSize := 32;
Result.AdditionalBufferSize := 384 * 4 + 3 * SizeOf(UInt32);
Result.NeedsAdditionalBufferBackup := True;
Result.MinRounds := 1;
Result.MaxRounds := 1;
Result.CipherType := [ctSymmetric, ctStream];
end;
procedure TCipher_SCOP.DoInit(const Key; Size: Integer);
var
Init_State: packed record
Coef: array[0..7, 0..3] of Byte;
X: array[0..3] of UInt32;
end;
procedure ExpandKey;
var
P: PByteArray;
I, C: Integer;
begin
C := 1;
P := @Init_State;
Move(Key, P^, Size);
for I := Size to 47 do
P[I] := P[I - Size] + P[I - Size + 1];
for I := 0 to 31 do
if P[I] = 0 then
begin
P[I] := C;
Inc(C);
end;
end;
procedure GP8(Data: PUInt32Array);
var
I, I2: Integer;
NewX: array[0..3] of UInt32;
X1, X2, X3, X4: UInt32;
Y1, Y2: UInt32;
begin
I := 0;
I2 := 0;
while I < 8 do
begin
X1 := Init_State.X[I2] shr 16;
X2 := X1 * X1;
X3 := X2 * X1;
X4 := X3 * X1;
Y1 := Init_State.Coef[I][0] * X4 +
Init_State.Coef[I][1] * X3 +
Init_State.Coef[I][2] * X2 +
Init_State.Coef[I][3] * X1 + 1;
X1 := Init_State.X[I2] and $FFFF;
X2 := X1 * X1;
X3 := X2 * X1;
X4 := X3 * X1;
Y2 := Init_State.Coef[I + 1][0] * X4 +
Init_State.Coef[I + 1][1] * X3 +
Init_State.Coef[I + 1][2] * X2 +
Init_State.Coef[I + 1][3] * X1 + 1;
Data[I2] := Y1 shl 16 or Y2 and $FFFF;
NewX[I2] := Y1 and $FFFF0000 or Y2 shr 16;
Inc(I2);
Inc(I, 2);
end;
Init_State.X[0] := NewX[0] shr 16 or NewX[3] shl 16;
Init_State.X[1] := NewX[0] shl 16 or NewX[1] shr 16;
Init_State.X[2] := NewX[1] shl 16 or NewX[2] shr 16;
Init_State.X[3] := NewX[2] shl 16 or NewX[3] shr 16;
end;
var
I, J: Integer;
T: array[0..3] of UInt32;
P: PUInt32Array;
begin
FillChar(Init_State, SizeOf(Init_State), 0);
FillChar(T, SizeOf(T), 0);
P := Pointer(PByte(FAdditionalBuffer) + 12); // for Pointer Math
ExpandKey;
for I := 0 to 7 do
GP8(@T);
for I := 0 to 11 do
begin
for J := 0 to 7 do
GP8(@P[I * 32 + J * 4]);
GP8(@T);
end;
GP8(@T);
I := T[3] and $7F;
P[I] := P[I] or 1;
P := FAdditionalBuffer;
P[0] := T[3] shr 24 and $FF;
P[1] := T[3] shr 16 and $FF;
P[2] := T[3] shr 8 and $FF;
ProtectBuffer(Init_State, SizeOf(Init_State));
end;
procedure TCipher_SCOP.DoEncode(Source, Dest: Pointer; Size: Integer);
var
I, J: Byte;
T2, T3, T1: UInt32;
P: PUInt32Array;
W: Integer;
begin
P := FAdditionalBuffer;
I := P[0];
J := P[1];
T3 := P[2];
for W := 0 to Size div 4 - 1 do
begin
T1 := P[J + 3 + 128]; Inc(J, T3);
T2 := P[J + 3 + 128];
PUInt32Array(Dest)[W] := PUInt32Array(Source)[W] + T1 + T2;
T3 := T2 + P[I + 3]; Inc(I);
P[J + 3 + 128] := T3;
Inc(J, T2);
end;
P[0] := I;
P[1] := J;
P[2] := T3;
end;
procedure TCipher_SCOP.DoDecode(Source, Dest: Pointer; Size: Integer);
var
I, J: Byte;
T1, T2, T3: UInt32;
P: PUInt32Array;
W: Integer;
begin
P := FAdditionalBuffer;
I := P[0];
J := P[1];
T3 := P[2];
for W := 0 to Size div 4 - 1 do
begin
T1 := P[J + 3 + 128]; Inc(J, T3);
T2 := P[J + 3 + 128];
PUInt32Array(Dest)[W] := PUInt32Array(Source)[W] - T1 - T2;
T3 := T2 + P[I + 3];
Inc(I);
P[J + 3 + 128] := T3;
Inc(J, T2);
end;
P[0] := I;
P[1] := J;
P[2] := T3;
end;
{ TCipher_SCOP_DEC52 }
{ TODO : The old failure needs to be restored again }
class function TCipher_SCOP_DEC52.Context: TCipherContext;
begin
Result.KeySize := 48;
Result.BlockSize := 4;
Result.BufferSize := 32;
Result.AdditionalBufferSize := 384 * 4 + 3 * SizeOf(UInt32);
Result.NeedsAdditionalBufferBackup := True;
Result.MinRounds := 1;
Result.MaxRounds := 1;
Result.CipherType := [ctSymmetric, ctStream];
end;
procedure TCipher_SCOP_DEC52.DoInit(const Key; Size: Integer);
var
Init_State: packed record
Coef: array[0..7, 0..3] of Byte;
X: array[0..3] of UInt32;
end;
procedure ExpandKey;
var
P: PByteArray;
I, C: Integer;
begin
C := 1;
P := @Init_State;
Move(Key, P^, Size);
for I := Size to 47 do
P[I] := P[I - Size] + P[I - Size + 1];
for I := 0 to 31 do
if P[I] = 0 then
begin
P[I] := C;
Inc(C);
end;
end;
procedure GP8(Data: PUInt32Array);
var
I, I2: Integer;
NewX: array[0..3] of UInt32;
X1, X2, X3, X4: UInt32;
Y1, Y2: UInt32;
begin
I := 0;
I2 := 0;
while I < 8 do
begin
X1 := Init_State.X[I2] shr 16;
X2 := X1 * X1;
X3 := X2 * X1;
X4 := X3 * X1;
Y1 := Init_State.Coef[I][0] * X4 +
Init_State.Coef[I][1] * X3 +
Init_State.Coef[I][2] * X2 +
Init_State.Coef[I][3] * X1 + 1;
X1 := Init_State.X[I2] and $FFFF;
X2 := X1 * X1;
X3 := X2 * X1;
X4 := X3 * X1;
Y2 := Init_State.Coef[I + 1][0] * X4 +
Init_State.Coef[I + 2][1] * X3 +
Init_State.Coef[I + 3][2] * X2 +
Init_State.Coef[I + 4][3] * X1 + 1;
Data[I2] := Y1 shl 16 or Y2 and $FFFF;
NewX[I2] := Y1 and $FFFF0000 or Y2 shr 16;
Inc(I2);
Inc(I, 2);
end;
Init_State.X[0] := NewX[0] shr 16 or NewX[3] shl 16;
Init_State.X[1] := NewX[0] shl 16 or NewX[1] shr 16;
Init_State.X[2] := NewX[1] shl 16 or NewX[2] shr 16;
Init_State.X[3] := NewX[2] shl 16 or NewX[3] shr 16;
end;
var
I, J: Integer;
T: array[0..3] of Integer;
P: PUInt32Array;
begin
FillChar(Init_State, SizeOf(Init_State), 0);
FillChar(T, SizeOf(T), 0);
P := Pointer(PByte(FAdditionalBuffer) + 12); // for Pointer Math
ExpandKey;
for I := 0 to 7 do
GP8(@T);
for I := 0 to 11 do
begin
for J := 0 to 7 do
GP8(@P[I * 32 + J * 4]);
GP8(@T);
end;
GP8(@T);
I := T[3] and $7F;
P[I + 3] := P[I + 3] or 1;
P := FAdditionalBuffer;
P[0] := T[3] shr 24 and $FF;
P[1] := T[3] shr 16 and $FF;
P[2] := T[3] shr 8 and $FF;
ProtectBuffer(Init_State, SizeOf(Init_State));
end;
procedure TCipher_SCOP_DEC52.DoEncode(Source, Dest: Pointer; Size: Integer);
var
I, J: Byte;
T2, T3, T1: UInt32;
P: PUInt32Array;
W: Integer;
begin
P := FAdditionalBuffer;
I := P[0];
J := P[1];
T3 := P[2];
for W := 0 to Size div 4 - 1 do
begin
T1 := P[J + 3 + 128]; Inc(J, T3);
T2 := P[J + 3 + 128];
PUInt32Array(Dest)[W] := PUInt32Array(Source)[W] + T1 + T2;
T3 := T2 + P[I + 3]; Inc(I);
P[J + 3 + 128] := T3;
Inc(J, T2);
end;
P[0] := I;
P[1] := J;
P[2] := T3;
end;
procedure TCipher_SCOP_DEC52.DoDecode(Source, Dest: Pointer; Size: Integer);
var
I, J: Byte;
T1, T2, T3: UInt32;
P: PUInt32Array;
W: Integer;
begin
P := FAdditionalBuffer;
I := P[0];
J := P[1];
T3 := P[2];
for W := 0 to Size div 4 - 1 do
begin
T1 := P[J + 3 + 128]; Inc(J, T3);
T2 := P[J + 3 + 128];
PUInt32Array(Dest)[W] := PUInt32Array(Source)[W] - T1 - T2;
T3 := T2 + P[I + 3];
Inc(I);
P[J + 3 + 128] := T3;
Inc(J, T2);
end;
P[0] := I;
P[1] := J;
P[2] := T3;
end;
{ TCipher_Sapphire }
type
PSapphireKey = ^TSapphireKey;
TSapphireKey = packed record
Cards: array[0..255] of UInt32;
Rotor: UInt32;
Ratchet: UInt32;
Avalanche: UInt32;
Plain: UInt32;
Cipher: UInt32;
end;
class function TCipher_Sapphire.Context: TCipherContext;
begin
Result.KeySize := 1024;
Result.BlockSize := 1;
Result.BufferSize := 32;
Result.AdditionalBufferSize := SizeOf(TSapphireKey);
Result.NeedsAdditionalBufferBackup := True;
Result.MinRounds := 1;
Result.MaxRounds := 1;
Result.CipherType := [ctSymmetric, ctStream];
end;
procedure TCipher_Sapphire.DoInit(const Key; Size: Integer);
var
Sum: Byte;
P: Integer;
function KeyRand(Max: UInt32): Byte;
var
I, M: UInt32;
begin
Result := 0;
if Max = 0 then
Exit;
I := 0;
M := 1;
while M < Max do
Inc(M, M or 1);
repeat
Inc(Sum, TByteArray(Key)[P]);
Inc(P);
if P >= Size then
begin
P := 0;
Inc(Sum, Size);
end;
Result := M and Sum;
Inc(I);
if I > 11 then
Result := Result mod Max;
until Result <= Max;
end;
var
I, S, T: Integer;
SKey : PSapphireKey;
begin
SKey := PSapphireKey(FAdditionalBuffer);
if Size <= 0 then
begin
SKey.Rotor := 1;
SKey.Ratchet := 3;
SKey.Avalanche := 5;
SKey.Plain := 7;
SKey.Cipher := 11;
for I := 0 to 255 do
SKey.Cards[I] := 255 - I;
end
else
begin
for I := 0 to 255 do
SKey.Cards[I] := I;
P := 0;
Sum := 0;
for I := 255 downto 1 do
begin
S := KeyRand(I);
T := SKey.Cards[I];
SKey.Cards[I] := SKey.Cards[S];
SKey.Cards[S] := T;
end;
SKey.Rotor := SKey.Cards[1];
SKey.Ratchet := SKey.Cards[3];
SKey.Avalanche := SKey.Cards[5];
SKey.Plain := SKey.Cards[7];
SKey.Cipher := SKey.Cards[Sum];
end;
end;
procedure TCipher_Sapphire.DoEncode(Source, Dest: Pointer; Size: Integer);
var
T: UInt32;
I: Integer;
SKey: PSapphireKey;
begin
SKey := PSapphireKey(FAdditionalBuffer);
for I := 0 to Size - 1 do
begin
SKey.Ratchet := (SKey.Ratchet + SKey.Cards[SKey.Rotor]) and $FF;
SKey.Rotor := (SKey.Rotor + 1) and $FF;
T := SKey.Cards[SKey.Cipher];
SKey.Cards[SKey.Cipher] := SKey.Cards[SKey.Ratchet];
SKey.Cards[SKey.Ratchet] := SKey.Cards[SKey.Plain];
SKey.Cards[SKey.Plain] := SKey.Cards[SKey.Rotor];
SKey.Cards[SKey.Rotor] := T;
SKey.Avalanche := (SKey.Avalanche + SKey.Cards[T]) and $FF;
T := (SKey.Cards[SKey.Plain] + SKey.Cards[SKey.Cipher] + SKey.Cards[SKey.Avalanche]) and $FF;
SKey.Plain := PByteArray(Source)[I];
SKey.Cipher := SKey.Plain xor SKey.Cards[SKey.Cards[T]] xor
SKey.Cards[(SKey.Cards[SKey.Ratchet] +
SKey.Cards[SKey.Rotor]) and $FF];
PByteArray(Dest)[I] := SKey.Cipher;
end;
end;
procedure TCipher_Sapphire.DoDecode(Source, Dest: Pointer; Size: Integer);
var
T: UInt32;
I: Integer;
SKey: PSapphireKey;
begin
SKey := PSapphireKey(FAdditionalBuffer);
for I := 0 to Size - 1 do
begin
SKey.Ratchet := (SKey.Ratchet + SKey.Cards[SKey.Rotor]) and $FF;
SKey.Rotor := (SKey.Rotor + 1) and $FF;
T := SKey.Cards[SKey.Cipher];
SKey.Cards[SKey.Cipher] := SKey.Cards[SKey.Ratchet];
SKey.Cards[SKey.Ratchet] := SKey.Cards[SKey.Plain];
SKey.Cards[SKey.Plain] := SKey.Cards[SKey.Rotor];
SKey.Cards[SKey.Rotor] := T;
SKey.Avalanche := (SKey.Avalanche + SKey.Cards[T]) and $FF;
T := (SKey.Cards[SKey.Plain] + SKey.Cards[SKey.Cipher] + SKey.Cards[SKey.Avalanche]) and $FF;
SKey.Cipher := PByteArray(Source)[I];
SKey.Plain := SKey.Cipher xor SKey.Cards[SKey.Cards[T]] xor
SKey.Cards[(SKey.Cards[SKey.Ratchet] +
SKey.Cards[SKey.Rotor]) and $FF];
PByteArray(Dest)[I] := SKey.Plain;
end;
end;
{ TCipher_1DES }
procedure DES_Func(Source, Dest, Key: PUInt32Array);
var
L, R, X, Y, I: UInt32;
begin
L := SwapUInt32(Source[0]);
R := SwapUInt32(Source[1]);
X := (L shr 4 xor R) and $0F0F0F0F; R := R xor X; L := L xor X shl 4;
X := (L shr 16 xor R) and $0000FFFF; R := R xor X; L := L xor X shl 16;
X := (R shr 2 xor L) and $33333333; L := L xor X; R := R xor X shl 2;
X := (R shr 8 xor L) and $00FF00FF; L := L xor X; R := R xor X shl 8;
R := R shl 1 or R shr 31;
X := (L xor R) and $AAAAAAAA;
R := R xor X;
L := L xor X;
L := L shl 1 or L shr 31;
for I := 0 to 7 do
begin
X := (R shl 28 or R shr 4) xor Key[0];
Y := R xor Key[1];
L := L xor (DES_Data[0, X and $3F] or DES_Data[1, X shr 8 and $3F] or
DES_Data[2, X shr 16 and $3F] or DES_Data[3, X shr 24 and $3F] or
DES_Data[4, Y and $3F] or DES_Data[5, Y shr 8 and $3F] or
DES_Data[6, Y shr 16 and $3F] or DES_Data[7, Y shr 24 and $3F]);
X := (L shl 28 or L shr 4) xor Key[2];
Y := L xor Key[3];
R := R xor (DES_Data[0, X and $3F] or DES_Data[1, X shr 8 and $3F] or
DES_Data[2, X shr 16 and $3F] or DES_Data[3, X shr 24 and $3F] or
DES_Data[4, Y and $3F] or DES_Data[5, Y shr 8 and $3F] or
DES_Data[6, Y shr 16 and $3F] or DES_Data[7, Y shr 24 and $3F]);
Key := @Key[4];
end;
R := R shl 31 or R shr 1;
X := (L xor R) and $AAAAAAAA;
R := R xor X;
L := L xor X;
L := L shl 31 or L shr 1;
X := (L shr 8 xor R) and $00FF00FF; R := R xor X; L := L xor X shl 8;
X := (L shr 2 xor R) and $33333333; R := R xor X; L := L xor X shl 2;
X := (R shr 16 xor L) and $0000FFFF; L := L xor X; R := R xor X shl 16;
X := (R shr 4 xor L) and $0F0F0F0F; L := L xor X; R := R xor X shl 4;
Dest[0] := SwapUInt32(R);
Dest[1] := SwapUInt32(L);
end;
class function TCipher_1DES.Context: TCipherContext;
begin
Result.KeySize := 8;
Result.BlockSize := 8;
Result.BufferSize := 8;
Result.AdditionalBufferSize := 32 * 4 * 2;
Result.NeedsAdditionalBufferBackup := False;
Result.MinRounds := 1;
Result.MaxRounds := 1;
Result.CipherType := [ctSymmetric, ctBlock];
end;
procedure TCipher_1DES.DoInitKey(const Data: array of Byte; Key: PUInt32Array; Reverse: Boolean);
const
ROT: array[0..15] of Byte = (1, 2, 4, 6, 8, 10, 12, 14, 15, 17, 19, 21, 23, 25, 27, 28);
var
I, J, L, M, N: UInt32;
PC_M, PC_R: array[0..55] of Byte;
K: array[0..31] of UInt32;
begin
FillChar(K, SizeOf(K), 0);
for I := 0 to 55 do
if Data[DES_PC1[I] shr 3] and ($80 shr (DES_PC1[I] and $07)) <> 0 then
PC_M[I] := 1
else
PC_M[I] := 0;
for I := 0 to 15 do
begin
if Reverse then
M := (15 - I) shl 1
else
M := I shl 1;
N := M + 1;
for J := 0 to 27 do
begin
L := J + ROT[I];
if L < 28 then
PC_R[J] := PC_M[L]
else
PC_R[J] := PC_M[L - 28];
end;
for J := 28 to 55 do
begin
L := J + ROT[I];
if L < 56 then
PC_R[J] := PC_M[L]
else
PC_R[J] := PC_M[L - 28];
end;
L := $1000000;
for J := 0 to 23 do
begin
L := L shr 1;
if PC_R[DES_PC2[J ]] <> 0 then
K[M] := K[M] or L;
if PC_R[DES_PC2[J + 24]] <> 0 then
K[N] := K[N] or L;
end;
end;
for I := 0 to 15 do
begin
M := I shl 1;
N := M + 1;
Key[0] := K[M] and $00FC0000 shl 6 or
K[M] and $00000FC0 shl 10 or
K[N] and $00FC0000 shr 10 or
K[N] and $00000FC0 shr 6;
Key[1] := K[M] and $0003F000 shl 12 or
K[M] and $0000003F shl 16 or
K[N] and $0003F000 shr 4 or
K[N] and $0000003F;
Key := @Key[2];
end;
ProtectBuffer(K, SizeOf(K));
ProtectBuffer(PC_M, SizeOf(PC_M));
ProtectBuffer(PC_R, SizeOf(PC_R));
end;
procedure TCipher_1DES.DoInit(const Key; Size: Integer);
var
K: array[0..7] of Byte;
begin
FillChar(K, SizeOf(K), 0);
Move(Key, K, Size);
DoInitKey(K, FAdditionalBuffer, False);
DoInitKey(K, @PUInt32Array(FAdditionalBuffer)[32], True);
ProtectBuffer(K, SizeOf(K));
end;
procedure TCipher_1DES.DoEncode(Source, Dest: Pointer; Size: Integer);
begin
Assert(Size = Context.BlockSize);
DES_Func(Source, Dest, FAdditionalBuffer);
end;
procedure TCipher_1DES.DoDecode(Source, Dest: Pointer; Size: Integer);
begin
Assert(Size = Context.BlockSize);
DES_Func(Source, Dest, @PUInt32Array(FAdditionalBuffer)[32]);
end;
{ TCipher_2DES }
class function TCipher_2DES.Context: TCipherContext;
begin
Result.KeySize := 16;
Result.BlockSize := 8;
Result.BufferSize := 8;
Result.AdditionalBufferSize := 32 * 4 * 2 * 2;
Result.NeedsAdditionalBufferBackup := False;
Result.MinRounds := 1;
Result.MaxRounds := 1;
Result.CipherType := [ctSymmetric, ctBlock];
end;
procedure TCipher_2DES.DoInit(const Key; Size: Integer);
var
K: array[0..15] of Byte;
P: PUInt32Array;
begin
FillChar(K, SizeOf(K), 0);
Move(Key, K, Size);
P := FAdditionalBuffer;
DoInitKey(K[0], @P[ 0], False);
DoInitKey(K[8], @P[32], True);
DoInitKey(K[0], @P[64], True);
DoInitKey(K[8], @P[96], False);
ProtectBuffer(K, SizeOf(K));
end;
procedure TCipher_2DES.DoEncode(Source, Dest: Pointer; Size: Integer);
begin
Assert(Size = Context.BlockSize);
DES_Func(Source, Dest, FAdditionalBuffer);
DES_Func(Source, Dest, @PUInt32Array(FAdditionalBuffer)[32]);
DES_Func(Source, Dest, FAdditionalBuffer);
end;
procedure TCipher_2DES.DoDecode(Source, Dest: Pointer; Size: Integer);
begin
Assert(Size = Context.BlockSize);
DES_Func(Source, Dest, @PUInt32Array(FAdditionalBuffer)[64]);
DES_Func(Source, Dest, @PUInt32Array(FAdditionalBuffer)[96]);
DES_Func(Source, Dest, @PUInt32Array(FAdditionalBuffer)[64]);
end;
{ TCipher_3DES }
class function TCipher_3DES.Context: TCipherContext;
begin
Result.KeySize := 24;
Result.BlockSize := 8;
Result.BufferSize := 8;
Result.AdditionalBufferSize := 32 * 4 * 2 * 3;
Result.NeedsAdditionalBufferBackup := False;
Result.MinRounds := 1;
Result.MaxRounds := 1;
Result.CipherType := [ctSymmetric, ctBlock];
end;
procedure TCipher_3DES.DoInit(const Key; Size: Integer);
var
K: array[0..23] of Byte;
P: PUInt32Array;
begin
FillChar(K, SizeOf(K), 0);
Move(Key, K, Size);
P := FAdditionalBuffer;
DoInitKey(K[ 0], @P[ 0], False);
DoInitKey(K[ 8], @P[ 32], True);
DoInitKey(K[16], @P[ 64], False);
DoInitKey(K[16], @P[ 96], True);
DoInitKey(K[ 8], @P[128], False);
DoInitKey(K[ 0], @P[160], True);
ProtectBuffer(K, SizeOf(K));
end;
procedure TCipher_3DES.DoEncode(Source, Dest: Pointer; Size: Integer);
begin
Assert(Size = Context.BlockSize);
DES_Func(Source, Dest, @PUInt32Array(FAdditionalBuffer)[ 0]);
DES_Func(Source, Dest, @PUInt32Array(FAdditionalBuffer)[32]);
DES_Func(Source, Dest, @PUInt32Array(FAdditionalBuffer)[64]);
end;
procedure TCipher_3DES.DoDecode(Source, Dest: Pointer; Size: Integer);
begin
Assert(Size = Context.BlockSize);
DES_Func(Source, Dest, @PUInt32Array(FAdditionalBuffer)[96]);
DES_Func(Source, Dest, @PUInt32Array(FAdditionalBuffer)[128]);
DES_Func(Source, Dest, @PUInt32Array(FAdditionalBuffer)[160]);
end;
{ TCipher_2DDES }
class function TCipher_2DDES.Context: TCipherContext;
begin
Result := inherited Context;
Result.BlockSize := 16;
Result.BufferSize := 16;
Result.MinRounds := 1;
Result.MaxRounds := 1;
Result.CipherType := [ctSymmetric, ctBlock];
end;
procedure TCipher_2DDES.DoEncode(Source, Dest: Pointer; Size: Integer);
var
T: UInt32;
begin
Assert(Size = Context.BlockSize);
DES_Func(@PUInt32Array(Source)[0], @PUInt32Array(Dest)[0], FAdditionalBuffer);
DES_Func(@PUInt32Array(Source)[2], @PUInt32Array(Dest)[2], FAdditionalBuffer);
T := PUInt32Array(Dest)[1];
PUInt32Array(Dest)[1] := PUInt32Array(Dest)[2];
PUInt32Array(Dest)[2] := T;
DES_Func(@PUInt32Array(Dest)[0], @PUInt32Array(Dest)[0], @PUInt32Array(FAdditionalBuffer)[32]);
DES_Func(@PUInt32Array(Dest)[2], @PUInt32Array(Dest)[2], @PUInt32Array(FAdditionalBuffer)[32]);
T := PUInt32Array(Dest)[1];
PUInt32Array(Dest)[1] := PUInt32Array(Dest)[2];
PUInt32Array(Dest)[2] := T;
DES_Func(@PUInt32Array(Dest)[0], @PUInt32Array(Dest)[0], FAdditionalBuffer);
DES_Func(@PUInt32Array(Dest)[2], @PUInt32Array(Dest)[2], FAdditionalBuffer);
end;
procedure TCipher_2DDES.DoDecode(Source, Dest: Pointer; Size: Integer);
var
T: UInt32;
begin
Assert(Size = Context.BlockSize);
DES_Func(@PUInt32Array(Source)[0], @PUInt32Array(Dest)[0], @PUInt32Array(FAdditionalBuffer)[64]);
DES_Func(@PUInt32Array(Source)[2], @PUInt32Array(Dest)[2], @PUInt32Array(FAdditionalBuffer)[64]);
T := PUInt32Array(Dest)[1];
PUInt32Array(Dest)[1] := PUInt32Array(Dest)[2];
PUInt32Array(Dest)[2] := T;
DES_Func(@PUInt32Array(Dest)[0], @PUInt32Array(Dest)[0], @PUInt32Array(FAdditionalBuffer)[96]);
DES_Func(@PUInt32Array(Dest)[2], @PUInt32Array(Dest)[2], @PUInt32Array(FAdditionalBuffer)[96]);
T := PUInt32Array(Dest)[1];
PUInt32Array(Dest)[1] := PUInt32Array(Dest)[2];
PUInt32Array(Dest)[2] := T;
DES_Func(@PUInt32Array(Dest)[0], @PUInt32Array(Dest)[0], @PUInt32Array(FAdditionalBuffer)[64]);
DES_Func(@PUInt32Array(Dest)[2], @PUInt32Array(Dest)[2], @PUInt32Array(FAdditionalBuffer)[64]);
end;
{ TCipher_3DDES }
class function TCipher_3DDES.Context: TCipherContext;
begin
Result := inherited Context;
Result.BlockSize := 16;
Result.BufferSize := 16;
Result.MinRounds := 1;
Result.MaxRounds := 1;
Result.CipherType := [ctSymmetric, ctBlock];
end;
procedure TCipher_3DDES.DoEncode(Source, Dest: Pointer; Size: Integer);
var
T: UInt32;
begin
Assert(Size = Context.BlockSize);
DES_Func(@PUInt32Array(Source)[0], @PUInt32Array(Dest)[0], FAdditionalBuffer);
DES_Func(@PUInt32Array(Source)[2], @PUInt32Array(Dest)[2], FAdditionalBuffer);
T := PUInt32Array(Dest)[1];
PUInt32Array(Dest)[1] := PUInt32Array(Dest)[2];
PUInt32Array(Dest)[2] := T;
DES_Func(@PUInt32Array(Dest)[0], @PUInt32Array(Dest)[0], @PUInt32Array(FAdditionalBuffer)[32]);
DES_Func(@PUInt32Array(Dest)[2], @PUInt32Array(Dest)[2], @PUInt32Array(FAdditionalBuffer)[32]);
T := PUInt32Array(Dest)[1];
PUInt32Array(Dest)[1] := PUInt32Array(Dest)[2];
PUInt32Array(Dest)[2] := T;
DES_Func(@PUInt32Array(Dest)[0], @PUInt32Array(Dest)[0], @PUInt32Array(FAdditionalBuffer)[64]);
DES_Func(@PUInt32Array(Dest)[2], @PUInt32Array(Dest)[2], @PUInt32Array(FAdditionalBuffer)[64]);
end;
procedure TCipher_3DDES.DoDecode(Source, Dest: Pointer; Size: Integer);
var
T: UInt32;
begin
Assert(Size = Context.BlockSize);
DES_Func(@PUInt32Array(Source)[0], @PUInt32Array(Dest)[0], @PUInt32Array(FAdditionalBuffer)[96]);
DES_Func(@PUInt32Array(Source)[2], @PUInt32Array(Dest)[2], @PUInt32Array(FAdditionalBuffer)[96]);
T := PUInt32Array(Dest)[1];
PUInt32Array(Dest)[1] := PUInt32Array(Dest)[2];
PUInt32Array(Dest)[2] := T;
DES_Func(@PUInt32Array(Dest)[0], @PUInt32Array(Dest)[0], @PUInt32Array(FAdditionalBuffer)[128]);
DES_Func(@PUInt32Array(Dest)[2], @PUInt32Array(Dest)[2], @PUInt32Array(FAdditionalBuffer)[128]);
T := PUInt32Array(Dest)[1];
PUInt32Array(Dest)[1] := PUInt32Array(Dest)[2];
PUInt32Array(Dest)[2] := T;
DES_Func(@PUInt32Array(Dest)[0], @PUInt32Array(Dest)[0], @PUInt32Array(FAdditionalBuffer)[160]);
DES_Func(@PUInt32Array(Dest)[2], @PUInt32Array(Dest)[2], @PUInt32Array(FAdditionalBuffer)[160]);
end;
{ TCipher_3TDES }
class function TCipher_3TDES.Context: TCipherContext;
begin
Result := inherited Context;
Result.BlockSize := 24;
Result.BufferSize := 24;
Result.MinRounds := 1;
Result.MaxRounds := 1;
Result.CipherType := [ctSymmetric, ctBlock];
end;
procedure TCipher_3TDES.DoEncode(Source, Dest: Pointer; Size: Integer);
var
T: UInt32;
begin
Assert(Size = Context.BlockSize);
DES_Func(@PUInt32Array(Source)[0], @PUInt32Array(Dest)[0], FAdditionalBuffer);
DES_Func(@PUInt32Array(Source)[2], @PUInt32Array(Dest)[2], FAdditionalBuffer);
DES_Func(@PUInt32Array(Source)[4], @PUInt32Array(Dest)[4], FAdditionalBuffer);
T := PUInt32Array(Dest)[1];
PUInt32Array(Dest)[1] := PUInt32Array(Dest)[2];
PUInt32Array(Dest)[2] := T;
T := PUInt32Array(Dest)[3];
PUInt32Array(Dest)[3] := PUInt32Array(Dest)[4];
PUInt32Array(Dest)[4] := T;
DES_Func(@PUInt32Array(Dest)[0], @PUInt32Array(Dest)[0], @PUInt32Array(FAdditionalBuffer)[32]);
DES_Func(@PUInt32Array(Dest)[2], @PUInt32Array(Dest)[2], @PUInt32Array(FAdditionalBuffer)[32]);
DES_Func(@PUInt32Array(Dest)[4], @PUInt32Array(Dest)[4], @PUInt32Array(FAdditionalBuffer)[32]);
T := PUInt32Array(Dest)[1];
PUInt32Array(Dest)[1] := PUInt32Array(Dest)[2];
PUInt32Array(Dest)[2] := T;
T := PUInt32Array(Dest)[3];
PUInt32Array(Dest)[3] := PUInt32Array(Dest)[4];
PUInt32Array(Dest)[4] := T;
DES_Func(@PUInt32Array(Dest)[0], @PUInt32Array(Dest)[0], @PUInt32Array(FAdditionalBuffer)[64]);
DES_Func(@PUInt32Array(Dest)[2], @PUInt32Array(Dest)[2], @PUInt32Array(FAdditionalBuffer)[64]);
DES_Func(@PUInt32Array(Dest)[4], @PUInt32Array(Dest)[4], @PUInt32Array(FAdditionalBuffer)[64]);
end;
procedure TCipher_3TDES.DoDecode(Source, Dest: Pointer; Size: Integer);
var
T: UInt32;
begin
Assert(Size = Context.BlockSize);
DES_Func(@PUInt32Array(Source)[0], @PUInt32Array(Dest)[0], @PUInt32Array(FAdditionalBuffer)[96]);
DES_Func(@PUInt32Array(Source)[2], @PUInt32Array(Dest)[2], @PUInt32Array(FAdditionalBuffer)[96]);
DES_Func(@PUInt32Array(Source)[4], @PUInt32Array(Dest)[4], @PUInt32Array(FAdditionalBuffer)[96]);
T := PUInt32Array(Dest)[1];
PUInt32Array(Dest)[1] := PUInt32Array(Dest)[2];
PUInt32Array(Dest)[2] := T;
T := PUInt32Array(Dest)[3];
PUInt32Array(Dest)[3] := PUInt32Array(Dest)[4];
PUInt32Array(Dest)[4] := T;
DES_Func(@PUInt32Array(Dest)[0], @PUInt32Array(Dest)[0], @PUInt32Array(FAdditionalBuffer)[128]);
DES_Func(@PUInt32Array(Dest)[2], @PUInt32Array(Dest)[2], @PUInt32Array(FAdditionalBuffer)[128]);
DES_Func(@PUInt32Array(Dest)[4], @PUInt32Array(Dest)[4], @PUInt32Array(FAdditionalBuffer)[128]);
T := PUInt32Array(Dest)[1];
PUInt32Array(Dest)[1] := PUInt32Array(Dest)[2];
PUInt32Array(Dest)[2] := T;
T := PUInt32Array(Dest)[3];
PUInt32Array(Dest)[3] := PUInt32Array(Dest)[4];
PUInt32Array(Dest)[4] := T;
DES_Func(@PUInt32Array(Dest)[0], @PUInt32Array(Dest)[0], @PUInt32Array(FAdditionalBuffer)[160]);
DES_Func(@PUInt32Array(Dest)[2], @PUInt32Array(Dest)[2], @PUInt32Array(FAdditionalBuffer)[160]);
DES_Func(@PUInt32Array(Dest)[4], @PUInt32Array(Dest)[4], @PUInt32Array(FAdditionalBuffer)[160]);
end;
{ TCipher_3Way }
type
P3Way_Key = ^T3Way_Key;
T3Way_Key = packed record
E_Key: array[0..2] of UInt32;
E_Data: array[0..11] of UInt32;
D_Key: array[0..2] of UInt32;
D_Data: array[0..11] of UInt32;
end;
class function TCipher_3Way.Context: TCipherContext;
begin
Result.KeySize := 12;
Result.BlockSize := 12;
Result.BufferSize := 12;
Result.AdditionalBufferSize := SizeOf(T3Way_Key);
Result.NeedsAdditionalBufferBackup := False;
Result.MinRounds := 1;
Result.MaxRounds := 1;
Result.CipherType := [ctSymmetric, ctBlock];
end;
procedure TCipher_3Way.DoInit(const Key; Size: Integer);
procedure RANDGenerate(Start: UInt32; var P: array of UInt32);
var
I: Integer;
begin
for I := 0 to 11 do
begin
P[I] := Start;
Start := Start shl 1;
if Start and $10000 <> 0 then
Start := Start xor $11011;
end;
end;
var
A0, A1, A2: UInt32;
B0, B1, B2: UInt32;
P3WayKey: P3Way_Key;
begin
P3WayKey := P3Way_Key(FAdditionalBuffer);
Move(Key, P3WayKey.E_Key, Size);
Move(Key, P3WayKey.D_Key, Size);
RANDGenerate($0B0B, P3WayKey.E_Data);
RANDGenerate($B1B1, P3WayKey.D_Data);
A0 := P3WayKey.D_Key[0];
A1 := P3WayKey.D_Key[1];
A2 := P3WayKey.D_Key[2];
B0 := A0 xor A0 shr 16 xor A1 shl 16 xor A1 shr 16 xor A2 shl 16 xor
A1 shr 24 xor A2 shl 8 xor A2 shr 8 xor A0 shl 24 xor
A2 shr 16 xor A0 shl 16 xor A2 shr 24 xor A0 shl 8;
B1 := A1 xor A1 shr 16 xor A2 shl 16 xor A2 shr 16 xor A0 shl 16 xor
A2 shr 24 xor A0 shl 8 xor A0 shr 8 xor A1 shl 24 xor
A0 shr 16 xor A1 shl 16 xor A0 shr 24 xor A1 shl 8;
B2 := A2 xor A2 shr 16 xor A0 shl 16 xor A0 shr 16 xor A1 shl 16 xor
A0 shr 24 xor A1 shl 8 xor A1 shr 8 xor A2 shl 24 xor
A1 shr 16 xor A2 shl 16 xor A1 shr 24 xor A2 shl 8;
P3WayKey.D_Key[2] := ReverseBits(B0);
P3WayKey.D_Key[1] := ReverseBits(B1);
P3WayKey.D_Key[0] := ReverseBits(B2);
end;
procedure TCipher_3Way.DoEncode(Source, Dest: Pointer; Size: Integer);
var
I: Integer;
A0, A1, A2: UInt32;
B0, B1, B2: UInt32;
K0, K1, K2: UInt32;
E: PUInt32;
P3WayKey: P3Way_Key;
begin
Assert(Size = Context.BlockSize);
P3WayKey := P3Way_Key(FAdditionalBuffer);
K0 := P3WayKey.E_Key[0];
K1 := P3WayKey.E_Key[1];
K2 := P3WayKey.E_Key[2];
E := @P3WayKey.E_Data;
A0 := PUInt32Array(Source)[0];
A1 := PUInt32Array(Source)[1];
A2 := PUInt32Array(Source)[2];
for I := 0 to 10 do
begin
A0 := A0 xor K0 xor E^ shl 16;
A1 := A1 xor K1;
A2 := A2 xor K2 xor E^;
Inc(E);
B0 := A0 xor A0 shr 16 xor A1 shl 16 xor A1 shr 16 xor A2 shl 16 xor
A1 shr 24 xor A2 shl 8 xor A2 shr 8 xor A0 shl 24 xor
A2 shr 16 xor A0 shl 16 xor A2 shr 24 xor A0 shl 8;
B1 := A1 xor A1 shr 16 xor A2 shl 16 xor A2 shr 16 xor A0 shl 16 xor
A2 shr 24 xor A0 shl 8 xor A0 shr 8 xor A1 shl 24 xor
A0 shr 16 xor A1 shl 16 xor A0 shr 24 xor A1 shl 8;
B2 := A2 xor A2 shr 16 xor A0 shl 16 xor A0 shr 16 xor A1 shl 16 xor
A0 shr 24 xor A1 shl 8 xor A1 shr 8 xor A2 shl 24 xor
A1 shr 16 xor A2 shl 16 xor A1 shr 24 xor A2 shl 8;
B0 := B0 shr 10 or B0 shl 22;
B2 := B2 shl 1 or B2 shr 31;
A0 := B0 xor (B1 or not B2);
A1 := B1 xor (B2 or not B0);
A2 := B2 xor (B0 or not B1);
A0 := A0 shl 1 or A0 shr 31;
A2 := A2 shr 10 or A2 shl 22;
end;
A0 := A0 xor K0 xor E^ shl 16;
A1 := A1 xor K1;
A2 := A2 xor K2 xor E^;
PUInt32Array(Dest)[0] := A0 xor A0 shr 16 xor A1 shl 16 xor A1 shr 16 xor A2 shl 16 xor
A1 shr 24 xor A2 shl 8 xor A2 shr 8 xor A0 shl 24 xor
A2 shr 16 xor A0 shl 16 xor A2 shr 24 xor A0 shl 8;
PUInt32Array(Dest)[1] := A1 xor A1 shr 16 xor A2 shl 16 xor A2 shr 16 xor A0 shl 16 xor
A2 shr 24 xor A0 shl 8 xor A0 shr 8 xor A1 shl 24 xor
A0 shr 16 xor A1 shl 16 xor A0 shr 24 xor A1 shl 8;
PUInt32Array(Dest)[2] := A2 xor A2 shr 16 xor A0 shl 16 xor A0 shr 16 xor A1 shl 16 xor
A0 shr 24 xor A1 shl 8 xor A1 shr 8 xor A2 shl 24 xor
A1 shr 16 xor A2 shl 16 xor A1 shr 24 xor A2 shl 8;
end;
procedure TCipher_3Way.DoDecode(Source, Dest: Pointer; Size: Integer);
var
I: Integer;
A0, A1, A2: UInt32;
B0, B1, B2: UInt32;
K0, K1, K2: UInt32;
E: PUInt32;
P3WayKey: P3Way_Key;
begin
Assert(Size = Context.BlockSize);
P3WayKey := P3Way_Key(FAdditionalBuffer);
K0 := P3WayKey.D_Key[0];
K1 := P3WayKey.D_Key[1];
K2 := P3WayKey.D_Key[2];
E := @P3WayKey.D_Data;
A0 := ReverseBits(PUInt32Array(Source)[2]);
A1 := ReverseBits(PUInt32Array(Source)[1]);
A2 := ReverseBits(PUInt32Array(Source)[0]);
for I := 0 to 10 do
begin
A0 := A0 xor K0 xor E^ shl 16;
A1 := A1 xor K1;
A2 := A2 xor K2 xor E^;
Inc(E);
B0 := A0 xor A0 shr 16 xor A1 shl 16 xor A1 shr 16 xor A2 shl 16 xor
A1 shr 24 xor A2 shl 8 xor A2 shr 8 xor A0 shl 24 xor
A2 shr 16 xor A0 shl 16 xor A2 shr 24 xor A0 shl 8;
B1 := A1 xor A1 shr 16 xor A2 shl 16 xor A2 shr 16 xor A0 shl 16 xor
A2 shr 24 xor A0 shl 8 xor A0 shr 8 xor A1 shl 24 xor
A0 shr 16 xor A1 shl 16 xor A0 shr 24 xor A1 shl 8;
B2 := A2 xor A2 shr 16 xor A0 shl 16 xor A0 shr 16 xor A1 shl 16 xor
A0 shr 24 xor A1 shl 8 xor A1 shr 8 xor A2 shl 24 xor
A1 shr 16 xor A2 shl 16 xor A1 shr 24 xor A2 shl 8;
B0 := B0 shr 10 or B0 shl 22;
B2 := B2 shl 1 or B2 shr 31;
A0 := B0 xor (B1 or not B2);
A1 := B1 xor (B2 or not B0);
A2 := B2 xor (B0 or not B1);
A0 := A0 shl 1 or A0 shr 31;
A2 := A2 shr 10 or A2 shl 22;
end;
A0 := A0 xor K0 xor E^ shl 16;
A1 := A1 xor K1;
A2 := A2 xor K2 xor E^;
B0 := A0 xor A0 shr 16 xor A1 shl 16 xor A1 shr 16 xor A2 shl 16 xor
A1 shr 24 xor A2 shl 8 xor A2 shr 8 xor A0 shl 24 xor
A2 shr 16 xor A0 shl 16 xor A2 shr 24 xor A0 shl 8;
B1 := A1 xor A1 shr 16 xor A2 shl 16 xor A2 shr 16 xor A0 shl 16 xor
A2 shr 24 xor A0 shl 8 xor A0 shr 8 xor A1 shl 24 xor
A0 shr 16 xor A1 shl 16 xor A0 shr 24 xor A1 shl 8;
B2 := A2 xor A2 shr 16 xor A0 shl 16 xor A0 shr 16 xor A1 shl 16 xor
A0 shr 24 xor A1 shl 8 xor A1 shr 8 xor A2 shl 24 xor
A1 shr 16 xor A2 shl 16 xor A1 shr 24 xor A2 shl 8;
PUInt32Array(Dest)[2] := ReverseBits(B0);
PUInt32Array(Dest)[1] := ReverseBits(B1);
PUInt32Array(Dest)[0] := ReverseBits(B2);
end;
{ TCipher_Cast128 }
class function TCipher_Cast128.Context: TCipherContext;
begin
Result.KeySize := 16;
Result.BlockSize := 8;
Result.BufferSize := 8;
Result.AdditionalBufferSize := 128;
Result.NeedsAdditionalBufferBackup := false;
Result.MinRounds := 1;
Result.MaxRounds := 256;
Result.CipherType := [ctSymmetric, ctBlock];
end;
procedure TCipher_Cast128.SetRounds(Value: Integer);
begin
if Value <> FRounds then
begin
if not (FState in [csNew, csInitialized, csDone]) then
Done;
if (FState <> csNew) and (Value <= 0) then
Value := 16;
FRounds := Value;
end;
end;
procedure TCipher_Cast128.DoInit(const Key; Size: Integer);
var
Z, X, T: array[0..3] of UInt32;
K: PUInt32Array;
I: UInt32;
begin
if FRounds <= 0 then
begin
if Size <= 10 then
FRounds := 12
else
FRounds := 16;
end;
K := FAdditionalBuffer;
FillChar(X, SizeOf(X), 0);
Move(Key, X, Size);
SwapUInt32Buffer(X, X, 4);
I := 0;
while I < 32 do
begin
if I and 4 = 0 then
begin
Z[0] := X[0] xor Cast128_Key[0, X[3] shr 16 and $FF] xor
Cast128_Key[1, X[3] and $FF] xor
Cast128_Key[2, X[3] shr 24] xor
Cast128_Key[3, X[3] shr 8 and $FF] xor
Cast128_Key[2, X[2] shr 24];
T[0] := Z[0];
Z[1] := X[2] xor Cast128_Key[0, Z[0] shr 24] xor
Cast128_Key[1, Z[0] shr 8 and $FF] xor
Cast128_Key[2, Z[0] shr 16 and $FF] xor
Cast128_Key[3, Z[0] and $FF] xor
Cast128_Key[3, X[2] shr 8 and $FF];
T[1] := Z[1];
Z[2] := X[3] xor Cast128_Key[0, Z[1] and $FF] xor
Cast128_Key[1, Z[1] shr 8 and $FF] xor
Cast128_Key[2, Z[1] shr 16 and $FF] xor
Cast128_Key[3, Z[1] shr 24] xor
Cast128_Key[0, X[2] shr 16 and $FF];
T[2] := Z[2];
Z[3] := X[1] xor Cast128_Key[0, Z[2] shr 8 and $FF] xor
Cast128_Key[1, Z[2] shr 16 and $FF] xor
Cast128_Key[2, Z[2] and $FF] xor
Cast128_Key[3, Z[2] shr 24] xor
Cast128_Key[1, X[2] and $FF];
T[3] := Z[3];
end
else
begin
X[0] := Z[2] xor Cast128_Key[0, Z[1] shr 16 and $FF] xor
Cast128_Key[1, Z[1] and $FF] xor
Cast128_Key[2, Z[1] shr 24] xor
Cast128_Key[3, Z[1] shr 8 and $FF] xor
Cast128_Key[2, Z[0] shr 24];
T[0] := X[0];
X[1] := Z[0] xor Cast128_Key[0, X[0] shr 24] xor
Cast128_Key[1, X[0] shr 8 and $FF] xor
Cast128_Key[2, X[0] shr 16 and $FF] xor
Cast128_Key[3, X[0] and $FF] xor
Cast128_Key[3, Z[0] shr 8 and $FF];
T[1] := X[1];
X[2] := Z[1] xor Cast128_Key[0, X[1] and $FF] xor
Cast128_Key[1, X[1] shr 8 and $FF] xor
Cast128_Key[2, X[1] shr 16 and $FF] xor
Cast128_Key[3, X[1] shr 24] xor
Cast128_Key[0, Z[0] shr 16 and $FF];
T[2] := X[2];
X[3] := Z[3] xor Cast128_Key[0, X[2] shr 8 and $FF] xor
Cast128_Key[1, X[2] shr 16 and $FF] xor
Cast128_Key[2, X[2] and $FF] xor
Cast128_Key[3, X[2] shr 24] xor
Cast128_Key[1, Z[0] and $FF];
T[3] := X[3];
end;
case I and 12 of
0,12:
begin
K[I + 0] := Cast128_Key[0, T[2] shr 24] xor
Cast128_Key[1, T[2] shr 16 and $FF] xor
Cast128_Key[2, T[1] and $FF] xor
Cast128_Key[3, T[1] shr 8 and $FF];
K[I + 1] := Cast128_Key[0, T[2] shr 8 and $FF] xor
Cast128_Key[1, T[2] and $FF] xor
Cast128_Key[2, T[1] shr 16 and $FF] xor
Cast128_Key[3, T[1] shr 24];
K[I + 2] := Cast128_Key[0, T[3] shr 24] xor
Cast128_Key[1, T[3] shr 16 and $FF] xor
Cast128_Key[2, T[0] and $FF] xor
Cast128_Key[3, T[0] shr 8 and $FF];
K[I + 3] := Cast128_Key[0, T[3] shr 8 and $FF] xor
Cast128_Key[1, T[3] and $FF] xor
Cast128_Key[2, T[0] shr 16 and $FF] xor
Cast128_Key[3, T[0] shr 24];
end;
4,8:
begin
K[I + 0] := Cast128_Key[0, T[0] and $FF] xor
Cast128_Key[1, T[0] shr 8 and $FF] xor
Cast128_Key[2, T[3] shr 24] xor
Cast128_Key[3, T[3] shr 16 and $FF];
K[I + 1] := Cast128_Key[0, T[0] shr 16 and $FF] xor
Cast128_Key[1, T[0] shr 24] xor
Cast128_Key[2, T[3] shr 8 and $FF] xor
Cast128_Key[3, T[3] and $FF];
K[I + 2] := Cast128_Key[0, T[1] and $FF] xor
Cast128_Key[1, T[1] shr 8 and $FF] xor
Cast128_Key[2, T[2] shr 24] xor
Cast128_Key[3, T[2] shr 16 and $FF];
K[I + 3] := Cast128_Key[0, T[1] shr 16 and $FF] xor
Cast128_Key[1, T[1] shr 24] xor
Cast128_Key[2, T[2] shr 8 and $FF] xor
Cast128_Key[3, T[2] and $FF];
end;
end;
case I and 12 of
0: begin
K[I + 0] := K[I + 0] xor Cast128_Key[0, Z[0] shr 8 and $FF];
K[I + 1] := K[I + 1] xor Cast128_Key[1, Z[1] shr 8 and $FF];
K[I + 2] := K[I + 2] xor Cast128_Key[2, Z[2] shr 16 and $FF];
K[I + 3] := K[I + 3] xor Cast128_Key[3, Z[3] shr 24];
end;
4: begin
K[I + 0] := K[I + 0] xor Cast128_Key[0, X[2] shr 24];
K[I + 1] := K[I + 1] xor Cast128_Key[1, X[3] shr 16 and $FF];
K[I + 2] := K[I + 2] xor Cast128_Key[2, X[0] and $FF];
K[I + 3] := K[I + 3] xor Cast128_Key[3, X[1] and $FF];
end;
8: begin
K[I + 0] := K[I + 0] xor Cast128_Key[0, Z[2] shr 16 and $FF];
K[I + 1] := K[I + 1] xor Cast128_Key[1, Z[3] shr 24];
K[I + 2] := K[I + 2] xor Cast128_Key[2, Z[0] shr 8 and $FF];
K[I + 3] := K[I + 3] xor Cast128_Key[3, Z[1] shr 8 and $FF];
end;
12: begin
K[I + 0] := K[I + 0] xor Cast128_Key[0, X[0] and $FF];
K[I + 1] := K[I + 1] xor Cast128_Key[1, X[1] and $FF];
K[I + 2] := K[I + 2] xor Cast128_Key[2, X[2] shr 24];
K[I + 3] := K[I + 3] xor Cast128_Key[3, X[3] shr 16 and $FF];
end;
end;
if I >= 16 then
begin
K[I + 0] := K[I + 0] and $1F;
K[I + 1] := K[I + 1] and $1F;
K[I + 2] := K[I + 2] and $1F;
K[I + 3] := K[I + 3] and $1F;
end;
Inc(I, 4);
end;
ProtectBuffer(X, SizeOf(X));
ProtectBuffer(Z, SizeOf(Z));
ProtectBuffer(T, SizeOf(T));
end;
procedure TCipher_Cast128.DoEncode(Source, Dest: Pointer; Size: Integer);
var
T, I, A, B: UInt32;
K: PUInt32Array;
begin
Assert(Size = Context.BlockSize);
K := FAdditionalBuffer;
A := SwapUInt32(PUInt32Array(Source)[0]);
B := SwapUInt32(PUInt32Array(Source)[1]);
for I := 0 to 2 do
begin
T := K[0] + B;
T := T shl K[16] or T shr (32 - K[16]);
A := A xor (Cast128_Data[0, T shr 24] xor
Cast128_Data[1, T shr 16 and $FF] -
Cast128_Data[2, T shr 8 and $FF] +
Cast128_Data[3, T and $FF]);
T := K[1] xor A;
T := T shl K[17] or T shr (32 - K[17]);
B := B xor (Cast128_Data[0, T shr 24] -
Cast128_Data[1, T shr 16 and $FF] +
Cast128_Data[2, T shr 8 and $FF] xor
Cast128_Data[3, T and $FF]);
T := K[2] - B;
T := T shl K[18] or T shr (32 - K[18]);
A := A xor (Cast128_Data[0, T shr 24] +
Cast128_Data[1, T shr 16 and $FF] xor
Cast128_Data[2, T shr 8 and $FF] -
Cast128_Data[3, T and $FF]);
T := K[3] + A;
T := T shl K[19] or T shr (32 - K[19]);
B := B xor (Cast128_Data[0, T shr 24] xor
Cast128_Data[1, T shr 16 and $FF] -
Cast128_Data[2, T shr 8 and $FF] +
Cast128_Data[3, T and $FF]);
if I = 2 then
Break;
T := K[4] xor B;
T := T shl K[20] or T shr (32 - K[20]);
A := A xor (Cast128_Data[0, T shr 24] -
Cast128_Data[1, T shr 16 and $FF] +
Cast128_Data[2, T shr 8 and $FF] xor
Cast128_Data[3, T and $FF]);
T := K[5] - A;
T := T shl K[21] or T shr (32 - K[21]);
B := B xor (Cast128_Data[0, T shr 24] +
Cast128_Data[1, T shr 16 and $FF] xor
Cast128_Data[2, T shr 8 and $FF] -
Cast128_Data[3, T and $FF]);
if (I = 1) and (FRounds <= 12) then
Break;
K := @K[6];
end;
PUInt32Array(Dest)[0] := SwapUInt32(B);
PUInt32Array(Dest)[1] := SwapUInt32(A);
end;
procedure TCipher_Cast128.DoDecode(Source, Dest: Pointer; Size: Integer);
var
T, I, A, B: UInt32;
K: PUInt32Array;
JumpStart: Boolean;
begin
Assert(Size = Context.BlockSize);
JumpStart := False;
K := @PUInt32Array(FAdditionalBuffer)[12];
B := SwapUInt32(PUInt32Array(Source)[0]);
A := SwapUInt32(PUInt32Array(Source)[1]);
I := 2;
if FRounds <= 12 then
Dec(PUInt32(K), 6)
else
JumpStart := True;
while I > 0 do
begin
if not JumpStart then
begin
Dec(I);
T := K[5] - A;
T := T shl K[21] or T shr (32 - K[21]);
B := B xor (Cast128_Data[0, T shr 24] +
Cast128_Data[1, T shr 16 and $FF] xor
Cast128_Data[2, T shr 8 and $FF] -
Cast128_Data[3, T and $FF]);
T := K[4] xor B;
T := T shl K[20] or T shr (32 - K[20]);
A := A xor (Cast128_Data[0, T shr 24] -
Cast128_Data[1, T shr 16 and $FF] +
Cast128_Data[2, T shr 8 and $FF] xor
Cast128_Data[3, T and $FF]);
end
else
JumpStart := False;
T := K[3] + A;
T := T shl K[19] or T shr (32 - K[19]);
B := B xor (Cast128_Data[0, T shr 24] xor
Cast128_Data[1, T shr 16 and $FF] -
Cast128_Data[2, T shr 8 and $FF] +
Cast128_Data[3, T and $FF]);
T := K[2] - B;
T := T shl K[18] or T shr (32 - K[18]);
A := A xor (Cast128_Data[0, T shr 24] +
Cast128_Data[1, T shr 16 and $FF] xor
Cast128_Data[2, T shr 8 and $FF] -
Cast128_Data[3, T and $FF]);
T := K[1] xor A;
T := T shl K[17] or T shr (32 - K[17]);
B := B xor (Cast128_Data[0, T shr 24] -
Cast128_Data[1, T shr 16 and $FF] +
Cast128_Data[2, T shr 8 and $FF] xor
Cast128_Data[3, T and $FF]);
T := K[0] + B;
T := T shl K[16] or T shr (32 - K[16]);
A := A xor (Cast128_Data[0, T shr 24] xor
Cast128_Data[1, T shr 16 and $FF] -
Cast128_Data[2, T shr 8 and $FF] +
Cast128_Data[3, T and $FF]);
Dec(PUInt32(K), 6);
end;
PUInt32Array(Dest)[0] := SwapUInt32(A);
PUInt32Array(Dest)[1] := SwapUInt32(B);
end;
{ TCipher_Gost }
class function TCipher_Gost.Context: TCipherContext;
begin
Result.KeySize := 32;
Result.BlockSize := 8;
Result.BufferSize := 8;
Result.AdditionalBufferSize := 32;
Result.NeedsAdditionalBufferBackup := false;
Result.MinRounds := 1;
Result.MaxRounds := 1;
Result.CipherType := [ctSymmetric, ctBlock];
end;
procedure TCipher_Gost.DoInit(const Key; Size: Integer);
begin
Move(Key, FAdditionalBuffer^, Size);
end;
procedure TCipher_Gost.DoEncode(Source, Dest: Pointer; Size: Integer);
var
I, A, B, T: UInt32;
K: PUInt32Array;
begin
Assert(Size = Context.BlockSize);
K := FAdditionalBuffer;
A := PUInt32Array(Source)[0];
B := PUInt32Array(Source)[1];
for I := 0 to 11 do
begin
if I and 3 = 0 then
K := FAdditionalBuffer;
T := A + K[0];
B := B xor Gost_Data[0, T and $FF] xor
Gost_Data[1, T shr 8 and $FF] xor
Gost_Data[2, T shr 16 and $FF] xor
Gost_Data[3, T shr 24 ];
T := B + K[1];
A := A xor Gost_Data[0, T and $FF] xor
Gost_Data[1, T shr 8 and $FF] xor
Gost_Data[2, T shr 16 and $FF] xor
Gost_Data[3, T shr 24 ];
K := @K[2];
end;
K := @PUInt32Array(FAdditionalBuffer)[6];
for I := 0 to 3 do
begin
T := A + K[1];
B := B xor Gost_Data[0, T and $FF] xor
Gost_Data[1, T shr 8 and $FF] xor
Gost_Data[2, T shr 16 and $FF] xor
Gost_Data[3, T shr 24 ];
T := B + K[0];
A := A xor Gost_Data[0, T and $FF] xor
Gost_Data[1, T shr 8 and $FF] xor
Gost_Data[2, T shr 16 and $FF] xor
Gost_Data[3, T shr 24 ];
Dec(PUInt32(K), 2);
end;
PUInt32Array(Dest)[0] := B;
PUInt32Array(Dest)[1] := A;
end;
procedure TCipher_Gost.DoDecode(Source, Dest: Pointer; Size: Integer);
var
I, A, B, T: UInt32;
K: PUInt32Array;
begin
Assert(Size = Context.BlockSize);
A := PUInt32Array(Source)[0];
B := PUInt32Array(Source)[1];
K := FAdditionalBuffer;
for I := 0 to 3 do
begin
T := A + K[0];
B := B xor Gost_Data[0, T and $FF] xor
Gost_Data[1, T shr 8 and $FF] xor
Gost_Data[2, T shr 16 and $FF] xor
Gost_Data[3, T shr 24];
T := B + K[1];
A := A xor Gost_Data[0, T and $FF] xor
Gost_Data[1, T shr 8 and $FF] xor
Gost_Data[2, T shr 16 and $FF] xor
Gost_Data[3, T shr 24];
K := @K[2];
end;
for I := 0 to 11 do
begin
if I and 3 = 0 then
K := @PUInt32Array(FAdditionalBuffer)[6];
T := A + K[1];
B := B xor Gost_Data[0, T and $FF] xor
Gost_Data[1, T shr 8 and $FF] xor
Gost_Data[2, T shr 16 and $FF] xor
Gost_Data[3, T shr 24];
T := B + K[0];
A := A xor Gost_Data[0, T and $FF] xor
Gost_Data[1, T shr 8 and $FF] xor
Gost_Data[2, T shr 16 and $FF] xor
Gost_Data[3, T shr 24];
Dec(PUInt32(K), 2);
end;
PUInt32Array(Dest)[0] := B;
PUInt32Array(Dest)[1] := A;
end;
{ TCipher_Misty }
class function TCipher_Misty.Context: TCipherContext;
begin
Result.KeySize := 16;
Result.BlockSize := 8;
Result.BufferSize := 8;
Result.AdditionalBufferSize := 128;
Result.NeedsAdditionalBufferBackup := False;
Result.MinRounds := 1;
Result.MaxRounds := 1;
Result.CipherType := [ctSymmetric, ctBlock];
end;
function Misty_I(Value, Key: UInt32): UInt32;
begin
Result := Misty_Data9[Value shr 7 and $1FF] xor (Value and $7F);
Value := (Misty_Data7[Value and $7F] xor Result and $7F) xor (Key shr 9 and $7F);
Result := Misty_Data9[Result xor (Key and $1FF)] xor Value or Value shl 9;
end;
function Misty_O(Value, K: UInt32; Key: PUInt32Array): UInt32;
begin
Result := Misty_I((Value shr 16) xor Key[K], Key[(K + 5) and 7 + 8]) xor (Value and $FFFF);
Value := Misty_I((Value and $FFFF) xor Key[(K + 2) and 7], Key[(K + 1) and 7 + 8]) xor Result;
Result := Misty_I(Result xor Key[(K + 7) and 7], Key[(K + 3) and 7 + 8]) xor Value;
Result := Result or (Value xor Key[(K + 4) and 7]) shl 16;
end;
function Misty_E(Value, K: UInt32; Key: PUInt32Array): UInt32;
begin
Result := Value shr 16;
Value := Value and $FFFF;
if K and 1 <> 0 then
begin
K := K shr 1;
Value := Value xor (Result and Key[(K + 2) and 7 + 8]);
Result := Result xor (Value or Key[(K + 4) and 7]);
end
else
begin
K := K shr 1;
Value := Value xor (Result and Key[K]);
Result := Result xor (Value or Key[(K + 6) and 7 + 8]);
end;
Result:= (Result shl 16) or Value;
end;
function Misty_D(Value, K: UInt32; Key: PUInt32Array): UInt32;
begin
Result := Value shr 16;
Value := Value and $FFFF;
if K and 1 <> 0 then
begin
K := K shr 1;
Result := Result xor (Value or Key[(K + 4) and 7]);
Value := Value xor (Result and Key[(K + 2) and 7 + 8]);
end
else
begin
K := K shr 1;
Result := Result xor (Value or Key[(K + 6) and 7 + 8]);
Value := Value xor (Result and Key[K]);
end;
Result:= (Result shl 16) or Value;
end;
procedure TCipher_Misty.DoInit(const Key; Size: Integer);
var
K: array[0..15] of Byte;
D: PUInt32Array;
I: Integer;
begin
FillChar(K, SizeOf(K), 0);
Move(Key, K, Size);
D := FAdditionalBuffer;
for I := 0 to 7 do
D[I] := K[I * 2] * 256 + K[I * 2 + 1];
for I := 0 to 7 do
begin
D[I + 8] := Misty_I(D[I], D[(I + 1) and 7]);
D[I + 16] := D[I + 8] and $1FF;
D[I + 24] := D[I + 8] shr 9;
end;
ProtectBuffer(K, SizeOf(K));
end;
procedure TCipher_Misty.DoEncode(Source, Dest: Pointer; Size: Integer);
var
A, B: UInt32;
begin
Assert(Size = Context.BlockSize);
A := PUInt32Array(Source)[0];
B := PUInt32Array(Source)[1];
A := Misty_E(A, 0, FAdditionalBuffer);
B := Misty_E(B, 1, FAdditionalBuffer) xor Misty_O(A, 0, FAdditionalBuffer);
A := A xor Misty_O(B, 1, FAdditionalBuffer);
A := Misty_E(A, 2, FAdditionalBuffer);
B := Misty_E(B, 3, FAdditionalBuffer) xor Misty_O(A, 2, FAdditionalBuffer);
A := A xor Misty_O(B, 3, FAdditionalBuffer);
A := Misty_E(A, 4, FAdditionalBuffer);
B := Misty_E(B, 5, FAdditionalBuffer) xor Misty_O(A, 4, FAdditionalBuffer);
A := A xor Misty_O(B, 5, FAdditionalBuffer);
A := Misty_E(A, 6, FAdditionalBuffer);
B := Misty_E(B, 7, FAdditionalBuffer) xor Misty_O(A, 6, FAdditionalBuffer);
A := A xor Misty_O(B, 7, FAdditionalBuffer);
PUInt32Array(Dest)[0] := Misty_E(B, 9, FAdditionalBuffer);
PUInt32Array(Dest)[1] := Misty_E(A, 8, FAdditionalBuffer);
end;
procedure TCipher_Misty.DoDecode(Source, Dest: Pointer; Size: Integer);
var
A, B: UInt32;
begin
Assert(Size = Context.BlockSize);
B := Misty_D(PUInt32Array(Source)[0], 9, FAdditionalBuffer);
A := Misty_D(PUInt32Array(Source)[1], 8, FAdditionalBuffer);
A := A xor Misty_O(B, 7, FAdditionalBuffer);
B := Misty_D(B xor Misty_O(A, 6, FAdditionalBuffer), 7, FAdditionalBuffer);
A := Misty_D(A, 6, FAdditionalBuffer);
A := A xor Misty_O(B, 5, FAdditionalBuffer);
B := Misty_D(B xor Misty_O(A, 4, FAdditionalBuffer), 5, FAdditionalBuffer);
A := Misty_D(A, 4, FAdditionalBuffer);
A := A xor Misty_O(B, 3, FAdditionalBuffer);
B := Misty_D(B xor Misty_O(A, 2, FAdditionalBuffer), 3, FAdditionalBuffer);
A := Misty_D(A, 2, FAdditionalBuffer);
A := A xor Misty_O(B, 1, FAdditionalBuffer);
PUInt32Array(Dest)[0] := Misty_D(A, 0, FAdditionalBuffer);
PUInt32Array(Dest)[1] := Misty_D(B xor Misty_O(A, 0, FAdditionalBuffer), 1, FAdditionalBuffer);
end;
{ TCipher_NewDES }
procedure NewDES_Func(Source, Dest, Key: PByteArray);
var
I: Integer;
A, B, C, D, E, F, G, H: Byte;
begin
A := Source[0];
B := Source[1];
C := Source[2];
D := Source[3];
E := Source[4];
F := Source[5];
G := Source[6];
H := Source[7];
for I := 0 to 7 do
begin
E := E xor NewDES_Data[A xor Key[0]];
F := F xor NewDES_Data[B xor Key[1]];
G := G xor NewDES_Data[C xor Key[2]];
H := H xor NewDES_Data[D xor Key[3]];
B := B xor NewDES_Data[E xor Key[4]];
C := C xor NewDES_Data[F xor E];
D := D xor NewDES_Data[G xor Key[5]];
A := A xor NewDES_Data[H xor Key[6]];
Key := @Key[7];
end;
E := E xor NewDES_Data[A xor Key[0]];
F := F xor NewDES_Data[B xor Key[1]];
G := G xor NewDES_Data[C xor Key[2]];
H := H xor NewDES_Data[D xor Key[3]];
Dest[0] := A;
Dest[1] := B;
Dest[2] := C;
Dest[3] := D;
Dest[4] := E;
Dest[5] := F;
Dest[6] := G;
Dest[7] := H;
end;
class function TCipher_NewDES.Context: TCipherContext;
begin
Result.KeySize := 15;
Result.BlockSize := 8;
Result.BufferSize := 8;
Result.AdditionalBufferSize := 60 * 2;
Result.NeedsAdditionalBufferBackup := true;
Result.MinRounds := 1;
Result.MaxRounds := 1;
Result.CipherType := [ctSymmetric, ctBlock];
end;
procedure TCipher_NewDES.DoInit(const Key; Size: Integer);
var
K: array[0..14] of Byte;
E: PByteArray;
I: Integer;
begin
FillChar(K, SizeOf(K), 0);
Move(Key, K, Size);
E := FAdditionalBuffer;
Move(K, E[ 0], 15);
Move(K, E[15], 15);
Move(K, E[30], 15);
Move(K, E[45], 15);
E := @E[60];
I := 11;
repeat
E[0] := K[I]; I := (I + 1) mod 15;
E[1] := K[I]; I := (I + 1) mod 15;
E[2] := K[I]; I := (I + 1) mod 15;
E[3] := K[I]; I := (I + 9) mod 15;
if I = 12 then
Break;
E[4] := K[I]; Inc(I);
E[5] := K[I]; Inc(I);
E[6] := K[I]; I := (I + 9) mod 15;
E := @E[7];
until False;
ProtectBuffer(K, SizeOf(K));
end;
procedure TCipher_NewDES.DoEncode(Source, Dest: Pointer; Size: Integer);
begin
Assert(Size = Context.BlockSize);
NewDES_Func(Source, Dest, FAdditionalBuffer);
end;
procedure TCipher_NewDES.DoDecode(Source, Dest: Pointer; Size: Integer);
begin
Assert(Size = Context.BlockSize);
NewDES_Func(Source, Dest, @PByteArray(FAdditionalBuffer)[60]);
end;
{ TCipher_Q128 }
class function TCipher_Q128.Context: TCipherContext;
begin
Result.KeySize := 16;
Result.BlockSize := 16;
Result.BufferSize := 16;
Result.AdditionalBufferSize := 256;
Result.NeedsAdditionalBufferBackup := false;
Result.MinRounds := 1;
Result.MaxRounds := 1;
Result.CipherType := [ctSymmetric, ctBlock];
end;
procedure TCipher_Q128.DoInit(const Key; Size: Integer);
var
K: array[0..3] of UInt32;
D: PUInt32Array;
I: Integer;
begin
FillChar(K, SizeOf(K), 0);
Move(Key, K, Size);
D := FAdditionalBuffer;
for I := 19 downto 1 do
begin
K[1] := K[1] xor Q128_Data[K[0] and $03FF]; K[0] := K[0] shr 10 or K[0] shl 22;
K[2] := K[2] xor Q128_Data[K[1] and $03FF]; K[1] := K[1] shr 10 or K[1] shl 22;
K[3] := K[3] xor Q128_Data[K[2] and $03FF]; K[2] := K[2] shr 10 or K[2] shl 22;
K[0] := K[0] xor Q128_Data[K[3] and $03FF]; K[3] := K[3] shr 10 or K[3] shl 22;
if I <= 16 then
begin
D[0] := K[0];
D[1] := K[1];
D[2] := K[2];
D[3] := K[3];
D := @D[4];
end;
end;
ProtectBuffer(K, SizeOf(K));
end;
procedure TCipher_Q128.DoEncode(Source, Dest: Pointer; Size: Integer);
{$IFDEF X86ASM}
asm
PUSH ESI
PUSH EDI
PUSH EBX
PUSH EBP
PUSH ECX
MOV EDI,[EAX].TCipher_Q128.FAdditionalBuffer
MOV EAX,[EDX + 0] // B0
MOV EBX,[EDX + 4] // B1
MOV ECX,[EDX + 8] // B2
MOV EDX,[EDX + 12] // B3
MOV EBP,16
@@1: MOV ESI,EAX
ROL ESI,10
AND EAX,03FFh
MOV EAX,[EAX * 4 + OFFSET Q128_DATA]
ADD EAX,[EDI + 0]
XOR EAX,EBX
MOV EBX,EAX
ROL EBX,10
AND EAX,03FFh
MOV EAX,[EAX * 4 + OFFSET Q128_DATA]
ADD EAX,[EDI + 4]
XOR EAX,ECX
MOV ECX,EAX
ROL ECX,10
AND EAX,03FFh
MOV EAX,[EAX * 4 + OFFSET Q128_DATA]
ADD EAX,[EDI + 8]
XOR EAX,EDX
MOV EDX,EAX
ROL EDX,10
AND EAX,03FFh
MOV EAX,[EAX * 4 + OFFSET Q128_DATA]
ADD EAX,[EDI + 12]
XOR EAX,ESI
DEC EBP
LEA EDI,[EDI + 16]
JNZ @@1
POP ESI
MOV [ESI + 0],EAX // B0
MOV [ESI + 4],EBX // B1
MOV [ESI + 8],ECX // B2
MOV [ESI + 12],EDX // B3
POP EBP
POP EBX
POP EDI
POP ESI
end;
{$ELSE !X86ASM}
var
D: PUInt32Array;
B0, B1, B2, B3, I: UInt32;
begin
Assert(Size = Context.BlockSize);
D := Pointer(FAdditionalBuffer);
B0 := PUInt32Array(Source)[0];
B1 := PUInt32Array(Source)[1];
B2 := PUInt32Array(Source)[2];
B3 := PUInt32Array(Source)[3];
for I := 0 to 15 do
begin
B1 := B1 xor (Q128_Data[B0 and $03FF] + D[0]); B0 := B0 shl 10 or B0 shr 22;
B2 := B2 xor (Q128_Data[B1 and $03FF] + D[1]); B1 := B1 shl 10 or B1 shr 22;
B3 := B3 xor (Q128_Data[B2 and $03FF] + D[2]); B2 := B2 shl 10 or B2 shr 22;
B0 := B0 xor (Q128_Data[B3 and $03FF] + D[3]); B3 := B3 shl 10 or B3 shr 22;
D := @D[4];
end;
PUInt32Array(Dest)[0] := B0;
PUInt32Array(Dest)[1] := B1;
PUInt32Array(Dest)[2] := B2;
PUInt32Array(Dest)[3] := B3;
end;
{$ENDIF !X86ASM}
procedure TCipher_Q128.DoDecode(Source, Dest: Pointer; Size: Integer);
{$IFDEF X86ASM}
asm
PUSH ESI
PUSH EDI
PUSH EBX
PUSH EBP
PUSH ECX
MOV EDI,[EAX].TCipher_Q128.FAdditionalBuffer
LEA EDI,[EDI + 64 * 4]
MOV ESI,[EDX + 0] // B0
MOV EBX,[EDX + 4] // B1
MOV ECX,[EDX + 8] // B2
MOV EDX,[EDX + 12] // B3
MOV EBP,16
@@1: SUB EDI,16
ROR EDX,10
MOV EAX,EDX
AND EAX,03FFh
MOV EAX,[EAX * 4 + OFFSET Q128_DATA]
ADD EAX,[EDI + 12]
XOR ESI,EAX
ROR ECX,10
MOV EAX,ECX
AND EAX,03FFh
MOV EAX,[EAX * 4 + OFFSET Q128_DATA]
ADD EAX,[EDI + 8]
XOR EDX,EAX
ROR EBX,10
MOV EAX,EBX
AND EAX,03FFh
MOV EAX,[EAX * 4 + OFFSET Q128_DATA]
ADD EAX,[EDI + 4]
XOR ECX,EAX
ROR ESI,10
MOV EAX,ESI
AND EAX,03FFh
MOV EAX,[EAX * 4 + OFFSET Q128_DATA]
ADD EAX,[EDI]
XOR EBX,EAX
DEC EBP
JNZ @@1
POP EAX
MOV [EAX + 0],ESI // B0
MOV [EAX + 4],EBX // B1
MOV [EAX + 8],ECX // B2
MOV [EAX + 12],EDX // B3
POP EBP
POP EBX
POP EDI
POP ESI
end;
{$ELSE !X86ASM}
var
D: PUInt32Array;
B0, B1, B2, B3, I: UInt32;
begin
Assert(Size = Context.BlockSize);
D := @PUInt32Array(FAdditionalBuffer)[60];
B0 := PUInt32Array(Source)[0];
B1 := PUInt32Array(Source)[1];
B2 := PUInt32Array(Source)[2];
B3 := PUInt32Array(Source)[3];
for I := 0 to 15 do
begin
B3 := B3 shr 10 or B3 shl 22; B0 := B0 xor (Q128_Data[B3 and $03FF] + D[3]);
B2 := B2 shr 10 or B2 shl 22; B3 := B3 xor (Q128_Data[B2 and $03FF] + D[2]);
B1 := B1 shr 10 or B1 shl 22; B2 := B2 xor (Q128_Data[B1 and $03FF] + D[1]);
B0 := B0 shr 10 or B0 shl 22; B1 := B1 xor (Q128_Data[B0 and $03FF] + D[0]);
Dec(PUInt32(D), 4);
end;
PUInt32Array(Dest)[0] := B0;
PUInt32Array(Dest)[1] := B1;
PUInt32Array(Dest)[2] := B2;
PUInt32Array(Dest)[3] := B3;
end;
{$ENDIF !X86ASM}
{ TCipher_RC2 }
class function TCipher_RC2.Context: TCipherContext;
begin
Result.KeySize := 128;
Result.BlockSize := 8;
Result.BufferSize := 8;
Result.AdditionalBufferSize := 128;
Result.NeedsAdditionalBufferBackup := False;
Result.MinRounds := 1;
Result.MaxRounds := 1;
Result.CipherType := [ctSymmetric, ctBlock];
end;
procedure TCipher_RC2.DoInit(const Key; Size: Integer);
// New keyscheduling according to RFC2268 and it's testcases. The V3 keysetup
// was using an older, inferior version. Special thanks to Brendan Bosnan for
// pointing that out.
var
I, L, Mask, KeyEffectiveBits: Integer;
K: PByteArray;
begin
if Size <= 0 then
Exit;
KeyEffectiveBits := Size * 8;
L := KeyEffectiveBits and 7;
if L = 0 then
Mask := $FF
else
Mask := $FF shr (8 - L);
L := (KeyEffectiveBits + 7) shr 3;
K := FAdditionalBuffer;
Move(Key, K[0], Size);
for I := Size to 127 do
K[I] := RC2_Data[(K[I - Size] + K[I - 1]) and $FF];
K[128 - L] := RC2_Data[K[128 - L] and Mask];
for I := 127 - L downto 0 do
K[I] := RC2_Data[K[I + 1] xor K[I + L]];
end;
procedure TCipher_RC2.DoEncode(Source, Dest: Pointer; Size: Integer);
var
I: Integer;
K: PWordArray;
A, B, C, D: Word;
begin
Assert(Size = Context.BlockSize);
K := FAdditionalBuffer;
A := PWordArray(Source)[0];
B := PWordArray(Source)[1];
C := PWordArray(Source)[2];
D := PWordArray(Source)[3];
for I := 0 to 15 do
begin
Inc(A, (B and not D) + (C and D) + K[I * 4 + 0]); A := A shl 1 or A shr 15;
Inc(B, (C and not A) + (D and A) + K[I * 4 + 1]); B := B shl 2 or B shr 14;
Inc(C, (D and not B) + (A and B) + K[I * 4 + 2]); C := C shl 3 or C shr 13;
Inc(D, (A and not C) + (B and C) + K[I * 4 + 3]); D := D shl 5 or D shr 11;
if I in [4, 10] then
begin
Inc(A, K[D and $3F]);
Inc(B, K[A and $3F]);
Inc(C, K[B and $3F]);
Inc(D, K[C and $3F]);
end;
end;
PWordArray(Dest)[0] := A;
PWordArray(Dest)[1] := B;
PWordArray(Dest)[2] := C;
PWordArray(Dest)[3] := D;
end;
procedure TCipher_RC2.DoDecode(Source, Dest: Pointer; Size: Integer);
var
I: Integer;
K: PWordArray;
A, B, C, D: Word;
begin
Assert(Size = Context.BlockSize);
K := FAdditionalBuffer;
A := PWordArray(Source)[0];
B := PWordArray(Source)[1];
C := PWordArray(Source)[2];
D := PWordArray(Source)[3];
for I := 15 downto 0 do
begin
D := D shr 5 or D shl 11 - (A and not C) - (B and C) - K[I * 4 + 3];
C := C shr 3 or C shl 13 - (D and not B) - (A and B) - K[I * 4 + 2];
B := B shr 2 or B shl 14 - (C and not A) - (D and A) - K[I * 4 + 1];
A := A shr 1 or A shl 15 - (B and not D) - (C and D) - K[I * 4 + 0];
if I in [5, 11] then
begin
Dec(D, K[C and $3F]);
Dec(C, K[B and $3F]);
Dec(B, K[A and $3F]);
Dec(A, K[D and $3F]);
end;
end;
PWordArray(Dest)[0] := A;
PWordArray(Dest)[1] := B;
PWordArray(Dest)[2] := C;
PWordArray(Dest)[3] := D;
end;
{ TCipher_RC5 }
class function TCipher_RC5.Context: TCipherContext;
begin
Result.KeySize := 256;
Result.BlockSize := 8;
Result.BufferSize := 8;
Result.AdditionalBufferSize := 136;
Result.NeedsAdditionalBufferBackup := false;
Result.MinRounds := 1;
Result.MaxRounds := 256;
Result.CipherType := [ctSymmetric, ctBlock];
end;
procedure TCipher_RC5.SetRounds(Value: Integer);
begin
if Value <> FRounds then
begin
if not (FState in [csNew, csInitialized, csDone]) then
Done;
if Value <= 0 then
Value := 12;
FRounds := Value;
end;
end;
procedure TCipher_RC5.DoInit(const Key; Size: Integer);
var
K: array[0..63] of UInt32;
L, Z, I, J: Integer;
D: PUInt32Array;
A, B, T: UInt32;
begin
if FRounds <= 0 then
FRounds := 12;
FillChar(K, SizeOf(K), 0);
Move(Key, K, Size);
D := FAdditionalBuffer;
L := (Size + 3) shr 2;
if L <= 0 then
L := 1;
T := $B7E15163;
for I := 0 to (FRounds + 1) * 2 do
begin
D[I] := T;
Inc(T, $9E3779B9);
end;
if L > (FRounds + 1) * 2 then
Z := L * 3
else
Z := (FRounds + 1) * 6;
I := 0;
J := 0;
A := 0;
B := 0;
for Z := Z downto 1 do
begin
A := D[I] + A + B;
A := A shl 3 or A shr 29;
D[I] := A;
T := A + B;
B := K[J] + T;
B := B shl T or B shr (32 - T);
K[J] := B;
I := (I + 1) mod ((FRounds + 1) * 2);
J := (J + 1) mod L;
end;
ProtectBuffer(K, SizeOf(K));
end;
procedure TCipher_RC5.DoEncode(Source, Dest: Pointer; Size: Integer);
var
K: PUInt32Array;
I: Integer;
A, B: UInt32;
begin
Assert(Size = Context.BlockSize);
K := FAdditionalBuffer;
A := PUInt32Array(Source)[0] + K[0];
B := PUInt32Array(Source)[1] + K[1];
for I := 1 to FRounds do
begin
A := A xor B; A := A shl B or A shr (32 - B) + K[I * 2 + 0];
B := B xor A; B := B shl A or B shr (32 - A) + K[I * 2 + 1];
end;
PUInt32Array(Dest)[0] := A;
PUInt32Array(Dest)[1] := B;
end;
procedure TCipher_RC5.DoDecode(Source, Dest: Pointer; Size: Integer);
var
K: PUInt32Array;
I: Integer;
A, B: UInt32;
begin
Assert(Size = Context.BlockSize);
K := @PUInt32Array(FAdditionalBuffer)[0];
A := PUInt32Array(Source)[0];
B := PUInt32Array(Source)[1];
for I := FRounds downto 1 do
begin
B := B - K[I * 2 + 1]; B := B shr A or B shl (32 - A) xor A;
A := A - K[I * 2 + 0]; A := A shr B or A shl (32 - B) xor B;
end;
PUInt32Array(Dest)[0] := A - K[0];
PUInt32Array(Dest)[1] := B - K[1];
end;
{ TCipher_SAFER }
class function TCipher_SAFER.Context: TCipherContext;
begin
Result.KeySize := 16;
Result.BlockSize := 8;
Result.BufferSize := 8;
Result.AdditionalBufferSize := 768;
Result.NeedsAdditionalBufferBackup := false;
Result.MinRounds := 4;
Result.MaxRounds := 13;
Result.CipherType := [ctSymmetric, ctBlock];
end;
procedure TCipher_SAFER.SetRounds(Value: Integer);
begin
if not (FState in [csNew, csInitialized, csDone]) then
Done;
if (Value < 4) or (Value > 13) then
case FVersion of // Default Rounds
svK40, svSK40: Value := 5;
svK64, svSK64: Value := 6;
svK128, svSK128: Value := 10;
else
Value := 8;
end;
FRounds := Value;
end;
procedure TCipher_SAFER.SetVersion(Value: TSAFERVersion);
begin
if Value <> FVersion then
begin
if not (FState in [csNew, csInitialized, csDone]) then
Done;
FVersion := Value;
SetRounds(0);
end;
end;
procedure TCipher_SAFER.DoInit(const Key; Size: Integer);
procedure InitTab;
var
I, E: Integer;
Exp: PByteArray;
Log: PByteArray;
begin
Exp := FAdditionalBuffer;
Log := @Exp[256];
E := 1;
for I := 0 to 255 do
begin
Exp[I] := E and $FF;
Log[E and $FF] := I;
E := (E * 45) mod 257;
end;
end;
procedure InitKey;
var
D: PByte;
Exp: PByteArray;
Strong: Boolean;
K: array[Boolean, 0..8] of Byte;
I, J: Integer;
begin
Strong := FVersion in [svSK40, svSK64, svSK128];
Exp := FAdditionalBuffer;
D := @Exp[512];
FillChar(K, SizeOf(K), 0);
// Setup Key A
I := Size;
if I > 8 then
I := 8;
Move(Key, K[False], I);
// Setup the Key for K-40, SK-40
if FVersion in [svK40, svSK40] then
begin
K[False, 5] := K[False, 0] xor K[False, 2] xor 129;
K[False, 6] := K[False, 0] xor K[False, 3] xor K[False, 4] xor 66;
K[False, 7] := K[False, 1] xor K[False, 2] xor K[False, 4] xor 36;
K[False, 8] := K[False, 1] xor K[False, 3] xor 24;
Move(K[False], K[True], SizeOf(K[False]));
end
else
begin
if Size > 8 then
begin
I := Size - 8;
if I > 8 then
I := 8;
Move(TByteArray(Key)[8], K[True], I);
end
else
Move(K[False], K[True], 9);
for I := 0 to 7 do
begin
K[False, 8] := K[False, 8] xor K[False, I];
K[True, 8] := K[True, 8] xor K[True, I];
end;
end;
// Setup the KeyData
Move(K[True], D^, 8);
Inc(D, 8);
for I := 0 to 8 do
K[False, I] := K[False, I] shr 3 or K[False, I] shl 5;
for I := 1 to FRounds do
begin
for J := 0 to 8 do
begin
K[False, J] := K[False, J] shl 6 or K[False, J] shr 2;
K[True, J] := K[True, J] shl 6 or K[True, J] shr 2;
end;
for J := 0 to 7 do
begin
if Strong then
D^ := K[False, (J + I * 2 - 1) mod 9] + Exp[Exp[18 * I + J + 1]]
else
D^ := K[False, J] + Exp[Exp[18 * I + J + 1]];
Inc(D);
end;
for J := 0 to 7 do
begin
if Strong then
D^ := K[True, (J + I * 2) mod 9] + Exp[Exp[18 * I + J + 10]]
else
D^ := K[True, J] + Exp[Exp[18 * I + J + 10]];
Inc(D);
end;
end;
ProtectBuffer(K, SizeOf(K));
end;
begin
if (FRounds < 4) or (FRounds > 13) then
case FVersion of
svK40, svSK40: FRounds := 5;
svK64, svSK64: FRounds := 6;
svK128, svSK128: FRounds := 10;
else
FRounds := 8;
end;
InitTab;
InitKey;
end;
procedure TCipher_SAFER.DoEncode(Source, Dest: Pointer; Size: Integer);
var
Exp, Log, Key: PByteArray;
I: Integer;
A, B, C, D, E, F, G, H, T: Byte;
begin
Assert(Size = Context.BlockSize);
Exp := FAdditionalBuffer;
Log := @Exp[256];
Key := @Exp[512];
A := PByteArray(Source)[0];
B := PByteArray(Source)[1];
C := PByteArray(Source)[2];
D := PByteArray(Source)[3];
E := PByteArray(Source)[4];
F := PByteArray(Source)[5];
G := PByteArray(Source)[6];
H := PByteArray(Source)[7];
for I := 0 to FRounds - 1 do
begin
A := A xor Key[0];
B := B + Key[1];
C := C + Key[2];
D := D xor Key[3];
E := E xor Key[4];
F := F + Key[5];
G := G + Key[6];
H := H xor Key[7];
A := Exp[A] + Key[8];
B := Log[B] xor Key[9];
C := Log[C] xor Key[10];
D := Exp[D] + Key[11];
E := Exp[E] + Key[12];
F := Log[F] xor Key[13];
G := Log[G] xor Key[14];
H := Exp[H] + Key[15];
Inc(B, A); Inc(A, B);
Inc(D, C); Inc(C, D);
Inc(F, E); Inc(E, F);
Inc(H, G); Inc(G, H);
Inc(C, A); Inc(A, C);
Inc(G, E); Inc(E, G);
Inc(D, B); Inc(B, D);
Inc(H, F); Inc(F, H);
Inc(E, A); Inc(A, E);
Inc(F, B); Inc(B, F);
Inc(G, C); Inc(C, G);
Inc(H, D); Inc(D, H);
T := B; B := E; E := C; C := T;
T := D; D := F; F := G; G := T;
Key := @Key[16];
end;
PByteArray(Dest)[0] := A xor Key[0];
PByteArray(Dest)[1] := B + Key[1];
PByteArray(Dest)[2] := C + Key[2];
PByteArray(Dest)[3] := D xor Key[3];
PByteArray(Dest)[4] := E xor Key[4];
PByteArray(Dest)[5] := F + Key[5];
PByteArray(Dest)[6] := G + Key[6];
PByteArray(Dest)[7] := H xor Key[7];
end;
procedure TCipher_SAFER.DoDecode(Source, Dest: Pointer; Size: Integer);
var
Exp, Log, Key: PByteArray;
I: Integer;
A, B, C, D, E, F, G, H, T: Byte;
begin
Assert(Size = Context.BlockSize);
Exp := FAdditionalBuffer;
Log := @Exp[256];
Key := @Exp[504 + 8 * (FRounds * 2 + 1)];
A := PByteArray(Source)[0] xor Key[0];
B := PByteArray(Source)[1] - Key[1];
C := PByteArray(Source)[2] - Key[2];
D := PByteArray(Source)[3] xor Key[3];
E := PByteArray(Source)[4] xor Key[4];
F := PByteArray(Source)[5] - Key[5];
G := PByteArray(Source)[6] - Key[6];
H := PByteArray(Source)[7] xor Key[7];
for I := 0 to FRounds - 1 do
begin
Dec(PByte(Key), 16);
T := E; E := B; B := C; C := T;
T := F; F := D; D := G; G := T;
Dec(A, E); Dec(E, A);
Dec(B, F); Dec(F, B);
Dec(C, G); Dec(G, C);
Dec(D, H); Dec(H, D);
Dec(A, C); Dec(C, A);
Dec(E, G); Dec(G, E);
Dec(B, D); Dec(D, B);
Dec(F, H); Dec(H, F);
Dec(A, B); Dec(B, A);
Dec(C, D); Dec(D, C);
Dec(E, F); Dec(F, E);
Dec(G, H); Dec(H, G);
H := H - Key[15];
G := G xor Key[14];
F := F xor Key[13];
E := E - Key[12];
D := D - Key[11];
C := C xor Key[10];
B := B xor Key[9];
A := A - Key[8];
H := Log[H] xor Key[7];
G := Exp[G] - Key[6];
F := Exp[F] - Key[5];
E := Log[E] xor Key[4];
D := Log[D] xor Key[3];
C := Exp[C] - Key[2];
B := Exp[B] - Key[1];
A := Log[A] xor Key[0];
end;
PByteArray(Dest)[0] := A;
PByteArray(Dest)[1] := B;
PByteArray(Dest)[2] := C;
PByteArray(Dest)[3] := D;
PByteArray(Dest)[4] := E;
PByteArray(Dest)[5] := F;
PByteArray(Dest)[6] := G;
PByteArray(Dest)[7] := H;
end;
{ TCipher_SharkBase }
{$IFNDEF CPU64BITS}
function TCipher_SharkBase.Shark(D: TLong64; K: PLong64): TLong64;
var
R, T: Integer;
begin
for R := 0 to 4 do
begin
D.L := D.L xor K.L;
D.R := D.R xor K.R;
Inc(K);
T := Shark_CE[0, D.R shr 23 and $1FE] xor
Shark_CE[1, D.R shr 15 and $1FE] xor
Shark_CE[2, D.R shr 7 and $1FE] xor
Shark_CE[3, D.R shl 1 and $1FE] xor
Shark_CE[4, D.L shr 23 and $1FE] xor
Shark_CE[5, D.L shr 15 and $1FE] xor
Shark_CE[6, D.L shr 7 and $1FE] xor
Shark_CE[7, D.L shl 1 and $1FE];
D.R := Shark_CE[0, D.R shr 23 and $1FE or 1] xor
Shark_CE[1, D.R shr 15 and $1FE or 1] xor
Shark_CE[2, D.R shr 7 and $1FE or 1] xor
Shark_CE[3, D.R shl 1 and $1FE or 1] xor
Shark_CE[4, D.L shr 23 and $1FE or 1] xor
Shark_CE[5, D.L shr 15 and $1FE or 1] xor
Shark_CE[6, D.L shr 7 and $1FE or 1] xor
Shark_CE[7, D.L shl 1 and $1FE or 1];
D.L := T;
end;
D.L := D.L xor K.L;
D.R := D.R xor K.R;
Inc(K);
D.L := UInt32(Shark_SE[D.L shr 24 and $FF]) shl 24 xor
UInt32(Shark_SE[D.L shr 16 and $FF]) shl 16 xor
UInt32(Shark_SE[D.L shr 8 and $FF]) shl 8 xor
UInt32(Shark_SE[D.L and $FF]);
D.R := UInt32(Shark_SE[D.R shr 24 and $FF]) shl 24 xor
UInt32(Shark_SE[D.R shr 16 and $FF]) shl 16 xor
UInt32(Shark_SE[D.R shr 8 and $FF]) shl 8 xor
UInt32(Shark_SE[D.R and $FF]);
Result.L := D.L xor K.L;
Result.R := D.R xor K.R;
end;
function TCipher_SharkBase.Transform(A: TLong64; Log, ALog: TLogArray): TLong64;
function Mul(A, B: Integer): Byte;
begin
Result := ALog[(Log[A] + Log[B]) mod 255];
end;
var
I, J: Byte;
K, T: array[0..7] of Byte;
begin
Move(A.R, K[0], 4);
Move(A.L, K[4], 4);
SwapUInt32Buffer(K, K, 2);
for I := 0 to 7 do
begin
T[I] := Mul(Shark_I[I, 0], K[0]);
for J := 1 to 7 do
T[I] := T[I] xor Mul(Shark_I[I, J], K[J]);
end;
Result.L := T[0];
Result.R := 0;
for I := 1 to 7 do
begin
Result.R := Result.R shl 8 or Result.L shr 24;
Result.L := Result.L shl 8 xor T[I];
end;
end;
{$ELSE CPU64BITS}
function TCipher_SharkBase.Transform(A: UInt64; Log, ALog: TLogArray): UInt64;
var
I, J: Integer;
K, T: array[0..7] of Byte;
function Mul(A, B: Byte): Byte;
begin
// GF(256) multiplication via logarithm tables
Result := ALog[(Log[A] + Log[B]) mod 255];
end;
begin
for I := 0 to 7 do
K[I] := A shr (56 - 8 * i);
for I := 0 to 7 do
begin
T[I] := Mul(Shark_I[I, 0], K[0]);
for J := 1 to 7 do
T[I] := T[I] xor Mul(Shark_I[I, J], K[J]);
end;
Result := T[0];
for I := 1 to 7 do
Result := (Result shl 8) xor T[I];
end;
{$ENDIF}
{ TCipher_Shark }
class function TCipher_Shark.Context: TCipherContext;
begin
Result.KeySize := 16;
Result.BlockSize := 8;
Result.BufferSize := 8;
Result.AdditionalBufferSize := 112;
Result.NeedsAdditionalBufferBackup := False;
Result.MinRounds := 1;
Result.MaxRounds := 1;
Result.CipherType := [ctSymmetric, ctBlock];
end;
{$IFNDEF CPU64BITS}
procedure TCipher_Shark.DoInit(const Key; Size: Integer);
var
Log, ALog: TLogArray;
procedure InitLog;
var
I, J: Word;
begin
ALog[0] := 1;
for I := 1 to 255 do
begin
J := ALog[I - 1] shl 1;
if J and $100 <> 0 then
J := J xor $01F5;
ALog[I] := J;
end;
Log[0] := 0;
for I := 0 to 254 do
Log[ALog[I]] := I;
end;
var
T: array[0..6] of TLong64;
A: array[0..6] of TLong64;
K: array[0..15] of Byte;
I, J, R: Byte;
E, D: PLong64Array;
L: TLong64;
begin
FillChar(K, SizeOf(K), 0);
Move(Key, K, Size);
InitLog;
E := FAdditionalBuffer;
D := @E[7];
Move(Shark_CE[0], T, SizeOf(T));
T[6] := Transform(T[6], Log, ALog);
I := 0;
for R := 0 to 6 do
begin
A[R].L := K[I and $F];
A[R].R := 0;
Inc(I);
for J := 1 to 7 do
begin
A[R].R := A[R].R shl 8 or A[R].L shr 24;
A[R].L := A[R].L shl 8 or K[I and $F];
Inc(I);
end;
end;
L.L := 0;
L.R := 0;
L := Shark(L, @T);
E[0].L := A[0].L xor L.L;
E[0].R := A[0].R xor L.R;
for R := 1 to 6 do
begin
L := Shark(E[R - 1], @T);
E[R].L := A[R].L xor L.L;
E[R].R := A[R].R xor L.R;
end;
E[6] := Transform(E[6], Log, ALog);
D[0] := E[6];
D[6] := E[0];
for R := 1 to 5 do
D[R] := Transform(E[6-R], Log, ALog);
ProtectBuffer(T, SizeOf(T));
ProtectBuffer(A, SizeOf(A));
ProtectBuffer(K, SizeOf(K));
end;
procedure TCipher_Shark.DoEncode(Source, Dest: Pointer; Size: Integer);
var
I: Integer;
T, L, R: UInt32;
K: PUInt32Array;
begin
Assert(Size = Context.BlockSize);
K := FAdditionalBuffer;
L := PLong64(Source).L;
R := PLong64(Source).R;
for I := 0 to 4 do
begin
L := L xor K[I * 2 + 0];
R := R xor K[I * 2 + 1];
T := Shark_CE[0, R shr 23 and $1FE] xor
Shark_CE[1, R shr 15 and $1FE] xor
Shark_CE[2, R shr 7 and $1FE] xor
Shark_CE[3, R shl 1 and $1FE] xor
Shark_CE[4, L shr 23 and $1FE] xor
Shark_CE[5, L shr 15 and $1FE] xor
Shark_CE[6, L shr 7 and $1FE] xor
Shark_CE[7, L shl 1 and $1FE];
R := Shark_CE[0, R shr 23 and $1FE or 1] xor
Shark_CE[1, R shr 15 and $1FE or 1] xor
Shark_CE[2, R shr 7 and $1FE or 1] xor
Shark_CE[3, R shl 1 and $1FE or 1] xor
Shark_CE[4, L shr 23 and $1FE or 1] xor
Shark_CE[5, L shr 15 and $1FE or 1] xor
Shark_CE[6, L shr 7 and $1FE or 1] xor
Shark_CE[7, L shl 1 and $1FE or 1];
L := T;
end;
L := L xor K[10];
R := R xor K[11];
L := UInt32(Shark_SE[L shr 24 ]) shl 24 xor
UInt32(Shark_SE[L shr 16 and $FF]) shl 16 xor
UInt32(Shark_SE[L shr 8 and $FF]) shl 8 xor
UInt32(Shark_SE[L and $FF]);
R := UInt32(Shark_SE[R shr 24 ]) shl 24 xor
UInt32(Shark_SE[R shr 16 and $FF]) shl 16 xor
UInt32(Shark_SE[R shr 8 and $FF]) shl 8 xor
UInt32(Shark_SE[R and $FF]);
PLong64(Dest).L := L xor K[12];
PLong64(Dest).R := R xor K[13];
end;
procedure TCipher_Shark.DoDecode(Source, Dest: Pointer; Size: Integer);
var
I: Integer;
T, R, L: UInt32;
K: PUInt32Array;
begin
Assert(Size = Context.BlockSize);
K := @PUInt32Array(FAdditionalBuffer)[14];
L := PLong64(Source).L;
R := PLong64(Source).R;
for I := 0 to 4 do
begin
L := L xor K[I * 2 + 0];
R := R xor K[I * 2 + 1];
T := Shark_CD[0, R shr 23 and $1FE] xor
Shark_CD[1, R shr 15 and $1FE] xor
Shark_CD[2, R shr 7 and $1FE] xor
Shark_CD[3, R shl 1 and $1FE] xor
Shark_CD[4, L shr 23 and $1FE] xor
Shark_CD[5, L shr 15 and $1FE] xor
Shark_CD[6, L shr 7 and $1FE] xor
Shark_CD[7, L shl 1 and $1FE];
R := Shark_CD[0, R shr 23 and $1FE or 1] xor
Shark_CD[1, R shr 15 and $1FE or 1] xor
Shark_CD[2, R shr 7 and $1FE or 1] xor
Shark_CD[3, R shl 1 and $1FE or 1] xor
Shark_CD[4, L shr 23 and $1FE or 1] xor
Shark_CD[5, L shr 15 and $1FE or 1] xor
Shark_CD[6, L shr 7 and $1FE or 1] xor
Shark_CD[7, L shl 1 and $1FE or 1];
L := T;
end;
L := L xor K[10];
R := R xor K[11];
L := UInt32(Shark_SD[L shr 24 ]) shl 24 xor
UInt32(Shark_SD[L shr 16 and $FF]) shl 16 xor
UInt32(Shark_SD[L shr 8 and $FF]) shl 8 xor
UInt32(Shark_SD[L and $FF]);
R := UInt32(Shark_SD[R shr 24 ]) shl 24 xor
UInt32(Shark_SD[R shr 16 and $FF]) shl 16 xor
UInt32(Shark_SD[R shr 8 and $FF]) shl 8 xor
UInt32(Shark_SD[R and $FF]);
PLong64(Dest).L := L xor K[12];
PLong64(Dest).R := R xor K[13];
end;
{$ELSE CPU64BITS}
const
SHARK_ROUNDS = 6;
SHARK_ROUNDKEYS = SHARK_ROUNDS + 1;
SHARK_ROOT = $1F5; // GF(256) polynomial x^8 + x^7 + x^6 + x^5 + x^4 + x^2 + 1
function SharkEncode(D: UInt64; K: PUInt64): UInt64;
var
R: Integer;
begin
for R := 1 to SHARK_ROUNDS - 1 do
begin
D := D xor K^;
Inc(K);
D := Shark_CE[0, D shr 56 and $FF] xor
Shark_CE[1, D shr 48 and $FF] xor
Shark_CE[2, D shr 40 and $FF] xor
Shark_CE[3, D shr 32 and $FF] xor
Shark_CE[4, D shr 24 and $FF] xor
Shark_CE[5, D shr 16 and $FF] xor
Shark_CE[6, D shr 8 and $FF] xor
Shark_CE[7, D and $FF];
end;
D := D xor K^;
Inc(K);
D := UInt64(Shark_SE[D shr 56 and $FF]) shl 56 xor
UInt64(Shark_SE[D shr 48 and $FF]) shl 48 xor
UInt64(Shark_SE[D shr 40 and $FF]) shl 40 xor
UInt64(Shark_SE[D shr 32 and $FF]) shl 32 xor
UInt64(Shark_SE[D shr 24 and $FF]) shl 24 xor
UInt64(Shark_SE[D shr 16 and $FF]) shl 16 xor
UInt64(Shark_SE[D shr 8 and $FF]) shl 8 xor
UInt64(Shark_SE[D and $FF]);
Result := D xor K^;
end;
procedure TCipher_Shark.DoInit(const Key; Size: Integer);
var
Log, ALog: TLogArray;
procedure InitLog;
var
I, J: Word;
begin
// Generate GF(256) anti-logarithm and logarithm tables
ALog[0] := 1;
for I := 1 to 255 do
begin
J := ALog[I - 1] shl 1;
if J and $100 <> 0 then
J := J xor SHARK_ROOT;
ALog[I] := J;
end;
Log[0] := 0;
for I := 0 to 254 do
Log[ALog[I]] := I;
end;
var
T: array[0..SHARK_ROUNDS] of UInt64;
A: array[0..SHARK_ROUNDKEYS-1] of UInt64;
K: array[0..15] of Byte;
I, J, R: Integer;
E, D: PUInt64Array;
begin
FillChar(K, SizeOf(K), 0);
Move(Key, K, Size);
InitLog;
E := FAdditionalBuffer; // encryption round key
D := @E[SHARK_ROUNDS + 1]; // decryption round key
Move(Shark_CE[0], T, SizeOf(T));
T[SHARK_ROUNDS] := Transform(T[SHARK_ROUNDS], Log, ALog);
I := 0;
for R := 0 to High(A) do
begin
A[R] := K[I and $F];
Inc(I);
for J := 1 to 7 do
begin
A[R] := A[R] shl 8 or K[I and $F];
Inc(I);
end;
end;
E[0] := A[0] xor SharkEncode(0, @T);
for R := 1 to High(A) do
E[R] := A[R] xor SharkEncode(E[R - 1], @T);
E[SHARK_ROUNDS] := Transform(E[SHARK_ROUNDS], Log, ALog);
D[0] := E[SHARK_ROUNDS];
D[SHARK_ROUNDS] := E[0];
for R := 1 to SHARK_ROUNDS - 1 do
D[R] := Transform(E[SHARK_ROUNDS - R], Log, ALog);
ProtectBuffer(T, SizeOf(T));
ProtectBuffer(A, SizeOf(A));
ProtectBuffer(K, SizeOf(K));
end;
procedure TCipher_Shark.DoEncode(Source, Dest: Pointer; Size: Integer);
begin
Assert(Size = Context.BufferSize);
PUInt64(Dest)^ := SharkEncode(PUInt64(Source)^, FAdditionalBuffer);
end;
procedure TCipher_Shark.DoDecode(Source, Dest: Pointer; Size: Integer);
var
R: Integer;
D: UInt64;
K: PUInt64;
begin
Assert(Size = Context.BufferSize);
D := PUInt64(Source)^;
K := @PUInt64Array(FAdditionalBuffer)[SHARK_ROUNDS + 1]; // decryption round key
for R := 1 to SHARK_ROUNDS - 1 do
begin
D := D xor K^;
Inc(K);
D := Shark_CD[0, D shr 56 and $FF] xor
Shark_CD[1, D shr 48 and $FF] xor
Shark_CD[2, D shr 40 and $FF] xor
Shark_CD[3, D shr 32 and $FF] xor
Shark_CD[4, D shr 24 and $FF] xor
Shark_CD[5, D shr 16 and $FF] xor
Shark_CD[6, D shr 8 and $FF] xor
Shark_CD[7, D and $FF];
end;
D := D xor K^;
Inc(K);
D := UInt64(Shark_SD[D shr 56 and $FF]) shl 56 xor
UInt64(Shark_SD[D shr 48 and $FF]) shl 48 xor
UInt64(Shark_SD[D shr 40 and $FF]) shl 40 xor
UInt64(Shark_SD[D shr 32 and $FF]) shl 32 xor
UInt64(Shark_SD[D shr 24 and $FF]) shl 24 xor
UInt64(Shark_SD[D shr 16 and $FF]) shl 16 xor
UInt64(Shark_SD[D shr 8 and $FF]) shl 8 xor
UInt64(Shark_SD[D and $FF]);
PUInt64(Dest)^ := D xor K^;
end;
{$ENDIF CPU64BITS}
{ TCipher_Shark_DEC52 }
{$IFNDEF CPU64BITS}
procedure TCipher_Shark_DEC52.DoInit(const Key; Size: Integer);
var
Log, ALog: TLogArray;
procedure InitLog;
var
I, J: Word;
begin
ALog[0] := 1;
for I := 1 to 255 do
begin
J := ALog[I - 1] shl 1;
if J and $100 <> 0 then
J := J xor $01F5;
ALog[I] := J;
end;
for I := 1 to 254 do
Log[ALog[I]] := I;
end;
var
T: array[0..6] of TLong64;
A: array[0..6] of TLong64;
K: array[0..15] of Byte;
I, J, R: Byte;
E, D: PLong64Array;
L: TLong64;
begin
FillChar(K, SizeOf(K), 0);
Move(Key, K, Size);
InitLog;
E := FAdditionalBuffer;
D := @E[7];
Move(Shark_CE[0], T, SizeOf(T));
T[6] := Transform(T[6], Log, ALog);
I := 0;
for R := 0 to 6 do
begin
Inc(I);
A[R].L := K[I and $F];
A[R].R := 0;
for J := 1 to 7 do
begin
Inc(I);
A[R].R := A[R].R shl 8 or A[R].L shr 24;
A[R].L := A[R].L shl 8 or K[I and $F];
end;
end;
L.L := 0;
L.R := 0;
L := Shark(L, @T);
E[0].L := A[0].L xor L.L;
E[0].R := A[0].R xor L.R;
for R := 1 to 6 do
begin
L := Shark(E[R - 1], @T);
E[R].L := A[R].L xor L.L;
E[R].R := A[R].R xor L.R;
end;
E[6] := Transform(E[6], Log, ALog);
D[0] := E[6];
D[6] := E[0];
for R := 1 to 5 do
D[R] := Transform(E[6-R], Log, ALog);
ProtectBuffer(T, SizeOf(T));
ProtectBuffer(A, SizeOf(A));
ProtectBuffer(K, SizeOf(K));
end;
{$ELSE CPU64BITS}
procedure TCipher_Shark_DEC52.DoInit(const Key; Size: Integer);
var
Log, ALog: TLogArray;
procedure InitLog;
var
I, J: Word;
begin
// Generate GF(256) anti-logarithm and logarithm tables
ALog[0] := 1;
for I := 1 to 255 do
begin
J := ALog[I - 1] shl 1;
if J and $100 <> 0 then
J := J xor SHARK_ROOT;
ALog[I] := J;
end;
for I := 1 to 254 do
Log[ALog[I]] := I;
end;
var
T: array[0..SHARK_ROUNDS] of UInt64;
A: array[0..SHARK_ROUNDKEYS-1] of UInt64;
K: array[0..15] of Byte;
I, J, R: Integer;
E, D: PUInt64Array;
begin
FillChar(K, SizeOf(K), 0);
Move(Key, K, Size);
InitLog;
E := FAdditionalBuffer; // encryption round key
D := @E[SHARK_ROUNDS + 1]; // decryption round key
Move(Shark_CE[0], T, SizeOf(T));
T[SHARK_ROUNDS] := Transform(T[SHARK_ROUNDS], Log, ALog);
I := 0;
for R := 0 to High(A) do
begin
Inc(I);
A[R] := K[I and $F];
for J := 1 to 7 do
begin
Inc(I);
A[R] := A[R] shl 8 or K[I and $F];
end;
end;
E[0] := A[0] xor SharkEncode(0, @T);
for R := 1 to High(A) do
E[R] := A[R] xor SharkEncode(E[R - 1], @T);
E[SHARK_ROUNDS] := Transform(E[SHARK_ROUNDS], Log, ALog);
D[0] := E[SHARK_ROUNDS];
D[SHARK_ROUNDS] := E[0];
for R := 1 to SHARK_ROUNDS - 1 do
D[R] := Transform(E[SHARK_ROUNDS - R], Log, ALog);
ProtectBuffer(T, SizeOf(T));
ProtectBuffer(A, SizeOf(A));
ProtectBuffer(K, SizeOf(K));
end;
{$ENDIF}
{ TCipher_Skipjack }
class function TCipher_Skipjack.Context: TCipherContext;
begin
Result.KeySize := 10;
Result.BlockSize := 8;
Result.BufferSize := 8;
Result.AdditionalBufferSize := $A00;
Result.NeedsAdditionalBufferBackup := false;
Result.MinRounds := 1;
Result.MaxRounds := 1;
Result.CipherType := [ctSymmetric, ctBlock];
end;
procedure TCipher_Skipjack.DoInit(const Key; Size: Integer);
var
K: array[0..9] of Byte;
D: PByte;
I, J: Integer;
begin
FillChar(K, SizeOf(K), 0);
Move(Key, K, Size);
D := FAdditionalBuffer;
for I := 0 to 9 do
for J := 0 to 255 do
begin
D^ := Skipjack_Data[J xor K[I]];
Inc(D);
end;
ProtectBuffer(K, SizeOf(K));
end;
procedure TCipher_Skipjack.DoEncode(Source, Dest: Pointer; Size: Integer);
var
Tab, Min: PSkipjackTab;
Max: PByte;
K, T, A, B, C, D: UInt32;
begin
Assert(Size = Context.BlockSize);
Min := FAdditionalBuffer;
Max := PByte(Min) + 9 * 256; // for Pointer Math
Tab := Min;
A := Swap(PWordArray(Source)[0]);
B := Swap(PWordArray(Source)[1]);
C := Swap(PWordArray(Source)[2]);
D := Swap(PWordArray(Source)[3]);
K := 0;
repeat
Inc(K);
T := A;
T := T xor Tab[T and $FF] shl 8; SkipjackIncCheck(Tab, Min, Max);
T := T xor Tab[T shr 8]; SkipjackIncCheck(Tab, Min, Max);
T := T xor Tab[T and $FF] shl 8; SkipjackIncCheck(Tab, Min, Max);
T := T xor Tab[T shr 8]; SkipjackIncCheck(Tab, Min, Max);
A := T xor D xor K;
D := C;
C := B;
B := T;
until K = 8;
repeat
Inc(K);
T := A;
A := D;
D := C;
C := T xor B xor K;
T := T xor Tab[T and $FF] shl 8; SkipjackIncCheck(Tab, Min, Max);
T := T xor Tab[T shr 8]; SkipjackIncCheck(Tab, Min, Max);
T := T xor Tab[T and $FF] shl 8; SkipjackIncCheck(Tab, Min, Max);
T := T xor Tab[T shr 8]; SkipjackIncCheck(Tab, Min, Max);
B := T;
until K = 16;
repeat
Inc(K);
T := A;
T := T xor Tab[T and $FF] shl 8; SkipjackIncCheck(Tab, Min, Max);
T := T xor Tab[T shr 8]; SkipjackIncCheck(Tab, Min, Max);
T := T xor Tab[T and $FF] shl 8; SkipjackIncCheck(Tab, Min, Max);
T := T xor Tab[T shr 8]; SkipjackIncCheck(Tab, Min, Max);
A := T xor D xor K;
D := C;
C := B;
B := T;
until K = 24;
repeat
Inc(K);
T := A;
A := D;
D := C;
C := T xor B xor K;
T := T xor Tab[T and $FF] shl 8; SkipjackIncCheck(Tab, Min, Max);
T := T xor Tab[T shr 8]; SkipjackIncCheck(Tab, Min, Max);
T := T xor Tab[T and $FF] shl 8; SkipjackIncCheck(Tab, Min, Max);
T := T xor Tab[T shr 8]; SkipjackIncCheck(Tab, Min, Max);
B := T;
until K = 32;
PWordArray(Dest)[0] := Swap(A);
PWordArray(Dest)[1] := Swap(B);
PWordArray(Dest)[2] := Swap(C);
PWordArray(Dest)[3] := Swap(D);
end;
procedure TCipher_Skipjack.SkipjackIncCheck(var ATab: PSkipjackTab; AMin: PSkipjackTab; AMax: PByte);
begin
Inc(ATab);
if PByte(ATab) > AMax then
ATab := AMin;
end;
procedure TCipher_Skipjack.DoDecode(Source, Dest: Pointer; Size: Integer);
var
Tab, Max: PSkipjackTab;
Min: PByte; // for Pointer Math
K, T, A, B, C, D: UInt32;
begin
Assert(Size = Context.BlockSize);
Min := FAdditionalBuffer;
Max := Pointer(Min + 9 * 256);
Tab := Pointer(Min + 7 * 256);
A := Swap(PWordArray(Source)[0]); // holds an Integer, Compiler makes faster Code
B := Swap(PWordArray(Source)[1]);
C := Swap(PWordArray(Source)[2]);
D := Swap(PWordArray(Source)[3]);
K := 32;
repeat
T := B;
T := T xor Tab[T shr 8]; SkipjackDecCheck(Tab, Min, Max);
T := T xor Tab[T and $FF] shl 8; SkipjackDecCheck(Tab, Min, Max);
T := T xor Tab[T shr 8]; SkipjackDecCheck(Tab, Min, Max);
T := T xor Tab[T and $FF] shl 8; SkipjackDecCheck(Tab, Min, Max);
B := T xor C xor K;
C := D;
D := A;
A := T;
Dec(K);
until K = 24;
repeat
T := B;
B := C;
C := D;
D := T xor A xor K;
T := T xor Tab[T shr 8]; SkipjackDecCheck(Tab, Min, Max);
T := T xor Tab[T and $FF] shl 8; SkipjackDecCheck(Tab, Min, Max);
T := T xor Tab[T shr 8]; SkipjackDecCheck(Tab, Min, Max);
T := T xor Tab[T and $FF] shl 8; SkipjackDecCheck(Tab, Min, Max);
A := T;
Dec(K);
until K = 16;
repeat
T := B;
T := T xor Tab[T shr 8]; SkipjackDecCheck(Tab, Min, Max);
T := T xor Tab[T and $FF] shl 8; SkipjackDecCheck(Tab, Min, Max);
T := T xor Tab[T shr 8]; SkipjackDecCheck(Tab, Min, Max);
T := T xor Tab[T and $FF] shl 8; SkipjackDecCheck(Tab, Min, Max);
B := C xor T xor K;
C := D;
D := A;
A := T;
Dec(K);
until K = 8;
repeat
T := B;
B := C;
C := D;
D := T xor A xor K;
T := T xor Tab[T shr 8]; SkipjackDecCheck(Tab, Min, Max);
T := T xor Tab[T and $FF] shl 8; SkipjackDecCheck(Tab, Min, Max);
T := T xor Tab[T shr 8]; SkipjackDecCheck(Tab, Min, Max);
T := T xor Tab[T and $FF] shl 8; SkipjackDecCheck(Tab, Min, Max);
A := T;
Dec(K);
until K = 0;
PWordArray(Dest)[0] := Swap(A);
PWordArray(Dest)[1] := Swap(B);
PWordArray(Dest)[2] := Swap(C);
PWordArray(Dest)[3] := Swap(D);
end;
procedure TCipher_Skipjack.SkipjackDecCheck(var ATab: PSkipjackTab; AMin: PByte; AMax: PSkipjackTab);
begin
Dec(ATab);
// {$IFDEF DELPHIORBCB}
// if ATab < AMin then
// {$ELSE !DELPHIORBCB}
{ TODO : Prüfen ob so korrekt, da ATab auf PByte umgestellt wurde, außerdem sollte
diese interne procedure eher zu einer strict private methode werden}
if PByte(ATab) < AMin then
// {$ENDIF !DELPHIORBCB}
ATab := AMax;
end;
{ TCipher_TEA }
const
TEA_Delta = $9E3779B9; // magic constant, decimal 2654435769
class function TCipher_TEA.Context: TCipherContext;
begin
Result.KeySize := 16; // 128 bits
Result.BlockSize := 8; // 64 bits
Result.BufferSize := 8; // 64 bits
Result.AdditionalBufferSize := 32; // 256 bits
Result.NeedsAdditionalBufferBackup := false;
Result.MinRounds := 16;
Result.MaxRounds := 256;
Result.CipherType := [ctSymmetric, ctBlock];
end;
procedure TCipher_TEA.SetRounds(Value: Integer);
begin
if not (FState in [csNew, csInitialized, csDone]) then
Done;
if Value < 16 then
Value := 16
else
if Value > 256 then
Value := 256;
FRounds := Value;
end;
procedure TCipher_TEA.DoInit(const Key; Size: Integer);
begin
Move(Key, FAdditionalBuffer^, Size);
SetRounds(FRounds);
end;
procedure TCipher_TEA.DoEncode(Source, Dest: Pointer; Size: Integer);
var
I: Integer;
Sum,
X, Y, A, B, C, D: UInt32;
begin
Assert(Size = Context.BlockSize);
Sum := 0;
A := PUInt32Array(FAdditionalBuffer)[0];
B := PUInt32Array(FAdditionalBuffer)[1];
C := PUInt32Array(FAdditionalBuffer)[2];
D := PUInt32Array(FAdditionalBuffer)[3];
X := PUInt32Array(Source)[0];
Y := PUInt32Array(Source)[1];
for I := 0 to FRounds - 1 do
begin
Inc(Sum, TEA_Delta);
Inc(X, (((Y shl 4 + A) xor Y) + Sum) xor (Y shr 5 + B));
Inc(Y, (((X shl 4 + C) xor X) + Sum) xor (X shr 5 + D));
end;
PUInt32Array(Dest)[0] := X;
PUInt32Array(Dest)[1] := Y;
end;
procedure TCipher_TEA.DoDecode(Source, Dest: Pointer; Size: Integer);
var
I: Integer;
Sum,
X, Y, A, B, C, D: UInt32;
begin
Assert(Size = Context.BlockSize);
Sum := TEA_Delta * UInt32(FRounds);
A := PUInt32Array(FAdditionalBuffer)[0];
B := PUInt32Array(FAdditionalBuffer)[1];
C := PUInt32Array(FAdditionalBuffer)[2];
D := PUInt32Array(FAdditionalBuffer)[3];
X := PUInt32Array(Source)[0];
Y := PUInt32Array(Source)[1];
for I := 0 to FRounds - 1 do
begin
Dec(Y, (X shl 4 + C) xor X + Sum xor (X shr 5 + D));
Dec(X, (Y shl 4 + A) xor Y + Sum xor (Y shr 5 + B));
Dec(Sum, TEA_Delta);
end;
PUInt32Array(Dest)[0] := X;
PUInt32Array(Dest)[1] := Y;
end;
{ TCipher_XTEA }
procedure TCipher_XTEA.DoEncode(Source, Dest: Pointer; Size: Integer);
var
Sum,
I, X, Y: UInt32;
K: PUInt32Array;
begin
Assert(Size = Context.BlockSize);
Sum := 0;
X := PUInt32Array(Source)[0];
Y := PUInt32Array(Source)[1];
K := FAdditionalBuffer;
for I := 0 to FRounds - 1 do
begin
Inc(X, (((Y shl 4) xor (Y shr 5)) + Y) xor (Sum + K[Sum and 3]));
Inc(Sum, TEA_Delta);
Inc(Y, (((X shl 4) xor (X shr 5)) + X) xor (Sum + K[Sum shr 11 and 3]));
end;
PUInt32Array(Dest)[0] := X;
PUInt32Array(Dest)[1] := Y;
end;
procedure TCipher_XTEA.DoDecode(Source, Dest: Pointer; Size: Integer);
var
I: Integer;
Sum,
X, Y: UInt32;
K: PUInt32Array;
begin
Assert(Size = Context.BlockSize);
Sum := TEA_Delta * UInt32(FRounds);
X := PUInt32Array(Source)[0];
Y := PUInt32Array(Source)[1];
K := FAdditionalBuffer;
for I := 0 to FRounds - 1 do
begin
Dec(Y, (((X shl 4) xor (X shr 5)) + X) xor (Sum + K[Sum shr 11 and 3]));
Dec(Sum, TEA_Delta);
Dec(X, (((Y shl 4) xor (Y shr 5)) + Y) xor (Sum + K[Sum and 3]));
end;
PUInt32Array(Dest)[0] := X;
PUInt32Array(Dest)[1] := Y;
end;
{ TCipher_XTEA_DEC52 }
{ TODO : The old failure needs to be restored again }
procedure TCipher_XTEA_DEC52.DoEncode(Source, Dest: Pointer; Size: Integer);
var
Sum,
I, X, Y: UInt32;
K: PUInt32Array;
begin
Assert(Size = Context.BlockSize);
Sum := 0;
X := PUInt32Array(Source)[0];
Y := PUInt32Array(Source)[1];
K := FAdditionalBuffer;
for I := 0 to FRounds - 1 do
begin
Inc(X, (Y shl 4 xor Y shr 5) + (Y xor Sum) + K[Sum and 3]);
Inc(Sum, TEA_Delta);
Inc(Y, (X shl 4 xor X shr 5) + (X xor Sum) + K[Sum shr 11 and 3]);
end;
PUInt32Array(Dest)[0] := X;
PUInt32Array(Dest)[1] := Y;
end;
procedure TCipher_XTEA_DEC52.DoDecode(Source, Dest: Pointer; Size: Integer);
var
I: Integer;
Sum,
X, Y: UInt32;
K: PUInt32Array;
begin
Assert(Size = Context.BlockSize);
Sum := TEA_Delta * UInt32(FRounds);
X := PUInt32Array(Source)[0];
Y := PUInt32Array(Source)[1];
K := FAdditionalBuffer;
for I := 0 to FRounds - 1 do
begin
Dec(Y, (X shl 4 xor X shr 5) + (X xor Sum) + K[Sum shr 11 and 3]);
Dec(Sum, TEA_Delta);
Dec(X, (Y shl 4 xor Y shr 5) + (Y xor Sum) + K[Sum and 3]);
end;
PUInt32Array(Dest)[0] := X;
PUInt32Array(Dest)[1] := Y;
end;
{$IFDEF RESTORE_RANGECHECKS}{$R+}{$ENDIF}
{$IFDEF RESTORE_OVERFLOWCHECKS}{$Q+}{$ENDIF}
initialization
SetDefaultCipherClass(TCipher_Null);
{$IFNDEF ManualRegisterClasses}
TCipher_Null.RegisterClass(TDECCipher.ClassList);
TCipher_Blowfish.RegisterClass(TDECCipher.ClassList);
TCipher_Twofish.RegisterClass(TDECCipher.ClassList);
TCipher_IDEA.RegisterClass(TDECCipher.ClassList);
TCipher_Cast256.RegisterClass(TDECCipher.ClassList);
TCipher_Mars.RegisterClass(TDECCipher.ClassList);
TCipher_RC4.RegisterClass(TDECCipher.ClassList);
TCipher_RC6.RegisterClass(TDECCipher.ClassList);
// Explicitely not registered, as Rijndael is 1:1 the same as AES and AES is the
// more common name
// TCipher_Rijndael.RegisterClass(TDECCipher.ClassList);
TCipher_AES.RegisterClass(TDECCipher.ClassList);
TCipher_Square.RegisterClass(TDECCipher.ClassList);
TCipher_SCOP.RegisterClass(TDECCipher.ClassList);
TCipher_Sapphire.RegisterClass(TDECCipher.ClassList);
TCipher_1DES.RegisterClass(TDECCipher.ClassList);
TCipher_2DES.RegisterClass(TDECCipher.ClassList);
TCipher_3DES.RegisterClass(TDECCipher.ClassList);
TCipher_2DDES.RegisterClass(TDECCipher.ClassList);
TCipher_3DDES.RegisterClass(TDECCipher.ClassList);
TCipher_3TDES.RegisterClass(TDECCipher.ClassList);
TCipher_3Way.RegisterClass(TDECCipher.ClassList);
TCipher_Cast128.RegisterClass(TDECCipher.ClassList);
TCipher_Gost.RegisterClass(TDECCipher.ClassList);
// Explicitely not registered, as this is an alias for Gost only
// TCipher_Magma.RegisterClass(TDECCipher.ClassList);
TCipher_Misty.RegisterClass(TDECCipher.ClassList);
TCipher_NewDES.RegisterClass(TDECCipher.ClassList);
TCipher_Q128.RegisterClass(TDECCipher.ClassList);
TCipher_RC2.RegisterClass(TDECCipher.ClassList);
TCipher_RC5.RegisterClass(TDECCipher.ClassList);
TCipher_SAFER.RegisterClass(TDECCipher.ClassList);
TCipher_Shark.RegisterClass(TDECCipher.ClassList);
TCipher_Skipjack.RegisterClass(TDECCipher.ClassList);
TCipher_TEA.RegisterClass(TDECCipher.ClassList);
TCipher_XTEA.RegisterClass(TDECCipher.ClassList);
TCipher_TEAN.RegisterClass(TDECCipher.ClassList);
{$IFDEF OLD_REGISTER_FAULTY_CIPHERS}
// Those classes are only there for those who might have relied on the
// faulty implementation
TCipher_SCOP_DEC52.RegisterClass(TDECCipher.ClassList);
TCipher_Shark_DEC52.RegisterClass(TDECCipher.ClassList);
TCipher_XTEA_DEC52.RegisterClass(TDECCipher.ClassList);
{$ENDIF}
{$ENDIF}
finalization
end.