C#とPHPで暗号化されている3倍が同じ(PKCS7、ECB)?
-
11-10-2019 - |
質問
私は今これを理解しようとして数時間費やしましたが、私はそれを機能させることができません。 PHPで一致する必要があるC#暗号化ルーチンがあります。 C#バージョンを変更することはできませんが、それはオプションではありません(これについては、サードパーティがしっかりしています)。
これがC#コードです:
//In C#
// Console.WriteLine(ApiEncode("testing", "56dsfkj3kj23asdf83kseegflkj43458afdl"));
// Results in:
// XvHbR/CsLTo=
public static string ApiEncode(string data, string secret)
{
byte[] clear;
var encoding = new UTF8Encoding();
var md5 = new MD5CryptoServiceProvider();
byte[] key = md5.ComputeHash(encoding.GetBytes(secret));
TripleDESCryptoServiceProvider des = new TripleDESCryptoServiceProvider();
des.Key = key;
des.Mode = CipherMode.ECB;
des.Padding = PaddingMode.PKCS7;
byte[] input = encoding.GetBytes(data);
try { clear = des.CreateEncryptor().TransformFinalBlock(input, 0, input.Length); }
finally
{
des.Clear();
md5.Clear();
}
return Convert.ToBase64String(clear);
}
これが私がPHPで思いついたものの中で最高です:
//In PHP
// echo apiEncode("testing", "56dsfkj3kj23asdf83kseegflkj43458afdl");
// Results in:
// 5aqvY6q1T54=
function apiEncode($data, $secret)
{
//Generate a key from a hash
$key = md5(utf8_encode($secret), true);
//Create init vector
$iv = mcrypt_create_iv(mcrypt_get_iv_size(MCRYPT_3DES, MCRYPT_MODE_ecb), MCRYPT_RAND);
//Pad for PKCS7
$blockSize = mcrypt_get_block_size('tripledes', 'ecb');
$len = strlen($data);
$pad = $blockSize - ($len % $blockSize);
$data .= str_repeat(chr($pad), $pad);
//Encrypt data
$encData = mcrypt_encrypt('tripledes', $key, $data, 'ecb'); //, $iv);
return base64_encode($encData);
}
私の知る限り、私はPHP側でPKCS7パディングを適切に処理しています。他に何を試すべきかわかりません。
注意すべきことの1つは、C#がWindowsで発生していること、LinuxでPHPが発生しているため、それが違いを生むかどうかはわかりません。
解決
PHPバージョンのパディング長は、パスワードの長さに基づいています。これは間違っています。代わりにメッセージの長さに基づいている必要があります。
交換してみてください strlen($password)
と strlen($data)
.
2番目の問題は、です mcrypt
ライブラリには24バイトのキーが必要です。 Triple DEは通常のDESを3回適用するため、DES Kの各ラウンドで使用される8バイトキーを呼び出すことができます1, 、k2, 、k3. 。これらのキーを選択するには、さまざまな方法があります。最も安全なのは、3つの異なるキーを選択することです。別の方法は、kを設定することです3 kに等しい1. 。最も安全な方法(DESに相当)は、kを作成することです1 = k2 = k3.
ほとんどのライブラリは、上記の2番目のオプションとして16バイトの3DESキーを解釈するのに十分な「スマート」です。3 = k1. 。 .NET実装はあなたのためにこれを行っていますが、 mcrypt
図書館はそうではありません。代わりに、kを設定しています3 =0。あなたはこれを自分で修正し、合格する必要があります mcrypt
24バイトキー。
MD5ハッシュを計算した後、最初の8バイトを取ります $key
, 、そしてそれらを終了に追加します $key
, 、そのため、24バイトの値があります mcrypt_encrypt()
.
他のヒント
解決策を見つけ、このリンクをチェックして、あなたを助けるかもしれません。 http://sanity-free.com/131/triple_des_between_php_and_csharp.html
そして、ここに念のために復号化機能があります:
public static string Decrypt(string cypherString)
{
byte[] key = Encoding.ASCII.GetBytes("icatalogDR0wSS@P6660juht");
byte[] iv = Encoding.ASCII.GetBytes("iCatalog");
byte[] data = Convert.FromBase64String(cypherString);
byte[] enc = new byte[0];
TripleDES tdes = TripleDES.Create();
tdes.IV = iv;
tdes.Key = key;
tdes.Mode = CipherMode.CBC;
tdes.Padding = PaddingMode.Zeros;
ICryptoTransform ict = tdes.CreateDecryptor();
enc = ict.TransformFinalBlock(data, 0, data.Length);
return UTF8Encoding.UTF8.GetString(enc, 0, enc.Length);
}
Encoding.getBytesをご覧ください。UTF8からの秘密のキーバイトが必要です...
C#バージョンが設定されていないようです IV. 。 MSDNが言っているので、これが何であるかわからない場合、これは問題になる可能性があります。
IVプロパティは、SymmetlicalGorithmクラスの1つの新しいインスタンスを作成する場合、またはGenerateIVメソッドを手動で呼び出すときはいつでも、新しいランダム値に自動的に設定されます。
PHPバージョンのように見えますが、 IV. 。 IVを提供せず、C#バージョンがZerosも使用することを願っています。
編集:ECBのように見え、IVは無視されます。
また、C#バージョンのようにキーをエンコードする必要があるかもしれません utf8-encode