libgcrypt 如何增加 CTR 模式的计数器?
How does libgcrypt increment the counter for CTR mode?
我有一个使用 libgcrypt 的 CTR 模式实施的 AES-256 加密的文件。
我希望能够部分解密文件(例如,解密 20 个块中的第 5-10 个块而不解密整个文件)。
我知道通过点击率模式,我应该可以做到。我所需要的只是知道正确的计数器。
问题在于我所拥有的只是块 0 的初始计数器。例如,如果我想解密块 5,我需要另一个计数器,这是通过对从 0 开始的每个块的初始计数器执行一些操作来实现的到 5.
我似乎找不到 libgcrypt 公开的 API,以便在给定初始计数器的情况下计算后续块的计数器。
如何在给定块 #0 的计数器的情况下计算后面块(例如块 #5)的计数器?
如有疑问,请转到 the source。这是 gcrypt 的通用 CTR 模式实现(_gcry_cipher_ctr_encrypt()
in cipher-ctr.c
)中递增计数器的代码:
for (i = blocksize; i > 0; i--)
{
c->u_ctr.ctr[i-1]++;
if (c->u_ctr.ctr[i-1] != 0)
break;
}
在 libgcrypt 源代码的其他地方可以找到其他更优化的计数器递增实现,例如在各种特定于密码的快速批量 CTR 加密实现中,但这个通用的恰好很好且可读。 (当然,所有这些替代实现无论如何都需要产生相同的计数器值序列,以便 gcrypt 保持与自身兼容。)
好的,那么它实际上做了什么?
嗯,看看上下文(或者更具体地说,cipher-internal.h
),很明显 c->u_ctr.ctr
是一个 blocksize
无符号字节数组(其中 blocksize
等于 AES 的 16 个字节)。上面的代码将其最后一个字节递增 1,并检查结果是否环绕为零。如果没有,它就会停止;如果它确实换行,则代码然后移动到倒数第二个字节,递增它,检查它是否换行,并继续循环直到它找到一个在递增时不换行的字节,或者它已经递增所有 blocksize
个字节。
因此,例如,如果您的原始计数器值是 {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}
,那么递增后它将变为 {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1}
。如果再次递增,它将变为 {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2}
,然后是 {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3}
,依此类推直到 {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255}
,之后下一个计数器值将是 {0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0}
(然后是 {0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1}
、{0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,2}
、{0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3}
、等等)。
当然,这实际上只是算术递增一个 (blocksize
× 8) 位整数,以 big-endian 字节顺序存储在内存中。
我有一个使用 libgcrypt 的 CTR 模式实施的 AES-256 加密的文件。 我希望能够部分解密文件(例如,解密 20 个块中的第 5-10 个块而不解密整个文件)。
我知道通过点击率模式,我应该可以做到。我所需要的只是知道正确的计数器。 问题在于我所拥有的只是块 0 的初始计数器。例如,如果我想解密块 5,我需要另一个计数器,这是通过对从 0 开始的每个块的初始计数器执行一些操作来实现的到 5.
我似乎找不到 libgcrypt 公开的 API,以便在给定初始计数器的情况下计算后续块的计数器。
如何在给定块 #0 的计数器的情况下计算后面块(例如块 #5)的计数器?
如有疑问,请转到 the source。这是 gcrypt 的通用 CTR 模式实现(_gcry_cipher_ctr_encrypt()
in cipher-ctr.c
)中递增计数器的代码:
for (i = blocksize; i > 0; i--)
{
c->u_ctr.ctr[i-1]++;
if (c->u_ctr.ctr[i-1] != 0)
break;
}
在 libgcrypt 源代码的其他地方可以找到其他更优化的计数器递增实现,例如在各种特定于密码的快速批量 CTR 加密实现中,但这个通用的恰好很好且可读。 (当然,所有这些替代实现无论如何都需要产生相同的计数器值序列,以便 gcrypt 保持与自身兼容。)
好的,那么它实际上做了什么?
嗯,看看上下文(或者更具体地说,cipher-internal.h
),很明显 c->u_ctr.ctr
是一个 blocksize
无符号字节数组(其中 blocksize
等于 AES 的 16 个字节)。上面的代码将其最后一个字节递增 1,并检查结果是否环绕为零。如果没有,它就会停止;如果它确实换行,则代码然后移动到倒数第二个字节,递增它,检查它是否换行,并继续循环直到它找到一个在递增时不换行的字节,或者它已经递增所有 blocksize
个字节。
因此,例如,如果您的原始计数器值是 {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}
,那么递增后它将变为 {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1}
。如果再次递增,它将变为 {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2}
,然后是 {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3}
,依此类推直到 {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255}
,之后下一个计数器值将是 {0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0}
(然后是 {0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1}
、{0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,2}
、{0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3}
、等等)。
当然,这实际上只是算术递增一个 (blocksize
× 8) 位整数,以 big-endian 字节顺序存储在内存中。