GCM乘法实施

Pau*_* A. 5 encryption cryptography multiplication aes-gcm galois-field

我的GCM SP-800-38D文档中puting开块的乘法(Alogrithm 1)C代码这里.第11-12页.

完成代码后,我想看看是否有任何方法可以测试代码.您可以在我提供的代码下面找到附件.请注意,我使用24位块代替128位块,仅用于测试目的.如有必要,我将不胜感激.

void BLK_MUL (u8 *val_1,u8 *val_2, u8 *out_val)
{ 

    u8 xdata R_val = 0xE1;     
    u8 xdata Z_val[3],V_val[3];
    u8 mask_b   = 0x80;        
    u16 i;  u8 j;           
    bit rnd;                

    for(j=0;j<3;j++,++val_2)    
    {
        Z_val[j]=0x00;      
        V_val[j]=*val_2;    
    }       


    for(i=0;i<24;i++)
    { 
        if (*val_1 & mask_b)
        {
            for(j=0;j<3;j++)    
                Z_val[j]^=V_val[j]; 
        }
        if (!(V_val[2] & 0x01))
        {//if LSB of V_val is 0
            for(j=0;j<3;j++)
            { //V_val = rightshift(V_val)
                if (j!=0)
                    if (V_val[2-j] & 0x01)
                        V_val[3-j] |= 0x80;
                V_val[2-j]>>=1;          
            }
        }
        else
        {//if LSB of V_val is 1
            for(j=0;j<3;j++)
            {//V_val = rightshift(V_val)
                if (j!=0)
                    if (V_val[2-j] & 0x01)
                        V_val[3-j] |= 0x80;
                V_val[2-j]>>=1;          
            }
            V_val[0]^=R_val; //V_val = rightshift(V_val) ^ R                
        }
        if(mask_b & 0x01)   { val_1++; rnd=1;}  
        mask_b >>= 1;                       
        if (rnd)    { mask_b=0x80; rnd=0; } 
    }

    STR_CPY(out_val,Z_val,3);   

    return ;        
}


void main()
{

    code unsigned char val_1[3] ={  0x2b,0x7e,0x15  };
    code unsigned char val_2[3] ={  0x39,0x25,0x84  };
    unsigned char out[3];

    BLK_MUL (val_1,val_2,out);

    return;
}
Run Code Online (Sandbox Code Playgroud)

Jac*_*ack 9

在某些时候,您当然必须根据测试向量检查您的代码.但是,您可以执行相当多的测试而无需知道或计算任何测试向量.

首先,GF(2 ^ 128)中的乘法是可交换的.因此,您可以使用任何输入计算BLK_MUL(val_1,val_2,out1)和BLK_MUL(val_2,val_1,out2),您应该得到相同的结果.由于您的代码使用val_1和val_2不同,这已经是一个非常好的测试.

然后你可以使用那个乘法是分配的,即你可以测试(x + y)*z =(x*z)+(y*z),(其中GF(2 ^ 128)中的加法是由xoring对应计算的这两个值的字节在一起).

最后,一旦你实现了整个字段GF(2 ^ 128),你也可以利用它的顺序是2 ^ 128-1.即如果你从一个值x开始然后将它平方128次,那么你应该得到x.


一些额外的评论:

使用公式进行测试(仅使用测试向量)的优点是可以轻松运行大量测试.因为以这种方式添加测试相当容易,所以我经常首先使用稀疏输入(例如,在输入中设置单个位)进行一些简单的测试.如果出现问题,那么这有助于快速识别错误.

您当前的代码使用临时变量作为结果.这确实是一个好主意,因为它可以确保复制安全.我认为一个好的单元测试也应该涵盖这个案例.即你可能想要计算两次相同的结果:一次输入和输出指向不同的内存位置,一次输出与输入相同的内存.

此外,至少有一个其他答案谈到了优化.我认为如果你重构代码,那么你应该寻找有意义的组件来重用,而不是盲目地寻找类似代码片段.由于GF(2 ^ 128)是一个字段,因此字段中的加法和乘法当然是有意义的组件.另一个有意义的组件是多项式x的乘法(这是在加密中经常使用的东西).


emb*_*oss 5

为GCM模式的测试向量可以发现这里和有一堆NIST测试向量的位置.