OpenSSL密码库算法笔记——第 3.3章 模逆

在模运算中,一般没有直接做模除法。模除法a/b mod m都是先计算模逆t=b-1 mod m,再计算模乘at mod m。因此本节就来讨论模逆运算该怎样实现。

求模逆的算法主要是扩展欧几里德算法。该算法的大意如下。

假设计算a^{-1}modm。算法通过反复迭代Ad+dm=uCa+em=v(A、C、d、e为某些待定数)而得出a^{-1}modm,这里的迭代主要是做乘法和减法。

算法的步骤大概是这样的。开始的时候先进行初始化——取A=1,d=0,C=0,e=1,得到:

                …………(3.2)

然后反复做如下迭代(为了记号的方便,迭代过程中始终让u≥v,否则,交换<1>、<2>两式):

  • q=\left \lfloor u/v \right \rfloor
  • 新的<1>式 ← 老的<2>式;
  • 新的<2>式 ← 老的<1>式-q×老的<2>式;

如此迭代,直到v=0为止。最后得出Amodm=a^{-1}modm,注意最后得出的A可能是负数(比如下面举的例子就是这样),此时只需要加上m即可。

下面给出用扩展欧几里德算法计算的详细描述。算法中出现的符号和上面的介绍一致,新增加的三个变量t1,t2,t3为临时变量。算法可参见[2,§4.5.2算法X]。

───────────────────────────────────────

───────────────────────────────────────

以上是一般情况下的扩展欧几里德算法。如果模数m为奇数(为了以示区别,记此时的奇模数为p),算法可以变的更加简单快捷——利用反复的右移(即除2)来代替除法。

下面来看看这个特殊的算法怎样计算a^{-1}modp,这里的p为奇数。(也可参见[9,算法8])。

───────────────────────────────────────

 

───────────────────────────────────────

下面介绍的求模逆的C程序综合利用了以上两种算法:当模数是奇数而且字长小于450时,利用特殊的扩展欧几里德算法——模数为奇数的扩展欧几里德算法来进行计算,如果模数不满足这个条件,就用一般的扩展欧几里德算法来进行计算。

───────────────────────────────────────

BIGNUM *BN_mod_inverse(BIGNUM *in,const BIGNUM *a, const BIGNUM *n)

功能:    求模逆

输入:    a【被模数】,n【模数】

输出:    in ← 1/a mod n

返回:    in【正常】 or NULL【出错】

出处:    bn_gcd.c

───────────────────────────────────────

有一个特殊的模逆函数BN_mod_inverse_no_branch,它利用一些特殊的方法来防止信息泄漏,抵抗能量攻击。其算法思想类似普通的扩展欧几里德算法,但其中间用了点小技巧以防止信息泄漏,详细情况请参见原函数。

───────────────────────────────────────

static BIGNUM *BN_mod_inverse_no_branch(BIGNUM *in, const BIGNUM *a, const BIGNUM *n)

功能:    用抗能量攻击法求模逆

输入:    a【被模数】,n【模数】

输出:    in ← 1/a mod n

返回:    in【正常】 or NULL【出错】

出处:    bn_gcd.c

───────────────────────────────────────

  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
首先,OpenSSL是一个开源的密码,提供了许多密码学相关的工具和算法,包括对称加密、非对称加密、哈希函数等。下面我们来看一下OpenSSL的加密解密算法的实现。 我们选取AES算法作为例子,先看一下AES加密函数的源码: ```c int AES_encrypt(const unsigned char *in, unsigned char *out, const AES_KEY *key) { if (key->enc_block == (block128_f)AES_encrypt) { const union { long one; char little; } is_endian = {1}; if (is_endian.little) { (*key->block.cbc) (in, out, AES_BLOCK_SIZE, key->rd_key, key->rounds, key->iv, AES_ENCRYPT); return 1; } else { (*key->block.ecb) (in, out, key->rd_key, AES_ENCRYPT); return 1; } } else { return key->enc_block(in, out, key->enc_key); } } ``` 这段代码实现了AES加密函数,接受输入in、输出out和密钥key。在函数内部,首先判断使用的是CBC模式还是ECB模式,具体的实现在key->block.cbc和key->block.ecb函数中。如果使用的是CBC模式,会调用cbc_encrypt函数进行加密,否则会调用ecb_encrypt函数进行加密。 接下来是AES解密函数的源码: ```c int AES_decrypt(const unsigned char *in, unsigned char *out, const AES_KEY *key) { if (key->enc_block == (block128_f)AES_encrypt) { const union { long one; char little; } is_endian = {1}; if (is_endian.little) { (*key->block.cbc) (in, out, AES_BLOCK_SIZE, key->rd_key, key->rounds, key->iv, AES_DECRYPT); return 1; } else { (*key->block.ecb) (in, out, key->rd_key, AES_DECRYPT); return 1; } } else { return key->dec_block(in, out, key->dec_key); } } ``` 与AES加密函数类似,AES解密函数也会根据使用的模式调用不同的函数进行解密。 最后,我们来分析一下AES加密函数中的代码: ```c const union { long one; char little; } is_endian = {1}; if (is_endian.little) { (*key->block.cbc) (in, out, AES_BLOCK_SIZE, key->rd_key, key->rounds, key->iv, AES_ENCRYPT); return 1; } else { (*key->block.ecb) (in, out, key->rd_key, AES_ENCRYPT); return 1; } ``` 这段代码的作用是判断系统的字节序是否为小端序,如果是小端序,则调用cbc_encrypt函数进行加密,否则调用ecb_encrypt函数进行加密。其中,key->block.cbc和key->block.ecb是函数指针,分别指向CBC模式和ECB模式的加密函数。在调用函数时,需要传入输入数据、输出数据、数据块大小、轮密钥、轮数、初始化向量和加密/解密标志。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值