Библиотека Delphi DEC (Rijndael) шифрование - PullRequest
7 голосов
/ 10 февраля 2012

Я пытаюсь использовать библиотеку DEC 3.0 ( Delphi Encryption Compedium Part I ) для шифрования данных в Delphi 7 и отправки их в скрипт PHP через POST, где я нахожусь расшифровав его с помощью mcrypt (RIJNDAEL_256, режим ECB).

Delphi part:

uses Windows, DECUtil, Cipher, Cipher1;

function EncryptMsgData(MsgData, Key: string): string;
var RCipher: TCipher_Rijndael;
begin
  RCipher:= TCipher_Rijndael.Create(KeyStr, nil);
  RCipher.Mode:= cmECB;
  Result:= RCipher.CodeString(MsgData, paEncode, fmtMIME64);
  RCipher.Free;
end;

PHP часть:

function decryptMsgContent($msgContent, $sKey) {
    return mcrypt_decrypt(MCRYPT_RIJNDAEL_256, $sKey, base64_decode($msgContent), MCRYPT_MODE_ECB, mcrypt_create_iv(mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB), MCRYPT_RAND));
}

Проблема заключается в том, что дешифрование из PHP не работает, и вывод является бессмысленным, что отличается от фактических данных.

Конечно, Delphi Key и PHP $Key - это одна и та же строка из 24 символов.

Теперь я знаю, что DEC 3.0 является устаревшим и устаревшим, и я не являюсь экспертом в области шифрования и не могу сказать, является ли это на самом деле Rijndael 256. Может быть, кто-то может сказать мне, как эта реализация отличается от PHP mcrypt w / RIJNDAEL_256 , Возможно, размер ключа другой, или размер блока, но не могу сказать это по коду. Вот выдержка из Cipher1.pas:

const
{ don’t change this }
  Rijndael_Blocks =  4;
  Rijndael_Rounds = 14;

class procedure TCipher_Rijndael.GetContext(var ABufSize, AKeySize, AUserSize: Integer);
begin
  ABufSize := Rijndael_Blocks * 4;
  AKeySize := 32;
  AUserSize := (Rijndael_Rounds + 1) * Rijndael_Blocks * SizeOf(Integer) * 2;
end;

Дополнительный вопрос:

Я знаю, что режим ECB не рекомендуется, и я буду использовать CBC, как только заработаю ECB. Вопрос в том, должен ли я также передавать сгенерированный IV в Delphi в скрипт PHP? Или знание ключа достаточно, как для ЕЦБ?

Ответы [ 3 ]

6 голосов
/ 10 февраля 2012

Вы вызываете TCipher.Create (const Password: String; AProtection: TProtection); конструктор, который вычислит хеш пароля перед передачей его методу Init, который выполняет стандартное расписание ключей реализованного алгоритма. Чтобы переопределить эту деривацию ключей, используйте:

function EncryptMsgData(MsgData, Key: string): string;
var RCipher: TCipher_Rijndael;
begin
  RCipher:= TCipher_Rijndael.Create('', nil);
  RCipher.Init(Pointer(Key)^,Length(Key),nil);
  RCipher.Mode:= cmECB;
  Result:= RCipher.CodeString(MsgData, paEncode, fmtMIME64);
  RCipher.Free;

конец;

2 голосов
/ 10 февраля 2012

ОК, чтобы подвести итог, было 3 проблемы с моим кодом:

  1. Из-за моего плохого понимания mcrypt и шифров в целом MCRYPT_RIJNDAEL_256 ссылается на 128 бит блок и не относится к размеру ключа. Мой правильный выбор должен был быть MCRYPT_RIJNDAEL_128, который является стандартом AES и также поддерживается DEC 3.0.

  2. У DEC есть собственный ключ по умолчанию, поэтому мне нужно было его обойти, чтобы мне не пришлось реализовывать его и в PHP. На самом деле я использую свой собственный алгоритм вывода ключей, который было легко воспроизвести в PHP (первые 32 символа sha1 (ключ)).

  3. DEC не дополняет открытый текст кратным размеру блока шифра, как ожидает mcrypt, поэтому мне пришлось сделать это вручную.

Предоставление рабочего кода ниже:

Delphi:

uses Windows, DECUtil, Cipher, Cipher1, CryptoAPI;

function EncryptMsgData(MsgData, Key: string): string;
var RCipher: TCipher_Rijndael;
    KeyStr: string;
begin
  Result:= '';
  try
    // key derivation; just making sure to feed the cipher a 24 chars key
    HashStr(HASH_SHA1, Key, KeyStr);
    KeyStr:= Copy(KeyStr, 1, 24);
    RCipher:= TCipher_Rijndael.Create('', nil);
    RCipher.Init(Pointer(KeyStr)^, Length(KeyStr), nil);
    RCipher.Mode:= cmECB;
    Result:= RCipher.CodeString(MsgData + StringOfChar(#0,16-(Length(MsgData) mod 16)), paEncode, fmtMIME64);
    RCipher.Free;
  except
  end;
end;

PHP:

function decryptMsgContent($msgContent, $sKey) {
    $sKey = substr(sha1(sKey), 0, 24);
    return trim(mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $sKey, base64_decode($msgContent), MCRYPT_MODE_ECB, mcrypt_create_iv(mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_ECB), MCRYPT_RAND)));
}
0 голосов
/ 19 октября 2014

256-битный ключ, который я нашел, - это 32 символа или 32 байта. Не 24. Это может быть проблемой.

[EDIT]

Я объединил все идеи (ansistring и т. Д.) В одну идею с исправлением.

Кроме того, вы используете кодовую строку (- это должна быть Encodestring (

Я вставил рабочий источник Encrypt and Decrypt ниже:


function EncryptMsgData(MsgData, Key: AnsiString): AnsiString;
var RCipher: TCipher_Rijndael;
begin
  RCipher:= TCipher_Rijndael.Create('', nil);
  RCipher.Init(Pointer(Key)^,Length(Key),nil);
  RCipher.Mode:= cmCBC;
  Result:= RCipher.EncodeString(MsgData);
  RCipher.Free;
end;

function DecryptMsgData(MsgData, Key: AnsiString): AnsiString;
var RCipher: TCipher_Rijndael;
begin
  RCipher:= TCipher_Rijndael.Create('',nil);
  RCipher.Init(Pointer(Key)^,Length(Key),nil);
  RCipher.Mode:= cmCBC;
  Result:= RCipher.DecodeString(MsgData);
  RCipher.Free;
end;

Используйте это с ключом из 32 символов, и вы получите правильное шифрование и дешифрование.

Для хранения и использования зашифрованных данных в виде строки вы можете использовать Base64Encode (

Но не забудьте использовать Base64Decode перед расшифровкой.

Это та же техника, что и для Blowfish. Иногда персонажи на самом деле похожи на клавишу возврата и выполняют функцию, а не отображаются на экране. Base64Encode в основном преобразует символы в то, что вы можете отобразить в тексте.

Перед передачей закодированных данных через Интернет или в другое приложение на том же или другом языке, вы ДОЛЖНЫ base64encode и декодировать, чтобы не потерять данные. Не забывайте и об этом в PHP!

...