0

所以我有一个不寻常的情况,我在模板和教程方面的经验似乎没有涵盖。

我正在编写一个程序,该程序会自动为另一个无法使用但 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() );

-吉米

编辑:虽然在评论中我说由于类树中的分叉而继承不起作用,但事实证明我一直在使用的文档是最新版本的。我用于测试的版本和 FIPS 版本较旧,从之前像 MD5 等功能被拆分成一个单独的“弱”结构。

编辑2:但是,我仍然很好奇是否有办法解决这个问题,即使这些类是分叉的并且没有从同一个地方继承CalculateDigest。

编辑 3:约翰班德拉回答了这个问题,但我只需要稍微改变他给我的东西。更改在答案的评论中。谢谢大家!

4

2 回答 2

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;
}
于 2012-11-28T21:35:04.537 回答
0

将代码分解成这样的模板函数

// 假设 _digest 和 _digest size 是类成员;

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);
}
...

离题,但您可能需要考虑使用向量而不是字节*

于 2012-11-28T20:01:18.550 回答