1月22日,Qian提出了对于IDA实验中的时间结果不太好的问题,希望可以对IDA的实现进行改进。主要问题是IDA disperse部分速度似乎比较慢,要比一般的对称加密还要慢一些,而其他相关工作中IDA的效率似乎要高不少,所以有必要重新修正一下IDA部分的相关实现。
(我不得不再次表示CSDN博客编辑系统太垃圾了,连一些基本的撤销、redo等功能都不支持,导致在格式上编辑博文十分不方便!!!)
首先,需要回顾越三个月前的实验过程(这时,更加发现以后必须要在项目实现的过程中好好的做好记录,做好相关代码、文档的管理)。找到原来的相关代码:
timetest.cc:
//g++ -std=c++0x -c timetest.cc -o timetest.o -lcryptopp
//g++ -std=c++0x timetest.o ida_rel.o -o crytimetest -lcryptopp
#include<sys/time.h>
#include<iostream>
#include <unistd.h>
#include <sys/types.h> /* basic system data types */
//#include <sys/socket.h> /* basic socket definitions */
//#include <netinet/in.h> /* sockaddr_in{} and other Internet defns */
//#include <arpa/inet.h> /* inet(3) functions */
#include <netdb.h> /*gethostbyname function */
//#include <iostream>
#include <cstdlib>
//#include <errno.h>
#include <stdio.h>
//#include <cstring>
//#include <sstream>
#include <time.h>
//#include <vector>
//#include <pthread.h>
#include<fstream>
//#include "trans_rel.h"
#include "ida_rel.h"
using namespace CryptoPP;
using namespace std;
int main( )
{
struct timeval tv1;
struct timeval tv2;
AutoSeededRandomPool prng;
string IDAin;
string IDAkey("key_en");
byte key[AES::DEFAULT_KEYLENGTH];
cout<<"AES key length:"<<AES::DEFAULT_KEYLENGTH<<endl;
prng.GenerateBlock(key, sizeof(key));
string cipher, keyencoded, recovered;
keyencoded.clear();
StringSource(key, sizeof(key), true,
new HexEncoder(
new StringSink(keyencoded)
) // HexEncoder
); // StringSource
cout << "The initial genetate AES key(hex): " << keyencoded << endl;
ofstream fkey(IDAkey.data());
fkey<< keyencoded;
fkey.close();
ofstream timef("crytime",ofstream::app);
try{// encrypt the file it will respond.
gettimeofday(&tv1,NULL);
ECB_Mode< AES >::Encryption e;
e.SetKey(key, sizeof(key));
AESEncryptFile("Cfile","cipherM",e);
gettimeofday(&tv2,NULL);
IDAin = "cipherM";
timef<<"AES Encryption "<<1000000*(tv2.tv_sec-tv1.tv_sec)+tv2.tv_usec-tv1.tv_usec<<endl;
cout<<"k:"<<4<<"n:"<<6<<endl;
InformationDisperseFile(4, 6, IDAin.data());
gettimeofday(&tv1,NULL);
timef<<"IDA disperse "<<1000000*(tv1.tv_sec-tv2.tv_sec)+tv1.tv_usec-tv2.tv_usec<<endl;
}
catch( const CryptoPP::Exception & e){
cerr << e.what() << endl;
exit(1);
}
vector< const char *> v_keys;
v_keys.clear();
v_keys.push_back("cipherM.000");
v_keys.push_back("cipherM.001");
v_keys.push_back("cipherM.002");
v_keys.push_back("cipherM.003");
gettimeofday(&tv1,NULL);
InformationRecoverFile(4, "cipherM_idarecv",v_keys);
gettimeofday(&tv2,NULL);
timef<<"IDA recovery "<<1000000*(tv2.tv_sec-tv1.tv_sec)+tv2.tv_usec-tv1.tv_usec<<endl;
ECB_Mode< AES >::Decryption d;
d.SetKey(key,sizeof(key));
// The StreamTransformationFilter removes
// // padding as required.
AESDecryptFile("cipherM_idarecv","file_aesde",d);
gettimeofday(&tv1,NULL);
timef<<"AES decryption "<<1000000*(tv1.tv_sec-tv2.tv_sec)+tv1.tv_usec-tv2.tv_usec<<endl;
getchar();
return 0;
}
其中 cyrpto_rel.cpp为
#include"crypto_rel.h"
using namespace std;
using namespace CryptoPP;
void HexEncode(const char *in, const char *out)//Hex编码
{
FileSource(in, true, new HexEncoder(new FileSink(out)));
}
void HexDecode(const char *in, const char *out)//HEX解码
{
FileSource(in, true, new HexDecoder(new FileSink(out)));
}
//****************************************
void AESEncryptFile(const char *in, const char *out, CryptoPP::ECB_Mode< AES >::Encryption ee)//加密文件
{
FileSource f(in, true, new StreamTransformationFilter(ee, new FileSink(out)));
}
void AESDecryptFile(const char *in, const char *out, CryptoPP::ECB_Mode< AES >::Decryption dd)//解密文件
{
FileSource
f(in, true, new StreamTransformationFilter(dd, new FileSink(out)));
}
//*****************************************
void InformationDisperseFile(int threshold, int nShares, const char *filename)// IDA算法加密分配文件
{
assert(nShares<=1000);
ChannelSwitch *channelSwitch;
FileSource source(filename, false, new InformationDispersal(threshold, nShares, channelSwitch = new ChannelSwitch));
vector_member_ptrs<FileSink> fileSinks(nShares);
string channel;
for (int i=0; i<nShares; i++)
{
char extension[5] = ".000";
extension[1]='0'+byte(i/100);
extension[2]='0'+byte((i/10)%10);
extension[3]='0'+byte(i%10);
fileSinks[i].reset(new FileSink((string(filename)+extension).c_str()));
channel = WordToString<word32>(i);
fileSinks[i]->Put((byte *)channel.data(), 4);
channelSwitch->AddRoute(channel, *fileSinks[i], DEFAULT_CHANNEL);
}
source.PumpAll();
}
void InformationRecoverFile(int threshold, const char *outFilename, char *const *inFilenames)//IDA算法解密恢复文件(使用文件名)
{
assert(threshold<=1000);
InformationRecovery recovery(threshold, new FileSink(outFilename));
vector_member_ptrs<FileSource> fileSources(threshold);
SecByteBlock channel(4);
int i;
for (i=0; i<threshold; i++)
{
fileSources[i].reset(new FileSource(inFilenames[i], false));
fileSources[i]->Pump(4);
fileSources[i]->Get(channel, 4);
fileSources[i]->Attach(new ChannelSwitch(recovery, string((char *)channel.begin(), 4)));
}
while (fileSources[0]->Pump(256))
for (i=1; i<threshold; i++)
fileSources[i]->Pump(256);
for (i=0; i<threshold; i++)
fileSources[i]->PumpAll();
}
void InformationRecoverFile(int threshold, const char *outFilename, const std::vector<const char * > &vectorinfile)//IDA算法解密恢复文件(使用存储文件名的vector)
{
assert(threshold<=1000);
InformationRecovery recovery(threshold, new FileSink(outFilename));
vector_member_ptrs<FileSource> fileSources(threshold);
SecByteBlock channel(4);
int i;
for (i=0; i<threshold; i++)
{
fileSources[i].reset(new FileSource(vectorinfile[i], false));
fileSources[i]->Pump(4);
fileSources[i]->Get(channel, 4);
fileSources[i]->Attach(new ChannelSwitch(recovery, string((char *)channel.begin(), 4)));
}
while (fileSources[0]->Pump(256))
for (i=1; i<threshold; i++)
fileSources[i]->Pump(256);
for (i=0; i<threshold; i++)
fileSources[i]->PumpAll();
}
void GenerateRSAKey(unsigned int keyLength, const char *privFilename, const char *pubFilename, const char *seed)
{
RandomPool randPool;
randPool.IncorporateEntropy((byte *)seed, strlen(seed));
RSAES_OAEP_SHA_Decryptor priv(randPool, keyLength);
HexEncoder privFile(new FileSink(privFilename));
priv.DEREncode(privFile);
privFile.MessageEnd();
RSAES_OAEP_SHA_Encryptor pub(priv);
HexEncoder pubFile(new FileSink(pubFilename));
pub.DEREncode(pubFile);
pubFile.MessageEnd();
}
string RSAEncryptString(const char *pubFilename, const char *seed, const char *message)
{
FileSource pubFile(pubFilename, true, new HexDecoder);
RSAES_OAEP_SHA_Encryptor pub(pubFile);
RandomPool randPool;
randPool.IncorporateEntropy((byte *)seed, strlen(seed));
string result;
StringSource(message, true, new PK_EncryptorFilter(randPool, pub, new HexEncoder(new StringSink(result))));
return result;
}
string RSADecryptString(const char *privFilename, const char *ciphertext)
{
FileSource privFile(privFilename, true, new HexDecoder);
RSAES_OAEP_SHA_Decryptor priv(privFile);
string result;
StringSource(ciphertext, true, new HexDecoder(new PK_DecryptorFilter(GlobalRNG(), priv, new StringSink(result))));
return result;
}
仔细看了一下原先实现IDA的相关代码和crypto++库中相关的源代码(如http://www.cryptopp.com/docs/ref/ida_8cpp_source.html)后,发现这一问题可能与我们之前对算法的实现以及测量方法有关。
在我们之前的代码中,对于IDA、RSA、AES这些算法的函数实现都是以文件为输入输出的。如对于IDA coding,我们实现的函数中输入为一个文件,输出为n个编码后文件(我们的实验中常用参数n=6,k=4时)。采用这样的实现主要是因为crypto++对此有很好的函数API,实现起来比较容易。而且其他部分的代码以文件为接口时可以较好的模块化,方便对于实验中各种大小文件数据的内部存储。
这可能就是导致了“看起来” IDA没有symmetric encryption效率高的原因。因为,运行中发现IDA splitting(coding)过程本身的computation overheads并不高,但随之需要将大的运算结果保存到六个文件中,这个I/O overheads是相对很高的,所以显得整体效率不好。
例如某一次运行相关代码片段得到各部分时间overheads数据为(针对100k大小的原始文件):
AES Encryption函数 : 542 um
IDA coding本身:39 um
IDA 函数(输入输出皆为文件形式): 19177 um
IDA recovery函数: 6464 um
AES decryption函数: 321 um
可见,IDA coding本身的overheads并不算高。
这一可能性在您给我的第一篇论文中也有一定的支持:“It is worth noting that the computational overheads of reasure codes is neglible compared to the overheads of reading, writing or sending data.” (第二页最后一段)。
不过感觉这样修改后还是不对,因为
如果我们看一下crypto++中关于Source的说明,当为false时,只相当于把各个过滤器像水管一样拼接起来了,还没有真正的水(数据)流到里面去,只有到最后pumpAll()时,才真正拧开水龙头,放入数据!随意按上述代码中的方式加以测量还是不对的。。。。