gpt4 book ai didi

c# - 当出现 "Padding is invalid and cannot be removed"错误时,如何将 C++ Rijndael 密码学转换为 C#?

转载 作者:行者123 更新时间:2023-11-28 06:16:35 25 4
gpt4 key购买 nike

我正在尝试将 C++ 源代码转换为 C#,后者使用 Rinjdael 密码学加密和解密文件。

但 c++ 源代码与正常的加密/解密有一点不同。

而且我不太擅长 C++,所以我很困惑。

我的一个客户的应用程序是用 VC++ 编写的,将其转换为 C# 是我工作的一部分。

而之前的 c++ 开发人员使用了来自 http://www.codeproject.com/Articles/10657/A-Simple-Portable-Rinjdael-AES-Based-Stream-Cipher 的开源代码操纵加密/解密。

这里是c++源代码。

int DCipher::DecryptFile(LPCTSTR szSrcFile, LPCTSTR szDestFile, const char* pwd, int head[19])
{
if(CheckMemSize() != 0)
return INSUFFICIENT_MEMORY;

FileSize=CurPosition=0;

_tcscpy(SrcFile, szSrcFile);
_tcscpy(OutFile, szDestFile);
//_tcscpy(OutFile, _T(".enc"));

strcpy(password, pwd);

for(int i=0; i<19; i++)
{
header[i] = head[i];
}

FILE *r, *w;
GetFileLength();

int nCheck = CheckIfEncrypted();

if(nCheck != ENCRYPTED_FILE )
return nCheck; //either NORMAL_FILE or BAD_SIGNATURE


if((r = _tfopen(SrcFile, _T("rb"))) == NULL)
return ERROR_SRC_FILE;


if((w = _tfopen(OutFile, _T("wb"))) == NULL)
{
fclose(r);
return ERROR_DST_FILE;
}

char zzz[26]; //fixed invalid pointer - DKeesler
fread(zzz, 25, 1, r); // Skip first 25 bytes of the file.

int pad = header[19];
pad *= 10;
pad += header[20];

// convert password to Rijndael key
strcpy((char*)key, (const char*)CalcMD5FromString((const char*)password));

/***************************************
Decryption algorithm
***************************************/
int rval = NO_ERRORS_DONE;
FileSize -= 25;

unsigned int BUFF_SIZE = liChunkSize;
unsigned int WRITE_SIZE = liChunkSize;

int nRound = FileSize / liChunkSize;
unsigned int LAST_BLOCK = FileSize % liChunkSize;

if(LAST_BLOCK >= 1)
nRound++;

const unsigned char* intext;
unsigned char* output;

intext = (const unsigned char*)malloc(BUFF_SIZE);
output = (unsigned char*)malloc(BUFF_SIZE+16);

if(intext == NULL || output == NULL)
{
fclose(r);
fclose(w);
return ALLOC_ERROR;
}

Rijndael rj;
rj.init(Rijndael::CBC, Rijndael::Decrypt, key, Rijndael::Key32Bytes);

for(int loop=1; loop <= nRound; loop++)
{

if(loop == nRound && LAST_BLOCK >= 1)
{
BUFF_SIZE = LAST_BLOCK;
WRITE_SIZE = LAST_BLOCK - pad;
}

fread((void*)intext, sizeof(char), BUFF_SIZE, r); // read plaintext into intext[] buffer

int bsize = BUFF_SIZE*8;
int len = rj.blockDecrypt((const UINT8*)intext, bsize, (UINT8*)output);

if(len >= 0)
{
fwrite((const void*)output, sizeof(char), WRITE_SIZE, w);
}
else
{
rval = READ_WRITE_ERROR;
break;
}
}

fclose(r); //close input file
fclose(w); //close output file

free((void*)intext);
free((void*)output);

//change these two lines if you want to leave backups or unencrypted copies...
//that would sort of defeat the purpose of encryption in my mind, but it's your
// app so write it like you want it.
if(DECRYPTION_CANCEL == rval) {
_tremove(OutFile);
}
else {
//_tremove(SrcFile); //remove input file
//_trename(OutFile, SrcFile); //rename output file to input filename
}

return rval; //ZERO .. see defines for description of error codes.
}

而c#源码来自https://msdn.microsoft.com/en-us/library/system.security.cryptography.rijndael(v=vs.110).aspx .

然后我更改了一些代码。

这是 C# 代码。

public int DecryptFile(string SourceFilePath, string DestFilePath, string Password, string Signature)
{
try
{
FileSize = CurPosition = 0;

FileInfo _fi = new FileInfo(SourceFilePath);
FileSize = _fi.Length;

// copy the signature to _header
for(int i = 0; i < 19; i++)
{
_header[i] = (byte)Signature[i];
}

/*
* check if the file is valid encrypted file.
*/
int nCheck = this.CheckIfEncrypted(SourceFilePath);
switch (nCheck)
{
case ENCRYPTED_FILE:
// The file is an encrypted file.
break;
case NORMAL_FILE:
throw new ArgumentException("The file is a normal file.");
case BAD_SIGNATURE:
throw new ArgumentException("User signature doesn't match.");
}

int pad = _header[19];
pad *= 10;
pad += _header[20];

// Rijndael session key
byte[] session_key = this.CalcMD5FromString(Password);

byte[] _restFileBytes = new byte[_fi.Length - 25];
using (FileStream _fs = new FileStream(SourceFilePath, FileMode.Open, FileAccess.Read))
{
_fs.Read(_restFileBytes, 0, _restFileBytes.Length);
}

int rval = NO_ERRORS_DONE;
FileSize -= 25;

int BUFF_SIZE = liChunkSize;
int WRITE_SIZE = liChunkSize;

int nRound = (int)FileSize / liChunkSize;
int LAST_BLOCK = (int)FileSize % liChunkSize;

if(LAST_BLOCK >= 1)
nRound++;

byte[] intext = new byte[BUFF_SIZE];
byte[] output = new byte[BUFF_SIZE + 16];

if (intext.Length == 0 || output.Length == 0)
{
return ALLOC_ERROR;
}

for (int loop = 1; loop <= nRound; loop++)
{
if (loop == nRound && LAST_BLOCK >= 1)
{
BUFF_SIZE = LAST_BLOCK;
WRITE_SIZE = LAST_BLOCK - pad;
}

intext = new byte[BUFF_SIZE];

System.Buffer.BlockCopy(_restFileBytes, (loop - 1) * this.liChunkSize, intext, 0, BUFF_SIZE);

int bsize = BUFF_SIZE * 8; // -> I still couldn't figure out what this bsize does on Rijndael decryption.
using (RijndaelManaged myRijndael = new RijndaelManaged())
{
myRijndael.Key = session_key;
//myRijndael.BlockSize = bsize;
//myRijndael.Padding = PaddingMode.None;
myRijndael.GenerateIV();

using (Rijndael rijAlg = Rijndael.Create())
{
rijAlg.Key = myRijndael.Key;
rijAlg.IV = myRijndael.IV;

// Create a decrytor to perform the stream transform.
ICryptoTransform decryptor = rijAlg.CreateDecryptor(rijAlg.Key, rijAlg.IV);

// Create the streams used for decryption.
using (MemoryStream msDecrypt = new MemoryStream(intext))
{
using (CryptoStream csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read))
{
//using (StreamReader srDecrypt = new StreamReader(csDecrypt))
//{
// // Read the decrypted bytes from the decrypting stream and place them in a string.
// //string s = srDecrypt.ReadToEnd();
//}
byte[] rettt = msDecrypt.ToArray();
} // --> Padding is invalid and cannot be removed error occurs here and msDecrypt byte array is just same as intext. So, it's not decrypted at all.
}

}
}
}


return rval;
}
catch
{
throw;
}
}

根据 Keesler(他是 codeproject.com 的 c++ 源代码的作者),前 25 个字节填充了用户数据(签名、填充和文件状态)。因此,我跳过了前 25 个字节并将其余字节保存到 _restFileBytes varialbes(字节数组)。

而 Keesler 有一个名为 chunk size 的变量,它将文件字节拆分为 block 大小(只要我理解)。

无论如何,我想我几乎转换为 c#,但当在 c# 中部署 CryptoStream 时,我仍然收到此错误消息“填充无效且无法删除”。

谁能给我一些指导来修复这个错误?

最佳答案

None 应该用作填充模式。看来您的同事和原始文章的作者制定了他们自己的填充方案。

此外,所有密文都应该从文件中流式传输(确保您读取了所有字节)。目前您正在为每个 block 重新使用 IV 进行加密,这并不好,IV 应该只在密文的开头使用。

在开始之前为 C++ 和 C# 打印出十六进制的 key 并进行比较。

请注意,Read 方法与 C++ 中的 fread 方法略有不同。

关于c# - 当出现 "Padding is invalid and cannot be removed"错误时,如何将 C++ Rijndael 密码学转换为 C#?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30158411/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com