通用恒定时间比较函数C
Generic constant time compare function c++
我正在编写一个受保护的PTTR类,该类使用Windows Crypto API保护内存中的对象,并且我遇到了一个问题,可以创建一个通用的恒定时间比较函数。我当前的代码:
template <class T>
bool operator==(volatile const ProtectedPtr& other)
{
std::size_t thisDataSize = sizeof(*protectedData) / sizeof(T);
std::size_t otherDataSize = sizeof(*other) / sizeof(T);
volatile auto thisData = (byte*)getEncyptedData();
volatile auto otherData = (byte*)other.getEncyptedData();
if (thisDataSize != otherDataSize)
return false;
volatile int result = 0;
for (int i = 0; i < thisDataSize; i++)
result |= thisData[i] ^ otherData[i];
return result == 0;
}
getencrypteddata函数:
std::unique_ptr<T> protectedData;
const T& getEncyptedData() const
{
ProtectMemory(true);
return *protectedData;
}
问题正在施放到字节*。当与字符串一起使用此课程时,我的编译器抱怨说,字符串无法施放给字节指针。我一直在想可能试图将我的功能从GO的ConstantTimeByTeeq函数中脱离,但这仍然使我回到了将模板类型转换为int或可以预先二进制二进制操作的最初问题。
GO的ConstantTimeByTeeq函数:
func ConstantTimeByteEq(x, y uint8) int {
z := ^(x ^ y)
z &= z >> 4
z &= z >> 2
z &= z >> 1
return int(z)
}
我如何轻松地将模板类型转换为可以在其上容易预先构造的二进制操作的东西?
update 根据lockcmpxchg8b的建议工作通用常数比较函数:
//only works on primative types, and types that don't have
//internal pointers pointing to dynamically allocated data
byte* serialize()
{
const size_t size = sizeof(*protectedData);
byte* out = new byte[size];
ProtectMemory(false);
memcpy(out, &(*protectedData), size);
ProtectMemory(true);
return out;
}
bool operator==(ProtectedPtr& other)
{
if (sizeof(*protectedData) != sizeof(*other))
return false;
volatile auto thisData = serialize();
volatile auto otherData = other.serialize();
volatile int result = 0;
for (int i = 0; i < sizeof(*protectedData); i++)
result |= thisData[i] ^ otherData[i];
//wipe the unencrypted copies of the data
SecureZeroMemory(thisData, sizeof(thisData));
SecureZeroMemory(otherData, sizeof(otherData));
return result == 0;
}
通常,您要在当前代码中要完成的工作称为格式保存加密。即,要加密std::string
,以使所得的密文也是有效的std::string
。这要比让加密过程从原始类型转换为一个字节的平面阵列要难得多。
要将转换为平面数组,声明"序列化器"对象的第二个模板参数,该对象知道如何将T型对象序列化为无符号字符的数组。您可以将其默认为通用的sizeof
/memcpy
序列化器,该序列化器适用于所有Primitve类型。
这是std::string
的示例。
template <class T>
class Serializer
{
public:
virtual size_t serializedSize(const T& obj) const = 0;
virtual size_t serialize(const T& obj, unsigned char *out, size_t max) const = 0;
virtual void deserialize(const unsigned char *in, size_t len, T& out) const = 0;
};
class StringSerializer : public Serializer<std::string>
{
public:
size_t serializedSize(const std::string& obj) const {
return obj.length();
};
size_t serialize(const std::string& obj, unsigned char *out, size_t max) const {
if(max >= obj.length()){
memcpy(out, obj.c_str(), obj.length());
return obj.length();
}
throw std::runtime_error("overflow");
}
void deserialize(const unsigned char *in, size_t len, std::string& out) const {
out = std::string((const char *)in, (const char *)(in+len));
}
};
将对象降低到unsigned char
s的平坦阵列后,您给定的恒定时间比较算法就可以正常工作。
这是使用上面序列化器的示例代码的真正愚蠢的版本。
template <class T, class S>
class Test
{
std::unique_ptr<unsigned char[]> protectedData;
size_t serSize;
public:
Test(const T& obj) : protectedData() {
S serializer;
size_t size = serializer.serializedSize(obj);
protectedData.reset(new unsigned char[size]);
serSize = serializer.serialize(obj, protectedData.get(), size);
// "Encrypt"
for(size_t i=0; i< size; i++)
protectedData.get()[i] ^= 0xa5;
}
size_t getEncryptedLen() const {
return serSize;
}
const unsigned char *getEncryptedData() const {
return protectedData.get();
}
const T getPlaintextData() const {
S serializer;
T target;
//"Decrypt"
for(size_t i=0; i< serSize; i++)
protectedData.get()[i] ^= 0xa5;
serializer.deserialize(protectedData.get(), serSize, target);
return target;
}
};
int main(int argc, char *argv[])
{
std::string data = "test";
Test<std::string, StringSerializer> tester(data);
const unsigned char *ptr = tester.getEncryptedData();
std::cout << ""Encrypted" bytes: ";
for(size_t i=0; i<tester.getEncryptedLen(); i++)
std::cout << std::setw(2) << std::hex << std::setfill('0') << (unsigned int)ptr[i] << " ";
std::cout << std::endl;
std::string recov = tester.getPlaintextData();
std::cout << "Recovered: " << recov << std::endl;
}
输出:
$ ./a.out
"Encrypted" bytes: d1 c0 d6 d1
Recovered: test
编辑:回答针对Primtive/Flat类型的通用序列化器的请求。将其视为伪代码,因为我在不进行测试的情况下将其输入到浏览器中。我不确定这是否是正确的模板语法。
template<class T>
class PrimitiveSerializer : public Serializer<T>
{
public:
size_t serializedSize(const T& obj) const {
return sizeof obj;
};
size_t serialize(const T& obj, unsigned char *out, size_t max) const {
if(max >= sizeof obj){
memcpy(out, &obj, sizeof obj);
return sizeof obj;
}
throw std::runtime_error("overflow");
}
void deserialize(const unsigned char *in, size_t len, T& out) const {
if(len < sizeof out) {
throw std::runtime_error("underflow");
}
memcpy(&out, in, sizeof out);
}
};
我很好奇编译器给您什么错误。
也就是说,尝试铸造到const char*
或const void*
。
另一个问题可能是从64位指针到8位byte
的铸造。尝试铸造到int
,long
或longlong
编辑:基于您的反馈,另一个较小的更改:
volatile auto thisData = (byte*)&getEncyptedData();
volatile auto otherData = (byte*)&other.getEncyptedData();
(注意ampersands)。这将允许以前的演员工作
- C++自定义比较函数
- 使用自定义比较函数使用std::sort()对矢量字符串进行排序时出现问题
- C++模板函数,用于比较任何无符号整数和有符号整数
- 函数类作为比较器
- 什么是自定义比较器以及如何在 C++ 的排序函数中使用它?
- 没有默认构造函数作为模板参数的自定义比较器
- std::max() 函数与定点实现的比较中的问题
- 如何比较两个函数的速度和性能
- 对没有比较器或λ函数的向量进行排序?
- 使用迭代器的自定义比较器函数
- 隐式转换为比较函数对象(函子)用于 std::sort 而不是 std::map?
- 比较 n 女王的 next_permutation 函数
- 用于基于成员字段或函数创建比较器的快捷方式
- 为什么 std::stable_sort() 的比较函数的参数必须是设置常量?
- 为什么在类或结构中传递自定义比较器函数?
- 浮点数比较为什么没有相等的函数
- 通过默认复制构造函数比较 C++ 字符串是否会影响性能,原因为何?
- 为什么函数比较器不像在排序中那样在优先级队列中工作?
- c++ STL集合的比较函数:比较函数可以是类的成员函数吗?
- 联合值的单函数比较