我正在用128位密钥进行一些加密,这需要使用16字节的数据块,我将这些数据块存储为16字节的无符号字符数组。

unsigned char nonce_counter[16] = "xCv6Jk0neeV5GoSZ";

我经常需要把这个值当作一个数字来做一些计算,但是我似乎找不到一种安全的方法来对这个值进行类型转换。
如何将16字节值转换为数字数据类型?
具体来说,我需要使用逐位异或A^B并递增A++。
我知道我可以做显而易见的事情,使用for循环并独立处理数组的每个元素,但我担心这样做会降低效率。
我的系统不支持__uint128_t

最佳答案

如何将16字节值转换为数字数据类型?
我的系统不支持uint128。
如果编译器不支持128位类型,则没有数值数据类型解决方案。
一个有用的替代方案是Aunion
避免将字符数组指针强制转换为更宽整数的指针。它会导致对齐错误(总线故障)。
对于这类应用程序,使用uint8_t比使用unsigned char更为清楚。

#include <stdint.h>
typedef union {
  uint8_t u8[16];
  uint64_t u64[2];
} my_uint128;

下面这样的代码需要解决endian问题。
void foo() {
  my_uint128 nonce_counter = { .u8 =  "xCv6Jk0neeV5GoSZ"};
  btoh_128(&nonce_counter); // this would be a no-op on a BE machine
  ...

^是endian安全的。
inline my_uint128 xor_128(my_uint128 a, my_uint128 b) {
  return (my_uint128) { .u64[0] = a.u64[0] ^ b.u64[0], .u64[1] = a.u64[1] ^ b.u64[1]};
}

增量需要更多的工作。LSB_128根据endian定义为0或1。
inline my_uint128 inc_128(my_uint128 a) {
  if (++a.u64[LS_128] == 0) {
    ++a.u64[MS_128]
  }
  return a;
}

我担心这样做会失去效率。
尝试上述方法,并在放弃此方法之前验证效率损失。给编译器一个优化的机会。
uint64_t u64[2];LS_128的另一种选择是struct { uint64_t ms,ls; };按照平台的端部顺序ls, ms
这种方法的一个优点是,union可以包含一个uint128_t成员(如果支持)。然后,各种例程可以使用直接的128位数学,而无需更改调用代码。

07-27 14:02