Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 29 Oct 2013 09:01:37 +0000 (UTC)
From:      Colin Percival <cperciva@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-user@freebsd.org
Subject:   svn commit: r257318 - user/cperciva/pkesh
Message-ID:  <201310290901.r9T91bHg084354@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: cperciva
Date: Tue Oct 29 09:01:37 2013
New Revision: 257318
URL: http://svnweb.freebsd.org/changeset/base/257318

Log:
  Code for performing public-key encryption of a message.  To be precise,
  the message is encrypted using AES256 in CBC mode; and the AES key, the
  CBC IV, and the SHA256 hash of the plaintext are then encrypted using
  RSA.
  
  In short, think GPG except without the "web of trust" and implemented as
  a shell script using only utilities in the FreeBSD base system.

Added:
  user/cperciva/pkesh/
  user/cperciva/pkesh/README
  user/cperciva/pkesh/pkesh.sh   (contents, props changed)

Added: user/cperciva/pkesh/README
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ user/cperciva/pkesh/README	Tue Oct 29 09:01:37 2013	(r257318)
@@ -0,0 +1,33 @@
+pkesh -- Public Key Encryption SHell script
+===========================================
+
+Usage
+-----
+# pkesh gen priv.key pub.key
+	Generates a public/private key pair.
+# pkesh enc pub.key in out
+	Encrypts "in" using the public key, writing to "out".
+# pkesh dec priv.key in out
+	Decrypts "in" using the private key, writing to "out".
+
+Note: Temporary working space is used under $TMP (or /tmp); if this is not
+a memory filesystem then keys or data may be leaked to permanent storage.
+There must be sufficient temporary space to hold the entire message.
+
+Encrypted format
+----------------
+Encrypted Message	= base64([Encrypted Header][Encrypted Data])
+Encrypted Header	= RSA2048-OAEP([Header])
+Header			= [AES256-CBC Key][AES256-CBC IV][Hash]
+AES256-CBC Key		= 256 bits (random)
+AES256-CBC IV		= 128 bits (random)
+Hash			= SHA256(Encrypted Data)
+Encrypted Data		= AES256-CBC(Data)
+Data			= arbitrary length input "in"
+
+Requirements
+------------
+
+openssl
+POSIX utilities: sh, cat, cmp, dd, od, rm, tr, wc
+non-POSIX but standard UNIX: mktemp

Added: user/cperciva/pkesh/pkesh.sh
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ user/cperciva/pkesh/pkesh.sh	Tue Oct 29 09:01:37 2013	(r257318)
@@ -0,0 +1,116 @@
+#!/bin/sh -e
+
+usage () {
+	echo "usage: pkesh gen priv.key pub.key"
+	echo "usage: pkesh enc pub.key in out"
+	echo "usage: pkesh dec priv.key in out"
+	exit 1
+}
+
+# gen priv.key pub.key
+gen () {
+	# Generate the key
+	openssl genrsa -out $D/rsakey -f4 2048 2>/dev/null
+
+	# Write out private and public parts
+	cat $D/rsakey > $1
+	openssl rsa -in $D/rsakey -pubout > $2 2>/dev/null
+}
+
+# enc pub.key in out
+enc () {
+	# Generate a random 256-bit AES key
+	openssl rand 32 > $D/aeskey
+
+	# Generate a random 128-bit IV
+	openssl rand 16 > $D/aesIV
+
+	# Generate the encrypted data
+	KEY=`od -An -v -t x1 < $D/aeskey | tr -Cd '0-9a-fA-F'`
+	IV=`od -An -v -t x1 < $D/aesIV | tr -Cd '0-9a-fA-F'`
+	openssl enc -aes-256-cbc -K $KEY -iv $IV < $2 > $D/encdata
+
+	# Compute the SHA256 hash of the encrypted data
+	openssl dgst -sha256 -binary $D/encdata > $D/hash
+
+	# Generate the header
+	cat $D/aeskey $D/aesIV $D/hash > $D/header
+
+	# Generate the encrypted header
+	openssl rsautl -inkey $1 -pubin -encrypt -oaep \
+	    < $D/header > $D/encheader
+
+	# Generate the entire encrypted message
+	cat $D/encheader $D/encdata | openssl enc -base64 > $3
+}
+
+# dec priv.key in out
+dec () {
+	# Base-64 decode the encrypted message
+	openssl enc -d -base64 < $2 > $D/encmessage
+
+	# Make sure the message is long enough
+	if [ `wc -c < $D/encmessage` -lt 256 ]; then
+		echo "Message is corrupt or truncated" >/dev/stderr
+		exit 1
+	fi
+
+	# Decrypt the header
+	dd if=$D/encmessage bs=256 count=1 of=$D/encheader 2>/dev/null
+	openssl rsautl -inkey $1 -decrypt -oaep < $D/encheader > $D/header
+
+	# Make sure the header is the right size
+	if [ `wc -c < $D/header` -ne 80 ]; then
+		echo "Message is corrupt" >/dev/stderr
+		exit 1
+	fi
+
+	# Split header into components
+	dd if=$D/header bs=1 count=32 of=$D/aeskey 2>/dev/null
+	dd if=$D/header bs=1 skip=32 count=16 of=$D/aesIV 2>/dev/null
+	dd if=$D/header bs=1 skip=48 count=32 of=$D/hash 2>/dev/null
+
+	# Verify the encrypted data hash
+	dd if=$D/encmessage bs=256 skip=1 2>/dev/null |
+	    openssl dgst -sha256 -binary > $D/encmessage.hash
+	if ! cmp -s $D/hash $D/encmessage.hash; then
+		echo "Message is corrupt or truncated" >/dev/stderr
+		exit 1
+	fi
+
+	# Decrypt the message
+	KEY=`od -An -v -t x1 < $D/aeskey | tr -Cd '0-9a-fA-F'`
+	IV=`od -An -v -t x1 < $D/aesIV | tr -Cd '0-9a-fA-F'`
+	dd if=$D/encmessage bs=256 skip=1 2>/dev/null |
+	    openssl enc -d -aes-256-cbc -K $KEY -iv $IV > $3
+}
+
+# Get operation type
+if [ $# -lt 1 ]; then
+	usage
+fi
+OP=$1
+shift
+
+# Check operation type and number of operands
+case $OP in
+gen)
+	if [ $# -ne 2 ]; then
+		usage
+	fi
+	;;
+enc|dec)
+	if [ $# -ne 3 ]; then
+		usage
+	fi
+	;;
+*)
+	usage
+esac
+
+# Create temporary working directory
+D=`mktemp -d "${TMP:-/tmp}/pkesh.XXXXXX"`
+trap 'rm -r "$D"' EXIT
+
+# Perform the operation
+$OP "$@"



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201310290901.r9T91bHg084354>