Skip to content

Commit 2a32827

Browse files
chenzhijiaGUIDINGLI
authored andcommitted
libs/libc/unistd: add crypt function
Add crypt function to pass tlpi example: https://man7.org/tlpi/code/online/dist/users_groups/check_password.c.html Signed-off-by: chenzhijia <chenzhijia@xiaomi.com>
1 parent ad70ca3 commit 2a32827

File tree

6 files changed

+345
-0
lines changed

6 files changed

+345
-0
lines changed

include/unistd.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -470,6 +470,11 @@ int profil(FAR unsigned short *buf, size_t bufsiz,
470470
size_t offset, unsigned int scale);
471471

472472
FAR char *getpass(FAR const char *prompt);
473+
#ifdef CONFIG_CRYPTO
474+
FAR char *crypt(FAR const char *key, FAR const char *salt);
475+
FAR char *crypt_r(FAR const char *key, FAR const char *salt,
476+
FAR char *output);
477+
#endif
473478

474479
#if CONFIG_FORTIFY_SOURCE > 0
475480
fortify_function(getcwd) FAR char *getcwd(FAR char *buf,

libs/libc/libc.csv

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,8 @@
4040
"crc32","nuttx/crc32.h","","uint32_t","FAR const uint8_t *","size_t"
4141
"crc32part","nuttx/crc32.h","","uint32_t","FAR const uint8_t *","size_t","uint32_t"
4242
"ctime","time.h","","char *","const time_t *"
43+
"crypt","unistd.h","defined(CONFIG_CRYPTO)","FAR const char *","FAR const char *"
44+
"crypt_r","unistd.h","defined(CONFIG_CRYPTO)","FAR const char *","FAR const char *","FAR char *"
4345
"daemon","unistd.h","","int","int","int"
4446
"dgettext","libintl.h","defined(CONFIG_LIBC_LOCALE_GETTEXT)","FAR char *","FAR const char *","FAR const char *"
4547
"dirname","libgen.h","","FAR char *","FAR char *"

libs/libc/unistd/CMakeLists.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,4 +97,8 @@ if(CONFIG_ARCH_HAVE_FORK)
9797
list(APPEND SRCS lib_fork.c)
9898
endif()
9999

100+
if(CONFIG_CRYPTO)
101+
list(APPEND SRCS lib_crypt.c lib_crypt_r.c)
102+
endif()
103+
100104
target_sources(c PRIVATE ${SRCS})

libs/libc/unistd/Make.defs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,10 @@ ifeq ($(CONFIG_ARCH_HAVE_FORK),y)
5555
CSRCS += lib_fork.c
5656
endif
5757

58+
ifeq ($(CONFIG_CRYPTO),y)
59+
CSRCS += lib_crypt.c lib_crypt_r.c
60+
endif
61+
5862
# Add the unistd directory to the build
5963

6064
DEPPATH += --dep-path unistd

libs/libc/unistd/lib_crypt.c

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
/****************************************************************************
2+
* libs/libc/unistd/lib_crypt.c
3+
*
4+
* Licensed to the Apache Software Foundation (ASF) under one or more
5+
* contributor license agreements. See the NOTICE file distributed with
6+
* this work for additional information regarding copyright ownership. The
7+
* ASF licenses this file to you under the Apache License, Version 2.0 (the
8+
* "License"); you may not use this file except in compliance with the
9+
* License. You may obtain a copy of the License at
10+
*
11+
* http://www.apache.org/licenses/LICENSE-2.0
12+
*
13+
* Unless required by applicable law or agreed to in writing, software
14+
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
15+
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
16+
* License for the specific language governing permissions and limitations
17+
* under the License.
18+
*
19+
****************************************************************************/
20+
21+
/****************************************************************************
22+
* Included Files
23+
****************************************************************************/
24+
25+
#include <unistd.h>
26+
27+
/****************************************************************************
28+
* Private Data
29+
****************************************************************************/
30+
31+
static char g_passwd[128];
32+
33+
/****************************************************************************
34+
* Public Functions
35+
****************************************************************************/
36+
37+
char *crypt(const char *key, const char *salt)
38+
{
39+
return crypt_r(key, salt, g_passwd);
40+
}

libs/libc/unistd/lib_crypt_r.c

Lines changed: 290 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,290 @@
1+
/****************************************************************************
2+
* libs/libc/unistd/lib_crypt_r.c
3+
*
4+
* Licensed to the Apache Software Foundation (ASF) under one or more
5+
* contributor license agreements. See the NOTICE file distributed with
6+
* this work for additional information regarding copyright ownership. The
7+
* ASF licenses this file to you under the Apache License, Version 2.0 (the
8+
* "License"); you may not use this file except in compliance with the
9+
* License. You may obtain a copy of the License at
10+
*
11+
* http://www.apache.org/licenses/LICENSE-2.0
12+
*
13+
* Unless required by applicable law or agreed to in writing, software
14+
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
15+
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
16+
* License for the specific language governing permissions and limitations
17+
* under the License.
18+
*
19+
****************************************************************************/
20+
21+
/****************************************************************************
22+
* Included Files
23+
****************************************************************************/
24+
25+
#include <crypto/cryptodev.h>
26+
#include <errno.h>
27+
#include <fcntl.h>
28+
#include <string.h>
29+
#include <sys/ioctl.h>
30+
#include <unistd.h>
31+
32+
/****************************************************************************
33+
* Pre-processor Definitions
34+
****************************************************************************/
35+
36+
#define KEY_MAX 30000
37+
#define SALT_MAX 8
38+
39+
/****************************************************************************
40+
* Private Types
41+
****************************************************************************/
42+
43+
typedef struct cryptodev_context_s
44+
{
45+
int fd;
46+
struct session_op session;
47+
struct crypt_op crypt;
48+
}cryptodev_context_t;
49+
50+
/****************************************************************************
51+
* Private Data
52+
****************************************************************************/
53+
54+
/* 0 ... 63 => ascii - 64 */
55+
56+
static const unsigned char g_md5_itoa64[] =
57+
"./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
58+
59+
/****************************************************************************
60+
* Private Functions
61+
****************************************************************************/
62+
63+
static FAR char *md5_to64(FAR char *s, unsigned long v, int n)
64+
{
65+
while (--n >= 0)
66+
{
67+
*s++ = g_md5_itoa64[v & 0x3f];
68+
v >>= 6;
69+
}
70+
71+
return s;
72+
}
73+
74+
static int md5_init(FAR cryptodev_context_t *ctx)
75+
{
76+
int ret;
77+
int fd;
78+
79+
memset(ctx, 0, sizeof(cryptodev_context_t));
80+
fd = open("/dev/crypto", O_RDWR, 0);
81+
if (fd < 0)
82+
{
83+
return -errno;
84+
}
85+
86+
ret = ioctl(fd, CRIOGET, &ctx->fd);
87+
close(fd);
88+
if (ret < 0)
89+
{
90+
ret = -errno;
91+
}
92+
93+
ctx->session.mac = CRYPTO_MD5;
94+
ret = ioctl(ctx->fd, CIOCGSESSION, &ctx->session);
95+
if (ret < 0)
96+
{
97+
return -errno;
98+
}
99+
100+
ctx->crypt.ses = ctx->session.ses;
101+
return ret;
102+
}
103+
104+
static int md5_update(FAR cryptodev_context_t *ctx,
105+
FAR const void *input, size_t ilen)
106+
{
107+
int ret;
108+
ctx->crypt.op = COP_ENCRYPT;
109+
ctx->crypt.flags |= COP_FLAG_UPDATE;
110+
ctx->crypt.src = (caddr_t)input;
111+
ctx->crypt.len = ilen;
112+
113+
ret = ioctl(ctx->fd, CIOCCRYPT, &ctx->crypt);
114+
return ret < 0 ? -errno : ret;
115+
}
116+
117+
static int md5_finish(FAR cryptodev_context_t *ctx,
118+
unsigned char output[16])
119+
{
120+
int ret;
121+
122+
ctx->crypt.op = COP_ENCRYPT;
123+
ctx->crypt.flags = 0;
124+
ctx->crypt.mac = (caddr_t)output;
125+
ret = ioctl(ctx->fd, CIOCCRYPT, &ctx->crypt);
126+
if (ret < 0)
127+
{
128+
return -errno;
129+
}
130+
131+
ioctl(ctx->fd, CIOCFSESSION, &ctx->session.ses);
132+
ctx->crypt.ses = 0;
133+
close(ctx->fd);
134+
memset(ctx, 0, sizeof(cryptodev_context_t));
135+
return ret;
136+
}
137+
138+
/* UNIX password
139+
* Use MD5 for what it is best at...
140+
*/
141+
142+
static FAR char *md5_crypt(FAR const char *key, FAR const char *setting,
143+
FAR char *output)
144+
{
145+
cryptodev_context_t ctx;
146+
unsigned char md[16];
147+
unsigned int i;
148+
unsigned int klen;
149+
unsigned int slen;
150+
FAR const char *salt;
151+
FAR char *p;
152+
static const unsigned char perm[][3] =
153+
{
154+
{
155+
0, 6, 12
156+
},
157+
{
158+
1, 7, 13
159+
},
160+
{
161+
2, 8, 14
162+
},
163+
{
164+
3, 9, 15
165+
},
166+
{
167+
4, 10, 5
168+
}
169+
};
170+
171+
/* Reject large keys */
172+
173+
klen = strnlen(key, KEY_MAX + 1);
174+
if (klen > KEY_MAX)
175+
{
176+
return 0;
177+
}
178+
179+
/* Setting: $1$salt$ (closing $ is optional) */
180+
181+
salt = setting + 3;
182+
for (i = 0; i < SALT_MAX && salt[i] && salt[i] != '$'; i++);
183+
slen = i;
184+
185+
/* Md5(key salt key) */
186+
187+
md5_init(&ctx);
188+
md5_update(&ctx, key, klen);
189+
md5_update(&ctx, salt, slen);
190+
md5_update(&ctx, key, klen);
191+
md5_finish(&ctx, md);
192+
193+
/* Md5(key $1$ salt repeated-md weird-key[0]-0) */
194+
195+
md5_init(&ctx);
196+
md5_update(&ctx, key, klen);
197+
md5_update(&ctx, setting, 3 + slen);
198+
for (i = klen; i > sizeof md; i -= sizeof md)
199+
{
200+
md5_update(&ctx, md, sizeof md);
201+
}
202+
203+
md5_update(&ctx, md, i);
204+
md[0] = 0;
205+
for (i = klen; i; i >>= 1)
206+
{
207+
if (i & 1)
208+
{
209+
md5_update(&ctx, md, 1);
210+
}
211+
else
212+
{
213+
md5_update(&ctx, key, 1);
214+
}
215+
}
216+
217+
md5_finish(&ctx, md);
218+
219+
for (i = 0; i < 1000; i++)
220+
{
221+
md5_init(&ctx);
222+
if (i % 2)
223+
{
224+
md5_update(&ctx, key, klen);
225+
}
226+
else
227+
{
228+
md5_update(&ctx, md, sizeof md);
229+
}
230+
231+
if (i % 3)
232+
{
233+
md5_update(&ctx, salt, slen);
234+
}
235+
236+
if (i % 7)
237+
{
238+
md5_update(&ctx, key, klen);
239+
}
240+
241+
if (i % 2)
242+
{
243+
md5_update(&ctx, md, sizeof md);
244+
}
245+
else
246+
{
247+
md5_update(&ctx, key, klen);
248+
}
249+
250+
md5_finish(&ctx, md);
251+
}
252+
253+
/* Output is $1$salt$hash */
254+
255+
memcpy(output, setting, 3 + slen);
256+
p = output + 3 + slen;
257+
*p++ = '$';
258+
259+
for (i = 0; i < 5; i++)
260+
{
261+
p = md5_to64(p, (md[perm[i][0]] << 16) |
262+
(md[perm[i][1]] << 8) | md[perm[i][2]], 4);
263+
}
264+
265+
p = md5_to64(p, md[11], 2);
266+
*p = 0;
267+
268+
return output;
269+
}
270+
271+
/****************************************************************************
272+
* Public Functions
273+
****************************************************************************/
274+
275+
FAR char *crypt_r(FAR const char *key, FAR const char *salt,
276+
FAR char *output)
277+
{
278+
/* First, check if we are supposed to be using the MD5
279+
* not support DES...
280+
*/
281+
282+
if (salt[0] == '$' && salt[1] == '1' && salt[2] == '$')
283+
{
284+
return md5_crypt(key, salt, output);
285+
}
286+
else
287+
{
288+
return NULL;
289+
}
290+
}

0 commit comments

Comments
 (0)