8

我正在为 AES-GCM 实现做一个 GHASH。

GHASH

我需要实现这个

eqn

其中v是A的最后一个块的位长,u是C的最后一个块的位长,|| 表示位串的串联。

如何连接 A 块以填充从 v 到 128 位的零填充,因为我不知道 A 的整个块的长度。所以我只取 A 块并将其与 128 的数组进行异或位

void GHASH(uint8_t H[16], uint8_t len_A, uint8_t A_i[len_A], uint8_t len_C,
    uint8_t C_i[len_C], uint8_t X_i[16]) {

uint8_t m;
uint8_t n;
uint8_t i;
uint8_t j;
uint8_t zeros[16] = {0};

 if (i == m + n) {
        for(j=16; j>=0; j--){
        C_i[j] = C_i[j] ^ zeros[j]; //XOR with zero array to fill in 0 of length 128-u
        tmp[j] = X_i[j] ^ C_i[j]; // X[m+n+1] XOR C[i] left shift by (128bit-u) and store into tmp
        gmul(tmp, H, X_i); //Do Multiplication of tmp to H and store into X
        }
    }

我很确定我不正确。但我不知道该怎么做。

4

2 回答 2

4

在我看来,您在这里遇到了几个问题,并且将它们混为一谈是问题的重要组成部分。将它们分开时会容易得多。

  • 第一:传入表单的参数uint8_t len_A, uint8_t A_i[len_A]是不正确的语法,不会给你你想要的。你实际上得到uint8_t len_A, uint8_t * A_i了 , A_i 的长度取决于它在上面的级别是如何声明的,而不是你如何尝试传递它。(请注意,这里的uint8_t * Aanduint8_t A[]功能相同;区别主要是程序员的语法糖.)

  • 在上面的级别上,由于我不知道它是由 malloc() 还是在堆栈上声明的,所以我不会对内存管理问题感兴趣。我将使用本地存储作为我的建议。

  • 单位清晰度:这里有一个不好的情况:位与字节与块长度。在不知道核心算法的情况下,在我看来,未声明的 m & n 是 A & C 的块长度;即,A 是 m 个块长,C 是 n 个块长,在这两种情况下,最后一个块都不需要是全长的。您传入 len_A 和 len_C 时没有告诉我们(或在代码中使用它们以便我们查看)它们是位长 u/v、A_i/C_i 的字节长度还是 A/C 的总长度,以位或字节或块为单位。根据(不正确的)声明,我假设它们是以字节为单位的 A_i/C_i 的长度,但这并不明显......也不是显而易见的事情。顾名思义,我猜它是 A/C 的长度(以位为单位)。提示:如果您的单位在名称中,

  • 迭代控制:您似乎在为第 i 次迭代传递 16 字节块,但没有传递 i。要么传入 i,要么传入完整的 A 和 C 而不是 A_i 和 C_i。您也在使用 m & n 而不设置它们或传递它们;同样的问题也适用。我会假装它们在使用时都是正确的,然后让你解决这个问题。

  • 最后,我不明白 i=m+n+1 情况的求和符号,特别是如何处理 len(A) 和 len(C) ,但你不是在问这种情况,所以我会忽略它。

鉴于这一切,让我们看看你的功能:

void GHASH(uint8_t H[], uint8_t len_A, uint8_t A_i[], uint8_t len_C, uint8_t C_i[], uint8_t X_i[]) {

    uint8_t tmpAC[16] = {0};
    uint8_t tmp[16];
    uint8_t * pAC = tmpAC;

    if (i == 0) {         // Initialization case
        for (j=0; j<len_A; ++j) {
            X_i[j] = 0;
        }
        return;
    } else if (i < m) {   // Use the input memory for A
        pAC = A_i;
    } else if (i == m) {     // Use temp memory init'ed to 0; copy in A as far as it goes
        for (j=0; j<len_A; ++j) {
            pAC[j] = A_i[j];
        }
    } else if (i < m+n) {    // Use the input memory for C
        pAC = C_i;
    } else if (i == m+n) {   // Use temp memory init'ed to 0; copy in C as far as it goes
        for (j=0; j<len_A; ++j) {
            pAC[j] = C_i[j];
        }
    } else if (i == m+n+1) { // Do something unclear to me. Maybe this?
       // Use temp memory init'ed to 0; copy in len(A) & len(C)
       pAC[0] = len_A;  // in blocks?  bits?  bytes?
       pAC[1] = len_C;  // in blocks?  bits?  bytes?
    }

    for(j=16; j>=0; j--){
        tmp[j] = X_i[j] ^ pAC[j]; // X[m+n+1] XOR A or C[i] and store into tmp
        gmul(tmp, H, X_i); //Do Multiplication of tmp to H and store into X
    }
}

我们只在 A 或 C 的最后一个块中复制内存,并使用本地内存进行复制。大多数块都使用单个指针副本处理,以指向输入内存的正确位。

于 2013-12-05T23:20:42.500 回答
3

如果您不关心每一点效率(我假设这是为了实验,而不是真正使用?)只需重新分配和填充(实际上,当您第一次声明这些时,您可以四舍五入和 calloc):

size_t round16(size_t n) {
    // if n isn't a multiple of 16, round up to next multiple
    if (n % 16) return 16 * (1 + n / 16);
    return n;
}

size_t realloc16(uint8_t **data, size_t len) {
    // if len isn't a multiple of 16, extend with 0s to next multiple
    size_t n = round16(len);
    *data = realloc(*data, n);
    for (size_t i = len; i < n; ++i) (*data)[i] = 0;
    return n;
}

void xor16(uint8_t *result, uint8_t *a, uint8_t *b) {
    // 16 byte xor
    for (size_t i = 0; i < 16; ++i) result[i] = a[i] ^ b[i];
}

void xorandmult(uint8_t *x, uint8_t *data, size_t n, unint8_t *h) {
    // run along the length of the (extended) data, xoring and mutliplying
    uint8_t tmp[16];
    for (size_t i = 0; i < n / 16; ++i) {
        xor16(tmp, x, data+i*16);
        multgcm(x, h, tmp);
    }
}

void ghash(uint8_t *x, uint8_t **a, size_t len_a, uint8_t **c, size_t len_c, uint8_t *h) {
    size_t m = realloc16(a, len_a);
    xorandmult(x, *a, m, h);
    size_t n = realloc16(c, len_c);
    xorandmult(x, *c, n, h);

    // then handle lengths
}

uint8_t x[16] = {0};
ghash(x, &a, len_a, &c, len_c, h);

免责声明 - 不是专家,只是浏览了规范。代码未经编译,未经检查,不适合“真正”使用。此外,该规范支持任意(位)长度,但我假设您以字节为单位工作。

另外,我仍然不确定我是否回答了正确的问题。

于 2013-11-30T22:44:14.073 回答