TPLockBox3 и PHP — шифрование AES в Delphi, расшифровка в PHP

У меня проблема с lockbox3 и PHP mcrypt. Я не могу передать IV на PHP. код Delphi:

var
  Codec: TCodec;
  CL: TCryptographicLibrary;
  PlainStream: TStringStream;
  CipherStream: TMemoryStream;
begin
  PlainStream := TStringStream.Create(Edit1.Text);
  CipherStream := TMemoryStream.Create;

  CL := TCryptographicLibrary.Create(nil);
  Codec := TCodec.Create(nil);
  Codec.CryptoLibrary := CL;
  Codec.ChainModeId := uTPLb_Constants.CBC_ProgId;
  Codec.StreamCipherId := uTPLb_Constants.BlockCipher_ProgId;
  Codec.BlockCipherId := Format(uTPLb_Constants.AES_ProgId, [256]);
  Codec.Password := Edit3.Text;

  Codec.EncryptStream(PlainStream, CipherStream);
  Codec.Burn;

  Memo1.Text := Stream_to_Base64(CipherStream);
  Memo2.Clear;
  Memo2.Lines.Add(Format('Size: %d bytes', [CipherStream.Size]));
  Memo2.Lines.Add(Format('Original size: %d bytes', [PlainStream.Size]));

  Codec.Free;
  CL.Free;
  CipherStream.Free;
  PlainStream.Free;

И код PHP:

  $ciphertext = base64_decode("zA/eeF+WFVMDsZ7+iA==");
  $iv = substr($ciphertext, 0, 8);
  $text = substr($ciphertext, 8, strlen($ciphertext) - 8);

  $td = mcrypt_module_open("rijndael-256", "", "cbc", $iv);
  mcrypt_generic_init($td, "PasswordPassword", $iv);
  $plaintext = mdecrypt_generic($td, $text);
  echo $plaintext;
  mcrypt_generic_deinit($td);
  mcrypt_module_close($td);

Я получил ошибку:

Предупреждение: mcrypt_generic_init() [function.mcrypt-generic-init]: неверный размер IV; предоставленная длина: 8, необходимая: 32 в C:...\aestest.php в строке 7

Связанная тема: AES Encrypt/Decrypt Delphi & PHP


person Maxim    schedule 23.11.2012    source источник
comment
rijndael-256 не является AES. Вместо этого используйте rijndael-128.   -  person CodesInChaos    schedule 25.11.2012


Ответы (1)


Вы не сказали, какую версию Delphi вы используете. Это важная деталь. На данный момент я предполагаю, что это Delphi 2010. В вашем коде есть ряд проблем. Я обращусь к ним...

(1) В Delphi 2010 и более поздних версиях строки кодируются в UTF-16LE, а в PHP — в кодировке UTF-8. Почитай эту свою строчку...

PlainStream := TStringStream.Create(Edit1.Text);

Что вы делаете, так это создаете кодировку UTF-16LE вашей строки полезной нагрузки. Вы шифруете это и передаете на сторону PHP и расшифровываете. Но вы не получите ожидаемого результата, потому что расшифрованные байты имеют формат UTF-16LE, а PHP ожидает, что они будут UTF-8.

(2) TP Lockbox 3 уже имел собственные методы шифрования строк. Почему бы не использовать их?

(3) Размер блока для всех трех вариантов AES составляет 128 бит, что составляет 16 байт. Размер IV всегда равен размеру блока. На стороне PHP, с точки зрения общего кодирования, вы всегда должны вызывать mcrypt_enc_get_iv_size() (вы этого не сделали). Прочтите справочную страницу здесь. В любом случае для AES-256 необходимо вернуть 16 байт. Если нет, то что-то серьезно не так.

(4) Ваши пароли не совпадают, поэтому вы никогда не можете разумно ожидать счастливого результата. На стороне Delphi ваш пароль закодирован в UTF-16LE. На стороне PHP ваш пароль представляет собой кодировку UTF-8 «PasswordPassword», которая никогда не может быть побайтно равна чему-то действительному в UTF-16.

(5) На стороне PHP вы написали..

 $iv = substr($ciphertext, 0, 8);

Вам нужно расширить его до 16 байт. Обратитесь к этому вопросу.


ОБНОВИТЬ

Как и было обещано, вот некоторый PHP-код для расшифровки зашифрованных сообщений, созданных TurboPower LockBox 3. Вам нужно будет создать файл css, иначе презентация будет уродливой.

<!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 ($0D) 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 $0D 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>&apos;<?php echo htmlspecialchars($password); ?>&apos;</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>&apos;<?php echo htmlspecialchars( $recon); ?>&apos;</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>

... а вот соответствующая программа Delphi для создания зашифрованных сообщений для предыдущей веб-страницы PHP в целях тестирования и демонстрации. (файл DFM не включен)...

unit umfmDelphi_to_PHP_Symetric;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, ActnList, StdCtrls, uTPLb_Codec, uTPLb_BaseNonVisualComponent,
  uTPLb_CryptographicLibrary, ExtCtrls;

type
  TmfmDelphi_to_PHP_Symetric = class(TForm)
    rgTestVectors: TRadioGroup;
    rgChainMode: TRadioGroup;
    edtPassword: TEdit;
    memoPlaintext: TMemo;
    lblPassword: TLabel;
    lblPlaintext: TLabel;
    cryptoMain: TCryptographicLibrary;
    codecAES: TCodec;
    memoOutput: TMemo;
    btnEncrypt: TButton;
    actlstMain: TActionList;
    actEncrypt: TAction;
    edtSeed: TEdit;
    lblSeed: TLabel;
    btnRandomize: TButton;
    actRandomize: TAction;
    rgCipher: TRadioGroup;
    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
  mfmDelphi_to_PHP_Symetric: TmfmDelphi_to_PHP_Symetric;

implementation



uses uTPLb_Random, uTPLb_StreamUtils, uTPLb_Constants;

{$R *.dfm}


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 TmfmDelphi_to_PHP_Symetric.actEncryptExecute( Sender: TObject);
const
  TestCaseNames: array[0..2] of string = ('Test Vector 1', 'Test Vector 2', 'Custom');
var
  usPlaintext: UTF8String;
  aCiphertext: ansistring;
  OriginalSeed: int64;
  stmCipher: TStream;
  sHex: string;
begin
memoOutput.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.EncryptAnsiString( usPlaintext, aCiphertext);
// 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 TmfmDelphi_to_PHP_Symetric.actEncryptUpdate( Sender: TObject);
begin
//
end;

procedure TmfmDelphi_to_PHP_Symetric.actRandomizeExecute(Sender: TObject);
begin
TRandomStream.Instance.Randomize;
edtSeed.Text := IntToStr( TRandomStream.Instance.Seed)
end;

procedure TmfmDelphi_to_PHP_Symetric.actRandomizeUpdate(Sender: TObject);
begin
(Sender as TAction).Enabled := rgTestVectors.ItemIndex = 2
end;

procedure TmfmDelphi_to_PHP_Symetric.FormCreate( Sender: TObject);
begin
memoOutput.Clear;
LogFmt( 'Select test case and chain mode.', []);
LogFmt( 'Enter password and plaintext message and then press the ''Encrypt'' button.', []);
end;

procedure TmfmDelphi_to_PHP_Symetric.LogFmt(
  const sLine: string; const Args: array of const);
begin
memoOutput.Lines.Add( Format( sLine, Args))
end;

procedure TmfmDelphi_to_PHP_Symetric.rgChainModeClick( Sender: TObject);
begin
//
end;

procedure TmfmDelphi_to_PHP_Symetric.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 TmfmDelphi_to_PHP_Symetric.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.
person Sean B. Durkin    schedule 24.11.2012
comment
Да, вы были правы, приняв версию Delphi за D2010. $td = mcrypt_module_open("rijndael-256", "", "cbc", ""); $ivsize = mcrypt_enc_get_iv_size($td); echo "IV size: $ivsize"; Этот код печатает: IV size: 32 - person Maxim; 24.11.2012
comment
Размер IV и блока для AES составляет 16 байт. Размер ключа для AES-256 составляет 32 байта. Это в стандарте и не может быть изменено. Если ваша реализация говорит иначе, то ваша реализация не соответствует стандарту AES. - person Sean B. Durkin; 24.11.2012
comment
Но PHP говорит мне, что размер IV составляет 32 байта. - person Maxim; 24.11.2012
comment
Спецификацию можно найти здесь. Размер блока указан на странице 1. Если PHP неправильный, вам нужно обсудить это с поставщиками PHP. - person Sean B. Durkin; 24.11.2012
comment
Передача iconv("UTF-8", "UTF-16LE", "PasswordPassword") в качестве ключа не дает никакого эффекта в php. IV дополняется нулями (chr(0)) до $ivlen - person Maxim; 24.11.2012
comment
Также обратите внимание на здесь и здесь. Это ошибка в PHP. - person Sean B. Durkin; 24.11.2012
comment
Спасибо за ваше сообщение. Кто-то прокомментировал на другом сайте: Можно подумать, что MCRYPT_RIJNDAEL_256 указывает 256-битное шифрование, но это неправильно. Три варианта определяют размер блока, который будет использоваться с шифрованием Rijndael. Из chilkatsoft.com/p/php_aes.asp - person Maxim; 24.11.2012
comment
Я не понимаю, как передать пароль в правильной кодировке. Использовать AnsiString в Delphi? Или использовать функции преобразования кодировки в PHP? - person Maxim; 24.11.2012
comment
Если вы можете подождать несколько дней, будет опубликован некоторый рабочий код PHP. - person Sean B. Durkin; 25.11.2012