问题
I am working on a project for secure file transfer which encrypts files using c# client on the customer side. i need to decrypt the files on server side using php and maybe phpseclib. The code here i copied from a msdn example. But i cant work out the decrypt function in php.
public static byte[] AES_Encrypt(byte[] bytesToBeEncrypted, byte[] passwordBytes)
{
byte[] encryptedBytes = null;
byte[] saltBytes = passwordBytes;
using (MemoryStream ms = new MemoryStream())
{
using (RijndaelManaged AES = new RijndaelManaged())
{
var key = new Rfc2898DeriveBytes(passwordBytes, saltBytes, 1000);
AES.KeySize = 256;
AES.BlockSize = 256;
AES.Mode = CipherMode.CBC;
AES.Padding = PaddingMode.Zeros;
AES.Key = key.GetBytes(AES.KeySize / 8);
AES.IV = key.GetBytes(AES.BlockSize / 8);
using (CryptoStream cs = new CryptoStream(ms, AES.CreateEncryptor(), CryptoStreamMode.Write))
{
cs.Write(bytesToBeEncrypted, 0, bytesToBeEncrypted.Length);
cs.Close();
}
encryptedBytes = ms.ToArray();
}
}
return encryptedBytes;
}
This is the php code which doesnt work:
$pw = "this_is_my_pw";
$aes = new Crypt_AES(CRYPT_AES_MODE_CBC);
$aes->setKey($pw);
$aes->setKeyLength(256);
$aes->disablePadding();
$file = "enc.txt";
$fh = fopen($file, "r");
$contents = trim(fread($fh, filesize($file)));
fclose($fh);
//echo "Encoded: \n\n" . $contents;
$contents = $aes->decrypt($contents);
#$block = mcrypt_get_block_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_CBC);
#$padding = $block - (strlen($clear) % $block);
#$dec = mcrypt_decrypt(MCRYPT_RIJNDAEL_256, $pw, base64_decode($contents), MCRYPT_MODE_CBC, $pw);
echo "Decoded: \n\n" . $contents;
Can someone help me fixing this or give me a hint what i do wrong?
回答1:
No initialization vector used when decrypting. You need to send the initialization vector (IV) along with the data - your PHP code is never calling
$aes->setIV
from phpseclib, so it will never be able to decrypt the text because phpseclib uses an IV of all zeros if one is not set according to the docs. I would personally recommend generating a secure random IV from C# using RijndaelManaged.GenerateIV, but apparently it's considered acceptable to derive the IV from a PBKDF2 key. PBKDF2 (specified in RFC 2898) is the key-stretching algorithmRfc2898DeriveBytes
implements. Regardless, you need to re-produce the IV on the PHP side, whether that means transmitting the IV with the encrypted data (which is completely fine) or re-deriving the IV on the PHP side.Using the password as the salt is a REALLY BAD IDEA. The salt needs to be of sufficient length and cryptographically randomly generated. Using the password as the salt completely defeats the point of having a salt. MSDN has some sample code that shows how to generate a cryptographically random salt in conjunction with using
Rfc2898DeriveBytes
, but the important part is here:
byte[] saltBytes = new byte[8];
using (RNGCryptoServiceProvider rngCsp = new RNGCryptoServiceProvider())
{
// Fill the array with a random value.
rngCsp.GetBytes(salt1);
}
- The salt must be transmitted with the encrypted data. You need to send the PBKDF2 salt bytes along with the IV bytes and encrypted data. phpseclib will need all of those to properly initialize itself and decrypt the data. You'll probably want to use phpseclib's setPassword to do this, like so:
$salt = ...; // get the salt to your PHP code somehow
$iv = ...; // get the IV to your PHP code
$pw = "this_is_my_pw";
$aes = new Crypt_AES(CRYPT_AES_MODE_CBC);
$aes->setPassword($pw, 'pbkdf2' /* key extension algorithm */,
'sha1' /* hash algorithm */, $salt /* generated salt from C# */,
1000 /* number of iterations, must be same as C# code */,
256 / 8 /* key size in bytes, 256 bit key / 8 bits per byte */
);
$aes->setIV($iv);
- Keep the other answers in mind about blocksize. 128 bits is the standard AES blocksize, so make sure both C# and phpseclib can function correctly with a larger blocksize, or just use the AES standard for both.
回答2:
If you are trying to use AES set the block size to 128-bits, that is the only block size that is supported. Using a different block size means you are using Rijndael encryption which is not well supported cross platform.
AES supports multiple key sizes of 128, 192 and 256 bits. Sometimes there is confusion when using a Rijndael implementation to use AES encryption.
回答3:
In the Java code I see AES.BlockSize = 256;
. Technically, AES has a fixed block size of 128 bits. Rijndael supports variable block sizes but AES doesn't. If you want to make use of variable block sizes in PHP with phpseclib you'd need to do this:
$pw = "this_is_my_pw";
$aes = new Crypt_Rijndael(CRYPT_RIJNDAEL_MODE_CBC);
$aes->setKey($pw);
$aes->setKeyLength(256);
$aes->setBlockLength(256);
$aes->disablePadding();
Also, your key is 13 bytes long. AES keys need to be either 16 bytes (128 bits) long, 24 bytes (192 bits) long or 32 bytes (256 bits) long. idk what js lib you're using but phpseclib 1.0/2.0 null pads keys if they're not long enough. The newest version of phpseclib - currently under development - throws exceptions.
Or maybe you mean to be using a password based key derivation function? phpseclib provides two that can be utilized via setPassword()
but if that were the case you'd need to know what method and parameters were being utilized by the js lib.
来源:https://stackoverflow.com/questions/44286287/file-encryption-in-c-sharp-with-aes-decryption-with-phpseclib