Base64_to_stream Turbo power Lockbox 3.6.2 Delphi Xe7 | E2010 不兼容的类型:'System.TArray<System.Byte>' 和 'string'
Base64_to_stream Turbo power Lockbox 3.6.2 Delphi Xe7 | E2010 Incompatible types: 'System.TArray<System.Byte>' and 'string'
我正在尝试使程序在 delphi XE7 上加密并在 PHP 端解密
我使用使用 AES 256 加密 CBC 模式的密码箱 3.6.2。
Delphi XE7 代码:
Main.pas
unit Main;
interface
uses
System.SysUtils, System.Types, System.UITypes, System.Classes,
System.Variants,
FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics, FMX.Dialogs,
TPLB3.CryptographicLibrary, TPLB3.BaseNonVisualComponent, TPLB3.Codec,
FMX.StdCtrls, FMX.Controls.Presentation, FMX.Edit, System.Actions,
FMX.ActnList, FMX.Menus, FMX.ExtCtrls, FMX.Layouts, FMX.Memo;
type
TForm2 = class(TForm)
codecAES: TCodec;
cryptoMain: TCryptographicLibrary;
btnEncrypt: TButton;
actlstMain: TActionList;
edtSeed: TEdit;
edtPassword: TEdit;
rgCipher: TPopupBox;
rgChainMode: TPopupBox;
rgTestVectors: TPopupBox;
btnRandomize: TButton;
memoOutput: TMemo;
memoPlaintext: TMemo;
Action1: TAction;
Action2: TAction;
procedure actEncryptUpdate(Sender: TObject);
procedure actEncryptExecute(Sender: TObject);
procedure FormCreate(Sender: TObject);
procedure rgTestVectorsClick(Sender: TObject);
procedure rgChainModeClick(Sender: TObject);
procedure actRandomizeUpdate(Sender: TObject);
procedure actRandomizeExecute(Sender: TObject);
private
procedure LogFmt(const sLine: string; const Args: array of const);
function SpaceOut(const sCompacted: string): string;
public
{ Public declarations }
end;
var
Form2: TForm2;
implementation
uses uTPLb_Random, uTPLb_StreamUtils, uTPLb_Constants;
{$R *.fmx}
function StreamToHex(Data: TStream): string;
var
b: byte;
sByte: string;
begin
Data.Position := 0;
result := '';
while Data.Read(b, 1) = 1 do
begin
sByte := Format('%x', [b]);
if Odd(Length(sByte)) then
sByte := '0' + sByte;
result := result + sByte
end
end;
procedure TForm2.actEncryptExecute(Sender: TObject);
const
TestCaseNames: array [0 .. 2] of string = ('Test Vector 1', 'Test Vector 2',
'Custom');
var
usPlaintext: String;
aCiphertext: string;
OriginalSeed: int64;
stmCipher: TStream;
FEncoding : TEncoding;
sHex: string;
begin
memoOutput.Lines.Clear;
case rgCipher.ItemIndex of
0:
codecAES.BlockCipherId := Format(AES_ProgId, [128]);
end;
case rgChainMode.ItemIndex of
0:
codecAES.ChainModeId := CFB_ProgId;
1:
codecAES.ChainModeId := CBC_ProgId;
2:
codecAES.ChainModeId := ECB_ProgId;
end;
codecAES.UTF8Password := edtPassword.Text;
usPlaintext := memoPlaintext.Lines.Text;
OriginalSeed := StrToInt64(edtSeed.Text);
TRandomStream.Instance.Seed := OriginalSeed;
codecAES.EncryptString(usPlaintext, aCiphertext, FEncoding.UTF8);
// NextSeed := TRandomStream.Instance.Seed;
LogFmt('Test case = %s', [TestCaseNames[rgTestVectors.ItemIndex]]);
LogFmt('Cipher = %s', [codecAES.Cipher]);
LogFmt('Chain mode = %s', [codecAES.ChainMode]);
LogFmt('PRNG seed = %d', [OriginalSeed]);
LogFmt('Passord (UTF-8) = ''%s''', [codecAES.UTF8Password]);
LogFmt('------------', []);
stmCipher := TMemoryStream.Create;
codecAES.Key.SaveToStream(stmCipher);
sHex := StreamToHex(stmCipher);
stmCipher.Free;
LogFmt('key as hex = %s', [sHex]);
LogFmt('Plaintext (UTF-8)', []);
LogFmt('''%s''', [usPlaintext]);
LogFmt('------------', []);
LogFmt('ciphertext (base64) [Includes prepended IV and block quantisation] =',
[]);
LogFmt(' ''%s''', [SpaceOut(aCiphertext)]);
LogFmt('------------', []);
stmCipher := TMemoryStream.Create;
Base64_to_stream(aCiphertext, stmCipher);
sHex := StreamToHex(stmCipher);
stmCipher.Free;
LogFmt('ciphertext (hex) [Includes prepended IV and block quantisation] =', []
);
LogFmt(' ''%s''', [SpaceOut(sHex)]);
LogFmt('------------', []);
end;
procedure TForm2.actEncryptUpdate(Sender: TObject);
begin
//
end;
procedure TForm2.actRandomizeExecute(Sender: TObject);
begin
TRandomStream.Instance.Randomize;
edtSeed.Text := IntToStr(TRandomStream.Instance.Seed)
end;
procedure TForm2.actRandomizeUpdate(Sender: TObject);
begin
(Sender as TAction).Enabled := rgTestVectors.ItemIndex = 2
end;
procedure TForm2.FormCreate(Sender: TObject);
begin
memoOutput.Lines.Clear;
LogFmt('Select test case and chain mode.', []);
LogFmt('Enter password and plaintext message and then press the ''Encrypt'' button.',
[]);
end;
procedure TForm2.LogFmt(const sLine: string; const Args: array of const);
begin
memoOutput.Lines.Add(Format(sLine, Args))
end;
procedure TForm2.rgChainModeClick(Sender: TObject);
begin
//
end;
procedure TForm2.rgTestVectorsClick(Sender: TObject);
var
isCustom: boolean;
begin
case rgTestVectors.ItemIndex of
0:
begin
edtPassword.Text := 'Your lips are smoother than vasoline.';
memoPlaintext.Lines.Text := 'Leeeeeeeeeroy Jenkins!';
// Above is constrained to:
// More than 16 and not a whole multiple of 16 bytes as UTF-8.
edtSeed.Text := '1';
rgChainMode.ItemIndex := 0;
rgCipher.ItemIndex := 0;
end;
1:
begin
edtPassword.Text := 'ORATIO IN L. CATILINAM PRIMA';
memoPlaintext.Lines.Text := 'Quo usque tandem abutere, Catili';
// Above is constrained to:
// A whole multiple of 16 bytes as UTF-8, excluding the empty case.
edtSeed.Text := '333';
rgChainMode.ItemIndex := 0;
rgCipher.ItemIndex := 0
end;
2:
;
end;
isCustom := rgTestVectors.ItemIndex = 2;
edtPassword.ReadOnly := not isCustom;
memoPlaintext.ReadOnly := not isCustom;
edtSeed.ReadOnly := not isCustom;
rgChainMode.Enabled := isCustom;
rgCipher.Enabled := isCustom
end;
function TForm2.SpaceOut(const sCompacted: string): string;
const
NewLineSpacing = 70;
BunchSpacing = 6;
var
i, j: integer;
begin
SetLength(result, 2 * Length(sCompacted));
i := 1;
for j := 1 to Length(sCompacted) do
begin
if ((j mod NewLineSpacing) = 1) and (j <> 1) then
begin
result[i] := #13;
Inc(i);
result[i] := #10;
Inc(i)
end
else if ((j mod BunchSpacing) = 1) and (j <> 1) then
begin
result[i] := ' ';
Inc(i)
end;
result[i] := sCompacted[j];
Inc(i)
end;
SetLength(result, i - 1)
end;
end.
它无法编译给出休闲错误:
[dcc32 Error] Main.pas(125): E2010 Incompatible types: 'System.TArray<System.Byte>' and 'string'
和PHP方面:
<!DOCTYPE html>
<html lang="en">
<head>
<META HTTP-EQUIV="CONTENT-TYPE" CONTENT="text/html; charset=UTF-8">
<META NAME="ROBOTS" CONTENT="NOINDEX,NOFOLLOW,NOARCHIVE" />
<META NAME="DESCRIPTION" CONTENT="Tutorial and demostration page for Delphi (TurboPower LockBox3) to PHP symetric cryptography." />
<META NAME="AUTHOR" CONTENT="Sean B. Durkin">
<META HTTP-EQUIV="CACHE-CONTROL" CONTENT="NO-CACHE">
<META NAME="KEYWORDS" CONTENT="cryptography,delphi,php,turbopower,lockbox,lockbox3">
<title>Delphi-to-PHP Cryptography Tutorial</title>
<link rel="stylesheet" media="screen and (min-device-width: 721px)" href="tut.css" /><!-- <== Desktop. -->
<link rel="stylesheet" media="screen and (max-device-width: 720px)" href="tut-phone.css" / --><!-- <== Phone and tablet. -->
<head>
<body>
<?php
error_reporting(E_ALL | E_COMPILE_ERROR);
$password = $_GET["password"];
$ciphertext_trans = $_GET["ciphertext-trans"];
$rawInputCiphertext = $_GET["ciphertext"];
$chain = $_GET["chain"];
$cipherIn = $_GET["cipherIn"];
function radioChecked($param,$value,$isDefault)
{
$echo = (($param == $value) or ($isDefault and ($param == ''))) ? ' checked="checked" ' : '';
echo $echo;
return $echo != '';
}
?>
<nav>
<div class="nav-bg"></div>
<div class="nav-content">
<h1><a href="http://lockbox.seanbdurkin.id.au/tiki-index.php?page=Delphi-to-PHP+Tutorial+project+home" title="Go to The Delphi-to-PHP project home"><span class="hidden">Project home</span></a></h1>
<dl>
<dt>Date created</dt>
<dd><time datetime="2012-11-29">29-Nov-2012</time></dd>
</dl>
<dl>
<dt>Date last modified</dt>
<dd><time datetime="2012-12-02">2-Dec-2012</time></dd>
</dl>
</div>
</nav>
<h1>Decrypt with PHP from Delphi (TurboPower LockBox3)</h1>
<form id="plainForm" class="floatbox" action="">
<fieldset>
<legend>Crypto data</legend>
<label class="first" for="password">Password (UTF-8)
<input id="password" name="password" type="text" placeholder="Enter TCodec password" value="<?php echo htmlspecialchars($password) ?>" />
</label>
<fieldset class="radio">
<legend>Transport encoding</legend>
<label for="ciphertext-trans-base64">
<input id="ciphertext-trans-base64" name="ciphertext-trans" type="radio" value="base64"
<?php radioChecked($ciphertext_trans,'base64',True); ?> />base64
</label>
<label for="ciphertext-trans-hex">
<input id="ciphertext-trans-hex" name="ciphertext-trans" type="radio" value="hex"
<?php radioChecked($ciphertext_trans,'hex',False); ?> />hex
</label>
</fieldset>
<label for="ciphertext">Ciphertext (transport encoded)
<input id="ciphertext" name="ciphertext" type="text" placeholder="Paste ciphertext here" value="<?php echo htmlspecialchars($rawInputCiphertext) ?>" />
</label>
</fieldset>
<fieldset>
<legend>Options</legend>
<fieldset class="radio">
<legend>Chaining mode</legend>
<label for="chain-cfb">
<input id="chain-cfb" name="chain" type="radio"
value="CFB" <?php radioChecked($chain,'CFB',True); ?> />CFB
</label>
<label for="chain-cbc">
<input id="chain-cbc" name="chain" type="radio"
value="CBC" <?php radioChecked($chain,'CBC',False); ?> />CBC
</label>
<label for="chain-ecb">
<input id="chain-ecb" name="chain" type="radio"
value="ECB" <?php radioChecked($chain,'ECB',False); ?> />ECB
</label>
</fieldset>
<fieldset class="radio">
<legend>Cipher</legend>
<label for="aes-128">
<input id="aes-128" name="cipherIn" type="radio"
value="AES-128" <?php radioChecked($cipherIn,'AES-128',True); ?> />AES-128
</label>
<!-- Extend here with more ciphers as required. Note: PHP does not support AES-256. -->
</fieldset>
</fieldset>
<input class="submit" type="submit" value="Decrypt" />
</form>
<?php if ($chain) { ?>
<?php
function purgeWhiteSpace($sparseHex)
{
return preg_replace('/\s+/', '', $sparseHex);
}
function expandWithWhiteSpace($compactHex)
{
// TODO: Insert white space for visual benefit. Bunch the brown spaces
// into words of 6 characters, and then separate words with a single space.
// Between every 10th word and 11th word, use a new-line ([=17=]D) instead of space.
// Assume that $compactHex ONLY consists of characters 0..9 and A..F .
return $compactHex;
}
function displayableMultiline($str)
{
// TODO: Assume $str ONLY consists of characters whose code-points are below
// 137. Insert '<br />' before each [=17=]D character.
return $str;
}
function hexToStr($hex)
{
$hex2 = purgeWhiteSpace( $hex);
$str='';
for ($i=0; $i < strlen($hex2)-1; $i+=2)
{
$str .= chr(hexdec($hex2[$i].$hex2[$i+1]));
}
return $str;
}
function strToHex($str)
{
$hex='';
for ($i=0; $i < strlen($str); $i++)
{
$addend = dechex(ord($str[$i]));
if (strlen($addend) < 2)
$addend = '0' . $addend;
$hex .= $addend;
}
return $hex;
}
$normalisedRawCiphertext = purgeWhiteSpace( $rawInputCiphertext);
if ($ciphertext_trans == 'base64')
{
$ciphertext = base64_decode( $normalisedRawCiphertext);
}
else
{
$ciphertext = hexToStr( $normalisedRawCiphertext);
}
if ($cipherIn == 'AES-128')
{
$cipher = MCRYPT_RIJNDAEL_128;
$cipherName = 'AES-128';
}
else
{
// Extend here with more ciphers as required. Note: PHP does not support AES-256.
$cipher = MCRYPT_RIJNDAEL_128; // Example only.
$cipherName = '???'; // Example only.
}
if ($chain == 'CFB')
$mode = 'ncfb'; // Proper block-mode CFB. There is no constant for this.
else if ($chain == 'CBC')
$mode = MCRYPT_MODE_CBC;
else
$mode = MCRYPT_MODE_ECB;
$blockSize = mcrypt_get_block_size( $cipher, $mode);
$keySize = mcrypt_get_key_size( $cipher, $mode);
// Work-around PHP bugs.
if (($cipher == MCRYPT_RIJNDAEL_128) and ($keySize == 32))
{ $keySize = 16; } // AES-128 key size is 16 bytes.
if (($cipher == MCRYPT_RIJNDAEL_256) and ($blockSize == 32))
{ $blockSize = 16; } // AES-256 block size is 16 bytes.
$ivSize = $blockSize; // Always. mcrypt_get_iv_size() is pointless.
if ($chain == 'ECB')
{
$iv = str_pad( 'NOT USED', 16, chr(0));
// $ciphertext unchanged.
}
else
{
$iv = substr( $ciphertext, 0, 8);
$iv = str_pad( $iv, $ivSize, chr(0));
$ciphertext = substr( $ciphertext, 8);
}
$ciphertextLen = strlen( $ciphertext);
if (($ciphertextLen > 0) && ($ciphertextLen < $blockSize) && ($chain == 'CBC'))
{ $mode = MCRYPT_MODE_CFB; } // CFB 8-bit. This is NOT the same as CFB.
if (strlen($password)==$keySize)
{
$key = $password;
}
else
{
$shaPassword = sha1( $password, True);
for ($key = ''; strlen( $key) < $keySize; $key .= $shaPassword) {}
$key = substr( $key, 0, $keySize);
}
$countBlocks = $ciphertextLen / $blockSize;
$countWholeBlocks = floor( $countBlocks);
$isRound = $countBlocks == $countWholeBlocks;
if ($isRound)
{
$lastBlockSize = 0;
}
else
{
$countBlocks = $countWholeBlocks + 1;
$lastBlockSize = $ciphertextLen - ($countWholeBlocks * $blockSize);
}
$isCipherStealing = ($mode == MCRYPT_MODE_CBC) && ($countWholeBlocks >= 1) && !$isRound;
if ($isCipherStealing)
{ // Reverse ciphertext stealing.
/*
Ciphertext stealing algorithm - Encryption:
Mix := Enc( CV[N-2], X[N-2]);
Steal := Last( B-b, Mix);
Recycle := X[N-1] + Steal;
Y[N-2] := Enc( CV[N-2], Recycle);
Y[N-1] := Head( b, Mix);
Ciphertext stealing algorithm - Decryption:
Recycle := Dec( CV[N-2], Y[N-2]);
Steal := Last( B-b, Recycle);
Mix := Y[N-1] + Steal;
X[N-2] := Dec( CV[N-2], Mix);
X[N-1] := Head( b, Recycle);
*/
// 1. Recycle := Dec( CV[N-2], Y[N-2]);
$Recycle = mcrypt_decrypt ( $cipher, $key, substr( $ciphertext, 0, $countWholeBlocks * $blockSize), $mode, $iv);
$reconUpToX_N_3 = substr( $Recycle, 0, ($countWholeBlocks - 1) * $blockSize); // X[0]..X{N-3]
$Recycle = substr( $Recycle, ($countWholeBlocks - 1) * $blockSize, $blockSize);
// 2. Steal := Last( B-b, Recycle);
$Steal = substr( $Recycle, $lastBlockSize, $blockSize - $lastBlockSize);
// 3. Mix := Y[N-1] + Steal;
$Y_N1 = substr( $ciphertext, $countWholeBlocks * $blockSize, $lastBlockSize);
$Mix = $Y_N1 . $Steal;
// 4. X[N-2] := Dec( CV[N-2], Mix);
$reconUpToX_N_2 = mcrypt_decrypt ( $cipher, $key, substr( $ciphertext, 0, ($countWholeBlocks - 1) * $blockSize) . $Mix, $mode, $iv);
// 5. X[N-1] := Head( b, Recycle);
$reconX_N_1 = substr( $Recycle, 0, $lastBlockSize);
// Putting it alltogether.
$recon = $reconUpToX_N_2 . $reconX_N_1;
}
else
{ // Normal decyrption.
$recon = mcrypt_decrypt ( $cipher, $key, $ciphertext, $mode, $iv);
}
if (($chain == 'ECB') and ($recon != ''))
{ // Trim ECB padding.
$last = strlen($recon);
for ($l = strlen($recon); ($l >= 0) and (ord($recon[$l])==0); $l--)
{$last = $l;}
$recon = substr( $recon, 0, $last-1);
}
?>
<hr />
<h2>Output</h2>
<h3>Summary2</h3>
<p>Cipher is <em><?php echo $cipherName; ?></em></p>
<p>Block size is <?php echo $blockSize; ?> bytes</p>
<?php if ($isRound) { ?>
<p>Given ciphertext was a round <?php echo $countBlocks; ?> blocks long.</p>
<?php } else { ?>
<p>Given ciphertext was a <?php echo $countWholeBlocks; ?> whole blocks long and <?php echo $lastBlockSize; ?> bytes in an odd block.</p>
<?php } ?>
<p>Key size is <?php echo $keySize; ?> bytes</p>
<p>Given chain mode was <em><?php echo $chain; ?></em></p>
<p>Given password was <em>'<?php echo htmlspecialchars($password); ?>'</em></p>
<p>Ciphertext as hex is...</p>
<code><?php echo '[' . $ciphertextLen . '] ' . displayableMultiline( expandWithWhiteSpace( strToHex( $ciphertext))); ?></code>
<p></p>
<p>Reconstructed plaintext message is <em>'<?php echo htmlspecialchars( $recon); ?>'</em></p>
<p></p>
<h2>Debug</h2>
<p>Key as hex is...</p>
<code><?php echo '[' . strlen($key) . '] ' . expandWithWhiteSpace( strToHex( $key)); ?></code>
<p>IV as hex is...</p>
<code><?php echo '[' . strlen($iv) . '] ' . expandWithWhiteSpace( strToHex( $iv)); ?></code>
<p>$countBlocks = <code><?php echo $countBlocks; ?></code></p>
<p>$countWholeBlocks = <code><?php echo $countWholeBlocks; ?></code></p>
<p>$isRound = <code><?php echo $isRound ? 'True' : 'False'; ?></code></p>
<p>$isCipherStealing = <code><?php echo $isCipherStealing ? 'True' : 'False'; ?></code></p>
<p>$lastBlockSize = <code><?php echo $lastBlockSize; ?></code></p>
<p>$Recycle = <code><?php echo '[' . strlen($Recycle) . '] ' . strToHex( $Recycle); ?></code></p>
<p>$recon X[0..N-3] = <code><?php echo '[' . strlen($reconUpToX_N_3) . '] ' . strToHex( $reconUpToX_N_3); ?></code></p>
<p>$Steal = <code><?php echo '[' . strlen($Steal) . '] ' . strToHex( $Steal); ?></code></p>
<p>$Mix = <code><?php echo '[' . strlen($Mix) . '] ' . strToHex( $Mix); ?></code></p>
<p>$recon X[0..N-2] = <code><?php echo '[' . strlen($reconUpToX_N_2) . '] ' . strToHex( $reconUpToX_N_2); ?></code></p>
<p>$recon X[N-1] = <code><?php echo '[' . strlen($reconX_N_1) . '] ' . strToHex( $reconX_N_1); ?></code></p>
<p>Reconstructed plaintext as hex is...</p>
<code><?php echo '[' . strlen($recon) . '] ' . expandWithWhiteSpace( strToHex( $recon)); ?></code>
<?php } ?>
</body>
</html>
到现在为止我对此没有任何问题,但我有一个问题,如果是 256 AES,我将使用 MCRYPT_RIJNDAEL_128 或 MCRYPT_RIJNDAEL_256
提前感谢您的帮助!
此行失败:
Base64_to_stream(aCiphertext, stmCipher);
现在,Base64_to_stream
在 TPLB3.StreamUtils
中声明如下:
procedure Base64_to_stream(const Base64: string; Destin: TStream);
如果您尝试调用 Base64_to_stream
那么您将不会看到编译错误。由于您没有在 uses 子句中包含 TPLB3.StreamUtils
,因此只能假设您的一个单元定义了一个不同的 Base64_to_stream
,它接受 TArray<Byte>
作为其第一个参数。
更新
根据您的单位名称和@TOndrej 提供的 link 判断,看起来您正在混合和匹配 LockBox 实现。这些单位 uTPLb_Random
、uTPLb_StreamUtils
和 uTPLb_Constants
似乎都来自不同的 LockBox 实现。
我建议您查看从何处获得这些不同的 LockBox 实现。您应该只使用一个 LockBox 实现。也许您应该考虑不使用搜索路径,而是明确地将这些单元添加到您的项目中。这样您就不会意外地使用您不想使用的单位。
我正在尝试使程序在 delphi XE7 上加密并在 PHP 端解密
我使用使用 AES 256 加密 CBC 模式的密码箱 3.6.2。
Delphi XE7 代码:
Main.pas
unit Main;
interface
uses
System.SysUtils, System.Types, System.UITypes, System.Classes,
System.Variants,
FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics, FMX.Dialogs,
TPLB3.CryptographicLibrary, TPLB3.BaseNonVisualComponent, TPLB3.Codec,
FMX.StdCtrls, FMX.Controls.Presentation, FMX.Edit, System.Actions,
FMX.ActnList, FMX.Menus, FMX.ExtCtrls, FMX.Layouts, FMX.Memo;
type
TForm2 = class(TForm)
codecAES: TCodec;
cryptoMain: TCryptographicLibrary;
btnEncrypt: TButton;
actlstMain: TActionList;
edtSeed: TEdit;
edtPassword: TEdit;
rgCipher: TPopupBox;
rgChainMode: TPopupBox;
rgTestVectors: TPopupBox;
btnRandomize: TButton;
memoOutput: TMemo;
memoPlaintext: TMemo;
Action1: TAction;
Action2: TAction;
procedure actEncryptUpdate(Sender: TObject);
procedure actEncryptExecute(Sender: TObject);
procedure FormCreate(Sender: TObject);
procedure rgTestVectorsClick(Sender: TObject);
procedure rgChainModeClick(Sender: TObject);
procedure actRandomizeUpdate(Sender: TObject);
procedure actRandomizeExecute(Sender: TObject);
private
procedure LogFmt(const sLine: string; const Args: array of const);
function SpaceOut(const sCompacted: string): string;
public
{ Public declarations }
end;
var
Form2: TForm2;
implementation
uses uTPLb_Random, uTPLb_StreamUtils, uTPLb_Constants;
{$R *.fmx}
function StreamToHex(Data: TStream): string;
var
b: byte;
sByte: string;
begin
Data.Position := 0;
result := '';
while Data.Read(b, 1) = 1 do
begin
sByte := Format('%x', [b]);
if Odd(Length(sByte)) then
sByte := '0' + sByte;
result := result + sByte
end
end;
procedure TForm2.actEncryptExecute(Sender: TObject);
const
TestCaseNames: array [0 .. 2] of string = ('Test Vector 1', 'Test Vector 2',
'Custom');
var
usPlaintext: String;
aCiphertext: string;
OriginalSeed: int64;
stmCipher: TStream;
FEncoding : TEncoding;
sHex: string;
begin
memoOutput.Lines.Clear;
case rgCipher.ItemIndex of
0:
codecAES.BlockCipherId := Format(AES_ProgId, [128]);
end;
case rgChainMode.ItemIndex of
0:
codecAES.ChainModeId := CFB_ProgId;
1:
codecAES.ChainModeId := CBC_ProgId;
2:
codecAES.ChainModeId := ECB_ProgId;
end;
codecAES.UTF8Password := edtPassword.Text;
usPlaintext := memoPlaintext.Lines.Text;
OriginalSeed := StrToInt64(edtSeed.Text);
TRandomStream.Instance.Seed := OriginalSeed;
codecAES.EncryptString(usPlaintext, aCiphertext, FEncoding.UTF8);
// NextSeed := TRandomStream.Instance.Seed;
LogFmt('Test case = %s', [TestCaseNames[rgTestVectors.ItemIndex]]);
LogFmt('Cipher = %s', [codecAES.Cipher]);
LogFmt('Chain mode = %s', [codecAES.ChainMode]);
LogFmt('PRNG seed = %d', [OriginalSeed]);
LogFmt('Passord (UTF-8) = ''%s''', [codecAES.UTF8Password]);
LogFmt('------------', []);
stmCipher := TMemoryStream.Create;
codecAES.Key.SaveToStream(stmCipher);
sHex := StreamToHex(stmCipher);
stmCipher.Free;
LogFmt('key as hex = %s', [sHex]);
LogFmt('Plaintext (UTF-8)', []);
LogFmt('''%s''', [usPlaintext]);
LogFmt('------------', []);
LogFmt('ciphertext (base64) [Includes prepended IV and block quantisation] =',
[]);
LogFmt(' ''%s''', [SpaceOut(aCiphertext)]);
LogFmt('------------', []);
stmCipher := TMemoryStream.Create;
Base64_to_stream(aCiphertext, stmCipher);
sHex := StreamToHex(stmCipher);
stmCipher.Free;
LogFmt('ciphertext (hex) [Includes prepended IV and block quantisation] =', []
);
LogFmt(' ''%s''', [SpaceOut(sHex)]);
LogFmt('------------', []);
end;
procedure TForm2.actEncryptUpdate(Sender: TObject);
begin
//
end;
procedure TForm2.actRandomizeExecute(Sender: TObject);
begin
TRandomStream.Instance.Randomize;
edtSeed.Text := IntToStr(TRandomStream.Instance.Seed)
end;
procedure TForm2.actRandomizeUpdate(Sender: TObject);
begin
(Sender as TAction).Enabled := rgTestVectors.ItemIndex = 2
end;
procedure TForm2.FormCreate(Sender: TObject);
begin
memoOutput.Lines.Clear;
LogFmt('Select test case and chain mode.', []);
LogFmt('Enter password and plaintext message and then press the ''Encrypt'' button.',
[]);
end;
procedure TForm2.LogFmt(const sLine: string; const Args: array of const);
begin
memoOutput.Lines.Add(Format(sLine, Args))
end;
procedure TForm2.rgChainModeClick(Sender: TObject);
begin
//
end;
procedure TForm2.rgTestVectorsClick(Sender: TObject);
var
isCustom: boolean;
begin
case rgTestVectors.ItemIndex of
0:
begin
edtPassword.Text := 'Your lips are smoother than vasoline.';
memoPlaintext.Lines.Text := 'Leeeeeeeeeroy Jenkins!';
// Above is constrained to:
// More than 16 and not a whole multiple of 16 bytes as UTF-8.
edtSeed.Text := '1';
rgChainMode.ItemIndex := 0;
rgCipher.ItemIndex := 0;
end;
1:
begin
edtPassword.Text := 'ORATIO IN L. CATILINAM PRIMA';
memoPlaintext.Lines.Text := 'Quo usque tandem abutere, Catili';
// Above is constrained to:
// A whole multiple of 16 bytes as UTF-8, excluding the empty case.
edtSeed.Text := '333';
rgChainMode.ItemIndex := 0;
rgCipher.ItemIndex := 0
end;
2:
;
end;
isCustom := rgTestVectors.ItemIndex = 2;
edtPassword.ReadOnly := not isCustom;
memoPlaintext.ReadOnly := not isCustom;
edtSeed.ReadOnly := not isCustom;
rgChainMode.Enabled := isCustom;
rgCipher.Enabled := isCustom
end;
function TForm2.SpaceOut(const sCompacted: string): string;
const
NewLineSpacing = 70;
BunchSpacing = 6;
var
i, j: integer;
begin
SetLength(result, 2 * Length(sCompacted));
i := 1;
for j := 1 to Length(sCompacted) do
begin
if ((j mod NewLineSpacing) = 1) and (j <> 1) then
begin
result[i] := #13;
Inc(i);
result[i] := #10;
Inc(i)
end
else if ((j mod BunchSpacing) = 1) and (j <> 1) then
begin
result[i] := ' ';
Inc(i)
end;
result[i] := sCompacted[j];
Inc(i)
end;
SetLength(result, i - 1)
end;
end.
它无法编译给出休闲错误:
[dcc32 Error] Main.pas(125): E2010 Incompatible types: 'System.TArray<System.Byte>' and 'string'
和PHP方面:
<!DOCTYPE html>
<html lang="en">
<head>
<META HTTP-EQUIV="CONTENT-TYPE" CONTENT="text/html; charset=UTF-8">
<META NAME="ROBOTS" CONTENT="NOINDEX,NOFOLLOW,NOARCHIVE" />
<META NAME="DESCRIPTION" CONTENT="Tutorial and demostration page for Delphi (TurboPower LockBox3) to PHP symetric cryptography." />
<META NAME="AUTHOR" CONTENT="Sean B. Durkin">
<META HTTP-EQUIV="CACHE-CONTROL" CONTENT="NO-CACHE">
<META NAME="KEYWORDS" CONTENT="cryptography,delphi,php,turbopower,lockbox,lockbox3">
<title>Delphi-to-PHP Cryptography Tutorial</title>
<link rel="stylesheet" media="screen and (min-device-width: 721px)" href="tut.css" /><!-- <== Desktop. -->
<link rel="stylesheet" media="screen and (max-device-width: 720px)" href="tut-phone.css" / --><!-- <== Phone and tablet. -->
<head>
<body>
<?php
error_reporting(E_ALL | E_COMPILE_ERROR);
$password = $_GET["password"];
$ciphertext_trans = $_GET["ciphertext-trans"];
$rawInputCiphertext = $_GET["ciphertext"];
$chain = $_GET["chain"];
$cipherIn = $_GET["cipherIn"];
function radioChecked($param,$value,$isDefault)
{
$echo = (($param == $value) or ($isDefault and ($param == ''))) ? ' checked="checked" ' : '';
echo $echo;
return $echo != '';
}
?>
<nav>
<div class="nav-bg"></div>
<div class="nav-content">
<h1><a href="http://lockbox.seanbdurkin.id.au/tiki-index.php?page=Delphi-to-PHP+Tutorial+project+home" title="Go to The Delphi-to-PHP project home"><span class="hidden">Project home</span></a></h1>
<dl>
<dt>Date created</dt>
<dd><time datetime="2012-11-29">29-Nov-2012</time></dd>
</dl>
<dl>
<dt>Date last modified</dt>
<dd><time datetime="2012-12-02">2-Dec-2012</time></dd>
</dl>
</div>
</nav>
<h1>Decrypt with PHP from Delphi (TurboPower LockBox3)</h1>
<form id="plainForm" class="floatbox" action="">
<fieldset>
<legend>Crypto data</legend>
<label class="first" for="password">Password (UTF-8)
<input id="password" name="password" type="text" placeholder="Enter TCodec password" value="<?php echo htmlspecialchars($password) ?>" />
</label>
<fieldset class="radio">
<legend>Transport encoding</legend>
<label for="ciphertext-trans-base64">
<input id="ciphertext-trans-base64" name="ciphertext-trans" type="radio" value="base64"
<?php radioChecked($ciphertext_trans,'base64',True); ?> />base64
</label>
<label for="ciphertext-trans-hex">
<input id="ciphertext-trans-hex" name="ciphertext-trans" type="radio" value="hex"
<?php radioChecked($ciphertext_trans,'hex',False); ?> />hex
</label>
</fieldset>
<label for="ciphertext">Ciphertext (transport encoded)
<input id="ciphertext" name="ciphertext" type="text" placeholder="Paste ciphertext here" value="<?php echo htmlspecialchars($rawInputCiphertext) ?>" />
</label>
</fieldset>
<fieldset>
<legend>Options</legend>
<fieldset class="radio">
<legend>Chaining mode</legend>
<label for="chain-cfb">
<input id="chain-cfb" name="chain" type="radio"
value="CFB" <?php radioChecked($chain,'CFB',True); ?> />CFB
</label>
<label for="chain-cbc">
<input id="chain-cbc" name="chain" type="radio"
value="CBC" <?php radioChecked($chain,'CBC',False); ?> />CBC
</label>
<label for="chain-ecb">
<input id="chain-ecb" name="chain" type="radio"
value="ECB" <?php radioChecked($chain,'ECB',False); ?> />ECB
</label>
</fieldset>
<fieldset class="radio">
<legend>Cipher</legend>
<label for="aes-128">
<input id="aes-128" name="cipherIn" type="radio"
value="AES-128" <?php radioChecked($cipherIn,'AES-128',True); ?> />AES-128
</label>
<!-- Extend here with more ciphers as required. Note: PHP does not support AES-256. -->
</fieldset>
</fieldset>
<input class="submit" type="submit" value="Decrypt" />
</form>
<?php if ($chain) { ?>
<?php
function purgeWhiteSpace($sparseHex)
{
return preg_replace('/\s+/', '', $sparseHex);
}
function expandWithWhiteSpace($compactHex)
{
// TODO: Insert white space for visual benefit. Bunch the brown spaces
// into words of 6 characters, and then separate words with a single space.
// Between every 10th word and 11th word, use a new-line ([=17=]D) instead of space.
// Assume that $compactHex ONLY consists of characters 0..9 and A..F .
return $compactHex;
}
function displayableMultiline($str)
{
// TODO: Assume $str ONLY consists of characters whose code-points are below
// 137. Insert '<br />' before each [=17=]D character.
return $str;
}
function hexToStr($hex)
{
$hex2 = purgeWhiteSpace( $hex);
$str='';
for ($i=0; $i < strlen($hex2)-1; $i+=2)
{
$str .= chr(hexdec($hex2[$i].$hex2[$i+1]));
}
return $str;
}
function strToHex($str)
{
$hex='';
for ($i=0; $i < strlen($str); $i++)
{
$addend = dechex(ord($str[$i]));
if (strlen($addend) < 2)
$addend = '0' . $addend;
$hex .= $addend;
}
return $hex;
}
$normalisedRawCiphertext = purgeWhiteSpace( $rawInputCiphertext);
if ($ciphertext_trans == 'base64')
{
$ciphertext = base64_decode( $normalisedRawCiphertext);
}
else
{
$ciphertext = hexToStr( $normalisedRawCiphertext);
}
if ($cipherIn == 'AES-128')
{
$cipher = MCRYPT_RIJNDAEL_128;
$cipherName = 'AES-128';
}
else
{
// Extend here with more ciphers as required. Note: PHP does not support AES-256.
$cipher = MCRYPT_RIJNDAEL_128; // Example only.
$cipherName = '???'; // Example only.
}
if ($chain == 'CFB')
$mode = 'ncfb'; // Proper block-mode CFB. There is no constant for this.
else if ($chain == 'CBC')
$mode = MCRYPT_MODE_CBC;
else
$mode = MCRYPT_MODE_ECB;
$blockSize = mcrypt_get_block_size( $cipher, $mode);
$keySize = mcrypt_get_key_size( $cipher, $mode);
// Work-around PHP bugs.
if (($cipher == MCRYPT_RIJNDAEL_128) and ($keySize == 32))
{ $keySize = 16; } // AES-128 key size is 16 bytes.
if (($cipher == MCRYPT_RIJNDAEL_256) and ($blockSize == 32))
{ $blockSize = 16; } // AES-256 block size is 16 bytes.
$ivSize = $blockSize; // Always. mcrypt_get_iv_size() is pointless.
if ($chain == 'ECB')
{
$iv = str_pad( 'NOT USED', 16, chr(0));
// $ciphertext unchanged.
}
else
{
$iv = substr( $ciphertext, 0, 8);
$iv = str_pad( $iv, $ivSize, chr(0));
$ciphertext = substr( $ciphertext, 8);
}
$ciphertextLen = strlen( $ciphertext);
if (($ciphertextLen > 0) && ($ciphertextLen < $blockSize) && ($chain == 'CBC'))
{ $mode = MCRYPT_MODE_CFB; } // CFB 8-bit. This is NOT the same as CFB.
if (strlen($password)==$keySize)
{
$key = $password;
}
else
{
$shaPassword = sha1( $password, True);
for ($key = ''; strlen( $key) < $keySize; $key .= $shaPassword) {}
$key = substr( $key, 0, $keySize);
}
$countBlocks = $ciphertextLen / $blockSize;
$countWholeBlocks = floor( $countBlocks);
$isRound = $countBlocks == $countWholeBlocks;
if ($isRound)
{
$lastBlockSize = 0;
}
else
{
$countBlocks = $countWholeBlocks + 1;
$lastBlockSize = $ciphertextLen - ($countWholeBlocks * $blockSize);
}
$isCipherStealing = ($mode == MCRYPT_MODE_CBC) && ($countWholeBlocks >= 1) && !$isRound;
if ($isCipherStealing)
{ // Reverse ciphertext stealing.
/*
Ciphertext stealing algorithm - Encryption:
Mix := Enc( CV[N-2], X[N-2]);
Steal := Last( B-b, Mix);
Recycle := X[N-1] + Steal;
Y[N-2] := Enc( CV[N-2], Recycle);
Y[N-1] := Head( b, Mix);
Ciphertext stealing algorithm - Decryption:
Recycle := Dec( CV[N-2], Y[N-2]);
Steal := Last( B-b, Recycle);
Mix := Y[N-1] + Steal;
X[N-2] := Dec( CV[N-2], Mix);
X[N-1] := Head( b, Recycle);
*/
// 1. Recycle := Dec( CV[N-2], Y[N-2]);
$Recycle = mcrypt_decrypt ( $cipher, $key, substr( $ciphertext, 0, $countWholeBlocks * $blockSize), $mode, $iv);
$reconUpToX_N_3 = substr( $Recycle, 0, ($countWholeBlocks - 1) * $blockSize); // X[0]..X{N-3]
$Recycle = substr( $Recycle, ($countWholeBlocks - 1) * $blockSize, $blockSize);
// 2. Steal := Last( B-b, Recycle);
$Steal = substr( $Recycle, $lastBlockSize, $blockSize - $lastBlockSize);
// 3. Mix := Y[N-1] + Steal;
$Y_N1 = substr( $ciphertext, $countWholeBlocks * $blockSize, $lastBlockSize);
$Mix = $Y_N1 . $Steal;
// 4. X[N-2] := Dec( CV[N-2], Mix);
$reconUpToX_N_2 = mcrypt_decrypt ( $cipher, $key, substr( $ciphertext, 0, ($countWholeBlocks - 1) * $blockSize) . $Mix, $mode, $iv);
// 5. X[N-1] := Head( b, Recycle);
$reconX_N_1 = substr( $Recycle, 0, $lastBlockSize);
// Putting it alltogether.
$recon = $reconUpToX_N_2 . $reconX_N_1;
}
else
{ // Normal decyrption.
$recon = mcrypt_decrypt ( $cipher, $key, $ciphertext, $mode, $iv);
}
if (($chain == 'ECB') and ($recon != ''))
{ // Trim ECB padding.
$last = strlen($recon);
for ($l = strlen($recon); ($l >= 0) and (ord($recon[$l])==0); $l--)
{$last = $l;}
$recon = substr( $recon, 0, $last-1);
}
?>
<hr />
<h2>Output</h2>
<h3>Summary2</h3>
<p>Cipher is <em><?php echo $cipherName; ?></em></p>
<p>Block size is <?php echo $blockSize; ?> bytes</p>
<?php if ($isRound) { ?>
<p>Given ciphertext was a round <?php echo $countBlocks; ?> blocks long.</p>
<?php } else { ?>
<p>Given ciphertext was a <?php echo $countWholeBlocks; ?> whole blocks long and <?php echo $lastBlockSize; ?> bytes in an odd block.</p>
<?php } ?>
<p>Key size is <?php echo $keySize; ?> bytes</p>
<p>Given chain mode was <em><?php echo $chain; ?></em></p>
<p>Given password was <em>'<?php echo htmlspecialchars($password); ?>'</em></p>
<p>Ciphertext as hex is...</p>
<code><?php echo '[' . $ciphertextLen . '] ' . displayableMultiline( expandWithWhiteSpace( strToHex( $ciphertext))); ?></code>
<p></p>
<p>Reconstructed plaintext message is <em>'<?php echo htmlspecialchars( $recon); ?>'</em></p>
<p></p>
<h2>Debug</h2>
<p>Key as hex is...</p>
<code><?php echo '[' . strlen($key) . '] ' . expandWithWhiteSpace( strToHex( $key)); ?></code>
<p>IV as hex is...</p>
<code><?php echo '[' . strlen($iv) . '] ' . expandWithWhiteSpace( strToHex( $iv)); ?></code>
<p>$countBlocks = <code><?php echo $countBlocks; ?></code></p>
<p>$countWholeBlocks = <code><?php echo $countWholeBlocks; ?></code></p>
<p>$isRound = <code><?php echo $isRound ? 'True' : 'False'; ?></code></p>
<p>$isCipherStealing = <code><?php echo $isCipherStealing ? 'True' : 'False'; ?></code></p>
<p>$lastBlockSize = <code><?php echo $lastBlockSize; ?></code></p>
<p>$Recycle = <code><?php echo '[' . strlen($Recycle) . '] ' . strToHex( $Recycle); ?></code></p>
<p>$recon X[0..N-3] = <code><?php echo '[' . strlen($reconUpToX_N_3) . '] ' . strToHex( $reconUpToX_N_3); ?></code></p>
<p>$Steal = <code><?php echo '[' . strlen($Steal) . '] ' . strToHex( $Steal); ?></code></p>
<p>$Mix = <code><?php echo '[' . strlen($Mix) . '] ' . strToHex( $Mix); ?></code></p>
<p>$recon X[0..N-2] = <code><?php echo '[' . strlen($reconUpToX_N_2) . '] ' . strToHex( $reconUpToX_N_2); ?></code></p>
<p>$recon X[N-1] = <code><?php echo '[' . strlen($reconX_N_1) . '] ' . strToHex( $reconX_N_1); ?></code></p>
<p>Reconstructed plaintext as hex is...</p>
<code><?php echo '[' . strlen($recon) . '] ' . expandWithWhiteSpace( strToHex( $recon)); ?></code>
<?php } ?>
</body>
</html>
到现在为止我对此没有任何问题,但我有一个问题,如果是 256 AES,我将使用 MCRYPT_RIJNDAEL_128 或 MCRYPT_RIJNDAEL_256
提前感谢您的帮助!
此行失败:
Base64_to_stream(aCiphertext, stmCipher);
现在,Base64_to_stream
在 TPLB3.StreamUtils
中声明如下:
procedure Base64_to_stream(const Base64: string; Destin: TStream);
如果您尝试调用 Base64_to_stream
那么您将不会看到编译错误。由于您没有在 uses 子句中包含 TPLB3.StreamUtils
,因此只能假设您的一个单元定义了一个不同的 Base64_to_stream
,它接受 TArray<Byte>
作为其第一个参数。
更新
根据您的单位名称和@TOndrej 提供的 link 判断,看起来您正在混合和匹配 LockBox 实现。这些单位 uTPLb_Random
、uTPLb_StreamUtils
和 uTPLb_Constants
似乎都来自不同的 LockBox 实现。
我建议您查看从何处获得这些不同的 LockBox 实现。您应该只使用一个 LockBox 实现。也许您应该考虑不使用搜索路径,而是明确地将这些单元添加到您的项目中。这样您就不会意外地使用您不想使用的单位。