RSA文件系统崩溃 [英] RSA File System Crash

查看:68
本文介绍了RSA文件系统崩溃的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我这个程序遇到了一些与RSA有关的问题。它从部分文件中读取数据,除解密过程中的崩溃外没有链接器或运行时错误。我有点陷入困境,为什么这不起作用,我不知道如何解决这个问题。

I've been having a few issues with this program that is meant to work with RSA. It reads data from a file in parts and has no linker or run time errors other than a crash during decryption. I am a little bit at a brick wall with why this doesn't work and I have no idea how to remedy this issue.

#include <iostream>
#include <string>
// Linked via .lib file with VS2015 console
#include "lib/rsa.h"
#include "lib/modes.h"      
#include "lib/filters.h"
#include "lib/files.h"
#include "lib/hex.h"
#include "lib/randpool.h"
#include "lib/cryptlib.h"
#include "lib/seed.h"
#include "lib/osrng.h"

using namespace CryptoPP;
using namespace std;

class Core
{
private:
	// Pretty much everything under private in this class is from the wiki. So far it all seems to work rather well.
	void Load(const string& filename, BufferedTransformation& bt)
	{
		// http://www.cryptopp.com/docs/ref/class_file_source.html
		FileSource file(filename.c_str(), true /*pumpAll*/);

		file.TransferTo(bt);
		bt.MessageEnd();
	}

	void Save(const string& filename, const BufferedTransformation& bt)
	{
		// http://www.cryptopp.com/docs/ref/class_file_sink.html
		FileSink file(filename.c_str());

		bt.CopyTo(file);
		file.MessageEnd();
	}

	void SavePrivateKey(const string& filename, const PrivateKey& key)
	{
		// http://www.cryptopp.com/docs/ref/class_byte_queue.html
		ByteQueue queue;
		key.Save(queue);

		Save(filename, queue);
	}

	void SavePublicKey(const string& filename, const PublicKey& key)
	{
		// http://www.cryptopp.com/docs/ref/class_byte_queue.html
		ByteQueue queue;
		key.Save(queue);

		Save(filename, queue);
	}

	void LoadPrivateKey(const string& filename, PrivateKey& key)
	{
		// http://www.cryptopp.com/docs/ref/class_byte_queue.html
		ByteQueue queue;

		Load(filename, queue);
		key.Load(queue);	
	}

	void LoadPublicKey(const string& filename, PublicKey& key)
	{
		// http://www.cryptopp.com/docs/ref/class_byte_queue.html
		ByteQueue queue;

		Load(filename, queue);
		key.Load(queue);	
	}
	
	// Encode and Decode do what they are labled as
	void encode(string in,string &out,string keyFileName)
	{
		AutoSeededRandomPool rng;
		RSA::PublicKey publicKey;
		LoadPublicKey(keyFileName,publicKey);
		RSAES_OAEP_SHA_Encryptor e(publicKey);
			StringSource ss1(in, true,
				new PK_EncryptorFilter(rng, e,
					new StringSink(out)
			   ) // PK_EncryptorFilter
			); // StringSource
	}
	
	void decode(string in,string &out,string keyFileName)
	{
		AutoSeededRandomPool rng;
		RSA::PrivateKey privateKey;
		LoadPrivateKey(keyFileName,privateKey);
		RSAES_OAEP_SHA_Decryptor d(privateKey);
		StringSource ss2(in, true,
			new PK_DecryptorFilter(rng, d,
				new StringSink(out)
		   ) // PK_DecryptorFilter
		); // StringSource
	}
	
public:
	// The title says it all
	void makeKeys()
	{
		AutoSeededRandomPool rnd;
		RSA::PrivateKey rsaPrivate;
		rsaPrivate.GenerateRandomWithKeySize(rnd, 3072);

		RSA::PublicKey rsaPublic(rsaPrivate);

		SavePrivateKey("rsa-private.Rkey", rsaPrivate);
		SavePublicKey("rsa-public.Rkey", rsaPublic);
	}


	void encodeFile(string inputFileName,string outputFileName,string keyFileName)
	{
		// Stuff that runs the file
		string in;
		size_t buffer_size = 342;
		string buffer(buffer_size,'\0');
		ifstream fileStreamIn(inputFileName,ios::binary);
		ofstream fileStreamOut(outputFileName,ios::binary);
		while(fileStreamIn)
		{
			fileStreamIn.read(&buffer.front(), buffer_size);
			size_t count = fileStreamIn.gcount();
			buffer.resize(count);
			encode(buffer,in,keyFileName);		
			buffer = in;			
			fileStreamOut.write(buffer.c_str(),buffer.length()); 
			buffer.resize(buffer_size);
			buffer = "";
			in = "";
			if (!count) 
			break;  
		}
		fileStreamIn.close();
		fileStreamOut.close();
	}
	// This function for one reason or another seems to cause a crash
	void decodeFile(string inputFileName,string outputFileName,string keyFileName)
	{
		// Stuff that runs the file
		string in;
		size_t buffer_size = 384;
		string buffer(buffer_size,'\0');
		ifstream fileStreamIn(inputFileName,ios::binary);
		ofstream fileStreamOut(outputFileName,ios::binary);
		while(fileStreamIn)
		{
			fileStreamIn.read(&buffer.front(), buffer_size);
			size_t count = fileStreamIn.gcount();
			buffer.resize(buffer_size);
		
			// This bit of logic is to prevent crash
			if(count == buffer_size)
			{
				decode(buffer,in,keyFileName);
			}
			buffer = in;
			fileStreamOut.write(buffer.c_str(),buffer.length()); 

			buffer = "";
			in = "";
			if (!count) 
			break;  
		}
		fileStreamIn.close();
		fileStreamOut.close();
	}
};

void main ()
{
	Core Function;
//	Function.makeKeys(); 
	Function.encodeFile("in","out","rsa-public.Rkey");
	Function.decodeFile("out","out1","rsa-private.Rkey");	

}
// The build file using the .lib file
/*
call "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat" x86_amd64
del main.exe
cl /EHsc /c main.cpp
link /LTCG main.obj cryptlibX64.lib /out:main.exe
del main.obj
timeout /t 9000 /nobreak
*/

推荐答案

这一行可能是来源:

This line might be the source:
fileStreamIn.read(&buffer.front(), buffer_size);



不应直接修改 std :: string 的内容。您在这里使用 front(),它允许修改引用的字符。但是你用它来修改字符串内容。因为 ifstream :: read()没有追加NULL字符,所以这可能适用于第一次调用(当字符串仍然填充NULL字符时),但会导致剩余的字符当读取较少时,可能会在最后一次读取时发生。



此外,稍后通过分配编码的字符串重新使用该字符串然后设置为一个空字符串(有效地在前面放置一个NULL字符)。因此,当文件的下一次读取没有使用全长时,字符串末尾会有随机字符。

[/ EDIT]



我不会在这里使用 std :: string 作为缓冲区类型,而只是 char 数组并追加读取后为NULL字节。如果您不想重写 decode 函数来使用 char * ,只需传递一个临时字符串(std) :: string(buffer))。



当使用 char 数组时,大小必须是比最大值多一个。从文件中读入以存储终止空字符的字符数。







一个可能的解决方案,将整个文件读入一个字符串并在之后解码(未经测试):


The content of a std::string should not be modified directly. You are using front() here which allows the modification of the referenced character. But you are using it to modifiy the string content. Because ifstream::read() does not append a NULL character, this might work with the first call (when the string is still filled with NULL chars) but results in remaining characters when less has been read in which probably occurs with the last reading.

Additionally the string is re-used later by assigning the encoded string and then set to an empty string (which effectively places a NULL character in front). As a result there are random characters at the end of the string when the next reading from file did not not use the full length.
[/EDIT]

I would not use std::string as buffer type here but just a char array and append a NULL byte after reading. If you don't want to rewrite your decode function to use a char*, just pass a temporary string (std::string(buffer)).

When using a char array, the size must be one more than the max. number of chars read in from file to store the terminating NULL character.



A possible solution reading the whole file into a string and decoding it afterwards (untested):

void decodeFile(string inputFileName,string outputFileName,string keyFileName)
{
    string fileBuffer;
    ifstream fileStreamIn(inputFileName,ios::binary);
    ofstream fileStreamOut(outputFileName,ios::binary);
    while(fileStreamIn)
    {
        // Local buffer to be filled from file
        char readBuffer[385];
        // Read from file letting space for terminating NULL char
        fileStreamIn.read(readBuffer, sizeof(read_buffer) - 1);
        size_t count = fileStreamIn.gcount();
        // Terminate local string
        readBuffer[count] = '\0';
        // Append to input file buffer
        fileBuffer += readBuffer;
    }
    std::string decoded;
    decode(fileBuffer, decoded, keyFileName);
    fileStreamOut.write(decoded.c_str(), decoded.length()); 
    fileStreamIn.close();
    fileStreamOut.close();
    }
};





另一个提示:

当你传递字符串时应该通过引用传递它们。实际上,您将始终创建该字符串的副本。此外,未修改的字符串应为const。结果函数定义如下:



And another tip:
When passing strings you should pass them by reference. Actually you will always create a copy of the string. Additionally, strings that are not modified should be const. The resulting function definitions are then:

void decodeFile(const string& inputFileName, const string& outputFileName, const string& keyFileName);
void decode(const string& in, string &out, const string& keyFileName);



与其他函数类似。但请注意,在调用另一个需要非const参数的函数时,不能使用 const 修饰符(对于 LoadPrivateKey() ss2())。


这篇关于RSA文件系统崩溃的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆