GCM是一种有大吞吐能力的加密认证模式。其中主要适用了CRT模式和类似CBC模式的GHASH模式。CRT模式基本上没有大多变化,GHASH则是利用有限域上的乘法进行HASH,此运算可以通常预先计算和查表优化加速。
GCM两个基本模块 GHASH和GCTR。加解密和认证验证过程都离不开这两个模块。
参考文献
GCTRK (ICB, X)的流程
准备:
输入:
输出:
步骤:
step 1. 如果X是空串,则返回空串Y。
step 2. n = 向上取整( len(X) / 128 )
step 3. 按分组大小划分串X = X1 || X2 || ... || Xn-1 || Xn*
其中X1, X2,..., Xn-1是完整分块,而Xn*可能是完整分块也可能不是。
step 4. CB1=ICB.
step 5. For i = 2 to n, let CBi = inc32(CBi-1).
step 6. For i = 1 to n-1, letYi = Xi⊕CIPHK(CBi).
step 7. Yn* = Xn*⊕MBSlen(Xn*)( CIPHK(CBi) )
step 8. Y = Y1 || Y2 || ... || Yn-1 || Yn*
step 9. Return Y.
其中
GCTR的流程图如下:
GCM中GCTR的流程图
GHASHH (X)
准备:
输入:
输出:
步骤:
step 1. 将X按分组大小划分X = X1 || X2 || ... || Xm-1 || Xm. 每个块都是完整块。
step 2. Y0 = 0128,即全零块.
step 3. For i = 1 to m, Yi = (Yi-1 ⊕ Xi) • H.
step 4. Return Ym.
其中
GHASH的流程图如下
GCM中GHASH的流程图
GCM-AEK (IV, P, A)
准备:
输入:
输出:
步骤:
step 1. H = CIPHK(0128).
step 2. 定义分块J0:
If len(IV)=96, J0 = IV || 031 ||1.
If len(IV)≠96, s = ( 128 - ( len(IV) mod 128 ) ) mod 128,
J0=GHASHH( IV || 0s+64 || [len(IV)]64 ).
step 3. C=GCTRK(inc32(J0), P).
step 4. u = ( 128 - ( len(C) mod 128 ) ) mod 128,v = ( 128 - ( len(A) mod 128 ) ) mod 128
step 5. S = GHASHH (A || 0v || C || 0u || [len(A)]64 || [len(C)]64).
step 6. T = MSBt ( GCTRK(J0, S) )
step 7. Return (C, T).
GCM认证加密的流程图如下:
GCM认证加密的流程图
GCM-ADK (IV, C, A, T)
准备:
输入
输出:
步骤:
step 1. 如果IV、A、C 的长度为不支持长度或或者len(T) ≠ t,则返回验证失败
step 2. H = CIPHK(0128).
step 3. 定义分块J0:
If len(IV)=96, J0 = IV || 031 ||1.
If len(IV)≠96, s = ( 128 - ( len(IV) mod 128 ) ) mod 128,
J0=GHASHH( IV || 0s+64 || [len(IV)]64 ).
step 4. P=GCTRK(inc32(J0), C)
step 5. u = ( 128 - (len(C) mod 128 ) ) mod 128,v = ( 128 - (len(A) mod 128 ) ) mod 128
step 6. S = GHASHH (A || 0v || C || 0u || [len(A)]64 || [len(C)]64).
step 7. T′ = MSBt ( GCTRK(J0, S) )
step 8. 如果 TT′=T, 返回P;否则返回失败。
GCM验证解密的流程图如下:
GCM验证解密的流程图
LibTomCrypt中与GCM相关的信息如下:
typedef struct {
symmetric_key K;
unsigned char H[16], /* multiplier */
X[16], /* accumulator */
Y[16], /* counter */
Y_0[16], /* initial counter */
buf[16]; /* buffer for stuff */
int cipher, /* which cipher */
ivmode, /* Which mode is the IV in? */
mode, /* mode the GCM code is in */
buflen; /* length of data in buf */
ulong64 totlen, /* 64-bit counter used for IV and AAD */
pttotlen; /* 64-bit counter for the PT */
#ifdef LTC_GCM_TABLES
unsigned char PC[16][256][16] /* 16 tables of 8x128 */
#ifdef LTC_GCM_TABLES_SSE2
__attribute__ ((aligned (16)))
#endif
;
#endif
} gcm_state;
GCM涉及的函数有
void gcm_mult_h(gcm_state *gcm, unsigned char *I);
int gcm_init(gcm_state *gcm, int cipher, const unsigned char *key, int keylen);
int gcm_reset(gcm_state *gcm);
int gcm_add_iv(gcm_state *gcm, const unsigned char *IV, unsigned long IVlen);
int gcm_add_aad(gcm_state *gcm, const unsigned char *adata, unsigned long adatalen);
int gcm_process(gcm_state *gcm, unsigned char *pt, unsigned long ptlen, unsigned char *ct, int direction);
int gcm_done(gcm_state *gcm, unsigned char *tag, unsigned long *taglen);
int gcm_memory( int cipher, const unsigned char *key, unsigned long keylen, const unsigned char *IV, unsigned long IVlen, const unsigned char *adata, unsigned long adatalen, unsigned char *pt, unsigned long ptlen, unsigned char *ct, unsigned char *tag, unsigned long *taglen, int direction);
──────────────────────────────────────
void gcm_mult_h(gcm_state *gcm, unsigned char *I);
// [功能] 与H的乘法
//备注:此为内部函数,不被外面调用
// 可以查8bit表加速运算
──────────────────────────────────────
通常的GCM工作流程如下
gcm_init( );
while(need_add_iv)
{
gcm_add_iv();//添加IV
}
while(need_add_aad)
{
gcm_add_aad();//添加AAD
}
while(need_add_pt)
{
gcm_process ();//不停的添加明文or密文
}
gcm_done( );//完成并获取TAG
──────────────────────────────────────
int gcm_init(gcm_state *gcm, int cipher, const unsigned char *key, int keylen);
// [功能] 初始化
//备注:1. 生成扩展密钥
// 2. 建立16个快速运算表Mi[x], 0 <= i < 16, 0 <= x < 256
──────────────────────────────────────
──────────────────────────────────────
int gcm_reset(gcm_state *gcm);
// [功能] 重置GCM信息
gcm // [输入/输出]GCM的状态
──────────────────────────────────────
──────────────────────────────────────
int gcm_add_iv(gcm_state *gcm, const unsigned char *IV, unsigned long IVlen)
// [功能] 添加IV
//备注: 1 bit <= IV bit len <= 2^64 - 1 bit, 这里要求以字节为单位
// 由于IV长度可以很长,所以允许将较长的IV分多次添加,即可多次调用gcm_add_iv
──────────────────────────────────────
──────────────────────────────────────
int gcm_add_aad(gcm_state *gcm, const unsigned char *adata, unsigned long adatalen);
// [功能] 添加AAD(仅认证不加密的数据)
//备注: 0 bit <= AAD bit len <= 2^64 - 1 bit, 这里要求以字节为单位
// 由于AAD长度可以很长,所以允许将较长的AAD分多次添加
// 第一次做gcm_add_aad时才能确认IV添加完毕,此时做添加IV的收尾工作
// 在添加AAD时就开始做与AAD相关的GHASH了
──────────────────────────────────────
──────────────────────────────────────
int gcm_process(gcm_state *gcm, unsigned char *pt, unsigned long ptlen, unsigned char *ct, int direction);
// [功能] 与H的乘法
//备注:加密时,输入明文,输出密文;解密时,输入密文,输出明文。明密文长度一样
// 第一次做gcm_process时才知道添加aad完成,此时做添加AAD的收尾工作
// GCM的tag要等所有处理完毕,到gcm_done()去获得
──────────────────────────────────────
──────────────────────────────────────
int gcm_done(gcm_state *gcm, unsigned char *tag, unsigned long *taglen);
// [功能] 完成GCM并获得TAG
//备注:输入taglen,内部根据输入值返回正确的taglen
──────────────────────────────────────
──────────────────────────────────────
int gcm_memory( int cipher, const unsigned char *key, unsigned long keylen, const unsigned char *IV, unsigned long IVlen, const unsigned char *adata, unsigned long adatalen, unsigned char *pt, unsigned long ptlen, unsigned char *ct, unsigned char *tag, unsigned long *taglen, int direction);
// [功能] 与H的乘法
//备注: 此函数只适合IV、AAD、明密文都不太长的情况
工作流程如下
gcm_init( );
gcm_add_iv();//添加IV
gcm_add_aad();//添加AAD
gcm_process ();//不停的添加明文or密文
gcm_done( );//完成并获取TAG
──────────────────────────────────────