<commit_before>#!/bin/sh

## safe-key-setup

####
# Creates a full-strength GPG keypair with a sub-key for encryption, optional multiple sub-keys
# for signing, optionally signs the key with specified existing keys, optionally imports a
# specified image, creates a revocation cert, backs up the master secret key and removes it from
# the main keyring (so it can be kept separate from the public master and subkeys, for use only
# when necessary).
####
# © Copyright 2013 <NAME>
#
#  This program is free software: you can redistribute it and/or modify
#  it under the terms of the GNU Affero General Public License as published by
#  the Free Software Foundation, either version 3 of the License, or
#  (at your option) any later version.
#
#  This program is distributed in the hope that it will be useful,
#  but WITHOUT ANY WARRANTY; without even the implied warranty of
#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#  GNU Affero General Public License for more details.
#
#  You should have received a copy of the GNU Affero  General Public License
#  along with this program.  If not, see <http://www.gnu.org/licenses/>.
####
# Reference links (TODO: may need to copy some license-headers from one or two of these if they
#                  have actual code similar to mine...?):
#
#  http://blog.sanctum.geek.nz/linux-crypto-gnupg-keys/
#  http://security.stackexchange.com/questions/31594/what-is-a-good-general-purpose-gnupg-key-setup
#  http://security.stackexchange.com/questions/29851/how-many-gpg-keys-should-i-make
#  http://keyring.debian.org/creating-key.html
#  https://wiki.debian.org/subkeys
#  http://www.openpgp-schulungen.de/scripte/keygeneration/#download
#  https://we.riseup.net/riseuplabs+paow/openpgp-best-practices


# NB:
#
# * I only had time to throw this together enough to "work for me". I know there are things that
#   still need ironing out, but my free-time is a bit sporadic at the moment. However I would love
#   this tool to become generally useful and would really appreciate any feedback, bug-reports and
#   patches. Particularly I want this to be paranoically safe - I have already used a weird hack
#   with a foregrounded memlockd to avoid swappable memory but haven't yet worked out how to
#   (temporarily disable?) avoid computer hibernation storing passwords to disk. Thanks.
#
# * Deliberately using same Full Name field and no Comment fields for all UIDs. When making a strong master
#   key there should be no ambiguity about the name, and comments are almost always used wrongly (which
#   confuses things later) and are almost never actually needed (the few who do should edit them manually).
#
# * Deliberately not offering to upload it to a keyserver at the end - I presently think that is
#   just too risky in an automated script and shouldn't be encouraged. If you think I should change
#   my mind please email me and give me your reasoning...

# FIXME:
#
#       [straight-forward stuff]
#
# * Make all code tolerate filenames with embedded space (this will introduce lots of evals
#   though...).
#
# * Set the password from the moment the key is created (so there is no window of vulnerability)
#   and pipe the password in for all steps using $HIDDEN_PRINTF.
#
# * Redirect this script's STDIN to /dev/null during keys' creation so any entropy assistance
#   (typing) won't be inserted later as gibberish when trying to save the key.
#
# * Use and respect gpg lock files (e.g. secring.gpg.lock, etc), for obvious reasons.
#
# * Manually audit this script and confirm each gpg invocation is inputting exactly the expected
#   sequence of text.
#
#       [not so simple stuff]
#
# * Work out if there is any way to avoid using hibernatable memory (or disable hibernation
#   during this script).
#
#       [can only be improved in gpg, not here -> heads-up gpg devs...!]
#
# * At present GPG's batch generation capability is not mature, so this script necessarily reverts
#   to hackish, not-future-proof, fragile "faked input" in some places. The only proper solution
#   to this is to improve GPG though.
#
# * It is only possible to specify one subkey during automated key creation, so the extra subkeys,
#   etc have to be added via an extra step. The "proper way" is for the GPG developers to extend its
#   batch generation facility for [A] multiple subkeys during key generation, and [B] adding subkeys
#   to existing keys, etc.

# TODO:
#
#       [when I have time]
#
# * Add copyright headers from one or two references in the list above, if relevant (can't remember
#   at the moment).
#
# * Add "set -e" to the top of the script and check that every command is failproofed.
#
#       [to decide if wise first]
#
# * Perhaps automate updating trustdb (configurably), after all other actions are done.

# Getopts
thisscript="$(readlink -e "$0")"
while $# -gt 0; do
	case "$1" in
	--source)
		cat "$thisscript"
		exit 0;;
	--)
		shift
		break;;
	-*)
		printf "Unknown commandline flag. Aborting.\n" >&2
		exit(1);;
	*)
		break;;
	esac
done

## This is a perverse hack to lock the whole script into non-swappable memory
printf -- '%s\n' "$thisscript" >/dev/shm/temp-memlock-$$.cfg
sudo /usr/sbin/memlockd -c /dev/shm/temp-memlock-$$.cfg -u memlockd -f -d >/dev/null 2>&1 &
mlockpid=$!

## Don't create anything readable by other users (except root...)
umask 077

## Preset these here. They can be overriden by env vars...
if test -z "$GPGINVOKE"; then
	if command -v gpg2 >/dev/null 2>&1; then
		GPGINVOKE='LC_ALL= LC_MESSAGES=C gpg2'
	else
		GPGINVOKE='LC_ALL= LC_MESSAGES=C gpg'
	fi
fi
HOME="${HOME:-$(cd && pwd)}"
GNUPGHOME="${GNUPGHOME:-${HOME}/.gnupg}"
GNUPGCONF="${GNUPGCONF:-${GNUPGHOME}/gpg.conf}"
GNUPGPUBKEYRING="${GNUPGPUBKEYRING:-${GNUPGHOME}/pubring.gpg}"
GNUPGSECKEYRING="${GNUPGSECKEYRING:-${GNUPGHOME}/secring.gpg}"
if test -z "$SAFEKEY_WORKDIR"; then
	if test -d /dev/shm && -r /dev/shm && -x /dev/shm && -w /dev/shm; then
		SAFEKEY_WORKDIR=/dev/shm
	else
		SAFEKEY_WORKDIR="$HOME"<commit_msg>Small comments cleanup.<commit_after>#!/bin/sh

## safe-key-setup

####
# Creates a full-strength GPG keypair with a sub-key for encryption, optional multiple sub-keys
# for signing, optionally signs the key with specified existing keys, optionally imports a
# specified image, creates a revocation cert, backs up the master secret key and removes it from
# the main keyring (so it can be kept separate from the public master and subkeys, for use only
# when necessary).
####
# © Copyright 2013 <NAME>
#
#  This program is free software: you can redistribute it and/or modify
#  it under the terms of the GNU Affero General Public License as published by
#  the Free Software Foundation, either version 3 of the License, or
#  (at your option) any later version.
#
#  This program is distributed in the hope that it will be useful,
#  but WITHOUT ANY WARRANTY; without even the implied warranty of
#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#  GNU Affero General Public License for more details.
#
#  You should have received a copy of the GNU Affero  General Public License
#  along with this program.  If not, see <http://www.gnu.org/licenses/>.
####
# Reference links (TODO: may need to copy some license-headers from one or two of these if they
#                  have actual code similar to mine...?):
#
#  http://blog.sanctum.geek.nz/linux-crypto-gnupg-keys/
#  http://security.stackexchange.com/questions/31594/what-is-a-good-general-purpose-gnupg-key-setup
#  http://security.stackexchange.com/questions/29851/how-many-gpg-keys-should-i-make
#  http://keyring.debian.org/creating-key.html
#  https://wiki.debian.org/subkeys
#  http://www.openpgp-schulungen.de/scripte/keygeneration/#download
#  https://we.riseup.net/riseuplabs+paow/openpgp-best-practices


# NB:
#
# * I only had time to throw this together enough to "work for me". I know there are things that
#   still need ironing out, but my free-time is a bit sporadic at the moment. However I would love
#   this tool to become generally useful and would really appreciate any feedback, bug-reports and
#   patches. Particularly I want this to be paranoically safe - I have already used a weird hack
#   with a foregrounded memlockd to avoid swappable memory but haven't yet worked out how to
#   (temporarily disable?) avoid computer hibernation storing passwords to disk. Thanks.
#
# * Deliberately using same Full Name field and no Comment fields for all UIDs. When making a strong master
#   key there should be no ambiguity about the name, and comments are almost always used wrongly (which
#   confuses things later) and are almost never actually needed (the few who do should edit them manually).
#
# * Deliberately not offering to upload it to a keyserver at the end - I presently think that is
#   just too risky in an automated script and shouldn't be encouraged. If you think I should change
#   my mind please email me and give me your reasoning...

# FIXME:
#
#       [straight-forward stuff]
#
# * Make all code tolerate filenames with embedded space (this will introduce lots of evals
#   though...).
#
# * Set the password from the moment the key is created (so there is no window of vulnerability)
#   and pipe the password in for all steps using $HIDDEN_PRINTF.
#
# * Redirect this script's STDIN to /dev/null during keys' creation so any entropy assistance
#   (typing) won't be inserted later as gibberish when trying to save the key.
#
# * Use and respect gpg lock files (e.g. secring.gpg.lock, etc), for obvious reasons.
#
# * Manually audit this script and confirm each gpg invocation is inputting exactly the expected
#   sequence of text.
#
#       [not so simple stuff]
#
# * Work out if there is any way to avoid using hibernatable memory (or disable hibernation
#   during this script).
#
#       [can only be improved in gpg, not here -> heads-up gpg devs...!]
#
# * At present GPG's batch generation capability is not mature, so this script necessarily reverts
#   to hackish, not-future-proof, fragile "faked input" in some places. The only proper solution
#   to this is to improve GPG though.
#
# * It is only possible to specify one subkey during automated key creation, so the extra subkeys,
#   etc have to be added via an extra step. The "proper way" is for the GPG developers to extend its
#   batch generation facility for [A] multiple subkeys during key generation, and [B] adding subkeys
#   to existing keys, etc.

# TODO:
#
#       [when I have time]
#
# * Add copyright headers from one or two references in the list above, if relevant (can't remember
#   at the moment).
#
# * Add "set -e" to the top of the script and check that every command is failproofed.
#
#       [to decide if wise first]
#
# * Perhaps automate updating trustdb (configurably), after all other actions are done.

# Getopts
thisscript="$(readlink -e "$0")"
while $# -gt 0; do
	case "$1" in
	--source)
		cat "$thisscript"
		exit 0;;
	--)
		shift
		break;;
	-*)
		printf "Unknown commandline flag. Aborting.\n" >&2
		exit(1);;
	*)
		break;;
	esac
done

## This is a perverse hack to lock the whole script into non-swappable memory
printf -- '%s\n' "$thisscript" >/dev/shm/temp-memlock-$$.cfg
sudo /usr/sbin/memlockd -c /dev/shm/temp-memlock-$$.cfg -u memlockd -f -d >/dev/null 2>&1 &
mlockpid=$!

## Don't create anything readable by other users (except root...)
umask 077

## Presets. Overridable by env vars...
if test -z "$GPGINVOKE"; then
	if command -v gpg2 >/dev/null 2>&1; then
		GPGINVOKE='LC_ALL= LC_MESSAGES=C gpg2'
	else
		GPGINVOKE='LC_ALL= LC_MESSAGES=C gpg'
	fi
fi
HOME="${HOME:-$(cd && pwd)}"
GNUPGHOME="${GNUPGHOME:-${HOME}/.gnupg}"
GNUPGCONF="${GNUPGCONF:-${GNUPGHOME}/gpg.conf}"
GNUPGPUBKEYRING="${GNUPGPUBKEYRING:-${GNUPGHOME}/pubring.gpg}"
GNUPGSECKEYRING="${GNUPGSECKEYRING:-${GNUPGHOME}/secring.gpg}"
if test -z "$SAFEKEY_WORKDIR"; then
	if test -d /dev/shm && -r /dev/shm && -x /dev/shm && -w /dev/shm; then
		SAFEKEY_WORKDIR=/dev/shm
	else
		SAFEKEY_WORKDIR="$HOME"
{'fraction_non_alphanumeric': 0.09878292764254752, 'fraction_numerical': 0.005001667222407469, 'mean_word_length': 3.713948919449902, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 21, 'https://': 4, 'lorem ipsum': 0, 'www.': 4, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2594357', 'n_tokens_mistral': 3834, 'n_tokens_neox': 3655, 'n_words': 1574}