Skip to content

Commit 98a4b57

Browse files
!fsutils/passwd: Replace TEA with PBKDF2-HMAC-SHA256
Migrate passwd encrypt/verify to PBKDF2 modular crypt format using kernel cryptodev (CRYPTO_PBKDF2_HMAC_SHA256 via /dev/crypto). Add passwd_pbkdf2 wrapper, base64url helpers, complexity validation, and pbkdf2_test for RFC 6070 vector coverage. FSUTILS_PASSWD selects CRYPTO, ALLOW_BSD_COMPONENTS, and CRYPTO_CRYPTODEV so existing sim defconfigs keep building. Change NSH_LOGIN_USERNAME default to root and remove fixed-login password defaults. BREAKING CHANGE: TEA-encoded /etc/passwd entries no longer verify. Regenerate each entry after upgrading. Pair with the nuttx host mkpasswd changes in apache/nuttx#19209. Boards must enable the appropriate software or hardware crypto backend for PBKDF2 at runtime. When CONFIG_NSH_LOGIN_FIXED=y, set CONFIG_NSH_LOGIN_PASSWORD in the board defconfig or menuconfig; there is no default password. Signed-off-by: Abhishek Mishra <mishra.abhishek2808@gmail.com>
1 parent a6477ec commit 98a4b57

18 files changed

Lines changed: 1111 additions & 204 deletions

fsutils/passwd/CMakeLists.txt

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,14 @@
2323
if(CONFIG_FSUTILS_PASSWD)
2424
set(CSRCS)
2525

26-
list(APPEND CSRCS passwd_verify.c passwd_find.c passwd_encrypt.c)
26+
list(
27+
APPEND
28+
CSRCS
29+
passwd_verify.c
30+
passwd_find.c
31+
passwd_encrypt.c
32+
passwd_base64.c
33+
passwd_pbkdf2.c)
2734

2835
if(NOT CONFIG_FSUTILS_PASSWD_READONLY)
2936
list(

fsutils/passwd/Kconfig

Lines changed: 17 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,15 @@
66
config FSUTILS_PASSWD
77
bool "Password file support"
88
default n
9+
select CRYPTO
10+
select ALLOW_BSD_COMPONENTS
11+
select CRYPTO_CRYPTODEV
912
---help---
10-
Enables support for /etc/passwd file access routines
13+
Enables support for /etc/passwd file access routines.
14+
15+
NOTE: Password hashes use PBKDF2-HMAC-SHA256 (modular crypt format).
16+
Existing TEA-encrypted /etc/passwd entries are NOT compatible and
17+
must be regenerated.
1118

1219
if FSUTILS_PASSWD
1320

@@ -23,20 +30,14 @@ config FSUTILS_PASSWD_IOBUFFER_SIZE
2330
int "Allocated I/O buffer size"
2431
default 512
2532

26-
config FSUTILS_PASSWD_KEY1
27-
hex "Encryption key value 1"
28-
default 0x12345678
29-
30-
config FSUTILS_PASSWD_KEY2
31-
hex "Encryption key value 2"
32-
default 0x9abcdef0
33-
34-
config FSUTILS_PASSWD_KEY3
35-
hex "Encryption key value 3"
36-
default 0x12345678
37-
38-
config FSUTILS_PASSWD_KEY4
39-
hex "Encryption key value 4"
40-
default 0x9abcdef0
33+
config FSUTILS_PASSWD_PBKDF2_ITERATIONS
34+
int "Default PBKDF2 iteration count for new passwords"
35+
default 10000
36+
range 1000 200000
37+
---help---
38+
Number of PBKDF2-HMAC-SHA256 iterations applied when setting a new
39+
password. Higher values slow brute-force attacks but also increase
40+
login latency on low-MHz MCUs. The iteration count is stored in each
41+
hash string, so changing this option only affects newly-set passwords.
4142

4243
endif # FSUTILS_PASSWD

fsutils/passwd/Makefile

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,8 @@ include $(APPDIR)/Make.defs
2525
# Password file access library
2626

2727
ifeq ($(CONFIG_FSUTILS_PASSWD),y)
28-
CSRCS += passwd_verify.c passwd_find.c passwd_encrypt.c
28+
CSRCS += passwd_verify.c passwd_find.c passwd_encrypt.c passwd_base64.c
29+
CSRCS += passwd_pbkdf2.c
2930
ifneq ($(CONFIG_FSUTILS_PASSWD_READONLY),y)
3031
CSRCS += passwd_adduser.c passwd_deluser.c passwd_update.c passwd_append.c
3132
CSRCS += passwd_delete.c passwd_lock.c

fsutils/passwd/passwd.h

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -36,17 +36,18 @@
3636
* Pre-processor Definitions
3737
****************************************************************************/
3838

39-
#define MAX_ENCRYPTED 48 /* Maximum size of a password (encrypted, ASCII) */
40-
#define MAX_USERNAME 48 /* Maximum size of a username */
41-
#define MAX_RECORD (MAX_USERNAME + MAX_ENCRYPTED + 1)
39+
/* MCF format: $pbkdf2-sha256$<iter>$<salt>$<hash> */
4240

43-
/* The TEA incryption algorithm generates 8 bytes of encrypted data per
44-
* 8 bytes of unencrypted data. The encrypted presentation is base64 which
45-
* is 8-bits of ASCII for each 6 bits of data. That is a 3-to-4 expansion
46-
* ratio. MAX_ENCRYPTED must be a multiple of 8 bytes.
47-
*/
41+
#define PASSWD_MCF_PREFIX "$pbkdf2-sha256$"
42+
#define PASSWD_SALT_BYTES 16
43+
#define PASSWD_HASH_BYTES 32
4844

49-
#define MAX_PASSWORD (3 * MAX_ENCRYPTED / 4)
45+
/* 15 + 6 + 1 + 22 + 1 + 43 = 88 bytes for default parameters */
46+
47+
#define MAX_ENCRYPTED 96
48+
#define MAX_USERNAME 48
49+
#define MAX_RECORD (MAX_USERNAME + MAX_ENCRYPTED + 1)
50+
#define MAX_PASSWORD 256
5051

5152
/****************************************************************************
5253
* Public Types
@@ -55,7 +56,7 @@
5556
struct passwd_s
5657
{
5758
off_t offset; /* File offset (start of record) */
58-
char encrypted[MAX_ENCRYPTED + 1]; /* Encrtyped password in file */
59+
char encrypted[MAX_ENCRYPTED + 1]; /* Password hash in file */
5960
};
6061

6162
/****************************************************************************
@@ -94,10 +95,11 @@ void passwd_unlock(FAR sem_t *sem);
9495
* Name: passwd_encrypt
9596
*
9697
* Description:
97-
* Encrypt a password. Currently uses the Tiny Encryption Algorithm.
98+
* Hash a password with PBKDF2-HMAC-SHA256 and encode the result in modular
99+
* crypt format for storage in /etc/passwd.
98100
*
99101
* Input Parameters:
100-
* password -- The password string to be encrypted
102+
* password -- The password string to be hashed
101103
*
102104
* Returned Value:
103105
* Zero (OK) is returned on success; a negated errno value is returned on

fsutils/passwd/passwd_base64.c

Lines changed: 187 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,187 @@
1+
/****************************************************************************
2+
* apps/fsutils/passwd/passwd_base64.c
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*
6+
* Licensed to the Apache Software Foundation (ASF) under one or more
7+
* contributor license agreements. See the NOTICE file distributed with
8+
* this work for additional information regarding copyright ownership. The
9+
* ASF licenses this file to you under the Apache License, Version 2.0 (the
10+
* "License"); you may not use this file except in compliance with the
11+
* License. You may obtain a copy of the License at
12+
*
13+
* http://www.apache.org/licenses/LICENSE-2.0
14+
*
15+
* Unless required by applicable law or agreed to in writing, software
16+
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
17+
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
18+
* License for the specific language governing permissions and limitations
19+
* under the License.
20+
*
21+
****************************************************************************/
22+
23+
/****************************************************************************
24+
* Included Files
25+
****************************************************************************/
26+
27+
#include <nuttx/config.h>
28+
29+
#include <errno.h>
30+
#include <stdint.h>
31+
32+
#include "passwd_base64.h"
33+
34+
/****************************************************************************
35+
* Pre-processor Definitions
36+
****************************************************************************/
37+
38+
/* RFC 4648 section 5 base64url alphabet (no padding). */
39+
40+
static const char g_base64url[] =
41+
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
42+
43+
/****************************************************************************
44+
* Private Functions
45+
****************************************************************************/
46+
47+
static int passwd_base64url_val(char c)
48+
{
49+
if (c >= 'A' && c <= 'Z')
50+
{
51+
return c - 'A';
52+
}
53+
54+
if (c >= 'a' && c <= 'z')
55+
{
56+
return c - 'a' + 26;
57+
}
58+
59+
if (c >= '0' && c <= '9')
60+
{
61+
return c - '0' + 52;
62+
}
63+
64+
if (c == '-')
65+
{
66+
return 62;
67+
}
68+
69+
if (c == '_')
70+
{
71+
return 63;
72+
}
73+
74+
return -1;
75+
}
76+
77+
/****************************************************************************
78+
* Public Functions
79+
****************************************************************************/
80+
81+
/****************************************************************************
82+
* Name: passwd_base64url_encode
83+
*
84+
* Description:
85+
* Encode binary data as unpadded base64url (RFC 4648 section 5).
86+
*
87+
****************************************************************************/
88+
89+
int passwd_base64url_encode(FAR const uint8_t *in, size_t inlen,
90+
FAR char *out, size_t outlen)
91+
{
92+
uint32_t acc = 0;
93+
size_t i;
94+
size_t o = 0;
95+
int bits = 0;
96+
97+
for (i = 0; i < inlen; i++)
98+
{
99+
acc = (acc << 8) | in[i];
100+
bits += 8;
101+
102+
while (bits >= 6)
103+
{
104+
if (o + 1 >= outlen)
105+
{
106+
return -E2BIG;
107+
}
108+
109+
bits -= 6;
110+
out[o++] = g_base64url[(acc >> bits) & 0x3f];
111+
}
112+
}
113+
114+
if (bits > 0)
115+
{
116+
if (o + 1 >= outlen)
117+
{
118+
return -E2BIG;
119+
}
120+
121+
out[o++] = g_base64url[(acc << (6 - bits)) & 0x3f];
122+
}
123+
124+
if (o >= outlen)
125+
{
126+
return -E2BIG;
127+
}
128+
129+
out[o] = '\0';
130+
return OK;
131+
}
132+
133+
/****************************************************************************
134+
* Name: passwd_base64url_decode
135+
*
136+
* Description:
137+
* Decode unpadded base64url (RFC 4648 section 5).
138+
*
139+
****************************************************************************/
140+
141+
int passwd_base64url_decode(FAR const char *in,
142+
FAR uint8_t *out, size_t outmax,
143+
FAR size_t *outlen)
144+
{
145+
uint32_t acc = 0;
146+
size_t o = 0;
147+
int bits = 0;
148+
int v;
149+
150+
*outlen = 0;
151+
152+
while (*in != '\0')
153+
{
154+
if (*in == '$' || *in == ':')
155+
{
156+
break;
157+
}
158+
159+
v = passwd_base64url_val(*in++);
160+
if (v < 0)
161+
{
162+
return -EINVAL;
163+
}
164+
165+
acc = (acc << 6) | (uint32_t)v;
166+
bits += 6;
167+
168+
if (bits >= 8)
169+
{
170+
bits -= 8;
171+
if (o >= outmax)
172+
{
173+
return -E2BIG;
174+
}
175+
176+
out[o++] = (uint8_t)((acc >> bits) & 0xff);
177+
}
178+
}
179+
180+
if (bits >= 6)
181+
{
182+
return -EINVAL;
183+
}
184+
185+
*outlen = o;
186+
return OK;
187+
}

fsutils/passwd/passwd_base64.h

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
/****************************************************************************
2+
* apps/fsutils/passwd/passwd_base64.h
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*
6+
* Licensed to the Apache Software Foundation (ASF) under one or more
7+
* contributor license agreements. See the NOTICE file distributed with
8+
* this work for additional information regarding copyright ownership. The
9+
* ASF licenses this file to you under the Apache License, Version 2.0 (the
10+
* "License"); you may not use this file except in compliance with the
11+
* License. You may obtain a copy of the License at
12+
*
13+
* http://www.apache.org/licenses/LICENSE-2.0
14+
*
15+
* Unless required by applicable law or agreed to in writing, software
16+
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
17+
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
18+
* License for the specific language governing permissions and limitations
19+
* under the License.
20+
*
21+
****************************************************************************/
22+
23+
#ifndef __APPS_FSUTILS_PASSWD_PASSWD_BASE64_H
24+
#define __APPS_FSUTILS_PASSWD_PASSWD_BASE64_H
25+
26+
/****************************************************************************
27+
* Included Files
28+
****************************************************************************/
29+
30+
#include <nuttx/config.h>
31+
32+
#include <sys/types.h>
33+
#include <stdint.h>
34+
35+
/****************************************************************************
36+
* Public Function Prototypes
37+
****************************************************************************/
38+
39+
int passwd_base64url_encode(FAR const uint8_t *in, size_t inlen,
40+
FAR char *out, size_t outlen);
41+
int passwd_base64url_decode(FAR const char *in,
42+
FAR uint8_t *out, size_t outmax,
43+
FAR size_t *outlen);
44+
45+
#endif /* __APPS_FSUTILS_PASSWD_PASSWD_BASE64_H */

0 commit comments

Comments
 (0)