A crypto/keytype => crypto/keytype +151 -0
@@ 0,0 1,151 @@
+#!/bin/bash
+
+name="keytype"
+version="1.0"
+read -r -d '' help_message <<-EOF
+ Inspect a cryptographic key for type and length
+ Usage: keytype [OPTIONS] KEYFILE
+ Options:
+ -h, --help print this message and exit
+ -q, --quiet suppress error messages and prompts
+ -v, --verbose show additional messages
+ -V, --version print version number and exit
+EOF
+
+source /usr/local/lib/mylib.bash
+
+quiet=0
+verbose=0
+while [[ $# -gt 0 ]]; do
+ case "$1" in
+
+ -h|--help)
+ help_msg
+ shift
+ ;;
+
+ -q|--quiet)
+ debug_msg "Setting quiet option to 1 (was ${quiet})"
+ quiet=1
+ shift
+ ;;
+
+ -v|--verbose)
+ debug_msg "Setting verbose option to 1 (was ${verbose})"
+ verbose=1
+ shift
+ ;;
+
+ -V|--version)
+ version_msg
+ ;;
+
+ *)
+ debug_msg "Argument '${1}' added to positional array"
+ positional+=("$1")
+ shift
+ ;;
+ esac
+done
+
+try_openssh() {
+ keylength=
+ keyfingerprint=
+ keytype=
+ keycomment=
+
+ keyinfo="$(/usr/bin/ssh-keygen -l -f "$keyfile" 2>/dev/null)"
+
+ if [ $? -ne 0 ]; then
+ debug_msg "file '${keyfile}' is not an OpenSSH key"
+ return 1
+ else
+ keylength="$(/usr/bin/cut --delimiter=' ' --field=1 <<<"$keyinfo")"
+ keyfingerprint="$(/usr/bin/cut --delimiter=' ' --field=2 <<<"$keyinfo")"
+ keycomment="$(/usr/bin/awk '{$1=$2=$NF="";print substr($0,3,length($0)-3)}' <<<"$keyinfo")"
+ keytype="$(/usr/bin/awk '{print substr($NF,2,length($NF)-2)}' <<<"$keyinfo")"
+
+ /usr/bin/printf "%s: %s-bit %s OpenSSH key\n" "${keyfile}" "${keylength}" "${keytype}"
+ return 0
+ fi
+}
+
+try_openpgp() {
+ keyinfo=
+ keyprivacy=
+ keylength=
+ keytypenum=
+ keytype=
+ keyfingerprint=
+
+ keyinfodump="$(/usr/bin/gpg2 --show-keys --with-colons "$keyfile" 2>/dev/null)"
+
+ if [ $? -ne 0 ]; then
+ debug_msg "file '${keyfile}' is not an OpenPGP key"
+ return 1
+ else
+ if /usr/bin/grep -e "^pub:" <<<"$keyinfodump" >/dev/null 2>&1; then
+ keyprivacy="public"
+ keyinfo="$(/usr/bin/grep -e "^pub:" <<<"$keyinfodump")"
+ elif /usr/bin/grep -e "^sec:" <<<"$keyinfodump" >/dev/null 2>&1; then
+ keyprivacy="private"
+ keyinfo="$(/usr/bin/grep -e "^sec:" <<<"$keyinfodump")"
+ else
+ debug_msg "file '${keyfile}' is an OpenPGP key, but it cannot be interpretted"
+ fi
+
+ keylength="$(/usr/bin/cut --delimiter=':' --field=3 <<<"$keyinfo")"
+ keytypenum="$(/usr/bin/cut --delimiter=':' --field=4 <<<"$keyinfo")"
+
+ case "$keytypenum" in
+ 1)
+ keytype="RSA"
+ ;;
+
+ 16)
+ keytype="Elgamel"
+ ;;
+
+ 17)
+ keytype="DSA"
+ ;;
+
+ *)
+ error_msg "Unknown algorythm on OpenPGP key"
+ ;;
+
+ #2 is deprecated as RSA Encrypt Only
+ #3 is deprecated as RSA Sign Only
+ #18 is reserved for Elliptic Curve but not part of the OpenPGP spec yet
+ #19 is reserved for ECDSA but not part of the OpenPGP spec yet
+ #20 is reserved; deprecated as Elgamel Encrypt or Sign
+ #21 is reserved for Diffie-Hellman but not part of the OpenPGP spec yet
+ #100-110 are reserved for experimental use
+ #256+ are reserved for Libgcrypt to allocate
+ esac
+
+ keyfingerprint="$(/usr/bin/cut --delimiter=':' --field=5 <<<"$keyinfo")"
+
+ /usr/bin/printf "%s: %s-bit %s %s OpenPGP key\n" "${keyfile}" "${keylength}" "${keyprivacy}" "${keytype}"
+ return 0
+ fi
+}
+
+try_openssl() {
+ #TODO: implement OpenSSL checks
+ :
+}
+
+code=0
+for keyfile in "${positional[@]}"; do
+ if ! try_openssh; then
+ if ! try_openpgp; then
+ if ! try_openssl; then
+ code=1
+ fi
+ fi
+ fi
+done
+
+exit "$code"
+
A crypto/mkhtpasswd => crypto/mkhtpasswd +39 -0
@@ 0,0 1,39 @@
+#!/bin/bash
+
+name="mkhtpasswd"
+version="1.0"
+read -r -d '' help_message <<-EOF
+ Create an Apache htpasswd file
+ Usage: mkhtpasswd [OPTIONS] >>.htpasswd
+ Options:
+ -h, --help print this message and exit
+ -q, --quiet suppress error messages and prompts
+ -v, --verbose show additional messages
+ -V, --version print version number and exit
+EOF
+
+source /usr/local/lib/mylib.bash
+. /usr/local/lib/myparse.bash
+
+# Get username
+user=
+/usr/bin/printf "Enter username: " >&2
+read user
+if [[ -z "$user" ]]; then
+ error_msg "expected non-empty username"
+fi
+
+# Get password
+passwd=
+/usr/bin/printf "Enter password:" >&2
+read -s passwd
+/usr/bin/printf "\n" >&2
+if [[ -z "$passwd" ]]; then
+ debug_msg "Using empty password"
+else
+ debug_msg "Using a non-empty password"
+fi
+
+# Print out the htpasswd file
+/usr/bin/printf '%s:%s\n' "$user" "$(/usr/bin/openssl passwd -crypt "$passwd")"
+
A crypto/mkkey => crypto/mkkey +204 -0
@@ 0,0 1,204 @@
+#!/bin/bash
+
+name="mkkey"
+version="1.0"
+read -r -d '' help_message <<-EOF
+ Create a cryptographic keypair
+ Usage: mkkey [OPTIONS] [FILE]
+ Options:
+ -a ALGO, algorithm for keypair [rsa, ed25519]
+ --algorithm ALGO
+ -h, --help print this message and exit
+ -q, --quiet suppress error messages and prompts
+ --private NAME private key file name
+ --public NAME public key file name
+ -t TYPE, type of keypair [ssh, pgp, ssl]
+ --type TYPE
+ -v, --verbose show additional messages
+ -V, --version print version number and exit
+EOF
+
+source /usr/local/lib/mylib.bash
+
+positional=()
+keytype=
+keyalgo=
+privkey=
+pubkey=
+quiet=
+verbose=
+while [[ $# -gt 0 ]]; do
+ case "$1" in
+
+ -a|--algorithm)
+ debug_msg "Setting algorithm to '$2' (was ${keyalgo})"
+ keyalgo="$2"
+ shift; shift
+ ;;
+
+ -h|--help)
+ help_msg
+ shift
+ ;;
+
+ -q|--quiet)
+ debug_msg "Setting quiet option to 1 (was ${quiet})"
+ quiet=1
+ shift
+ ;;
+
+ --private)
+ debug_msg "Setting private key file name to '$2' (was ${privkey})"
+ privkey="$2"
+ shift; shift
+ ;;
+
+ --public)
+ debug_msg "Setting public key file name to '$2' (was ${pubkey})"
+ pubkey="$2"
+ shift; shift
+ ;;
+
+ -t|--type)
+ debug_msg "Setting type to '$2' (was ${keytype})"
+ keytype="$2"
+ shift; shift
+ ;;
+
+ -v|--verbose)
+ debug_msg "Setting verbose option to 1 (was ${verbose})"
+ verbose=1
+ shift
+ ;;
+
+ -V|--version)
+ version_msg
+ ;;
+
+ *)
+ debug_msg "Argument '${1}' added to positional array"
+ positional+=("$1")
+ shift
+ ;;
+ esac
+done
+
+# handle output files
+# NOTE: individual key types have additional requirements for output files
+if [[ ${#positional[@]} -gt 0 ]] && [[ -z "$privkey" ]]; then
+ debug_msg "Moving a positional argument into private key file name option"
+ privkey="${positional[0]}"
+ positional=("${positional[@]:1}")
+fi
+if [[ "$privkey" = "$pubkey" ]]; then
+ error_msg "expected different file names for public and private key"
+fi
+
+try_openssh() {
+ # if pubkey filename is specified, check if it complies with ssh-keygen
+ if [[ ! -z "$pubkey" ]] && [[ "$pubkey" != "${privkey}.pub" ]]; then
+ if [[ -z "$privkey" ]]; then
+ privkey="$(/usr/bin/basename "$pubkey" ".pub")"
+ if [[ "$privkey" = "$pubkey" ]]; then
+ error_msg "public key must be written to a file named like the private key"
+ fi
+ else
+ error_msg "public key must be written to a file named like the private key"
+ fi
+ fi
+
+ # if privkey filename is not specified, use defaults
+ if [[ -z "$privkey" ]]; then
+ if [[ "$keyalgo" = "rsa" ]]; then
+ privkey="${HOME}/.ssh/id_rsa"
+ debug_msg "Default file for private RSA key is '${privkey}'"
+ pubkey="${privkey}.pub"
+ debug_msg "Default file for public RSA key is '${pubkey}'"
+ elif [[ "$keyalgo" = "ed25519" ]]; then
+ privkey="${HOME}/.ssh/id_ed25519"
+ debug_msg "Default file for private Ed25519 key is '${privkey}'"
+ pubkey="${privkey}.pub"
+ debug_msg "Default file for public Ed25519 key is '${pubkey}'"
+ else
+ error_msg "key algorithm '${keyalgo}' not implemented"
+ fi
+ fi
+
+ # check if keypair files already exist
+ if [[ -f "$privkey" ]]; then
+ error_msg "file '${privkey}' already exists"
+ elif [[ -f "${pubkey}" ]]; then
+ error_msg "file '${pubkey}' already exists"
+ fi
+
+ # make keypair
+ if [[ "$keyalgo" = "rsa" ]]; then
+ if ! /usr/bin/ssh-keygen -t rsa -b 4096 -f "$privkey"; then
+ error_msg "failed to generate RSA keypair"
+ fi
+ elif [[ "$keyalgo" = "ed25519" ]]; then
+ if ! /usr/bin/ssh-keygen -t ed25519 -f "$privkey"; then
+ error_msg "failed to generate Ed25519 keypair"
+ fi
+ else
+ error_msg "key algorithm '${keyalgo}' not implemented"
+ fi
+}
+
+try_openpgp() {
+ :
+}
+
+try_openssl() {
+ # if privkey filename is not specified, try basename of pubkey
+ if [[ -z "$privkey" ]]; then
+ if [[ -z "$pubkey" ]]; then
+ error_msg "expected private key file name"
+ else
+ privkey="$(/usr/bin/basename "$pubkey" ".pub")"
+ if [[ "$privkey" = "$pubkey" ]]; then
+ error_msg "expected private key file name"
+ fi
+ fi
+ fi
+
+ # if pubkey filename is not specified, use privkey as basename
+ if [[ -z "$pubkey" ]] && [[ ! -z "$privkey" ]]; then
+ pubkey="${privkey}.pub"
+ fi
+
+ # check if keypair files already exist
+ if [[ -f "$privkey" ]]; then
+ error_msg "file '${privkey}' already exists"
+ elif [[ -f "${pubkey}" ]]; then
+ error_msg "file '${pubkey}' already exists"
+ fi
+
+ # make keypair
+ if [[ "$keyalgo" = "rsa" ]]; then
+ if ! /usr/bin/openssl genrsa -out "$privkey" 4096; then
+ error_msg "failed to generate RSA keypair"
+ elif ! /usr/bin/openssl rsa -in "$privkey" -pubout -out "$pubkey"; then
+ error_msg "failed to generate RSA public key"
+ fi
+ elif [[ "$keyalgo" = "ed25519" ]]; then
+ if ! /usr/bin/openssl genpkey -algorithm Ed25519 -out "$privkey"; then
+ error_msg "failed to generate Ed25519 keypair"
+ elif ! /usr/bin/openssl pkey -in "$privkey" -pubout -out "$pubkey"; then
+ error_msg "failed to generate Ed25519 public key"
+ fi
+ else
+ error_msg "key algorithm '${keyalgo}' not implemented"
+ fi
+}
+
+if [[ "$keytype" = "ssh" ]]; then
+ try_openssh
+elif [[ "$keytype" = "pgp" ]]; then
+ try_openpgp
+elif [[ "$keytype" = "ssl" ]]; then
+ try_openssl
+else
+ error_msg "key type '${keytype}' not implemented"
+fi
+
A crypto/pgpls => crypto/pgpls +25 -0
@@ 0,0 1,25 @@
+#!/bin/sh
+
+name="pgpls"
+version="1.0"
+usage_message="Usage: pgpls [OPTIONS] [KEY ..]"
+help_message=$(/usr/bin/cat <<-EOF
+ List OpenPGP keys on the keychain
+ Usage: pgpls [OPTIONS]
+ Options:
+ -h, --help print this message and exit
+ -q, --quiet suppress error messages
+ -v, --version print version number and exit
+EOF
+)
+
+. /usr/local/lib/myminiparse.sh
+
+code=0
+if ! /usr/bin/gpg2 –list-keys; then
+ code=1
+fi
+
+# exit with stored code
+exit "$code"
+
A crypto/pgprm => crypto/pgprm +37 -0
@@ 0,0 1,37 @@
+#!/bin/sh
+
+name="pgprm"
+version="1.0"
+usage_message="Usage: pgprm [OPTIONS] [KEY ..]"
+help_message=$(/usr/bin/cat <<-EOF
+ Delete an OpenPGP key from the keychain
+ Usage: pgprm [OPTIONS] [KEY ..]
+ Options:
+ -h, --help print this message and exit
+ -q, --quiet suppress error messages
+ -v, --version print version number and exit
+EOF
+)
+
+. /usr/local/lib/myminiparse.sh
+
+# loop through arguments
+code=0
+for arg; do
+ case "$arg" in
+ -q|--quiet)
+ #ignore these
+ ;;
+
+ *)
+ # main routine
+ if ! /usr/bin/gpg2 -delete-key "$arg"; then
+ code=1
+ fi
+ ;;
+ esac
+done
+
+# exit with stored code
+exit "$code"
+
A crypto/sign => crypto/sign +5 -0
@@ 0,0 1,5 @@
+# gpg2 --detach-sign example
+# if ! gpg2 --verify example.sig example >/dev/null 2>&1; then code=1; fi
+
+# gpg2 --clearsign example
+# if ! gpg2 --verify example.asc >/dev/null 2>&1; then code=1; fi
A crypto/verify => crypto/verify +5 -0
@@ 0,0 1,5 @@
+# gpg2 --detach-sign example
+# if ! gpg2 --verify example.sig example >/dev/null 2>&1; then code=1; fi
+
+# gpg2 --clearsign example
+# if ! gpg2 --verify example.asc >/dev/null 2>&1; then code=1; fi
A crypto/verify-filter => crypto/verify-filter +115 -0
@@ 0,0 1,115 @@
+#!/bin/bash
+
+name="verify-filter"
+version="1.0"
+read -r -d '' help_message <<-EOF
+ Verify a PGP-signed file and print it
+ Usage: pgpcat [OPTIONS] FILE
+ Options:
+ -e, --exit exit without printing FILE if verification fails
+ -f FILE, --file FILE file to verify and print
+ -h, --help print this message and exit
+ -q, --quiet suppress error messages
+ -s SIG, --signature SIG detached signature file; if unspecified,
+ FILE should be armored clear-signed message
+ -v, --verbose show additional messages
+ -V, --version print version number and exit
+EOF
+
+source /usr/local/lib/mylib.bash
+
+positional=()
+fail_immediately=0
+msgfile=
+quiet=0
+sigfile=
+verbose=0
+
+while [[ $# -gt 0 ]]; do
+ case $1 in
+
+ -e|--exit)
+ debug_msg "Setting exit option to 1 (was ${fail_immediately})"
+ fail_immediately=1
+ shift
+ ;;
+
+ -f|--file)
+ debug_msg "Setting file option to ${2} (was ${msgfile})"
+ msgfile="$2"
+ shift; shift
+ ;;
+
+ -h|--help)
+ help_msg
+ shift
+ ;;
+
+ -q|--quiet)
+ debug_msg "Setting quiet option to 1 (was ${quiet})"
+ quiet=1
+ shift
+ ;;
+
+ -s|--signature)
+ debug_msg "Setting signature option to ${2} (was ${sigfile})"
+ sigfile="$2"
+ shift; shift
+ ;;
+
+ -v|--verbose)
+ debug_msg "Setting verbose option to 1 (was ${verbose})"
+ verbose=1
+ shift
+ ;;
+
+ -V|--version)
+ version_msg
+ ;;
+
+ *)
+ debug_msg "Argument '${1}' added to positional array"
+ positional+=("$1")
+ shift
+ ;;
+ esac
+done
+
+# handle input files
+if [[ -z "$msgfile" ]]; then
+ if [[ ${#positional[@]} -lt 1 ]]; then
+ error_msg "Expected input file (given none)"
+ else
+ debug_msg "Moving a positional argument into file option (${#positional[0]})"
+ msgfile="${positional[0]}"
+ positional=("${positional[@]:1}")
+ fi
+fi
+
+code=0
+if [[ -z "$sigfile" ]]; then
+ debug_msg "'${msgfile}' is armored clearsigned"
+ if ! /usr/bin/local/verify --file "$msgfile"; then
+ code=1
+ nonfatal_error_msg "Can not verify file '${msgfile}'"
+
+ if [[ "$fail_immediately" -eq 1 ]]; then
+ exit "$code"
+ fi
+ fi
+ /usr/bin/cat "$msgfile"
+else
+ debug_msg "'${msgfile}' is signed, '${sigfile}' is detached signature"
+ if ! /usr/bin/local/verify --file "$msgfile" --signature "${sigfile}"; then
+ code=1
+ nonfatal_error_msg "Can not verify file '${msgfile}'"
+
+ if [[ "$fail_immediately" -eq 1 ]]; then
+ exit "$code"
+ fi
+ fi
+ /usr/bin/cat "$msgfile"
+fi
+
+exit "$code"
+