Я пытаюсь преобразовать источник C++ в C#, который шифрует и дешифрует файл с использованием криптографии Rinjdael.Как преобразовать криптографию C++ Rijndael в C#, когда есть ошибка, говорящая, что «Заполнение недопустимо и не может быть удалено»?
Но источник C++ имеет немного отличное от нормального en/decryptions.
И я не очень хорош в C++, поэтому я сбиваюсь с толку.
Одно из приложений моих клиентов написано на VC++, и преобразовать его в C# является частью моей работы.
И предыдущий разработчик C++ использовал открытый код от http://www.codeproject.com/Articles/10657/A-Simple-Portable-Rinjdael-AES-Based-Stream-Cipher для управления en/decryption.
Вот исходные коды 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), первые 25 байтов заполняются данными пользователя (подпись, отступов и статус файла). Итак, я пропустил первые 25 байтов и сохранил оставшиеся байты в _restFileBytes varialbes (массив байтов).
И у Keesler есть переменная с названием chunk size, которая разбивает байты файлов на размер блока (если я понимаю).
В любом случае, я думаю, что почти конвертирован в C#, но я все еще получаю это сообщение об ошибке «Заполнение недопустимо и не может быть удалено», когда CryptoStream удаляет C#.
Может ли кто-нибудь дать мне руководство по исправлению этой ошибки?
Можете ли вы также опубликовать свой шифрованный код, возможно, у вас есть такая же проблема, о которой сообщалось здесь: http://stackoverflow.com/questions/8583112/padding-is-invalid-and-cannot-be-removed?rq=1 –
@ RodrigoLópez Вы имеете в виду мой код шифрования в C#? Я еще не начал его. У меня есть только код C++. –
@deviantfan Что вы имеете в виду, я не должен публиковать этот код. Это уже открытый исходный код, поскольку я упомянул исходный URL-адрес источника. Конечно, я бы с удовольствием использовал встроенные Rijndael calss, но есть так много файлов, зашифрованных предыдущим проектом C++, и мне все еще нужно, чтобы мое приложение было в состоянии en/decrypt этих файлов. –