1 /*
2  *  desblapi.c
3  *
4  *  core source file for DES-150 library
5  *  Implement DES Modes of Operation and Triple-DES.
6  *  Adapt DES-150 to blapi API.
7  *
8  * This Source Code Form is subject to the terms of the Mozilla Public
9  * License, v. 2.0. If a copy of the MPL was not distributed with this
10  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
11 
12 #ifdef FREEBL_NO_DEPEND
13 #include "stubs.h"
14 #endif
15 
16 #include "des.h"
17 #include "blapii.h"
18 #include <stddef.h>
19 #include "secerr.h"
20 
21 #if defined(NSS_X86_OR_X64)
22 /* Intel X86 CPUs do unaligned loads and stores without complaint. */
23 #define COPY8B(to, from, ptr) \
24     HALFPTR(to)               \
25     [0] = HALFPTR(from)[0];   \
26     HALFPTR(to)               \
27     [1] = HALFPTR(from)[1];
28 #else
29 #define COPY8B(to, from, ptr) memcpy(to, from, 8)
30 #endif
31 #define COPY8BTOHALF(to, from) COPY8B(to, from, from)
32 #define COPY8BFROMHALF(to, from) COPY8B(to, from, to)
33 
34 static void
DES_ECB(DESContext * cx,BYTE * out,const BYTE * in,unsigned int len)35 DES_ECB(DESContext *cx, BYTE *out, const BYTE *in, unsigned int len)
36 {
37     while (len) {
38         DES_Do1Block(cx->ks0, in, out);
39         len -= 8;
40         in += 8;
41         out += 8;
42     }
43 }
44 
45 static void
DES_EDE3_ECB(DESContext * cx,BYTE * out,const BYTE * in,unsigned int len)46 DES_EDE3_ECB(DESContext *cx, BYTE *out, const BYTE *in, unsigned int len)
47 {
48     while (len) {
49         DES_Do1Block(cx->ks0, in, out);
50         len -= 8;
51         in += 8;
52         DES_Do1Block(cx->ks1, out, out);
53         DES_Do1Block(cx->ks2, out, out);
54         out += 8;
55     }
56 }
57 
58 static void NO_SANITIZE_ALIGNMENT
DES_CBCEn(DESContext * cx,BYTE * out,const BYTE * in,unsigned int len)59 DES_CBCEn(DESContext *cx, BYTE *out, const BYTE *in, unsigned int len)
60 {
61     const BYTE *bufend = in + len;
62     HALF vec[2];
63 
64     while (in != bufend) {
65         COPY8BTOHALF(vec, in);
66         in += 8;
67         vec[0] ^= cx->iv[0];
68         vec[1] ^= cx->iv[1];
69         DES_Do1Block(cx->ks0, (BYTE *)vec, (BYTE *)cx->iv);
70         COPY8BFROMHALF(out, cx->iv);
71         out += 8;
72     }
73 }
74 
75 static void NO_SANITIZE_ALIGNMENT
DES_CBCDe(DESContext * cx,BYTE * out,const BYTE * in,unsigned int len)76 DES_CBCDe(DESContext *cx, BYTE *out, const BYTE *in, unsigned int len)
77 {
78     const BYTE *bufend;
79     HALF oldciphertext[2];
80     HALF plaintext[2];
81 
82     for (bufend = in + len; in != bufend;) {
83         oldciphertext[0] = cx->iv[0];
84         oldciphertext[1] = cx->iv[1];
85         COPY8BTOHALF(cx->iv, in);
86         in += 8;
87         DES_Do1Block(cx->ks0, (BYTE *)cx->iv, (BYTE *)plaintext);
88         plaintext[0] ^= oldciphertext[0];
89         plaintext[1] ^= oldciphertext[1];
90         COPY8BFROMHALF(out, plaintext);
91         out += 8;
92     }
93 }
94 
95 static void NO_SANITIZE_ALIGNMENT
DES_EDE3CBCEn(DESContext * cx,BYTE * out,const BYTE * in,unsigned int len)96 DES_EDE3CBCEn(DESContext *cx, BYTE *out, const BYTE *in, unsigned int len)
97 {
98     const BYTE *bufend = in + len;
99     HALF vec[2];
100 
101     while (in != bufend) {
102         COPY8BTOHALF(vec, in);
103         in += 8;
104         vec[0] ^= cx->iv[0];
105         vec[1] ^= cx->iv[1];
106         DES_Do1Block(cx->ks0, (BYTE *)vec, (BYTE *)cx->iv);
107         DES_Do1Block(cx->ks1, (BYTE *)cx->iv, (BYTE *)cx->iv);
108         DES_Do1Block(cx->ks2, (BYTE *)cx->iv, (BYTE *)cx->iv);
109         COPY8BFROMHALF(out, cx->iv);
110         out += 8;
111     }
112 }
113 
114 static void NO_SANITIZE_ALIGNMENT
DES_EDE3CBCDe(DESContext * cx,BYTE * out,const BYTE * in,unsigned int len)115 DES_EDE3CBCDe(DESContext *cx, BYTE *out, const BYTE *in, unsigned int len)
116 {
117     const BYTE *bufend;
118     HALF oldciphertext[2];
119     HALF plaintext[2];
120 
121     for (bufend = in + len; in != bufend;) {
122         oldciphertext[0] = cx->iv[0];
123         oldciphertext[1] = cx->iv[1];
124         COPY8BTOHALF(cx->iv, in);
125         in += 8;
126         DES_Do1Block(cx->ks0, (BYTE *)cx->iv, (BYTE *)plaintext);
127         DES_Do1Block(cx->ks1, (BYTE *)plaintext, (BYTE *)plaintext);
128         DES_Do1Block(cx->ks2, (BYTE *)plaintext, (BYTE *)plaintext);
129         plaintext[0] ^= oldciphertext[0];
130         plaintext[1] ^= oldciphertext[1];
131         COPY8BFROMHALF(out, plaintext);
132         out += 8;
133     }
134 }
135 
136 DESContext *
DES_AllocateContext(void)137 DES_AllocateContext(void)
138 {
139     return PORT_ZNew(DESContext);
140 }
141 
142 SECStatus
DES_InitContext(DESContext * cx,const unsigned char * key,unsigned int keylen,const unsigned char * iv,int mode,unsigned int encrypt,unsigned int unused)143 DES_InitContext(DESContext *cx, const unsigned char *key, unsigned int keylen,
144                 const unsigned char *iv, int mode, unsigned int encrypt,
145                 unsigned int unused)
146 {
147     DESDirection opposite;
148     if (!cx) {
149         PORT_SetError(SEC_ERROR_INVALID_ARGS);
150         return SECFailure;
151     }
152     cx->direction = encrypt ? DES_ENCRYPT : DES_DECRYPT;
153     opposite = encrypt ? DES_DECRYPT : DES_ENCRYPT;
154     switch (mode) {
155         case NSS_DES: /* DES ECB */
156             DES_MakeSchedule(cx->ks0, key, cx->direction);
157             cx->worker = &DES_ECB;
158             break;
159 
160         case NSS_DES_EDE3: /* DES EDE ECB */
161             cx->worker = &DES_EDE3_ECB;
162             if (encrypt) {
163                 DES_MakeSchedule(cx->ks0, key, cx->direction);
164                 DES_MakeSchedule(cx->ks1, key + 8, opposite);
165                 DES_MakeSchedule(cx->ks2, key + 16, cx->direction);
166             } else {
167                 DES_MakeSchedule(cx->ks2, key, cx->direction);
168                 DES_MakeSchedule(cx->ks1, key + 8, opposite);
169                 DES_MakeSchedule(cx->ks0, key + 16, cx->direction);
170             }
171             break;
172 
173         case NSS_DES_CBC: /* DES CBC */
174             COPY8BTOHALF(cx->iv, iv);
175             cx->worker = encrypt ? &DES_CBCEn : &DES_CBCDe;
176             DES_MakeSchedule(cx->ks0, key, cx->direction);
177             break;
178 
179         case NSS_DES_EDE3_CBC: /* DES EDE CBC */
180             COPY8BTOHALF(cx->iv, iv);
181             if (encrypt) {
182                 cx->worker = &DES_EDE3CBCEn;
183                 DES_MakeSchedule(cx->ks0, key, cx->direction);
184                 DES_MakeSchedule(cx->ks1, key + 8, opposite);
185                 DES_MakeSchedule(cx->ks2, key + 16, cx->direction);
186             } else {
187                 cx->worker = &DES_EDE3CBCDe;
188                 DES_MakeSchedule(cx->ks2, key, cx->direction);
189                 DES_MakeSchedule(cx->ks1, key + 8, opposite);
190                 DES_MakeSchedule(cx->ks0, key + 16, cx->direction);
191             }
192             break;
193 
194         default:
195             PORT_SetError(SEC_ERROR_INVALID_ARGS);
196             return SECFailure;
197     }
198     return SECSuccess;
199 }
200 
201 DESContext *
DES_CreateContext(const BYTE * key,const BYTE * iv,int mode,PRBool encrypt)202 DES_CreateContext(const BYTE *key, const BYTE *iv, int mode, PRBool encrypt)
203 {
204     DESContext *cx = PORT_ZNew(DESContext);
205     SECStatus rv = DES_InitContext(cx, key, 0, iv, mode, encrypt, 0);
206 
207     if (rv != SECSuccess) {
208         PORT_ZFree(cx, sizeof *cx);
209         cx = NULL;
210     }
211     return cx;
212 }
213 
214 void
DES_DestroyContext(DESContext * cx,PRBool freeit)215 DES_DestroyContext(DESContext *cx, PRBool freeit)
216 {
217     if (cx) {
218         memset(cx, 0, sizeof *cx);
219         if (freeit)
220             PORT_Free(cx);
221     }
222 }
223 
224 SECStatus
DES_Encrypt(DESContext * cx,BYTE * out,unsigned int * outLen,unsigned int maxOutLen,const BYTE * in,unsigned int inLen)225 DES_Encrypt(DESContext *cx, BYTE *out, unsigned int *outLen,
226             unsigned int maxOutLen, const BYTE *in, unsigned int inLen)
227 {
228 
229     if ((inLen % 8) != 0 || maxOutLen < inLen || !cx ||
230         cx->direction != DES_ENCRYPT) {
231         PORT_SetError(SEC_ERROR_INVALID_ARGS);
232         return SECFailure;
233     }
234 
235     cx->worker(cx, out, in, inLen);
236     if (outLen)
237         *outLen = inLen;
238     return SECSuccess;
239 }
240 
241 SECStatus
DES_Decrypt(DESContext * cx,BYTE * out,unsigned int * outLen,unsigned int maxOutLen,const BYTE * in,unsigned int inLen)242 DES_Decrypt(DESContext *cx, BYTE *out, unsigned int *outLen,
243             unsigned int maxOutLen, const BYTE *in, unsigned int inLen)
244 {
245 
246     if ((inLen % 8) != 0 || maxOutLen < inLen || !cx ||
247         cx->direction != DES_DECRYPT) {
248         PORT_SetError(SEC_ERROR_INVALID_ARGS);
249         return SECFailure;
250     }
251 
252     cx->worker(cx, out, in, inLen);
253     if (outLen)
254         *outLen = inLen;
255     return SECSuccess;
256 }
257