26
26
* it to find the directory entry again if requested. Naively, that would just
27
27
* mean using the ciphertext filenames. However, since the ciphertext filenames
28
28
* can contain illegal characters ('\0' and '/'), they must be encoded in some
29
- * way. We use base64 . But that can cause names to exceed NAME_MAX (255
29
+ * way. We use base64url . But that can cause names to exceed NAME_MAX (255
30
30
* bytes), so we also need to use a strong hash to abbreviate long names.
31
31
*
32
32
* The filesystem may also need another kind of hash, the "dirhash", to quickly
38
38
* casefolded directories use this type of dirhash. At least in these cases,
39
39
* each no-key name must include the name's dirhash too.
40
40
*
41
- * To meet all these requirements, we base64 -encode the following
41
+ * To meet all these requirements, we base64url -encode the following
42
42
* variable-length structure. It contains the dirhash, or 0's if the filesystem
43
43
* didn't provide one; up to 149 bytes of the ciphertext name; and for
44
44
* ciphertexts longer than 149 bytes, also the SHA-256 of the remaining bytes.
@@ -52,15 +52,19 @@ struct fscrypt_nokey_name {
52
52
u32 dirhash [2 ];
53
53
u8 bytes [149 ];
54
54
u8 sha256 [SHA256_DIGEST_SIZE ];
55
- }; /* 189 bytes => 252 bytes base64 -encoded, which is <= NAME_MAX (255) */
55
+ }; /* 189 bytes => 252 bytes base64url -encoded, which is <= NAME_MAX (255) */
56
56
57
57
/*
58
- * Decoded size of max-size nokey name, i.e. a name that was abbreviated using
58
+ * Decoded size of max-size no-key name, i.e. a name that was abbreviated using
59
59
* the strong hash and thus includes the 'sha256' field. This isn't simply
60
60
* sizeof(struct fscrypt_nokey_name), as the padding at the end isn't included.
61
61
*/
62
62
#define FSCRYPT_NOKEY_NAME_MAX offsetofend(struct fscrypt_nokey_name, sha256)
63
63
64
+ /* Encoded size of max-size no-key name */
65
+ #define FSCRYPT_NOKEY_NAME_MAX_ENCODED \
66
+ FSCRYPT_BASE64URL_CHARS(FSCRYPT_NOKEY_NAME_MAX)
67
+
64
68
static inline bool fscrypt_is_dot_dotdot (const struct qstr * str )
65
69
{
66
70
if (str -> len == 1 && str -> name [0 ] == '.' )
@@ -175,62 +179,82 @@ static int fname_decrypt(const struct inode *inode,
175
179
return 0 ;
176
180
}
177
181
178
- static const char lookup_table [65 ] =
179
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+, " ;
182
+ static const char base64url_table [65 ] =
183
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_ " ;
180
184
181
- #define BASE64_CHARS (nbytes ) DIV_ROUND_UP((nbytes) * 4, 3)
185
+ #define FSCRYPT_BASE64URL_CHARS (nbytes ) DIV_ROUND_UP((nbytes) * 4, 3)
182
186
183
187
/**
184
- * base64_encode () - base64 -encode some bytes
185
- * @src: the bytes to encode
186
- * @len: number of bytes to encode
187
- * @dst: (output) the base64 -encoded string. Not NUL-terminated.
188
+ * fscrypt_base64url_encode () - base64url -encode some binary data
189
+ * @src: the binary data to encode
190
+ * @srclen: the length of @src in bytes
191
+ * @dst: (output) the base64url -encoded string. Not NUL-terminated.
188
192
*
189
- * Encodes the input string using characters from the set [A-Za-z0-9+,].
190
- * The encoded string is roughly 4/3 times the size of the input string.
193
+ * Encodes data using base64url encoding, i.e. the "Base 64 Encoding with URL
194
+ * and Filename Safe Alphabet" specified by RFC 4648. '='-padding isn't used,
195
+ * as it's unneeded and not required by the RFC. base64url is used instead of
196
+ * base64 to avoid the '/' character, which isn't allowed in filenames.
191
197
*
192
- * Return: length of the encoded string
198
+ * Return: the length of the resulting base64url-encoded string in bytes.
199
+ * This will be equal to FSCRYPT_BASE64URL_CHARS(srclen).
193
200
*/
194
- static int base64_encode (const u8 * src , int len , char * dst )
201
+ static int fscrypt_base64url_encode (const u8 * src , int srclen , char * dst )
195
202
{
196
- int i , bits = 0 , ac = 0 ;
203
+ u32 ac = 0 ;
204
+ int bits = 0 ;
205
+ int i ;
197
206
char * cp = dst ;
198
207
199
- for (i = 0 ; i < len ; i ++ ) {
200
- ac += src [ i ] << bits ;
208
+ for (i = 0 ; i < srclen ; i ++ ) {
209
+ ac = ( ac << 8 ) | src [ i ] ;
201
210
bits += 8 ;
202
211
do {
203
- * cp ++ = lookup_table [ac & 0x3f ];
204
- ac >>= 6 ;
205
212
bits -= 6 ;
213
+ * cp ++ = base64url_table [(ac >> bits ) & 0x3f ];
206
214
} while (bits >= 6 );
207
215
}
208
216
if (bits )
209
- * cp ++ = lookup_table [ ac & 0x3f ];
217
+ * cp ++ = base64url_table [( ac << ( 6 - bits )) & 0x3f ];
210
218
return cp - dst ;
211
219
}
212
220
213
- static int base64_decode (const char * src , int len , u8 * dst )
221
+ /**
222
+ * fscrypt_base64url_decode() - base64url-decode a string
223
+ * @src: the string to decode. Doesn't need to be NUL-terminated.
224
+ * @srclen: the length of @src in bytes
225
+ * @dst: (output) the decoded binary data
226
+ *
227
+ * Decodes a string using base64url encoding, i.e. the "Base 64 Encoding with
228
+ * URL and Filename Safe Alphabet" specified by RFC 4648. '='-padding isn't
229
+ * accepted, nor are non-encoding characters such as whitespace.
230
+ *
231
+ * This implementation hasn't been optimized for performance.
232
+ *
233
+ * Return: the length of the resulting decoded binary data in bytes,
234
+ * or -1 if the string isn't a valid base64url string.
235
+ */
236
+ static int fscrypt_base64url_decode (const char * src , int srclen , u8 * dst )
214
237
{
215
- int i , bits = 0 , ac = 0 ;
216
- const char * p ;
217
- u8 * cp = dst ;
238
+ u32 ac = 0 ;
239
+ int bits = 0 ;
240
+ int i ;
241
+ u8 * bp = dst ;
242
+
243
+ for (i = 0 ; i < srclen ; i ++ ) {
244
+ const char * p = strchr (base64url_table , src [i ]);
218
245
219
- for (i = 0 ; i < len ; i ++ ) {
220
- p = strchr (lookup_table , src [i ]);
221
246
if (p == NULL || src [i ] == 0 )
222
- return -2 ;
223
- ac + = (p - lookup_table ) << bits ;
247
+ return -1 ;
248
+ ac = (ac << 6 ) | ( p - base64url_table ) ;
224
249
bits += 6 ;
225
250
if (bits >= 8 ) {
226
- * cp ++ = ac & 0xff ;
227
- ac >>= 8 ;
228
251
bits -= 8 ;
252
+ * bp ++ = (u8 )(ac >> bits );
229
253
}
230
254
}
231
- if (ac )
255
+ if (ac & (( 1 << bits ) - 1 ) )
232
256
return -1 ;
233
- return cp - dst ;
257
+ return bp - dst ;
234
258
}
235
259
236
260
bool fscrypt_fname_encrypted_size (const union fscrypt_policy * policy ,
@@ -263,10 +287,8 @@ bool fscrypt_fname_encrypted_size(const union fscrypt_policy *policy,
263
287
int fscrypt_fname_alloc_buffer (u32 max_encrypted_len ,
264
288
struct fscrypt_str * crypto_str )
265
289
{
266
- const u32 max_encoded_len = BASE64_CHARS (FSCRYPT_NOKEY_NAME_MAX );
267
- u32 max_presented_len ;
268
-
269
- max_presented_len = max (max_encoded_len , max_encrypted_len );
290
+ u32 max_presented_len = max_t (u32 , FSCRYPT_NOKEY_NAME_MAX_ENCODED ,
291
+ max_encrypted_len );
270
292
271
293
crypto_str -> name = kmalloc (max_presented_len + 1 , GFP_NOFS );
272
294
if (!crypto_str -> name )
@@ -342,7 +364,7 @@ int fscrypt_fname_disk_to_usr(const struct inode *inode,
342
364
offsetof(struct fscrypt_nokey_name , bytes ));
343
365
BUILD_BUG_ON (offsetofend (struct fscrypt_nokey_name , bytes ) !=
344
366
offsetof(struct fscrypt_nokey_name , sha256 ));
345
- BUILD_BUG_ON (BASE64_CHARS ( FSCRYPT_NOKEY_NAME_MAX ) > NAME_MAX );
367
+ BUILD_BUG_ON (FSCRYPT_NOKEY_NAME_MAX_ENCODED > NAME_MAX );
346
368
347
369
nokey_name .dirhash [0 ] = hash ;
348
370
nokey_name .dirhash [1 ] = minor_hash ;
@@ -358,7 +380,8 @@ int fscrypt_fname_disk_to_usr(const struct inode *inode,
358
380
nokey_name .sha256 );
359
381
size = FSCRYPT_NOKEY_NAME_MAX ;
360
382
}
361
- oname -> len = base64_encode ((const u8 * )& nokey_name , size , oname -> name );
383
+ oname -> len = fscrypt_base64url_encode ((const u8 * )& nokey_name , size ,
384
+ oname -> name );
362
385
return 0 ;
363
386
}
364
387
EXPORT_SYMBOL (fscrypt_fname_disk_to_usr );
@@ -432,14 +455,15 @@ int fscrypt_setup_filename(struct inode *dir, const struct qstr *iname,
432
455
* user-supplied name
433
456
*/
434
457
435
- if (iname -> len > BASE64_CHARS ( FSCRYPT_NOKEY_NAME_MAX ) )
458
+ if (iname -> len > FSCRYPT_NOKEY_NAME_MAX_ENCODED )
436
459
return - ENOENT ;
437
460
438
461
fname -> crypto_buf .name = kmalloc (FSCRYPT_NOKEY_NAME_MAX , GFP_KERNEL );
439
462
if (fname -> crypto_buf .name == NULL )
440
463
return - ENOMEM ;
441
464
442
- ret = base64_decode (iname -> name , iname -> len , fname -> crypto_buf .name );
465
+ ret = fscrypt_base64url_decode (iname -> name , iname -> len ,
466
+ fname -> crypto_buf .name );
443
467
if (ret < (int )offsetof(struct fscrypt_nokey_name , bytes [1 ]) ||
444
468
(ret > offsetof(struct fscrypt_nokey_name , sha256 ) &&
445
469
ret != FSCRYPT_NOKEY_NAME_MAX )) {
0 commit comments