summaryrefslogtreecommitdiffstats
path: root/crypto/des/cfb_enc.c
blob: 8630cc4293e11cd4df84d4a0e57069998bd18001 (plain)
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
/*
 * Copyright 1995-2016 The OpenSSL Project Authors. All Rights Reserved.
 *
 * Licensed under the Apache License 2.0 (the "License").  You may not use
 * this file except in compliance with the License.  You can obtain a copy
 * in the file LICENSE in the source distribution or at
 * https://www.openssl.org/source/license.html
 */

#include "e_os.h"
#include "des_local.h"
#include <assert.h>

/*
 * The input and output are loaded in multiples of 8 bits. What this means is
 * that if you hame numbits=12 and length=2 the first 12 bits will be
 * retrieved from the first byte and half the second.  The second 12 bits
 * will come from the 3rd and half the 4th byte.
 */
/*
 * Until Aug 1 2003 this function did not correctly implement CFB-r, so it
 * will not be compatible with any encryption prior to that date. Ben.
 */
void DES_cfb_encrypt(const unsigned char *in, unsigned char *out, int numbits,
                     long length, DES_key_schedule *schedule,
                     DES_cblock *ivec, int enc)
{
    register DES_LONG d0, d1, v0, v1;
    register unsigned long l = length;
    register int num = numbits / 8, n = (numbits + 7) / 8, i, rem =
        numbits % 8;
    DES_LONG ti[2];
    unsigned char *iv;
#ifndef L_ENDIAN
    unsigned char ovec[16];
#else
    unsigned int sh[4];
    unsigned char *ovec = (unsigned char *)sh;

    /* I kind of count that compiler optimizes away this assertion, */
    assert(sizeof(sh[0]) == 4); /* as this holds true for all, */
    /* but 16-bit platforms...      */

#endif

    if (numbits <= 0 || numbits > 64)
        return;
    iv = &(*ivec)[0];
    c2l(iv, v0);
    c2l(iv, v1);
    if (enc) {
        while (l >= (unsigned long)n) {
            l -= n;
            ti[0] = v0;
            ti[1] = v1;
            DES_encrypt1((DES_LONG *)ti, schedule, DES_ENCRYPT);
            c2ln(in, d0, d1, n);
            in += n;
            d0 ^= ti[0];
            d1 ^= ti[1];
            l2cn(d0, d1, out, n);
            out += n;
            /*
             * 30-08-94 - eay - changed because l>>32 and l<<32 are bad under
             * gcc :-(
             */
            if (numbits == 32) {
                v0 = v1;
                v1 = d0;
            } else if (numbits == 64) {
                v0 = d0;
                v1 = d1;
            } else {
#ifndef L_ENDIAN
                iv = &ovec[0];
                l2c(v0, iv);
                l2c(v1, iv);
                l2c(d0, iv);
                l2c(d1, iv);
#else
                sh[0] = v0, sh[1] = v1, sh[2] = d0, sh[3] = d1;
#endif
                if (rem == 0)
                    memmove(ovec, ovec + num, 8);
                else
                    for (i = 0; i < 8; ++i)
                        ovec[i] = ovec[i + num] << rem |
                            ovec[i + num + 1] >> (8 - rem);
#ifdef L_ENDIAN
                v0 = sh[0], v1 = sh[1];
#else
                iv = &ovec[0];
                c2l(iv, v0);
                c2l(iv, v1);
#endif
            }
        }
    } else {
        while (l >= (unsigned long)n) {
            l -= n;
            ti[0] = v0;
            ti[1] = v1;
            DES_encrypt1((DES_LONG *)ti, schedule, DES_ENCRYPT);
            c2ln(in, d0, d1, n);
            in += n;
            /*
             * 30-08-94 - eay - changed because l>>32 and l<<32 are bad under
             * gcc :-(
             */
            if (numbits == 32) {
                v0 = v1;
                v1 = d0;
            } else if (numbits == 64) {
                v0 = d0;
                v1 = d1;
            } else {
#ifndef L_ENDIAN
                iv = &ovec[0];
                l2c(v0, iv);
                l2c(v1, iv);
                l2c(d0, iv);
                l2c(d1, iv);
#else
                sh[0] = v0, sh[1] = v1, sh[2] = d0, sh[3] = d1;
#endif
                if (rem == 0)
                    memmove(ovec, ovec + num, 8);
                else
                    for (i = 0; i < 8; ++i)
                        ovec[i] = ovec[i + num] << rem |
                            ovec[i + num + 1] >> (8 - rem);
#ifdef L_ENDIAN
                v0 = sh[0], v1 = sh[1];
#else
                iv = &ovec[0];
                c2l(iv, v0);
                c2l(iv, v1);
#endif
            }
            d0 ^= ti[0];
            d1 ^= ti[1];
            l2cn(d0, d1, out, n);
            out += n;
        }
    }
    iv = &(*ivec)[0];
    l2c(v0, iv);
    l2c(v1, iv);
    v0 = v1 = d0 = d1 = ti[0] = ti[1] = 0;
}