xref: /openbsd/lib/libcrypto/des/des_fcrypt.c (revision 48d3e433)
1 /* $OpenBSD: des_fcrypt.c,v 1.4 2024/08/31 16:22:18 jsing Exp $ */
2 /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
3  * All rights reserved.
4  *
5  * This package is an SSL implementation written
6  * by Eric Young (eay@cryptsoft.com).
7  * The implementation was written so as to conform with Netscapes SSL.
8  *
9  * This library is free for commercial and non-commercial use as long as
10  * the following conditions are aheared to.  The following conditions
11  * apply to all code found in this distribution, be it the RC4, RSA,
12  * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
13  * included with this distribution is covered by the same copyright terms
14  * except that the holder is Tim Hudson (tjh@cryptsoft.com).
15  *
16  * Copyright remains Eric Young's, and as such any Copyright notices in
17  * the code are not to be removed.
18  * If this package is used in a product, Eric Young should be given attribution
19  * as the author of the parts of the library used.
20  * This can be in the form of a textual message at program startup or
21  * in documentation (online or textual) provided with the package.
22  *
23  * Redistribution and use in source and binary forms, with or without
24  * modification, are permitted provided that the following conditions
25  * are met:
26  * 1. Redistributions of source code must retain the copyright
27  *    notice, this list of conditions and the following disclaimer.
28  * 2. Redistributions in binary form must reproduce the above copyright
29  *    notice, this list of conditions and the following disclaimer in the
30  *    documentation and/or other materials provided with the distribution.
31  * 3. All advertising materials mentioning features or use of this software
32  *    must display the following acknowledgement:
33  *    "This product includes cryptographic software written by
34  *     Eric Young (eay@cryptsoft.com)"
35  *    The word 'cryptographic' can be left out if the rouines from the library
36  *    being used are not cryptographic related :-).
37  * 4. If you include any Windows specific code (or a derivative thereof) from
38  *    the apps directory (application code) you must include an acknowledgement:
39  *    "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
40  *
41  * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
42  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
43  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
44  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
45  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
46  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
47  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
48  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
49  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
50  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
51  * SUCH DAMAGE.
52  *
53  * The licence and distribution terms for any publically available version or
54  * derivative of this code cannot be changed.  i.e. this code cannot simply be
55  * copied and put under another distribution licence
56  * [including the GNU Public Licence.]
57  */
58 
59 #include <stdio.h>
60 
61 /* This version of crypt has been developed from my MIT compatible
62  * DES library.
63  * Eric Young (eay@cryptsoft.com)
64  */
65 
66 /* Modification by Jens Kupferschmidt (Cu)
67  * I have included directive PARA for shared memory computers.
68  * I have included a directive LONGCRYPT to using this routine to cipher
69  * passwords with more than 8 bytes like HP-UX 10.x it used. The MAXPLEN
70  * definition is the maximum of length of password and can changed. I have
71  * defined 24.
72  */
73 
74 #define DES_FCRYPT
75 #include "des_local.h"
76 #undef DES_FCRYPT
77 
78 #undef PERM_OP
79 #define PERM_OP(a,b,t,n,m) ((t)=((((a)>>(n))^(b))&(m)),			\
80 	(b)^=(t),							\
81 	(a)^=((t)<<(n)))
82 
83 #undef HPERM_OP
84 #define HPERM_OP(a,t,n,m) ((t)=((((a)<<(16-(n)))^(a))&(m)),		\
85 	(a)=(a)^(t)^(t>>(16-(n))))					\
86 
87 static void
fcrypt_body(DES_LONG * out,DES_key_schedule * ks,DES_LONG Eswap0,DES_LONG Eswap1)88 fcrypt_body(DES_LONG *out, DES_key_schedule *ks, DES_LONG Eswap0,
89     DES_LONG Eswap1)
90 {
91 	DES_LONG l, r, t, u;
92 	DES_LONG *s;
93 	int j;
94 	DES_LONG E0, E1;
95 
96 	l = 0;
97 	r = 0;
98 
99 	s = (DES_LONG *)ks;
100 	E0 = Eswap0;
101 	E1 = Eswap1;
102 
103 	for (j = 0; j < 25; j++) {
104 #ifndef DES_UNROLL
105 		int i;
106 
107 		for (i = 0; i < 32; i += 4) {
108 			D_ENCRYPT(l, r, i + 0); /*  1 */
109 			D_ENCRYPT(r, l, i + 2); /*  2 */
110 		}
111 #else
112 		D_ENCRYPT(l, r, 0); /*  1 */
113 		D_ENCRYPT(r, l, 2); /*  2 */
114 		D_ENCRYPT(l, r, 4); /*  3 */
115 		D_ENCRYPT(r, l, 6); /*  4 */
116 		D_ENCRYPT(l, r, 8); /*  5 */
117 		D_ENCRYPT(r, l, 10); /*  6 */
118 		D_ENCRYPT(l, r, 12); /*  7 */
119 		D_ENCRYPT(r, l, 14); /*  8 */
120 		D_ENCRYPT(l, r, 16); /*  9 */
121 		D_ENCRYPT(r, l, 18); /*  10 */
122 		D_ENCRYPT(l, r, 20); /*  11 */
123 		D_ENCRYPT(r, l, 22); /*  12 */
124 		D_ENCRYPT(l, r, 24); /*  13 */
125 		D_ENCRYPT(r, l, 26); /*  14 */
126 		D_ENCRYPT(l, r, 28); /*  15 */
127 		D_ENCRYPT(r, l, 30); /*  16 */
128 #endif
129 
130 		t = l;
131 		l = r;
132 		r = t;
133 	}
134 	l = ROTATE(l, 3) & 0xffffffffL;
135 	r = ROTATE(r, 3) & 0xffffffffL;
136 
137 	PERM_OP(l, r, t, 1, 0x55555555L);
138 	PERM_OP(r, l, t, 8, 0x00ff00ffL);
139 	PERM_OP(l, r, t, 2, 0x33333333L);
140 	PERM_OP(r, l, t, 16, 0x0000ffffL);
141 	PERM_OP(l, r, t, 4, 0x0f0f0f0fL);
142 
143 	out[0] = r;
144 	out[1] = l;
145 }
146 
147 /* Added more values to handle illegal salt values the way normal
148  * crypt() implementations do.  The patch was sent by
149  * Bjorn Gronvall <bg@sics.se>
150  */
151 static unsigned const char con_salt[128] = {
152 	0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9,
153 	0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF, 0xE0, 0xE1,
154 	0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9,
155 	0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF, 0xF0, 0xF1,
156 	0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9,
157 	0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF, 0x00, 0x01,
158 	0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09,
159 	0x0A, 0x0B, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A,
160 	0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12,
161 	0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A,
162 	0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, 0x21, 0x22,
163 	0x23, 0x24, 0x25, 0x20, 0x21, 0x22, 0x23, 0x24,
164 	0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C,
165 	0x2D, 0x2E, 0x2F, 0x30, 0x31, 0x32, 0x33, 0x34,
166 	0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C,
167 	0x3D, 0x3E, 0x3F, 0x40, 0x41, 0x42, 0x43, 0x44,
168 };
169 
170 static unsigned const char cov_2char[64] = {
171 	0x2E, 0x2F, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35,
172 	0x36, 0x37, 0x38, 0x39, 0x41, 0x42, 0x43, 0x44,
173 	0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C,
174 	0x4D, 0x4E, 0x4F, 0x50, 0x51, 0x52, 0x53, 0x54,
175 	0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x61, 0x62,
176 	0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A,
177 	0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70, 0x71, 0x72,
178 	0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A
179 };
180 
181 char *
DES_crypt(const char * buf,const char * salt)182 DES_crypt(const char *buf, const char *salt)
183 {
184 	static char buff[14];
185 
186 	return (DES_fcrypt(buf, salt, buff));
187 }
188 LCRYPTO_ALIAS(DES_crypt);
189 
190 char *
DES_fcrypt(const char * buf,const char * salt,char * ret)191 DES_fcrypt(const char *buf, const char *salt, char *ret)
192 {
193 	unsigned int i, j, x, y;
194 	DES_LONG Eswap0, Eswap1;
195 	DES_LONG out[2], ll;
196 	DES_cblock key;
197 	DES_key_schedule ks;
198 	unsigned char bb[9];
199 	unsigned char *b = bb;
200 	unsigned char c, u;
201 
202 	/* eay 25/08/92
203 	 * If you call crypt("pwd","*") as often happens when you
204 	 * have * as the pwd field in /etc/passwd, the function
205 	 * returns *\0xxxxxxxxx
206 	 * The \0 makes the string look like * so the pwd "*" would
207 	 * crypt to "*".  This was found when replacing the crypt in
208 	 * our shared libraries.  People found that the disabled
209 	 * accounts effectively had no passwd :-(. */
210 	x = ret[0] = ((salt[0] == '\0') ? 'A' : salt[0]);
211 	Eswap0 = con_salt[x] << 2;
212 	x = ret[1] = ((salt[1] == '\0') ? 'A' : salt[1]);
213 	Eswap1 = con_salt[x] << 6;
214 /* EAY
215 r=strlen(buf);
216 r=(r+7)/8;
217 */
218 	for (i = 0; i < 8; i++) {
219 		c = *(buf++);
220 		if (!c)
221 			break;
222 		key[i] = (c << 1);
223 	}
224 	for (; i < 8; i++)
225 		key[i] = 0;
226 
227 	DES_set_key_unchecked(&key, &ks);
228 	fcrypt_body(&(out[0]), &ks, Eswap0, Eswap1);
229 
230 	ll = out[0];
231 	l2c(ll, b);
232 	ll = out[1];
233 	l2c(ll, b);
234 	y = 0;
235 	u = 0x80;
236 	bb[8] = 0;
237 	for (i = 2; i < 13; i++) {
238 		c = 0;
239 		for (j = 0; j < 6; j++) {
240 			c <<= 1;
241 			if (bb[y] & u)
242 				c |= 1;
243 			u >>= 1;
244 			if (!u) {
245 				y++;
246 				u = 0x80;
247 			}
248 		}
249 		ret[i] = cov_2char[c];
250 	}
251 	ret[13] = '\0';
252 	return (ret);
253 }
254 LCRYPTO_ALIAS(DES_fcrypt);
255