/src/nss-nspr/nss/lib/freebl/desblapi.c
Line | Count | Source (jump to first uncovered line) |
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 | 1 | HALFPTR(to) \ |
25 | 1 | [0] = HALFPTR(from)[0]; \ |
26 | 1 | HALFPTR(to) \ |
27 | 1 | [1] = HALFPTR(from)[1]; |
28 | | #else |
29 | | #define COPY8B(to, from, ptr) memcpy(to, from, 8) |
30 | | #endif |
31 | 1 | #define COPY8BTOHALF(to, from) COPY8B(to, from, from) |
32 | 0 | #define COPY8BFROMHALF(to, from) COPY8B(to, from, to) |
33 | | |
34 | | static void |
35 | | DES_ECB(DESContext *cx, BYTE *out, const BYTE *in, unsigned int len) |
36 | 1 | { |
37 | 2 | while (len) { |
38 | 1 | DES_Do1Block(cx->ks0, in, out); |
39 | 1 | len -= 8; |
40 | 1 | in += 8; |
41 | 1 | out += 8; |
42 | 1 | } |
43 | 1 | } |
44 | | |
45 | | static void |
46 | | DES_EDE3_ECB(DESContext *cx, BYTE *out, const BYTE *in, unsigned int len) |
47 | 0 | { |
48 | 0 | while (len) { |
49 | 0 | DES_Do1Block(cx->ks0, in, out); |
50 | 0 | len -= 8; |
51 | 0 | in += 8; |
52 | 0 | DES_Do1Block(cx->ks1, out, out); |
53 | 0 | DES_Do1Block(cx->ks2, out, out); |
54 | 0 | out += 8; |
55 | 0 | } |
56 | 0 | } |
57 | | |
58 | | static void NO_SANITIZE_ALIGNMENT |
59 | | DES_CBCEn(DESContext *cx, BYTE *out, const BYTE *in, unsigned int len) |
60 | 0 | { |
61 | 0 | const BYTE *bufend = in + len; |
62 | 0 | HALF vec[2]; |
63 | |
|
64 | 0 | while (in != bufend) { |
65 | 0 | COPY8BTOHALF(vec, in); |
66 | 0 | in += 8; |
67 | 0 | vec[0] ^= cx->iv[0]; |
68 | 0 | vec[1] ^= cx->iv[1]; |
69 | 0 | DES_Do1Block(cx->ks0, (BYTE *)vec, (BYTE *)cx->iv); |
70 | 0 | COPY8BFROMHALF(out, cx->iv); |
71 | 0 | out += 8; |
72 | 0 | } |
73 | 0 | } |
74 | | |
75 | | static void NO_SANITIZE_ALIGNMENT |
76 | | DES_CBCDe(DESContext *cx, BYTE *out, const BYTE *in, unsigned int len) |
77 | 0 | { |
78 | 0 | const BYTE *bufend; |
79 | 0 | HALF oldciphertext[2]; |
80 | 0 | HALF plaintext[2]; |
81 | |
|
82 | 0 | for (bufend = in + len; in != bufend;) { |
83 | 0 | oldciphertext[0] = cx->iv[0]; |
84 | 0 | oldciphertext[1] = cx->iv[1]; |
85 | 0 | COPY8BTOHALF(cx->iv, in); |
86 | 0 | in += 8; |
87 | 0 | DES_Do1Block(cx->ks0, (BYTE *)cx->iv, (BYTE *)plaintext); |
88 | 0 | plaintext[0] ^= oldciphertext[0]; |
89 | 0 | plaintext[1] ^= oldciphertext[1]; |
90 | 0 | COPY8BFROMHALF(out, plaintext); |
91 | 0 | out += 8; |
92 | 0 | } |
93 | 0 | } |
94 | | |
95 | | static void NO_SANITIZE_ALIGNMENT |
96 | | DES_EDE3CBCEn(DESContext *cx, BYTE *out, const BYTE *in, unsigned int len) |
97 | 0 | { |
98 | 0 | const BYTE *bufend = in + len; |
99 | 0 | HALF vec[2]; |
100 | |
|
101 | 0 | while (in != bufend) { |
102 | 0 | COPY8BTOHALF(vec, in); |
103 | 0 | in += 8; |
104 | 0 | vec[0] ^= cx->iv[0]; |
105 | 0 | vec[1] ^= cx->iv[1]; |
106 | 0 | DES_Do1Block(cx->ks0, (BYTE *)vec, (BYTE *)cx->iv); |
107 | 0 | DES_Do1Block(cx->ks1, (BYTE *)cx->iv, (BYTE *)cx->iv); |
108 | 0 | DES_Do1Block(cx->ks2, (BYTE *)cx->iv, (BYTE *)cx->iv); |
109 | 0 | COPY8BFROMHALF(out, cx->iv); |
110 | 0 | out += 8; |
111 | 0 | } |
112 | 0 | } |
113 | | |
114 | | static void NO_SANITIZE_ALIGNMENT |
115 | | DES_EDE3CBCDe(DESContext *cx, BYTE *out, const BYTE *in, unsigned int len) |
116 | 0 | { |
117 | 0 | const BYTE *bufend; |
118 | 0 | HALF oldciphertext[2]; |
119 | 0 | HALF plaintext[2]; |
120 | |
|
121 | 0 | for (bufend = in + len; in != bufend;) { |
122 | 0 | oldciphertext[0] = cx->iv[0]; |
123 | 0 | oldciphertext[1] = cx->iv[1]; |
124 | 0 | COPY8BTOHALF(cx->iv, in); |
125 | 0 | in += 8; |
126 | 0 | DES_Do1Block(cx->ks0, (BYTE *)cx->iv, (BYTE *)plaintext); |
127 | 0 | DES_Do1Block(cx->ks1, (BYTE *)plaintext, (BYTE *)plaintext); |
128 | 0 | DES_Do1Block(cx->ks2, (BYTE *)plaintext, (BYTE *)plaintext); |
129 | 0 | plaintext[0] ^= oldciphertext[0]; |
130 | 0 | plaintext[1] ^= oldciphertext[1]; |
131 | 0 | COPY8BFROMHALF(out, plaintext); |
132 | 0 | out += 8; |
133 | 0 | } |
134 | 0 | } |
135 | | |
136 | | DESContext * |
137 | | DES_AllocateContext(void) |
138 | 0 | { |
139 | 0 | return PORT_ZNew(DESContext); |
140 | 0 | } |
141 | | |
142 | | SECStatus |
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 | 3 | { |
147 | 3 | DESDirection opposite; |
148 | 3 | if (!cx) { |
149 | 0 | PORT_SetError(SEC_ERROR_INVALID_ARGS); |
150 | 0 | return SECFailure; |
151 | 0 | } |
152 | 3 | cx->direction = encrypt ? DES_ENCRYPT : DES_DECRYPT; |
153 | 3 | opposite = encrypt ? DES_DECRYPT : DES_ENCRYPT; |
154 | 3 | switch (mode) { |
155 | 2 | case NSS_DES: /* DES ECB */ |
156 | 2 | DES_MakeSchedule(cx->ks0, key, cx->direction); |
157 | 2 | cx->worker = &DES_ECB; |
158 | 2 | break; |
159 | | |
160 | 0 | case NSS_DES_EDE3: /* DES EDE ECB */ |
161 | 0 | cx->worker = &DES_EDE3_ECB; |
162 | 0 | if (encrypt) { |
163 | 0 | DES_MakeSchedule(cx->ks0, key, cx->direction); |
164 | 0 | DES_MakeSchedule(cx->ks1, key + 8, opposite); |
165 | 0 | DES_MakeSchedule(cx->ks2, key + 16, cx->direction); |
166 | 0 | } else { |
167 | 0 | DES_MakeSchedule(cx->ks2, key, cx->direction); |
168 | 0 | DES_MakeSchedule(cx->ks1, key + 8, opposite); |
169 | 0 | DES_MakeSchedule(cx->ks0, key + 16, cx->direction); |
170 | 0 | } |
171 | 0 | break; |
172 | | |
173 | 1 | case NSS_DES_CBC: /* DES CBC */ |
174 | 1 | COPY8BTOHALF(cx->iv, iv); |
175 | 1 | cx->worker = encrypt ? &DES_CBCEn : &DES_CBCDe; |
176 | 1 | DES_MakeSchedule(cx->ks0, key, cx->direction); |
177 | 1 | break; |
178 | | |
179 | 0 | case NSS_DES_EDE3_CBC: /* DES EDE CBC */ |
180 | 0 | COPY8BTOHALF(cx->iv, iv); |
181 | 0 | if (encrypt) { |
182 | 0 | cx->worker = &DES_EDE3CBCEn; |
183 | 0 | DES_MakeSchedule(cx->ks0, key, cx->direction); |
184 | 0 | DES_MakeSchedule(cx->ks1, key + 8, opposite); |
185 | 0 | DES_MakeSchedule(cx->ks2, key + 16, cx->direction); |
186 | 0 | } else { |
187 | 0 | cx->worker = &DES_EDE3CBCDe; |
188 | 0 | DES_MakeSchedule(cx->ks2, key, cx->direction); |
189 | 0 | DES_MakeSchedule(cx->ks1, key + 8, opposite); |
190 | 0 | DES_MakeSchedule(cx->ks0, key + 16, cx->direction); |
191 | 0 | } |
192 | 0 | break; |
193 | | |
194 | 0 | default: |
195 | 0 | PORT_SetError(SEC_ERROR_INVALID_ARGS); |
196 | 0 | return SECFailure; |
197 | 3 | } |
198 | 3 | return SECSuccess; |
199 | 3 | } |
200 | | |
201 | | DESContext * |
202 | | DES_CreateContext(const BYTE *key, const BYTE *iv, int mode, PRBool encrypt) |
203 | 3 | { |
204 | 3 | DESContext *cx = PORT_ZNew(DESContext); |
205 | 3 | SECStatus rv = DES_InitContext(cx, key, 0, iv, mode, encrypt, 0); |
206 | | |
207 | 3 | if (rv != SECSuccess) { |
208 | 0 | PORT_ZFree(cx, sizeof *cx); |
209 | 0 | cx = NULL; |
210 | 0 | } |
211 | 3 | return cx; |
212 | 3 | } |
213 | | |
214 | | void |
215 | | DES_DestroyContext(DESContext *cx, PRBool freeit) |
216 | 3 | { |
217 | 3 | if (cx) { |
218 | 3 | memset(cx, 0, sizeof *cx); |
219 | 3 | if (freeit) |
220 | 3 | PORT_Free(cx); |
221 | 3 | } |
222 | 3 | } |
223 | | |
224 | | SECStatus |
225 | | DES_Encrypt(DESContext *cx, BYTE *out, unsigned int *outLen, |
226 | | unsigned int maxOutLen, const BYTE *in, unsigned int inLen) |
227 | 1 | { |
228 | | |
229 | 1 | if ((inLen % 8) != 0 || maxOutLen < inLen || !cx || |
230 | 1 | cx->direction != DES_ENCRYPT) { |
231 | 1 | PORT_SetError(SEC_ERROR_INVALID_ARGS); |
232 | 1 | return SECFailure; |
233 | 1 | } |
234 | | |
235 | 0 | cx->worker(cx, out, in, inLen); |
236 | 0 | if (outLen) |
237 | 0 | *outLen = inLen; |
238 | 0 | return SECSuccess; |
239 | 1 | } |
240 | | |
241 | | SECStatus |
242 | | DES_Decrypt(DESContext *cx, BYTE *out, unsigned int *outLen, |
243 | | unsigned int maxOutLen, const BYTE *in, unsigned int inLen) |
244 | 3 | { |
245 | | |
246 | 3 | if ((inLen % 8) != 0 || maxOutLen < inLen || !cx || |
247 | 3 | cx->direction != DES_DECRYPT) { |
248 | 2 | PORT_SetError(SEC_ERROR_INVALID_ARGS); |
249 | 2 | return SECFailure; |
250 | 2 | } |
251 | | |
252 | 1 | cx->worker(cx, out, in, inLen); |
253 | 1 | if (outLen) |
254 | 1 | *outLen = inLen; |
255 | 1 | return SECSuccess; |
256 | 3 | } |