首页
社区
课程
招聘
[原创]常见密码算法总结--(4)加密模式的openssl代码分析之cfb模式
发表于: 2010-6-16 12:39 6216

[原创]常见密码算法总结--(4)加密模式的openssl代码分析之cfb模式

2010-6-16 12:39
6216
其他见:

《常见密码算法总结--(1)分组对称密码》见
http://bbs.pediy.com/showthread.php?t=113921
http://blog.csdn.net/NJZhuJinhua/archive/2010/05/27/5629455.aspx

《常见密码算法总结--(2)分组密码加密模式》见
http://bbs.pediy.com/showthread.php?t=114169
http://blog.csdn.net/NJZhuJinhua/archive/2010/05/30/5635313.aspx

《常见密码算法总结--(3)加密模式的openssl代码分析之cbc模式》
NJZhuJinhua@csdn May.30, 2010
http://bbs.pediy.com/showthread.php?t=114170

本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/NJZhuJinhua/archive/2010/05/30/5635343.aspx

NJZhuJinhua@csdn Jun.6, 2010

转载请注明出处。

(2)CRYPTO_cfb128_encrypt  CRYPTO_cfb128_1_encrypt  CRYPTO_cfb128_8_encrypt
这三个实现了cfb模式的三种制式。其函数声明见上文描述。
这三种均被seed_cfb.c  cmll_cfb.c  aes_cfb.c引用。
在aes_cfb.c内使用情况如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
void AES_cfb128_encrypt(const unsigned char *in, unsigned char *out,
                        size_t length, const AES_KEY *key,
                        unsigned char *ivec, int *num, const int enc) {
     
    CRYPTO_cfb128_encrypt(in,out,length,key,ivec,num,enc,(block128_f)AES_encrypt);
}
 
/* N.B. This expects the input to be packed, MS bit first */
void AES_cfb1_encrypt(const unsigned char *in, unsigned char *out,
                      size_t length, const AES_KEY *key,
                      unsigned char *ivec, int *num, const int enc)
{
    CRYPTO_cfb128_1_encrypt(in,out,length,key,ivec,num,enc,(block128_f)AES_encrypt);
}
 
void AES_cfb8_encrypt(const unsigned char *in, unsigned char *out,
                      size_t length, const AES_KEY *key,
                      unsigned char *ivec, int *num, const int enc)
{
    CRYPTO_cfb128_8_encrypt(in,out,length,key,ivec,num,enc,(block128_f)AES_encrypt);
}


上述中的cfb1,cfb8,cfb128分别指cfb模式中分组继续分段的段的大小,分别为1位,8位机128位
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
/* The input and output encrypted as though 128bit cfb mode is being
* used.  The extra state information to record how much of the
* 128bit block we have used is contained in *num;
*/
void CRYPTO_cfb128_encrypt(const unsigned char *in, unsigned char *out,
                           size_t len, const void *key,
                           unsigned char ivec[16], int *num,
                           int enc, block128_f block)
{
    unsigned int n;
    size_t l = 0;
     
    assert(in && out && key && ivec && num);
     
    n = *num;
     
    if (enc) 加密时
    {
#if !defined(OPENSSL_SMALL_FOOTPRINT)
        if (16%sizeof(size_t) == 0)  /* always true actually */
        {
            do
            {
                while (n && len)
                {
                    *(out++) = ivec[n] ^= *(in++);
                    --len;
                    n = (n+1) % 16;
                }
   上述代码段中n最多在n,(n+1)%16,...,15之间,len最多在len,len-1,...,len-14之间变动,具体变动范围还要看16-n与len的关系。
16-n>len时  依次执行的是ivec[n...n+(len-1)]和明文in[0...(len-1)]的异或,之后len的值变为0了,即明文已用完。
假设len为6, n=3的话是
ivec  [0  1  2  3  4  5  6  7  8  9  0  a  b  c  d  e  f]
in             [0  1  2  3  4  5]
的异或得到out,此时得到的out后后面没机会执行了,没加密意义。
 
16-n<=len时依次执行的是ivec[n...n+(len-1)]和明文in[0...(15-n)]的异或,之后n的值变为0了。
假设len为>=13, n=3的话是
ivec  [0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f]
in             [0  1  2  3  4  5  6  7  8  9  a  b  c]
的异或得到out及新的ivec,如
  out[0]=ivec[3]^in[0];out[c]=ivec[f]^in[c],out[d]=0;
  ivec[0]=ivec[0],ivec[5]=ivec[5]^in[2];
 
如上生成的out均算是成品了,
#if defined(STRICT_ALIGNMENT)
                if (((size_t)in|(size_t)out|(size_t)ivec)%sizeof(size_t) != 0)
                    break;
#endif
               while (len>=16)
                {
对于剩余的明文长度大于等于16时进行迭代,即用密钥key加密上面或上一次的本处循环生成的生成ivec,ivec的密文继续作为ivec,并与明文分组进行异或。如此循环知道len<16了
                    (*block)(ivec, ivec, key);
                    for (n=0; n<16; n+=sizeof(size_t))
                    {
                        *(size_t*)(out+n) =
                            *(size_t*)(ivec+n) ^= *(size_t*)(in+n);
                    }
                    len -= 16;
                    out += 16;
                    in  += 16;
                }
                n = 0;
                if (len)
                {这里意味着len大于0小于16了,那么生成新的一组流ivec,并将前len长度字节与剩余的len长度明文进行异或,得到最后不足一分组的密文输出。
                    (*block)(ivec, ivec, key);
                    while (len--)
                    {
                        out[n] = ivec[n] ^= in[n];
                        ++n;
                    }
                }
                *num = n; 设置num值,这里n为最后一个ivec那个使用的字节数。
设明文长度为len,入参*num值为num_in可以推断出,出参*num值为(len+(num_in-1))%16
                return;
            } while (0);
        }
        /* the rest would be commonly eliminated by x86* compiler */
#endif
        while (l<len)
        {这里根本就不会执行
            if (n == 0)
            {
                (*block)(ivec, ivec, key);
            }
            out[l] = ivec[n] ^= in[l];
            ++l;
            n = (n+1) % 16;
        }
        *num = n;
    }
    else
    {
 //解密  原理同上,只是一个逆过程,不再赘述。
#if !defined(OPENSSL_SMALL_FOOTPRINT)
        if (16%sizeof(size_t) == 0) do
        { /* always true actually */
            while (n && len)
            {
                unsigned char c;
                *(out++) = ivec[n] ^ (c = *(in++)); ivec[n] = c;
                --len;
                n = (n+1) % 16;
            }
#if defined(STRICT_ALIGNMENT)
            if (((size_t)in|(size_t)out|(size_t)ivec)%sizeof(size_t) != 0)
                break;
#endif            while (len>=16)
            {
                (*block)(ivec, ivec, key);
                for (n=0; n<16; n+=sizeof(size_t))
                {
                    size_t t = *(size_t*)(in+n);
                    *(size_t*)(out+n) = *(size_t*)(ivec+n) ^ t;
                    *(size_t*)(ivec+n) = t;
                }
                len -= 16;
                out += 16;
                in  += 16;
            }
            n = 0;
            if (len)
            {
                (*block)(ivec, ivec, key);
                while (len--)
                {
                    unsigned char c;
                    out[n] = ivec[n] ^ (c = in[n]); ivec[n] = c;
                    ++n;
                }
            }
            *num = n;
            return;
        } while (0);
        /* the rest would be commonly eliminated by x86* compiler */
#endif        while (l<len)
        {
            unsigned char c;
            if (n == 0)
            {
                (*block)(ivec, ivec, key);
            }
            out[l] = ivec[n] ^ (c = in[l]); ivec[n] = c;
            ++l;
            n = (n+1) % 16;
        }
        *num=n;
    }
}
 
/* This expects a single block of size nbits for both in and out. Note that
it corrupts any extra bits in the last byte of out */
static void cfbr_encrypt_block(const unsigned char *in,unsigned char *out,
                               int nbits,const void *key,
                               unsigned char ivec[16],int enc,
                               block128_f block)
{
    int n,rem,num;
    unsigned char ovec[16*2 + 1];  /* +1 because we dererefence (but don't use) one byte off the end */
     
    if (nbits<=0 || nbits>128) return;
     
    /* fill in the first half of the new IV with the current IV */
    memcpy(ovec,ivec,16);
    //向量变化:ovec=ivec[0...15]|NULL
    /* construct the new IV */
    (*block)(ivec,ivec,key);  //Ek(ivec)
    num = (nbits+7)/8// nbits位对应的字节数
    if (enc) /* encrypt the input */
    {
        // 对应加密过程
        for(n=0 ; n < num ; ++n)
            out[n] = (ovec[16+n] = in[n] ^ ivec[n]);
        // 设1<=nbits<=8 则num为1。则此处仅
        // out[0]=ovec[16]=in[0]^ivec[0]=in[0]^(Ek(ivec))[0];
 
        //向量变化:ovec=ivec[0...15]|in[0]^(Ek(ivec))[0];
    }
    else  /* decrypt the input */
    {
        // 对应解密过程
        for(n=0 ; n < num ; ++n)
            out[n] = (ovec[16+n] = in[n]) ^ ivec[n];
        // 与上完全一样,不过in代表密文,out代表输出的明文了
 
        //向量变化:ovec=ivec[0...15]|in[0]^(Ek(ivec))[0];
    }
    /* shift ovec left... */
    rem = nbits%8; //ovec要左移的位数
    num = nbits/8;
    if(rem==0)
    {
        // 可见 1<=num<=16
        memcpy(ivec,ovec+num,16);
        //如果在nbits为8的整倍数的时候,如8时用ivec[1...15]|(Ek(ivec)[0]^in[0]) 作为下一轮的ivec
        //如nbits为16时用ivec[2...15]|(Ek(ivec)[0]^in[0])|(Ek(ivec)[1]^in[1]) 作为下一轮的ivec
 
        //向量变化:ivec=ivec[num...15]|in[0...(num-1)]^(Ek(ivec))[0...(num-1)];
 
    }
    else
    {
        // 可见 0<=num<=15
        for(n=0 ; n < 16 ; ++n)
        {
            ivec[n] = ovec[n+num]<<rem | ovec[n+num+1]>>(8-rem);
        }
        //如果nbits不为8的倍数,则需要将ivec[num]字节的右边低8-rem位直到ivec[16+num]的左边高rem位共计128位作为下一轮的ivec
    }
     
 
    /* it is not necessary to cleanse ovec, since the IV is not secret */
}
 
/* N.B. This expects the input to be packed, MS bit first */
void CRYPTO_cfb128_1_encrypt(const unsigned char *in, unsigned char *out,
                             size_t bits, const void *key,
                             unsigned char ivec[16], int *num,
                             int enc, block128_f block)
{
    size_t n;
    unsigned char c[1],d[1];
     
    assert(in && out && key && ivec && num);
    assert(*num == 0);
     
    for(n=0 ; n<bits ; ++n)
    {
        c[0]=(in[n/8]&(1 << (7-n%8))) ? 0x80 : 0;
        // in的第n位为1 则 c[0]=0x80  否则 c[0]=0;即最高位为in的第n位的值,其他位为0.
         
        cfbr_encrypt_block(c,d,1,key,ivec,enc,block);
         
        out[n/8]=(out[n/8]&~(1 << (unsigned int)(7-n%8))) |
            ((d[0]&0x80) >> (unsigned int)(n%8));
        //设置out结果的第n位为d[0]最高位的值。
    }
}
 
void CRYPTO_cfb128_8_encrypt(const unsigned char *in, unsigned char *out,
                             size_t length, const void *key,
                             unsigned char ivec[16], int *num,
                             int enc, block128_f block)
{
    size_t n;
     
    assert(in && out && key && ivec && num);
    assert(*num == 0);
     
    for(n=0 ; n<length ; ++n)
        cfbr_encrypt_block(&in[n],&out[n],8,key,ivec,enc,block);
    //对于每次偏移位数为8时,为整字节运算,本函数的第3参数为字节数。
}


本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/NJZhuJinhua/archive/2010/06/06/5651871.aspx

[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课

收藏
免费
支持
分享
最新回复 (0)
游客
登录 | 注册 方可回帖
返回

账号登录
验证码登录

忘记密码?
没有账号?立即免费注册