2012-02-10 6 views
7

私は、Delphi 7でデータを暗号化し、私はmcryptの(とそれを解読していますPOSTを介して、PHPスクリプトに送信する12月3.0ライブラリDelphi Encryption Compedium Part I)を使用しようとしていますRIJNDAEL_256、ECBモード)。デルファイ12月ライブラリ(ラインダール)暗号化

Delphiの一部:

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モードが推奨されていません知っていると私はできるだけ早く私はECBの作業を取得としてCBCを使用します。問題は、Delphiで生成されたIVをPHPスクリプトにも送信する必要があるということですか? ECBのように、キーが十分であることを知っていますか?

+0

これは非常にばかげた質問かもしれません。しかし、あなたは暗号化されたデータを復号化できるのですか?ああ、この質問への答えは役に立ちます:http://stackoverflow.com/q/8313992/41338 – RobS

+0

あなたはmcrypt_create_iv()を呼び出します。 Delphiで使用したIVは何ですか? –

+0

@ldsandon:talereaderはECBモードを使用しています。 IVはありません。 –

答えて

6

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; 

end;

+0

ありがとう、これは私を正しい軌道に乗せる。私は実際にPasswordSecret + Timestampのsha1の最初の24文字(POSTデータに沿ったもの)だけを取る私自身のパスワード変換(コードからは省略)を使用しています。 PHPでmcryptが最大24文字の鍵を受け入れたというエラーが発生したとき、私はこれを義務づけました。 – talereader

+0

問題のもう1つの部分は、DEC実装が実際には** 128ビット** Rijndaelであったことです。 PHP decrypt関数をRIJNDAEL_128を使用するように変更することで、それがわかりました。 PHPの解読関数の出力には元々のデータ+最後にはちょっとぎこちないものがあります。以前私がstackoverflowの他の記事で読んだことから、ここではどこかで私が把握しなければならないパディングの問題があります。 – talereader

+0

また、DECソースを見ると、128ビットのブロックサイズと256のキーサイズ(AES 256)のバリアントに変換するためにいくつかの変更を加えることができるので、mcrypt w/RIJNDAEL_256と組み合わせるでしょう? – talereader

2

OK、そう私のコードと3つの問題があった、これを合計する:原因mcryptのと一般的な暗号の私の理解不足に

  1. は、MCRYPT_RIJNDAEL_256は128ビットブロックとdoesnの」に言及しますキーのサイズを参照してください。私の正しい選択はMCRYPT_RIJNDAEL_128だったはずです。これはAES標準であり、DEC 3.0でもサポートされています。

  2. DECには独自のデフォルトキーの導出がありますので、PHPで実装する必要がないようにバイパスする必要がありました。実際には、PHPで再現しやすい独自のキー導出アルゴリズム(sha1(キー)の最初の32文字)を使用しています。

  3. DECはmcryptが想定しているように、暗号のブロックサイズの倍数に平文をパディングしないので、手動で行う必要がありました。以下

設ける作業コード:

デルファイ:

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

SHA-1は20バイトしか出力しません。最も簡単な解決策は、おそらくキーサイズを128ビット/ 16バイトに減らすことです。もう1つの方法は、SHA-256を使用し、DEC 3.0から OpenStrSecIIまたはStreamSec ToolsやDCP CryptなどのSHA-256をサポートする別のライブラリに切り替えることです。 3番目の選択肢は、キーストレッチでSHA-1を使用することですが、それはPHPで実装するのが簡単ではなく、DEC 3.0はPKCS#5 v2.0の機能を実装していません。 –

+0

上記のコードは、キーの長さが24文字であっても、実際にはAES-128ではなく192文字を使用しています。キーの長さを16に減らすべきですか?私は今のところAES-128に固執するので、それは小さなプロジェクトです。また、私はCBCに切り替え、DECに内部的にIVを生成させ、IV base64をデータと一緒に渡すだけです。 – talereader

+0

AES-192を使用していますが、キーにエントロピーが最大160ビットあり(SHA-1の出力長に制限されています)、キーの最後の4バイト(#21〜#24)は未定義ですあなたはそれが働いてからおそらく0です)。 –

0

256ビットキーは32 charachters、または32バイトです。これは問題かもしれません。

[EDIT]

私は修正して1つのアイデアにすべての人のアイデア(AnsiStringの、など)を組み合わせました。


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 charachterとのこと: -

また、あなたは(符号列を使用している、それは(

をEncodestringしなければならない私は、以下の作業を暗号化と復号化のソースを貼り付け適切な暗号化と復号化が得られます。

暗号化を保存して使用するにはあなたがBase64Encode(

を解読する前にBase64Decodeすることを忘れないでください。

これはBlowfishに必要な技術と同じです。キャラクターは実際にはバックスペースのようなもので、スクリーンに表示するのではなく機能を実行することがあります。 Base64Encodeは、基本的にキャラクタをテキストで表示できるものに変換します。

エンコードされたデータを同じ言語または別の言語でインターネットまたは別のアプリケーションに転送する前に、データを失わないためにbase64エンコードおよびデコードする必要があります。 PHPでもそれを忘れないでください!