|
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 <stddef.h> |
|
18 #include "secerr.h" |
|
19 |
|
20 #if defined(NSS_X86_OR_X64) |
|
21 /* Intel X86 CPUs do unaligned loads and stores without complaint. */ |
|
22 #define COPY8B(to, from, ptr) \ |
|
23 HALFPTR(to)[0] = HALFPTR(from)[0]; \ |
|
24 HALFPTR(to)[1] = HALFPTR(from)[1]; |
|
25 #elif defined(USE_MEMCPY) |
|
26 #define COPY8B(to, from, ptr) memcpy(to, from, 8) |
|
27 #else |
|
28 #define COPY8B(to, from, ptr) \ |
|
29 if (((ptrdiff_t)(ptr) & 0x3) == 0) { \ |
|
30 HALFPTR(to)[0] = HALFPTR(from)[0]; \ |
|
31 HALFPTR(to)[1] = HALFPTR(from)[1]; \ |
|
32 } else if (((ptrdiff_t)(ptr) & 0x1) == 0) { \ |
|
33 SHORTPTR(to)[0] = SHORTPTR(from)[0]; \ |
|
34 SHORTPTR(to)[1] = SHORTPTR(from)[1]; \ |
|
35 SHORTPTR(to)[2] = SHORTPTR(from)[2]; \ |
|
36 SHORTPTR(to)[3] = SHORTPTR(from)[3]; \ |
|
37 } else { \ |
|
38 BYTEPTR(to)[0] = BYTEPTR(from)[0]; \ |
|
39 BYTEPTR(to)[1] = BYTEPTR(from)[1]; \ |
|
40 BYTEPTR(to)[2] = BYTEPTR(from)[2]; \ |
|
41 BYTEPTR(to)[3] = BYTEPTR(from)[3]; \ |
|
42 BYTEPTR(to)[4] = BYTEPTR(from)[4]; \ |
|
43 BYTEPTR(to)[5] = BYTEPTR(from)[5]; \ |
|
44 BYTEPTR(to)[6] = BYTEPTR(from)[6]; \ |
|
45 BYTEPTR(to)[7] = BYTEPTR(from)[7]; \ |
|
46 } |
|
47 #endif |
|
48 #define COPY8BTOHALF(to, from) COPY8B(to, from, from) |
|
49 #define COPY8BFROMHALF(to, from) COPY8B(to, from, to) |
|
50 |
|
51 static void |
|
52 DES_ECB(DESContext *cx, BYTE *out, const BYTE *in, unsigned int len) |
|
53 { |
|
54 while (len) { |
|
55 DES_Do1Block(cx->ks0, in, out); |
|
56 len -= 8; |
|
57 in += 8; |
|
58 out += 8; |
|
59 } |
|
60 } |
|
61 |
|
62 static void |
|
63 DES_EDE3_ECB(DESContext *cx, BYTE *out, const BYTE *in, unsigned int len) |
|
64 { |
|
65 while (len) { |
|
66 DES_Do1Block(cx->ks0, in, out); |
|
67 len -= 8; |
|
68 in += 8; |
|
69 DES_Do1Block(cx->ks1, out, out); |
|
70 DES_Do1Block(cx->ks2, out, out); |
|
71 out += 8; |
|
72 } |
|
73 } |
|
74 |
|
75 static void |
|
76 DES_CBCEn(DESContext *cx, BYTE *out, const BYTE *in, unsigned int len) |
|
77 { |
|
78 const BYTE * bufend = in + len; |
|
79 HALF vec[2]; |
|
80 |
|
81 while (in != bufend) { |
|
82 COPY8BTOHALF(vec, in); |
|
83 in += 8; |
|
84 vec[0] ^= cx->iv[0]; |
|
85 vec[1] ^= cx->iv[1]; |
|
86 DES_Do1Block( cx->ks0, (BYTE *)vec, (BYTE *)cx->iv); |
|
87 COPY8BFROMHALF(out, cx->iv); |
|
88 out += 8; |
|
89 } |
|
90 } |
|
91 |
|
92 static void |
|
93 DES_CBCDe(DESContext *cx, BYTE *out, const BYTE *in, unsigned int len) |
|
94 { |
|
95 const BYTE * bufend; |
|
96 HALF oldciphertext[2]; |
|
97 HALF plaintext [2]; |
|
98 |
|
99 for (bufend = in + len; in != bufend; ) { |
|
100 oldciphertext[0] = cx->iv[0]; |
|
101 oldciphertext[1] = cx->iv[1]; |
|
102 COPY8BTOHALF(cx->iv, in); |
|
103 in += 8; |
|
104 DES_Do1Block(cx->ks0, (BYTE *)cx->iv, (BYTE *)plaintext); |
|
105 plaintext[0] ^= oldciphertext[0]; |
|
106 plaintext[1] ^= oldciphertext[1]; |
|
107 COPY8BFROMHALF(out, plaintext); |
|
108 out += 8; |
|
109 } |
|
110 } |
|
111 |
|
112 static void |
|
113 DES_EDE3CBCEn(DESContext *cx, BYTE *out, const BYTE *in, unsigned int len) |
|
114 { |
|
115 const BYTE * bufend = in + len; |
|
116 HALF vec[2]; |
|
117 |
|
118 while (in != bufend) { |
|
119 COPY8BTOHALF(vec, in); |
|
120 in += 8; |
|
121 vec[0] ^= cx->iv[0]; |
|
122 vec[1] ^= cx->iv[1]; |
|
123 DES_Do1Block( cx->ks0, (BYTE *)vec, (BYTE *)cx->iv); |
|
124 DES_Do1Block( cx->ks1, (BYTE *)cx->iv, (BYTE *)cx->iv); |
|
125 DES_Do1Block( cx->ks2, (BYTE *)cx->iv, (BYTE *)cx->iv); |
|
126 COPY8BFROMHALF(out, cx->iv); |
|
127 out += 8; |
|
128 } |
|
129 } |
|
130 |
|
131 static void |
|
132 DES_EDE3CBCDe(DESContext *cx, BYTE *out, const BYTE *in, unsigned int len) |
|
133 { |
|
134 const BYTE * bufend; |
|
135 HALF oldciphertext[2]; |
|
136 HALF plaintext [2]; |
|
137 |
|
138 for (bufend = in + len; in != bufend; ) { |
|
139 oldciphertext[0] = cx->iv[0]; |
|
140 oldciphertext[1] = cx->iv[1]; |
|
141 COPY8BTOHALF(cx->iv, in); |
|
142 in += 8; |
|
143 DES_Do1Block(cx->ks0, (BYTE *)cx->iv, (BYTE *)plaintext); |
|
144 DES_Do1Block(cx->ks1, (BYTE *)plaintext, (BYTE *)plaintext); |
|
145 DES_Do1Block(cx->ks2, (BYTE *)plaintext, (BYTE *)plaintext); |
|
146 plaintext[0] ^= oldciphertext[0]; |
|
147 plaintext[1] ^= oldciphertext[1]; |
|
148 COPY8BFROMHALF(out, plaintext); |
|
149 out += 8; |
|
150 } |
|
151 } |
|
152 |
|
153 DESContext * |
|
154 DES_AllocateContext(void) |
|
155 { |
|
156 return PORT_ZNew(DESContext); |
|
157 } |
|
158 |
|
159 SECStatus |
|
160 DES_InitContext(DESContext *cx, const unsigned char *key, unsigned int keylen, |
|
161 const unsigned char *iv, int mode, unsigned int encrypt, |
|
162 unsigned int unused) |
|
163 { |
|
164 DESDirection opposite; |
|
165 if (!cx) { |
|
166 PORT_SetError(SEC_ERROR_INVALID_ARGS); |
|
167 return SECFailure; |
|
168 } |
|
169 cx->direction = encrypt ? DES_ENCRYPT : DES_DECRYPT; |
|
170 opposite = encrypt ? DES_DECRYPT : DES_ENCRYPT; |
|
171 switch (mode) { |
|
172 case NSS_DES: /* DES ECB */ |
|
173 DES_MakeSchedule( cx->ks0, key, cx->direction); |
|
174 cx->worker = &DES_ECB; |
|
175 break; |
|
176 |
|
177 case NSS_DES_EDE3: /* DES EDE ECB */ |
|
178 cx->worker = &DES_EDE3_ECB; |
|
179 if (encrypt) { |
|
180 DES_MakeSchedule(cx->ks0, key, cx->direction); |
|
181 DES_MakeSchedule(cx->ks1, key + 8, opposite); |
|
182 DES_MakeSchedule(cx->ks2, key + 16, cx->direction); |
|
183 } else { |
|
184 DES_MakeSchedule(cx->ks2, key, cx->direction); |
|
185 DES_MakeSchedule(cx->ks1, key + 8, opposite); |
|
186 DES_MakeSchedule(cx->ks0, key + 16, cx->direction); |
|
187 } |
|
188 break; |
|
189 |
|
190 case NSS_DES_CBC: /* DES CBC */ |
|
191 COPY8BTOHALF(cx->iv, iv); |
|
192 cx->worker = encrypt ? &DES_CBCEn : &DES_CBCDe; |
|
193 DES_MakeSchedule(cx->ks0, key, cx->direction); |
|
194 break; |
|
195 |
|
196 case NSS_DES_EDE3_CBC: /* DES EDE CBC */ |
|
197 COPY8BTOHALF(cx->iv, iv); |
|
198 if (encrypt) { |
|
199 cx->worker = &DES_EDE3CBCEn; |
|
200 DES_MakeSchedule(cx->ks0, key, cx->direction); |
|
201 DES_MakeSchedule(cx->ks1, key + 8, opposite); |
|
202 DES_MakeSchedule(cx->ks2, key + 16, cx->direction); |
|
203 } else { |
|
204 cx->worker = &DES_EDE3CBCDe; |
|
205 DES_MakeSchedule(cx->ks2, key, cx->direction); |
|
206 DES_MakeSchedule(cx->ks1, key + 8, opposite); |
|
207 DES_MakeSchedule(cx->ks0, key + 16, cx->direction); |
|
208 } |
|
209 break; |
|
210 |
|
211 default: |
|
212 PORT_SetError(SEC_ERROR_INVALID_ARGS); |
|
213 return SECFailure; |
|
214 } |
|
215 return SECSuccess; |
|
216 } |
|
217 |
|
218 DESContext * |
|
219 DES_CreateContext(const BYTE * key, const BYTE *iv, int mode, PRBool encrypt) |
|
220 { |
|
221 DESContext *cx = PORT_ZNew(DESContext); |
|
222 SECStatus rv = DES_InitContext(cx, key, 0, iv, mode, encrypt, 0); |
|
223 |
|
224 if (rv != SECSuccess) { |
|
225 PORT_ZFree(cx, sizeof *cx); |
|
226 cx = NULL; |
|
227 } |
|
228 return cx; |
|
229 } |
|
230 |
|
231 void |
|
232 DES_DestroyContext(DESContext *cx, PRBool freeit) |
|
233 { |
|
234 if (cx) { |
|
235 memset(cx, 0, sizeof *cx); |
|
236 if (freeit) |
|
237 PORT_Free(cx); |
|
238 } |
|
239 } |
|
240 |
|
241 SECStatus |
|
242 DES_Encrypt(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_ENCRYPT) { |
|
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 |
|
258 SECStatus |
|
259 DES_Decrypt(DESContext *cx, BYTE *out, unsigned int *outLen, |
|
260 unsigned int maxOutLen, const BYTE *in, unsigned int inLen) |
|
261 { |
|
262 |
|
263 if ((inLen % 8) != 0 || maxOutLen < inLen || !cx || |
|
264 cx->direction != DES_DECRYPT) { |
|
265 PORT_SetError(SEC_ERROR_INVALID_ARGS); |
|
266 return SECFailure; |
|
267 } |
|
268 |
|
269 cx->worker(cx, out, in, inLen); |
|
270 if (outLen) |
|
271 *outLen = inLen; |
|
272 return SECSuccess; |
|
273 } |