├── .gitignore ├── Makefile ├── README ├── lib └── libpam │ └── modules │ ├── Makefile.inc │ └── pam_pefs │ ├── Makefile │ ├── Version.map │ ├── pam_pefs.8 │ └── pam_pefs.c ├── sbin └── pefs │ ├── Makefile │ ├── pefs.8 │ ├── pefs_ctl.c │ ├── pefs_ctl.h │ ├── pefs_key.c │ ├── pefs_keychain.c │ ├── pefs_keychain.h │ └── pefs_subr.c ├── sys ├── crypto │ ├── crypto_verify_bytes.c │ ├── crypto_verify_bytes.h │ ├── hmac │ │ ├── hmac_sha512.c │ │ └── hmac_sha512.h │ ├── pbkdf2 │ │ ├── pbkdf2_hmac_sha512.c │ │ └── pbkdf2_hmac_sha512.h │ ├── rijndael │ │ ├── rijndael-alg-fst.c │ │ ├── rijndael-api-fst.c │ │ ├── rijndael-api-fst.h │ │ ├── rijndael-api.c │ │ ├── rijndael.h │ │ └── rijndael_local.h │ └── sha2 │ │ ├── sha384.h │ │ ├── sha512.h │ │ └── sha512c.c ├── fs │ └── pefs │ │ ├── pefs.h │ │ ├── pefs_aesni.c │ │ ├── pefs_aesni.h │ │ ├── pefs_compat.h │ │ ├── pefs_crypto.c │ │ ├── pefs_crypto.h │ │ ├── pefs_dircache.c │ │ ├── pefs_dircache.h │ │ ├── pefs_subr.c │ │ ├── pefs_vfsops.c │ │ ├── pefs_vnops.c │ │ ├── pefs_xbase64.c │ │ ├── pefs_xts.c │ │ ├── vmac.c │ │ └── vmac.h └── modules │ └── pefs │ └── Makefile └── tests └── sbin ├── Kyuafile ├── Makefile ├── basic_test.sh └── lock_test.sh /.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | *.ko 3 | *.pico 4 | 5 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | SUBDIR= sys/modules/pefs \ 2 | sbin/pefs 3 | 4 | # Should be built from sources tree 5 | SUBDIR+= lib/libpam/modules/pam_pefs 6 | 7 | .include 8 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | PEFS (Private Encrypted File System) is a kernel level stacked cryptographic 2 | filesystem for FreeBSD. 3 | 4 | PEFS website: http://pefs.io/ 5 | 6 | The following is a list of its most important features: 7 | 8 | * Kernel level file system, no user level daemons needed. Transparently runs 9 | on top of existing file systems. 10 | 11 | * Random per file tweak value used for encryption, which guaranties different 12 | cipher texts for the same encrypted files. 13 | 14 | * Saves metadata only in encrypted file name, but not in file itself. 15 | 16 | * Supports arbitrary number of keys per file system, default directory key, 17 | mixing files encrypted with different keys in same directory. 18 | 19 | * Allows defining key chains, can be used to add/delete several keys by 20 | specifying only master key. 21 | 22 | * Uses modern cryptographic algorithms: AES and Camellia in XTS mode, 23 | PKCS#5v2 and HKDF for key generation. 24 | 25 | FreeBSD wiki page: http://wiki.freebsd.org/PEFS 26 | blog: http://glebkurtsou.blogspot.com/search/label/pefs 27 | 28 | 29 | Installation instructions: 30 | 31 | # git clone git://github.com/glk/pefs.git pefs 32 | # cd pefs 33 | # make obj all 34 | # make install 35 | # make clean 36 | -------------------------------------------------------------------------------- /lib/libpam/modules/Makefile.inc: -------------------------------------------------------------------------------- 1 | # Include Makefiles from $SRCDIR 2 | 3 | LIBDIR=${PREFIX}/lib 4 | 5 | SYSDIR?= /usr/src/sys 6 | 7 | .include <${SYSDIR}/../lib/libpam/modules/Makefile.inc> 8 | -------------------------------------------------------------------------------- /lib/libpam/modules/pam_pefs/Makefile: -------------------------------------------------------------------------------- 1 | # PAM module for pefs 2 | # $FreeBSD$ 3 | 4 | SYS= ${.CURDIR}/../../../../sys 5 | PEFSDIR= ${.CURDIR}/../../../../sbin/pefs 6 | 7 | LIB= pam_pefs 8 | MAN= pam_pefs.8 9 | SRCS= pam_pefs.c 10 | SRCS+= pefs_key.c pefs_keychain.c pefs_subr.c 11 | SRCS+= rijndael-api.c rijndael-api-fst.c rijndael-alg-fst.c 12 | SRCS+= sha512c.c 13 | SRCS+= hmac_sha512.c 14 | SRCS+= pbkdf2_hmac_sha512.c 15 | SRCS+= crypto_verify_bytes.c 16 | 17 | CFLAGS+= -I${PEFSDIR} 18 | CFLAGS+= -I${SYS} 19 | VERSION_MAP= ${.CURDIR}/Version.map 20 | WARNS?= 2 21 | 22 | DPADD= ${LIBUTIL} 23 | LDADD= -lutil 24 | 25 | .include 26 | 27 | .PATH: ${PEFSDIR} 28 | .PATH: ${SYS}/fs/pefs 29 | .PATH: ${SYS}/crypto 30 | .PATH: ${SYS}/crypto/rijndael 31 | .PATH: ${SYS}/crypto/hmac ${SYS}/crypto/pbkdf2 ${SYS}/crypto/sha2 32 | 33 | # Fix build without OBJDIR for shared components 34 | .NOPATH: ${OBJS} 35 | -------------------------------------------------------------------------------- /lib/libpam/modules/pam_pefs/Version.map: -------------------------------------------------------------------------------- 1 | { 2 | local: 3 | SHA*; 4 | _libmd_SHA*; 5 | crypto*; 6 | hmac*; 7 | pbkdf2*; 8 | pefs*; 9 | rijndael*; 10 | }; 11 | -------------------------------------------------------------------------------- /lib/libpam/modules/pam_pefs/pam_pefs.8: -------------------------------------------------------------------------------- 1 | .\" Copyright (c) 2001 Mark R V Murray 2 | .\" Copyright (c) 2001-2003 Networks Associates Technology, Inc. 3 | .\" Copyright (c) 2009 Gleb Kurtsou 4 | .\" All rights reserved. 5 | .\" 6 | .\" This software was developed for the FreeBSD Project by ThinkSec AS and 7 | .\" NAI Labs, the Security Research Division of Network Associates, Inc. 8 | .\" under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), as part of the 9 | .\" DARPA CHATS research program. 10 | .\" 11 | .\" Redistribution and use in source and binary forms, with or without 12 | .\" modification, are permitted provided that the following conditions 13 | .\" are met: 14 | .\" 1. Redistributions of source code must retain the above copyright 15 | .\" notice, this list of conditions and the following disclaimer. 16 | .\" 2. Redistributions in binary form must reproduce the above copyright 17 | .\" notice, this list of conditions and the following disclaimer in the 18 | .\" documentation and/or other materials provided with the distribution. 19 | .\" 3. The name of the author may not be used to endorse or promote 20 | .\" products derived from this software without specific prior written 21 | .\" permission. 22 | .\" 23 | .\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 24 | .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 | .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26 | .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 27 | .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 | .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29 | .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30 | .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31 | .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32 | .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33 | .\" SUCH DAMAGE. 34 | .\" 35 | .\" $FreeBSD$ 36 | .\" 37 | .Dd December 1, 2009 38 | .Dt PAM_PEFS 8 39 | .Os 40 | .Sh NAME 41 | .Nm pam_pefs 42 | .Nd pefs PAM module 43 | .Sh SYNOPSIS 44 | .Op Ar service-name 45 | .Ar module-type 46 | .Ar control-flag 47 | .Pa pam_pefs 48 | .Op Ar options 49 | .Sh DESCRIPTION 50 | The 51 | pefs 52 | authentication service module for PAM, 53 | .Nm 54 | provides functionality for two PAM categories: 55 | authentication 56 | and session management. 57 | In terms of the 58 | .Ar module-type 59 | parameter, they are the 60 | .Dq Li auth 61 | and 62 | .Dq Li session 63 | features. 64 | .Pp 65 | Module expects pefs file system to be mounted on user home directory 66 | and fails otherwise. 67 | .Ss Pefs Authentication Module 68 | The 69 | pefs 70 | authentication component 71 | provides a function to verify the identity of a user 72 | .Pq Fn pam_sm_authenticate , 73 | by prompting the user for a passphrase and verifying that it exists in 74 | pefs key chain database. 75 | .Pp 76 | The following options may be passed to the authentication module: 77 | .Bl -tag -width ".Cm use_first_pass" 78 | .It Cm use_first_pass 79 | If the authentication module 80 | is not the first in the stack, 81 | and a previous module 82 | obtained the user's password, 83 | that password is used 84 | to authenticate the user. 85 | If this fails, 86 | the authentication module returns failure 87 | without prompting the user for a password. 88 | This option has no effect 89 | if the authentication module 90 | is the first in the stack, 91 | or if no previous modules 92 | obtained the user's password. 93 | .It Cm try_first_pass 94 | This option is similar to the 95 | .Cm use_first_pass 96 | option, 97 | except that if the previously obtained password fails, 98 | the user is prompted for another password. 99 | .It Cm ignore_missing 100 | Accept any passphrase provided by the user. 101 | This option is used not to authenticate user, but to preserve keys that 102 | should be added to pefs file system by session management module. 103 | Option is incompatible with 104 | .Cm try_first_pass 105 | option and should be used with 106 | .Cm use_first_pass 107 | option. 108 | .It Cm delkeys 109 | Remove keys at the end of last session. 110 | Module tracks the number of concurrent sessions, removing all keys from 111 | file system when session count reaches zero. 112 | .El 113 | .Ss Pefs Session Management Module 114 | The 115 | pefs 116 | session management component 117 | provides functions to initiate 118 | .Pq Fn pam_sm_open_session 119 | and terminate 120 | .Pq Fn pam_sm_close_session 121 | sessions. 122 | The 123 | .Fn pam_sm_open_session 124 | function adds key or key chain decrypted during the authentication phase 125 | to the pefs file system mounted on user home directory. 126 | .Sh FILES 127 | .Bl -tag -width ".Pa $HOME/.pefs.conf" -compact 128 | .It Pa $HOME/.pefs.conf 129 | pefs configuration file 130 | .It Pa $HOME/.pefs.db 131 | pefs key chain database file 132 | .El 133 | .Sh SEE ALSO 134 | .Xr pam.conf 5 , 135 | .Xr pam 8 136 | .Xr pefs 8 137 | .Sh AUTHORS 138 | The 139 | .Nm 140 | module was written by 141 | .An -nosplit 142 | .An "Gleb Kurtsou" Aq gleb@FreeBSD.org . 143 | .Sh BUGS 144 | .Fn pam_sm_close_session 145 | function 146 | doesn't delete keys added during by 147 | .Fn pam_sm_open_session . 148 | -------------------------------------------------------------------------------- /lib/libpam/modules/pam_pefs/pam_pefs.c: -------------------------------------------------------------------------------- 1 | /*- 2 | * Copyright (c) 2003 Networks Associates Technology, Inc. 3 | * Copyright (c) 2009 Gleb Kurtsou 4 | * All rights reserved. 5 | * 6 | * This software was developed for the FreeBSD Project by ThinkSec AS and 7 | * NAI Labs, the Security Research Division of Network Associates, Inc. 8 | * under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), as part of the 9 | * DARPA CHATS research program. 10 | * 11 | * Redistribution and use in source and binary forms, with or without 12 | * modification, are permitted provided that the following conditions 13 | * are met: 14 | * 1. Redistributions of source code must retain the above copyright 15 | * notice, this list of conditions and the following disclaimer. 16 | * 2. Redistributions in binary form must reproduce the above copyright 17 | * notice, this list of conditions and the following disclaimer in the 18 | * documentation and/or other materials provided with the distribution. 19 | * 3. The name of the author may not be used to endorse or promote 20 | * products derived from this software without specific prior written 21 | * permission. 22 | * 23 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 24 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 27 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33 | * SUCH DAMAGE. 34 | */ 35 | 36 | #include 37 | __FBSDID("$FreeBSD$"); 38 | 39 | #include 40 | #include 41 | #include 42 | #include 43 | 44 | #include 45 | #include 46 | #include 47 | #include 48 | #include 49 | #include 50 | #include 51 | #include 52 | #include 53 | #include 54 | #include 55 | #include 56 | #include 57 | #include 58 | 59 | #define PAM_SM_AUTH 60 | #define PAM_SM_SESSION 61 | 62 | #include 63 | #include 64 | #include 65 | #include 66 | 67 | #include 68 | 69 | #include "pefs_ctl.h" 70 | #include "pefs_keychain.h" 71 | 72 | #define PEFS_OPT_IGNORE_MISSING "ignore_missing" 73 | #define PEFS_OPT_DELKEYS "delkeys" 74 | 75 | #define PAM_PEFS_KEYS "pam_pefs_keys" 76 | #define PAM_PEFS_SESSION "pam_pefs_session" 77 | 78 | #define PEFS_SESSION_SIZE 16 79 | #define PEFS_SESSION_DIR "/var/run/pefs" 80 | #define PEFS_SESSION_DIR_MODE 0700 81 | #define PEFS_SESSION_FILE_MODE 0600 82 | #define PEFS_SESSION_FILE_FLAGS \ 83 | (O_RDWR | O_NONBLOCK | O_CREAT | O_EXLOCK) 84 | 85 | static int pam_pefs_debug; 86 | 87 | void 88 | pefs_warn(const char *fmt, ...) 89 | { 90 | static const char *label = "pam_pefs: "; 91 | char buf[BUFSIZ]; 92 | va_list ap; 93 | 94 | if (pam_pefs_debug == 0) 95 | return; 96 | 97 | va_start(ap, fmt); 98 | if (strlen(fmt) + sizeof(label) >= sizeof(buf)) { 99 | vsyslog(LOG_DEBUG, fmt, ap); 100 | } else { 101 | strlcpy(buf, label, sizeof(buf)); 102 | strlcat(buf, fmt, sizeof(buf)); 103 | vsyslog(LOG_DEBUG, buf, ap); 104 | } 105 | va_end(ap); 106 | } 107 | 108 | static int 109 | flopen_retry(const char *filename) 110 | { 111 | int fd, try; 112 | 113 | for (try = 1; try <= 1024; try *= 2) { 114 | fd = flopen(filename, PEFS_SESSION_FILE_FLAGS, 115 | PEFS_SESSION_FILE_MODE); 116 | if (fd != -1) 117 | return (fd); 118 | else if (errno != EWOULDBLOCK) 119 | return (-1); 120 | // Exponential back-off up to 1 second 121 | usleep(try * 1000000 / 1024); 122 | } 123 | errno = ETIMEDOUT; 124 | return (-1); 125 | } 126 | 127 | static bool 128 | session_ctr_empty(const uint8_t *sc) 129 | { 130 | const uint8_t *end; 131 | uint8_t acc; 132 | 133 | for (end = sc + PEFS_SESSION_SIZE, acc = 0; sc < end; sc++) 134 | acc |= *sc; 135 | return (acc == 0); 136 | } 137 | 138 | static void 139 | session_ctr_xor(uint8_t *sc, const uint8_t *si) 140 | { 141 | int i; 142 | 143 | for (i = 0; i < PEFS_SESSION_SIZE; sc++, si++, i++) 144 | *sc ^= *si; 145 | } 146 | 147 | static int 148 | session_ctr_update(const char *user, const char *sess_id, bool incr) 149 | { 150 | struct stat sb; 151 | struct timespec tp_uptime, tp_now; 152 | ssize_t sess_size; 153 | int fd; 154 | char filename[MAXPATHLEN]; 155 | uint8_t sess_ctr[PEFS_SESSION_SIZE]; 156 | 157 | if (session_ctr_empty(sess_id)) 158 | return (-1); 159 | 160 | snprintf(filename, sizeof(filename), "%s/%s", PEFS_SESSION_DIR, user); 161 | 162 | if (lstat(PEFS_SESSION_DIR, &sb) == -1) { 163 | if (errno != ENOENT) { 164 | pefs_warn("unable to access session directory %s: %s", 165 | PEFS_SESSION_DIR, strerror(errno)); 166 | return (-1); 167 | } 168 | if (mkdir(PEFS_SESSION_DIR, PEFS_SESSION_DIR_MODE) == -1) { 169 | pefs_warn("unable to create session directory %s: %s", 170 | PEFS_SESSION_DIR, strerror(errno)); 171 | return (-1); 172 | } 173 | } else if (!S_ISDIR(sb.st_mode)) { 174 | pefs_warn("%s is not a directory", PEFS_SESSION_DIR); 175 | return (-1); 176 | } 177 | 178 | if ((fd = flopen_retry(filename)) == -1) { 179 | pefs_warn("unable to create session counter file %s: %s", 180 | filename, strerror(errno)); 181 | return (-1); 182 | } 183 | 184 | if ((sess_size = pread(fd, sess_ctr, PEFS_SESSION_SIZE, 0)) == -1) { 185 | pefs_warn("unable to read from the session counter file %s: %s", 186 | filename, strerror(errno)); 187 | close(fd); 188 | return (-1); 189 | } 190 | lseek(fd, 0L, SEEK_SET); 191 | if (sess_size != PEFS_SESSION_SIZE) { 192 | if (sess_size != 0) { 193 | pefs_warn("invalid session counter file size: %s: %zd", 194 | filename, sess_size); 195 | } 196 | memset(sess_ctr, 0, PEFS_SESSION_SIZE); 197 | ftruncate(fd, PEFS_SESSION_SIZE); 198 | } 199 | 200 | /* 201 | * Determine if this is the first increment of the session file. 202 | * 203 | * It is considered the first increment if the session file has not 204 | * been modified since the last boot time. 205 | */ 206 | if (incr && !session_ctr_empty(sess_ctr)) { 207 | if (fstat(fd, &sb) == -1) { 208 | pefs_warn("unable to access session counter file %s: %s", 209 | filename, strerror(errno)); 210 | close(fd); 211 | return (-1); 212 | } 213 | /* 214 | * Check is messy and will fail if wall clock isn't monotonical 215 | * (e.g. because of ntp, DST, leap seconds) 216 | */ 217 | clock_gettime(CLOCK_REALTIME_FAST, &tp_now); 218 | clock_gettime(CLOCK_UPTIME_FAST, &tp_uptime); 219 | if (sb.st_mtime < tp_now.tv_sec - tp_uptime.tv_sec) { 220 | pefs_warn("stale session counter file: %s", 221 | filename); 222 | memset(sess_ctr, 0, PEFS_SESSION_SIZE); 223 | } 224 | } 225 | 226 | session_ctr_xor(sess_ctr, sess_id); 227 | if (incr && session_ctr_empty(sess_ctr)) { 228 | pefs_warn("corrupted session counter file after increment: %s", 229 | filename); 230 | close(fd); 231 | return (-1); 232 | } 233 | pwrite(fd, sess_ctr, PEFS_SESSION_SIZE, 0); 234 | close(fd); 235 | 236 | return (session_ctr_empty(sess_ctr) ? 0 : 1); 237 | } 238 | 239 | static int 240 | session_ctr_incr(pam_handle_t *pamh, const char *user) 241 | { 242 | uint8_t *id; 243 | int r; 244 | 245 | id = malloc(PEFS_SESSION_SIZE); 246 | if (id == NULL) 247 | return (-1); 248 | arc4random_buf(id, PEFS_SESSION_SIZE); 249 | if (session_ctr_empty(id)) 250 | arc4random_buf(id, PEFS_SESSION_SIZE); 251 | r = pam_set_data(pamh, PAM_PEFS_SESSION, id, openpam_free_data); 252 | if (r != PAM_SUCCESS) { 253 | free(id); 254 | return (-1); 255 | } 256 | r = session_ctr_update(user, id, true); 257 | if (r == -1) { 258 | /* Make consequent session_ctr_decr no-op. */ 259 | memset(id, 0, PEFS_SESSION_SIZE); 260 | } 261 | return (r); 262 | } 263 | 264 | static int 265 | session_ctr_decr(pam_handle_t *pamh, const char *user) 266 | { 267 | const uint8_t *id; 268 | int r; 269 | 270 | r = pam_get_data(pamh, PAM_PEFS_SESSION, (const void **)(void *)&id); 271 | if (r != PAM_SUCCESS) 272 | return (-1); 273 | r = session_ctr_update(user, id, false); 274 | pam_set_data(pamh, PAM_PEFS_SESSION, NULL, NULL); 275 | return (r); 276 | } 277 | 278 | static int 279 | pam_pefs_checkfs(const char *homedir) 280 | { 281 | char fsroot[MAXPATHLEN]; 282 | int error; 283 | 284 | error = pefs_getfsroot(homedir, 0, fsroot, sizeof(fsroot)); 285 | if (error != 0) { 286 | pefs_warn("file system is not mounted: %s", homedir); 287 | return (PAM_USER_UNKNOWN); 288 | } if (strcmp(fsroot, homedir) != 0) { 289 | pefs_warn("file system is not mounted on home dir: %s", fsroot); 290 | return (PAM_USER_UNKNOWN); 291 | } 292 | 293 | return (PAM_SUCCESS); 294 | } 295 | 296 | /* 297 | * Perform key lookup in ~/.pefs; 298 | * returns PAM_AUTH_ERR if and only if key wasn't found in database. 299 | */ 300 | static int 301 | pam_pefs_getkeys(struct pefs_keychain_head *kch, 302 | const char *homedir, const char *passphrase, int chainflags) 303 | { 304 | struct pefs_xkey k; 305 | struct pefs_keyparam kp; 306 | int error; 307 | 308 | pefs_keyparam_create(&kp); 309 | pefs_keyparam_init(&kp, homedir); 310 | 311 | error = pefs_key_generate(&k, passphrase, &kp); 312 | if (error != 0) 313 | return (PAM_SERVICE_ERR); 314 | 315 | error = pefs_keychain_get(kch, homedir, chainflags, &k); 316 | bzero(&k, sizeof(k)); 317 | if (error != 0) 318 | return (error == PEFS_ERR_NOENT ? PAM_AUTH_ERR : 319 | PAM_SERVICE_ERR); 320 | 321 | return (PAM_SUCCESS); 322 | } 323 | 324 | static int 325 | pam_pefs_addkeys(const char *homedir, struct pefs_keychain_head *kch) 326 | { 327 | struct pefs_keychain *kc; 328 | int fd; 329 | 330 | fd = open(homedir, O_RDONLY); 331 | if (fd == -1) { 332 | pefs_warn("cannot open homedir %s: %s", 333 | homedir, strerror(errno)); 334 | return (PAM_USER_UNKNOWN); 335 | } 336 | 337 | TAILQ_FOREACH(kc, kch, kc_entry) { 338 | if (ioctl(fd, PEFS_ADDKEY, &kc->kc_key) == -1) { 339 | pefs_warn("cannot add key: %s: %s", 340 | homedir, strerror(errno)); 341 | break; 342 | } 343 | } 344 | close(fd); 345 | 346 | return (PAM_SUCCESS); 347 | } 348 | 349 | static int 350 | pam_pefs_delkeys(const char *homedir) 351 | { 352 | struct pefs_xkey k; 353 | int fd; 354 | 355 | fd = open(homedir, O_RDONLY); 356 | if (fd == -1) { 357 | pefs_warn("cannot open homedir %s: %s", 358 | homedir, strerror(errno)); 359 | return (PAM_USER_UNKNOWN); 360 | } 361 | 362 | bzero(&k, sizeof(k)); 363 | while (1) { 364 | if (ioctl(fd, PEFS_GETKEY, &k) == -1) 365 | break; 366 | 367 | if (ioctl(fd, PEFS_DELKEY, &k) == -1) { 368 | pefs_warn("cannot del key: %s: %s", 369 | homedir, strerror(errno)); 370 | k.pxk_index++; 371 | } 372 | } 373 | close(fd); 374 | 375 | return (PAM_SUCCESS); 376 | } 377 | 378 | static void 379 | pam_pefs_freekeys(pam_handle_t *pamh __unused, void *data, int pam_err __unused) 380 | { 381 | struct pefs_keychain_head *kch = data; 382 | 383 | pefs_keychain_free(kch); 384 | free(kch); 385 | } 386 | 387 | PAM_EXTERN int 388 | pam_sm_authenticate(pam_handle_t *pamh, int flags __unused, 389 | int argc __unused, const char *argv[] __unused) 390 | { 391 | struct pefs_keychain_head *kch; 392 | struct passwd *pwd; 393 | const char *passphrase, *user; 394 | const void *item; 395 | int pam_err, canretry, chainflags; 396 | 397 | /* Get user name and home directory */ 398 | pam_err = pam_get_user(pamh, &user, NULL); 399 | if (pam_err != PAM_SUCCESS) 400 | return (pam_err); 401 | pwd = getpwnam(user); 402 | if (pwd == NULL) 403 | return (PAM_USER_UNKNOWN); 404 | if (pwd->pw_dir == NULL) 405 | return (PAM_AUTH_ERR); 406 | 407 | pam_pefs_debug = (openpam_get_option(pamh, PAM_OPT_DEBUG) != NULL); 408 | 409 | chainflags = PEFS_KEYCHAIN_USE; 410 | if (openpam_get_option(pamh, PEFS_OPT_IGNORE_MISSING) != NULL) 411 | chainflags = PEFS_KEYCHAIN_IGNORE_MISSING; 412 | 413 | canretry = (pam_get_item(pamh, PAM_AUTHTOK, &item) == PAM_SUCCESS && 414 | item != NULL && chainflags != PEFS_KEYCHAIN_IGNORE_MISSING); 415 | 416 | pam_err = openpam_borrow_cred(pamh, pwd); 417 | if (pam_err != PAM_SUCCESS) 418 | return (pam_err); 419 | 420 | /* 421 | * Check to see if the passwd db is available, avoids asking for 422 | * password if we cannot even validate it. 423 | */ 424 | pam_err = pam_pefs_checkfs(pwd->pw_dir); 425 | openpam_restore_cred(pamh); 426 | if (pam_err != PAM_SUCCESS) 427 | return (pam_err); 428 | 429 | 430 | retry: 431 | /* Get passphrase */ 432 | pam_err = pam_get_authtok(pamh, PAM_AUTHTOK, 433 | &passphrase, NULL); 434 | if (pam_err != PAM_SUCCESS) 435 | return (pam_err); 436 | 437 | if (*passphrase != '\0') { 438 | kch = calloc(1, sizeof(*kch)); 439 | if (kch == NULL) 440 | return (PAM_SYSTEM_ERR); 441 | 442 | /* Switch to user credentials */ 443 | pam_err = openpam_borrow_cred(pamh, pwd); 444 | if (pam_err != PAM_SUCCESS) 445 | return (pam_err); 446 | 447 | pam_err = pam_pefs_getkeys(kch, pwd->pw_dir, passphrase, 448 | chainflags); 449 | if (pam_err == PAM_SUCCESS) 450 | pam_set_data(pamh, PAM_PEFS_KEYS, kch, 451 | pam_pefs_freekeys); 452 | else 453 | free(kch); 454 | 455 | /* Switch back to arbitrator credentials */ 456 | openpam_restore_cred(pamh); 457 | } else 458 | pam_err = PAM_AUTH_ERR; 459 | 460 | /* 461 | * If we tried an old token and didn't get anything, and 462 | * try_first_pass was specified, try again after prompting the 463 | * user for a new passphrase. 464 | */ 465 | if (pam_err == PAM_AUTH_ERR && canretry != 0 && 466 | openpam_get_option(pamh, "try_first_pass") != NULL) { 467 | pam_set_item(pamh, PAM_AUTHTOK, NULL); 468 | canretry = 0; 469 | goto retry; 470 | } 471 | 472 | return (pam_err); 473 | } 474 | 475 | PAM_EXTERN int 476 | pam_sm_setcred(pam_handle_t *pamh __unused, int flags __unused, 477 | int argc __unused, const char *argv[] __unused) 478 | { 479 | 480 | return (PAM_SUCCESS); 481 | } 482 | 483 | PAM_EXTERN int 484 | pam_sm_open_session(pam_handle_t *pamh, int flags __unused, 485 | int argc __unused, const char *argv[] __unused) 486 | { 487 | struct pefs_keychain_head *kch = NULL; 488 | struct passwd *pwd; 489 | const char *user; 490 | int pam_err, opt_delkeys; 491 | 492 | pam_err = pam_get_user(pamh, &user, NULL); 493 | if (pam_err != PAM_SUCCESS) 494 | return (pam_err); 495 | pwd = getpwnam(user); 496 | if (pwd == NULL) 497 | return (PAM_USER_UNKNOWN); 498 | if (pwd->pw_dir == NULL) 499 | return (PAM_SYSTEM_ERR); 500 | 501 | pam_pefs_debug = (openpam_get_option(pamh, PAM_OPT_DEBUG) != NULL); 502 | opt_delkeys = (openpam_get_option(pamh, PEFS_OPT_DELKEYS) != NULL); 503 | 504 | pam_err = pam_get_data(pamh, PAM_PEFS_KEYS, 505 | (const void **)(void *)&kch); 506 | if (pam_err != PAM_SUCCESS || kch == NULL || TAILQ_EMPTY(kch)) { 507 | pam_err = PAM_SUCCESS; 508 | opt_delkeys = 0; 509 | goto out; 510 | } 511 | 512 | /* Switch to user credentials */ 513 | pam_err = openpam_borrow_cred(pamh, pwd); 514 | if (pam_err != PAM_SUCCESS) 515 | goto out; 516 | 517 | pam_err = pam_pefs_checkfs(pwd->pw_dir); 518 | if (pam_err != PAM_SUCCESS) { 519 | openpam_restore_cred(pamh); 520 | pam_err = PAM_SUCCESS; 521 | opt_delkeys = 0; 522 | goto out; 523 | } 524 | 525 | pam_err = pam_pefs_addkeys(pwd->pw_dir, kch); 526 | 527 | /* Switch back to arbitrator credentials */ 528 | openpam_restore_cred(pamh); 529 | 530 | out: 531 | /* Remove keys from memory */ 532 | pam_set_data(pamh, PAM_PEFS_KEYS, NULL, NULL); 533 | 534 | /* Increment login count */ 535 | if (pam_err == PAM_SUCCESS && opt_delkeys) { 536 | session_ctr_incr(pamh, user); 537 | } 538 | 539 | return (pam_err); 540 | } 541 | 542 | PAM_EXTERN int 543 | pam_sm_close_session(pam_handle_t *pamh, int flags __unused, 544 | int argc __unused, const char *argv[] __unused) 545 | { 546 | struct passwd *pwd; 547 | const char *user; 548 | int pam_err, opt_delkeys; 549 | 550 | pam_err = pam_get_user(pamh, &user, NULL); 551 | if (pam_err != PAM_SUCCESS) 552 | return (pam_err); 553 | 554 | pwd = getpwnam(user); 555 | if (pwd == NULL) 556 | return (PAM_USER_UNKNOWN); 557 | if (pwd->pw_dir == NULL) 558 | return (PAM_SYSTEM_ERR); 559 | 560 | pam_pefs_debug = (openpam_get_option(pamh, PAM_OPT_DEBUG) != NULL); 561 | opt_delkeys = (openpam_get_option(pamh, PEFS_OPT_DELKEYS) != NULL); 562 | if (!opt_delkeys) 563 | return PAM_SUCCESS; 564 | 565 | pam_err = openpam_borrow_cred(pamh, pwd); 566 | if (pam_err != PAM_SUCCESS) 567 | return (pam_err); 568 | pam_err = pam_pefs_checkfs(pwd->pw_dir); 569 | openpam_restore_cred(pamh); 570 | if (pam_err != PAM_SUCCESS) 571 | return (PAM_SUCCESS); 572 | 573 | /* Decrease login count and remove keys if at zero */ 574 | pam_err = PAM_SUCCESS; 575 | if (session_ctr_decr(pamh, user) == 0) { 576 | pam_err = openpam_borrow_cred(pamh, pwd); 577 | if (pam_err != PAM_SUCCESS) 578 | return (pam_err); 579 | pam_err = pam_pefs_delkeys(pwd->pw_dir); 580 | openpam_restore_cred(pamh); 581 | } 582 | 583 | return (pam_err); 584 | } 585 | 586 | PAM_MODULE_ENTRY("pam_pefs"); 587 | -------------------------------------------------------------------------------- /sbin/pefs/Makefile: -------------------------------------------------------------------------------- 1 | # $FreeBSD$ 2 | 3 | SYS= ${.CURDIR}/../../sys 4 | .PATH: ${SYS}/fs/pefs 5 | .PATH: ${SYS}/crypto 6 | .PATH: ${SYS}/crypto/rijndael 7 | .PATH: ${SYS}/crypto/hmac ${SYS}/crypto/pbkdf2 ${SYS}/crypto/sha2 8 | 9 | PROG= pefs 10 | SRCS= pefs_ctl.c pefs_key.c pefs_keychain.c pefs_subr.c 11 | SRCS+= rijndael-api.c rijndael-api-fst.c rijndael-alg-fst.c 12 | SRCS+= sha512c.c 13 | SRCS+= hmac_sha512.c 14 | SRCS+= pbkdf2_hmac_sha512.c 15 | SRCS+= crypto_verify_bytes.c 16 | 17 | MAN= pefs.8 18 | 19 | CFLAGS+=-I${SYS} 20 | WARNS?= 2 21 | 22 | DPADD= ${LIBUTIL} 23 | LDADD= -lutil 24 | 25 | BINDIR?= /sbin 26 | .include 27 | -------------------------------------------------------------------------------- /sbin/pefs/pefs.8: -------------------------------------------------------------------------------- 1 | .\" Copyright (c) 2005-2008 Pawel Jakub Dawidek 2 | .\" Copyright (c) 2009 Gleb Kurtsou 3 | .\" All rights reserved. 4 | .\" 5 | .\" Redistribution and use in source and binary forms, with or without 6 | .\" modification, are permitted provided that the following conditions 7 | .\" are met: 8 | .\" 1. Redistributions of source code must retain the above copyright 9 | .\" notice, this list of conditions and the following disclaimer. 10 | .\" 2. Redistributions in binary form must reproduce the above copyright 11 | .\" notice, this list of conditions and the following disclaimer in the 12 | .\" documentation and/or other materials provided with the distribution. 13 | .\" 14 | .\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND 15 | .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 | .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 | .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE 18 | .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 | .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 | .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 | .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 | .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 | .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 | .\" SUCH DAMAGE. 25 | .\" 26 | .\" $FreeBSD$ 27 | .\" 28 | .Dd December 1, 2009 29 | .Dt PEFS 8 30 | .Os 31 | .Sh NAME 32 | .Nm pefs 33 | .Nd configure pefs file systems 34 | .Sh SYNOPSIS 35 | .Nm 36 | .Cm mount 37 | .Op Fl o Ar options 38 | .Op Ar from filesystem 39 | .Nm 40 | .Cm unmount 41 | .Op Fl fv 42 | .Ar filesystem 43 | .Pp 44 | .Nm 45 | .Cm addkey 46 | .Op Fl cCpv 47 | .Op Fl a Ar alg 48 | .Op Fl i Ar iterations 49 | .Op Fl j Ar passfile 50 | .Op Fl k Ar keyfile 51 | .Ar filesystem 52 | .Nm 53 | .Cm delkey 54 | .Op Fl cCpv 55 | .Op Fl i Ar iterations 56 | .Op Fl j Ar passfile 57 | .Op Fl k Ar keyfile 58 | .Ar filesystem 59 | .Nm 60 | .Cm flushkeys 61 | .Ar filesystem 62 | .Nm 63 | .Cm getkey 64 | .Op Fl t 65 | .Ar file 66 | .Nm 67 | .Cm setkey 68 | .Op Fl cCpvx 69 | .Op Fl a Ar alg 70 | .Op Fl i Ar iterations 71 | .Op Fl j Ar passfile 72 | .Op Fl k Ar keyfile 73 | .Ar directory 74 | .Nm 75 | .Cm showkeys 76 | .Op Fl t 77 | .Ar filesystem 78 | .Pp 79 | .Nm 80 | .Cm addchain 81 | .Op Fl fpPvZ 82 | .Op Fl a Ar alg 83 | .Op Fl i Ar iterations 84 | .Op Fl j Ar passfile 85 | .Op Fl k Ar keyfile 86 | .Op Fl A Ar alg 87 | .Op Fl I Ar iterations 88 | .Op Fl J Ar passfile 89 | .Op Fl K Ar keyfile 90 | .Ar filesystem 91 | .Nm 92 | .Cm delchain 93 | .Op Fl fFpv 94 | .Op Fl i Ar iterations 95 | .Op Fl j Ar passfile 96 | .Op Fl k Ar keyfile 97 | .Ar filesystem 98 | .Nm 99 | .Cm randomchain 100 | .Op Fl fv 101 | .Op Fl i Ar iterations 102 | .Op Fl j Ar passfile 103 | .Op Fl k Ar keyfile 104 | .Ar filesystem 105 | .Nm 106 | .Cm showchains 107 | .Op Fl fp 108 | .Op Fl i Ar iterations 109 | .Op Fl j Ar passfile 110 | .Op Fl k Ar keyfile 111 | .Ar filesystem 112 | .Pp 113 | .Nm 114 | .Cm showalgs 115 | .Sh DESCRIPTION 116 | The 117 | .Nm 118 | utility is the user interface for configuring stacked cryptographic file system. 119 | .Pp 120 | The following is a list of the most important file system features: 121 | .Bl -bullet -offset indent -compact 122 | .It 123 | Kernel level file system, no user level daemons needed. 124 | Transparently runs on top of existing file systems. 125 | .It 126 | Random per file tweak value used for encryption, which guaranties different 127 | cipher texts for the same encrypted files. 128 | .It 129 | Saves metadata only in encrypted file name, but not in file itself. 130 | .It 131 | Supports arbitrary number of keys per file system, default directory key, 132 | mixing files encrypted with different keys in same directory. 133 | .It 134 | Allows defining key chains, can be used to add/delete several keys by 135 | specifying only master key. 136 | .It 137 | Uses modern cryptographic algorithms: AES and Camellia in XTS mode, 138 | PKCS#5v2 and HKDF for key generation. 139 | .El 140 | .Pp 141 | First argument of 142 | .Nm 143 | utility indicates the command to be performed (see the 144 | .Sx COMMAND OPTIONS 145 | section for information on options): 146 | .Bl -tag -width indent 147 | .It Cm mount 148 | Mount file system. 149 | Encryption keys should be specified separately after mounting the file system. 150 | If no argument specified prints all mounted 151 | .Nm 152 | file systems. 153 | See 154 | .Xr mount 8 155 | for more information. 156 | .It Cm unmount Ar filesystem 157 | Unmount 158 | .Ar filesystem . 159 | .Fl f 160 | and 161 | .Fl v 162 | options can be specified to force unmount or enable verbose mode respectively. 163 | See 164 | .Xr umount 8 165 | for more information. 166 | .It Cm addkey Ar filesystem 167 | Add key to the 168 | .Ar filesystem 169 | .It Cm delkey Ar filesystem 170 | Delete key from 171 | .Ar filesystem . 172 | Command doesn't accept 173 | .Fl a Ar alg 174 | argument because the key fingerprint generated from the key doesn't depend on 175 | encryption algorithm. 176 | .It Cm getkey Ar file 177 | Print fingerprint of the key used by 178 | .Ar file . 179 | .It Cm flushkeys Ar filesystem 180 | Delete all keys from 181 | .Ar filesystem . 182 | After the command all opened files would become unavailable. 183 | .It Cm setkey Ar directory 184 | Change default key for the 185 | .Ar directory . 186 | Default key is used as a new key for files and directories created in the 187 | .Ar directory . 188 | Technically just a rename takes place on underlaying file system. 189 | Keys for entries in the 190 | .Ar directory 191 | are not changed and no data is re-encrypted with new key. 192 | .Fl x 193 | option can be used to add a new key to file system if it isn't found. 194 | .It Cm showkeys Ar filesystem 195 | Print fingerprints if all active keys. 196 | .It Cm addchain Ar filesystem 197 | Add a new key chain element. 198 | Element consists of parent and child keys. 199 | Parent key is defined by 200 | .Fl a , Fl i 201 | and 202 | .Fl p 203 | options and child key by equivalent 204 | .Fl A , Fl I 205 | and 206 | .Fl P 207 | options. 208 | Element consisting only of a parent key can be constructed by specifying 209 | .Fl Z 210 | option. 211 | .Fl f 212 | option disables file system type checks making manipulation on key chains 213 | possible without mounting 214 | .Nm 215 | file system. 216 | See 217 | .Sx KEY CHAINS 218 | section for more information. 219 | .It Cm delchain Ar filesystem 220 | Delete key chain element defined by parent key. 221 | Use 222 | .Fl F 223 | option to delete all elements from the chain. 224 | .It Cm randomchain Ar filesystem 225 | The command is deprecated and will not be available in future versions. 226 | Create random key chain elements. 227 | Minimum and maximum number of elements is controlled by 228 | .Fl n Ar min 229 | and 230 | .Fl N Ar max 231 | options. 232 | The command can be used to add false elements into key chain database, which 233 | may complicate analysis of key usage patterns by attacker. 234 | .It Cm showchains Ar filesystem 235 | Print all elements of the key chain staring with given parent key. 236 | .It Cm showalgs 237 | Print list of all supported algorithms. 238 | .El 239 | .Pp 240 | .Ss COMMAND OPTIONS 241 | The following options are available when invoking 242 | .Nm : 243 | .Bl -tag -width indent 244 | .It Fl a Ar alg 245 | Encryption algorithm to use. 246 | Use 247 | .Cm showalgs 248 | command to get list of supported algorithms. 249 | The default algorithm is AES-128. 250 | .It Fl A Ar alg 251 | Specifies algorithm for the secondary/child key. 252 | .It Fl c 253 | Forces key chain lookup. 254 | Error returned if chain is not found for the key. 255 | By default lookup errors are silently ignored. 256 | .It Fl C 257 | Disables key chain lookup. 258 | By default if chain is found, keys it consists of are also used for operation. 259 | .It Fl i Ar iterations 260 | Number of 261 | .Ar iterations 262 | to use with PKCS#5v2. 263 | If this option is not specified default value of 50000 is used. 264 | .It Fl I Ar iterations 265 | Specifies number of 266 | .Ar iterations 267 | for the secondary/child key. 268 | .It Fl j Ar passfile 269 | Specifies a file which contains the passphrase. 270 | If 271 | .Ar passfile 272 | is given as -, standard input will be used. 273 | Only the first line (excluding new-line character) is taken from the given 274 | file. 275 | This argument can be specified multiple times, which has the effect of 276 | reassembling a single passphrase split across multiple files. 277 | Cannot be combined with the 278 | .Fl p 279 | option. 280 | .It Fl J Ar passfile 281 | Specifies a file which contains the passphrase for secondary/child key. 282 | Cannot be combined with 283 | .Fl P 284 | option. 285 | .It Fl f 286 | Forces operation. 287 | Use to force 288 | .Cm unmount 289 | or to disable file system type check for key chain commands. 290 | .It Fl F 291 | Used with 292 | .Cm delchain 293 | command to delete all elements from a key chain. 294 | .It Fl k Ar keyfile 295 | Specifies a file which contains part of the key. 296 | If 297 | .Ar keyfile 298 | is given as -, standard input will be used. 299 | .It Fl K Ar keyfile 300 | Specifies a file which contains part of the secondary/child key. 301 | .It Fl o Ar options 302 | Mount options passed to 303 | .Xr mount 8 304 | utility. 305 | .It Fl p 306 | Do not ask for passphrase. 307 | .It Fl P 308 | Do not ask for passphrase for secondary/child key. 309 | .It Fl t 310 | Test-only mode. 311 | Do not perform actual operation but check if it can be performed. 312 | Usable for scripting. 313 | .It Fl v 314 | Verbose mode. 315 | .It Fl x 316 | Used with 317 | .Cm setkey 318 | command. 319 | Forces adding of the key if it is not specified for the file system. 320 | .It Fl Z 321 | Create chain with zero child key. 322 | Can be useful for 323 | .Cm addkey Fl c 324 | command to verify the key before adding it. 325 | .El 326 | .Pp 327 | .Ss KEY CHAINS 328 | Key chain consists of one or several elements. 329 | Each element is defined by a 330 | .Em parent key 331 | and a 332 | .Em child key . 333 | All elements are stored encrypted in a database file. 334 | .Pp 335 | Parent key fingerprint is used as an index to access child key in database. 336 | Chaining is achieved by reusing child key fingerprint as next index. 337 | .Pp 338 | .Ss CONFIGURATION FILE 339 | In addition to command line options some options can be specified in per file 340 | system configuration file: 341 | .Em /.pefs.conf . 342 | .Em .pefs.conf 343 | is not a regular file, but a symbolic link. 344 | .Dq Li Name 345 | of the file referenced by the link consists of a list of options separated by 346 | colon. 347 | Supported option list is the following: 348 | .Bd -literal -offset indent 349 | .Em algorithm:iterations 350 | .Ed 351 | .Pp 352 | Note that key chain database entries already contain algorithm used, and 353 | expected use of the configuration file is to specify 354 | .Em iterations 355 | option for 356 | .Xr pam_pefs 8 357 | or default 358 | .Em algorithm , 359 | if one adds/removes keys often without using key chain database. 360 | .Pp 361 | .Sh SYSCTL VARIABLES 362 | The following 363 | .Xr sysctl 8 364 | variables can be used to control the behavior of 365 | .Nm 366 | file systems or monitor 367 | them. 368 | .Bl -tag -width indent 369 | .It Va vfs.pefs.nodes 370 | Number of active nodes. 371 | Unlike 372 | .Xr nullfs 8 373 | .Nm 374 | doesn't recycle vnodes as early as possible, but expects kernel to recycle 375 | vnodes when necessary. 376 | .It Va vfs.pefs.dircache.enable 377 | Enable directory content caching. 378 | Content caching can only be enabled for file systems that are known to properly 379 | propagate changes to upper levels, and it's permanently disabled for the rest. 380 | When disabled directory cache subsystem is still used as a file name decryption 381 | cache for all underlying file systems. 382 | .It Va vfs.pefs.dircache.entries 383 | Number of entries in directory cache. 384 | Directory cache is mainly used as a file name decryption cache, but can also be 385 | used to cache directory content if underlying file system is known to propagate 386 | changes to upper levels properly. 387 | .It Va vfs.pefs.dircache.buckets 388 | Number of dircache hash table buckets. 389 | Value can be set as a kernel environment variable by specifying it in 390 | .Ar /boot/loader.conf 391 | file, or using 392 | .Xr kenv 1 393 | utility 394 | before loading 395 | .Nm 396 | kernel module. 397 | .El 398 | .Sh EXAMPLES 399 | Encrypting a directory: 400 | .Bd -literal -offset indent 401 | % mkdir ~/Private 402 | % pefs mount ~/Private ~/Private 403 | % pefs addkey ~/Private 404 | Enter passphrase: 405 | \&... 406 | % pefs unmount ~/Private 407 | .Ed 408 | .Pp 409 | In such setup one has to manually check if passphrase valid, because 410 | .Nm 411 | would accept any key for a file system. 412 | Key chaining can be used to verify keys: 413 | .Bd -literal -offset indent 414 | % mkdir ~/Private 415 | % pefs addchain -fZ ~/Private 416 | Enter parent key passphrase: 417 | Reenter parent key passphrase: 418 | % pefs mount ~/Private ~/Private 419 | % pefs addkey -c ~/Private 420 | Enter passphrase: 421 | \&... 422 | % pefs unmount ~/Private 423 | .Ed 424 | .Pp 425 | In the example key chain database file (~/Private/.pefs.db) is created on 426 | unencrypted underlying file. 427 | And 428 | .Cm addkey Fl c 429 | is used to force key verification. 430 | Key chain database file is not encrypted by 431 | .Nm , 432 | but it's is internally encrypted by the utility and there should be no risk. 433 | .Pp 434 | Set default number of PKCS#5v2 iterations to 100000 for home directory not 435 | changing default algorithm: 436 | .Bd -literal -offset indent 437 | # make sure ~/ is not encrypted 438 | % ln -s :100000 ~/.pefs.conf 439 | .Ed 440 | .Pp 441 | .Sh DATA AUTHENTICATION 442 | .Nm 443 | provides no data integrity checking. 444 | Thus it's strongly advised to use additional data integrity checking tools. 445 | .Sh FILES 446 | .Bl -tag -width /.pefs.conf -compact 447 | .It Pa /.pefs.conf 448 | Configuration file (symbolic link). 449 | .It Pa /.pefs.db 450 | Key chain database file. 451 | .El 452 | .Sh SEE ALSO 453 | .Xr kenv 1 , 454 | .Xr crypto 4 , 455 | .Xr nullfs 5 , 456 | .Xr geli 8 , 457 | .Xr mount 8 , 458 | .Xr sysctl 8 459 | .Xr umount 8 460 | .Sh HISTORY 461 | The 462 | .Nm 463 | utility appeared in 464 | .Fx x.0 . 465 | .Sh AUTHORS 466 | .An Gleb Kurtsou Aq gleb@FreeBSD.org 467 | -------------------------------------------------------------------------------- /sbin/pefs/pefs_ctl.h: -------------------------------------------------------------------------------- 1 | /*- 2 | * Copyright (c) 2009 Gleb Kurtsou 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions 7 | * are met: 8 | * 1. Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * 2. Redistributions in binary form must reproduce the above copyright 11 | * notice, this list of conditions and the following disclaimer in the 12 | * documentation and/or other materials provided with the distribution. 13 | * 14 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 | * SUCH DAMAGE. 25 | * 26 | * $FreeBSD$ 27 | */ 28 | 29 | #include 30 | 31 | #define PEFS_FSTYPE "pefs" 32 | #define PEFS_KLD PEFS_FSTYPE 33 | 34 | #define PEFS_ALG_DEFAULT PEFS_ALG_AES_XTS 35 | #define PEFS_ALG_DEFAULT_KEYBITS 128 36 | 37 | #define PEFS_KDF_ITERATIONS 50000 38 | 39 | #define PEFS_FILE_KEYCHAIN ".pefs.db" 40 | #define PEFS_FILE_KEYCONF ".pefs.conf" 41 | 42 | #define PEFS_KEYCONF_ALG_IND 0 43 | #define PEFS_KEYCONF_ITERATIONS_IND 1 44 | 45 | #define PEFS_RANDOMCHAIN_MIN 16 46 | #define PEFS_RANDOMCHAIN_MAX 64 47 | 48 | #define PEFS_KEYENC_MAC_SIZE (PEFS_KEY_SIZE / 2) 49 | 50 | #define PEFS_KEYPARAM_FILES_MAX 16 51 | 52 | #define PEFS_ERR_GENERIC 1 53 | #define PEFS_ERR_USAGE 2 54 | #define PEFS_ERR_IO 3 55 | #define PEFS_ERR_SYS 4 56 | #define PEFS_ERR_NOENT 5 57 | #define PEFS_ERR_EXIST 6 58 | #define PEFS_ERR_INVALID 7 59 | 60 | #define PEFS_FS_IGNORE_TYPE 0x0001 61 | 62 | struct pefs_xkeyenc { 63 | struct { 64 | struct pefs_xkey ke_next; 65 | uint32_t ke_alg; 66 | uint32_t ke_keybits; 67 | } a; 68 | u_char ke_mac[PEFS_KEYENC_MAC_SIZE]; 69 | }; 70 | 71 | struct pefs_keyparam { 72 | int kp_alg; 73 | int kp_keybits; 74 | int kp_nopassphrase; 75 | int kp_iterations; 76 | int kp_keyfile_count; 77 | int kp_passfile_count; 78 | const char *kp_keyfile[PEFS_KEYPARAM_FILES_MAX]; 79 | const char *kp_passfile[PEFS_KEYPARAM_FILES_MAX]; 80 | }; 81 | 82 | void pefs_warn(const char *, ...) __printf0like(1, 2); 83 | 84 | int pefs_getfsroot(const char *path, int flags, char *fsroot, size_t size); 85 | int pefs_readfiles(const char **files, size_t count, void *ctx, 86 | int (*handler)(void *, uint8_t *, size_t, const char *)); 87 | 88 | int pefs_key_generate(struct pefs_xkey *xk, const char *passphrase, 89 | struct pefs_keyparam *kp); 90 | int pefs_key_encrypt(struct pefs_xkeyenc *xe, 91 | const struct pefs_xkey *xk_parent); 92 | int pefs_key_decrypt(struct pefs_xkeyenc *xe, 93 | const struct pefs_xkey *xk_parent); 94 | uintmax_t pefs_keyid_as_int(char *keyid); 95 | 96 | const char * pefs_alg_name(struct pefs_xkey *xk); 97 | void pefs_alg_list(FILE *stream); 98 | 99 | int pefs_keyparam_init(struct pefs_keyparam *kp, const char *fsroot); 100 | int pefs_keyparam_setalg(struct pefs_keyparam *kp, const char *algname); 101 | int pefs_keyparam_setiterations(struct pefs_keyparam *kp, const char *arg); 102 | int pefs_keyparam_setfile(struct pefs_keyparam *kp, const char **files, 103 | const char *arg); 104 | 105 | static inline void 106 | pefs_keyparam_create(struct pefs_keyparam *kp) 107 | { 108 | kp->kp_nopassphrase = 0; 109 | kp->kp_iterations = -1; 110 | kp->kp_keyfile_count = 0; 111 | kp->kp_passfile_count = 0; 112 | kp->kp_alg = 0; 113 | kp->kp_keybits = 0; 114 | } 115 | -------------------------------------------------------------------------------- /sbin/pefs/pefs_key.c: -------------------------------------------------------------------------------- 1 | /*- 2 | * Copyright (c) 2004-2008 Pawel Jakub Dawidek 3 | * Copyright (c) 2009 Gleb Kurtsou 4 | * All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without 7 | * modification, are permitted provided that the following conditions 8 | * are met: 9 | * 1. Redistributions of source code must retain the above copyright 10 | * notice, this list of conditions and the following disclaimer. 11 | * 2. Redistributions in binary form must reproduce the above copyright 12 | * notice, this list of conditions and the following disclaimer in the 13 | * documentation and/or other materials provided with the distribution. 14 | * 15 | * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND 16 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE 19 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 | * SUCH DAMAGE. 26 | */ 27 | 28 | #include 29 | __FBSDID("$FreeBSD$"); 30 | 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include 40 | #include 41 | 42 | #include 43 | #include 44 | #include 45 | #include 46 | #include 47 | 48 | #include "pefs_ctl.h" 49 | 50 | #define AES_BLOCK_SIZE 16 51 | 52 | struct algorithm { 53 | const char *name; 54 | uint32_t id; 55 | uint32_t keybits; 56 | }; 57 | 58 | static struct algorithm algs[] = { 59 | { "aes128-xts", PEFS_ALG_AES_XTS, 128 }, 60 | { "aes128", PEFS_ALG_AES_XTS, 128 }, 61 | { "aes192-xts", PEFS_ALG_AES_XTS, 192 }, 62 | { "aes192", PEFS_ALG_AES_XTS, 192 }, 63 | { "aes256-xts", PEFS_ALG_AES_XTS, 256 }, 64 | { "aes256", PEFS_ALG_AES_XTS, 256 }, 65 | { "camellia128-xts", PEFS_ALG_CAMELLIA_XTS, 128 }, 66 | { "camellia128", PEFS_ALG_CAMELLIA_XTS, 128 }, 67 | { "camellia192-xts", PEFS_ALG_CAMELLIA_XTS, 192 }, 68 | { "camellia192", PEFS_ALG_CAMELLIA_XTS, 192 }, 69 | { "camellia256-xts", PEFS_ALG_CAMELLIA_XTS, 256 }, 70 | { "camellia256", PEFS_ALG_CAMELLIA_XTS, 256 }, 71 | { NULL, 0, 0 }, 72 | }; 73 | 74 | static char magic_keyid_info[] = ""; 75 | static char magic_enckey_info[] = ""; 76 | 77 | static void 78 | pefs_aes_ctr(const rijndael_ctx *aes_ctx, const uint8_t *iv, 79 | const uint8_t *plaintext, uint8_t *ciphertext, int len) 80 | { 81 | uint8_t ctr[AES_BLOCK_SIZE]; 82 | uint8_t block[AES_BLOCK_SIZE]; 83 | int l, i; 84 | 85 | if (iv != NULL) 86 | memcpy(ctr, iv, sizeof(ctr)); 87 | else 88 | bzero(ctr, sizeof(ctr)); 89 | 90 | while (len > 0) { 91 | rijndael_encrypt(aes_ctx, ctr, block); 92 | l = (len < AES_BLOCK_SIZE ? len : AES_BLOCK_SIZE); 93 | for (i = 0; i < l; i++) 94 | *(ciphertext++) = block[i] ^ *(plaintext++); 95 | /* Increment counter */ 96 | for (i = 0; i < AES_BLOCK_SIZE; i++) { 97 | ctr[i]++; 98 | if (ctr[i] != 0) 99 | break; 100 | } 101 | len -= l; 102 | } 103 | } 104 | 105 | const char * 106 | pefs_alg_name(struct pefs_xkey *xk) 107 | { 108 | struct algorithm *alg; 109 | 110 | for (alg = algs; alg->name != NULL; alg++) { 111 | if (alg->id == xk->pxk_alg && alg->keybits == xk->pxk_keybits) 112 | return (alg->name); 113 | } 114 | 115 | return (""); 116 | } 117 | 118 | void 119 | pefs_alg_list(FILE *stream) 120 | { 121 | struct algorithm *prev, *alg; 122 | 123 | fprintf(stream, "Supported algorithms:\n"); 124 | for (prev = NULL, alg = algs; alg->name != NULL; prev = alg++) { 125 | if (prev != NULL && alg->id == prev->id && 126 | alg->keybits == prev->keybits) 127 | fprintf(stream, "\t%-16s (alias for %s)\n", alg->name, prev->name); 128 | else if (alg->id == PEFS_ALG_DEFAULT && 129 | alg->keybits == PEFS_ALG_DEFAULT_KEYBITS) 130 | fprintf(stream, "\t%-16s (default)\n", alg->name); 131 | else 132 | fprintf(stream, "\t%s\n", alg->name); 133 | } 134 | } 135 | 136 | int 137 | pefs_keyparam_setalg(struct pefs_keyparam *kp, const char *algname) 138 | { 139 | struct algorithm *alg; 140 | 141 | for (alg = algs; alg->name != NULL; alg++) { 142 | if (strcmp(algname, alg->name) == 0) { 143 | kp->kp_alg = alg->id; 144 | kp->kp_keybits = alg->keybits; 145 | return (0); 146 | } 147 | } 148 | 149 | pefs_warn("invalid algorithm %s", algname); 150 | return (PEFS_ERR_INVALID); 151 | } 152 | 153 | int 154 | pefs_keyparam_setiterations(struct pefs_keyparam *kp, const char *arg) 155 | { 156 | kp->kp_iterations = atoi(arg); 157 | if (kp->kp_iterations < 0) { 158 | pefs_warn("invalid iterations number: %s", arg); 159 | return (PEFS_ERR_INVALID); 160 | } 161 | 162 | return (0); 163 | } 164 | 165 | int 166 | pefs_keyparam_setfile(struct pefs_keyparam *kp, const char **files, 167 | const char *arg) 168 | { 169 | int *countp; 170 | 171 | if (files == kp->kp_keyfile) 172 | countp = &kp->kp_keyfile_count; 173 | else if (files == kp->kp_passfile) 174 | countp = &kp->kp_passfile_count; 175 | else { 176 | pefs_warn("internal error. invalid key parameters file type"); 177 | return (PEFS_ERR_INVALID); 178 | } 179 | if (arg == NULL || arg[0] == '\0') { 180 | pefs_warn("invalid key file"); 181 | return (PEFS_ERR_INVALID); 182 | } 183 | if (*countp == PEFS_KEYPARAM_FILES_MAX) { 184 | pefs_warn("key file limit exceed, %d max", 185 | PEFS_KEYPARAM_FILES_MAX); 186 | return (PEFS_ERR_INVALID); 187 | } 188 | files[(*countp)++] = arg; 189 | 190 | return (0); 191 | } 192 | 193 | static int 194 | pefs_keyparam_handle(struct pefs_keyparam *kp, int ind, const char *param) 195 | { 196 | int err; 197 | 198 | if (*param == '\0') 199 | return (0); 200 | 201 | switch (ind) { 202 | case PEFS_KEYCONF_ALG_IND: 203 | err = pefs_keyparam_setalg(kp, param); 204 | break; 205 | case PEFS_KEYCONF_ITERATIONS_IND: 206 | err = pefs_keyparam_setiterations(kp, param); 207 | break; 208 | default: 209 | pefs_warn("invalid configuration option at position %d: %s", 210 | ind + 1, param); 211 | err = PEFS_ERR_USAGE; 212 | } 213 | 214 | return (err); 215 | } 216 | 217 | int 218 | pefs_keyparam_init(struct pefs_keyparam *kp, const char *fsroot) 219 | { 220 | char conffile[MAXPATHLEN]; 221 | char buf[BUFSIZ]; 222 | char *s, *e; 223 | int ind, err; 224 | ssize_t bufsz; 225 | 226 | snprintf(conffile, sizeof(conffile), "%s/%s", fsroot, 227 | PEFS_FILE_KEYCONF); 228 | bufsz = readlink(conffile, buf, sizeof(buf)); 229 | if (bufsz > 0 && bufsz < (ssize_t)sizeof(buf)) { 230 | buf[bufsz] = '\0'; 231 | e = buf; 232 | for (ind = 0; e != NULL; ind++) { 233 | s = e; 234 | e = strchr(s, ':'); 235 | if (e != NULL) 236 | *(e++) = '\0'; 237 | err = pefs_keyparam_handle(kp, ind, s); 238 | if (err != 0) 239 | return (err); 240 | } 241 | } 242 | if (kp->kp_iterations < 0) 243 | kp->kp_iterations = PEFS_KDF_ITERATIONS; 244 | if (kp->kp_alg <= 0) { 245 | kp->kp_alg = PEFS_ALG_DEFAULT; 246 | kp->kp_keybits = PEFS_ALG_DEFAULT_KEYBITS; 247 | } 248 | 249 | return (0); 250 | } 251 | 252 | uintmax_t 253 | pefs_keyid_as_int(char *keyid) 254 | { 255 | uintmax_t r; 256 | int i; 257 | 258 | assert(sizeof(uintmax_t) >= PEFS_KEYID_SIZE); 259 | for (i = 0, r = 0; i < PEFS_KEYID_SIZE; i++) { 260 | if (i) 261 | r <<= 8; 262 | r |= keyid[i] & 0xff; 263 | } 264 | 265 | return (r); 266 | } 267 | 268 | static int 269 | pefs_readkeyfile_handler(void *a, uint8_t *buf, size_t len, 270 | const char *file __unused) 271 | { 272 | struct hmac_sha512_ctx *ctx = a; 273 | 274 | hmac_sha512_update(ctx, buf, len); 275 | 276 | return (0); 277 | } 278 | 279 | int 280 | pefs_key_generate(struct pefs_xkey *xk, const char *passphrase, 281 | struct pefs_keyparam *kp) 282 | { 283 | struct hmac_sha512_ctx ctx; 284 | int error; 285 | 286 | if (kp->kp_alg <= 0 || kp->kp_keybits <= 0 || 287 | kp->kp_iterations < 0) { 288 | pefs_warn("key parameters are not initialized"); 289 | return (PEFS_ERR_INVALID); 290 | } 291 | 292 | xk->pxk_index = -1; 293 | xk->pxk_alg = kp->kp_alg; 294 | xk->pxk_keybits = kp->kp_keybits; 295 | 296 | hmac_sha512_init(&ctx, NULL, 0); 297 | 298 | if (kp->kp_keyfile_count == 0 && passphrase[0] == '\0') { 299 | pefs_warn("no key components given"); 300 | return (PEFS_ERR_USAGE); 301 | } 302 | if (kp->kp_keyfile_count != 0) { 303 | error = pefs_readfiles(kp->kp_keyfile, kp->kp_keyfile_count, 304 | &ctx, pefs_readkeyfile_handler); 305 | if (error != 0) 306 | return (error); 307 | } 308 | 309 | if (passphrase[0] != '\0') { 310 | if (kp->kp_iterations == 0) { 311 | hmac_sha512_update(&ctx, passphrase, 312 | strlen(passphrase)); 313 | } else { 314 | pbkdf2_hmac_sha512_genkey(xk->pxk_key, PEFS_KEY_SIZE, 315 | passphrase, 0, passphrase, 316 | kp->kp_iterations); 317 | hmac_sha512_update(&ctx, xk->pxk_key, 318 | PEFS_KEY_SIZE); 319 | } 320 | } 321 | hmac_sha512_final(&ctx, xk->pxk_key, PEFS_KEY_SIZE); 322 | 323 | hmac_sha512_init(&ctx, xk->pxk_key, PEFS_KEY_SIZE); 324 | hmac_sha512_update(&ctx, magic_keyid_info, sizeof(magic_keyid_info)); 325 | hmac_sha512_final(&ctx, xk->pxk_keyid, PEFS_KEYID_SIZE); 326 | 327 | bzero(&ctx, sizeof(ctx)); 328 | 329 | return (0); 330 | } 331 | 332 | static int 333 | pefs_key_cipher(struct pefs_xkeyenc *xe, int enc, 334 | const struct pefs_xkey *xk_parent) 335 | { 336 | struct hmac_sha512_ctx hmac_ctx; 337 | rijndael_ctx enc_ctx; 338 | uint8_t key[PEFS_KEY_SIZE]; 339 | uint8_t mac[PEFS_KEYENC_MAC_SIZE]; 340 | uint8_t *data = (uint8_t *) &xe->a; 341 | const int datasize = sizeof(xe->a); 342 | const int keysize = 128 / 8; 343 | 344 | bzero(key, PEFS_KEY_SIZE); 345 | hmac_sha512_init(&hmac_ctx, xk_parent->pxk_key, 346 | PEFS_KEY_SIZE); 347 | hmac_sha512_update(&hmac_ctx, magic_enckey_info, 348 | sizeof(magic_enckey_info)); 349 | hmac_sha512_final(&hmac_ctx, key, PEFS_KEY_SIZE); 350 | 351 | hmac_sha512_init(&hmac_ctx, key, PEFS_KEY_SIZE); 352 | 353 | if (!enc) { 354 | hmac_sha512_update(&hmac_ctx, data, datasize); 355 | hmac_sha512_final(&hmac_ctx, mac, PEFS_KEYENC_MAC_SIZE); 356 | bzero(&hmac_ctx, sizeof(hmac_ctx)); 357 | if (crypto_verify_bytes(mac, xe->ke_mac, 358 | PEFS_KEYENC_MAC_SIZE) != 0) { 359 | return (PEFS_ERR_INVALID); 360 | } 361 | } 362 | 363 | rijndael_set_key(&enc_ctx, key, keysize * 8); 364 | pefs_aes_ctr(&enc_ctx, NULL, data, data, datasize); 365 | bzero(key, sizeof(key)); 366 | bzero(&enc_ctx, sizeof(enc_ctx)); 367 | 368 | if (enc) { 369 | hmac_sha512_update(&hmac_ctx, data, datasize); 370 | hmac_sha512_final(&hmac_ctx, xe->ke_mac, 371 | PEFS_KEYENC_MAC_SIZE); 372 | bzero(&hmac_ctx, sizeof(hmac_ctx)); 373 | } 374 | 375 | return (0); 376 | } 377 | 378 | int 379 | pefs_key_encrypt(struct pefs_xkeyenc *xe, const struct pefs_xkey *xk_parent) 380 | { 381 | return (pefs_key_cipher(xe, 1, xk_parent)); 382 | } 383 | 384 | int 385 | pefs_key_decrypt(struct pefs_xkeyenc *xe, const struct pefs_xkey *xk_parent) 386 | { 387 | return (pefs_key_cipher(xe, 0, xk_parent)); 388 | } 389 | -------------------------------------------------------------------------------- /sbin/pefs/pefs_keychain.c: -------------------------------------------------------------------------------- 1 | /*- 2 | * Copyright (c) 2009 Gleb Kurtsou 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions 7 | * are met: 8 | * 1. Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * 2. Redistributions in binary form must reproduce the above copyright 11 | * notice, this list of conditions and the following disclaimer in the 12 | * documentation and/or other materials provided with the distribution. 13 | * 14 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 | * SUCH DAMAGE. 25 | */ 26 | 27 | #include 28 | __FBSDID("$FreeBSD$"); 29 | 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include 40 | #include 41 | #include 42 | 43 | #include 44 | 45 | #include 46 | 47 | #include "pefs_ctl.h" 48 | #include "pefs_keychain.h" 49 | 50 | static DB * 51 | keychain_dbopen(const char *filesystem, int kc_flags, int flags) 52 | { 53 | char buf[MAXPATHLEN]; 54 | DB *db; 55 | 56 | snprintf(buf, sizeof(buf), "%s/%s", filesystem, PEFS_FILE_KEYCHAIN); 57 | db = dbopen(buf, flags | O_EXLOCK, S_IRUSR | S_IWUSR, DB_BTREE, NULL); 58 | if (db == NULL && (kc_flags & PEFS_KEYCHAIN_USE || errno != ENOENT)) 59 | pefs_warn("key chain %s: %s", buf, strerror(errno)); 60 | return (db); 61 | } 62 | 63 | void 64 | pefs_keychain_free(struct pefs_keychain_head *kch) 65 | { 66 | struct pefs_keychain *kc; 67 | 68 | if (kch == NULL) 69 | return; 70 | while ((kc = TAILQ_FIRST(kch)) != NULL) { 71 | TAILQ_REMOVE(kch, kc, kc_entry); 72 | bzero(kc, sizeof(struct pefs_keychain)); 73 | free(kc); 74 | } 75 | } 76 | 77 | static int 78 | pefs_keychain_get_db(DB *db, struct pefs_keychain_head *kch) 79 | { 80 | struct pefs_keychain *kc_parent = NULL, *kc = NULL; 81 | struct pefs_xkeyenc ke; 82 | DBT db_key, db_data; 83 | int error; 84 | 85 | while (1) { 86 | kc_parent = TAILQ_LAST(kch, pefs_keychain_head); 87 | TAILQ_FOREACH(kc, kch, kc_entry) { 88 | if (kc != kc_parent && 89 | crypto_verify_bytes(kc->kc_key.pxk_keyid, 90 | kc_parent->kc_key.pxk_keyid, 91 | PEFS_KEYID_SIZE) == 0) { 92 | pefs_warn("key chain loop detected: %016jx", 93 | pefs_keyid_as_int(kc->kc_key.pxk_keyid)); 94 | error = PEFS_ERR_INVALID; 95 | break; 96 | } 97 | } 98 | kc = NULL; 99 | db_key.data = kc_parent->kc_key.pxk_keyid; 100 | db_key.size = PEFS_KEYID_SIZE; 101 | error = db->get(db, &db_key, &db_data, 0); 102 | if (error != 0) { 103 | if (error == -1) { 104 | pefs_warn("key chain database error: %s", 105 | strerror(errno)); 106 | error = PEFS_ERR_SYS; 107 | } 108 | if (TAILQ_FIRST(kch) != kc_parent) 109 | error = 0; 110 | break; 111 | } 112 | if (db_data.size != sizeof(struct pefs_xkeyenc)) { 113 | pefs_warn("key chain database damaged"); 114 | error = PEFS_ERR_INVALID; 115 | break; 116 | } 117 | 118 | kc = calloc(1, sizeof(struct pefs_keychain)); 119 | if (kc == NULL) { 120 | pefs_warn("calloc: %s", strerror(errno)); 121 | error = PEFS_ERR_SYS; 122 | break; 123 | } 124 | 125 | memcpy(&ke, db_data.data, sizeof(struct pefs_xkeyenc)); 126 | error = pefs_key_decrypt(&ke, &kc_parent->kc_key); 127 | if (error) 128 | break; 129 | kc->kc_key = ke.a.ke_next; 130 | kc_parent->kc_key.pxk_alg = le32toh(ke.a.ke_alg); 131 | kc_parent->kc_key.pxk_keybits = le32toh(ke.a.ke_keybits); 132 | if (pefs_alg_name(&kc_parent->kc_key) == NULL) { 133 | pefs_warn("key chain database damaged"); 134 | error = PEFS_ERR_INVALID; 135 | break; 136 | } 137 | kc->kc_key.pxk_index = -1; 138 | kc->kc_key.pxk_alg = le32toh(kc->kc_key.pxk_alg); 139 | kc->kc_key.pxk_keybits = le32toh(kc->kc_key.pxk_keybits); 140 | 141 | if (kc->kc_key.pxk_alg == PEFS_ALG_INVALID || 142 | pefs_alg_name(&kc->kc_key) == NULL) { 143 | if (kc->kc_key.pxk_alg != PEFS_ALG_INVALID) { 144 | error = PEFS_ERR_INVALID; 145 | pefs_warn("key chain %016jx -> %016jx: " 146 | "invalid algorithm (decyption failed)", 147 | pefs_keyid_as_int( 148 | kc_parent->kc_key.pxk_keyid), 149 | pefs_keyid_as_int(kc->kc_key.pxk_keyid)); 150 | } 151 | bzero(&kc->kc_key, sizeof(struct pefs_xkey)); 152 | break; 153 | } 154 | TAILQ_INSERT_TAIL(kch, kc, kc_entry); 155 | kc = NULL; 156 | } 157 | 158 | if (error != 0 && kc != NULL) { 159 | bzero(&kc->kc_key, sizeof(struct pefs_xkey)); 160 | free(kc); 161 | } 162 | return (error); 163 | } 164 | 165 | int 166 | pefs_keychain_get(struct pefs_keychain_head *kch, const char *filesystem, 167 | int flags, struct pefs_xkey *xk) 168 | { 169 | struct pefs_keychain *kc; 170 | DB *db; 171 | int error; 172 | 173 | assert(filesystem != NULL && kch != NULL && xk != NULL); 174 | 175 | TAILQ_INIT(kch); 176 | 177 | kc = calloc(1, sizeof(struct pefs_keychain)); 178 | if (kc == NULL) { 179 | pefs_warn("calloc: %s", strerror(errno)); 180 | return (PEFS_ERR_SYS); 181 | } 182 | kc->kc_key = *xk; 183 | TAILQ_INSERT_HEAD(kch, kc, kc_entry); 184 | 185 | if (flags == 0) 186 | return (0); 187 | 188 | db = keychain_dbopen(filesystem, flags, O_RDONLY); 189 | if (db == NULL) { 190 | if (flags & PEFS_KEYCHAIN_IGNORE_MISSING) 191 | return (0); 192 | pefs_keychain_free(kch); 193 | return (PEFS_ERR_NOENT); 194 | } 195 | 196 | error = pefs_keychain_get_db(db, kch); 197 | 198 | db->close(db); 199 | 200 | if (error != 0 && (flags & PEFS_KEYCHAIN_USE) != 0) { 201 | pefs_keychain_free(kch); 202 | pefs_warn("key chain not found: %016jx", 203 | pefs_keyid_as_int(xk->pxk_keyid)); 204 | return (PEFS_ERR_NOENT); 205 | } 206 | 207 | return (0); 208 | } 209 | 210 | int 211 | pefs_keychain_set(const char *filesystem, struct pefs_xkey *xk, 212 | struct pefs_xkey *xknext) 213 | { 214 | struct pefs_xkeyenc ke; 215 | DBT db_key, db_data; 216 | DB *db; 217 | int error; 218 | 219 | ke.a.ke_next = *xknext; 220 | ke.a.ke_next.pxk_index = (uint32_t)random(); 221 | ke.a.ke_next.pxk_alg = htole32(ke.a.ke_next.pxk_alg); 222 | ke.a.ke_next.pxk_keybits = htole32(ke.a.ke_next.pxk_keybits); 223 | ke.a.ke_alg = htole32(xk->pxk_alg); 224 | ke.a.ke_keybits = htole32(xk->pxk_keybits); 225 | if (pefs_key_encrypt(&ke, xk) != 0) 226 | return (PEFS_ERR_INVALID); 227 | 228 | db = keychain_dbopen(filesystem, PEFS_KEYCHAIN_USE, O_RDWR | O_CREAT); 229 | if (db == NULL) 230 | return (PEFS_ERR_INVALID); 231 | 232 | db_data.data = &ke; 233 | db_data.size = sizeof(struct pefs_xkeyenc); 234 | db_key.data = xk->pxk_keyid; 235 | db_key.size = PEFS_KEYID_SIZE; 236 | error = db->put(db, &db_key, &db_data, R_NOOVERWRITE); 237 | bzero(&ke, sizeof(struct pefs_xkeyenc)); 238 | if (error != 0) { 239 | if (error == -1) { 240 | error = PEFS_ERR_SYS; 241 | pefs_warn("key chain database error: %s", 242 | strerror(errno)); 243 | } else { 244 | error = PEFS_ERR_EXIST; 245 | pefs_warn("key chain already exists: %016jx", 246 | pefs_keyid_as_int(xk->pxk_keyid)); 247 | } 248 | } 249 | db->close(db); 250 | 251 | return (error); 252 | } 253 | 254 | int 255 | pefs_keychain_del(const char *filesystem, int flags, struct pefs_xkey *xk) 256 | { 257 | DBT db_key; 258 | DB *db; 259 | int error; 260 | 261 | db = keychain_dbopen(filesystem, PEFS_KEYCHAIN_USE, O_RDWR | O_CREAT); 262 | if (db == NULL) 263 | return (-1); 264 | db_key.data = xk->pxk_keyid; 265 | db_key.size = PEFS_KEYID_SIZE; 266 | error = db->del(db, &db_key, 0); 267 | if (error != 0) { 268 | if (error == -1) { 269 | error = PEFS_ERR_SYS; 270 | pefs_warn("key chain database error: %s", 271 | strerror(errno)); 272 | } else { 273 | if ((flags & PEFS_KEYCHAIN_IGNORE_MISSING) == 0) { 274 | error = PEFS_ERR_NOENT; 275 | pefs_warn("cannot delete key chain %016jx", 276 | pefs_keyid_as_int(xk->pxk_keyid)); 277 | } else 278 | error = 0; 279 | } 280 | } 281 | db->close(db); 282 | 283 | return (error); 284 | } 285 | -------------------------------------------------------------------------------- /sbin/pefs/pefs_keychain.h: -------------------------------------------------------------------------------- 1 | /*- 2 | * Copyright (c) 2009 Gleb Kurtsou 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions 7 | * are met: 8 | * 1. Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * 2. Redistributions in binary form must reproduce the above copyright 11 | * notice, this list of conditions and the following disclaimer in the 12 | * documentation and/or other materials provided with the distribution. 13 | * 14 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 | * SUCH DAMAGE. 25 | * 26 | * $FreeBSD$ 27 | */ 28 | 29 | #include 30 | 31 | #define PEFS_KEYCHAIN_USE 0x0001 32 | #define PEFS_KEYCHAIN_IGNORE_MISSING 0x0002 33 | 34 | struct pefs_keychain 35 | { 36 | TAILQ_ENTRY(pefs_keychain) kc_entry; 37 | struct pefs_xkey kc_key; 38 | }; 39 | 40 | TAILQ_HEAD(pefs_keychain_head, pefs_keychain); 41 | 42 | int pefs_keychain_get(struct pefs_keychain_head *kch, 43 | const char *filesystem, int flags, struct pefs_xkey *xk); 44 | int pefs_keychain_set(const char *filesystem, struct pefs_xkey *xk, 45 | struct pefs_xkey *xknext); 46 | int pefs_keychain_del(const char *filesystem, int flags, 47 | struct pefs_xkey *xk); 48 | void pefs_keychain_free(struct pefs_keychain_head *kch); 49 | -------------------------------------------------------------------------------- /sbin/pefs/pefs_subr.c: -------------------------------------------------------------------------------- 1 | /*- 2 | * Copyright (c) 2009 Gleb Kurtsou 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions 7 | * are met: 8 | * 1. Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * 2. Redistributions in binary form must reproduce the above copyright 11 | * notice, this list of conditions and the following disclaimer in the 12 | * documentation and/or other materials provided with the distribution. 13 | * 14 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 | * SUCH DAMAGE. 25 | * 26 | */ 27 | 28 | #include 29 | __FBSDID("$FreeBSD$"); 30 | 31 | #include 32 | #include 33 | #include 34 | #include 35 | 36 | #include 37 | #include 38 | #include 39 | #include 40 | #include 41 | #include 42 | #include 43 | #include 44 | #include 45 | 46 | #include 47 | 48 | #include "pefs_ctl.h" 49 | 50 | int 51 | pefs_getfsroot(const char *path, int flags, char *fsroot, size_t size) 52 | { 53 | struct statfs fs; 54 | const char *realfsroot; 55 | 56 | if (statfs(path, &fs) == -1) { 57 | pefs_warn("statfs failed: %s: %s", path, strerror(errno)); 58 | return (PEFS_ERR_SYS); 59 | } 60 | 61 | realfsroot = fs.f_mntonname; 62 | if (strcmp(PEFS_FSTYPE, fs.f_fstypename) != 0) { 63 | if ((flags & PEFS_FS_IGNORE_TYPE) != 0) 64 | realfsroot = path; 65 | else { 66 | pefs_warn("invalid file system type: %s", path); 67 | return (PEFS_ERR_INVALID); 68 | } 69 | } 70 | 71 | if (fsroot != NULL) 72 | strlcpy(fsroot, realfsroot, size); 73 | 74 | return (0); 75 | } 76 | 77 | int 78 | pefs_readfiles(const char **files, size_t count, void *ctx, 79 | int (*handler)(void *, uint8_t *, size_t, const char *)) 80 | { 81 | uint8_t buf[BUFSIZ + 1]; 82 | ssize_t done; 83 | size_t i; 84 | int error, fd; 85 | 86 | for (i = 0; i < count; i++) { 87 | if (strcmp(files[i], "-") == 0) 88 | fd = STDIN_FILENO; 89 | else { 90 | fd = open(files[i], O_RDONLY); 91 | if (fd == -1) { 92 | pefs_warn("cannot open key file %s: %s", 93 | files[i], strerror(errno)); 94 | return (PEFS_ERR_IO); 95 | } 96 | } 97 | while ((done = read(fd, buf, sizeof(buf) - 1)) > 0) { 98 | buf[done] = '\0'; 99 | error = handler(ctx, buf, done, files[i]); 100 | if (error != 0) 101 | return (error); 102 | } 103 | bzero(buf, sizeof(buf)); 104 | if (done == -1) { 105 | pefs_warn("cannot read key file %s: %s", 106 | files[i], strerror(errno)); 107 | return (PEFS_ERR_IO); 108 | } 109 | if (fd != STDIN_FILENO) 110 | close(fd); 111 | } 112 | return (0); 113 | } 114 | -------------------------------------------------------------------------------- /sys/crypto/crypto_verify_bytes.c: -------------------------------------------------------------------------------- 1 | /*- 2 | * Copyright 2005-2013 Colin Percival. 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions 7 | * are met: 8 | * 1. Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * 2. Redistributions in binary form must reproduce the above copyright 11 | * notice, this list of conditions and the following disclaimer in the 12 | * documentation and/or other materials provided with the distribution. 13 | * 14 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 | * SUCH DAMAGE. 25 | */ 26 | 27 | #include 28 | 29 | #include 30 | 31 | /** 32 | * crypto_verify_bytes(buf0, buf1, len): 33 | * Return zero if and only if buf0[0 .. len - 1] and buf1[0 .. len - 1] are 34 | * identical. Do not leak any information via timing side channels. 35 | */ 36 | uint8_t 37 | crypto_verify_bytes(const uint8_t * buf0, const uint8_t * buf1, size_t len) 38 | { 39 | uint8_t rc = 0; 40 | size_t i; 41 | 42 | for (i = 0; i < len; i++) 43 | rc = rc | (buf0[i] ^ buf1[i]); 44 | 45 | return (rc); 46 | } 47 | -------------------------------------------------------------------------------- /sys/crypto/crypto_verify_bytes.h: -------------------------------------------------------------------------------- 1 | /*- 2 | * Copyright 2005-2013 Colin Percival. 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions 7 | * are met: 8 | * 1. Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * 2. Redistributions in binary form must reproduce the above copyright 11 | * notice, this list of conditions and the following disclaimer in the 12 | * documentation and/or other materials provided with the distribution. 13 | * 14 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 | * SUCH DAMAGE. 25 | */ 26 | 27 | #ifndef _CRYPTO_VERIFY_BYTES_H_ 28 | #define _CRYPTO_VERIFY_BYTES_H_ 29 | 30 | /** 31 | * crypto_verify_bytes(buf0, buf1, len): 32 | * Return zero if and only if buf0[0 .. len - 1] and buf1[0 .. len - 1] are 33 | * identical. Do not leak any information via timing side channels. 34 | */ 35 | uint8_t crypto_verify_bytes(const uint8_t *, const uint8_t *, size_t); 36 | 37 | #endif /* !_CRYPTO_VERIFY_BYTES_H_ */ 38 | -------------------------------------------------------------------------------- /sys/crypto/hmac/hmac_sha512.c: -------------------------------------------------------------------------------- 1 | /*- 2 | * Copyright (c) 2005-2010 Pawel Jakub Dawidek 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions 7 | * are met: 8 | * 1. Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * 2. Redistributions in binary form must reproduce the above copyright 11 | * notice, this list of conditions and the following disclaimer in the 12 | * documentation and/or other materials provided with the distribution. 13 | * 14 | * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND 15 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE 18 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 | * SUCH DAMAGE. 25 | */ 26 | 27 | #include 28 | __FBSDID("$FreeBSD$"); 29 | 30 | #include 31 | #ifdef _KERNEL 32 | #include 33 | #include 34 | #else 35 | #include 36 | #include 37 | #include 38 | #endif 39 | #include 40 | 41 | void 42 | hmac_sha512_init(struct hmac_sha512_ctx *ctx, const uint8_t *hkey, 43 | size_t hkeylen) 44 | { 45 | u_char k_ipad[128], key[128]; 46 | SHA512_CTX lctx; 47 | u_int i; 48 | 49 | bzero(key, sizeof(key)); 50 | if (hkeylen == 0) 51 | ; /* do nothing */ 52 | else if (hkeylen <= 128) 53 | bcopy(hkey, key, hkeylen); 54 | else { 55 | /* If key is longer than 128 bytes reset it to key = SHA512(key). */ 56 | SHA512_Init(&lctx); 57 | SHA512_Update(&lctx, hkey, hkeylen); 58 | SHA512_Final(key, &lctx); 59 | } 60 | 61 | /* XOR key with ipad and opad values. */ 62 | for (i = 0; i < sizeof(key); i++) { 63 | k_ipad[i] = key[i] ^ 0x36; 64 | ctx->k_opad[i] = key[i] ^ 0x5c; 65 | } 66 | bzero(key, sizeof(key)); 67 | /* Perform inner SHA512. */ 68 | SHA512_Init(&ctx->shactx); 69 | SHA512_Update(&ctx->shactx, k_ipad, sizeof(k_ipad)); 70 | bzero(k_ipad, sizeof(k_ipad)); 71 | } 72 | 73 | void 74 | hmac_sha512_update(struct hmac_sha512_ctx *ctx, const uint8_t *data, 75 | size_t datasize) 76 | { 77 | 78 | SHA512_Update(&ctx->shactx, data, datasize); 79 | } 80 | 81 | void 82 | hmac_sha512_final(struct hmac_sha512_ctx *ctx, uint8_t *md, size_t mdsize) 83 | { 84 | u_char digest[SHA512_DIGEST_LENGTH]; 85 | SHA512_CTX lctx; 86 | 87 | SHA512_Final(digest, &ctx->shactx); 88 | /* Perform outer SHA512. */ 89 | SHA512_Init(&lctx); 90 | SHA512_Update(&lctx, ctx->k_opad, sizeof(ctx->k_opad)); 91 | bzero(ctx, sizeof(*ctx)); 92 | SHA512_Update(&lctx, digest, sizeof(digest)); 93 | SHA512_Final(digest, &lctx); 94 | bzero(&lctx, sizeof(lctx)); 95 | /* mdsize == 0 means "Give me the whole hash!" */ 96 | if (mdsize == 0) 97 | mdsize = SHA512_DIGEST_LENGTH; 98 | bcopy(digest, md, mdsize); 99 | bzero(digest, sizeof(digest)); 100 | } 101 | 102 | void 103 | hmac_sha512(const uint8_t *hkey, size_t hkeysize, const uint8_t *data, 104 | size_t datasize, uint8_t *md, size_t mdsize) 105 | { 106 | struct hmac_sha512_ctx ctx; 107 | 108 | hmac_sha512_init(&ctx, hkey, hkeysize); 109 | hmac_sha512_update(&ctx, data, datasize); 110 | hmac_sha512_final(&ctx, md, mdsize); 111 | } 112 | -------------------------------------------------------------------------------- /sys/crypto/hmac/hmac_sha512.h: -------------------------------------------------------------------------------- 1 | /*- 2 | * Copyright (c) 2005-2011 Pawel Jakub Dawidek 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions 7 | * are met: 8 | * 1. Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * 2. Redistributions in binary form must reproduce the above copyright 11 | * notice, this list of conditions and the following disclaimer in the 12 | * documentation and/or other materials provided with the distribution. 13 | * 14 | * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND 15 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE 18 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 | * SUCH DAMAGE. 25 | * 26 | * $FreeBSD$ 27 | */ 28 | 29 | #ifndef _SYS_CRYPTO_HMAC_SHA512_ 30 | #define _SYS_CRYPTO_HMAC_SHA512_ 31 | 32 | #include 33 | 34 | struct hmac_sha512_ctx { 35 | SHA512_CTX shactx; 36 | u_char k_opad[128]; 37 | }; 38 | 39 | void hmac_sha512_init(struct hmac_sha512_ctx *ctx, const uint8_t *hkey, 40 | size_t hkeylen); 41 | void hmac_sha512_update(struct hmac_sha512_ctx *ctx, const uint8_t *data, 42 | size_t datasize); 43 | void hmac_sha512_final(struct hmac_sha512_ctx *ctx, uint8_t *md, size_t mdsize); 44 | void hmac_sha512(const uint8_t *hkey, size_t hkeysize, 45 | const uint8_t *data, size_t datasize, uint8_t *md, size_t mdsize); 46 | 47 | #endif /* !_SYS_CRYPTO_HMAC_SHA512_ */ 48 | -------------------------------------------------------------------------------- /sys/crypto/pbkdf2/pbkdf2_hmac_sha512.c: -------------------------------------------------------------------------------- 1 | /*- 2 | * Copyright (c) 2005 Pawel Jakub Dawidek 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions 7 | * are met: 8 | * 1. Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * 2. Redistributions in binary form must reproduce the above copyright 11 | * notice, this list of conditions and the following disclaimer in the 12 | * documentation and/or other materials provided with the distribution. 13 | * 14 | * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND 15 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE 18 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 | * SUCH DAMAGE. 25 | */ 26 | 27 | #include 28 | __FBSDID("$FreeBSD$"); 29 | 30 | #include 31 | #ifdef _KERNEL 32 | #include 33 | #include 34 | #else 35 | #include 36 | #include 37 | #include 38 | #include 39 | #endif 40 | 41 | #include 42 | #include 43 | 44 | static __inline void 45 | xor(uint8_t *dst, const uint8_t *src, size_t size) 46 | { 47 | 48 | for (; size > 0; size--) 49 | *dst++ ^= *src++; 50 | } 51 | 52 | void 53 | pbkdf2_hmac_sha512_genkey(uint8_t *key, unsigned keylen, const uint8_t *salt, 54 | size_t saltsize, const char *passphrase, u_int iterations) 55 | { 56 | uint8_t md[SHA512_DIGEST_LENGTH]; 57 | uint8_t saltcount[saltsize + sizeof(uint32_t)]; 58 | uint8_t *counter, *keyp; 59 | u_int i, bsize, passlen; 60 | uint32_t count; 61 | 62 | passlen = strlen(passphrase); 63 | bzero(key, keylen); 64 | bcopy(salt, saltcount, saltsize); 65 | counter = saltcount + saltsize; 66 | 67 | keyp = key; 68 | for (count = 1; keylen > 0; count++, keylen -= bsize, keyp += bsize) { 69 | bsize = MIN(keylen, sizeof(md)); 70 | 71 | counter[0] = (count >> 24) & 0xff; 72 | counter[1] = (count >> 16) & 0xff; 73 | counter[2] = (count >> 8) & 0xff; 74 | counter[3] = count & 0xff; 75 | hmac_sha512(passphrase, passlen, saltcount, 76 | sizeof(saltcount), md, 0); 77 | xor(keyp, md, bsize); 78 | 79 | for(i = 1; i < iterations; i++) { 80 | hmac_sha512(passphrase, passlen, md, sizeof(md), md, 0); 81 | xor(keyp, md, bsize); 82 | } 83 | } 84 | } 85 | 86 | #ifndef _KERNEL 87 | /* 88 | * Return the number of microseconds needed for 'interations' iterations. 89 | */ 90 | static int 91 | pbkdf2_hmac_sha512_probe(int iterations, size_t keylen, size_t saltlen) 92 | { 93 | uint8_t key[keylen], salt[saltlen]; 94 | uint8_t passphrase[] = "passphrase"; 95 | struct rusage start, end; 96 | int usecs; 97 | 98 | getrusage(RUSAGE_SELF, &start); 99 | pbkdf2_hmac_sha512_genkey(key, sizeof(key), salt, sizeof(salt), 100 | passphrase, iterations); 101 | getrusage(RUSAGE_SELF, &end); 102 | 103 | usecs = end.ru_utime.tv_sec - start.ru_utime.tv_sec; 104 | usecs *= 1000000; 105 | usecs += end.ru_utime.tv_usec - start.ru_utime.tv_usec; 106 | return (usecs); 107 | } 108 | 109 | /* 110 | * Return the number of iterations which takes 'usecs' microseconds. 111 | */ 112 | int 113 | pbkdf2_hmac_sha512_calculate(int usecs, size_t keylen, size_t saltlen) 114 | { 115 | int iterations, v; 116 | 117 | for (iterations = 1; ; iterations <<= 1) { 118 | v = pbkdf2_hmac_sha512_probe(iterations, keylen, saltlen); 119 | if (v > 2000000) 120 | break; 121 | } 122 | return (((intmax_t)iterations * (intmax_t)usecs) / v); 123 | } 124 | 125 | #endif /* !_KERNEL */ 126 | -------------------------------------------------------------------------------- /sys/crypto/pbkdf2/pbkdf2_hmac_sha512.h: -------------------------------------------------------------------------------- 1 | /*- 2 | * Copyright (c) 2005 Pawel Jakub Dawidek 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions 7 | * are met: 8 | * 1. Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * 2. Redistributions in binary form must reproduce the above copyright 11 | * notice, this list of conditions and the following disclaimer in the 12 | * documentation and/or other materials provided with the distribution. 13 | * 14 | * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND 15 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE 18 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 | * SUCH DAMAGE. 25 | * 26 | * $FreeBSD$ 27 | */ 28 | 29 | #ifndef _SYS_CRYPTO_PBKDF2_HMAC_SHA512H_ 30 | #define _SYS_CRYPTO_PBKDF2_HMAC_SHA512H_ 31 | 32 | void pbkdf2_hmac_sha512_genkey(uint8_t *key, unsigned keylen, 33 | const uint8_t *salt, size_t saltsize, const char *passphrase, 34 | u_int iterations); 35 | #ifndef _KERNEL 36 | int pbkdf2_hmac_sha512_calculate(int usecs, size_t keylen, size_t saltlen); 37 | #endif 38 | 39 | #endif /* !_SYS_CRYPTO_PBKDF2_HMAC_SHA512H_ */ 40 | -------------------------------------------------------------------------------- /sys/crypto/rijndael/rijndael-api-fst.c: -------------------------------------------------------------------------------- 1 | /* $KAME: rijndael-api-fst.c,v 1.10 2001/05/27 09:34:18 itojun Exp $ */ 2 | 3 | /* 4 | * rijndael-api-fst.c v2.3 April '2000 5 | * 6 | * Optimised ANSI C code 7 | * 8 | * authors: v1.0: Antoon Bosselaers 9 | * v2.0: Vincent Rijmen 10 | * v2.1: Vincent Rijmen 11 | * v2.2: Vincent Rijmen 12 | * v2.3: Paulo Barreto 13 | * v2.4: Vincent Rijmen 14 | * 15 | * This code is placed in the public domain. 16 | */ 17 | 18 | #include 19 | __FBSDID("$FreeBSD$"); 20 | 21 | #include 22 | #ifdef _KERNEL 23 | #include 24 | #else 25 | #include 26 | #endif 27 | 28 | #include 29 | #include 30 | 31 | #ifndef TRUE 32 | #define TRUE 1 33 | #endif 34 | 35 | typedef u_int8_t BYTE; 36 | 37 | int rijndael_makeKey(keyInstance *key, BYTE direction, int keyLen, char *keyMaterial) { 38 | u_int8_t cipherKey[RIJNDAEL_MAXKB]; 39 | 40 | if (key == NULL) { 41 | return BAD_KEY_INSTANCE; 42 | } 43 | 44 | if ((direction == DIR_ENCRYPT) || (direction == DIR_DECRYPT)) { 45 | key->direction = direction; 46 | } else { 47 | return BAD_KEY_DIR; 48 | } 49 | 50 | if ((keyLen == 128) || (keyLen == 192) || (keyLen == 256)) { 51 | key->keyLen = keyLen; 52 | } else { 53 | return BAD_KEY_MAT; 54 | } 55 | 56 | if (keyMaterial != NULL) { 57 | memcpy(key->keyMaterial, keyMaterial, keyLen/8); 58 | } 59 | 60 | /* initialize key schedule: */ 61 | memcpy(cipherKey, key->keyMaterial, keyLen/8); 62 | if (direction == DIR_ENCRYPT) { 63 | key->Nr = rijndaelKeySetupEnc(key->rk, cipherKey, keyLen); 64 | } else { 65 | key->Nr = rijndaelKeySetupDec(key->rk, cipherKey, keyLen); 66 | } 67 | rijndaelKeySetupEnc(key->ek, cipherKey, keyLen); 68 | return TRUE; 69 | } 70 | 71 | int rijndael_cipherInit(cipherInstance *cipher, BYTE mode, char *IV) { 72 | if ((mode == MODE_ECB) || (mode == MODE_CBC) || (mode == MODE_CFB1)) { 73 | cipher->mode = mode; 74 | } else { 75 | return BAD_CIPHER_MODE; 76 | } 77 | if (IV != NULL) { 78 | memcpy(cipher->IV, IV, RIJNDAEL_MAX_IV_SIZE); 79 | } else { 80 | memset(cipher->IV, 0, RIJNDAEL_MAX_IV_SIZE); 81 | } 82 | return TRUE; 83 | } 84 | 85 | int rijndael_blockEncrypt(cipherInstance *cipher, keyInstance *key, 86 | BYTE *input, int inputLen, BYTE *outBuffer) { 87 | int i, k, numBlocks; 88 | u_int8_t block[16], iv[4][4]; 89 | 90 | if (cipher == NULL || 91 | key == NULL || 92 | key->direction == DIR_DECRYPT) { 93 | return BAD_CIPHER_STATE; 94 | } 95 | if (input == NULL || inputLen <= 0) { 96 | return 0; /* nothing to do */ 97 | } 98 | 99 | numBlocks = inputLen/128; 100 | 101 | switch (cipher->mode) { 102 | case MODE_ECB: 103 | for (i = numBlocks; i > 0; i--) { 104 | rijndaelEncrypt(key->rk, key->Nr, input, outBuffer); 105 | input += 16; 106 | outBuffer += 16; 107 | } 108 | break; 109 | 110 | case MODE_CBC: 111 | #if 1 /*STRICT_ALIGN*/ 112 | memcpy(block, cipher->IV, 16); 113 | memcpy(iv, input, 16); 114 | ((u_int32_t*)block)[0] ^= ((u_int32_t*)iv)[0]; 115 | ((u_int32_t*)block)[1] ^= ((u_int32_t*)iv)[1]; 116 | ((u_int32_t*)block)[2] ^= ((u_int32_t*)iv)[2]; 117 | ((u_int32_t*)block)[3] ^= ((u_int32_t*)iv)[3]; 118 | #else 119 | ((u_int32_t*)block)[0] = ((u_int32_t*)cipher->IV)[0] ^ ((u_int32_t*)input)[0]; 120 | ((u_int32_t*)block)[1] = ((u_int32_t*)cipher->IV)[1] ^ ((u_int32_t*)input)[1]; 121 | ((u_int32_t*)block)[2] = ((u_int32_t*)cipher->IV)[2] ^ ((u_int32_t*)input)[2]; 122 | ((u_int32_t*)block)[3] = ((u_int32_t*)cipher->IV)[3] ^ ((u_int32_t*)input)[3]; 123 | #endif 124 | rijndaelEncrypt(key->rk, key->Nr, block, outBuffer); 125 | input += 16; 126 | for (i = numBlocks - 1; i > 0; i--) { 127 | #if 1 /*STRICT_ALIGN*/ 128 | memcpy(block, outBuffer, 16); 129 | memcpy(iv, input, 16); 130 | ((u_int32_t*)block)[0] ^= ((u_int32_t*)iv)[0]; 131 | ((u_int32_t*)block)[1] ^= ((u_int32_t*)iv)[1]; 132 | ((u_int32_t*)block)[2] ^= ((u_int32_t*)iv)[2]; 133 | ((u_int32_t*)block)[3] ^= ((u_int32_t*)iv)[3]; 134 | #else 135 | ((u_int32_t*)block)[0] = ((u_int32_t*)outBuffer)[0] ^ ((u_int32_t*)input)[0]; 136 | ((u_int32_t*)block)[1] = ((u_int32_t*)outBuffer)[1] ^ ((u_int32_t*)input)[1]; 137 | ((u_int32_t*)block)[2] = ((u_int32_t*)outBuffer)[2] ^ ((u_int32_t*)input)[2]; 138 | ((u_int32_t*)block)[3] = ((u_int32_t*)outBuffer)[3] ^ ((u_int32_t*)input)[3]; 139 | #endif 140 | outBuffer += 16; 141 | rijndaelEncrypt(key->rk, key->Nr, block, outBuffer); 142 | input += 16; 143 | } 144 | break; 145 | 146 | case MODE_CFB1: 147 | #if 1 /*STRICT_ALIGN*/ 148 | memcpy(iv, cipher->IV, 16); 149 | #else /* !STRICT_ALIGN */ 150 | *((u_int32_t*)iv[0]) = *((u_int32_t*)(cipher->IV )); 151 | *((u_int32_t*)iv[1]) = *((u_int32_t*)(cipher->IV+ 4)); 152 | *((u_int32_t*)iv[2]) = *((u_int32_t*)(cipher->IV+ 8)); 153 | *((u_int32_t*)iv[3]) = *((u_int32_t*)(cipher->IV+12)); 154 | #endif /* ?STRICT_ALIGN */ 155 | for (i = numBlocks; i > 0; i--) { 156 | for (k = 0; k < 128; k++) { 157 | *((u_int32_t*) block ) = *((u_int32_t*)iv[0]); 158 | *((u_int32_t*)(block+ 4)) = *((u_int32_t*)iv[1]); 159 | *((u_int32_t*)(block+ 8)) = *((u_int32_t*)iv[2]); 160 | *((u_int32_t*)(block+12)) = *((u_int32_t*)iv[3]); 161 | rijndaelEncrypt(key->ek, key->Nr, block, 162 | block); 163 | outBuffer[k/8] ^= (block[0] & 0x80) >> (k & 7); 164 | iv[0][0] = (iv[0][0] << 1) | (iv[0][1] >> 7); 165 | iv[0][1] = (iv[0][1] << 1) | (iv[0][2] >> 7); 166 | iv[0][2] = (iv[0][2] << 1) | (iv[0][3] >> 7); 167 | iv[0][3] = (iv[0][3] << 1) | (iv[1][0] >> 7); 168 | iv[1][0] = (iv[1][0] << 1) | (iv[1][1] >> 7); 169 | iv[1][1] = (iv[1][1] << 1) | (iv[1][2] >> 7); 170 | iv[1][2] = (iv[1][2] << 1) | (iv[1][3] >> 7); 171 | iv[1][3] = (iv[1][3] << 1) | (iv[2][0] >> 7); 172 | iv[2][0] = (iv[2][0] << 1) | (iv[2][1] >> 7); 173 | iv[2][1] = (iv[2][1] << 1) | (iv[2][2] >> 7); 174 | iv[2][2] = (iv[2][2] << 1) | (iv[2][3] >> 7); 175 | iv[2][3] = (iv[2][3] << 1) | (iv[3][0] >> 7); 176 | iv[3][0] = (iv[3][0] << 1) | (iv[3][1] >> 7); 177 | iv[3][1] = (iv[3][1] << 1) | (iv[3][2] >> 7); 178 | iv[3][2] = (iv[3][2] << 1) | (iv[3][3] >> 7); 179 | iv[3][3] = (iv[3][3] << 1) | ((outBuffer[k/8] >> (7-(k&7))) & 1); 180 | } 181 | } 182 | break; 183 | 184 | default: 185 | return BAD_CIPHER_STATE; 186 | } 187 | 188 | return 128*numBlocks; 189 | } 190 | 191 | /** 192 | * Encrypt data partitioned in octets, using RFC 2040-like padding. 193 | * 194 | * @param input data to be encrypted (octet sequence) 195 | * @param inputOctets input length in octets (not bits) 196 | * @param outBuffer encrypted output data 197 | * 198 | * @return length in octets (not bits) of the encrypted output buffer. 199 | */ 200 | int rijndael_padEncrypt(cipherInstance *cipher, keyInstance *key, 201 | BYTE *input, int inputOctets, BYTE *outBuffer) { 202 | int i, numBlocks, padLen; 203 | u_int8_t block[16], *iv, *cp; 204 | 205 | if (cipher == NULL || 206 | key == NULL || 207 | key->direction == DIR_DECRYPT) { 208 | return BAD_CIPHER_STATE; 209 | } 210 | if (input == NULL || inputOctets <= 0) { 211 | return 0; /* nothing to do */ 212 | } 213 | 214 | numBlocks = inputOctets/16; 215 | 216 | switch (cipher->mode) { 217 | case MODE_ECB: 218 | for (i = numBlocks; i > 0; i--) { 219 | rijndaelEncrypt(key->rk, key->Nr, input, outBuffer); 220 | input += 16; 221 | outBuffer += 16; 222 | } 223 | padLen = 16 - (inputOctets - 16*numBlocks); 224 | if (padLen <= 0 || padLen > 16) 225 | return BAD_CIPHER_STATE; 226 | memcpy(block, input, 16 - padLen); 227 | for (cp = block + 16 - padLen; cp < block + 16; cp++) 228 | *cp = padLen; 229 | rijndaelEncrypt(key->rk, key->Nr, block, outBuffer); 230 | break; 231 | 232 | case MODE_CBC: 233 | iv = cipher->IV; 234 | for (i = numBlocks; i > 0; i--) { 235 | ((u_int32_t*)block)[0] = ((u_int32_t*)input)[0] ^ ((u_int32_t*)iv)[0]; 236 | ((u_int32_t*)block)[1] = ((u_int32_t*)input)[1] ^ ((u_int32_t*)iv)[1]; 237 | ((u_int32_t*)block)[2] = ((u_int32_t*)input)[2] ^ ((u_int32_t*)iv)[2]; 238 | ((u_int32_t*)block)[3] = ((u_int32_t*)input)[3] ^ ((u_int32_t*)iv)[3]; 239 | rijndaelEncrypt(key->rk, key->Nr, block, outBuffer); 240 | iv = outBuffer; 241 | input += 16; 242 | outBuffer += 16; 243 | } 244 | padLen = 16 - (inputOctets - 16*numBlocks); 245 | if (padLen <= 0 || padLen > 16) 246 | return BAD_CIPHER_STATE; 247 | for (i = 0; i < 16 - padLen; i++) { 248 | block[i] = input[i] ^ iv[i]; 249 | } 250 | for (i = 16 - padLen; i < 16; i++) { 251 | block[i] = (BYTE)padLen ^ iv[i]; 252 | } 253 | rijndaelEncrypt(key->rk, key->Nr, block, outBuffer); 254 | break; 255 | 256 | default: 257 | return BAD_CIPHER_STATE; 258 | } 259 | 260 | return 16*(numBlocks + 1); 261 | } 262 | 263 | int rijndael_blockDecrypt(cipherInstance *cipher, keyInstance *key, 264 | BYTE *input, int inputLen, BYTE *outBuffer) { 265 | int i, k, numBlocks; 266 | u_int8_t block[16], iv[4][4]; 267 | 268 | if (cipher == NULL || 269 | key == NULL || 270 | (cipher->mode != MODE_CFB1 && key->direction == DIR_ENCRYPT)) { 271 | return BAD_CIPHER_STATE; 272 | } 273 | if (input == NULL || inputLen <= 0) { 274 | return 0; /* nothing to do */ 275 | } 276 | 277 | numBlocks = inputLen/128; 278 | 279 | switch (cipher->mode) { 280 | case MODE_ECB: 281 | for (i = numBlocks; i > 0; i--) { 282 | rijndaelDecrypt(key->rk, key->Nr, input, outBuffer); 283 | input += 16; 284 | outBuffer += 16; 285 | } 286 | break; 287 | 288 | case MODE_CBC: 289 | #if 1 /*STRICT_ALIGN */ 290 | memcpy(iv, cipher->IV, 16); 291 | #else 292 | *((u_int32_t*)iv[0]) = *((u_int32_t*)(cipher->IV )); 293 | *((u_int32_t*)iv[1]) = *((u_int32_t*)(cipher->IV+ 4)); 294 | *((u_int32_t*)iv[2]) = *((u_int32_t*)(cipher->IV+ 8)); 295 | *((u_int32_t*)iv[3]) = *((u_int32_t*)(cipher->IV+12)); 296 | #endif 297 | for (i = numBlocks; i > 0; i--) { 298 | rijndaelDecrypt(key->rk, key->Nr, input, block); 299 | ((u_int32_t*)block)[0] ^= *((u_int32_t*)iv[0]); 300 | ((u_int32_t*)block)[1] ^= *((u_int32_t*)iv[1]); 301 | ((u_int32_t*)block)[2] ^= *((u_int32_t*)iv[2]); 302 | ((u_int32_t*)block)[3] ^= *((u_int32_t*)iv[3]); 303 | #if 1 /*STRICT_ALIGN*/ 304 | memcpy(iv, input, 16); 305 | memcpy(outBuffer, block, 16); 306 | #else 307 | *((u_int32_t*)iv[0]) = ((u_int32_t*)input)[0]; ((u_int32_t*)outBuffer)[0] = ((u_int32_t*)block)[0]; 308 | *((u_int32_t*)iv[1]) = ((u_int32_t*)input)[1]; ((u_int32_t*)outBuffer)[1] = ((u_int32_t*)block)[1]; 309 | *((u_int32_t*)iv[2]) = ((u_int32_t*)input)[2]; ((u_int32_t*)outBuffer)[2] = ((u_int32_t*)block)[2]; 310 | *((u_int32_t*)iv[3]) = ((u_int32_t*)input)[3]; ((u_int32_t*)outBuffer)[3] = ((u_int32_t*)block)[3]; 311 | #endif 312 | input += 16; 313 | outBuffer += 16; 314 | } 315 | break; 316 | 317 | case MODE_CFB1: 318 | #if 1 /*STRICT_ALIGN */ 319 | memcpy(iv, cipher->IV, 16); 320 | #else 321 | *((u_int32_t*)iv[0]) = *((u_int32_t*)(cipher->IV)); 322 | *((u_int32_t*)iv[1]) = *((u_int32_t*)(cipher->IV+ 4)); 323 | *((u_int32_t*)iv[2]) = *((u_int32_t*)(cipher->IV+ 8)); 324 | *((u_int32_t*)iv[3]) = *((u_int32_t*)(cipher->IV+12)); 325 | #endif 326 | for (i = numBlocks; i > 0; i--) { 327 | for (k = 0; k < 128; k++) { 328 | *((u_int32_t*) block ) = *((u_int32_t*)iv[0]); 329 | *((u_int32_t*)(block+ 4)) = *((u_int32_t*)iv[1]); 330 | *((u_int32_t*)(block+ 8)) = *((u_int32_t*)iv[2]); 331 | *((u_int32_t*)(block+12)) = *((u_int32_t*)iv[3]); 332 | rijndaelEncrypt(key->ek, key->Nr, block, 333 | block); 334 | iv[0][0] = (iv[0][0] << 1) | (iv[0][1] >> 7); 335 | iv[0][1] = (iv[0][1] << 1) | (iv[0][2] >> 7); 336 | iv[0][2] = (iv[0][2] << 1) | (iv[0][3] >> 7); 337 | iv[0][3] = (iv[0][3] << 1) | (iv[1][0] >> 7); 338 | iv[1][0] = (iv[1][0] << 1) | (iv[1][1] >> 7); 339 | iv[1][1] = (iv[1][1] << 1) | (iv[1][2] >> 7); 340 | iv[1][2] = (iv[1][2] << 1) | (iv[1][3] >> 7); 341 | iv[1][3] = (iv[1][3] << 1) | (iv[2][0] >> 7); 342 | iv[2][0] = (iv[2][0] << 1) | (iv[2][1] >> 7); 343 | iv[2][1] = (iv[2][1] << 1) | (iv[2][2] >> 7); 344 | iv[2][2] = (iv[2][2] << 1) | (iv[2][3] >> 7); 345 | iv[2][3] = (iv[2][3] << 1) | (iv[3][0] >> 7); 346 | iv[3][0] = (iv[3][0] << 1) | (iv[3][1] >> 7); 347 | iv[3][1] = (iv[3][1] << 1) | (iv[3][2] >> 7); 348 | iv[3][2] = (iv[3][2] << 1) | (iv[3][3] >> 7); 349 | iv[3][3] = (iv[3][3] << 1) | ((input[k/8] >> (7-(k&7))) & 1); 350 | outBuffer[k/8] ^= (block[0] & 0x80) >> (k & 7); 351 | } 352 | } 353 | break; 354 | 355 | default: 356 | return BAD_CIPHER_STATE; 357 | } 358 | 359 | return 128*numBlocks; 360 | } 361 | 362 | int rijndael_padDecrypt(cipherInstance *cipher, keyInstance *key, 363 | BYTE *input, int inputOctets, BYTE *outBuffer) { 364 | int i, numBlocks, padLen; 365 | u_int8_t block[16]; 366 | u_int32_t iv[4]; 367 | 368 | if (cipher == NULL || 369 | key == NULL || 370 | key->direction == DIR_ENCRYPT) { 371 | return BAD_CIPHER_STATE; 372 | } 373 | if (input == NULL || inputOctets <= 0) { 374 | return 0; /* nothing to do */ 375 | } 376 | if (inputOctets % 16 != 0) { 377 | return BAD_DATA; 378 | } 379 | 380 | numBlocks = inputOctets/16; 381 | 382 | switch (cipher->mode) { 383 | case MODE_ECB: 384 | /* all blocks but last */ 385 | for (i = numBlocks - 1; i > 0; i--) { 386 | rijndaelDecrypt(key->rk, key->Nr, input, outBuffer); 387 | input += 16; 388 | outBuffer += 16; 389 | } 390 | /* last block */ 391 | rijndaelDecrypt(key->rk, key->Nr, input, block); 392 | padLen = block[15]; 393 | if (padLen >= 16) { 394 | return BAD_DATA; 395 | } 396 | for (i = 16 - padLen; i < 16; i++) { 397 | if (block[i] != padLen) { 398 | return BAD_DATA; 399 | } 400 | } 401 | memcpy(outBuffer, block, 16 - padLen); 402 | break; 403 | 404 | case MODE_CBC: 405 | memcpy(iv, cipher->IV, 16); 406 | /* all blocks but last */ 407 | for (i = numBlocks - 1; i > 0; i--) { 408 | rijndaelDecrypt(key->rk, key->Nr, input, block); 409 | ((u_int32_t*)block)[0] ^= iv[0]; 410 | ((u_int32_t*)block)[1] ^= iv[1]; 411 | ((u_int32_t*)block)[2] ^= iv[2]; 412 | ((u_int32_t*)block)[3] ^= iv[3]; 413 | memcpy(iv, input, 16); 414 | memcpy(outBuffer, block, 16); 415 | input += 16; 416 | outBuffer += 16; 417 | } 418 | /* last block */ 419 | rijndaelDecrypt(key->rk, key->Nr, input, block); 420 | ((u_int32_t*)block)[0] ^= iv[0]; 421 | ((u_int32_t*)block)[1] ^= iv[1]; 422 | ((u_int32_t*)block)[2] ^= iv[2]; 423 | ((u_int32_t*)block)[3] ^= iv[3]; 424 | padLen = block[15]; 425 | if (padLen <= 0 || padLen > 16) { 426 | return BAD_DATA; 427 | } 428 | for (i = 16 - padLen; i < 16; i++) { 429 | if (block[i] != padLen) { 430 | return BAD_DATA; 431 | } 432 | } 433 | memcpy(outBuffer, block, 16 - padLen); 434 | break; 435 | 436 | default: 437 | return BAD_CIPHER_STATE; 438 | } 439 | 440 | return 16*numBlocks - padLen; 441 | } 442 | -------------------------------------------------------------------------------- /sys/crypto/rijndael/rijndael-api-fst.h: -------------------------------------------------------------------------------- 1 | /* $FreeBSD$ */ 2 | /* $KAME: rijndael-api-fst.h,v 1.6 2001/05/27 00:23:23 itojun Exp $ */ 3 | 4 | /* 5 | * rijndael-api-fst.h v2.3 April '2000 6 | * 7 | * Optimised ANSI C code 8 | * 9 | */ 10 | 11 | #ifndef __RIJNDAEL_API_FST_H 12 | #define __RIJNDAEL_API_FST_H 13 | 14 | #include 15 | 16 | /* Generic Defines */ 17 | #define DIR_ENCRYPT 0 /* Are we encrpyting? */ 18 | #define DIR_DECRYPT 1 /* Are we decrpyting? */ 19 | #define MODE_ECB 1 /* Are we ciphering in ECB mode? */ 20 | #define MODE_CBC 2 /* Are we ciphering in CBC mode? */ 21 | #define MODE_CFB1 3 /* Are we ciphering in 1-bit CFB mode? */ 22 | #define BITSPERBLOCK 128 /* Default number of bits in a cipher block */ 23 | 24 | /* Error Codes */ 25 | #define BAD_KEY_DIR -1 /* Key direction is invalid, e.g., unknown value */ 26 | #define BAD_KEY_MAT -2 /* Key material not of correct length */ 27 | #define BAD_KEY_INSTANCE -3 /* Key passed is not valid */ 28 | #define BAD_CIPHER_MODE -4 /* Params struct passed to cipherInit invalid */ 29 | #define BAD_CIPHER_STATE -5 /* Cipher in wrong state (e.g., not initialized) */ 30 | #define BAD_BLOCK_LENGTH -6 31 | #define BAD_CIPHER_INSTANCE -7 32 | #define BAD_DATA -8 /* Data contents are invalid, e.g., invalid padding */ 33 | #define BAD_OTHER -9 /* Unknown error */ 34 | 35 | /* Algorithm-specific Defines */ 36 | #define RIJNDAEL_MAX_KEY_SIZE 64 /* # of ASCII char's needed to represent a key */ 37 | #define RIJNDAEL_MAX_IV_SIZE 16 /* # bytes needed to represent an IV */ 38 | 39 | /* Typedefs */ 40 | 41 | /* The structure for key information */ 42 | typedef struct { 43 | u_int8_t direction; /* Key used for encrypting or decrypting? */ 44 | int keyLen; /* Length of the key */ 45 | char keyMaterial[RIJNDAEL_MAX_KEY_SIZE+1]; /* Raw key data in ASCII, e.g., user input or KAT values */ 46 | int Nr; /* key-length-dependent number of rounds */ 47 | u_int32_t rk[4*(RIJNDAEL_MAXNR + 1)]; /* key schedule */ 48 | u_int32_t ek[4*(RIJNDAEL_MAXNR + 1)]; /* CFB1 key schedule (encryption only) */ 49 | } keyInstance; 50 | 51 | /* The structure for cipher information */ 52 | typedef struct { /* changed order of the components */ 53 | u_int8_t mode; /* MODE_ECB, MODE_CBC, or MODE_CFB1 */ 54 | u_int8_t IV[RIJNDAEL_MAX_IV_SIZE]; /* A possible Initialization Vector for ciphering */ 55 | } cipherInstance; 56 | 57 | /* Function prototypes */ 58 | 59 | int rijndael_makeKey(keyInstance *, u_int8_t, int, char *); 60 | 61 | int rijndael_cipherInit(cipherInstance *, u_int8_t, char *); 62 | 63 | int rijndael_blockEncrypt(cipherInstance *, keyInstance *, u_int8_t *, int, 64 | u_int8_t *); 65 | int rijndael_padEncrypt(cipherInstance *, keyInstance *, u_int8_t *, int, 66 | u_int8_t *); 67 | 68 | int rijndael_blockDecrypt(cipherInstance *, keyInstance *, u_int8_t *, int, 69 | u_int8_t *); 70 | int rijndael_padDecrypt(cipherInstance *, keyInstance *, u_int8_t *, int, 71 | u_int8_t *); 72 | 73 | #endif /* __RIJNDAEL_API_FST_H */ 74 | -------------------------------------------------------------------------------- /sys/crypto/rijndael/rijndael-api.c: -------------------------------------------------------------------------------- 1 | /* $KAME: rijndael.c,v 1.3 2003/08/28 14:20:22 itojun Exp $ */ 2 | 3 | /* 4 | * rijndael-alg-fst.c 5 | * 6 | * @version 3.0 (December 2000) 7 | * 8 | * Optimised ANSI C code for the Rijndael cipher (now AES) 9 | * 10 | * @author Vincent Rijmen 11 | * @author Antoon Bosselaers 12 | * @author Paulo Barreto 13 | * 14 | * This code is hereby placed in the public domain. 15 | * 16 | * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ''AS IS'' AND ANY EXPRESS 17 | * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE 20 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 23 | * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 24 | * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 25 | * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 26 | * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | */ 28 | 29 | #include 30 | __FBSDID("$FreeBSD$"); 31 | 32 | #include 33 | #ifdef _KERNEL 34 | #include 35 | #endif 36 | 37 | #include 38 | 39 | void 40 | rijndael_set_key(rijndael_ctx *ctx, const u_char *key, int bits) 41 | { 42 | 43 | ctx->Nr = rijndaelKeySetupEnc(ctx->ek, key, bits); 44 | rijndaelKeySetupDec(ctx->dk, key, bits); 45 | } 46 | 47 | void 48 | rijndael_decrypt(const rijndael_ctx *ctx, const u_char *src, u_char *dst) 49 | { 50 | 51 | rijndaelDecrypt(ctx->dk, ctx->Nr, src, dst); 52 | } 53 | 54 | void 55 | rijndael_encrypt(const rijndael_ctx *ctx, const u_char *src, u_char *dst) 56 | { 57 | 58 | rijndaelEncrypt(ctx->ek, ctx->Nr, src, dst); 59 | } 60 | -------------------------------------------------------------------------------- /sys/crypto/rijndael/rijndael.h: -------------------------------------------------------------------------------- 1 | /* $KAME: rijndael.h,v 1.6 2003/08/28 08:36:32 itojun Exp $ */ 2 | /* $FreeBSD$ */ 3 | 4 | /** 5 | * rijndael-alg-fst.h 6 | * 7 | * @version 3.0 (December 2000) 8 | * 9 | * Optimised ANSI C code for the Rijndael cipher (now AES) 10 | * 11 | * @author Vincent Rijmen 12 | * @author Antoon Bosselaers 13 | * @author Paulo Barreto 14 | * 15 | * This code is hereby placed in the public domain. 16 | * 17 | * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ''AS IS'' AND ANY EXPRESS 18 | * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 19 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE 21 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 24 | * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 25 | * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 26 | * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 27 | * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | */ 29 | 30 | #ifndef __RIJNDAEL_H 31 | #define __RIJNDAEL_H 32 | 33 | #define RIJNDAEL_MAXKC (256/32) 34 | #define RIJNDAEL_MAXKB (256/8) 35 | #define RIJNDAEL_MAXNR 14 36 | 37 | typedef struct { 38 | int decrypt; 39 | int Nr; /* key-length-dependent number of rounds */ 40 | uint32_t ek[4 * (RIJNDAEL_MAXNR + 1)]; /* encrypt key schedule */ 41 | uint32_t dk[4 * (RIJNDAEL_MAXNR + 1)]; /* decrypt key schedule */ 42 | } rijndael_ctx; 43 | 44 | void rijndael_set_key(rijndael_ctx *, const u_char *, int); 45 | void rijndael_decrypt(const rijndael_ctx *, const u_char *, u_char *); 46 | void rijndael_encrypt(const rijndael_ctx *, const u_char *, u_char *); 47 | 48 | int rijndaelKeySetupEnc(u_int32_t [/*4*(Nr+1)*/], const u_int8_t [], int); 49 | int rijndaelKeySetupDec(u_int32_t [/*4*(Nr+1)*/], const u_int8_t [], int); 50 | void rijndaelEncrypt(const u_int32_t [/*4*(Nr+1)*/], int, 51 | const u_int8_t[16], u_int8_t [16]); 52 | void rijndaelDecrypt(const u_int32_t [/*4*(Nr+1)*/], int, 53 | const u_int8_t [16], u_int8_t [16]); 54 | 55 | #endif /* __RIJNDAEL_H */ 56 | -------------------------------------------------------------------------------- /sys/crypto/rijndael/rijndael_local.h: -------------------------------------------------------------------------------- 1 | /* $KAME: rijndael_local.h,v 1.5 2003/08/28 08:37:24 itojun Exp $ */ 2 | /* $FreeBSD$ */ 3 | 4 | /* the file should not be used from outside */ 5 | typedef u_int8_t u8; 6 | typedef u_int16_t u16; 7 | typedef u_int32_t u32; 8 | -------------------------------------------------------------------------------- /sys/crypto/sha2/sha384.h: -------------------------------------------------------------------------------- 1 | /*- 2 | * Copyright 2005 Colin Percival 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions 7 | * are met: 8 | * 1. Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * 2. Redistributions in binary form must reproduce the above copyright 11 | * notice, this list of conditions and the following disclaimer in the 12 | * documentation and/or other materials provided with the distribution. 13 | * 14 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 | * SUCH DAMAGE. 25 | * 26 | * $FreeBSD$ 27 | */ 28 | 29 | #ifndef _SHA384_H_ 30 | #define _SHA384_H_ 31 | 32 | #ifndef _KERNEL 33 | #include 34 | #endif 35 | 36 | #define SHA384_BLOCK_LENGTH 128 37 | #define SHA384_DIGEST_LENGTH 48 38 | #define SHA384_DIGEST_STRING_LENGTH (SHA384_DIGEST_LENGTH * 2 + 1) 39 | 40 | typedef struct SHA384Context { 41 | uint64_t state[8]; 42 | uint64_t count[2]; 43 | uint8_t buf[SHA384_BLOCK_LENGTH]; 44 | } SHA384_CTX; 45 | 46 | __BEGIN_DECLS 47 | 48 | /* Ensure libmd symbols do not clash with libcrypto */ 49 | #ifndef SHA384_Init 50 | #define SHA384_Init _libmd_SHA384_Init 51 | #endif 52 | #ifndef SHA384_Update 53 | #define SHA384_Update _libmd_SHA384_Update 54 | #endif 55 | #ifndef SHA384_Final 56 | #define SHA384_Final _libmd_SHA384_Final 57 | #endif 58 | #ifndef SHA384_End 59 | #define SHA384_End _libmd_SHA384_End 60 | #endif 61 | #ifndef SHA384_File 62 | #define SHA384_File _libmd_SHA384_File 63 | #endif 64 | #ifndef SHA384_FileChunk 65 | #define SHA384_FileChunk _libmd_SHA384_FileChunk 66 | #endif 67 | #ifndef SHA384_Data 68 | #define SHA384_Data _libmd_SHA384_Data 69 | #endif 70 | 71 | #ifndef SHA384_version 72 | #define SHA384_version _libmd_SHA384_version 73 | #endif 74 | 75 | void SHA384_Init(SHA384_CTX *); 76 | void SHA384_Update(SHA384_CTX *, const void *, size_t); 77 | void SHA384_Final(unsigned char [SHA384_DIGEST_LENGTH], SHA384_CTX *); 78 | #ifndef _KERNEL 79 | char *SHA384_End(SHA384_CTX *, char *); 80 | char *SHA384_Data(const void *, unsigned int, char *); 81 | char *SHA384_File(const char *, char *); 82 | char *SHA384_FileChunk(const char *, char *, off_t, off_t); 83 | #endif 84 | 85 | __END_DECLS 86 | 87 | #endif /* !_SHA384_H_ */ 88 | -------------------------------------------------------------------------------- /sys/crypto/sha2/sha512.h: -------------------------------------------------------------------------------- 1 | /*- 2 | * Copyright 2005 Colin Percival 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions 7 | * are met: 8 | * 1. Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * 2. Redistributions in binary form must reproduce the above copyright 11 | * notice, this list of conditions and the following disclaimer in the 12 | * documentation and/or other materials provided with the distribution. 13 | * 14 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 | * SUCH DAMAGE. 25 | * 26 | * $FreeBSD$ 27 | */ 28 | 29 | #ifndef _SHA512_H_ 30 | #define _SHA512_H_ 31 | 32 | #ifndef _KERNEL 33 | #include 34 | #endif 35 | 36 | #define SHA512_BLOCK_LENGTH 128 37 | #define SHA512_DIGEST_LENGTH 64 38 | #define SHA512_DIGEST_STRING_LENGTH (SHA512_DIGEST_LENGTH * 2 + 1) 39 | 40 | typedef struct SHA512Context { 41 | uint64_t state[8]; 42 | uint64_t count[2]; 43 | uint8_t buf[SHA512_BLOCK_LENGTH]; 44 | } SHA512_CTX; 45 | 46 | __BEGIN_DECLS 47 | 48 | /* Ensure libmd symbols do not clash with libcrypto */ 49 | #ifndef SHA512_Init 50 | #define SHA512_Init _libmd_SHA512_Init 51 | #endif 52 | #ifndef SHA512_Update 53 | #define SHA512_Update _libmd_SHA512_Update 54 | #endif 55 | #ifndef SHA512_Final 56 | #define SHA512_Final _libmd_SHA512_Final 57 | #endif 58 | #ifndef SHA512_End 59 | #define SHA512_End _libmd_SHA512_End 60 | #endif 61 | #ifndef SHA512_File 62 | #define SHA512_File _libmd_SHA512_File 63 | #endif 64 | #ifndef SHA512_FileChunk 65 | #define SHA512_FileChunk _libmd_SHA512_FileChunk 66 | #endif 67 | #ifndef SHA512_Data 68 | #define SHA512_Data _libmd_SHA512_Data 69 | #endif 70 | 71 | #ifndef SHA512_Transform 72 | #define SHA512_Transform _libmd_SHA512_Transform 73 | #endif 74 | #ifndef SHA512_version 75 | #define SHA512_version _libmd_SHA512_version 76 | #endif 77 | 78 | void SHA512_Init(SHA512_CTX *); 79 | void SHA512_Update(SHA512_CTX *, const void *, size_t); 80 | void SHA512_Final(unsigned char [SHA512_DIGEST_LENGTH], SHA512_CTX *); 81 | #ifndef _KERNEL 82 | char *SHA512_End(SHA512_CTX *, char *); 83 | char *SHA512_Data(const void *, unsigned int, char *); 84 | char *SHA512_File(const char *, char *); 85 | char *SHA512_FileChunk(const char *, char *, off_t, off_t); 86 | #endif 87 | 88 | __END_DECLS 89 | 90 | #endif /* !_SHA512_H_ */ 91 | -------------------------------------------------------------------------------- /sys/crypto/sha2/sha512c.c: -------------------------------------------------------------------------------- 1 | /*- 2 | * Copyright 2005 Colin Percival 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions 7 | * are met: 8 | * 1. Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * 2. Redistributions in binary form must reproduce the above copyright 11 | * notice, this list of conditions and the following disclaimer in the 12 | * documentation and/or other materials provided with the distribution. 13 | * 14 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 | * SUCH DAMAGE. 25 | */ 26 | 27 | #include 28 | __FBSDID("$FreeBSD$"); 29 | 30 | #include 31 | #include 32 | 33 | #ifdef _KERNEL 34 | #include 35 | #else 36 | #include 37 | #endif 38 | 39 | #include "sha512.h" 40 | #include "sha384.h" 41 | 42 | #if BYTE_ORDER == BIG_ENDIAN 43 | 44 | /* Copy a vector of big-endian uint64_t into a vector of bytes */ 45 | #define be64enc_vect(dst, src, len) \ 46 | memcpy((void *)dst, (const void *)src, (size_t)len) 47 | 48 | /* Copy a vector of bytes into a vector of big-endian uint64_t */ 49 | #define be64dec_vect(dst, src, len) \ 50 | memcpy((void *)dst, (const void *)src, (size_t)len) 51 | 52 | #else /* BYTE_ORDER != BIG_ENDIAN */ 53 | 54 | /* 55 | * Encode a length len/4 vector of (uint64_t) into a length len vector of 56 | * (unsigned char) in big-endian form. Assumes len is a multiple of 8. 57 | */ 58 | static void 59 | be64enc_vect(unsigned char *dst, const uint64_t *src, size_t len) 60 | { 61 | size_t i; 62 | 63 | for (i = 0; i < len / 8; i++) 64 | be64enc(dst + i * 8, src[i]); 65 | } 66 | 67 | /* 68 | * Decode a big-endian length len vector of (unsigned char) into a length 69 | * len/4 vector of (uint64_t). Assumes len is a multiple of 8. 70 | */ 71 | static void 72 | be64dec_vect(uint64_t *dst, const unsigned char *src, size_t len) 73 | { 74 | size_t i; 75 | 76 | for (i = 0; i < len / 8; i++) 77 | dst[i] = be64dec(src + i * 8); 78 | } 79 | 80 | #endif /* BYTE_ORDER != BIG_ENDIAN */ 81 | 82 | /* Elementary functions used by SHA512 */ 83 | #define Ch(x, y, z) ((x & (y ^ z)) ^ z) 84 | #define Maj(x, y, z) ((x & (y | z)) | (y & z)) 85 | #define SHR(x, n) (x >> n) 86 | #define ROTR(x, n) ((x >> n) | (x << (64 - n))) 87 | #define S0(x) (ROTR(x, 28) ^ ROTR(x, 34) ^ ROTR(x, 39)) 88 | #define S1(x) (ROTR(x, 14) ^ ROTR(x, 18) ^ ROTR(x, 41)) 89 | #define s0(x) (ROTR(x, 1) ^ ROTR(x, 8) ^ SHR(x, 7)) 90 | #define s1(x) (ROTR(x, 19) ^ ROTR(x, 61) ^ SHR(x, 6)) 91 | 92 | /* SHA512 round function */ 93 | #define RND(a, b, c, d, e, f, g, h, k) \ 94 | t0 = h + S1(e) + Ch(e, f, g) + k; \ 95 | t1 = S0(a) + Maj(a, b, c); \ 96 | d += t0; \ 97 | h = t0 + t1; 98 | 99 | /* Adjusted round function for rotating state */ 100 | #define RNDr(S, W, i, k) \ 101 | RND(S[(80 - i) % 8], S[(81 - i) % 8], \ 102 | S[(82 - i) % 8], S[(83 - i) % 8], \ 103 | S[(84 - i) % 8], S[(85 - i) % 8], \ 104 | S[(86 - i) % 8], S[(87 - i) % 8], \ 105 | W[i] + k) 106 | 107 | /* 108 | * SHA512 block compression function. The 512-bit state is transformed via 109 | * the 512-bit input block to produce a new state. 110 | */ 111 | static void 112 | SHA512_Transform(uint64_t * state, const unsigned char block[SHA512_BLOCK_LENGTH]) 113 | { 114 | uint64_t W[80]; 115 | uint64_t S[8]; 116 | uint64_t t0, t1; 117 | int i; 118 | 119 | /* 1. Prepare message schedule W. */ 120 | be64dec_vect(W, block, SHA512_BLOCK_LENGTH); 121 | for (i = 16; i < 80; i++) 122 | W[i] = s1(W[i - 2]) + W[i - 7] + s0(W[i - 15]) + W[i - 16]; 123 | 124 | /* 2. Initialize working variables. */ 125 | memcpy(S, state, SHA512_DIGEST_LENGTH); 126 | 127 | /* 3. Mix. */ 128 | RNDr(S, W, 0, 0x428a2f98d728ae22ULL); 129 | RNDr(S, W, 1, 0x7137449123ef65cdULL); 130 | RNDr(S, W, 2, 0xb5c0fbcfec4d3b2fULL); 131 | RNDr(S, W, 3, 0xe9b5dba58189dbbcULL); 132 | RNDr(S, W, 4, 0x3956c25bf348b538ULL); 133 | RNDr(S, W, 5, 0x59f111f1b605d019ULL); 134 | RNDr(S, W, 6, 0x923f82a4af194f9bULL); 135 | RNDr(S, W, 7, 0xab1c5ed5da6d8118ULL); 136 | RNDr(S, W, 8, 0xd807aa98a3030242ULL); 137 | RNDr(S, W, 9, 0x12835b0145706fbeULL); 138 | RNDr(S, W, 10, 0x243185be4ee4b28cULL); 139 | RNDr(S, W, 11, 0x550c7dc3d5ffb4e2ULL); 140 | RNDr(S, W, 12, 0x72be5d74f27b896fULL); 141 | RNDr(S, W, 13, 0x80deb1fe3b1696b1ULL); 142 | RNDr(S, W, 14, 0x9bdc06a725c71235ULL); 143 | RNDr(S, W, 15, 0xc19bf174cf692694ULL); 144 | RNDr(S, W, 16, 0xe49b69c19ef14ad2ULL); 145 | RNDr(S, W, 17, 0xefbe4786384f25e3ULL); 146 | RNDr(S, W, 18, 0x0fc19dc68b8cd5b5ULL); 147 | RNDr(S, W, 19, 0x240ca1cc77ac9c65ULL); 148 | RNDr(S, W, 20, 0x2de92c6f592b0275ULL); 149 | RNDr(S, W, 21, 0x4a7484aa6ea6e483ULL); 150 | RNDr(S, W, 22, 0x5cb0a9dcbd41fbd4ULL); 151 | RNDr(S, W, 23, 0x76f988da831153b5ULL); 152 | RNDr(S, W, 24, 0x983e5152ee66dfabULL); 153 | RNDr(S, W, 25, 0xa831c66d2db43210ULL); 154 | RNDr(S, W, 26, 0xb00327c898fb213fULL); 155 | RNDr(S, W, 27, 0xbf597fc7beef0ee4ULL); 156 | RNDr(S, W, 28, 0xc6e00bf33da88fc2ULL); 157 | RNDr(S, W, 29, 0xd5a79147930aa725ULL); 158 | RNDr(S, W, 30, 0x06ca6351e003826fULL); 159 | RNDr(S, W, 31, 0x142929670a0e6e70ULL); 160 | RNDr(S, W, 32, 0x27b70a8546d22ffcULL); 161 | RNDr(S, W, 33, 0x2e1b21385c26c926ULL); 162 | RNDr(S, W, 34, 0x4d2c6dfc5ac42aedULL); 163 | RNDr(S, W, 35, 0x53380d139d95b3dfULL); 164 | RNDr(S, W, 36, 0x650a73548baf63deULL); 165 | RNDr(S, W, 37, 0x766a0abb3c77b2a8ULL); 166 | RNDr(S, W, 38, 0x81c2c92e47edaee6ULL); 167 | RNDr(S, W, 39, 0x92722c851482353bULL); 168 | RNDr(S, W, 40, 0xa2bfe8a14cf10364ULL); 169 | RNDr(S, W, 41, 0xa81a664bbc423001ULL); 170 | RNDr(S, W, 42, 0xc24b8b70d0f89791ULL); 171 | RNDr(S, W, 43, 0xc76c51a30654be30ULL); 172 | RNDr(S, W, 44, 0xd192e819d6ef5218ULL); 173 | RNDr(S, W, 45, 0xd69906245565a910ULL); 174 | RNDr(S, W, 46, 0xf40e35855771202aULL); 175 | RNDr(S, W, 47, 0x106aa07032bbd1b8ULL); 176 | RNDr(S, W, 48, 0x19a4c116b8d2d0c8ULL); 177 | RNDr(S, W, 49, 0x1e376c085141ab53ULL); 178 | RNDr(S, W, 50, 0x2748774cdf8eeb99ULL); 179 | RNDr(S, W, 51, 0x34b0bcb5e19b48a8ULL); 180 | RNDr(S, W, 52, 0x391c0cb3c5c95a63ULL); 181 | RNDr(S, W, 53, 0x4ed8aa4ae3418acbULL); 182 | RNDr(S, W, 54, 0x5b9cca4f7763e373ULL); 183 | RNDr(S, W, 55, 0x682e6ff3d6b2b8a3ULL); 184 | RNDr(S, W, 56, 0x748f82ee5defb2fcULL); 185 | RNDr(S, W, 57, 0x78a5636f43172f60ULL); 186 | RNDr(S, W, 58, 0x84c87814a1f0ab72ULL); 187 | RNDr(S, W, 59, 0x8cc702081a6439ecULL); 188 | RNDr(S, W, 60, 0x90befffa23631e28ULL); 189 | RNDr(S, W, 61, 0xa4506cebde82bde9ULL); 190 | RNDr(S, W, 62, 0xbef9a3f7b2c67915ULL); 191 | RNDr(S, W, 63, 0xc67178f2e372532bULL); 192 | RNDr(S, W, 64, 0xca273eceea26619cULL); 193 | RNDr(S, W, 65, 0xd186b8c721c0c207ULL); 194 | RNDr(S, W, 66, 0xeada7dd6cde0eb1eULL); 195 | RNDr(S, W, 67, 0xf57d4f7fee6ed178ULL); 196 | RNDr(S, W, 68, 0x06f067aa72176fbaULL); 197 | RNDr(S, W, 69, 0x0a637dc5a2c898a6ULL); 198 | RNDr(S, W, 70, 0x113f9804bef90daeULL); 199 | RNDr(S, W, 71, 0x1b710b35131c471bULL); 200 | RNDr(S, W, 72, 0x28db77f523047d84ULL); 201 | RNDr(S, W, 73, 0x32caab7b40c72493ULL); 202 | RNDr(S, W, 74, 0x3c9ebe0a15c9bebcULL); 203 | RNDr(S, W, 75, 0x431d67c49c100d4cULL); 204 | RNDr(S, W, 76, 0x4cc5d4becb3e42b6ULL); 205 | RNDr(S, W, 77, 0x597f299cfc657e2aULL); 206 | RNDr(S, W, 78, 0x5fcb6fab3ad6faecULL); 207 | RNDr(S, W, 79, 0x6c44198c4a475817ULL); 208 | 209 | /* 4. Mix local working variables into global state */ 210 | for (i = 0; i < 8; i++) 211 | state[i] += S[i]; 212 | } 213 | 214 | static unsigned char PAD[SHA512_BLOCK_LENGTH] = { 215 | 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 216 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 217 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 218 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 219 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 220 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 221 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 222 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 223 | }; 224 | 225 | /* Add padding and terminating bit-count. */ 226 | static void 227 | SHA512_Pad(SHA512_CTX * ctx) 228 | { 229 | unsigned char len[16]; 230 | uint64_t r, plen; 231 | 232 | /* 233 | * Convert length to a vector of bytes -- we do this now rather 234 | * than later because the length will change after we pad. 235 | */ 236 | be64enc_vect(len, ctx->count, 16); 237 | 238 | /* Add 1--128 bytes so that the resulting length is 112 mod 128 */ 239 | r = (ctx->count[1] >> 3) & 0x7f; 240 | plen = (r < 112) ? (112 - r) : (240 - r); 241 | SHA512_Update(ctx, PAD, (size_t)plen); 242 | 243 | /* Add the terminating bit-count */ 244 | SHA512_Update(ctx, len, 16); 245 | } 246 | 247 | /* SHA-512 initialization. Begins a SHA-512 operation. */ 248 | void 249 | SHA512_Init(SHA512_CTX * ctx) 250 | { 251 | 252 | /* Zero bits processed so far */ 253 | ctx->count[0] = ctx->count[1] = 0; 254 | 255 | /* Magic initialization constants */ 256 | ctx->state[0] = 0x6a09e667f3bcc908ULL; 257 | ctx->state[1] = 0xbb67ae8584caa73bULL; 258 | ctx->state[2] = 0x3c6ef372fe94f82bULL; 259 | ctx->state[3] = 0xa54ff53a5f1d36f1ULL; 260 | ctx->state[4] = 0x510e527fade682d1ULL; 261 | ctx->state[5] = 0x9b05688c2b3e6c1fULL; 262 | ctx->state[6] = 0x1f83d9abfb41bd6bULL; 263 | ctx->state[7] = 0x5be0cd19137e2179ULL; 264 | } 265 | 266 | /* Add bytes into the hash */ 267 | void 268 | SHA512_Update(SHA512_CTX * ctx, const void *in, size_t len) 269 | { 270 | uint64_t bitlen[2]; 271 | uint64_t r; 272 | const unsigned char *src = in; 273 | 274 | /* Number of bytes left in the buffer from previous updates */ 275 | r = (ctx->count[1] >> 3) & 0x7f; 276 | 277 | /* Convert the length into a number of bits */ 278 | bitlen[1] = ((uint64_t)len) << 3; 279 | bitlen[0] = ((uint64_t)len) >> 61; 280 | 281 | /* Update number of bits */ 282 | if ((ctx->count[1] += bitlen[1]) < bitlen[1]) 283 | ctx->count[0]++; 284 | ctx->count[0] += bitlen[0]; 285 | 286 | /* Handle the case where we don't need to perform any transforms */ 287 | if (len < SHA512_BLOCK_LENGTH - r) { 288 | memcpy(&ctx->buf[r], src, len); 289 | return; 290 | } 291 | 292 | /* Finish the current block */ 293 | memcpy(&ctx->buf[r], src, SHA512_BLOCK_LENGTH - r); 294 | SHA512_Transform(ctx->state, ctx->buf); 295 | src += SHA512_BLOCK_LENGTH - r; 296 | len -= SHA512_BLOCK_LENGTH - r; 297 | 298 | /* Perform complete blocks */ 299 | while (len >= SHA512_BLOCK_LENGTH) { 300 | SHA512_Transform(ctx->state, src); 301 | src += SHA512_BLOCK_LENGTH; 302 | len -= SHA512_BLOCK_LENGTH; 303 | } 304 | 305 | /* Copy left over data into buffer */ 306 | memcpy(ctx->buf, src, len); 307 | } 308 | 309 | /* 310 | * SHA-512 finalization. Pads the input data, exports the hash value, 311 | * and clears the context state. 312 | */ 313 | void 314 | SHA512_Final(unsigned char digest[SHA512_DIGEST_LENGTH], SHA512_CTX * ctx) 315 | { 316 | 317 | /* Add padding */ 318 | SHA512_Pad(ctx); 319 | 320 | /* Write the hash */ 321 | be64enc_vect(digest, ctx->state, SHA512_DIGEST_LENGTH); 322 | 323 | /* Clear the context state */ 324 | memset((void *)ctx, 0, sizeof(*ctx)); 325 | } 326 | 327 | /*** SHA-384: *********************************************************/ 328 | /* 329 | * the SHA384 and SHA512 transforms are identical, so SHA384 is skipped 330 | */ 331 | 332 | /* SHA-384 initialization. Begins a SHA-384 operation. */ 333 | void 334 | SHA384_Init(SHA384_CTX * ctx) 335 | { 336 | 337 | /* Zero bits processed so far */ 338 | ctx->count[0] = ctx->count[1] = 0; 339 | 340 | /* Magic initialization constants */ 341 | ctx->state[0] = 0xcbbb9d5dc1059ed8ULL; 342 | ctx->state[1] = 0x629a292a367cd507ULL; 343 | ctx->state[2] = 0x9159015a3070dd17ULL; 344 | ctx->state[3] = 0x152fecd8f70e5939ULL; 345 | ctx->state[4] = 0x67332667ffc00b31ULL; 346 | ctx->state[5] = 0x8eb44a8768581511ULL; 347 | ctx->state[6] = 0xdb0c2e0d64f98fa7ULL; 348 | ctx->state[7] = 0x47b5481dbefa4fa4ULL; 349 | } 350 | 351 | /* Add bytes into the SHA-384 hash */ 352 | void 353 | SHA384_Update(SHA384_CTX * ctx, const void *in, size_t len) 354 | { 355 | 356 | SHA512_Update((SHA512_CTX *)ctx, in, len); 357 | } 358 | 359 | /* 360 | * SHA-384 finalization. Pads the input data, exports the hash value, 361 | * and clears the context state. 362 | */ 363 | void 364 | SHA384_Final(unsigned char digest[SHA384_DIGEST_LENGTH], SHA384_CTX * ctx) 365 | { 366 | 367 | /* Add padding */ 368 | SHA512_Pad((SHA512_CTX *)ctx); 369 | 370 | /* Write the hash */ 371 | be64enc_vect(digest, ctx->state, SHA384_DIGEST_LENGTH); 372 | 373 | /* Clear the context state */ 374 | memset((void *)ctx, 0, sizeof(*ctx)); 375 | } 376 | 377 | #ifdef WEAK_REFS 378 | /* When building libmd, provide weak references. Note: this is not 379 | activated in the context of compiling these sources for internal 380 | use in libcrypt. 381 | */ 382 | #undef SHA512_Init 383 | __weak_reference(_libmd_SHA512_Init, SHA512_Init); 384 | #undef SHA512_Update 385 | __weak_reference(_libmd_SHA512_Update, SHA512_Update); 386 | #undef SHA512_Final 387 | __weak_reference(_libmd_SHA512_Final, SHA512_Final); 388 | #undef SHA512_Transform 389 | __weak_reference(_libmd_SHA512_Transform, SHA512_Transform); 390 | 391 | #undef SHA384_Init 392 | __weak_reference(_libmd_SHA384_Init, SHA384_Init); 393 | #undef SHA384_Update 394 | __weak_reference(_libmd_SHA384_Update, SHA384_Update); 395 | #undef SHA384_Final 396 | __weak_reference(_libmd_SHA384_Final, SHA384_Final); 397 | #endif 398 | -------------------------------------------------------------------------------- /sys/fs/pefs/pefs.h: -------------------------------------------------------------------------------- 1 | /*- 2 | * Copyright (c) 2009 Gleb Kurtsou 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions 7 | * are met: 8 | * 1. Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * 2. Redistributions in binary form must reproduce the above copyright 11 | * notice, this list of conditions and the following disclaimer in the 12 | * documentation and/or other materials provided with the distribution. 13 | * 14 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 | * SUCH DAMAGE. 25 | * 26 | * $FreeBSD$ 27 | */ 28 | 29 | #define PEFS_SECTOR_SIZE 4096 30 | #define PEFS_SECTOR_MASK (PEFS_SECTOR_SIZE - 1) 31 | 32 | #define PEFS_ALG_INVALID 0 33 | #define PEFS_ALG_AES_XTS 4 34 | #define PEFS_ALG_CAMELLIA_XTS 5 35 | 36 | #define PEFS_TWEAK_SIZE 8 37 | #define PEFS_KEY_BITS 512 38 | #define PEFS_KEY_SIZE (PEFS_KEY_BITS / 8) 39 | #define PEFS_KEYID_SIZE 8 40 | #define PEFS_NAME_CSUM_SIZE 8 41 | #define PEFS_NAME_BLOCK_SIZE 16 42 | 43 | struct pefs_xkey { 44 | uint32_t pxk_index; 45 | uint32_t pxk_alg; 46 | uint32_t pxk_keybits; 47 | char pxk_keyid[PEFS_KEYID_SIZE]; 48 | char pxk_key[PEFS_KEY_SIZE]; 49 | }; 50 | 51 | #ifdef _IO 52 | #define PEFS_GETKEY _IOWR('p', 0, struct pefs_xkey) 53 | #define PEFS_ADDKEY _IOWR('p', 1, struct pefs_xkey) 54 | #define PEFS_SETKEY _IOWR('p', 2, struct pefs_xkey) 55 | #define PEFS_DELKEY _IOWR('p', 3, struct pefs_xkey) 56 | #define PEFS_FLUSHKEYS _IO('p', 4) 57 | #define PEFS_GETNODEKEY _IOWR('p', 5, struct pefs_xkey) 58 | #endif 59 | 60 | #ifdef _KERNEL 61 | 62 | #define PEFS_NAME_NTOP_SIZE(a) (((a) * 4 + 2)/3) 63 | #define PEFS_NAME_PTON_SIZE(a) (((a) * 3)/4) 64 | 65 | #ifdef PEFS_DEBUG 66 | #define PEFSDEBUG(format, args...) printf(format ,## args) 67 | #else 68 | #define PEFSDEBUG(format, args...) do { } while (0) 69 | #endif /* PEFS_DEBUG */ 70 | 71 | struct pefs_alg; 72 | struct pefs_ctx; 73 | struct pefs_dircache; 74 | struct pefs_dircache_pool; 75 | struct vfsconf; 76 | 77 | TAILQ_HEAD(pefs_key_head, pefs_key); 78 | 79 | struct pefs_key { 80 | TAILQ_ENTRY(pefs_key) pk_entry; 81 | volatile u_int pk_refcnt; 82 | const struct pefs_alg *pk_alg; 83 | struct pefs_ctx *pk_name_csum_ctx; 84 | struct pefs_ctx *pk_name_ctx; 85 | struct pefs_ctx *pk_tweak_ctx; 86 | struct pefs_ctx *pk_data_ctx; 87 | struct mtx *pk_entry_lock; 88 | int pk_algid; 89 | int pk_keybits; 90 | char pk_keyid[PEFS_KEYID_SIZE]; 91 | }; 92 | 93 | struct pefs_tkey { 94 | struct pefs_key *ptk_key; 95 | char ptk_tweak[PEFS_TWEAK_SIZE]; 96 | }; 97 | 98 | #define PN_HASKEY 0x000001 99 | #define PN_WANTRECYCLE 0x000100 100 | #define PN_LOCKBUF_SMALL 0x001000 101 | #define PN_LOCKBUF_LARGE 0x002000 102 | 103 | struct pefs_node { 104 | LIST_ENTRY(pefs_node) pn_listentry; 105 | struct vnode *pn_lowervp; 106 | struct vnode *pn_lowervp_dead; 107 | struct vnode *pn_vnode; 108 | struct pefs_dircache *pn_dircache; 109 | void *pn_buf_small; 110 | void *pn_buf_large; 111 | int pn_flags; 112 | volatile u_int pn_rename_xlock; 113 | struct pefs_tkey pn_tkey; 114 | }; 115 | 116 | #define PM_ROOT_CANRECURSE 0x01 117 | #define PM_DIRCACHE 0x02 118 | #define PM_ASYNCRECLAIM 0x04 119 | 120 | struct pefs_mount { 121 | struct mount *pm_lowervfs; 122 | struct vnode *pm_rootvp; 123 | struct mtx pm_keys_lock; 124 | struct pefs_key_head pm_keys; 125 | struct pefs_dircache_pool *pm_dircache_pool; 126 | int pm_flags; 127 | }; 128 | 129 | struct pefs_chunk { 130 | size_t pc_size; 131 | size_t pc_capacity; 132 | void *pc_base; 133 | int pc_nodebuf; 134 | struct iovec pc_iov; 135 | struct uio pc_uio; 136 | }; 137 | 138 | int pefs_init(struct vfsconf *vfsp); 139 | int pefs_uninit(struct vfsconf *vfsp); 140 | void pefs_crypto_init(void); 141 | void pefs_crypto_uninit(void); 142 | 143 | void pefs_zone_dtor_bzero(void *mem, int size, void *arg); 144 | void pefs_zone_fini_bzero(void *mem, int size); 145 | 146 | int pefs_node_get_nokey(struct mount *mp, struct vnode *lvp, 147 | struct vnode **vpp); 148 | int pefs_node_get_haskey(struct mount *mp, struct vnode *lvp, 149 | struct vnode **vpp, struct pefs_tkey *ptk); 150 | int pefs_node_get_lookupkey(struct mount *mp, struct vnode *lvp, 151 | struct vnode **vpp, struct ucred *cred); 152 | void pefs_node_asyncfree(struct pefs_node *xp); 153 | struct pefs_key *pefs_node_key(struct pefs_node *pn); 154 | void pefs_node_buf_free(struct pefs_node *pn); 155 | 156 | struct pefs_ctx *pefs_ctx_get(void); 157 | void pefs_ctx_free(struct pefs_ctx *ctx); 158 | 159 | struct pefs_key *pefs_key_get(int alg, int keybits, const char *key, 160 | const char *keyid); 161 | struct pefs_key *pefs_key_ref(struct pefs_key *pk); 162 | void pefs_key_release(struct pefs_key *pk); 163 | 164 | struct pefs_key *pefs_key_lookup(struct pefs_mount *pm, char *keyid); 165 | int pefs_key_add(struct pefs_mount *pm, int index, struct pefs_key *pk); 166 | void pefs_key_remove(struct pefs_mount *pm, struct pefs_key *pk); 167 | int pefs_key_remove_all(struct pefs_mount *pm); 168 | 169 | void pefs_data_encrypt(struct pefs_tkey *ptk, off_t offset, 170 | struct pefs_chunk *pc); 171 | void pefs_data_decrypt(struct pefs_tkey *ptk, off_t offset, 172 | struct pefs_chunk *pc); 173 | 174 | int pefs_name_encrypt(struct pefs_ctx *ctx, struct pefs_tkey *ptk, 175 | const char *plain, size_t plain_len, char *enc, size_t enc_size); 176 | int pefs_name_decrypt(struct pefs_ctx *ctx, struct pefs_key *pk, 177 | struct pefs_tkey *ptk, const char *enc, size_t enc_len, char *plain, 178 | size_t plain_size); 179 | 180 | int pefs_name_ntop(u_char const *src, size_t srclength, char *target, 181 | size_t targsize); 182 | int pefs_name_pton(char const *src, size_t srclen, u_char *target, 183 | size_t targsize); 184 | 185 | void pefs_chunk_create(struct pefs_chunk *pc, struct pefs_node *pn, 186 | size_t size); 187 | void pefs_chunk_restore(struct pefs_chunk* pc); 188 | void pefs_chunk_free(struct pefs_chunk* pc, struct pefs_node *pn); 189 | void pefs_chunk_zero(struct pefs_chunk *pc); 190 | int pefs_chunk_copy(struct pefs_chunk *pc, size_t skip, struct uio *uio); 191 | void pefs_chunk_setsize(struct pefs_chunk *pc, size_t size); 192 | struct uio *pefs_chunk_uio(struct pefs_chunk *pc, off_t uio_offset, 193 | enum uio_rw uio_rw); 194 | 195 | #ifdef DIAGNOSTIC 196 | struct vnode *pefs_checkvp(struct vnode *vp, char *fil, int lno); 197 | #endif 198 | 199 | #ifdef SYSCTL_DECL 200 | SYSCTL_DECL(_vfs_pefs); 201 | #endif 202 | 203 | #ifdef MALLOC_DECLARE 204 | MALLOC_DECLARE(M_PEFSBUF); 205 | MALLOC_DECLARE(M_PEFSHASH); 206 | #endif 207 | 208 | extern struct vop_vector pefs_vnodeops; 209 | 210 | static __inline struct pefs_mount * 211 | VFS_TO_PEFS(struct mount *mp) 212 | { 213 | MPASS(mp != NULL && mp->mnt_data != NULL); 214 | return ((struct pefs_mount *)(mp->mnt_data)); 215 | } 216 | 217 | static __inline struct pefs_node * 218 | VP_TO_PN(struct vnode *vp) 219 | { 220 | MPASS(vp != NULL && vp->v_data != NULL); 221 | return ((struct pefs_node *)vp->v_data); 222 | } 223 | 224 | static __inline struct vnode * 225 | PN_TO_VP(struct pefs_node *pn) 226 | { 227 | MPASS(pn != NULL && pn->pn_vnode != NULL); 228 | return (pn->pn_vnode); 229 | } 230 | 231 | static __inline struct vnode * 232 | PEFS_LOWERVP(struct vnode *vp) 233 | { 234 | struct vnode *lvp; 235 | 236 | MPASS(vp != NULL); 237 | #ifdef DIAGNOSTIC 238 | pefs_checkvp((vp), __FILE__, __LINE__); 239 | #endif 240 | lvp = VP_TO_PN(vp)->pn_lowervp; 241 | MPASS(lvp != NULL); 242 | return (lvp); 243 | } 244 | 245 | static __inline void ** 246 | pefs_node_buf(struct pefs_node *pn, int flag) 247 | { 248 | MPASS(flag == PN_LOCKBUF_SMALL || flag == PN_LOCKBUF_LARGE); 249 | if (flag == PN_LOCKBUF_SMALL) 250 | return (&pn->pn_buf_small); 251 | else 252 | return (&pn->pn_buf_large); 253 | } 254 | 255 | static __inline struct pefs_key * 256 | pefs_rootkey(struct pefs_mount *pm) 257 | { 258 | struct pefs_key *pk; 259 | 260 | mtx_lock(&pm->pm_keys_lock); 261 | pk = TAILQ_FIRST(&pm->pm_keys); 262 | mtx_unlock(&pm->pm_keys_lock); 263 | 264 | return (pk); 265 | } 266 | 267 | static __inline int 268 | pefs_no_keys(struct vnode *vp) 269 | { 270 | return (!(VP_TO_PN(vp)->pn_flags & PN_HASKEY) && 271 | pefs_rootkey(VFS_TO_PEFS(vp->v_mount)) == NULL); 272 | } 273 | 274 | static __inline uint32_t 275 | pefs_hash_mixptr(void *ptr) 276 | { 277 | uintptr_t h = (uintptr_t)ptr; 278 | 279 | h = (~h) + (h << 18); 280 | h = h ^ (h >> 31); 281 | h = h * 21; 282 | h = h ^ (h >> 11); 283 | h = h + (h << 6); 284 | h = h ^ (h >> 22); 285 | return (h); 286 | } 287 | 288 | #endif /* _KERNEL */ 289 | -------------------------------------------------------------------------------- /sys/fs/pefs/pefs_aesni.c: -------------------------------------------------------------------------------- 1 | /*- 2 | * Copyright (c) 2010 Konstantin Belousov 3 | * Copyright (c) 2010 Pawel Jakub Dawidek 4 | * All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without 7 | * modification, are permitted provided that the following conditions 8 | * are met: 9 | * 1. Redistributions of source code must retain the above copyright 10 | * notice, this list of conditions and the following disclaimer. 11 | * 2. Redistributions in binary form must reproduce the above copyright 12 | * notice, this list of conditions and the following disclaimer in the 13 | * documentation and/or other materials provided with the distribution. 14 | * 15 | * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND 16 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE 19 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 | * SUCH DAMAGE. 26 | */ 27 | 28 | #include 29 | __FBSDID("$FreeBSD$"); 30 | 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include 40 | #include 41 | #include 42 | 43 | #include 44 | 45 | #define AESNI_ENABLE_ENV "vfs.pefs.aesni_enable" 46 | 47 | DPCPU_DEFINE(struct fpu_kern_ctx *, pefs_aesni_fpu); 48 | 49 | #if __FreeBSD_version < 900503 50 | static struct fpu_kern_ctx * 51 | fpu_kern_alloc_ctx(int flags __unused) 52 | { 53 | struct fpu_kern_ctx *ctx; 54 | 55 | ctx = malloc(sizeof(*ctx), M_TEMP, M_WAITOK | M_ZERO); 56 | return (ctx); 57 | } 58 | 59 | static void 60 | fpu_kern_free_ctx(struct fpu_kern_ctx *ctx) 61 | { 62 | free(ctx, M_TEMP); 63 | } 64 | #endif 65 | 66 | #if __FreeBSD_version < 902507 67 | static inline uintptr_t pefs_compat_atomic_swap_ptr(volatile void *p, uintptr_t v) 68 | { 69 | uintptr_t expected; 70 | 71 | while (1) { 72 | expected = *(volatile uintptr_t *)(p); 73 | if (atomic_cmpset_ptr(p, expected, v)) 74 | return (expected); 75 | } 76 | } 77 | #define atomic_swap_ptr(p, v) pefs_compat_atomic_swap_ptr((p), (v)) 78 | #endif 79 | 80 | static int 81 | pefs_aesni_keysetup(const struct pefs_session *xses, 82 | struct pefs_ctx *xctx, const uint8_t *key, uint32_t keybits) 83 | { 84 | const struct pefs_aesni_ses *ses = &xses->o.ps_aesni; 85 | struct pefs_aesni_ctx *ctx = &xctx->o.pctx_aesni; 86 | struct fpu_kern_ctx *tmpctx = NULL; 87 | 88 | switch (keybits) { 89 | case 128: 90 | ctx->rounds = AES128_ROUNDS; 91 | break; 92 | case 192: 93 | ctx->rounds = AES192_ROUNDS; 94 | break; 95 | case 256: 96 | ctx->rounds = AES256_ROUNDS; 97 | break; 98 | default: 99 | printf("pefs: AESNI: invalid key length: %d", keybits); 100 | return (EINVAL); 101 | } 102 | 103 | if (ses->fpu_saved < 0) { 104 | tmpctx = fpu_kern_alloc_ctx(FPU_KERN_NORMAL); 105 | if (tmpctx == NULL) 106 | return (ENOMEM); 107 | fpu_kern_enter(curthread, tmpctx, FPU_KERN_NORMAL); 108 | } 109 | 110 | aesni_set_enckey(key, ctx->enc_schedule, ctx->rounds); 111 | aesni_set_deckey(ctx->enc_schedule, ctx->dec_schedule, ctx->rounds); 112 | rijndael_set_key(&ctx->sw, key, keybits); 113 | 114 | if (tmpctx != NULL) { 115 | fpu_kern_leave(curthread, tmpctx); 116 | fpu_kern_free_ctx(tmpctx); 117 | } 118 | 119 | return (0); 120 | } 121 | 122 | static void 123 | pefs_aesni_encrypt(const struct pefs_session *xses, 124 | const struct pefs_ctx *xctx, const uint8_t *in, uint8_t *out) 125 | { 126 | const struct pefs_aesni_ses *ses = &xses->o.ps_aesni; 127 | const struct pefs_aesni_ctx *ctx = &xctx->o.pctx_aesni; 128 | 129 | if (ses->fpu_saved >= 0) 130 | aesni_encrypt_ecb(ctx->rounds, ctx->enc_schedule, AES_BLOCK_LEN, 131 | in, out); 132 | else 133 | rijndael_encrypt(&ctx->sw, in, out); 134 | } 135 | 136 | static void 137 | pefs_aesni_decrypt(const struct pefs_session *xses, 138 | const struct pefs_ctx *xctx, const uint8_t *in, uint8_t *out) 139 | { 140 | const struct pefs_aesni_ses *ses = &xses->o.ps_aesni; 141 | const struct pefs_aesni_ctx *ctx = &xctx->o.pctx_aesni; 142 | 143 | if (ses->fpu_saved >= 0) 144 | aesni_decrypt_ecb(ctx->rounds, ctx->dec_schedule, AES_BLOCK_LEN, 145 | in, out); 146 | else 147 | rijndael_decrypt(&ctx->sw, in, out); 148 | } 149 | 150 | static void 151 | pefs_aesni_enter(struct pefs_session *xses) 152 | { 153 | struct pefs_aesni_ses *ses = &xses->o.ps_aesni; 154 | 155 | if (is_fpu_kern_thread(0)) { 156 | ses->fpu_saved = 0; 157 | return; 158 | } 159 | 160 | critical_enter(); 161 | ses->fpu_ctx = (void *)atomic_swap_ptr( 162 | (volatile void *)DPCPU_PTR(pefs_aesni_fpu), (uintptr_t)NULL); 163 | if (ses->fpu_ctx != NULL) { 164 | ses->td = curthread; 165 | ses->fpu_cpuid = curcpu; 166 | fpu_kern_enter(ses->td, ses->fpu_ctx, FPU_KERN_NORMAL); 167 | ses->fpu_saved = 1; 168 | } else { 169 | ses->fpu_saved = -1; 170 | } 171 | critical_exit(); 172 | } 173 | 174 | static void 175 | pefs_aesni_leave(struct pefs_session *xses) 176 | { 177 | struct pefs_aesni_ses *ses = &xses->o.ps_aesni; 178 | 179 | if (ses->fpu_saved <= 0) 180 | return; 181 | 182 | fpu_kern_leave(ses->td, ses->fpu_ctx); 183 | DPCPU_ID_SET(ses->fpu_cpuid, pefs_aesni_fpu, ses->fpu_ctx); 184 | } 185 | 186 | static void 187 | pefs_aesni_uninit(struct pefs_alg *pa) 188 | { 189 | struct fpu_kern_ctx *fpu_ctx; 190 | u_int cpuid; 191 | 192 | CPU_FOREACH(cpuid) { 193 | fpu_ctx = (void *)atomic_swap_ptr( 194 | (volatile void *)DPCPU_ID_PTR(cpuid, pefs_aesni_fpu), 195 | (uintptr_t)NULL); 196 | if (fpu_ctx != NULL) 197 | fpu_kern_free_ctx(fpu_ctx); 198 | } 199 | } 200 | 201 | void 202 | pefs_aesni_init(struct pefs_alg *pa) 203 | { 204 | struct fpu_kern_ctx *fpu_ctx; 205 | u_long enable = 1; 206 | u_int cpuid; 207 | 208 | TUNABLE_ULONG_FETCH(AESNI_ENABLE_ENV, &enable); 209 | 210 | if (enable != 0 && (cpu_feature2 & CPUID2_AESNI) != 0) { 211 | printf("pefs: AESNI hardware acceleration enabled\n"); 212 | pa->pa_uninit = pefs_aesni_uninit; 213 | pa->pa_enter = pefs_aesni_enter; 214 | pa->pa_leave = pefs_aesni_leave; 215 | pa->pa_keysetup = pefs_aesni_keysetup; 216 | pa->pa_encrypt = pefs_aesni_encrypt; 217 | pa->pa_decrypt = pefs_aesni_decrypt; 218 | CPU_FOREACH(cpuid) { 219 | fpu_ctx = fpu_kern_alloc_ctx(FPU_KERN_NORMAL); 220 | DPCPU_ID_SET(cpuid, pefs_aesni_fpu, fpu_ctx); 221 | } 222 | } else 223 | #ifndef PEFS_DEBUG 224 | if (bootverbose) 225 | #endif 226 | printf("pefs: AESNI hardware acceleration disabled\n"); 227 | } 228 | -------------------------------------------------------------------------------- /sys/fs/pefs/pefs_aesni.h: -------------------------------------------------------------------------------- 1 | /*- 2 | * Copyright (c) 2010 Konstantin Belousov 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions 7 | * are met: 8 | * 1. Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * 2. Redistributions in binary form must reproduce the above copyright 11 | * notice, this list of conditions and the following disclaimer in the 12 | * documentation and/or other materials provided with the distribution. 13 | * 14 | * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND 15 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE 18 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 | * SUCH DAMAGE. 25 | * 26 | * $FreeBSD$ 27 | */ 28 | 29 | #ifdef PEFS_AESNI 30 | 31 | #include 32 | 33 | struct pefs_aesni_ctx { 34 | uint8_t enc_schedule[AES_SCHED_LEN] __aligned(16); 35 | uint8_t dec_schedule[AES_SCHED_LEN] __aligned(16); 36 | int rounds; 37 | rijndael_ctx sw; 38 | }; 39 | 40 | struct pefs_aesni_ses { 41 | struct fpu_kern_ctx *fpu_ctx; 42 | struct thread *td; 43 | u_int fpu_cpuid; 44 | int fpu_saved; 45 | }; 46 | 47 | #endif 48 | -------------------------------------------------------------------------------- /sys/fs/pefs/pefs_compat.h: -------------------------------------------------------------------------------- 1 | /*- 2 | * Copyright (c) 2016 Gleb Kurtsou 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions 7 | * are met: 8 | * 1. Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * 2. Redistributions in binary form must reproduce the above copyright 11 | * notice, this list of conditions and the following disclaimer in the 12 | * documentation and/or other materials provided with the distribution. 13 | * 14 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 | * SUCH DAMAGE. 25 | * 26 | * $FreeBSD$ 27 | */ 28 | 29 | 30 | /* 31 | * Use PEFS_OSREL defines for backported changes. 32 | * Format: 33 | * PEFS_OSREL__ 34 | */ 35 | 36 | #if P_OSREL_MAJOR(__FreeBSD_version) == 11 37 | #if __FreeBSD_version >= 1100506 38 | #define PEFS_OSREL_1200013_PAGE_SLEEP_XBUSY 39 | #endif 40 | #if __FreeBSD_version >= 1100509 41 | #define PEFS_OSREL_1200013_CACHE_PURGEVFS 42 | #endif 43 | #if __FreeBSD_version >= 1100514 44 | #define PEFS_OSREL_1200014_VM_PAGE_CACHE 45 | #endif 46 | #if __FreeBSD_version >= 1100510 47 | #define PEFS_OSREL_1200020_M_STATFS 48 | #endif 49 | #endif 50 | 51 | #if P_OSREL_MAJOR(__FreeBSD_version) == 10 52 | #if __FreeBSD_version >= 1003510 53 | #define PEFS_OSREL_1200013_PAGE_SLEEP_XBUSY 54 | #endif 55 | #endif 56 | 57 | #if __FreeBSD_version < 1300074 58 | #define PEFS_VOP_UNLOCK(vp) VOP_UNLOCK(vp, 0) 59 | #else 60 | #define PEFS_VOP_UNLOCK(vp) VOP_UNLOCK(vp) 61 | #endif 62 | 63 | #if __FreeBSD_version < 1300064 64 | #define VN_IS_DOOMED(vp) ((vp)->v_iflag & VI_DOOMED) 65 | #endif 66 | 67 | #if __FreeBSD_version < 1300077 68 | typedef unsigned int encname_len_t; 69 | #else 70 | typedef size_t encname_len_t; 71 | #endif 72 | -------------------------------------------------------------------------------- /sys/fs/pefs/pefs_crypto.h: -------------------------------------------------------------------------------- 1 | /*- 2 | * Copyright (c) 2009 Gleb Kurtsou 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions 7 | * are met: 8 | * 1. Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * 2. Redistributions in binary form must reproduce the above copyright 11 | * notice, this list of conditions and the following disclaimer in the 12 | * documentation and/or other materials provided with the distribution. 13 | * 14 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 | * SUCH DAMAGE. 25 | * 26 | * $FreeBSD$ 27 | */ 28 | 29 | #include 30 | #include 31 | #include 32 | 33 | #ifdef PEFS_AESNI 34 | #include 35 | #endif 36 | #include 37 | 38 | struct pefs_alg; 39 | struct pefs_ctx; 40 | struct pefs_session; 41 | 42 | typedef void algop_init_t(struct pefs_alg *alg); 43 | typedef void algop_uninit_t(struct pefs_alg *alg); 44 | typedef void algop_session_t(struct pefs_session *ses); 45 | typedef int algop_keysetup_t(const struct pefs_session *sess, 46 | struct pefs_ctx *ctx, const uint8_t *key, uint32_t keybits); 47 | typedef void algop_crypt_t(const struct pefs_session *sess, 48 | const struct pefs_ctx *ctx, const uint8_t *in, uint8_t *out); 49 | 50 | struct pefs_alg { 51 | algop_session_t *pa_enter; 52 | algop_session_t *pa_leave; 53 | algop_crypt_t *pa_encrypt; 54 | algop_crypt_t *pa_decrypt; 55 | algop_keysetup_t *pa_keysetup; 56 | algop_init_t *pa_init; 57 | algop_uninit_t *pa_uninit; 58 | int pa_id; 59 | }; 60 | 61 | struct pefs_ctx { 62 | union { 63 | camellia_ctx pctx_camellia; 64 | rijndael_ctx pctx_aes; 65 | struct hmac_sha512_ctx pctx_hmac; 66 | vmac_ctx_t pctx_vmac; 67 | #ifdef PEFS_AESNI 68 | struct pefs_aesni_ctx pctx_aesni; 69 | #endif 70 | } o; 71 | } __aligned(CACHE_LINE_SIZE); 72 | 73 | struct pefs_session { 74 | union { 75 | int dummy; 76 | #ifdef PEFS_AESNI 77 | struct pefs_aesni_ses ps_aesni; 78 | #endif 79 | } o; 80 | }; 81 | 82 | algop_init_t pefs_aesni_init; 83 | 84 | void pefs_xts_block_encrypt(const struct pefs_alg *alg, 85 | const struct pefs_session *ses, 86 | const struct pefs_ctx *tweak_ctx, const struct pefs_ctx *data_ctx, 87 | uint64_t sector, const uint8_t *xtweak, int len, 88 | const uint8_t *src, uint8_t *dst); 89 | 90 | void pefs_xts_block_decrypt(const struct pefs_alg *alg, 91 | const struct pefs_session *ses, 92 | const struct pefs_ctx *tweak_ctx, const struct pefs_ctx *data_ctx, 93 | uint64_t sector, const uint8_t *xtweak, int len, 94 | const uint8_t *src, uint8_t *dst); 95 | -------------------------------------------------------------------------------- /sys/fs/pefs/pefs_dircache.c: -------------------------------------------------------------------------------- 1 | /*- 2 | * Copyright (c) 2009 Gleb Kurtsou 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions 7 | * are met: 8 | * 1. Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * 2. Redistributions in binary form must reproduce the above copyright 11 | * notice, this list of conditions and the following disclaimer in the 12 | * documentation and/or other materials provided with the distribution. 13 | * 14 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 | * SUCH DAMAGE. 25 | */ 26 | 27 | #include 28 | __FBSDID("$FreeBSD$"); 29 | 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include 40 | #include 41 | #include 42 | #include 43 | #include 44 | #include 45 | #include 46 | #include 47 | 48 | #include 49 | #include 50 | 51 | #define DIRCACHE_SIZE_ENV "vfs.pefs.dircache.buckets" 52 | #define DIRCACHE_SIZE_MIN 512 53 | #define DIRCACHE_SIZE_DEFAULT (desiredvnodes / 8) 54 | 55 | #define DIRCACHE_GLOBAL_ENV "vfs.pefs.dircache.global" 56 | 57 | #define DIRCACHE_TBL(pool, hash) \ 58 | (&(pool)->pdp_tbl[(hash) & dircache_hashmask]) 59 | #define DIRCACHE_ENCTBL(pool, hash) \ 60 | (&(pool)->pdp_enctbl[(hash) & dircache_hashmask]) 61 | #define DIRCACHE_MTX(hash) \ 62 | (&dircache_mtxs[(hash) % MAXCPU]) 63 | 64 | struct pefs_dircache_pool 65 | { 66 | struct pefs_dircache_listhead *pdp_tbl; 67 | struct pefs_dircache_listhead *pdp_enctbl; 68 | }; 69 | 70 | static struct pefs_dircache_pool dircache_global; 71 | 72 | static u_long dircache_hashmask; 73 | 74 | #if __FreeBSD_version < 1000500 75 | #define mtx_padalign mtx 76 | #endif 77 | 78 | static struct mtx_padalign dircache_mtxs[MAXCPU]; 79 | 80 | static uma_zone_t dircache_zone; 81 | static uma_zone_t dircache_entry_zone; 82 | 83 | SYSCTL_NODE(_vfs_pefs, OID_AUTO, dircache, CTLFLAG_RW, 0, 84 | "PEFS directory cache"); 85 | 86 | int pefs_dircache_enable = 1; 87 | SYSCTL_INT(_vfs_pefs_dircache, OID_AUTO, enable, CTLFLAG_RW, 88 | &pefs_dircache_enable, 0, "Enable dircache"); 89 | 90 | static int dircache_global_enable = 1; 91 | SYSCTL_INT(_vfs_pefs_dircache, OID_AUTO, global, CTLFLAG_RD, 92 | &dircache_global_enable, 0, "Global dircache hash table"); 93 | 94 | static u_long dircache_buckets = 0; 95 | SYSCTL_ULONG(_vfs_pefs_dircache, OID_AUTO, buckets, CTLFLAG_RD, 96 | &dircache_buckets, 0, "Number of dircache hash table buckets"); 97 | 98 | static u_long dircache_entries = 0; 99 | SYSCTL_ULONG(_vfs_pefs_dircache, OID_AUTO, entries, CTLFLAG_RD, 100 | &dircache_entries, 0, "Entries in dircache"); 101 | 102 | static void pefs_dircache_pool_init(struct pefs_dircache_pool *pdp); 103 | static void pefs_dircache_pool_uninit(struct pefs_dircache_pool *pdp); 104 | 105 | void 106 | pefs_dircache_init(void) 107 | { 108 | u_int i; 109 | 110 | TUNABLE_ULONG_FETCH(DIRCACHE_SIZE_ENV, &dircache_buckets); 111 | TUNABLE_INT_FETCH(DIRCACHE_GLOBAL_ENV, &dircache_global_enable); 112 | 113 | if (dircache_buckets < DIRCACHE_SIZE_MIN) 114 | dircache_buckets = DIRCACHE_SIZE_DEFAULT; 115 | dircache_hashmask = (1ULL << flsl(dircache_buckets)) - 1; 116 | dircache_global_enable = !!dircache_global_enable; 117 | 118 | for (i = 0; i < MAXCPU; i++) { 119 | mtx_init(&dircache_mtxs[i], "dircache_mtx", NULL, MTX_DEF); 120 | } 121 | 122 | dircache_zone = uma_zcreate("pefs_dircache", 123 | sizeof(struct pefs_dircache), NULL, NULL, NULL, NULL, 124 | UMA_ALIGN_PTR, 0); 125 | dircache_entry_zone = uma_zcreate("pefs_dircache_entry", 126 | sizeof(struct pefs_dircache_entry), NULL, NULL, NULL, 127 | pefs_zone_fini_bzero, UMA_ALIGN_PTR, 0); 128 | 129 | if (dircache_global_enable != 0) { 130 | pefs_dircache_pool_init(&dircache_global); 131 | } 132 | } 133 | 134 | void 135 | pefs_dircache_uninit(void) 136 | { 137 | u_int i; 138 | 139 | if (dircache_global_enable != 0) { 140 | pefs_dircache_pool_uninit(&dircache_global); 141 | } 142 | 143 | uma_zdestroy(dircache_zone); 144 | uma_zdestroy(dircache_entry_zone); 145 | 146 | for (i = 0; i < MAXCPU; i++) { 147 | mtx_destroy(&dircache_mtxs[i]); 148 | } 149 | } 150 | 151 | static void 152 | pefs_dircache_pool_init(struct pefs_dircache_pool *pdp) 153 | { 154 | u_long tbl_size = dircache_hashmask + 1; 155 | u_long i; 156 | 157 | pdp->pdp_tbl = malloc(tbl_size * sizeof(pdp->pdp_tbl[0]), 158 | M_PEFSHASH, M_WAITOK); 159 | pdp->pdp_enctbl = malloc(tbl_size * sizeof(pdp->pdp_enctbl[0]), 160 | M_PEFSHASH, M_WAITOK); 161 | for (i = 0; i < tbl_size; i++) { 162 | LIST_INIT(&pdp->pdp_tbl[i]); 163 | LIST_INIT(&pdp->pdp_enctbl[i]); 164 | } 165 | } 166 | 167 | static void 168 | pefs_dircache_pool_uninit(struct pefs_dircache_pool *pdp) 169 | { 170 | free(pdp->pdp_tbl, M_PEFSHASH); 171 | free(pdp->pdp_enctbl, M_PEFSHASH); 172 | pdp->pdp_tbl = NULL; 173 | pdp->pdp_enctbl = NULL; 174 | } 175 | 176 | struct pefs_dircache_pool * 177 | pefs_dircache_pool_create(void) 178 | { 179 | struct pefs_dircache_pool *pdp; 180 | 181 | if (dircache_global_enable != 0) 182 | return (&dircache_global); 183 | 184 | pdp = malloc(sizeof(*pdp), M_PEFSHASH, M_WAITOK); 185 | pefs_dircache_pool_init(pdp); 186 | return (pdp); 187 | } 188 | 189 | void 190 | pefs_dircache_pool_free(struct pefs_dircache_pool *pdp) 191 | { 192 | if (dircache_global_enable != 0) 193 | return; 194 | 195 | pefs_dircache_pool_uninit(pdp); 196 | free(pdp, M_PEFSHASH); 197 | } 198 | 199 | static __inline uint32_t 200 | dircache_hashname(struct pefs_dircache *pd, char const *buf, size_t len) 201 | { 202 | uint32_t h; 203 | 204 | h = pefs_hash_mixptr(pd); 205 | h ^= hash32_buf(buf, len, HASHINIT * len); 206 | return (h); 207 | } 208 | 209 | static void 210 | dircache_entry_free(struct pefs_dircache_entry *pde) 211 | { 212 | PEFSDEBUG("dircache_entry_free: %p %s -> %s\n", 213 | pde, pde->pde_name, pde->pde_encname); 214 | 215 | pefs_key_release(pde->pde_tkey.ptk_key); 216 | LIST_REMOVE(pde, pde_dir_entry); 217 | 218 | atomic_subtract_long(&dircache_entries, 1); 219 | uma_zfree(dircache_entry_zone, pde); 220 | } 221 | 222 | static void 223 | dircache_gc_locked(struct pefs_dircache *pd) 224 | { 225 | struct pefs_dircache_entry *pde, *tmp; 226 | 227 | // ASSERT_VOP_ELOCKED 228 | LIST_FOREACH_SAFE(pde, &pd->pd_stalehead, pde_dir_entry, tmp) { 229 | dircache_entry_free(pde); 230 | } 231 | } 232 | 233 | static void 234 | dircache_entry_expire_locked(struct pefs_dircache_entry *pde) 235 | { 236 | struct pefs_dircache *pd; 237 | struct mtx_padalign *bucket_mtx; 238 | 239 | pd = pde->pde_dircache; 240 | pde->pde_dircache = NULL; 241 | 242 | LIST_REMOVE(pde, pde_dir_entry); 243 | LIST_INSERT_HEAD(&pd->pd_stalehead, pde, pde_dir_entry); 244 | 245 | bucket_mtx = DIRCACHE_MTX(pde->pde_namehash); 246 | mtx_lock(bucket_mtx); 247 | LIST_REMOVE(pde, pde_hash_entry); 248 | mtx_unlock(bucket_mtx); 249 | 250 | bucket_mtx = DIRCACHE_MTX(pde->pde_encnamehash); 251 | mtx_lock(bucket_mtx); 252 | LIST_REMOVE(pde, pde_enchash_entry); 253 | mtx_unlock(bucket_mtx); 254 | } 255 | 256 | static __inline int 257 | dircache_cmp_name(struct pefs_dircache_entry *pde, uint32_t h, 258 | char const *name, size_t name_len) 259 | { 260 | if (pde->pde_namehash == h && 261 | pde->pde_namelen == name_len && 262 | memcmp(pde->pde_name, name, name_len) == 0) 263 | return 1; 264 | return 0; 265 | } 266 | 267 | static __inline int 268 | dircache_cmp_encname(struct pefs_dircache_entry *pde, uint32_t h, 269 | char const *encname, size_t encname_len) 270 | { 271 | if (pde->pde_encnamehash == h && 272 | pde->pde_encnamelen == encname_len && 273 | memcmp(pde->pde_encname, encname, encname_len) == 0) 274 | return 1; 275 | return 0; 276 | } 277 | 278 | static __inline void 279 | dircache_retry_set(struct pefs_dircache *pd, struct pefs_dircache_entry *pde) 280 | { 281 | uint32_t h; 282 | 283 | h = (pde->pde_encnamehash & PEFS_DIRCACHE_RETRY_MASK); 284 | atomic_store_rel_ptr((volatile uintptr_t *)&pd->pd_retry[h], 285 | (uintptr_t)pde); 286 | } 287 | 288 | static __inline void 289 | dircache_retry_clear(struct pefs_dircache *pd) 290 | { 291 | u_int i; 292 | 293 | for (i = 0; i < PEFS_DIRCACHE_RETRY_COUNT; i++) 294 | atomic_store_rel_ptr((volatile uintptr_t *)&pd->pd_retry[i], 0); 295 | } 296 | 297 | struct pefs_dircache * 298 | pefs_dircache_create(struct pefs_dircache_pool *pdp) 299 | { 300 | struct pefs_dircache *pd; 301 | 302 | pd = uma_zalloc(dircache_zone, M_WAITOK | M_ZERO); 303 | mtx_init(&pd->pd_mtx, "pefs_dircache_mtx", NULL, MTX_DEF); 304 | pd->pd_pool = pdp; 305 | LIST_INIT(&pd->pd_activehead); 306 | LIST_INIT(&pd->pd_stalehead); 307 | 308 | return (pd); 309 | } 310 | 311 | void 312 | pefs_dircache_purge(struct pefs_dircache *pd) 313 | { 314 | struct pefs_dircache_entry *pde, *tmp; 315 | 316 | if (pd == NULL) 317 | return; 318 | 319 | // ASSERT_VOP_ELOCKED 320 | mtx_lock(&pd->pd_mtx); 321 | atomic_store_rel_long(&pd->pd_gen, 0); 322 | atomic_store_rel_64(&pd->pd_filerev, 0); 323 | LIST_FOREACH_SAFE(pde, &pd->pd_activehead, pde_dir_entry, tmp) { 324 | dircache_entry_expire_locked(pde); 325 | } 326 | mtx_unlock(&pd->pd_mtx); 327 | 328 | pefs_dircache_gc(pd); 329 | } 330 | 331 | void 332 | pefs_dircache_expire(struct pefs_dircache_entry *pde, u_int dflags) 333 | { 334 | struct pefs_dircache *pd; 335 | 336 | pd = pde->pde_dircache; 337 | if (pd == NULL) 338 | return; 339 | mtx_lock(&pd->pd_mtx); 340 | atomic_store_rel_long(&pd->pd_gen, 0); 341 | atomic_store_rel_64(&pd->pd_filerev, 0); 342 | dircache_retry_clear(pd); 343 | if (pde->pde_dircache != NULL) { 344 | dircache_entry_expire_locked(pde); 345 | if ((dflags & PEFS_DF_FORCE_GC) != 0) 346 | dircache_gc_locked(pd); 347 | 348 | } 349 | mtx_unlock(&pd->pd_mtx); 350 | } 351 | 352 | void 353 | pefs_dircache_expire_encname(struct pefs_dircache *pd, 354 | const char *encname, size_t encname_len, u_int dflags) 355 | { 356 | struct pefs_dircache_entry *pde; 357 | 358 | PEFSDEBUG("dircache_expire_encname: %.*s\n", 359 | (int)encname_len, encname); 360 | pde = pefs_dircache_enclookup_retry(pd, encname, encname_len); 361 | if (pde == NULL) 362 | pde = pefs_dircache_enclookup(pd, encname, encname_len); 363 | if (pde != NULL) 364 | pefs_dircache_expire(pde, dflags); 365 | } 366 | 367 | void 368 | pefs_dircache_gc(struct pefs_dircache *pd) 369 | { 370 | if (pd == NULL) 371 | return; 372 | 373 | mtx_lock(&pd->pd_mtx); 374 | dircache_retry_clear(pd); 375 | dircache_gc_locked(pd); 376 | mtx_unlock(&pd->pd_mtx); 377 | } 378 | 379 | void 380 | pefs_dircache_free(struct pefs_dircache *pd) 381 | { 382 | if (pd == NULL) 383 | return; 384 | 385 | pefs_dircache_purge(pd); 386 | mtx_destroy(&pd->pd_mtx); 387 | uma_zfree(dircache_zone, pd); 388 | } 389 | 390 | struct pefs_dircache_entry * 391 | pefs_dircache_insert(struct pefs_dircache *pd, struct pefs_tkey *ptk, 392 | char const *name, size_t name_len, 393 | char const *encname, size_t encname_len) 394 | { 395 | struct pefs_dircache_pool *pdp; 396 | struct pefs_dircache_listhead *bucket; 397 | struct pefs_dircache_entry *pde, *xpde; 398 | struct mtx_padalign *bucket_mtx; 399 | 400 | MPASS(ptk->ptk_key != NULL); 401 | 402 | if (name_len == 0 || name_len >= sizeof(pde->pde_name) || 403 | encname_len == 0 || encname_len >= sizeof(pde->pde_encname)) 404 | panic("pefs: invalid file name length: %zd/%zd", 405 | name_len, encname_len); 406 | 407 | pde = uma_zalloc(dircache_entry_zone, M_WAITOK | M_ZERO); 408 | pde->pde_dircache = pd; 409 | 410 | pde->pde_tkey = *ptk; 411 | pefs_key_ref(pde->pde_tkey.ptk_key); 412 | 413 | pde->pde_namelen = name_len; 414 | memcpy(pde->pde_name, name, name_len); 415 | pde->pde_name[name_len] = '\0'; 416 | pde->pde_namehash = dircache_hashname(pd, pde->pde_name, 417 | pde->pde_namelen); 418 | 419 | pde->pde_encnamelen = encname_len; 420 | memcpy(pde->pde_encname, encname, encname_len); 421 | pde->pde_encname[encname_len] = '\0'; 422 | pde->pde_encnamehash = dircache_hashname(pd, pde->pde_encname, 423 | pde->pde_encnamelen); 424 | 425 | /* Insert into list and set pge_gen */ 426 | pdp = pd->pd_pool; 427 | 428 | mtx_lock(&pd->pd_mtx); 429 | 430 | bucket = DIRCACHE_ENCTBL(pdp, pde->pde_encnamehash); 431 | bucket_mtx = DIRCACHE_MTX(pde->pde_encnamehash); 432 | mtx_lock(bucket_mtx); 433 | LIST_FOREACH(xpde, bucket, pde_enchash_entry) { 434 | if (xpde->pde_dircache == pd && 435 | dircache_cmp_encname(xpde, pde->pde_encnamehash, 436 | encname, encname_len) != 0) { 437 | mtx_unlock(bucket_mtx); 438 | mtx_unlock(&pd->pd_mtx); 439 | PEFSDEBUG("pefs_dircache_insert: collision %s\n", 440 | pde->pde_name); 441 | pefs_key_release(pde->pde_tkey.ptk_key); 442 | uma_zfree(dircache_entry_zone, pde); 443 | return (xpde); 444 | } 445 | } 446 | LIST_INSERT_HEAD(bucket, pde, pde_enchash_entry); 447 | mtx_unlock(bucket_mtx); 448 | 449 | bucket = DIRCACHE_TBL(pdp, pde->pde_namehash); 450 | bucket_mtx = DIRCACHE_MTX(pde->pde_namehash); 451 | mtx_lock(bucket_mtx); 452 | LIST_INSERT_HEAD(bucket, pde, pde_hash_entry); 453 | mtx_unlock(bucket_mtx); 454 | 455 | LIST_INSERT_HEAD(&pd->pd_activehead, pde, pde_dir_entry); 456 | mtx_unlock(&pd->pd_mtx); 457 | 458 | atomic_add_long(&dircache_entries, 1); 459 | 460 | PEFSDEBUG("pefs_dircache_insert: %p %s -> %s\n", 461 | pde, pde->pde_name, pde->pde_encname); 462 | 463 | return (pde); 464 | } 465 | 466 | struct pefs_dircache_entry * 467 | pefs_dircache_lookup(struct pefs_dircache *pd, char const *name, 468 | size_t name_len) 469 | { 470 | struct pefs_dircache_entry *pde; 471 | struct pefs_dircache_listhead *bucket; 472 | struct mtx_padalign *bucket_mtx; 473 | uint32_t h; 474 | 475 | MPASS(pd != NULL); 476 | 477 | h = dircache_hashname(pd, name, name_len); 478 | bucket = DIRCACHE_TBL(pd->pd_pool, h); 479 | bucket_mtx = DIRCACHE_MTX(h); 480 | mtx_lock(bucket_mtx); 481 | LIST_FOREACH(pde, bucket, pde_hash_entry) { 482 | if (pde->pde_dircache == pd && 483 | dircache_cmp_name(pde, h, name, name_len) != 0) { 484 | mtx_unlock(bucket_mtx); 485 | PEFSDEBUG("pefs_dircache_lookup: found %s -> %s\n", 486 | pde->pde_name, pde->pde_encname); 487 | dircache_retry_set(pd, pde); 488 | return (pde); 489 | } 490 | } 491 | mtx_unlock(bucket_mtx); 492 | PEFSDEBUG("pefs_dircache_lookup: not found %s\n", name); 493 | return (NULL); 494 | } 495 | 496 | struct pefs_dircache_entry * 497 | pefs_dircache_enclookup(struct pefs_dircache *pd, char const *encname, 498 | size_t encname_len) 499 | { 500 | struct pefs_dircache_entry *pde; 501 | struct pefs_dircache_listhead *bucket; 502 | struct mtx_padalign *bucket_mtx; 503 | uint32_t h; 504 | 505 | h = dircache_hashname(pd, encname, encname_len); 506 | bucket = DIRCACHE_ENCTBL(pd->pd_pool, h); 507 | bucket_mtx = DIRCACHE_MTX(h); 508 | mtx_lock(bucket_mtx); 509 | LIST_FOREACH(pde, bucket, pde_enchash_entry) { 510 | if (pde->pde_dircache == pd && 511 | dircache_cmp_encname(pde, h, encname, encname_len) != 0) { 512 | mtx_unlock(bucket_mtx); 513 | PEFSDEBUG("pefs_dircache_enclookup: found %s -> %s\n", 514 | pde->pde_name, pde->pde_encname); 515 | dircache_retry_set(pd, pde); 516 | return (pde); 517 | } 518 | } 519 | mtx_unlock(bucket_mtx); 520 | PEFSDEBUG("pefs_dircache_enclookup: not found %s\n", encname); 521 | return (NULL); 522 | } 523 | 524 | struct pefs_dircache_entry * 525 | pefs_dircache_lookup_retry(struct pefs_dircache *pd, char const *name, 526 | size_t name_len) 527 | { 528 | struct pefs_dircache_entry *pde; 529 | u_int i; 530 | 531 | for (i = 0; i < PEFS_DIRCACHE_RETRY_COUNT; i++) { 532 | pde = (void *)atomic_load_acq_ptr( 533 | (volatile uintptr_t *)&pd->pd_retry[i]); 534 | if (pde != NULL && pde->pde_dircache == pd && 535 | pde->pde_namelen == name_len && 536 | memcmp(pde->pde_name, name, name_len) == 0) 537 | return (pde); 538 | } 539 | return (NULL); 540 | } 541 | 542 | struct pefs_dircache_entry * 543 | pefs_dircache_enclookup_retry(struct pefs_dircache *pd, char const *encname, 544 | size_t encname_len) 545 | { 546 | struct pefs_dircache_entry *pde; 547 | u_int i; 548 | 549 | for (i = 0; i < PEFS_DIRCACHE_RETRY_COUNT; i++) { 550 | pde = (void *)atomic_load_acq_ptr( 551 | (volatile uintptr_t *)&pd->pd_retry[i]); 552 | if (pde != NULL && pde->pde_dircache == pd && 553 | pde->pde_encnamelen == encname_len && 554 | memcmp(pde->pde_encname, encname, encname_len) == 0) 555 | return (pde); 556 | } 557 | return (NULL); 558 | } 559 | -------------------------------------------------------------------------------- /sys/fs/pefs/pefs_dircache.h: -------------------------------------------------------------------------------- 1 | /*- 2 | * Copyright (c) 2009 Gleb Kurtsou 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions 7 | * are met: 8 | * 1. Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * 2. Redistributions in binary form must reproduce the above copyright 11 | * notice, this list of conditions and the following disclaimer in the 12 | * documentation and/or other materials provided with the distribution. 13 | * 14 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 | * SUCH DAMAGE. 25 | * 26 | * $FreeBSD$ 27 | */ 28 | 29 | 30 | #define PEFS_CACHENAME_MAXLEN PEFS_NAME_PTON_SIZE(MAXNAMLEN) 31 | 32 | #define PEFS_DIRCACHE_RETRY_COUNT 4 33 | #define PEFS_DIRCACHE_RETRY_MASK (PEFS_DIRCACHE_RETRY_COUNT - 1) 34 | 35 | #define PEFS_DF_FORCE_GC 0x0001 36 | 37 | struct pefs_dircache_pool; 38 | struct pefs_dircache_entry; 39 | LIST_HEAD(pefs_dircache_listhead, pefs_dircache_entry); 40 | 41 | struct pefs_dircache { 42 | struct mtx pd_mtx; 43 | struct pefs_dircache_listhead pd_activehead; 44 | struct pefs_dircache_listhead pd_stalehead; 45 | volatile u_long pd_gen; 46 | volatile u_quad_t pd_filerev; 47 | struct pefs_dircache_pool *pd_pool; 48 | struct pefs_dircache_entry *pd_retry[PEFS_DIRCACHE_RETRY_COUNT]; 49 | }; 50 | 51 | struct pefs_dircache_entry { 52 | LIST_ENTRY(pefs_dircache_entry) pde_dir_entry; 53 | LIST_ENTRY(pefs_dircache_entry) pde_hash_entry; 54 | LIST_ENTRY(pefs_dircache_entry) pde_enchash_entry; 55 | struct pefs_dircache *pde_dircache; 56 | struct pefs_tkey pde_tkey; 57 | uint32_t pde_namehash; 58 | uint32_t pde_encnamehash; 59 | uint16_t pde_namelen; 60 | uint16_t pde_encnamelen; 61 | char pde_name[PEFS_CACHENAME_MAXLEN + 1]; 62 | char pde_encname[MAXNAMLEN + 1]; 63 | }; 64 | 65 | extern int pefs_dircache_enable; 66 | 67 | void pefs_dircache_init(void); 68 | void pefs_dircache_uninit(void); 69 | 70 | struct pefs_dircache_pool *pefs_dircache_pool_create(void); 71 | void pefs_dircache_pool_free(struct pefs_dircache_pool *); 72 | 73 | struct pefs_dircache *pefs_dircache_create(struct pefs_dircache_pool *pdp); 74 | void pefs_dircache_purge(struct pefs_dircache *pd); 75 | void pefs_dircache_free(struct pefs_dircache *pd); 76 | struct pefs_dircache_entry *pefs_dircache_lookup(struct pefs_dircache *pd, 77 | char const *name, size_t name_len); 78 | struct pefs_dircache_entry *pefs_dircache_lookup_retry(struct pefs_dircache *pd, 79 | char const *name, size_t name_len); 80 | struct pefs_dircache_entry *pefs_dircache_enclookup(struct pefs_dircache *pd, 81 | char const *encname, size_t encname_len); 82 | struct pefs_dircache_entry *pefs_dircache_enclookup_retry( 83 | struct pefs_dircache *pd, char const *encname, size_t encname_len); 84 | struct pefs_dircache_entry *pefs_dircache_insert(struct pefs_dircache *pd, 85 | struct pefs_tkey *ptk, char const *name, size_t name_len, 86 | char const *encname, size_t encname_len); 87 | void pefs_dircache_expire(struct pefs_dircache_entry *pde, u_int dflags); 88 | void pefs_dircache_expire_encname(struct pefs_dircache *pd, 89 | char const *encname, size_t encname_len, u_int dflags); 90 | void pefs_dircache_gc(struct pefs_dircache *pd); 91 | 92 | static __inline int 93 | pefs_dircache_valid(struct pefs_dircache *pd, u_long gen, u_quad_t filerev) 94 | { 95 | u_long pd_gen; 96 | u_quad_t pd_filerev; 97 | 98 | if (filerev == 0 && gen == 0) 99 | return 0; 100 | 101 | pd_gen = atomic_load_acq_long(&pd->pd_gen); 102 | pd_filerev = atomic_load_acq_64(&pd->pd_filerev); 103 | return ((filerev == pd_filerev || filerev == 0) && (gen == pd_gen || gen == 0)); 104 | } 105 | 106 | static __inline void 107 | pefs_dircache_beginupdate(struct pefs_dircache *pd) 108 | { 109 | } 110 | 111 | static __inline void 112 | pefs_dircache_endupdate(struct pefs_dircache *pd, u_long gen, u_quad_t filerev) 113 | { 114 | atomic_store_rel_long(&pd->pd_gen, gen); 115 | atomic_store_rel_64(&pd->pd_filerev, filerev); 116 | } 117 | 118 | static __inline void 119 | pefs_dircache_abortupdate(struct pefs_dircache *pd) 120 | { 121 | } 122 | -------------------------------------------------------------------------------- /sys/fs/pefs/pefs_vfsops.c: -------------------------------------------------------------------------------- 1 | /*- 2 | * Copyright (c) 1992, 1993, 1995 3 | * The Regents of the University of California. All rights reserved. 4 | * Copyright (c) 2009 Gleb Kurtsou 5 | * 6 | * This code is derived from software donated to Berkeley by 7 | * Jan-Simon Pendry. 8 | * 9 | * Redistribution and use in source and binary forms, with or without 10 | * modification, are permitted provided that the following conditions 11 | * are met: 12 | * 1. Redistributions of source code must retain the above copyright 13 | * notice, this list of conditions and the following disclaimer. 14 | * 2. Redistributions in binary form must reproduce the above copyright 15 | * notice, this list of conditions and the following disclaimer in the 16 | * documentation and/or other materials provided with the distribution. 17 | * 4. Neither the name of the University nor the names of its contributors 18 | * may be used to endorse or promote products derived from this software 19 | * without specific prior written permission. 20 | * 21 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 | * SUCH DAMAGE. 32 | */ 33 | 34 | #include 35 | __FBSDID("$FreeBSD$"); 36 | 37 | #include 38 | #include 39 | #include 40 | #include 41 | #include 42 | #include 43 | #include 44 | #include 45 | #include 46 | #include 47 | #include 48 | 49 | #include 50 | #include 51 | #include 52 | 53 | struct pefs_opt_descr { 54 | char *fs; 55 | int initial; 56 | int forbid; 57 | }; 58 | 59 | static const struct pefs_opt_descr pefs_opt_support[] = { 60 | { 61 | .fs = "zfs", 62 | #if __FreeBSD_version >= 1000025 63 | .initial = PM_DIRCACHE, 64 | #else 65 | .initial = PM_DIRCACHE | PM_ASYNCRECLAIM, 66 | #endif 67 | .forbid = 0 68 | }, 69 | { /* default flags */ 70 | .fs = NULL, 71 | .initial = 0, 72 | .forbid = PM_DIRCACHE, 73 | } 74 | }; 75 | 76 | static const char *pefs_opts[] = { 77 | "from", 78 | "export", 79 | "dircache", 80 | "nodircache", 81 | "asyncreclaim", 82 | NULL 83 | }; 84 | 85 | static MALLOC_DEFINE(M_PEFSMNT, "pefs_mount", "PEFS mount structure"); 86 | 87 | static void 88 | pefs_opt_set(struct mount *mp, int opt, struct pefs_mount *pm, 89 | int flag, const char *flagname) 90 | { 91 | const struct pefs_opt_descr *descr; 92 | char *lowerfs; 93 | 94 | lowerfs = mp->mnt_vnodecovered->v_mount->mnt_vfc->vfc_name; 95 | for (descr = pefs_opt_support; descr->fs != NULL; descr++) 96 | if (strcmp(lowerfs, descr->fs) == 0) 97 | break; 98 | if (opt < 0) 99 | opt = descr->initial & flag; 100 | else if (opt > 0 && (descr->forbid & flag) != 0) { 101 | printf("pefs: %s is not supported by file system: %s\n", 102 | flagname, lowerfs); 103 | opt = 0; 104 | } 105 | 106 | if (opt == 0) 107 | pm->pm_flags &= ~flag; 108 | else 109 | pm->pm_flags |= flag; 110 | PEFSDEBUG("pefs_mount: %s %s\n", 111 | flagname, (opt ? "enabled" : "disabed")); 112 | } 113 | 114 | static int 115 | subdir(const char *p, const char *dir) 116 | { 117 | int l; 118 | 119 | l = strlen(dir); 120 | if (l <= 1) 121 | return (1); 122 | 123 | if ((strncmp(p, dir, l) == 0) && (p[l] == '/' || p[l] == '\0')) 124 | return (1); 125 | 126 | return (0); 127 | } 128 | 129 | /* 130 | * Mount null layer 131 | */ 132 | static int 133 | pefs_mount(struct mount *mp) 134 | { 135 | struct vnode *lowerrootvp, *vp; 136 | struct vnode *pm_rootvp; 137 | struct nameidata nd, *ndp = &nd; 138 | struct pefs_mount *pm; 139 | char *from, *from_free; 140 | int isvnunlocked = 0, len; 141 | int opt_dircache, opt_asyncreclaim; 142 | int error = 0; 143 | 144 | PEFSDEBUG("pefs_mount(mp = %p)\n", (void *)mp); 145 | 146 | if (mp->mnt_flag & MNT_ROOTFS) 147 | return (EOPNOTSUPP); 148 | 149 | if (vfs_filteropt(mp->mnt_optnew, pefs_opts)) 150 | return (EINVAL); 151 | 152 | opt_dircache = -1; 153 | if (vfs_flagopt(mp->mnt_optnew, "dircache", NULL, 0)) { 154 | vfs_deleteopt(mp->mnt_optnew, "dircache"); 155 | opt_dircache = 1; 156 | } else if (vfs_flagopt(mp->mnt_optnew, "nodircache", NULL, 0)) { 157 | vfs_deleteopt(mp->mnt_optnew, "nodircache"); 158 | opt_dircache = 0; 159 | } 160 | opt_asyncreclaim = -1; 161 | if (vfs_flagopt(mp->mnt_optnew, "asyncreclaim", NULL, 0)) { 162 | vfs_deleteopt(mp->mnt_optnew, "asyncreclaim"); 163 | opt_asyncreclaim = 1; 164 | } 165 | 166 | if (mp->mnt_flag & MNT_UPDATE) { 167 | error = EOPNOTSUPP; 168 | if (vfs_flagopt(mp->mnt_optnew, "export", NULL, 0)) 169 | error = 0; 170 | if (opt_dircache >= 0) { 171 | pefs_opt_set(mp, opt_dircache, mp->mnt_data, 172 | PM_DIRCACHE, "dircache"); 173 | error = 0; 174 | } 175 | if (opt_asyncreclaim >= 0) { 176 | pefs_opt_set(mp, opt_dircache, mp->mnt_data, 177 | PM_ASYNCRECLAIM, "asyncreclaim"); 178 | error = 0; 179 | } 180 | return (error); 181 | } 182 | 183 | /* 184 | * Get argument 185 | */ 186 | error = vfs_getopt(mp->mnt_optnew, "from", (void **)&from, &len); 187 | if (error || from[len - 1] != '\0') 188 | return (EINVAL); 189 | vfs_mountedfrom(mp, from); 190 | 191 | /* 192 | * Unlock lower node to avoid deadlock. 193 | * (XXX) VOP_ISLOCKED is needed? 194 | */ 195 | if ((mp->mnt_vnodecovered->v_op == &pefs_vnodeops) && 196 | VOP_ISLOCKED(mp->mnt_vnodecovered)) { 197 | PEFS_VOP_UNLOCK(mp->mnt_vnodecovered); 198 | isvnunlocked = 1; 199 | } 200 | /* 201 | * Find lower node 202 | */ 203 | #if __FreeBSD_version > 1400042 204 | NDINIT(ndp, LOOKUP, FOLLOW, UIO_SYSSPACE, from); 205 | #else 206 | NDINIT(ndp, LOOKUP, FOLLOW, UIO_SYSSPACE, from, curthread); 207 | #endif 208 | error = namei(ndp); 209 | 210 | if (error == 0) { 211 | from_free = NULL; 212 | #if __FreeBSD_version < 1300111 213 | error = vn_fullpath(curthread, ndp->ni_vp, &from, 214 | &from_free); 215 | #else 216 | error = vn_fullpath(ndp->ni_vp, &from, &from_free); 217 | #endif 218 | if (error == 0) 219 | vfs_mountedfrom(mp, from); 220 | else 221 | error = 0; 222 | free(from_free, M_TEMP); 223 | } 224 | /* 225 | * Re-lock vnode. 226 | */ 227 | if (isvnunlocked && !VOP_ISLOCKED(mp->mnt_vnodecovered)) 228 | vn_lock(mp->mnt_vnodecovered, LK_EXCLUSIVE | LK_RETRY); 229 | 230 | if (error != 0) 231 | return (error); 232 | #if __FreeBSD_version > 1300134 233 | NDFREE_PNBUF(ndp); 234 | #else 235 | NDFREE(ndp, NDF_ONLY_PNBUF); 236 | #endif 237 | 238 | /* 239 | * Sanity check on lower vnode 240 | */ 241 | lowerrootvp = ndp->ni_vp; 242 | vn_lock(lowerrootvp, LK_EXCLUSIVE | LK_RETRY); 243 | if (VN_IS_DOOMED(lowerrootvp)) { 244 | PEFSDEBUG("pefs_mount: target vnode disappeared\n"); 245 | vput(lowerrootvp); 246 | return (ENOENT); 247 | } 248 | 249 | /* 250 | * Check multi pefs mount to avoid `lock against myself' panic. 251 | */ 252 | if (lowerrootvp->v_mount->mnt_vfc == mp->mnt_vfc) { 253 | PEFSDEBUG("pefs_mount: multi pefs mount\n"); 254 | vput(lowerrootvp); 255 | return (EDEADLK); 256 | } 257 | 258 | /* 259 | * Check paths are not nested 260 | */ 261 | if ((lowerrootvp != mp->mnt_vnodecovered) && 262 | (subdir(mp->mnt_stat.f_mntfromname, mp->mnt_stat.f_mntonname) || 263 | subdir(mp->mnt_stat.f_mntonname, mp->mnt_stat.f_mntfromname))) { 264 | PEFSDEBUG("pefs_mount: %s and %s are nested paths\n", 265 | mp->mnt_stat.f_mntfromname, mp->mnt_stat.f_mntonname); 266 | vput(lowerrootvp); 267 | return (EDEADLK); 268 | } 269 | 270 | pm = (struct pefs_mount *)malloc(sizeof(struct pefs_mount), M_PEFSMNT, 271 | M_WAITOK | M_ZERO); 272 | 273 | mtx_init(&pm->pm_keys_lock, "pefs_mount lock", NULL, MTX_DEF); 274 | TAILQ_INIT(&pm->pm_keys); 275 | 276 | /* 277 | * Save reference to underlying FS 278 | */ 279 | pm->pm_lowervfs = lowerrootvp->v_mount; 280 | if (lowerrootvp == mp->mnt_vnodecovered) 281 | pm->pm_flags |= PM_ROOT_CANRECURSE; 282 | pefs_opt_set(mp, opt_dircache, pm, PM_DIRCACHE, "dircache"); 283 | pefs_opt_set(mp, opt_asyncreclaim, pm, PM_ASYNCRECLAIM, "asyncreclaim"); 284 | 285 | pm->pm_dircache_pool = pefs_dircache_pool_create(); 286 | 287 | mp->mnt_data = pm; 288 | 289 | /* 290 | * Save reference. Each mount also holds 291 | * a reference on the root vnode. 292 | */ 293 | vp = NULL; 294 | error = pefs_node_get_nokey(mp, lowerrootvp, &vp); 295 | /* 296 | * Make sure the node alias worked 297 | */ 298 | if (error != 0) { 299 | vput(lowerrootvp); 300 | mtx_destroy(&pm->pm_keys_lock); 301 | free(pm, M_PEFSMNT); 302 | mp->mnt_data = NULL; 303 | return (error); 304 | } 305 | 306 | /* 307 | * Keep a held reference to the root vnode. 308 | * It is vrele'd in pefs_unmount. 309 | */ 310 | pm_rootvp = vp; 311 | pm_rootvp->v_vflag |= VV_ROOT; 312 | pm->pm_rootvp = pm_rootvp; 313 | 314 | /* 315 | * Unlock the node (either the lower or the alias) 316 | */ 317 | PEFS_VOP_UNLOCK(vp); 318 | 319 | 320 | MNT_ILOCK(mp); 321 | if (lowerrootvp->v_mount->mnt_flag & MNT_LOCAL) { 322 | mp->mnt_flag |= MNT_LOCAL; 323 | } 324 | #if __FreeBSD_version < 1000021 325 | mp->mnt_kern_flag |= lowerrootvp->v_mount->mnt_kern_flag & MNTK_MPSAFE; 326 | #else 327 | mp->mnt_kern_flag |= lowerrootvp->v_mount->mnt_kern_flag & 328 | (MNTK_LOOKUP_SHARED | MNTK_EXTENDED_SHARED); 329 | #endif 330 | MNT_IUNLOCK(mp); 331 | vfs_getnewfsid(mp); 332 | 333 | PEFSDEBUG("pefs_mount: lower %s, alias at %s\n", 334 | mp->mnt_stat.f_mntfromname, mp->mnt_stat.f_mntonname); 335 | return (0); 336 | } 337 | 338 | /* 339 | * Free reference to null layer 340 | */ 341 | static int 342 | pefs_unmount(struct mount *mp, int mntflags) 343 | { 344 | struct pefs_mount *pm; 345 | int error; 346 | int flags = 0; 347 | 348 | PEFSDEBUG("pefs_unmount: mp = %p\n", (void *)mp); 349 | 350 | if (mntflags & MNT_FORCE) 351 | flags |= FORCECLOSE; 352 | 353 | /* There is 1 extra root vnode reference (pm_rootvp). */ 354 | error = vflush(mp, 1, flags, curthread); 355 | if (error != 0) 356 | return (error); 357 | 358 | /* 359 | * Finally, throw away the pefs_mount structure 360 | */ 361 | pm = VFS_TO_PEFS(mp); 362 | pefs_dircache_pool_free(pm->pm_dircache_pool); 363 | mp->mnt_data = 0; 364 | pefs_key_remove_all(pm); 365 | mtx_destroy(&pm->pm_keys_lock); 366 | free(pm, M_PEFSMNT); 367 | return (0); 368 | } 369 | 370 | static int 371 | pefs_root(struct mount *mp, int flags, struct vnode **vpp) 372 | { 373 | struct vnode *vp; 374 | 375 | /* 376 | * Return locked reference to root. 377 | */ 378 | vp = VFS_TO_PEFS(mp)->pm_rootvp; 379 | VREF(vp); 380 | 381 | vn_lock(vp, flags | LK_RETRY); 382 | *vpp = vp; 383 | return (0); 384 | } 385 | #if __FreeBSD_version < 1400018 386 | static int 387 | pefs_quotactl(struct mount *mp, int cmd, uid_t uid, void *arg) 388 | { 389 | return (VFS_QUOTACTL(VFS_TO_PEFS(mp)->pm_lowervfs, cmd, uid, arg)); 390 | } 391 | #else 392 | static int 393 | pefs_quotactl(struct mount *mp, int cmd, uid_t uid, void *arg, bool *mp_busy) 394 | { 395 | struct mount *lowermp; 396 | struct pefs_mount *mntdata; 397 | int error; 398 | bool unbusy; 399 | 400 | mntdata = (struct pefs_mount *)(mp->mnt_data); 401 | lowermp = atomic_load_ptr(&mntdata->pm_lowervfs); 402 | KASSERT(*mp_busy == true, ("upper mount not busy")); 403 | /* 404 | * See comment in sys_quotactl() for an explanation of why the 405 | * lower mount needs to be busied by the caller of VFS_QUOTACTL() 406 | * but may be unbusied by the implementation. We must unbusy 407 | * the upper mount for the same reason; otherwise a namei lookup 408 | * issued by the VFS_QUOTACTL() implementation could traverse the 409 | * upper mount and deadlock. 410 | */ 411 | vfs_unbusy(mp); 412 | *mp_busy = false; 413 | unbusy = true; 414 | error = vfs_busy(lowermp, 0); 415 | if (error == 0) 416 | error = VFS_QUOTACTL(lowermp, cmd, uid, arg, &unbusy); 417 | if (unbusy) 418 | vfs_unbusy(lowermp); 419 | 420 | return (error); 421 | } 422 | #endif 423 | 424 | static int 425 | pefs_statfs(struct mount *mp, struct statfs *sbp) 426 | { 427 | struct statfs *mstat; 428 | int error; 429 | 430 | #if __FreeBSD_version >= 1200020 || defined(PEFS_OSREL_1200020_M_STATFS) 431 | mstat = malloc(sizeof(struct statfs), M_STATFS, M_WAITOK | M_ZERO); 432 | #else 433 | mstat = malloc(sizeof(struct statfs), M_TEMP, M_WAITOK | M_ZERO); 434 | #endif 435 | error = VFS_STATFS(VFS_TO_PEFS(mp)->pm_lowervfs, mstat); 436 | if (error == 0) { 437 | /* now copy across the "interesting" information and fake the rest */ 438 | sbp->f_type = mstat->f_type; 439 | sbp->f_flags = mstat->f_flags; 440 | sbp->f_bsize = mstat->f_bsize; 441 | sbp->f_iosize = mstat->f_iosize; 442 | sbp->f_blocks = mstat->f_blocks; 443 | sbp->f_bfree = mstat->f_bfree; 444 | sbp->f_bavail = mstat->f_bavail; 445 | sbp->f_files = mstat->f_files; 446 | sbp->f_ffree = mstat->f_ffree; 447 | } 448 | 449 | #if __FreeBSD_version >= 1200020 || defined(PEFS_OSREL_1200020_M_STATFS) 450 | free(mstat, M_STATFS); 451 | #else 452 | free(mstat, M_TEMP); 453 | #endif 454 | return (error); 455 | } 456 | 457 | static int 458 | pefs_sync(struct mount *mp, int waitfor) 459 | { 460 | /* 461 | * XXX - Assumes no data cached at null layer. 462 | */ 463 | return (0); 464 | } 465 | 466 | static int 467 | pefs_vget(struct mount *mp, ino_t ino, int flags, struct vnode **vpp) 468 | { 469 | int error; 470 | error = VFS_VGET(VFS_TO_PEFS(mp)->pm_lowervfs, ino, flags, vpp); 471 | if (error != 0) 472 | return (error); 473 | 474 | return (pefs_node_get_lookupkey(mp, *vpp, vpp, curthread->td_ucred)); 475 | } 476 | 477 | static int 478 | #if __FreeBSD_version >= 900038 479 | pefs_fhtovp(struct mount *mp, struct fid *fidp, int flags, struct vnode **vpp) 480 | #else 481 | pefs_fhtovp(struct mount *mp, struct fid *fidp, struct vnode **vpp) 482 | #endif 483 | { 484 | int error; 485 | 486 | #if __FreeBSD_version >= 900038 487 | error = VFS_FHTOVP(VFS_TO_PEFS(mp)->pm_lowervfs, fidp, flags, vpp); 488 | #else 489 | error = VFS_FHTOVP(VFS_TO_PEFS(mp)->pm_lowervfs, fidp, vpp); 490 | #endif /* __FreeBSD_version */ 491 | if (error != 0) 492 | return (error); 493 | 494 | error = pefs_node_get_lookupkey(mp, *vpp, vpp, curthread->td_ucred); 495 | if (error != 0) 496 | return (error); 497 | vnode_create_vobject(*vpp, 0, curthread); 498 | return (error); 499 | } 500 | 501 | static int 502 | pefs_extattrctl(struct mount *mp, int cmd, struct vnode *filename_vp, 503 | int namespace, const char *attrname) 504 | { 505 | return (VFS_EXTATTRCTL(VFS_TO_PEFS(mp)->pm_lowervfs, cmd, filename_vp, 506 | namespace, attrname)); 507 | } 508 | 509 | 510 | static struct vfsops pefs_vfsops = { 511 | .vfs_extattrctl = pefs_extattrctl, 512 | .vfs_fhtovp = pefs_fhtovp, 513 | .vfs_init = pefs_init, 514 | .vfs_mount = pefs_mount, 515 | .vfs_quotactl = pefs_quotactl, 516 | .vfs_root = pefs_root, 517 | .vfs_statfs = pefs_statfs, 518 | .vfs_sync = pefs_sync, 519 | .vfs_uninit = pefs_uninit, 520 | .vfs_unmount = pefs_unmount, 521 | .vfs_vget = pefs_vget, 522 | }; 523 | 524 | VFS_SET(pefs_vfsops, pefs, VFCF_LOOPBACK); 525 | MODULE_DEPEND(pefs, crypto, 1, 1, 1); 526 | #ifdef PEFS_AESNI 527 | MODULE_DEPEND(pefs, aesni, 1, 1, 1); 528 | #endif 529 | -------------------------------------------------------------------------------- /sys/fs/pefs/pefs_xbase64.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 1996, 1998 by Internet Software Consortium. 3 | * 4 | * Permission to use, copy, modify, and distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS 9 | * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES 10 | * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE 11 | * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL 12 | * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR 13 | * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS 14 | * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS 15 | * SOFTWARE. 16 | */ 17 | 18 | /* 19 | * Portions Copyright (c) 1995 by International Business Machines, Inc. 20 | * 21 | * International Business Machines, Inc. (hereinafter called IBM) grants 22 | * permission under its copyrights to use, copy, modify, and distribute this 23 | * Software with or without fee, provided that the above copyright notice and 24 | * all paragraphs of this notice appear in all copies, and that the name of IBM 25 | * not be used in connection with the marketing of any product incorporating 26 | * the Software or modifications thereof, without specific, written prior 27 | * permission. 28 | * 29 | * To the extent it has a right to do so, IBM grants an immunity from suit 30 | * under its patents, if any, for the use, sale or manufacture of products to 31 | * the extent that such products are used for performing Domain Name System 32 | * dynamic updates in TCP/IP networks by means of the Software. No immunity is 33 | * granted for any product per se or for any other function of any product. 34 | * 35 | * THE SOFTWARE IS PROVIDED "AS IS", AND IBM DISCLAIMS ALL WARRANTIES, 36 | * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 37 | * PARTICULAR PURPOSE. IN NO EVENT SHALL IBM BE LIABLE FOR ANY SPECIAL, 38 | * DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER ARISING 39 | * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE, EVEN 40 | * IF IBM IS APPRISED OF THE POSSIBILITY OF SUCH DAMAGES. 41 | */ 42 | 43 | #include 44 | __FBSDID("$FreeBSD$"); 45 | 46 | #include 47 | #include 48 | #include 49 | #include 50 | #include 51 | 52 | #include 53 | 54 | #define Assert(Cond) (void)0 55 | 56 | /* 57 | * Algorithm is standard base64 with few exceptions: 58 | * - file system friendly alphabet 59 | * - no paddings and whitespace skip 60 | */ 61 | static const char Base64[] = 62 | "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+_"; 63 | 64 | int 65 | pefs_name_ntop(u_char const *src, size_t srclength, 66 | char *target, size_t targsize) 67 | { 68 | size_t datalength = 0; 69 | u_char input[3]; 70 | u_char output[4]; 71 | size_t i; 72 | 73 | while (2 < srclength) { 74 | input[0] = *src++; 75 | input[1] = *src++; 76 | input[2] = *src++; 77 | srclength -= 3; 78 | 79 | output[0] = input[0] >> 2; 80 | output[1] = ((input[0] & 0x03) << 4) + (input[1] >> 4); 81 | output[2] = ((input[1] & 0x0f) << 2) + (input[2] >> 6); 82 | output[3] = input[2] & 0x3f; 83 | Assert(output[0] < 64); 84 | Assert(output[1] < 64); 85 | Assert(output[2] < 64); 86 | Assert(output[3] < 64); 87 | 88 | if (datalength + 4 > targsize) 89 | return (-1); 90 | target[datalength++] = Base64[output[0]]; 91 | target[datalength++] = Base64[output[1]]; 92 | target[datalength++] = Base64[output[2]]; 93 | target[datalength++] = Base64[output[3]]; 94 | } 95 | 96 | /* Now we worry about padding. */ 97 | if (0 != srclength) { 98 | /* Get what's left. */ 99 | input[0] = input[1] = input[2] = '\0'; 100 | for (i = 0; i < srclength; i++) 101 | input[i] = *src++; 102 | 103 | output[0] = input[0] >> 2; 104 | output[1] = ((input[0] & 0x03) << 4) + (input[1] >> 4); 105 | output[2] = ((input[1] & 0x0f) << 2) + (input[2] >> 6); 106 | Assert(output[0] < 64); 107 | Assert(output[1] < 64); 108 | Assert(output[2] < 64); 109 | 110 | if (datalength + 2 > targsize) 111 | return (-1); 112 | target[datalength++] = Base64[output[0]]; 113 | target[datalength++] = Base64[output[1]]; 114 | if (srclength == 2) { 115 | if (datalength + 1 > targsize) 116 | return (-1); 117 | target[datalength++] = Base64[output[2]]; 118 | } 119 | } 120 | if (datalength >= targsize || datalength == 0) 121 | return (-1); 122 | target[datalength] = '\0'; /* Returned value doesn't count \0. */ 123 | return (datalength); 124 | } 125 | 126 | int 127 | pefs_name_pton(char const *src, size_t srclen, u_char *target, size_t targsize) 128 | { 129 | int tarindex, state, ch; 130 | char *pos; 131 | 132 | state = 0; 133 | tarindex = 0; 134 | 135 | while ((ch = *src++) != '\0' && srclen-- > 0) { 136 | if (target && (size_t)tarindex >= targsize) 137 | return (-1); 138 | 139 | pos = strchr(Base64, ch); 140 | if (pos == 0) /* A non-base64 character. */ 141 | return (-1); 142 | 143 | switch (state) { 144 | case 0: 145 | if (target) { 146 | target[tarindex] = (pos - Base64) << 2; 147 | } 148 | state = 1; 149 | break; 150 | case 1: 151 | if (target) { 152 | target[tarindex] |= (pos - Base64) >> 4; 153 | if ((size_t)tarindex + 1 < targsize) 154 | target[tarindex+1] = 155 | ((pos - Base64) & 0x0f) << 4 ; 156 | } 157 | tarindex++; 158 | state = 2; 159 | break; 160 | case 2: 161 | if (target) { 162 | target[tarindex] |= (pos - Base64) >> 2; 163 | if ((size_t)tarindex + 1 < targsize) 164 | target[tarindex+1] = 165 | ((pos - Base64) & 0x03) << 6; 166 | } 167 | tarindex++; 168 | state = 3; 169 | break; 170 | case 3: 171 | if (target) { 172 | target[tarindex] |= (pos - Base64); 173 | } 174 | tarindex++; 175 | state = 0; 176 | break; 177 | default: 178 | return (-1); 179 | } 180 | } 181 | 182 | if (tarindex == 0) 183 | return (-1); 184 | return (tarindex); 185 | } 186 | 187 | -------------------------------------------------------------------------------- /sys/fs/pefs/pefs_xts.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2007, 2008 University of Tsukuba 3 | * Copyright (c) 2010 Gleb Kurtsou 4 | * All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without 7 | * modification, are permitted provided that the following conditions are met: 8 | * 9 | * 1. Redistributions of source code must retain the above copyright notice, 10 | * this list of conditions and the following disclaimer. 11 | * 2. Redistributions in binary form must reproduce the above copyright notice, 12 | * this list of conditions and the following disclaimer in the documentation 13 | * and/or other materials provided with the distribution. 14 | * 3. Neither the name of the University of Tsukuba nor the names of its 15 | * contributors may be used to endorse or promote products derived from 16 | * this software without specific prior written permission. 17 | * 18 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 22 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 26 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28 | * POSSIBILITY OF SUCH DAMAGE. 29 | */ 30 | 31 | #include 32 | #include 33 | 34 | #include 35 | 36 | #ifdef _KERNEL 37 | #include 38 | #else 39 | #include 40 | #endif 41 | 42 | #define XTS_BLK_BYTES 16 43 | #define XTS_BLK_MASK (XTS_BLK_BYTES - 1) 44 | 45 | static __inline void 46 | xor128(void *dst, const void *src1, const void *src2) 47 | { 48 | const uint64_t *s1 = (const uint64_t *)src1; 49 | const uint64_t *s2 = (const uint64_t *)src2; 50 | uint64_t *d = (uint64_t *)dst; 51 | 52 | d[0] = s1[0] ^ s2[0]; 53 | d[1] = s1[1] ^ s2[1]; 54 | } 55 | 56 | static __inline void 57 | gf_mul128(uint64_t *dst, const uint64_t *src) 58 | { 59 | static const int gf_128_fdbk = 0x87; 60 | int8_t c0, c1; 61 | 62 | c0 = (src[0] >> 63); 63 | c1 = (src[1] >> 63); 64 | dst[0] = (src[0] << 1); 65 | dst[1] = (src[1] << 1) | c0; 66 | 67 | c1 = (uint8_t)(-(int)c1 & gf_128_fdbk); 68 | ((uint8_t *)dst)[0] ^= c1; 69 | } 70 | 71 | static __inline void 72 | xts_fullblock(algop_crypt_t *data_crypt, const struct pefs_session *ses, 73 | const struct pefs_ctx *data_ctx, 74 | uint64_t *tweak, const uint8_t *src, uint8_t *dst) 75 | { 76 | xor128(dst, src, tweak); 77 | data_crypt(ses, data_ctx, dst, dst); 78 | xor128(dst, dst, tweak); 79 | gf_mul128(tweak, tweak); 80 | } 81 | 82 | static __inline void 83 | xts_lastblock(algop_crypt_t *data_crypt, const struct pefs_session *ses, 84 | const struct pefs_ctx *data_ctx, 85 | uint64_t *tweak, const uint8_t *src, uint8_t *dst, int len) 86 | { 87 | uint8_t b[XTS_BLK_BYTES]; 88 | 89 | dst -= XTS_BLK_BYTES; /* m - 1 */ 90 | memcpy(b, dst, XTS_BLK_BYTES); 91 | memcpy(b, src, len); 92 | memcpy(dst + XTS_BLK_BYTES, dst, len); 93 | 94 | xor128(dst, b, tweak); 95 | data_crypt(ses, data_ctx, dst, dst); 96 | xor128(dst, dst, tweak); 97 | } 98 | 99 | static __inline void 100 | xts_smallblock(const struct pefs_alg *alg, const struct pefs_session *ses, 101 | const struct pefs_ctx *data_ctx, 102 | uint64_t *tweak, const uint8_t *src, uint8_t *dst, int len) 103 | { 104 | uint8_t buf[XTS_BLK_BYTES], *p; 105 | 106 | /* 107 | * Encryption/decryption of sectors smaller then 128 bits is not defined 108 | * by IEEE P1619 standard. 109 | * To work around it encrypt such sector in CTR mode. 110 | * CTR tweak (counter) value is XTS-tweak xor'ed with block length, i.e. 111 | * entire small block has to be reencrypted after length change. 112 | */ 113 | memset(buf, len, XTS_BLK_BYTES); 114 | xor128(buf, buf, tweak); 115 | alg->pa_encrypt(ses, data_ctx, buf, buf); 116 | for (p = buf; len > 0; len--) 117 | *(dst++) = *(src++) ^ *(p++); 118 | } 119 | 120 | static __inline void 121 | xts_start(const struct pefs_alg *alg, const struct pefs_session *ses, 122 | const struct pefs_ctx *tweak_ctx, 123 | uint64_t *tweak, uint64_t sector, const uint8_t *xtweak) 124 | { 125 | tweak[0] = htole64(sector); 126 | tweak[1] = *((const uint64_t *)xtweak); 127 | 128 | /* encrypt the tweak */ 129 | alg->pa_encrypt(ses, tweak_ctx, (uint8_t *)tweak, (uint8_t *)tweak); 130 | } 131 | 132 | void 133 | pefs_xts_block_encrypt(const struct pefs_alg *alg, 134 | const struct pefs_session *ses, 135 | const struct pefs_ctx *tweak_ctx, const struct pefs_ctx *data_ctx, 136 | uint64_t sector, const uint8_t *xtweak, int len, 137 | const uint8_t *src, uint8_t *dst) 138 | { 139 | uint64_t tweak[XTS_BLK_BYTES / 8]; 140 | 141 | xts_start(alg, ses, tweak_ctx, tweak, sector, xtweak); 142 | 143 | if (len < XTS_BLK_BYTES) { 144 | xts_smallblock(alg, ses, data_ctx, tweak, src, dst, len); 145 | return; 146 | } 147 | 148 | while (len >= XTS_BLK_BYTES) { 149 | xts_fullblock(alg->pa_encrypt, ses, data_ctx, tweak, src, dst); 150 | dst += XTS_BLK_BYTES; 151 | src += XTS_BLK_BYTES; 152 | len -= XTS_BLK_BYTES; 153 | } 154 | 155 | if (len != 0) 156 | xts_lastblock(alg->pa_encrypt, ses, data_ctx, tweak, 157 | src, dst, len); 158 | } 159 | 160 | void 161 | pefs_xts_block_decrypt(const struct pefs_alg *alg, 162 | const struct pefs_session *ses, 163 | const struct pefs_ctx *tweak_ctx, const struct pefs_ctx *data_ctx, 164 | uint64_t sector, const uint8_t *xtweak, int len, 165 | const uint8_t *src, uint8_t *dst) 166 | { 167 | uint64_t tweak[XTS_BLK_BYTES / 8]; 168 | uint64_t prevtweak[XTS_BLK_BYTES / 8]; 169 | 170 | xts_start(alg, ses, tweak_ctx, tweak, sector, xtweak); 171 | 172 | if (len < XTS_BLK_BYTES) { 173 | xts_smallblock(alg, ses, data_ctx, tweak, src, dst, len); 174 | return; 175 | } 176 | 177 | if ((len & XTS_BLK_MASK) != 0) 178 | len -= XTS_BLK_BYTES; 179 | 180 | while (len >= XTS_BLK_BYTES) { 181 | xts_fullblock(alg->pa_decrypt, ses, data_ctx, tweak, src, dst); 182 | dst += XTS_BLK_BYTES; 183 | src += XTS_BLK_BYTES; 184 | len -= XTS_BLK_BYTES; 185 | } 186 | 187 | if (len != 0) { 188 | len += XTS_BLK_BYTES; 189 | prevtweak[0] = tweak[0]; 190 | prevtweak[1] = tweak[1]; 191 | gf_mul128(tweak, tweak); 192 | xts_fullblock(alg->pa_decrypt, ses, data_ctx, tweak, src, dst); 193 | dst += XTS_BLK_BYTES; 194 | src += XTS_BLK_BYTES; 195 | len -= XTS_BLK_BYTES; 196 | xts_lastblock(alg->pa_decrypt, ses, data_ctx, prevtweak, 197 | src, dst, len); 198 | } 199 | } 200 | -------------------------------------------------------------------------------- /sys/fs/pefs/vmac.h: -------------------------------------------------------------------------------- 1 | #ifndef __VMAC_H 2 | #define __VMAC_H 3 | 4 | /* -------------------------------------------------------------------------- 5 | * VMAC and VHASH Implementation by Ted Krovetz (tdk@acm.org) and Wei Dai. 6 | * This implementation is herby placed in the public domain. 7 | * The authors offers no warranty. Use at your own risk. 8 | * Please send bug reports to the authors. 9 | * Last modified: 17 APR 08, 1700 PDT 10 | * ----------------------------------------------------------------------- */ 11 | 12 | /* -------------------------------------------------------------------------- 13 | * User definable settings. 14 | * ----------------------------------------------------------------------- */ 15 | #define VMAC_TAG_LEN 64 /* Must be 64 or 128 - 64 sufficient for most */ 16 | #define VMAC_KEY_LEN 128 /* Must be 128, 192 or 256 */ 17 | #define VMAC_NHBYTES 128 /* Must 2^i for any 3 < i < 13. Standard = 128 */ 18 | #define VMAC_PREFER_BIG_ENDIAN 0 /* Prefer non-x86 */ 19 | 20 | #define VMAC_CACHE_NONCES 0 /* Set to non-zero to cause caching */ 21 | /* of consecutive nonces on 64-bit tags */ 22 | 23 | /* --------------------------------------------------------------------- */ 24 | 25 | typedef struct { 26 | uint64_t nhkey [(VMAC_NHBYTES/8)+2*(VMAC_TAG_LEN/64-1)]; 27 | uint64_t polykey[2*VMAC_TAG_LEN/64]; 28 | uint64_t l3key [2*VMAC_TAG_LEN/64]; 29 | uint64_t polytmp[2*VMAC_TAG_LEN/64]; 30 | uint32_t cipher_key[4*(VMAC_KEY_LEN/32+7)]; 31 | #if (VMAC_TAG_LEN == 64) && (VMAC_CACHE_NONCES) 32 | uint64_t cached_nonce[2]; 33 | uint64_t cached_aes[2]; 34 | #endif 35 | int first_block_processed; 36 | } vmac_ctx_t; 37 | 38 | /* -------------------------------------------------------------------------- 39 | * <<<<< USAGE NOTES >>>>> 40 | * 41 | * Given msg m (mbytes in length) and nonce buffer n 42 | * this function returns a tag as its output. The tag is returned as 43 | * a number. When VMAC_TAG_LEN == 64, the 'return'ed integer is the tag, 44 | * and *tagl is meaningless. When VMAC_TAG_LEN == 128 the tag is the 45 | * number y * 2^64 + *tagl where y is the function's return value. 46 | * If you want to consider tags to be strings, then you must do so with 47 | * an agreed upon endian orientation for interoperability, and convert 48 | * the results appropriately. VHASH hashes m without creating any tag. 49 | * Consecutive substrings forming a prefix of a message may be passed 50 | * to vhash_update, with vhash or vmac being called with the remainder 51 | * to produce the output. 52 | * 53 | * Requirements: 54 | * - On 32-bit architectures with SSE2 instructions, ctx and m MUST be 55 | * begin on 16-byte memory boundaries. 56 | * - m MUST be your message followed by zeroes to the nearest 16-byte 57 | * boundary. If m is a length multiple of 16 bytes, then it is already 58 | * at a 16-byte boundary and needs no padding. mbytes should be your 59 | * message length without any padding. 60 | * - The first bit of the nonce buffer n must be 0. An i byte nonce, is made 61 | * as the first 16-i bytes of n being zero, and the final i the nonce. 62 | * - vhash_update MUST have mbytes be a positive multiple of VMAC_NHBYTES 63 | * ----------------------------------------------------------------------- */ 64 | 65 | #define vmac_update vhash_update 66 | 67 | void vhash_update(unsigned char m[], 68 | unsigned int mbytes, 69 | vmac_ctx_t *ctx); 70 | 71 | uint64_t vmac(unsigned char m[], 72 | unsigned int mbytes, 73 | const unsigned char n[16], 74 | uint64_t *tagl, 75 | vmac_ctx_t *ctx); 76 | 77 | uint64_t vhash(unsigned char m[], 78 | unsigned int mbytes, 79 | uint64_t *tagl, 80 | vmac_ctx_t *ctx); 81 | 82 | /* -------------------------------------------------------------------------- 83 | * When passed a VMAC_KEY_LEN bit user_key, this function initialazies ctx. 84 | * ----------------------------------------------------------------------- */ 85 | 86 | void vmac_set_key(unsigned char user_key[], vmac_ctx_t *ctx); 87 | 88 | /* -------------------------------------------------------------------------- 89 | * This function aborts current hash and resets ctx, ready for a new message. 90 | * ----------------------------------------------------------------------- */ 91 | 92 | void vhash_abort(vmac_ctx_t *ctx); 93 | 94 | /* --------------------------------------------------------------------- */ 95 | 96 | #endif /* __VMAC_H */ 97 | -------------------------------------------------------------------------------- /sys/modules/pefs/Makefile: -------------------------------------------------------------------------------- 1 | # $FreeBSD$ 2 | 3 | .PATH: ${.CURDIR}/../../fs/pefs 4 | .PATH: ${.CURDIR}/../../crypto 5 | .PATH: ${.CURDIR}/../../crypto/sha2 6 | .PATH: ${.CURDIR}/../../crypto/hmac 7 | .PATH: ${.CURDIR}/../../crypto/pbkdf2 8 | 9 | KMOD= pefs 10 | SRCS= vnode_if.h \ 11 | pefs_subr.c pefs_vfsops.c pefs_vnops.c pefs_xbase64.c pefs_crypto.c \ 12 | pefs_dircache.c \ 13 | pefs_xts.c vmac.c \ 14 | crypto_verify_bytes.c hmac_sha512.c sha512c.c 15 | 16 | .if (${MACHINE_CPUARCH} == "i386" || ${MACHINE_CPUARCH} == "amd64") && !defined(PEFS_AESNI_DISABLE) 17 | SRCS+= pefs_aesni.c 18 | CFLAGS+= -DPEFS_AESNI 19 | .endif 20 | 21 | .if defined(PEFS_DEBUG) 22 | CFLAGS+= -DPEFS_DEBUG 23 | .endif 24 | 25 | CFLAGS+= -I${.CURDIR}/../../ 26 | 27 | .include 28 | -------------------------------------------------------------------------------- /tests/sbin/Kyuafile: -------------------------------------------------------------------------------- 1 | -- SPDX-License-Identifier: BSD-3-Clause 2 | -- Copyright (c) 2021 Daniel O'Connor . All rights reserved. 3 | -- 4 | -- Redistribution and use in source and binary forms, with or without 5 | -- modification, are permitted provided that the following conditions 6 | -- are met: 7 | -- 1. Redistributions of source code must retain the above copyright 8 | -- notice, this list of conditions and the following disclaimer. 9 | -- 2. Redistributions in binary form must reproduce the above copyright 10 | -- notice, this list of conditions and the following disclaimer in the 11 | -- documentation and/or other materials provided with the distribution. 12 | -- 13 | -- THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 14 | -- ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15 | -- IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 16 | -- ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 17 | -- FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 18 | -- DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 19 | -- OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 20 | -- HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 21 | -- LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 22 | -- OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 23 | -- SUCH DAMAGE. 24 | syntax(2) 25 | test_suite('FreeBSD') 26 | atf_test_program{name='basic_test', required_user='root'} 27 | -------------------------------------------------------------------------------- /tests/sbin/Makefile: -------------------------------------------------------------------------------- 1 | PACKAGE= tests 2 | ATF_TESTS_SH= basic_test \ 3 | lock_test 4 | TESTSDIR= ${TESTSBASE}/sbin/pefs 5 | 6 | .include 7 | -------------------------------------------------------------------------------- /tests/sbin/basic_test.sh: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: BSD-3-Clause 2 | # Copyright (c) 2021 Daniel O'Connor . All rights reserved. 3 | # 4 | # Redistribution and use in source and binary forms, with or without 5 | # modification, are permitted provided that the following conditions 6 | # are met: 7 | # 1. Redistributions of source code must retain the above copyright 8 | # notice, this list of conditions and the following disclaimer. 9 | # 2. Redistributions in binary form must reproduce the above copyright 10 | # notice, this list of conditions and the following disclaimer in the 11 | # documentation and/or other materials provided with the distribution. 12 | # 13 | # THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 14 | # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15 | # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 16 | # ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 17 | # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 18 | # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 19 | # OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 20 | # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 21 | # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 22 | # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 23 | # SUCH DAMAGE. 24 | 25 | atf_test_case basic cleanup 26 | basic_body() { 27 | kldstat -qm pefs 28 | if [ $? -ne 0 ]; then 29 | atf_skip "PEFS kernel module not loaded" 30 | fi 31 | mkdir mnt 32 | echo test123 >keyfile 33 | atf_check -s exit:0 -o empty -e empty pefs addchain -fZj keyfile mnt 34 | atf_check -s exit:0 -o empty -e empty pefs mount mnt mnt 35 | atf_check -s exit:0 -o empty -e empty pefs addkey -cj keyfile mnt 36 | orig=$(dd if=/dev/random count=100 | tee mnt/testfile | sha256 -q) 37 | atf_check -s exit:0 -o empty -e empty pefs umount mnt 38 | if [ -e mnt/testfile ]; then 39 | aft_fail "Test filename was present after umount" 40 | fi 41 | atf_check -s exit:0 -o empty -e empty pefs mount mnt mnt 42 | atf_check -s exit:0 -o empty -e empty pefs addkey -cj keyfile mnt 43 | new=$(sha256 -q mnt/testfile) 44 | atf_check_equal $orig ${new} 45 | } 46 | 47 | basic_cleanup() { 48 | if [ -e mnt ]; then 49 | umount -f mnt 50 | fi 51 | } 52 | 53 | atf_init_test_cases() { 54 | atf_add_test_case basic 55 | } 56 | -------------------------------------------------------------------------------- /tests/sbin/lock_test.sh: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: BSD-3-Clause 2 | # Copyright (c) 2021 Daniel O'Connor . All rights reserved. 3 | # 4 | # Redistribution and use in source and binary forms, with or without 5 | # modification, are permitted provided that the following conditions 6 | # are met: 7 | # 1. Redistributions of source code must retain the above copyright 8 | # notice, this list of conditions and the following disclaimer. 9 | # 2. Redistributions in binary form must reproduce the above copyright 10 | # notice, this list of conditions and the following disclaimer in the 11 | # documentation and/or other materials provided with the distribution. 12 | # 13 | # THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 14 | # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15 | # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 16 | # ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 17 | # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 18 | # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 19 | # OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 20 | # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 21 | # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 22 | # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 23 | # SUCH DAMAGE. 24 | 25 | atf_test_case lock cleanup 26 | lock_body() { 27 | kldstat -qm pefs 28 | if [ $? -ne 0 ]; then 29 | atf_skip "PEFS kernel module not loaded" 30 | fi 31 | mkdir mnt 32 | echo test123 >keyfile 33 | atf_check -s exit:0 -o empty -e empty pefs addchain -fZj keyfile mnt 34 | atf_check -s exit:0 -o empty -e empty pefs mount mnt mnt 35 | atf_check -s exit:0 -o empty -e empty pefs addkey -cj keyfile mnt 36 | lockf -k -t 0 mnt/test.lock sleep 1 & 37 | atf_check -s exit:75 -o empty -e ignore lockf -k -t 0 mnt/test.lock echo lock 38 | sleep 2 39 | atf_check -s exit:0 -o match:lock -e empty lockf -k -t 0 mnt/test.lock echo lock 40 | } 41 | 42 | lock_cleanup() { 43 | if [ -e mnt ]; then 44 | umount -f mnt 45 | fi 46 | } 47 | 48 | atf_init_test_cases() { 49 | atf_add_test_case lock 50 | } 51 | --------------------------------------------------------------------------------