├── .SRCINFO ├── .gitignore ├── CONTRIBUTORS.md ├── COPYING ├── PKGBUILD ├── README.md ├── initramfs-scencrypt.install ├── kexec-example.sh ├── scencrypt-hook └── scencrypt-install /.SRCINFO: -------------------------------------------------------------------------------- 1 | pkgbase = initramfs-scencrypt 2 | pkgdesc = initramfs hook that adds PGP smartcard support for LUKS FDE 3 | pkgver = 1.8 4 | pkgrel = 1 5 | install = initramfs-scencrypt.install 6 | arch = any 7 | depends = gnupg 8 | source = scencrypt-hook 9 | source = scencrypt-install 10 | source = README.md 11 | md5sums = SKIP 12 | md5sums = SKIP 13 | md5sums = SKIP 14 | 15 | pkgname = initramfs-scencrypt 16 | 17 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.pkg.tar.gz 2 | *.pkg.tar.xz 3 | -------------------------------------------------------------------------------- /CONTRIBUTORS.md: -------------------------------------------------------------------------------- 1 | # Contributors and license releases 2 | 3 | All contributors of code to this project must include an entry in this file indicating their commitment to release 4 | all contributions to the project, past present and future, under the MIT license. 5 | 6 | To do this, you must sign the following statement with the same PGP key you use for signing commits on GitHub: 7 | 8 | ``` 9 | I'm hereby licensing my contributions to github.com/fuhry/initramfs-scencrypt, 10 | present and future, under the MIT license (SPDX "MIT", https://spdx.org/licenses/MIT.html#licenseText) 11 | ``` 12 | 13 | ## License releases 14 | 15 | ---- 16 | 17 | Legal name: Dan Fuhry 18 | 19 | GitHub username: https://github.com/fuhry 20 | 21 | PGP key ID: 0xF4911EC47898A7550EDA7C6FDCD5C4E7C0B94A99 22 | 23 | License release: 24 | ``` 25 | -----BEGIN PGP SIGNED MESSAGE----- 26 | Hash: SHA256 27 | 28 | I'm hereby licensing my contributions to github.com/fuhry/initramfs-scencrypt, 29 | present and future, under the MIT license (SPDX "MIT", https://spdx.org/licenses/MIT.html#licenseText) 30 | -----BEGIN PGP SIGNATURE----- 31 | 32 | iQEzBAEBCAAdFiEE9JEexHiYp1UO2nxv3NXE58C5SpkFAlyZBHoACgkQ3NXE58C5 33 | SpkdEwgAhO+IpFP1ePa4PUT7XEOmYpNFklsuALcwXe+iwumlwHBnUZ+u/cX/IL8p 34 | js+5Otjjb7EA9DuqpEFbo0h6uMEpw5mcaao7g0wXZei/zgmKxgnvmFEv2i71NaKf 35 | jUty4Jt3MQBCPXDlPfTZlceOHNNOcXUzAUJxF23DpjZy3WxwjFe++BKEtb7uXziE 36 | vVXGl4atMb5YJwD93AzIUgllxn3l8R87M2c6k/KbRxN+0H8hvcNLqT7fzJ8fAQNV 37 | AwhzEA/2q5l7lnwd2Zj6UGMIO6JIJ86FT+7cWzh9bkpkzOdoc8tKTKXyiW8dlzfD 38 | X6hiy2qk9xS5GfACHhX26mXP3YJa6Q== 39 | =xACU 40 | -----END PGP SIGNATURE----- 41 | ``` 42 | 43 | ---- 44 | 45 | Legal name: Alexander Schittler 46 | 47 | GitHub username: https://github.com/damongant 48 | 49 | PGP key ID: 0xF9AC7F0071BFFAA47BC30EC92DB2C6CD77C3AD74 50 | 51 | License release: 52 | 53 | ``` 54 | -----BEGIN PGP SIGNED MESSAGE----- 55 | Hash: SHA512 56 | 57 | I'm hereby licensing my contributions to github.com/fuhry/initramfs-scencrypt, 58 | present and future, under the MIT license (SPDX "MIT", https://spdx.org/licenses/MIT.html#licenseText) 59 | -----BEGIN PGP SIGNATURE----- 60 | 61 | iQEzBAEBCgAdFiEE+ax/AHG/+qR7ww7JLbLGzXfDrXQFAluI/EcACgkQLbLGzXfD 62 | rXT4Bgf/VPSTqAoXUZ+oDJrlmHpeTvU5rdOlka4hXqq5je3FPIWnu1RJEisiCWHS 63 | YcQjeww3s4uDHBG2fL+6fFw4xQcoVIcXcAXK7ROoTk0ts0DckX/52cUEUg0qFqmy 64 | 7HHijI+vUvtK58Nuj5GWwbARlv7QG+IvCY6I41mmvUmEld59FCvsuJoYlEUjEufm 65 | LRKjiZWeqeGxs4leyuw3e5broELOXzzU92ou040fW7fjlrP/9vCj+ZM3AmKk5gAE 66 | nx5q7jR2C2Du6ny7bREp6IbxZIew/6z/xRewKichLwb47d9Y0X08dOtTMqqUOHtS 67 | S6M/X6njcceQ2CrlKy9Gq1waKRNJIg== 68 | =aScJ 69 | -----END PGP SIGNATURE----- 70 | ``` 71 | 72 | ---- 73 | 74 | Legal Name: Finn Behrens 75 | 76 | GitHub username: https://github.com/Kloenk 77 | 78 | PGP key ID: 0x68815A95D715D429659B48A4B92445CFC9546F9D 79 | 80 | License release: 81 | 82 | ``` 83 | -----BEGIN PGP SIGNED MESSAGE----- 84 | Hash: SHA256 85 | 86 | I'm hereby licensing my contributions to github.com/fuhry/initramfs-scencrypt, 87 | present and future, under the MIT license (SPDX "MIT", https://spdx.org/licenses/MIT.html#licenseText) 88 | -----BEGIN PGP SIGNATURE----- 89 | 90 | iHUEARYIAB0WIQRogVqV1xXUKWWbSKS5JEXPyVRvnQUCXDY5dQAKCRC5JEXPyVRv 91 | nUA1AQDMkiVNxuOEXCUp1R5umStJH1bgQXOoHKeAmbcnYgvXKgD/ZGZbFwMKGmeX 92 | 17RjJ34UYkqn0/rCJh9JVtalkH+v1wQ= 93 | =hcpm 94 | -----END PGP SIGNATURE----- 95 | ``` 96 | 97 | ---- 98 | 99 | Legal Name: Christoph Hoopmann 100 | 101 | GitHub username: https://github.com/choopm 102 | 103 | PGP key ID: 0x331552D979DFD7B351DD328D1BF7E603AB689BB7 104 | 105 | License release: 106 | 107 | ``` 108 | -----BEGIN PGP SIGNED MESSAGE----- 109 | Hash: SHA256 110 | 111 | I'm hereby licensing my contributions to github.com/fuhry/initramfs-scencrypt, 112 | present and future, under the MIT license (SPDX "MIT", https://spdx.org/licenses/MIT.html#licenseText) 113 | -----BEGIN PGP SIGNATURE----- 114 | 115 | iQIzBAEBCAAdFiEEMxVS2Xnf17NR3TKNG/fmA6tom7cFAl151lMACgkQG/fmA6to 116 | m7fxkhAAsrGb4PJXZo+dnKPdfbzKiikJMaDSrW8F3LmoLRCZEPESpKze36IDH5SB 117 | qcGVQYI6i2w6uZTHUAetOIDl5gddua4L5CBh+UOKFQUj/YJ0hJeYzrPgyXCh0y1G 118 | EMxuetk+RWuDB1aD8Eov/GL4eTO2Dpl+snPKYbTgiGmON+a43DYP+Aidn1SVGf4V 119 | cxOsqDK+PGmM2xF8NBWzVB69gkxj9SAsP3d9yNPjgs14RarOaZ6YZJL2A8zhkteO 120 | ru49h7phVYB4bdckARnZPZkE6sLHF+InHQW0k7cwJMwQ/5u7ixMHpHDD4I/h+Gko 121 | hiPmsh5iUHInXmvOxQpmxEuYzSwAPdIiLntZcXCeEa/hG2TMwDxd+jpbrc5pILoc 122 | V8bfKyUcr1aJdI7ofDLLjSWefMDBVWrkorayEgcMJnKc4qU+2uF9Rm6h/bT5mEqi 123 | 1vXk5KEJngDIVeAaFsVqTkPExoTgO+0qFb4xfpHkWzexQ6yIcilir/C92SJiJIys 124 | thxqsh4XPOdeZlQ4fkwllK6aDKDciBtYhnwDgcYUaibnUp9Fnhep6BARY9ZO9PrM 125 | oPnQG+8+Io4TO9xqfM2HpG/Rqa5aJNICYpg6Qb7BRUwH2jO4EszASSsqPlbNBgPE 126 | x+vlOtVX1SUgHBNlOwOJbaoj2VyQRrsavA9WzgDtuWshghRenZg= 127 | =vP+F 128 | -----END PGP SIGNATURE----- 129 | ``` 130 | 131 | -------------------------------------------------------------------------------- /COPYING: -------------------------------------------------------------------------------- 1 | THE MIT LICENSE 2 | 3 | Copyright (c) 2019 Dan Fuhry and other contributors 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /PKGBUILD: -------------------------------------------------------------------------------- 1 | pkgname=initramfs-scencrypt 2 | pkgdesc="initramfs hook that adds PGP smartcard support for LUKS FDE" 3 | pkgver=1.8 4 | pkgrel=1 5 | license=(MIT) 6 | arch=(any) 7 | depends=(gnupg) 8 | install=${pkgname}.install 9 | source=(scencrypt-hook 10 | scencrypt-install 11 | README.md) 12 | 13 | build() { 14 | return 0 15 | } 16 | 17 | package() { 18 | mkdir -p "${pkgdir}/usr/lib/initcpio/hooks" 19 | mkdir -p "${pkgdir}/usr/lib/initcpio/install" 20 | 21 | cp "${srcdir}/scencrypt-hook" "${pkgdir}/usr/lib/initcpio/hooks/scencrypt" 22 | cp "${srcdir}/scencrypt-install" "${pkgdir}/usr/lib/initcpio/install/scencrypt" 23 | 24 | mkdir -p "${pkgdir}/usr/share/doc/${pkgname}" 25 | cp "${srcdir}/README.md" "${pkgdir}/usr/share/doc/${pkgname}/" 26 | } 27 | 28 | md5sums=('SKIP' 29 | 'SKIP' 30 | 'SKIP') 31 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # GnuPG hook for Arch Linux initcpio 2 | 3 | This initcpio hook allows you to use a PGP-compatible smart card during early boot to decrypt your full disk encrypted system. 4 | 5 | # Why? 6 | 7 | This is a great solution if you want the best possible encryption strength, but without having to type a huge passphrase in every time you boot. Using a hardware-backed RSA key on a PGP smart card, with the card performing decryption of the FDE key on-chip without releasing the private key to the OS, gives you extremely strong protection from attacks, even sophisticated/well-equipped adversaries. 8 | 9 | As is the case with all LUKS systems, anyone who gets root on your box after it's booted can run `dmsetup table --showkeys` to dump the master key, the changing of which requires a complete wipe of your disk, in contrast to LUKS user key changing which requires only wiping and replacing the key slot. So don't let an adversary get root - watch your setuid programs, sudo rights, running services, etc. carefully. 10 | 11 | PGP smart cards have varying options for PIN limits and reset or self-destruct functionality - choose one that fits your needs. 12 | 13 | This hook has only been tested with the YubiKey NEO. 14 | 15 | ## Disclaimer 16 | 17 | Use this hook at your own risk. It's highly recommended to have a backup key somewhere, in case you lose or destroy your primary key. 18 | 19 | # Configuration process 20 | 21 | 1. Install Arch onto a LUKS encrypted system and get it booting using the stock `encrypt` hook and passphrase. (Beyond the scope of this document) 22 | 1. Configure your smartcard and get it working to the point that you can encrypt and decrypt things on your machine using the card. (Beyond the scope of this document) 23 | 1. Generate a new random key and encrypt it: `dd if=/dev/random bs=64 count=1 | gpg --encrypt -r your@email.tld > disk.bin.gpg` 24 | 1. Decrypt the key into memory so you can add it to your LUKS volume: `gpg --decrypt -o /dev/shm/disk.bin disk.bin.gpg` 25 | 1. `sudo cryptsetup luksAddKey /dev/your_luks_device /dev/shm/disk.bin` 26 | 1. `shred -u -n1 /dev/shm/disk.bin` to delete the decrypted `disk.bin` file from memory. 27 | 1. Edit `/etc/crypttab` to include your encrypted device. The line will look somewhat like: 28 | `arch_crypt /dev/your_luks_device /home/you/disk.bin.gpg discard` 29 | 1. Edit `/etc/mkinitcpio.conf` and replace the `encrypt` hook with `scencrypt`. Do not leave both `encrypt` and `scencrypt` enabled. 30 | 1. Make sure `root` has a GPG keychain with your public key (e.g. `gpg --export -a 0x13C7C0BA66FB8DC7 > ~/pub.gpg`, `sudo su`, `gpg --import /home//pub.gpg` 31 | 1. Run `mkinitcpio -p linux`. If there are no errors, reboot with your smart card plugged in to find out if it works. 32 | 1. (Optional) `sudo cryptSetup luksRemoveKey /dev/your_luks_device` and type the passphrase you added when you were installing Arch. This will remove the old passphrase so that only your GPG-encrypted key file can unseal the disk. 33 | 34 | # Technical details 35 | 36 | The hook works by copying your encrypted key file to the initramfs, decrypting it in memory, passing it to LUKS to unseal the disk, and then using `shred` to overwrite it in memory. 37 | 38 | Behind the scenes, `gpg` starts `scdaemon`, which talks to `pcscd` and `pinentry-tty` to get your PIN and pass it to the card along with the payload for decryption. The private key itself is held securely on the smartcard - it cannot be released even with the PIN on hand. But the decryption is quick because the payload is small. Once the disk is mounted, the smartcard can safely be removed from the system - the result of the decryption is merely a "user key" that LUKS uses to decrypt the volume's master key. There is an excellent [white paper](http://clemens.endorphin.org/nmihde/nmihde-A4-ds.pdf) written by one of the original LUKS authors detailing LUKS's extensive anti-forensic hardening. 39 | 40 | The hook will prefer `cryptkey=` kernel cmdline argument if present. It uses the same options as the stock `encrypt` hook, refer to the `cryptsetup` package for details. This allows you to use `kexec` without having to re-insert your YubiKey. For this to work you can kexec-load a `initrd` which contains the plain key file. For security reasons that initrd shall only reside in RAM. Have a look at [kexec-example.sh](kexec-example.sh). 41 | 42 | # How to contribute 43 | 44 | 1. Fork the repository 45 | 1. If you're fixing a bug, create an issue for it. New features/enhancements don't need an issue created. 46 | 1. Work in a branch ideally named after the issue you're working on, if applicable 47 | 1. When ready for review, open a pull request. 48 | 1. Don't update version numbers - the maintainers will do this when new versions are released. 49 | 1. If you're a first time contributor, add your name, PGP key ID and GitHub username to [CONTIRBUTORS.md](CONTRIBUTORS.md). **If you have not done this, your pull request will not be accepted.** 50 | -------------------------------------------------------------------------------- /initramfs-scencrypt.install: -------------------------------------------------------------------------------- 1 | post_install() { 2 | echo " >> initramfs-scencrypt - READ ME!" 3 | echo " >> Make sure to add your encrypted disks to /etc/crypttab. There is" 4 | echo " >> no support for cryptdevice=... on the kernel command line." 5 | echo "" 6 | echo " >> Key file path must end in .gpg and the private key must be" 7 | echo " >> accessible by root." 8 | echo "" 9 | echo " >> For more information, read /usr/share/doc/initramfs-scencrypt/README.md" 10 | } 11 | -------------------------------------------------------------------------------- /kexec-example.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # This script will copy the initramfs to /dev/shm, add the plain key file and use kexec to 4 | # load the new kernel+initrd+cmdline. Afterwards you can trigger kexec directly or via systemd. 5 | # You could install a pacman hook for automation, ex: /etc/pacman.d/hooks/100-kexec-load.hook 6 | # [Trigger] 7 | # Type = File 8 | # Operation = Install 9 | # Operation = Upgrade 10 | # Target = boot/vmlinuz-linux 11 | # Target = boot/initramfs-linux.img 12 | # [Action] 13 | # Description = Preparing kexec 14 | # When = PostTransaction 15 | # Exec = /home/choopm/bin/kexec-load.sh linux 16 | 17 | LINUX="${1:-linux}" 18 | INITRAMFS="/boot/initramfs-$LINUX.img" 19 | KERNEL="/boot/vmlinuz-$LINUX" 20 | KEYFILE="/home/choopm/.luks.key" 21 | 22 | umask 0077 23 | CRYPTROOT_TMPDIR="$(mktemp -d --tmpdir=/dev/shm)" 24 | INITRD="${CRYPTROOT_TMPDIR}/initrd.img" 25 | ROOTFS="$CRYPTROOT_TMPDIR/rootfs" 26 | FILENAME="keyfile.bin" 27 | CMDLINE=$(echo "$(cat /proc/cmdline | sed 's/cryptkey[^ ]*//') cryptkey=rootfs:/${FILENAME}") 28 | KVERSION=$(file $KERNEL | sed -r 's/.*version ([^ ]*).*/\1/') 29 | mkdir -p $ROOTFS 30 | 31 | cleanup() { 32 | shred -fu "$ROOTFS/$FILENAME" || true 33 | shred -fu "$INITRD" || true 34 | rm -rf "${CRYPTROOT_TMPDIR}" 35 | } 36 | trap cleanup INT TERM EXIT 37 | 38 | echo "==> Patching and kexec-loading ${INITRD}" 39 | 40 | cd "${ROOTFS}" 41 | cat "${INITRAMFS}" | gzip -cd | cpio --quiet -i 42 | cp $KEYFILE $FILENAME 43 | find . | cpio --quiet -H newc -o | gzip >> "${INITRD}" 44 | 45 | /usr/bin/kexec -l "${KERNEL}" --initrd="${INITRD}" --command-line="${CMDLINE}" 46 | echo "==> Loaded kernel ${KVERSION}, use: systemctl kexec to reboot" 47 | 48 | -------------------------------------------------------------------------------- /scencrypt-hook: -------------------------------------------------------------------------------- 1 | #!/usr/bin/ash 2 | 3 | card_status() { 4 | /usr/bin/gpg --homedir "/etc/initcpio/gpg" --card-status --no-tty \ 5 | >/dev/null 2>&1 6 | return $? 7 | } 8 | 9 | decrypt_file() { 10 | local input="$1" 11 | local output="${2:--}" 12 | local status_file="/etc/initcpio/status" 13 | local again=1 14 | while [ $again -eq 1 ]; do 15 | /usr/bin/gpg --homedir "/etc/initcpio/gpg" \ 16 | --status-file "$status_file" \ 17 | -o "${output}" --decrypt "${input}" \ 18 | 0/dev/console 2>/dev/console 19 | local status=$? 20 | if [ "$status" -eq 0 ]; then 21 | again=0 22 | else 23 | grep "^\[GNUPG:\] ERROR pkdecrypt_failed 100663383$" "$status_file" 24 | if [ $? -eq 0 ]; then 25 | again=1 26 | else 27 | again=0 28 | fi 29 | fi 30 | echo -n "" > "$status_file" 31 | done 32 | return $status 33 | } 34 | 35 | retry() { 36 | local timeout="$1"; shift 37 | local message="$1"; shift 38 | local command="$@" 39 | local status=1 40 | local i=0 41 | eval $command 42 | status=$? 43 | if [ "$status" -gt 0 ]; then 44 | echo "$message" >/dev/console 45 | echo -n "Timeout is $timeout seconds:" >/dev/console 46 | while true; do 47 | eval $command 48 | status=$? 49 | [ $status -eq 0 ] && break 50 | [ $i -eq $timeout ] && break 51 | i=$(($i + 1)) 52 | echo -n "." >/dev/console 53 | read -t 1 -s 0/dev/console 56 | fi 57 | return $status 58 | } 59 | 60 | run_hook() { 61 | modprobe -a -q dm-crypt >/dev/null 2>&1 62 | [ "${quiet}" = "y" ] && CSQUIET=">/dev/null" 63 | 64 | # Get plain key file if specified, example: cryptkey=/dev/sda:2048:4096, cryptkey=rootfs:/keyfile.bin 65 | ckeyfile= 66 | if [ -n "$cryptkey" ]; then 67 | IFS=: read ckdev ckarg1 ckarg2 </dev/null 2>&1 81 | umount /ckey 82 | ;; 83 | *) 84 | # Read raw data from the block device 85 | # ckarg1 is numeric: ckarg1=offset, ckarg2=length 86 | dd if="$resolved" of="$ckeyfile" bs=1 skip="$ckarg1" count="$ckarg2" >/dev/null 2>&1 87 | ;; 88 | esac 89 | fi 90 | fi 91 | 92 | sed -re 's;#.*$;;g' -e '/^[ ]*$/ d' -i /etc/crypttab 93 | 94 | IFS_BACKUP="$IFS" 95 | IFS=$'\n' 96 | for line in $(cat /etc/crypttab); do 97 | # parse fields in the crypttab line 98 | IFS="$IFS_BACKUP" read mapped_name device_path key_spec options </dev/null 2>&1 116 | key_file=/keyfile.bin 117 | elif [ -b "${key_file}" ]; then 118 | echo "ERROR: Key files on block devices are not supported yet." 119 | key_file= 120 | elif [ -r "${key_file}" -a "${key_file%.gpg}" != "${key_file}" ]; then 121 | # /.gnupg is where the scdaemon socket lives 122 | test -d /.gnupg || mkdir -p /.gnupg 123 | chmod -R go-rwx /.gnupg /etc/initcpio/gpg 124 | 125 | # store the key at a known path. this allows the same key to be 126 | # used for multiple disks and only have to decrypt once. 127 | key_dest_path=/etc/initcpio/gpg/key_${key_file//\//S} 128 | 129 | # only attempt decryption if the keypath doesn't exist. 130 | if [ -r "${key_dest_path}" ]; then 131 | key_file="${key_dest_path}" 132 | else 133 | # we need to decrypt. 134 | 135 | # test communication with card - this is also needed for 136 | # decryption to work at all 137 | retry 60 "Waiting for the smartcard to be inserted 138 | (or press enter to falling back to passphrase)" card_status 139 | 140 | # now attempt to decrypt 141 | if decrypt_file "${key_file}" "${key_dest_path}"; then 142 | # we got it! 143 | key_file="${key_dest_path}" 144 | else 145 | # if decryption fails, still prompt for a passphrase 146 | echo "Failed to decrypt key file with GPG." 147 | echo "Falling back to passphrase." 148 | key_file= 149 | fi 150 | fi 151 | elif [ -r "${key_file}" ]; then 152 | cp "${key_file}" /keyfile.bin 153 | key_file=/keyfile.bin 154 | fi 155 | 156 | ## end key retrieval 157 | ## start device setup 158 | 159 | # parse options 160 | luksoptions="" 161 | for option in ${options//,/ }; do 162 | case "$option" in 163 | discard) 164 | luksoptions="$luksoptions --allow-discards" 165 | ;; 166 | *) 167 | echo "Warning: ignoring unknown crypttab option: $option" 168 | esac 169 | done 170 | 171 | # resolve block device 172 | if resolved=$(resolve_device "${device_path}" "${rootdelay}"); then 173 | if cryptsetup isLuks "${device_path}"; then 174 | # LUKS devices 175 | 176 | # open device with key file 177 | if [ -n "$key_file" ]; then 178 | if ! eval cryptsetup luksOpen --key-file="${key_file}" \ 179 | $luksoptions "${resolved}" "${mapped_name}"; then 180 | echo "WARNING: Failed to luksOpen crypto device" \ 181 | ${device_path} 182 | key_file= 183 | fi 184 | fi 185 | 186 | # open device with passphrase 187 | if [ ! -n "$key_file" ]; then 188 | if ! eval cryptsetup luksOpen $luksoptions "${resolved}" \ 189 | "${mapped_name}"; then 190 | echo "WARNING: Failed to luksOpen crypto device" \ 191 | ${device_path} 192 | fi 193 | fi 194 | else 195 | # non-LUKS 196 | echo "ERROR: ${device_path} is not a LUKS volume." 197 | echo "Plain dm-crypt is not supported by the scencrypt hook." 198 | fi 199 | else 200 | echo "WARNING: Failed to resolve crypto device ${device_path}" 201 | fi 202 | done 203 | IFS="$IFS_BACKUP" 204 | 205 | /usr/bin/gpg-connect-agent --homedir "/etc/initcpio/gpg" KILLAGENT /bye \ 206 | >/dev/null 2>&1 207 | rm -rf /etc/initcpio/gpg 208 | } 209 | 210 | # vim: set ft=sh ts=4 sw=4 et: 211 | -------------------------------------------------------------------------------- /scencrypt-install: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | build() { 4 | local mod 5 | 6 | add_module dm-crypt 7 | if [[ $CRYPTO_MODULES ]]; then 8 | for mod in $CRYPTO_MODULES; do 9 | add_module "$mod" 10 | done 11 | else 12 | add_all_modules '/crypto/' 13 | fi 14 | 15 | if [ -d $BUILDROOT/etc/initcpio/gpg ]; then 16 | echo "WARNING! /etc/initcpio/gpg exists in initramfs buildroot. Huh?" 17 | rm -rf "$BUILDROOT/etc/initcpio/gpg" 18 | fi 19 | 20 | mkdir -p $BUILDROOT/etc/initcpio/gpg 21 | chmod 0700 $BUILDROOT/etc/initcpio/gpg 22 | echo "pinentry-program /usr/bin/pinentry" > $BUILDROOT/etc/initcpio/gpg/gpg-agent.conf 23 | 24 | add_binary "cryptsetup" 25 | add_binary "dmsetup" 26 | add_binary "gpg" 27 | add_binary "gpg-agent" 28 | add_binary "pinentry-tty" 29 | add_binary "gpg-connect-agent" 30 | add_binary "/usr/lib/gnupg/scdaemon" 31 | add_file "/usr/lib/udev/rules.d/10-dm.rules" 32 | add_file "/usr/lib/udev/rules.d/13-dm-disk.rules" 33 | add_file "/usr/lib/udev/rules.d/95-dm-notify.rules" 34 | add_file "/usr/lib/initcpio/udev/11-dm-initramfs.rules" "/usr/lib/udev/rules.d/11-dm-initramfs.rules" 35 | 36 | # cryptsetup calls pthread_create(), which dlopen()s libgcc_s.so.1 37 | add_binary "/usr/lib/libgcc_s.so.1" 38 | 39 | # add_file "/etc/crypttab" # file is added later line by line 40 | 41 | ln -s "pinentry-tty" "$BUILDROOT/usr/bin/pinentry" 42 | 43 | # create a tmp dir 44 | mkdir -p $BUILDROOT/tmp 45 | 46 | # Iterate over entries in /etc/crypttab looking for regular keyfiles 47 | sed -re 's;#.*$;;g' -e '/^[ \t]*$/ d' /etc/crypttab | awk '{print $3;}' | \ 48 | while read f; do 49 | # Path must begin with a slash and must be a regular file 50 | if [ "${f:0:1}" = "/" -a -f "$f" ]; then 51 | # file must end in .gpg 52 | extension="${f##*.}" 53 | if [[ "${extension}" =~ ^(gpg|pgp|asc)$ ]] ; then 54 | # add file line to crypttab 55 | fgrep -w $f /etc/crypttab >> "$BUILDROOT/tmp/crypttab" 56 | 57 | # Determine the keyid used to encrypt this keyfile 58 | keyid=$(gpg -q --list-packets --list-only $f 2>&1 | egrep -o '(ID|keyid) [0-9A-F]{16}' | awk '{print $2;}' | tail -1) 59 | 60 | # If we got a keyid, export that key. Recent versions of GPG will fail to 61 | # export secret key stubs, so if we don't get any output, export just the 62 | # public key. Note that this means decryption will fail if you add only the 63 | # public key to root's keyring. 64 | if [ -n "$keyid" ]; then 65 | keyfile="$BUILDROOT/tmp/$keyid.asc" 66 | gpg --homedir /root/.gnupg --export-options export-minimal --export-secret-keys -a 0x${keyid} 2>/dev/null > $keyfile 67 | if ! egrep -q '.*' $keyfile; then 68 | gpg --homedir /root/.gnupg --export-options export-minimal --export -a 0x${keyid} > $keyfile 69 | fi 70 | gpg --homedir "$BUILDROOT/etc/initcpio/gpg" --import $keyfile 71 | fi 72 | fi 73 | add_file "$f" 74 | fi 75 | done 76 | 77 | # Remove duplicate lines (first sort and then use uniq) 78 | sort "$BUILDROOT/tmp/crypttab" | uniq > "$BUILDROOT/etc/crypttab" 79 | # Remove tmp dir 80 | rm -rf "$BUILDROOT/tmp" 81 | 82 | add_runscript 83 | } 84 | 85 | help() { 86 | cat <