使用AES的C#文件加密,使用phpseclib解密
我正在从事一个安全文件传输项目,该项目在客户端使用c#client对文件进行加密。我需要使用php或者phpseclib对服务器端的文件进行解密。这里的代码是我从一个msdn示例复制的。但是我不能在php中计算出解密函数使用AES的C#文件加密,使用phpseclib解密,c#,php,encryption,phpseclib,C#,Php,Encryption,Phpseclib,我正在从事一个安全文件传输项目,该项目在客户端使用c#client对文件进行加密。我需要使用php或者phpseclib对服务器端的文件进行解密。这里的代码是我从一个msdn示例复制的。但是我不能在php中计算出解密函数 public static byte[] AES_Encrypt(byte[] bytesToBeEncrypted, byte[] passwordBytes) { byte[] encryptedBytes = null;
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;
}
这是无法工作的php代码:
$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;
有人能帮我解决这个问题或者给我一个提示我做错了什么吗?在我看到的Java代码中
AES.BlockSize=256代码>。从技术上讲,AES具有128位的固定块大小。Rijndael支持可变块大小,但AES不支持。如果您想在PHP和phpseclib中使用可变块大小,您需要执行以下操作:
$pw = "this_is_my_pw";
$aes = new Crypt_Rijndael(CRYPT_RIJNDAEL_MODE_CBC);
$aes->setKey($pw);
$aes->setKeyLength(256);
$aes->setBlockLength(256);
$aes->disablePadding();
此外,您的密钥长度为13字节。AES密钥需要16字节(128位)长、24字节(192位)长或32字节(256位)长。idk您正在使用的js库,但phpseclib 1.0/2.0 null会在键不够长时填充键。phpseclib的最新版本(目前正在开发中)引发异常
或者,您的意思是使用基于密码的密钥派生函数?phpseclib提供了两种可通过setPassword()
使用的方法,但如果是这种情况,您需要知道js库使用的方法和参数。如果您试图使用AES,请将块大小设置为128位,这是唯一受支持的块大小。使用不同的块大小意味着您使用的是Rijndael加密,这在跨平台上没有得到很好的支持
AES支持128、192和256位的多种密钥大小。有时在使用Rijndael实现使用AES加密时会出现混乱
解密时不使用初始化向量。您需要将初始化向量(IV)与数据一起发送-您的PHP代码从未从phpseclib调用$aes->setIV
,因此它将永远无法解密文本,因为phpseclib在未设置的情况下使用全零的IV。我个人建议使用C#生成一个安全的随机IV,但显然从PBKDF2密钥派生IV是可以接受的。PBKDF2(在RFC 2898中指定)是关键拉伸算法Rfc2898DeriveBytes
实现。无论如何,您需要在PHP端重新生成IV,无论这意味着使用加密数据传输IV(这是完全正确的),还是在PHP端重新派生IV
使用密码作为salt是一个非常糟糕的主意。salt必须具有足够的长度,并以加密方式随机生成。使用密码作为salt完全违背了拥有salt的意义。这说明了如何结合使用Rfc2898DeriveBytes
生成加密随机salt,但重要的是:
byte[]saltBytes=新字节[8];
使用(RNGCryptoServiceProvider rngCsp=new RNGCryptoServiceProvider())
{
//用随机值填充数组。
rngCsp.GetBytes(salt1);
}
salt必须与加密数据一起传输。您需要发送PBKDF2 salt字节以及IV字节和加密数据。phpseclib将需要所有这些来正确初始化自身和解密数据。您可能需要使用phpseclib来实现这一点,如下所示:
$salt=…;//以某种方式将盐添加到PHP代码中
$iv=…;//获取PHP代码的IV
$pw=“这是我的”;
$aes=新加密aes(加密aes模式CBC);
$aes->setPassword($pw,'pbkdf2'/*密钥扩展算法*/,,
'sha1'/*散列算法*/,$salt/*从C#*/*生成的salt,
1000/*迭代次数,必须与C#代码*/,
256/8/*密钥大小(字节),256位密钥/8位/字节*/
);
$aes->setIV($iv);
记住关于blocksize的其他答案。128位是标准的AES blocksize,因此请确保C#和phpseclib都能在较大的blocksize下正常工作,或者只使用AES标准
使用不完全支持长度的加密密钥取决于非标准密钥填充,这不是一个好主意,可能会导致互操作性困难。使用文本作为密钥也会降低安全性。在本例中,密码表示少于86位的密钥材料。@zaph-关于密钥大小的好发现-我实际上没有看到它。我刚刚注意到了块大小的一点,有点跳到了上面。答案是Rijndael(setBlockLength(256)
)不是AES,Rijndael允许密钥和块大小分别为128、160、192、224或256位。@zaph-正确。但是,OP使用的是RijndaelManaged AES=new RijndaelManaged()
和AES.BlockSize=256所以我这样做似乎是完全合理的。我在第二句话中也说了同样的话。引用它,从技术上讲,AES具有128位的固定块大小。Rijndael支持可变块大小,但AES并不是所有的好建议。1.有趣的是,有一个不正确的IV将导致第一个块被不正确地解密,但消息的其余部分将被正确地解密,这样的结果有助于指向一个不正确的IV。一个最佳实践是将IV预先添加到加密数据中。2.使用PBKDF2(在RFC 2898中指定)是一种最佳实践,并提供互操作性。还需要为解密提供迭代计数。