所以我有一点不寻常的情况,我的模板和教程经验似乎没有涵盖。
我正在编写一个程序,该程序会自动为另一个程序签署消息,该程序无法使用但API有限。有一个配置文件,其中包含一个字符串,告诉我的程序用于签名消息的哈希值。 该字符串存储在signatureAlgorithm对象中,该对象存储摘要,摘要应该是大小,并提供一些用于摘要编码的选项。 我正在使用Crypto ++库来进行散列函数。 现在我有一大组if / else if语句和每个语句中的三个命令,具体取决于算法应该是什么字符串,如下所示:
void signatureAlgorithm::createDigest(string input)
{
bool digestFail = false;
if (_algorithm == "md5")
{
//byte digest[ CryptoPP::MD5::DIGESTSIZE ];
_digestSize = (CryptoPP::MD5::DIGESTSIZE);
_digest = new byte[ _digestSize ];
CryptoPP::MD5().CalculateDigest( _digest, (byte*) input.c_str(), input.length() );
}
.....
else if (_algorithm == "sha256")
{
_digestSize = (CryptoPP::SHA256::DIGESTSIZE);
_digest = new byte[ _digestSize ];
CryptoPP::SHA256().CalculateDigest( _digest, (byte*) input.c_str(), input.length() );
}
else if (_algorithm == "sha512")
{
_digestSize = (CryptoPP::SHA512::DIGESTSIZE);
_digest = new byte[ _digestSize ];
CryptoPP::SHA512().CalculateDigest( _digest, (byte*) input.c_str(), input.length() );
}
else
digestFail = true;
if (!digestFail)
_ready = true;
else
_ready = false;
}
_digestSize将摘要大小存储在对象中,因为_digest对摘要的字节进行了处理(字节为typedef const unsigned char *),并且_ready用于其他函数以确定在赋予它之前已消化的值调用程序,或者将错误返回给程序。
我最终计划切换到地图以使事情更有效和更整洁,但在此之前,我必须找到一种方法来设置_digestSize并调用CreateDigest()更通用。我试图避免修改库,因为我想在最终版本中以编译形式维护Crypto ++的FIPS状态,但是现在我只是测试使用源代码,如果这会产生影响。
我考虑过模板,每个if语句的内部部分只是设置值,但我找不到以这种方式使用模板的示例。我发现它们用于创建有其他函数的类,但在这种情况下,我只需要能够创建一个通用类,如果我在这里想的话,它只是指向另一个类。
我正在尝试做的伪代码:
class tempClass {};
if (_algorithm == "md5")
{
tempClass = CryptoPP::MD5
}
......
else
digestFail = true;
_digestSize = (tempClass::DIGESTSIZE);
_digest = new byte[_digestSize];
tempClass().CalculateDigest( _digest, (byte*) input.c_str(), input.length() );
-Jimmy
编辑:虽然在评论中我说由于类树中的分叉,继承不起作用,但事实证明我一直在使用的文档是最新版本。我用于测试的版本和FIPS版本较旧,从MD5之类的功能分割成单独的“弱”结构之前。
编辑2:但是,我仍然很好奇是否有办法解决这个问题,即使这些类是分叉的并且没有从同一个地方继承CalculateDigest。
编辑3:John Bandela回答了这个问题,但我只是想改变他给我的一点点。更改在答案的评论中。谢谢大家!
答案 0 :(得分:0)
将代码分解为像这样的模板函数
//假设_digest和_digest大小是类成员;
template<class Digest>
byte* doDigest(string input, int& digestSize){
int digestSize = (Digest::DIGESTSIZE);
byte* digest = new byte[ digestSize ];
Digest().CalculateDigest( digest, (byte*) input.c_str(), input.length() );
return digest;
}
然后在你的createDigest函数中执行此操作
if (_algorithm == "md5")
{
_digest = doDigest<CryptoPP::MD5>(input,_digestSize);
}
else if (_algorithm == "sha256")
{
_digest = doDigest<CryptoPP::SHA256>(input,_digestSize);
}
...
关闭主题,但您可能需要考虑使用向量而不是字节*
答案 1 :(得分:0)
使用更多模板元编程的另一种方法
表示完整的可运行示例,请参阅
https://gist.github.com/4164700
template<class Digest, class... T>
struct DigestMatcher{
template<class U, class ... V>
static byte* doDigest(std::string input, int& digestSize,std::string algorithm,U firstalgorithm, U nextalgorithm, V... algorithms){
if(algorithm==firstalgorithm){
return doDigest(input,digestSize);
}
else{
return DigestMatcher<T...>::doDigest(input,digestSize,algorithm,nextalgorithm,algorithms...);
}
}
template<class U>
static byte* doDigest(std::string input, int& digestSize,std::string algorithm, U firstalgorithm){
if(algorithm==firstalgorithm){
return doDigest(input,digestSize);
}
else{
std::cout << algorithm << " invalid" << std::endl;
return 0;
}
}
static byte* doDigest(std::string input, int& digestSize){
// Cout for debug purposes
std::cout << "using " << typeid(Digest).name() << std::endl;
digestSize = Digest::DIGESTSIZE;
byte* digest = new byte[ digestSize ];
Digest().CalculateDigest( digest, (byte*) input.c_str(), input.length() );
return digest;
}
};
然后是你的主叫代码
void signatureAlgorithm::createDigest(std::string input)
{
_digest = DigestMatcher<MD5,SHA256,SHA512>::doDigest(input,_digestSize,_algorithm,"md5","sha256","sha512");
if(_digest)
_ready = true;
else
_ready = false;
}