First working version of encrypt/decrypt
* use protobuf for encryption-header * use fixed size file-header (42 bytes) before the encryption-header * add encryption/decryption contexts * teach MakePrivateKey() to fixup its internal public key bits
This commit is contained in:
parent
9473c10bfd
commit
21445ba1a1
12 changed files with 1893 additions and 144 deletions
5
Makefile
5
Makefile
|
@ -4,11 +4,10 @@ pwd = $(shell pwd)
|
||||||
.PHONY: all test clean realclean
|
.PHONY: all test clean realclean
|
||||||
|
|
||||||
all:
|
all:
|
||||||
mkdir -p bin
|
./build -s
|
||||||
go build -o bin/sigtool .
|
|
||||||
|
|
||||||
test:
|
test:
|
||||||
go test ./sign
|
go test ./sign
|
||||||
|
|
||||||
clean realclean:
|
clean realclean:
|
||||||
rm -f bin/sigtool
|
rm -rf bin
|
||||||
|
|
82
README.md
82
README.md
|
@ -4,15 +4,54 @@
|
||||||
|
|
||||||
|
|
||||||
## What is this?
|
## What is this?
|
||||||
`sigtool` is an opinionated tool to generate, sign and verify Ed25519
|
`sigtool` is an opinionated tool to generate keys, sign, verify, encrypt &
|
||||||
signatures on files. In many ways, it is like like OpenBSD's signify_
|
decrypt files using Ed25519 signature scheme. In many ways, it is like
|
||||||
-- except written in Golang and definitely easier to use.
|
like OpenBSD's [signify][1] -- except written in Golang and definitely
|
||||||
|
easier to use.
|
||||||
|
|
||||||
It can sign and verify very large files - it prehashes the files
|
It can sign and verify very large files - it prehashes the files
|
||||||
with SHA-512 and then signs the SHA-512 checksum.
|
with SHA-512 and then signs the SHA-512 checksum. The keys and signatures
|
||||||
|
are YAML files and so, human readable.
|
||||||
|
|
||||||
All the artifacts produced by this tool are standard YAML files -
|
It can encrypt & decrypt files by converting the Ed25519 keys to their
|
||||||
thus, human readable.
|
corresponding Curve25519 variants. This elliptic co-ordinate transform
|
||||||
|
follows [FiloSottile's writeup][2]. The file encryption uses
|
||||||
|
AES-GCM-256 (AEAD); the input is broken into chunks and each chunk is
|
||||||
|
AEAD encrypted. The default chunk size is 4MB (4 * 1048576 bytes).
|
||||||
|
|
||||||
|
A random 32-byte key is used to actually encrypt the file contents in
|
||||||
|
AES-GCM mode. This file-encryption key is **wrapped** using the recipient's
|
||||||
|
public key. Thus, a given input file (or stream) can be encrypted to be
|
||||||
|
read by multiple recipients - each of whom is identified by their Ed25519
|
||||||
|
public keys. The file-encryptionb-key can optionally be wrapped using the
|
||||||
|
sender's Private Key - this authenticates the sender. If this private key is
|
||||||
|
not provided for the encrypt operation, then `sigtool` generates ephemeral
|
||||||
|
Curve25519 keys and wraps the file-encryption key using the ephemeral
|
||||||
|
private key and the recipient's public key.
|
||||||
|
|
||||||
|
Every encrypted file starts with a header:
|
||||||
|
|
||||||
|
7 byte magic ("SigTool")
|
||||||
|
1 byte version number
|
||||||
|
4 byte header length
|
||||||
|
32 byte SHA256 of the encryption-header
|
||||||
|
|
||||||
|
The encryption-header is described as a protobuf file (sign/hdr.proto):
|
||||||
|
|
||||||
|
```protobuf
|
||||||
|
message header {
|
||||||
|
uint32 chunk_size = 1;
|
||||||
|
bytes salt = 2;
|
||||||
|
repeated wrapped_key keys = 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
message wrapped_key {
|
||||||
|
bytes pk_hash = 1; // hash of Ed25519 PK
|
||||||
|
bytes pk = 2; // curve25519 PK
|
||||||
|
bytes nonce = 3; // AEAD nonce
|
||||||
|
bytes key = 4; // AEAD encrypted key
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
## How do I build it?
|
## How do I build it?
|
||||||
With Go 1.5 and later:
|
With Go 1.5 and later:
|
||||||
|
@ -21,7 +60,9 @@ With Go 1.5 and later:
|
||||||
cd sigtool
|
cd sigtool
|
||||||
make
|
make
|
||||||
|
|
||||||
The binary will be in `./sigtool`.
|
The binary will be in `./bin/$HOSTOS-$ARCH/sigtool`.
|
||||||
|
where `$HOSTOS` is the host OS where you are building (e.g., openbsd)
|
||||||
|
and `$ARCH` is the CPU architecture (e.g., amd64).
|
||||||
|
|
||||||
## How do I use it?
|
## How do I use it?
|
||||||
Broadly, the tool can:
|
Broadly, the tool can:
|
||||||
|
@ -29,6 +70,8 @@ Broadly, the tool can:
|
||||||
- generate new key pairs (public key and private key)
|
- generate new key pairs (public key and private key)
|
||||||
- sign a file
|
- sign a file
|
||||||
- verify a file against its signature
|
- verify a file against its signature
|
||||||
|
- encrypt a file
|
||||||
|
- decrypt a file
|
||||||
|
|
||||||
### Generate Key pair
|
### Generate Key pair
|
||||||
To start with, you generate a new key pair (a public key used for
|
To start with, you generate a new key pair (a public key used for
|
||||||
|
@ -73,6 +116,22 @@ e.g., to verify the signature of *archive.tar.gz* against
|
||||||
|
|
||||||
sigtool verify /tmp/testkey.pub archive.sig archive.tar.gz
|
sigtool verify /tmp/testkey.pub archive.sig archive.tar.gz
|
||||||
|
|
||||||
|
### Encrypt a file by authenticating the sender
|
||||||
|
If the sender wishes to prove to the recipient that they encrypted
|
||||||
|
a file:
|
||||||
|
|
||||||
|
sigtool encrypt -s mykey.key theirkey.pub -o archive.tar.gz.enc archive.tar.gz
|
||||||
|
|
||||||
|
|
||||||
|
This will create an encrypted file *archive.tar.gz.enc* such that the
|
||||||
|
recipient in possession of *theikey.key* can decrypt it. Furthermore, if
|
||||||
|
the recipient has *mykey.pub*, they can verify that the sender is indeed
|
||||||
|
who they expect.
|
||||||
|
|
||||||
|
### Encrypt a file *without* authenticating the sender
|
||||||
|
|
||||||
|
### Decrypt a file
|
||||||
|
|
||||||
## How is the private key protected?
|
## How is the private key protected?
|
||||||
The Ed25519 private key is encrypted using a key derived from the
|
The Ed25519 private key is encrypted using a key derived from the
|
||||||
user supplied pass phrase. This pass phrase is used to derive an
|
user supplied pass phrase. This pass phrase is used to derive an
|
||||||
|
@ -111,6 +170,8 @@ A serialized Ed25519 public key looks like so:
|
||||||
### Ed25519 Private Key
|
### Ed25519 Private Key
|
||||||
And, a serialized Ed25519 private key looks like so:
|
And, a serialized Ed25519 private key looks like so:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
|
||||||
esk: t3vfqHbgUiA733KKPymFjWT8DdnBEkiMfsDHolPUdQWpvVn/F1Z4J6KYV3M5rGO9xgKxh5RAmqt+6LKgOiJAMQ==
|
esk: t3vfqHbgUiA733KKPymFjWT8DdnBEkiMfsDHolPUdQWpvVn/F1Z4J6KYV3M5rGO9xgKxh5RAmqt+6LKgOiJAMQ==
|
||||||
salt: pPHKG55UJYtJ5wU0G9hBvNQJ0DvT0a7T4Fmj4aPB84s=
|
salt: pPHKG55UJYtJ5wU0G9hBvNQJ0DvT0a7T4Fmj4aPB84s=
|
||||||
algo: scrypt-sha256
|
algo: scrypt-sha256
|
||||||
|
@ -118,6 +179,7 @@ And, a serialized Ed25519 private key looks like so:
|
||||||
Z: 131072
|
Z: 131072
|
||||||
r: 16
|
r: 16
|
||||||
p: 1
|
p: 1
|
||||||
|
```
|
||||||
|
|
||||||
The Ed25519 private key is encrypted using Scrypt password hashing
|
The Ed25519 private key is encrypted using Scrypt password hashing
|
||||||
mechanism. A user supplied passphrase to protect the private key
|
mechanism. A user supplied passphrase to protect the private key
|
||||||
|
@ -146,9 +208,12 @@ ensures that the supplied passphrase yields the same value as
|
||||||
### Ed25519 Signature
|
### Ed25519 Signature
|
||||||
A generated signature looks like below after serialization:
|
A generated signature looks like below after serialization:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
|
||||||
comment: inpfile=/tmp/file.txt
|
comment: inpfile=/tmp/file.txt
|
||||||
pkhash: 36z9tCwTIVNwwDlExrB0SQ==
|
pkhash: 36z9tCwTIVNwwDlExrB0SQ==
|
||||||
signature: ow2oBP+buDbEvlNakOrsxgB5Yc/7PYyPVZCkfyu7oahw8BakF4Qf32uswPaKGZ8RVz4uXboYHdZtfrEjCgP/Cg==
|
signature: ow2oBP+buDbEvlNakOrsxgB5Yc/7PYyPVZCkfyu7oahw8BakF4Qf32uswPaKGZ8RVz4uXboYHdZtfrEjCgP/Cg==
|
||||||
|
```
|
||||||
|
|
||||||
Here, ```pkhash`` is a SHA256 of the public key needed to verify
|
Here, ```pkhash`` is a SHA256 of the public key needed to verify
|
||||||
this signature.
|
this signature.
|
||||||
|
@ -163,4 +228,5 @@ See the file ``LICENSE.md`` for the full terms of the license.
|
||||||
## Author
|
## Author
|
||||||
Sudhi Herle <sw@herle.net>
|
Sudhi Herle <sw@herle.net>
|
||||||
|
|
||||||
.. _signify: https://www.openbsd.org/papers/bsdcan-signify.html
|
[1]: https://www.openbsd.org/papers/bsdcan-signify.html
|
||||||
|
[2]: https://blog.filippo.io/using-ed25519-keys-for-encryption/
|
||||||
|
|
373
build
Executable file
373
build
Executable file
|
@ -0,0 +1,373 @@
|
||||||
|
#! /usr/bin/env bash
|
||||||
|
|
||||||
|
# Tool to build go programs in this repo
|
||||||
|
#
|
||||||
|
# - it tacks on a version number for use by the individual tools
|
||||||
|
# - it supports git and mercurial version#
|
||||||
|
#
|
||||||
|
# NB:
|
||||||
|
# o the attempt at decoding dirty repo state for mercurial is
|
||||||
|
# borked. It doesn't know about untracked files
|
||||||
|
#
|
||||||
|
# (c) 2016 Sudhi Herle
|
||||||
|
#
|
||||||
|
# License: GPLv2
|
||||||
|
#
|
||||||
|
Progs=".:sigtool"
|
||||||
|
|
||||||
|
# Relative path to protobuf sources
|
||||||
|
# e.g. src/foo/a.proto
|
||||||
|
Protobufs="sign/hdr.proto"
|
||||||
|
|
||||||
|
|
||||||
|
# -- DO NOT CHANGE ANYTHING AFTER THIS --
|
||||||
|
|
||||||
|
Z=`basename $0`
|
||||||
|
PWD=`pwd`
|
||||||
|
|
||||||
|
Static=0
|
||||||
|
Dryrun=0
|
||||||
|
Prodver=0.1
|
||||||
|
Verbose=0
|
||||||
|
|
||||||
|
hostos=$(go env GOHOSTOS) || exit 1
|
||||||
|
hostcpu=$(go env GOHOSTARCH) || exit 1
|
||||||
|
|
||||||
|
[ -f ./version ] && Prodver=$(cat ./version)
|
||||||
|
|
||||||
|
die() {
|
||||||
|
echo "$Z: $@" 1>&2
|
||||||
|
exit 0
|
||||||
|
}
|
||||||
|
|
||||||
|
warn() {
|
||||||
|
echo "$Z: $@" 1>&2
|
||||||
|
}
|
||||||
|
|
||||||
|
case $BASH_VERSION in
|
||||||
|
4.*|5.*) ;;
|
||||||
|
|
||||||
|
*) die "I need bash 4.x to run!"
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
|
||||||
|
# build a tool that runs on the host - if needed.
|
||||||
|
hosttool() {
|
||||||
|
local tool=$1
|
||||||
|
local bindir=$2
|
||||||
|
local src=$3
|
||||||
|
|
||||||
|
local p=$(type -P $tool)
|
||||||
|
if [ -n "$p" ]; then
|
||||||
|
echo $p
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
# from here - we want this dir to find all build artifacts
|
||||||
|
PATH=$PATH:$bindir
|
||||||
|
export PATH
|
||||||
|
|
||||||
|
p=$bindir/$tool
|
||||||
|
if [ -x $p ]; then
|
||||||
|
echo $p
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
# build it and stash it in the hostdir
|
||||||
|
echo "Building tool $tool from $src .."
|
||||||
|
$e go get -d $src || exit 1
|
||||||
|
$e go build -o $p $src || exit 1
|
||||||
|
echo $p
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
usage() {
|
||||||
|
|
||||||
|
cat <<EOF
|
||||||
|
$0 - A Go production build tool that adds git-repository information,
|
||||||
|
product version, build-timestamp etc. It supports cross-compilation,
|
||||||
|
static linking and generating protobuf output.
|
||||||
|
|
||||||
|
If needed, it uses the gogo-slick protobuf compiler [github.com/gogo/protobuf].
|
||||||
|
|
||||||
|
Build output is in bin/\$OS-\$CPU for a given OS, CPU combination.
|
||||||
|
|
||||||
|
Usage: $0
|
||||||
|
$0 [options] [PROGS]
|
||||||
|
|
||||||
|
Where OS-ARCH denotes one of the valid OS, ARCH combinations supported by 'go'.
|
||||||
|
And, PROGS is one or more go programs.
|
||||||
|
|
||||||
|
With no arguments, $0 builds: $Progs (source in ./src/)
|
||||||
|
|
||||||
|
If ./version is present, its content are used as version number for the binary.
|
||||||
|
|
||||||
|
Options:
|
||||||
|
-h, --help Show this help message and quit
|
||||||
|
-s, --static Build a statically linked binary [False]
|
||||||
|
-V N, --version=N Use 'N' as the product version string [$Prodver]
|
||||||
|
-a X, --arch=X Cross compile for OS-CPU 'X' [$hostos-$hostcpu]
|
||||||
|
-n, --dry-run Dry-run, don't actually build anything [False]
|
||||||
|
-t, --test Run "go test" on modules named on the command line [False]
|
||||||
|
-v, --verbose Build verbosely (adds "-v" to go tooling) [False]
|
||||||
|
--vet Run "go vet" on modules named on the command line [False]
|
||||||
|
-x Run in debug/trace mode [False]
|
||||||
|
EOF
|
||||||
|
|
||||||
|
exit 0
|
||||||
|
}
|
||||||
|
|
||||||
|
host=`uname|tr '[A-Z]' '[a-z]'`
|
||||||
|
export GO15VENDOREXPERIMENT=1
|
||||||
|
|
||||||
|
declare -A oses
|
||||||
|
declare -A cpus
|
||||||
|
declare -A cgo
|
||||||
|
|
||||||
|
# Supported & Verified OS/CPU combos for this script
|
||||||
|
oslist="linux android openbsd freebsd darwin dragonfly netbsd windows"
|
||||||
|
needcgo="android"
|
||||||
|
cpulist="i386 amd64 arm arm64"
|
||||||
|
cpualias_i386="i486 i586 i686"
|
||||||
|
cpualias_amd64="x86_64"
|
||||||
|
cpualias_arm64="aarch64"
|
||||||
|
|
||||||
|
# CGO Cross-Compilers for various CPU+OS combinations of Android
|
||||||
|
android_i386=i686-linux-android-gcc
|
||||||
|
android_arm64=aarch64-linux-android-gcc
|
||||||
|
android_arm=arm-linux-androideabi-gcc
|
||||||
|
|
||||||
|
# initialize the various hash tables
|
||||||
|
for o in $oslist; do oses[$o]=$o; done
|
||||||
|
for o in $needcgo; do cgo[$o]=$o; done
|
||||||
|
for c in $cpulist; do
|
||||||
|
cpus[$c]=$c
|
||||||
|
a="cpualias_$c"
|
||||||
|
a=${!a}
|
||||||
|
for x in $a; do cpus[$x]=$c; done
|
||||||
|
done
|
||||||
|
|
||||||
|
|
||||||
|
Tool=
|
||||||
|
doinit=0
|
||||||
|
args=
|
||||||
|
|
||||||
|
#set -x
|
||||||
|
ac_prev=
|
||||||
|
for ac_option
|
||||||
|
do
|
||||||
|
shift
|
||||||
|
|
||||||
|
if [ -n "$ac_prev" ]; then
|
||||||
|
eval "$ac_prev=\$ac_option"
|
||||||
|
ac_prev=
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
|
||||||
|
case "$ac_option" in
|
||||||
|
-*=*) ac_optarg=`echo "$ac_option" | sed 's/[-_a-zA-Z0-9]*=//'` ;;
|
||||||
|
*) ac_optarg= ;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
|
||||||
|
case "$ac_option" in
|
||||||
|
--help|-h|--hel|--he|--h)
|
||||||
|
usage;
|
||||||
|
;;
|
||||||
|
|
||||||
|
--arch=*)
|
||||||
|
Arch=$ac_optarg
|
||||||
|
;;
|
||||||
|
-a|--arch)
|
||||||
|
ac_prev=Arch
|
||||||
|
;;
|
||||||
|
|
||||||
|
--version=*)
|
||||||
|
Prodver=$ac_optarg
|
||||||
|
;;
|
||||||
|
--test|-t)
|
||||||
|
Tool=test
|
||||||
|
;;
|
||||||
|
|
||||||
|
--vet)
|
||||||
|
Tool=vet
|
||||||
|
;;
|
||||||
|
|
||||||
|
-V|--version)
|
||||||
|
ac_prev=Prodver
|
||||||
|
;;
|
||||||
|
-v|--verbose)
|
||||||
|
Verbose=1
|
||||||
|
;;
|
||||||
|
|
||||||
|
-s|--static)
|
||||||
|
Static=1
|
||||||
|
;;
|
||||||
|
|
||||||
|
--dry-run|-n)
|
||||||
|
Dryrun=1
|
||||||
|
;;
|
||||||
|
|
||||||
|
--debug|-x)
|
||||||
|
set -x
|
||||||
|
;;
|
||||||
|
|
||||||
|
*) # first non option terminates option processing.
|
||||||
|
# we gather all remaining args and bundle them up.
|
||||||
|
args="$args $ac_option"
|
||||||
|
for xx
|
||||||
|
do
|
||||||
|
args="$args $xx"
|
||||||
|
done
|
||||||
|
break
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
[ $Dryrun -gt 0 ] && e=echo
|
||||||
|
|
||||||
|
# let every error abort
|
||||||
|
set -e
|
||||||
|
|
||||||
|
# This fragment can't be in a function - since it exports several vars
|
||||||
|
if [ -n "$Arch" ]; then
|
||||||
|
ox=${Arch%%-*}
|
||||||
|
cx=${Arch##*-}
|
||||||
|
[ "$ox" = "$cx" ] && cx=$hostcpu
|
||||||
|
|
||||||
|
os=${oses[$ox]}
|
||||||
|
cpu=${cpus[$cx]}
|
||||||
|
[ -z "$os" ] && die "Don't know anything about OS $ox"
|
||||||
|
[ -z "$cpu" ] && die "Don't know anything about CPU $cx"
|
||||||
|
|
||||||
|
export GOOS=$os GOARCH=$cpu
|
||||||
|
cross=$os-$cpu
|
||||||
|
|
||||||
|
else
|
||||||
|
os=$hostos
|
||||||
|
cpu=$hostcpu
|
||||||
|
cross=$os-$cpu
|
||||||
|
fi
|
||||||
|
|
||||||
|
# If we don't need CGO, then we can attempt a static link
|
||||||
|
if [ -n "${cgo[$os]}" ]; then
|
||||||
|
export CGO_ENABLED=1
|
||||||
|
|
||||||
|
# See if we have a specific cross-compiler for this CPU+OS combo
|
||||||
|
xcc="${GOOS}_${GOARCH}"
|
||||||
|
xcc=${!xcc}
|
||||||
|
if [ -n "$xcc" ]; then
|
||||||
|
p=`type -p $xcc`
|
||||||
|
[ -n "$p" ] || die "Can't find $xcc! Do you have compilers for $GOARCH available in PATH?"
|
||||||
|
export CC=$xcc
|
||||||
|
else
|
||||||
|
echo "$Z: No Cross compiler defined for $GOOS-$GOARCH. Build may fail.." 1>&2
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
if [ $Static -gt 0 ]; then
|
||||||
|
export CGO_ENABLED=0
|
||||||
|
|
||||||
|
isuffix="--installsuffix cgo"
|
||||||
|
ldflags="-s"
|
||||||
|
msg="statically linked"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# This is where build outputs go
|
||||||
|
Bindir=$PWD/bin/$cross
|
||||||
|
Hostbindir=$PWD/bin/$hostos-$hostcpu
|
||||||
|
|
||||||
|
[ -d $Bindir ] || mkdir -p $Bindir
|
||||||
|
[ -d $Hostbindir ] || mkdir -p $Hostbindir
|
||||||
|
|
||||||
|
# Get git/hg version info for the build
|
||||||
|
if [ -d "./.hg" ]; then
|
||||||
|
xrev=$(hg id --id) || exit 1
|
||||||
|
brev=${xrev%+}
|
||||||
|
if [ "$brev" != "$xrev" ]; then
|
||||||
|
rev="hg:${brev}-dirty"
|
||||||
|
else
|
||||||
|
rev="hg:${brev}"
|
||||||
|
fi
|
||||||
|
elif [ -d "./.git" ]; then
|
||||||
|
xrev=$(git describe --always --dirty --long --abbrev=12) || exit 1
|
||||||
|
rev="git:$xrev"
|
||||||
|
else
|
||||||
|
rev="UNKNOWN-VER"
|
||||||
|
echo "$0: Can't find version info" 1>&2
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Do Protobufs if needed
|
||||||
|
if [ -n "$Protobufs" ]; then
|
||||||
|
slick=$Hostbindir/protoc-gen-gogoslick
|
||||||
|
slicksrc=github.com/gogo/protobuf/protoc-gen-gogoslick
|
||||||
|
pc=$(type -p protoc)
|
||||||
|
|
||||||
|
[ -z "$pc" ] && die "Need 'protoc' for building .."
|
||||||
|
|
||||||
|
slick=$(hosttool protoc-gen-gogoslick $Hostbindir $slicksrc) || exit 1
|
||||||
|
#if [ ! -f $slick ]; then
|
||||||
|
# echo "Building $slick .."
|
||||||
|
# $e go build -o $slick github.com/gogo/protobuf/protoc-gen-gogoslick || exit 1
|
||||||
|
#i
|
||||||
|
|
||||||
|
PATH=$Hostbindir:$PATH
|
||||||
|
export PATH
|
||||||
|
|
||||||
|
for f in $Protobufs; do
|
||||||
|
dn=$(dirname $f)
|
||||||
|
bn=$(basename $f .proto)
|
||||||
|
of=$dn/${bn}.pb.go
|
||||||
|
if [ $f -nt $of ]; then
|
||||||
|
echo "gogoslick: $f -> $of ..."
|
||||||
|
$e $pc --gogoslick_out=. $f || exit 1
|
||||||
|
$e gofmt -w $of
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
|
||||||
|
repover="main.RepoVersion=$rev"
|
||||||
|
prodver="main.ProductVersion=$Prodver"
|
||||||
|
date="main.Buildtime=`date -u '+%Y-%m-%dT%H:%M.%SZ'`"
|
||||||
|
ldflags="-ldflags \"-X $repover -X $prodver -X $date $ldflags\""
|
||||||
|
vflag=""
|
||||||
|
|
||||||
|
[ $Verbose -gt 0 ] && vflag="-v"
|
||||||
|
|
||||||
|
case $Tool in
|
||||||
|
test)
|
||||||
|
set -- $args
|
||||||
|
$e go test $vflag "$@"
|
||||||
|
;;
|
||||||
|
|
||||||
|
vet)
|
||||||
|
set -- $args
|
||||||
|
$e go vet $vflag "$@"
|
||||||
|
;;
|
||||||
|
|
||||||
|
*) # Default is to build programs
|
||||||
|
set -- $args
|
||||||
|
if [ -z "$1" ]; then
|
||||||
|
all=$Progs
|
||||||
|
else
|
||||||
|
all="$@"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "Building $rev, $cross $msg .."
|
||||||
|
|
||||||
|
for p in $all; do
|
||||||
|
if echo $p | grep -q ':' ; then
|
||||||
|
out=${p##*:}
|
||||||
|
dir=${p%%:*}
|
||||||
|
else
|
||||||
|
out=$p
|
||||||
|
dir=$p
|
||||||
|
fi
|
||||||
|
echo " $dir: $out .. "
|
||||||
|
$e eval go build $vflag -o $Bindir/$out $isuffix "$ldflags" ./$dir || exit 1
|
||||||
|
done
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
# vim: ft=sh:expandtab:ts=4:sw=4:tw=84:
|
47
crypt.go
47
crypt.go
|
@ -18,8 +18,8 @@ import (
|
||||||
"io"
|
"io"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
flag "github.com/opencoff/pflag"
|
|
||||||
"github.com/opencoff/go-utils"
|
"github.com/opencoff/go-utils"
|
||||||
|
flag "github.com/opencoff/pflag"
|
||||||
"github.com/opencoff/sigtool/sign"
|
"github.com/opencoff/sigtool/sign"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -108,7 +108,10 @@ func encrypt(args []string) {
|
||||||
outfd = outf
|
outfd = outf
|
||||||
}
|
}
|
||||||
|
|
||||||
var recip []*sign.PublicKey
|
en, err := sign.NewEncryptor(sk)
|
||||||
|
if err != nil {
|
||||||
|
die("%s", err)
|
||||||
|
}
|
||||||
|
|
||||||
for i := 0; i < len(args)-1; i++ {
|
for i := 0; i < len(args)-1; i++ {
|
||||||
fn := args[i]
|
fn := args[i]
|
||||||
|
@ -116,11 +119,18 @@ func encrypt(args []string) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
die("%s", err)
|
die("%s", err)
|
||||||
}
|
}
|
||||||
recip = append(recip, pk)
|
|
||||||
|
err = en.AddRecipient(pk)
|
||||||
|
if err != nil {
|
||||||
|
die("%s", err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
encryptFile(sk, recip, infd, outfd)
|
|
||||||
|
|
||||||
|
err = en.Encrypt(infd, outfd)
|
||||||
|
if err != nil {
|
||||||
|
die("%s", err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// sigtool decrypt a.key [file] [-o output]
|
// sigtool decrypt a.key [file] [-o output]
|
||||||
|
@ -132,11 +142,13 @@ func decrypt(args []string) {
|
||||||
|
|
||||||
var envpw string
|
var envpw string
|
||||||
var outfile string
|
var outfile string
|
||||||
|
var pubkey string
|
||||||
var pw bool
|
var pw bool
|
||||||
|
|
||||||
fs.StringVarP(&outfile, "outfile", "o", "", "Write the output to file `F`")
|
fs.StringVarP(&outfile, "outfile", "o", "", "Write the output to file `F`")
|
||||||
fs.BoolVarP(&pw, "password", "p", false, "Ask for passphrase to decrypt the private key")
|
fs.BoolVarP(&pw, "password", "p", false, "Ask for passphrase to decrypt the private key")
|
||||||
fs.StringVarP(&envpw, "env-password", "", "", "Use passphrase from environment variable `E`")
|
fs.StringVarP(&envpw, "env-password", "", "", "Use passphrase from environment variable `E`")
|
||||||
|
fs.StringVarP(&pubkey, "verify-sender", "v", "", "Verify that the sender matches public key in `F`")
|
||||||
|
|
||||||
err := fs.Parse(args)
|
err := fs.Parse(args)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -153,7 +165,6 @@ func decrypt(args []string) {
|
||||||
var inf *os.File
|
var inf *os.File
|
||||||
var pws, infile string
|
var pws, infile string
|
||||||
|
|
||||||
|
|
||||||
if len(envpw) > 0 {
|
if len(envpw) > 0 {
|
||||||
pws = os.Getenv(envpw)
|
pws = os.Getenv(envpw)
|
||||||
} else if pw {
|
} else if pw {
|
||||||
|
@ -169,6 +180,15 @@ func decrypt(args []string) {
|
||||||
die("%s", err)
|
die("%s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var pk *sign.PublicKey
|
||||||
|
|
||||||
|
if len(pubkey) > 0 {
|
||||||
|
pk, err = sign.ReadPublicKey(pubkey)
|
||||||
|
if err != nil {
|
||||||
|
die("%s", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if len(args) > 1 {
|
if len(args) > 1 {
|
||||||
infile = args[1]
|
infile = args[1]
|
||||||
if infile != "-" {
|
if infile != "-" {
|
||||||
|
@ -200,14 +220,21 @@ func decrypt(args []string) {
|
||||||
outfd = outf
|
outfd = outf
|
||||||
}
|
}
|
||||||
|
|
||||||
decryptFile(sk, infd, outfd)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
d, err := sign.NewDecryptor(infd, pk)
|
||||||
|
if err != nil {
|
||||||
|
die("%s", err)
|
||||||
|
}
|
||||||
|
|
||||||
func encryptFile(sk *sign.PrivateKey, pks []*sign.PublicKey, infd io.Reader, outfd io.Writer) {
|
err = d.SetPrivateKey(sk)
|
||||||
}
|
if err != nil {
|
||||||
|
die("%s", err)
|
||||||
|
}
|
||||||
|
|
||||||
func decryptFile(sk *sign.PrivateKey, infd io.Reader, outfd io.Writer) {
|
err = d.Decrypt(outfd)
|
||||||
|
if err != nil {
|
||||||
|
die("%s", err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
1
go.mod
1
go.mod
|
@ -3,6 +3,7 @@ module github.com/opencoff/sigtool
|
||||||
go 1.13
|
go 1.13
|
||||||
|
|
||||||
require (
|
require (
|
||||||
|
github.com/gogo/protobuf v1.3.1
|
||||||
github.com/opencoff/go-utils v0.3.0
|
github.com/opencoff/go-utils v0.3.0
|
||||||
github.com/opencoff/pflag v0.3.3
|
github.com/opencoff/pflag v0.3.3
|
||||||
golang.org/x/crypto v0.0.0-20191002192127-34f69633bfdc
|
golang.org/x/crypto v0.0.0-20191002192127-34f69633bfdc
|
||||||
|
|
5
go.sum
5
go.sum
|
@ -1,3 +1,7 @@
|
||||||
|
github.com/gogo/protobuf v1.3.1 h1:DqDEcV5aeaTmdFBePNpYsp3FlcVH/2ISVVM9Qf8PSls=
|
||||||
|
github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=
|
||||||
|
github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00=
|
||||||
|
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||||
github.com/opencoff/go-utils v0.3.0 h1:/TQXjf50o3GSB9MItog5L8Gf4GWJ4B5+rmqjB4g2RZQ=
|
github.com/opencoff/go-utils v0.3.0 h1:/TQXjf50o3GSB9MItog5L8Gf4GWJ4B5+rmqjB4g2RZQ=
|
||||||
github.com/opencoff/go-utils v0.3.0/go.mod h1:c+7QUAiCCHcNH6OGvsZ0fviG7cgse8Y3ucg+xy7sGXM=
|
github.com/opencoff/go-utils v0.3.0/go.mod h1:c+7QUAiCCHcNH6OGvsZ0fviG7cgse8Y3ucg+xy7sGXM=
|
||||||
github.com/opencoff/pflag v0.3.3 h1:yohZkwYGPkB34WXvUQzU5GyLhImnjfePDARUaE8me3U=
|
github.com/opencoff/pflag v0.3.3 h1:yohZkwYGPkB34WXvUQzU5GyLhImnjfePDARUaE8me3U=
|
||||||
|
@ -11,6 +15,7 @@ golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5h
|
||||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d h1:+R4KGOnez64A81RvjARKc4UT5/tI9ujCIVX+P5KiHuI=
|
golang.org/x/sys v0.0.0-20190412213103-97732733099d h1:+R4KGOnez64A81RvjARKc4UT5/tI9ujCIVX+P5KiHuI=
|
||||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
|
golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/yaml.v2 v2.2.4 h1:/eiJrUcujPVeJ3xlSWaiNi3uSVmDGBK1pDHUHAnao1I=
|
gopkg.in/yaml.v2 v2.2.4 h1:/eiJrUcujPVeJ3xlSWaiNi3uSVmDGBK1pDHUHAnao1I=
|
||||||
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
|
|
592
sign/encrypt.go
592
sign/encrypt.go
|
@ -17,98 +17,427 @@ import (
|
||||||
"crypto/aes"
|
"crypto/aes"
|
||||||
"crypto/cipher"
|
"crypto/cipher"
|
||||||
"crypto/ed25519"
|
"crypto/ed25519"
|
||||||
|
"crypto/sha256"
|
||||||
"crypto/sha512"
|
"crypto/sha512"
|
||||||
"encoding/hex"
|
"crypto/subtle"
|
||||||
"fmt"
|
"fmt"
|
||||||
"golang.org/x/crypto/curve25519"
|
"golang.org/x/crypto/curve25519"
|
||||||
"golang.org/x/crypto/hkdf"
|
"golang.org/x/crypto/hkdf"
|
||||||
"io"
|
"io"
|
||||||
"math/big"
|
"math/big"
|
||||||
"strings"
|
"bytes"
|
||||||
|
"encoding/binary"
|
||||||
)
|
)
|
||||||
|
|
||||||
// A File-encryption-key wrapped by the Ed25519 public key of the recipient
|
|
||||||
type WrappedKey struct {
|
// Encryption chunk size = 4MB
|
||||||
Key []byte // KEK - wrapped with the Curve25519 PK of recipient
|
const chunkSize int = 4 * 1048576
|
||||||
Pk []byte // Curve25519 PK used to wrap
|
|
||||||
PkHash []byte // hash of the corresponding Ed25519 PK
|
const _Magic = "SigTool"
|
||||||
|
const _MagicLen = len(_Magic)
|
||||||
|
const _AEADNonceLen = 32
|
||||||
|
|
||||||
|
|
||||||
|
// Encryptor holds the encryption context
|
||||||
|
type Encryptor struct {
|
||||||
|
Header
|
||||||
|
key [32]byte // file encryption key
|
||||||
|
|
||||||
|
ae cipher.AEAD
|
||||||
|
sender *PrivateKey
|
||||||
|
started bool
|
||||||
|
|
||||||
|
buf []byte
|
||||||
}
|
}
|
||||||
|
|
||||||
func hx(b []byte) string {
|
// Create a new Encryption context and use the optional private key 'sk' for
|
||||||
return hex.EncodeToString(b)
|
// signing any recipient keys. If 'sk' is nil, then ephmeral Curve25519 keys
|
||||||
}
|
// are generated and used with recipient's public key.
|
||||||
|
func NewEncryptor(sk *PrivateKey) (*Encryptor, error) {
|
||||||
|
|
||||||
func unhx(s string) ([]byte, error) {
|
e := &Encryptor{
|
||||||
return hex.DecodeString(s)
|
Header: Header{
|
||||||
}
|
ChunkSize: uint32(chunkSize),
|
||||||
|
Salt: make([]byte, _AEADNonceLen),
|
||||||
|
},
|
||||||
|
|
||||||
func (w *WrappedKey) ToString() string {
|
sender: sk,
|
||||||
return fmt.Sprintf("(ed25519 to=%x, pk=%x, kek=%x)",
|
|
||||||
hx(w.PkHash), hx(w.Pk), hx(w.Key))
|
|
||||||
}
|
|
||||||
|
|
||||||
func parseErr(s string, v ...interface{}) error {
|
|
||||||
return fmt.Errorf(s, v...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Given an marshalled stream of bytes, return the PubKey, encrypted key
|
|
||||||
func ParseWrappedKey(s string) (*WrappedKey, error) {
|
|
||||||
s = strings.TrimSpace(s)
|
|
||||||
if s[0] != '(' {
|
|
||||||
return nil, parseErr("missing '(' in wrapped key")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if s[len(s)-1] != ')' {
|
randread(e.key[:])
|
||||||
return nil, parseErr("missing ')' in wrapped key")
|
randread(e.Salt)
|
||||||
}
|
|
||||||
|
|
||||||
s = s[1 : len(s)-1]
|
|
||||||
v := strings.Fields(s)
|
|
||||||
if len(v) != 3 {
|
|
||||||
return nil, parseErr("Incorrect number of elements (exp 3, saw %d) in wrapped key", len(v))
|
|
||||||
}
|
|
||||||
|
|
||||||
var w WrappedKey
|
|
||||||
|
|
||||||
for _, z := range v {
|
|
||||||
kw := strings.Split(z, "=")
|
|
||||||
if len(kw) != 2 {
|
|
||||||
return nil, parseErr("malformed key=value pair (%s) in wrapped key", z)
|
|
||||||
}
|
|
||||||
|
|
||||||
var err error
|
|
||||||
switch strings.ToLower(kw[0]) {
|
|
||||||
case "to":
|
|
||||||
w.PkHash, err = unhx(kw[1])
|
|
||||||
|
|
||||||
case "pk":
|
|
||||||
w.Pk, err = unhx(kw[1])
|
|
||||||
|
|
||||||
case "kek":
|
|
||||||
w.Key, err = unhx(kw[1])
|
|
||||||
|
|
||||||
default:
|
|
||||||
return nil, parseErr("unknown keyword %s in wrapped key", kw[0])
|
|
||||||
}
|
|
||||||
|
|
||||||
|
aes, err := aes.NewCipher(e.key[:])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, parseErr("can't parse value for %s in wrapped key", kw[0])
|
return nil, fmt.Errorf("encrypt: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
e.ae, err = cipher.NewGCMWithNonceSize(aes, _AEADNonceLen)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("encrypt: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
e.buf = make([]byte, chunkSize + 4 + e.ae.Overhead())
|
||||||
|
return e, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Add a new recipient to this encryption context.
|
||||||
|
func (e *Encryptor) AddRecipient(pk *PublicKey) error {
|
||||||
|
if e.started {
|
||||||
|
return fmt.Errorf("encrypt: can't add new recipient after encryption has started")
|
||||||
|
}
|
||||||
|
|
||||||
|
var w *WrappedKey
|
||||||
|
var err error
|
||||||
|
|
||||||
|
if e.sender != nil {
|
||||||
|
w, err = e.sender.WrapKey(pk, e.key[:])
|
||||||
|
} else {
|
||||||
|
w, err = pk.WrapKeyEphemeral(e.key[:])
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
e.Keys = append(e.Keys, w)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Begin the encryption process by writing the header
|
||||||
|
func (e *Encryptor) start(wr io.Writer) error {
|
||||||
|
msize := e.Size()
|
||||||
|
|
||||||
|
// marshal the header and recipients
|
||||||
|
hdrlen := _MagicLen + 1 + 4 + sha256.Size
|
||||||
|
|
||||||
|
buf := make([]byte, hdrlen + msize)
|
||||||
|
hdrbuf := buf[hdrlen:]
|
||||||
|
|
||||||
|
copy(buf[:], []byte(_Magic))
|
||||||
|
|
||||||
|
buf[_MagicLen] = 1 // file version#
|
||||||
|
|
||||||
|
// The fixed header is the magic _and _ the length of the variable segment.
|
||||||
|
// So, we capture the length of the variable portion first.
|
||||||
|
binary.BigEndian.PutUint32(buf[_MagicLen + 1:], uint32(sha256.Size + msize))
|
||||||
|
|
||||||
|
// Now marshal the variable portion
|
||||||
|
_, err := e.MarshalToSizedBuffer(hdrbuf)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("encrypt: can't marshal header: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// and calculate the header checksum
|
||||||
|
cksum := buf[_MagicLen + 1 + 4:]
|
||||||
|
h := sha256.New()
|
||||||
|
h.Write(hdrbuf)
|
||||||
|
h.Sum(cksum[:0])
|
||||||
|
|
||||||
|
// Finally write it out
|
||||||
|
err = fullwrite(buf, wr)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("encrypt: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
e.started = true
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write _all_ bytes of buffer 'buf'
|
||||||
|
func fullwrite(buf []byte, wr io.Writer) error {
|
||||||
|
n := len(buf)
|
||||||
|
|
||||||
|
for n > 0 {
|
||||||
|
m, err := wr.Write(buf)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("I/O error: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
n -= m
|
||||||
|
buf = buf[m:]
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Encrypt the input stream 'rd' and write encrypted stream to 'wr'
|
||||||
|
func (e *Encryptor) Encrypt(rd io.Reader, wr io.Writer) error {
|
||||||
|
if !e.started {
|
||||||
|
err := e.start(wr)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(w.PkHash) != 16 {
|
buf := make([]byte, e.ChunkSize)
|
||||||
return nil, parseErr("invalid PkHash length (exp 16, saw %d) in wrapped key", len(w.PkHash))
|
i := 0
|
||||||
|
|
||||||
|
for {
|
||||||
|
n, err := io.ReadAtLeast(rd, buf, int(e.ChunkSize))
|
||||||
|
if n == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
if n > 0 {
|
||||||
|
err = e.encrypt(buf[:n], wr, i)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
i++
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if err != nil && err != io.EOF {
|
||||||
|
return fmt.Errorf("encrypt: I/O read error: %s", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// encrypt exactly _one_ block of data
|
||||||
|
// The nonce for the block is: sha256(salt || chunkLen || block#)
|
||||||
|
// This protects the output stream from re-ordering attacks and length
|
||||||
|
// modification attacks. The encoded length & block number is used as
|
||||||
|
// additional data in the AEAD construction.
|
||||||
|
func (e *Encryptor) encrypt(buf []byte, wr io.Writer, i int) error {
|
||||||
|
var b [8]byte
|
||||||
|
var noncebuf [32]byte
|
||||||
|
|
||||||
|
binary.BigEndian.PutUint32(b[:4], uint32(e.ae.Overhead() + len(buf)))
|
||||||
|
binary.BigEndian.PutUint32(b[4:], uint32(i))
|
||||||
|
|
||||||
|
h := sha256.New()
|
||||||
|
h.Write(e.Salt)
|
||||||
|
h.Write(b[:])
|
||||||
|
nonce := h.Sum(noncebuf[:0])
|
||||||
|
|
||||||
|
copy(e.buf[:4], b[:4])
|
||||||
|
cbuf := e.buf[4:]
|
||||||
|
c := e.ae.Seal(cbuf[:0], nonce, buf, b[:])
|
||||||
|
|
||||||
|
n := len(c) + 4
|
||||||
|
|
||||||
|
err := fullwrite(e.buf[:n], wr)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("encrypt: %s", err)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Decryptor holds the decryption context
|
||||||
|
type Decryptor struct {
|
||||||
|
Header
|
||||||
|
|
||||||
|
ae cipher.AEAD
|
||||||
|
rd io.Reader
|
||||||
|
buf []byte
|
||||||
|
|
||||||
|
// Decrypted key
|
||||||
|
key []byte
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Create a new decryption context and if 'pk' is given, check that it matches
|
||||||
|
// the sender
|
||||||
|
func NewDecryptor(rd io.Reader, pk *PublicKey) (*Decryptor, error) {
|
||||||
|
var b [12]byte
|
||||||
|
|
||||||
|
_, err := io.ReadFull(rd, b[:])
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if bytes.Compare(b[:_MagicLen], []byte(_Magic)) != 0 {
|
||||||
|
return nil, fmt.Errorf("decrypt: Not a sigtool encrypted file?")
|
||||||
|
}
|
||||||
|
|
||||||
|
if b[_MagicLen] != 1 {
|
||||||
|
return nil, fmt.Errorf("decrypt: Unsupported version %d", b[_MagicLen])
|
||||||
|
}
|
||||||
|
|
||||||
|
hdrlen := binary.BigEndian.Uint32(b[_MagicLen+1:])
|
||||||
|
if hdrlen > 65536 {
|
||||||
|
return nil, fmt.Errorf("decrypt: header too large (max 65536)")
|
||||||
|
}
|
||||||
|
if hdrlen < 32 {
|
||||||
|
return nil, fmt.Errorf("decrypt: header too small (min 32)")
|
||||||
|
}
|
||||||
|
|
||||||
|
hdr := make([]byte, hdrlen)
|
||||||
|
|
||||||
|
_, err = io.ReadFull(rd, hdr)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
verify := hdr[:32]
|
||||||
|
hdr = hdr[32:]
|
||||||
|
|
||||||
|
cksum := sha256.Sum256(hdr)
|
||||||
|
if subtle.ConstantTimeCompare(verify, cksum[:]) == 0 {
|
||||||
|
return nil, fmt.Errorf("decrypt: header corrupted")
|
||||||
|
}
|
||||||
|
|
||||||
|
d := &Decryptor{
|
||||||
|
rd: rd,
|
||||||
|
}
|
||||||
|
|
||||||
|
err = d.Header.Unmarshal(hdr)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("decrypt: decode error: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if d.ChunkSize == 0 || d.ChunkSize > (16 * 1048576) {
|
||||||
|
return nil, fmt.Errorf("decrypt: invalid chunkSize %d", d.ChunkSize)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(d.Salt) != 32 {
|
||||||
|
return nil, fmt.Errorf("decrypt: invalid nonce length %d", len(d.Salt))
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(d.Keys) == 0 {
|
||||||
|
return nil, fmt.Errorf("decrypt: no wrapped keys")
|
||||||
|
}
|
||||||
|
|
||||||
|
// sanity check on the wrapped keys
|
||||||
|
for i, w := range d.Keys {
|
||||||
|
if len(w.PkHash) != PKHashLength {
|
||||||
|
return nil, fmt.Errorf("decrypt: wrapped key %d: invalid PkHash", i)
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(w.Pk) != 32 {
|
if len(w.Pk) != 32 {
|
||||||
return nil, parseErr("invalid Public Key length (exp 32, saw %d) in wrapped key", len(w.Pk))
|
return nil, fmt.Errorf("decrypt: wrapped key %d: invalid Curve25519 PK", i)
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(w.Key) != 32 {
|
// XXX Default AES-256-GCM Nonce size is 12
|
||||||
return nil, parseErr("invalid Key length (exp 32, saw %d) in wrapped key", len(w.Key))
|
if len(w.Nonce) != 12 {
|
||||||
|
return nil, fmt.Errorf("decrypt: wrapped key %d: invalid Nonce", i)
|
||||||
}
|
}
|
||||||
|
|
||||||
return &w, nil
|
if len(w.Key) == 0 {
|
||||||
|
return nil, fmt.Errorf("decrypt: wrapped key %d: missing encrypted key", i)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
d.buf = make([]byte, d.ChunkSize)
|
||||||
|
if pk != nil {
|
||||||
|
validSender := false
|
||||||
|
pkh := pk.Hash()
|
||||||
|
for _, w := range d.Keys {
|
||||||
|
if subtle.ConstantTimeCompare(pkh, w.PkHash) == 1 {
|
||||||
|
validSender = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !validSender {
|
||||||
|
return nil, fmt.Errorf("decrypt: Can't find sender's public key in the header")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return d, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Use Private Key 'sk' to decrypt the encrypted keys in the header
|
||||||
|
func (d *Decryptor) SetPrivateKey(sk *PrivateKey) error {
|
||||||
|
var err error
|
||||||
|
|
||||||
|
pkh := sk.PublicKey().Hash()
|
||||||
|
for i, w := range d.Keys {
|
||||||
|
if subtle.ConstantTimeCompare(pkh, w.PkHash) == 1 {
|
||||||
|
d.key, err = w.UnwrapKey(sk)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("decrypt: can't unwrap key %d: %s", i, err)
|
||||||
|
}
|
||||||
|
goto havekey
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return fmt.Errorf("decrypt: Can't find any public key to match the given private key")
|
||||||
|
|
||||||
|
|
||||||
|
havekey:
|
||||||
|
aes, err := aes.NewCipher(d.key)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("decrypt: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
d.ae, err = cipher.NewGCMWithNonceSize(aes, _AEADNonceLen)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("decrypt: %s", err)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return a list of Wrapped keys in the encrypted file header
|
||||||
|
func (d *Decryptor) WrappedKeys() []*WrappedKey {
|
||||||
|
return d.Keys
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Decrypt the file and write to 'wr'
|
||||||
|
func (d *Decryptor) Decrypt(wr io.Writer) error {
|
||||||
|
if d.key == nil {
|
||||||
|
return fmt.Errorf("decrypt: wrapped-key not decrypted (missing SetPrivateKey()?")
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := 0; ; i++ {
|
||||||
|
c, err := d.decrypt(i)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if len(c) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(c) > 0 {
|
||||||
|
err = fullwrite(c, wr)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("decrypt: %s", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Decrypt exactly one chunk of data
|
||||||
|
func (d *Decryptor) decrypt(i int) ([]byte, error) {
|
||||||
|
var b [8]byte
|
||||||
|
var nonceb [32]byte
|
||||||
|
|
||||||
|
n, err := io.ReadFull(d.rd, b[:4])
|
||||||
|
if n == 0 || err == io.EOF {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("decrypt: can't read chunk %d length: %s", i, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
chunklen := int(binary.BigEndian.Uint32(b[:4]))
|
||||||
|
binary.BigEndian.PutUint32(b[4:], uint32(i))
|
||||||
|
h := sha256.New()
|
||||||
|
h.Write(d.Salt)
|
||||||
|
h.Write(b[:])
|
||||||
|
nonce := h.Sum(nonceb[:0])
|
||||||
|
|
||||||
|
n, err = io.ReadFull(d.rd, d.buf[:chunklen])
|
||||||
|
if n == 0 || err == io.EOF {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("decrypt: can't read chunk %d: %s", i, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
p, err := d.ae.Open(d.buf[:0], nonce, d.buf[:chunklen], b[:])
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("decrypt: can't decrypt chunk %d: %s", i, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return p, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// given a file-encryption-key, wrap it in the identity of the recipient 'pk' using our
|
// given a file-encryption-key, wrap it in the identity of the recipient 'pk' using our
|
||||||
|
@ -125,6 +454,23 @@ func (sk *PrivateKey) WrapKey(pk *PublicKey, key []byte) (*WrappedKey, error) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Unwrap a wrapped key using the private key 'sk'
|
||||||
|
func (w *WrappedKey) UnwrapKey(sk *PrivateKey) ([]byte, error) {
|
||||||
|
var shared, theirPK, ourSK [32]byte
|
||||||
|
|
||||||
|
pk := sk.PublicKey()
|
||||||
|
copy(ourSK[:], sk.toCurve25519SK())
|
||||||
|
copy(theirPK[:], w.Pk)
|
||||||
|
curve25519.ScalarMult(&shared, &ourSK, &theirPK)
|
||||||
|
|
||||||
|
key, err := aeadOpen(w.Key, w.Nonce, shared[:], pk.Pk)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return key, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// Wrap a shared key with the recipient's public key 'pk' by generating an ephemeral
|
// Wrap a shared key with the recipient's public key 'pk' by generating an ephemeral
|
||||||
// Curve25519 keypair. This function does not identify the sender (non-repudiation).
|
// Curve25519 keypair. This function does not identify the sender (non-repudiation).
|
||||||
func (pk *PublicKey) WrapKeyEphemeral(key []byte) (*WrappedKey, error) {
|
func (pk *PublicKey) WrapKeyEphemeral(key []byte) (*WrappedKey, error) {
|
||||||
|
@ -144,22 +490,16 @@ func (pk *PublicKey) WrapKeyEphemeral(key []byte) (*WrappedKey, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func wrapKey(pk *PublicKey, k, theirPK, shared []byte) (*WrappedKey, error) {
|
func wrapKey(pk *PublicKey, k, theirPK, shared []byte) (*WrappedKey, error) {
|
||||||
|
ek, nonce, err := aeadSeal(k, shared[:], pk.Pk)
|
||||||
// hkdf or HMAC-sha-256
|
|
||||||
kek, err := expand(shared[:], pk.Pk)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("wrap: %s", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
ek, err := aeadSeal(k, kek)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("wrap: %s", err)
|
return nil, fmt.Errorf("wrap: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return &WrappedKey{
|
return &WrappedKey{
|
||||||
Key: ek,
|
|
||||||
Pk: theirPK,
|
|
||||||
PkHash: pk.hash,
|
PkHash: pk.hash,
|
||||||
|
Pk: theirPK,
|
||||||
|
Nonce: nonce,
|
||||||
|
Key: ek,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -226,67 +566,65 @@ func expand(shared, pk []byte) ([]byte, error) {
|
||||||
return kek, err
|
return kek, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func aeadSeal(data, key []byte) ([]byte, error) {
|
|
||||||
var salt [32]byte
|
|
||||||
var nonceb [64]byte
|
|
||||||
|
|
||||||
randread(salt[:])
|
// seal the data via AEAD after suitably expanding 'shared'
|
||||||
|
func aeadSeal(data, shared, pk []byte) ([]byte, []byte, error) {
|
||||||
h := sha512.New()
|
kek, err := expand(shared[:], pk)
|
||||||
h.Write(salt[:])
|
|
||||||
h.Write(key)
|
|
||||||
nonce := h.Sum(nonceb[:0])[:32]
|
|
||||||
|
|
||||||
aes, err := aes.NewCipher(key)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, nil, fmt.Errorf("wrap: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
ae, err := cipher.NewGCMWithNonceSize(aes, len(nonce))
|
aes, err := aes.NewCipher(kek)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, nil, fmt.Errorf("wrap: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
ae, err := cipher.NewGCM(aes)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, fmt.Errorf("wrap: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
noncesize := ae.NonceSize()
|
||||||
|
tagsize := ae.Overhead()
|
||||||
|
|
||||||
|
buf := make([]byte, tagsize + len(kek))
|
||||||
|
nonce := make([]byte, noncesize)
|
||||||
|
|
||||||
|
randread(nonce)
|
||||||
|
|
||||||
|
out := ae.Seal(buf[:0], nonce, data, nil)
|
||||||
|
return out, nonce, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func aeadOpen(data, nonce, shared, pk []byte) ([]byte, error) {
|
||||||
|
// hkdf or HMAC-sha-256
|
||||||
|
kek, err := expand(shared, pk)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("unwrap: %s", err)
|
||||||
|
}
|
||||||
|
aes, err := aes.NewCipher(kek)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("unwrap: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
ae, err := cipher.NewGCM(aes)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("unwrap: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
want := 32 + ae.Overhead()
|
||||||
|
if len(data) != want {
|
||||||
|
return nil, fmt.Errorf("unwrap: incorrect decrypt bytes (need %d, saw %d)", want, len(data))
|
||||||
|
}
|
||||||
|
|
||||||
|
c, err := ae.Open(data[:0], nonce, data, nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("unwrap: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
c := ae.Seal(nil, nonce, data, nil)
|
|
||||||
c = append(c, salt[:]...)
|
|
||||||
return c, nil
|
return c, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func aeadOpen(data, key []byte) ([]byte, error) {
|
|
||||||
var nonceb [64]byte
|
|
||||||
// GCM tag: 16 bytes
|
|
||||||
// salt: 32 bytes
|
|
||||||
// last 32 bytes: salt
|
|
||||||
|
|
||||||
n := len(data)
|
|
||||||
if n < (32 + 16) {
|
|
||||||
return nil, fmt.Errorf("aead: too few decrypt bytes (min 48, saw %d)", n)
|
|
||||||
}
|
|
||||||
|
|
||||||
salt := data[n-32:]
|
|
||||||
data = data[:n-32]
|
|
||||||
|
|
||||||
h := sha512.New()
|
|
||||||
h.Write(salt)
|
|
||||||
h.Write(key)
|
|
||||||
nonce := h.Sum(nonceb[:0])[:32]
|
|
||||||
|
|
||||||
aes, err := aes.NewCipher(key)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
ae, err := cipher.NewGCMWithNonceSize(aes, len(nonce))
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
c, err := ae.Open(nil, nonce, data, nil)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return c, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func clamp(k []byte) []byte {
|
func clamp(k []byte) []byte {
|
||||||
k[0] &= 248
|
k[0] &= 248
|
||||||
|
|
899
sign/hdr.pb.go
Normal file
899
sign/hdr.pb.go
Normal file
|
@ -0,0 +1,899 @@
|
||||||
|
// Code generated by protoc-gen-gogo. DO NOT EDIT.
|
||||||
|
// source: sign/hdr.proto
|
||||||
|
|
||||||
|
package sign
|
||||||
|
|
||||||
|
import (
|
||||||
|
bytes "bytes"
|
||||||
|
fmt "fmt"
|
||||||
|
proto "github.com/gogo/protobuf/proto"
|
||||||
|
io "io"
|
||||||
|
math "math"
|
||||||
|
math_bits "math/bits"
|
||||||
|
reflect "reflect"
|
||||||
|
strings "strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Reference imports to suppress errors if they are not otherwise used.
|
||||||
|
var _ = proto.Marshal
|
||||||
|
var _ = fmt.Errorf
|
||||||
|
var _ = math.Inf
|
||||||
|
|
||||||
|
// This is a compile-time assertion to ensure that this generated file
|
||||||
|
// is compatible with the proto package it is being compiled against.
|
||||||
|
// A compilation error at this line likely means your copy of the
|
||||||
|
// proto package needs to be updated.
|
||||||
|
const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package
|
||||||
|
|
||||||
|
type Header struct {
|
||||||
|
ChunkSize uint32 `protobuf:"varint,1,opt,name=chunk_size,json=chunkSize,proto3" json:"chunk_size,omitempty"`
|
||||||
|
Salt []byte `protobuf:"bytes,2,opt,name=salt,proto3" json:"salt,omitempty"`
|
||||||
|
Keys []*WrappedKey `protobuf:"bytes,3,rep,name=keys,proto3" json:"keys,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Header) Reset() { *m = Header{} }
|
||||||
|
func (*Header) ProtoMessage() {}
|
||||||
|
func (*Header) Descriptor() ([]byte, []int) {
|
||||||
|
return fileDescriptor_85aff542c746609f, []int{0}
|
||||||
|
}
|
||||||
|
func (m *Header) XXX_Unmarshal(b []byte) error {
|
||||||
|
return m.Unmarshal(b)
|
||||||
|
}
|
||||||
|
func (m *Header) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
|
||||||
|
if deterministic {
|
||||||
|
return xxx_messageInfo_Header.Marshal(b, m, deterministic)
|
||||||
|
} else {
|
||||||
|
b = b[:cap(b)]
|
||||||
|
n, err := m.MarshalToSizedBuffer(b)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return b[:n], nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
func (m *Header) XXX_Merge(src proto.Message) {
|
||||||
|
xxx_messageInfo_Header.Merge(m, src)
|
||||||
|
}
|
||||||
|
func (m *Header) XXX_Size() int {
|
||||||
|
return m.Size()
|
||||||
|
}
|
||||||
|
func (m *Header) XXX_DiscardUnknown() {
|
||||||
|
xxx_messageInfo_Header.DiscardUnknown(m)
|
||||||
|
}
|
||||||
|
|
||||||
|
var xxx_messageInfo_Header proto.InternalMessageInfo
|
||||||
|
|
||||||
|
func (m *Header) GetChunkSize() uint32 {
|
||||||
|
if m != nil {
|
||||||
|
return m.ChunkSize
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Header) GetSalt() []byte {
|
||||||
|
if m != nil {
|
||||||
|
return m.Salt
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Header) GetKeys() []*WrappedKey {
|
||||||
|
if m != nil {
|
||||||
|
return m.Keys
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type WrappedKey struct {
|
||||||
|
PkHash []byte `protobuf:"bytes,1,opt,name=pk_hash,json=pkHash,proto3" json:"pk_hash,omitempty"`
|
||||||
|
Pk []byte `protobuf:"bytes,2,opt,name=pk,proto3" json:"pk,omitempty"`
|
||||||
|
Nonce []byte `protobuf:"bytes,3,opt,name=nonce,proto3" json:"nonce,omitempty"`
|
||||||
|
Key []byte `protobuf:"bytes,4,opt,name=key,proto3" json:"key,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *WrappedKey) Reset() { *m = WrappedKey{} }
|
||||||
|
func (*WrappedKey) ProtoMessage() {}
|
||||||
|
func (*WrappedKey) Descriptor() ([]byte, []int) {
|
||||||
|
return fileDescriptor_85aff542c746609f, []int{1}
|
||||||
|
}
|
||||||
|
func (m *WrappedKey) XXX_Unmarshal(b []byte) error {
|
||||||
|
return m.Unmarshal(b)
|
||||||
|
}
|
||||||
|
func (m *WrappedKey) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
|
||||||
|
if deterministic {
|
||||||
|
return xxx_messageInfo_WrappedKey.Marshal(b, m, deterministic)
|
||||||
|
} else {
|
||||||
|
b = b[:cap(b)]
|
||||||
|
n, err := m.MarshalToSizedBuffer(b)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return b[:n], nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
func (m *WrappedKey) XXX_Merge(src proto.Message) {
|
||||||
|
xxx_messageInfo_WrappedKey.Merge(m, src)
|
||||||
|
}
|
||||||
|
func (m *WrappedKey) XXX_Size() int {
|
||||||
|
return m.Size()
|
||||||
|
}
|
||||||
|
func (m *WrappedKey) XXX_DiscardUnknown() {
|
||||||
|
xxx_messageInfo_WrappedKey.DiscardUnknown(m)
|
||||||
|
}
|
||||||
|
|
||||||
|
var xxx_messageInfo_WrappedKey proto.InternalMessageInfo
|
||||||
|
|
||||||
|
func (m *WrappedKey) GetPkHash() []byte {
|
||||||
|
if m != nil {
|
||||||
|
return m.PkHash
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *WrappedKey) GetPk() []byte {
|
||||||
|
if m != nil {
|
||||||
|
return m.Pk
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *WrappedKey) GetNonce() []byte {
|
||||||
|
if m != nil {
|
||||||
|
return m.Nonce
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *WrappedKey) GetKey() []byte {
|
||||||
|
if m != nil {
|
||||||
|
return m.Key
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
proto.RegisterType((*Header)(nil), "sign.header")
|
||||||
|
proto.RegisterType((*WrappedKey)(nil), "sign.wrapped_key")
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() { proto.RegisterFile("sign/hdr.proto", fileDescriptor_85aff542c746609f) }
|
||||||
|
|
||||||
|
var fileDescriptor_85aff542c746609f = []byte{
|
||||||
|
// 257 bytes of a gzipped FileDescriptorProto
|
||||||
|
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x4c, 0x90, 0x31, 0x4a, 0xc4, 0x40,
|
||||||
|
0x14, 0x86, 0xe7, 0x25, 0x31, 0xe2, 0xdb, 0x75, 0xd1, 0x41, 0x30, 0x8d, 0x8f, 0xb0, 0x20, 0xa4,
|
||||||
|
0x8a, 0xa0, 0x9e, 0xc0, 0xca, 0x3a, 0xf6, 0x86, 0xec, 0x66, 0x70, 0xc2, 0x48, 0x32, 0x64, 0x56,
|
||||||
|
0x24, 0x5b, 0x79, 0x04, 0x8f, 0xe1, 0x51, 0x2c, 0x53, 0x6e, 0x69, 0x26, 0x8d, 0xe5, 0x1e, 0x41,
|
||||||
|
0x32, 0x5a, 0xd8, 0xfd, 0xff, 0xf7, 0xe0, 0x7d, 0xf0, 0xe3, 0xc2, 0x54, 0x4f, 0xf5, 0x95, 0x2c,
|
||||||
|
0xdb, 0x54, 0xb7, 0xcd, 0xa6, 0xe1, 0xc1, 0xd4, 0x97, 0x2b, 0x0c, 0xa5, 0x28, 0x4a, 0xd1, 0xf2,
|
||||||
|
0x0b, 0xc4, 0xb5, 0x7c, 0xa9, 0x55, 0x6e, 0xaa, 0xad, 0x88, 0x20, 0x86, 0xe4, 0x38, 0x3b, 0x72,
|
||||||
|
0xe4, 0xa1, 0xda, 0x0a, 0xce, 0x31, 0x30, 0xc5, 0xf3, 0x26, 0xf2, 0x62, 0x48, 0xe6, 0x99, 0xcb,
|
||||||
|
0xfc, 0x12, 0x03, 0x25, 0x3a, 0x13, 0xf9, 0xb1, 0x9f, 0xcc, 0xae, 0x4f, 0xd3, 0xe9, 0x63, 0xfa,
|
||||||
|
0xda, 0x16, 0x5a, 0x8b, 0x32, 0x57, 0xa2, 0xcb, 0xdc, 0x79, 0xf9, 0x88, 0xb3, 0x7f, 0x90, 0x9f,
|
||||||
|
0xe3, 0xa1, 0x56, 0xb9, 0x2c, 0x8c, 0x74, 0x96, 0x79, 0x16, 0x6a, 0x75, 0x5f, 0x18, 0xc9, 0x17,
|
||||||
|
0xe8, 0x69, 0xf5, 0x27, 0xf0, 0xb4, 0xe2, 0x67, 0x78, 0x50, 0x37, 0xf5, 0x5a, 0x44, 0xbe, 0x43,
|
||||||
|
0xbf, 0x85, 0x9f, 0xa0, 0xaf, 0x44, 0x17, 0x05, 0x8e, 0x4d, 0xf1, 0xee, 0xb6, 0x1f, 0x88, 0xed,
|
||||||
|
0x06, 0x62, 0xfb, 0x81, 0xe0, 0xcd, 0x12, 0x7c, 0x58, 0x82, 0x4f, 0x4b, 0xd0, 0x5b, 0x82, 0x2f,
|
||||||
|
0x4b, 0xf0, 0x6d, 0x89, 0xed, 0x2d, 0xc1, 0xfb, 0x48, 0xac, 0x1f, 0x89, 0xed, 0x46, 0x62, 0xab,
|
||||||
|
0xd0, 0xcd, 0x70, 0xf3, 0x13, 0x00, 0x00, 0xff, 0xff, 0xde, 0xf2, 0x28, 0xc0, 0x18, 0x01, 0x00,
|
||||||
|
0x00,
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *Header) Equal(that interface{}) bool {
|
||||||
|
if that == nil {
|
||||||
|
return this == nil
|
||||||
|
}
|
||||||
|
|
||||||
|
that1, ok := that.(*Header)
|
||||||
|
if !ok {
|
||||||
|
that2, ok := that.(Header)
|
||||||
|
if ok {
|
||||||
|
that1 = &that2
|
||||||
|
} else {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if that1 == nil {
|
||||||
|
return this == nil
|
||||||
|
} else if this == nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if this.ChunkSize != that1.ChunkSize {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if !bytes.Equal(this.Salt, that1.Salt) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if len(this.Keys) != len(that1.Keys) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
for i := range this.Keys {
|
||||||
|
if !this.Keys[i].Equal(that1.Keys[i]) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
func (this *WrappedKey) Equal(that interface{}) bool {
|
||||||
|
if that == nil {
|
||||||
|
return this == nil
|
||||||
|
}
|
||||||
|
|
||||||
|
that1, ok := that.(*WrappedKey)
|
||||||
|
if !ok {
|
||||||
|
that2, ok := that.(WrappedKey)
|
||||||
|
if ok {
|
||||||
|
that1 = &that2
|
||||||
|
} else {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if that1 == nil {
|
||||||
|
return this == nil
|
||||||
|
} else if this == nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if !bytes.Equal(this.PkHash, that1.PkHash) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if !bytes.Equal(this.Pk, that1.Pk) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if !bytes.Equal(this.Nonce, that1.Nonce) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if !bytes.Equal(this.Key, that1.Key) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
func (this *Header) GoString() string {
|
||||||
|
if this == nil {
|
||||||
|
return "nil"
|
||||||
|
}
|
||||||
|
s := make([]string, 0, 7)
|
||||||
|
s = append(s, "&sign.Header{")
|
||||||
|
s = append(s, "ChunkSize: "+fmt.Sprintf("%#v", this.ChunkSize)+",\n")
|
||||||
|
s = append(s, "Salt: "+fmt.Sprintf("%#v", this.Salt)+",\n")
|
||||||
|
if this.Keys != nil {
|
||||||
|
s = append(s, "Keys: "+fmt.Sprintf("%#v", this.Keys)+",\n")
|
||||||
|
}
|
||||||
|
s = append(s, "}")
|
||||||
|
return strings.Join(s, "")
|
||||||
|
}
|
||||||
|
func (this *WrappedKey) GoString() string {
|
||||||
|
if this == nil {
|
||||||
|
return "nil"
|
||||||
|
}
|
||||||
|
s := make([]string, 0, 8)
|
||||||
|
s = append(s, "&sign.WrappedKey{")
|
||||||
|
s = append(s, "PkHash: "+fmt.Sprintf("%#v", this.PkHash)+",\n")
|
||||||
|
s = append(s, "Pk: "+fmt.Sprintf("%#v", this.Pk)+",\n")
|
||||||
|
s = append(s, "Nonce: "+fmt.Sprintf("%#v", this.Nonce)+",\n")
|
||||||
|
s = append(s, "Key: "+fmt.Sprintf("%#v", this.Key)+",\n")
|
||||||
|
s = append(s, "}")
|
||||||
|
return strings.Join(s, "")
|
||||||
|
}
|
||||||
|
func valueToGoStringHdr(v interface{}, typ string) string {
|
||||||
|
rv := reflect.ValueOf(v)
|
||||||
|
if rv.IsNil() {
|
||||||
|
return "nil"
|
||||||
|
}
|
||||||
|
pv := reflect.Indirect(rv).Interface()
|
||||||
|
return fmt.Sprintf("func(v %v) *%v { return &v } ( %#v )", typ, typ, pv)
|
||||||
|
}
|
||||||
|
func (m *Header) Marshal() (dAtA []byte, err error) {
|
||||||
|
size := m.Size()
|
||||||
|
dAtA = make([]byte, size)
|
||||||
|
n, err := m.MarshalToSizedBuffer(dAtA[:size])
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return dAtA[:n], nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Header) MarshalTo(dAtA []byte) (int, error) {
|
||||||
|
size := m.Size()
|
||||||
|
return m.MarshalToSizedBuffer(dAtA[:size])
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Header) MarshalToSizedBuffer(dAtA []byte) (int, error) {
|
||||||
|
i := len(dAtA)
|
||||||
|
_ = i
|
||||||
|
var l int
|
||||||
|
_ = l
|
||||||
|
if len(m.Keys) > 0 {
|
||||||
|
for iNdEx := len(m.Keys) - 1; iNdEx >= 0; iNdEx-- {
|
||||||
|
{
|
||||||
|
size, err := m.Keys[iNdEx].MarshalToSizedBuffer(dAtA[:i])
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
i -= size
|
||||||
|
i = encodeVarintHdr(dAtA, i, uint64(size))
|
||||||
|
}
|
||||||
|
i--
|
||||||
|
dAtA[i] = 0x1a
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(m.Salt) > 0 {
|
||||||
|
i -= len(m.Salt)
|
||||||
|
copy(dAtA[i:], m.Salt)
|
||||||
|
i = encodeVarintHdr(dAtA, i, uint64(len(m.Salt)))
|
||||||
|
i--
|
||||||
|
dAtA[i] = 0x12
|
||||||
|
}
|
||||||
|
if m.ChunkSize != 0 {
|
||||||
|
i = encodeVarintHdr(dAtA, i, uint64(m.ChunkSize))
|
||||||
|
i--
|
||||||
|
dAtA[i] = 0x8
|
||||||
|
}
|
||||||
|
return len(dAtA) - i, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *WrappedKey) Marshal() (dAtA []byte, err error) {
|
||||||
|
size := m.Size()
|
||||||
|
dAtA = make([]byte, size)
|
||||||
|
n, err := m.MarshalToSizedBuffer(dAtA[:size])
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return dAtA[:n], nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *WrappedKey) MarshalTo(dAtA []byte) (int, error) {
|
||||||
|
size := m.Size()
|
||||||
|
return m.MarshalToSizedBuffer(dAtA[:size])
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *WrappedKey) MarshalToSizedBuffer(dAtA []byte) (int, error) {
|
||||||
|
i := len(dAtA)
|
||||||
|
_ = i
|
||||||
|
var l int
|
||||||
|
_ = l
|
||||||
|
if len(m.Key) > 0 {
|
||||||
|
i -= len(m.Key)
|
||||||
|
copy(dAtA[i:], m.Key)
|
||||||
|
i = encodeVarintHdr(dAtA, i, uint64(len(m.Key)))
|
||||||
|
i--
|
||||||
|
dAtA[i] = 0x22
|
||||||
|
}
|
||||||
|
if len(m.Nonce) > 0 {
|
||||||
|
i -= len(m.Nonce)
|
||||||
|
copy(dAtA[i:], m.Nonce)
|
||||||
|
i = encodeVarintHdr(dAtA, i, uint64(len(m.Nonce)))
|
||||||
|
i--
|
||||||
|
dAtA[i] = 0x1a
|
||||||
|
}
|
||||||
|
if len(m.Pk) > 0 {
|
||||||
|
i -= len(m.Pk)
|
||||||
|
copy(dAtA[i:], m.Pk)
|
||||||
|
i = encodeVarintHdr(dAtA, i, uint64(len(m.Pk)))
|
||||||
|
i--
|
||||||
|
dAtA[i] = 0x12
|
||||||
|
}
|
||||||
|
if len(m.PkHash) > 0 {
|
||||||
|
i -= len(m.PkHash)
|
||||||
|
copy(dAtA[i:], m.PkHash)
|
||||||
|
i = encodeVarintHdr(dAtA, i, uint64(len(m.PkHash)))
|
||||||
|
i--
|
||||||
|
dAtA[i] = 0xa
|
||||||
|
}
|
||||||
|
return len(dAtA) - i, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func encodeVarintHdr(dAtA []byte, offset int, v uint64) int {
|
||||||
|
offset -= sovHdr(v)
|
||||||
|
base := offset
|
||||||
|
for v >= 1<<7 {
|
||||||
|
dAtA[offset] = uint8(v&0x7f | 0x80)
|
||||||
|
v >>= 7
|
||||||
|
offset++
|
||||||
|
}
|
||||||
|
dAtA[offset] = uint8(v)
|
||||||
|
return base
|
||||||
|
}
|
||||||
|
func (m *Header) Size() (n int) {
|
||||||
|
if m == nil {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
var l int
|
||||||
|
_ = l
|
||||||
|
if m.ChunkSize != 0 {
|
||||||
|
n += 1 + sovHdr(uint64(m.ChunkSize))
|
||||||
|
}
|
||||||
|
l = len(m.Salt)
|
||||||
|
if l > 0 {
|
||||||
|
n += 1 + l + sovHdr(uint64(l))
|
||||||
|
}
|
||||||
|
if len(m.Keys) > 0 {
|
||||||
|
for _, e := range m.Keys {
|
||||||
|
l = e.Size()
|
||||||
|
n += 1 + l + sovHdr(uint64(l))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return n
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *WrappedKey) Size() (n int) {
|
||||||
|
if m == nil {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
var l int
|
||||||
|
_ = l
|
||||||
|
l = len(m.PkHash)
|
||||||
|
if l > 0 {
|
||||||
|
n += 1 + l + sovHdr(uint64(l))
|
||||||
|
}
|
||||||
|
l = len(m.Pk)
|
||||||
|
if l > 0 {
|
||||||
|
n += 1 + l + sovHdr(uint64(l))
|
||||||
|
}
|
||||||
|
l = len(m.Nonce)
|
||||||
|
if l > 0 {
|
||||||
|
n += 1 + l + sovHdr(uint64(l))
|
||||||
|
}
|
||||||
|
l = len(m.Key)
|
||||||
|
if l > 0 {
|
||||||
|
n += 1 + l + sovHdr(uint64(l))
|
||||||
|
}
|
||||||
|
return n
|
||||||
|
}
|
||||||
|
|
||||||
|
func sovHdr(x uint64) (n int) {
|
||||||
|
return (math_bits.Len64(x|1) + 6) / 7
|
||||||
|
}
|
||||||
|
func sozHdr(x uint64) (n int) {
|
||||||
|
return sovHdr(uint64((x << 1) ^ uint64((int64(x) >> 63))))
|
||||||
|
}
|
||||||
|
func (this *Header) String() string {
|
||||||
|
if this == nil {
|
||||||
|
return "nil"
|
||||||
|
}
|
||||||
|
repeatedStringForKeys := "[]*WrappedKey{"
|
||||||
|
for _, f := range this.Keys {
|
||||||
|
repeatedStringForKeys += strings.Replace(fmt.Sprintf("%v", f), "WrappedKey", "WrappedKey", 1) + ","
|
||||||
|
}
|
||||||
|
repeatedStringForKeys += "}"
|
||||||
|
s := strings.Join([]string{`&Header{`,
|
||||||
|
`ChunkSize:` + fmt.Sprintf("%v", this.ChunkSize) + `,`,
|
||||||
|
`Salt:` + fmt.Sprintf("%v", this.Salt) + `,`,
|
||||||
|
`Keys:` + repeatedStringForKeys + `,`,
|
||||||
|
`}`,
|
||||||
|
}, "")
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
func (this *WrappedKey) String() string {
|
||||||
|
if this == nil {
|
||||||
|
return "nil"
|
||||||
|
}
|
||||||
|
s := strings.Join([]string{`&WrappedKey{`,
|
||||||
|
`PkHash:` + fmt.Sprintf("%v", this.PkHash) + `,`,
|
||||||
|
`Pk:` + fmt.Sprintf("%v", this.Pk) + `,`,
|
||||||
|
`Nonce:` + fmt.Sprintf("%v", this.Nonce) + `,`,
|
||||||
|
`Key:` + fmt.Sprintf("%v", this.Key) + `,`,
|
||||||
|
`}`,
|
||||||
|
}, "")
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
func valueToStringHdr(v interface{}) string {
|
||||||
|
rv := reflect.ValueOf(v)
|
||||||
|
if rv.IsNil() {
|
||||||
|
return "nil"
|
||||||
|
}
|
||||||
|
pv := reflect.Indirect(rv).Interface()
|
||||||
|
return fmt.Sprintf("*%v", pv)
|
||||||
|
}
|
||||||
|
func (m *Header) Unmarshal(dAtA []byte) error {
|
||||||
|
l := len(dAtA)
|
||||||
|
iNdEx := 0
|
||||||
|
for iNdEx < l {
|
||||||
|
preIndex := iNdEx
|
||||||
|
var wire uint64
|
||||||
|
for shift := uint(0); ; shift += 7 {
|
||||||
|
if shift >= 64 {
|
||||||
|
return ErrIntOverflowHdr
|
||||||
|
}
|
||||||
|
if iNdEx >= l {
|
||||||
|
return io.ErrUnexpectedEOF
|
||||||
|
}
|
||||||
|
b := dAtA[iNdEx]
|
||||||
|
iNdEx++
|
||||||
|
wire |= uint64(b&0x7F) << shift
|
||||||
|
if b < 0x80 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fieldNum := int32(wire >> 3)
|
||||||
|
wireType := int(wire & 0x7)
|
||||||
|
if wireType == 4 {
|
||||||
|
return fmt.Errorf("proto: header: wiretype end group for non-group")
|
||||||
|
}
|
||||||
|
if fieldNum <= 0 {
|
||||||
|
return fmt.Errorf("proto: header: illegal tag %d (wire type %d)", fieldNum, wire)
|
||||||
|
}
|
||||||
|
switch fieldNum {
|
||||||
|
case 1:
|
||||||
|
if wireType != 0 {
|
||||||
|
return fmt.Errorf("proto: wrong wireType = %d for field ChunkSize", wireType)
|
||||||
|
}
|
||||||
|
m.ChunkSize = 0
|
||||||
|
for shift := uint(0); ; shift += 7 {
|
||||||
|
if shift >= 64 {
|
||||||
|
return ErrIntOverflowHdr
|
||||||
|
}
|
||||||
|
if iNdEx >= l {
|
||||||
|
return io.ErrUnexpectedEOF
|
||||||
|
}
|
||||||
|
b := dAtA[iNdEx]
|
||||||
|
iNdEx++
|
||||||
|
m.ChunkSize |= uint32(b&0x7F) << shift
|
||||||
|
if b < 0x80 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case 2:
|
||||||
|
if wireType != 2 {
|
||||||
|
return fmt.Errorf("proto: wrong wireType = %d for field Salt", wireType)
|
||||||
|
}
|
||||||
|
var byteLen int
|
||||||
|
for shift := uint(0); ; shift += 7 {
|
||||||
|
if shift >= 64 {
|
||||||
|
return ErrIntOverflowHdr
|
||||||
|
}
|
||||||
|
if iNdEx >= l {
|
||||||
|
return io.ErrUnexpectedEOF
|
||||||
|
}
|
||||||
|
b := dAtA[iNdEx]
|
||||||
|
iNdEx++
|
||||||
|
byteLen |= int(b&0x7F) << shift
|
||||||
|
if b < 0x80 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if byteLen < 0 {
|
||||||
|
return ErrInvalidLengthHdr
|
||||||
|
}
|
||||||
|
postIndex := iNdEx + byteLen
|
||||||
|
if postIndex < 0 {
|
||||||
|
return ErrInvalidLengthHdr
|
||||||
|
}
|
||||||
|
if postIndex > l {
|
||||||
|
return io.ErrUnexpectedEOF
|
||||||
|
}
|
||||||
|
m.Salt = append(m.Salt[:0], dAtA[iNdEx:postIndex]...)
|
||||||
|
if m.Salt == nil {
|
||||||
|
m.Salt = []byte{}
|
||||||
|
}
|
||||||
|
iNdEx = postIndex
|
||||||
|
case 3:
|
||||||
|
if wireType != 2 {
|
||||||
|
return fmt.Errorf("proto: wrong wireType = %d for field Keys", wireType)
|
||||||
|
}
|
||||||
|
var msglen int
|
||||||
|
for shift := uint(0); ; shift += 7 {
|
||||||
|
if shift >= 64 {
|
||||||
|
return ErrIntOverflowHdr
|
||||||
|
}
|
||||||
|
if iNdEx >= l {
|
||||||
|
return io.ErrUnexpectedEOF
|
||||||
|
}
|
||||||
|
b := dAtA[iNdEx]
|
||||||
|
iNdEx++
|
||||||
|
msglen |= int(b&0x7F) << shift
|
||||||
|
if b < 0x80 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if msglen < 0 {
|
||||||
|
return ErrInvalidLengthHdr
|
||||||
|
}
|
||||||
|
postIndex := iNdEx + msglen
|
||||||
|
if postIndex < 0 {
|
||||||
|
return ErrInvalidLengthHdr
|
||||||
|
}
|
||||||
|
if postIndex > l {
|
||||||
|
return io.ErrUnexpectedEOF
|
||||||
|
}
|
||||||
|
m.Keys = append(m.Keys, &WrappedKey{})
|
||||||
|
if err := m.Keys[len(m.Keys)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
iNdEx = postIndex
|
||||||
|
default:
|
||||||
|
iNdEx = preIndex
|
||||||
|
skippy, err := skipHdr(dAtA[iNdEx:])
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if skippy < 0 {
|
||||||
|
return ErrInvalidLengthHdr
|
||||||
|
}
|
||||||
|
if (iNdEx + skippy) < 0 {
|
||||||
|
return ErrInvalidLengthHdr
|
||||||
|
}
|
||||||
|
if (iNdEx + skippy) > l {
|
||||||
|
return io.ErrUnexpectedEOF
|
||||||
|
}
|
||||||
|
iNdEx += skippy
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if iNdEx > l {
|
||||||
|
return io.ErrUnexpectedEOF
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
func (m *WrappedKey) Unmarshal(dAtA []byte) error {
|
||||||
|
l := len(dAtA)
|
||||||
|
iNdEx := 0
|
||||||
|
for iNdEx < l {
|
||||||
|
preIndex := iNdEx
|
||||||
|
var wire uint64
|
||||||
|
for shift := uint(0); ; shift += 7 {
|
||||||
|
if shift >= 64 {
|
||||||
|
return ErrIntOverflowHdr
|
||||||
|
}
|
||||||
|
if iNdEx >= l {
|
||||||
|
return io.ErrUnexpectedEOF
|
||||||
|
}
|
||||||
|
b := dAtA[iNdEx]
|
||||||
|
iNdEx++
|
||||||
|
wire |= uint64(b&0x7F) << shift
|
||||||
|
if b < 0x80 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fieldNum := int32(wire >> 3)
|
||||||
|
wireType := int(wire & 0x7)
|
||||||
|
if wireType == 4 {
|
||||||
|
return fmt.Errorf("proto: wrapped_key: wiretype end group for non-group")
|
||||||
|
}
|
||||||
|
if fieldNum <= 0 {
|
||||||
|
return fmt.Errorf("proto: wrapped_key: illegal tag %d (wire type %d)", fieldNum, wire)
|
||||||
|
}
|
||||||
|
switch fieldNum {
|
||||||
|
case 1:
|
||||||
|
if wireType != 2 {
|
||||||
|
return fmt.Errorf("proto: wrong wireType = %d for field PkHash", wireType)
|
||||||
|
}
|
||||||
|
var byteLen int
|
||||||
|
for shift := uint(0); ; shift += 7 {
|
||||||
|
if shift >= 64 {
|
||||||
|
return ErrIntOverflowHdr
|
||||||
|
}
|
||||||
|
if iNdEx >= l {
|
||||||
|
return io.ErrUnexpectedEOF
|
||||||
|
}
|
||||||
|
b := dAtA[iNdEx]
|
||||||
|
iNdEx++
|
||||||
|
byteLen |= int(b&0x7F) << shift
|
||||||
|
if b < 0x80 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if byteLen < 0 {
|
||||||
|
return ErrInvalidLengthHdr
|
||||||
|
}
|
||||||
|
postIndex := iNdEx + byteLen
|
||||||
|
if postIndex < 0 {
|
||||||
|
return ErrInvalidLengthHdr
|
||||||
|
}
|
||||||
|
if postIndex > l {
|
||||||
|
return io.ErrUnexpectedEOF
|
||||||
|
}
|
||||||
|
m.PkHash = append(m.PkHash[:0], dAtA[iNdEx:postIndex]...)
|
||||||
|
if m.PkHash == nil {
|
||||||
|
m.PkHash = []byte{}
|
||||||
|
}
|
||||||
|
iNdEx = postIndex
|
||||||
|
case 2:
|
||||||
|
if wireType != 2 {
|
||||||
|
return fmt.Errorf("proto: wrong wireType = %d for field Pk", wireType)
|
||||||
|
}
|
||||||
|
var byteLen int
|
||||||
|
for shift := uint(0); ; shift += 7 {
|
||||||
|
if shift >= 64 {
|
||||||
|
return ErrIntOverflowHdr
|
||||||
|
}
|
||||||
|
if iNdEx >= l {
|
||||||
|
return io.ErrUnexpectedEOF
|
||||||
|
}
|
||||||
|
b := dAtA[iNdEx]
|
||||||
|
iNdEx++
|
||||||
|
byteLen |= int(b&0x7F) << shift
|
||||||
|
if b < 0x80 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if byteLen < 0 {
|
||||||
|
return ErrInvalidLengthHdr
|
||||||
|
}
|
||||||
|
postIndex := iNdEx + byteLen
|
||||||
|
if postIndex < 0 {
|
||||||
|
return ErrInvalidLengthHdr
|
||||||
|
}
|
||||||
|
if postIndex > l {
|
||||||
|
return io.ErrUnexpectedEOF
|
||||||
|
}
|
||||||
|
m.Pk = append(m.Pk[:0], dAtA[iNdEx:postIndex]...)
|
||||||
|
if m.Pk == nil {
|
||||||
|
m.Pk = []byte{}
|
||||||
|
}
|
||||||
|
iNdEx = postIndex
|
||||||
|
case 3:
|
||||||
|
if wireType != 2 {
|
||||||
|
return fmt.Errorf("proto: wrong wireType = %d for field Nonce", wireType)
|
||||||
|
}
|
||||||
|
var byteLen int
|
||||||
|
for shift := uint(0); ; shift += 7 {
|
||||||
|
if shift >= 64 {
|
||||||
|
return ErrIntOverflowHdr
|
||||||
|
}
|
||||||
|
if iNdEx >= l {
|
||||||
|
return io.ErrUnexpectedEOF
|
||||||
|
}
|
||||||
|
b := dAtA[iNdEx]
|
||||||
|
iNdEx++
|
||||||
|
byteLen |= int(b&0x7F) << shift
|
||||||
|
if b < 0x80 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if byteLen < 0 {
|
||||||
|
return ErrInvalidLengthHdr
|
||||||
|
}
|
||||||
|
postIndex := iNdEx + byteLen
|
||||||
|
if postIndex < 0 {
|
||||||
|
return ErrInvalidLengthHdr
|
||||||
|
}
|
||||||
|
if postIndex > l {
|
||||||
|
return io.ErrUnexpectedEOF
|
||||||
|
}
|
||||||
|
m.Nonce = append(m.Nonce[:0], dAtA[iNdEx:postIndex]...)
|
||||||
|
if m.Nonce == nil {
|
||||||
|
m.Nonce = []byte{}
|
||||||
|
}
|
||||||
|
iNdEx = postIndex
|
||||||
|
case 4:
|
||||||
|
if wireType != 2 {
|
||||||
|
return fmt.Errorf("proto: wrong wireType = %d for field Key", wireType)
|
||||||
|
}
|
||||||
|
var byteLen int
|
||||||
|
for shift := uint(0); ; shift += 7 {
|
||||||
|
if shift >= 64 {
|
||||||
|
return ErrIntOverflowHdr
|
||||||
|
}
|
||||||
|
if iNdEx >= l {
|
||||||
|
return io.ErrUnexpectedEOF
|
||||||
|
}
|
||||||
|
b := dAtA[iNdEx]
|
||||||
|
iNdEx++
|
||||||
|
byteLen |= int(b&0x7F) << shift
|
||||||
|
if b < 0x80 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if byteLen < 0 {
|
||||||
|
return ErrInvalidLengthHdr
|
||||||
|
}
|
||||||
|
postIndex := iNdEx + byteLen
|
||||||
|
if postIndex < 0 {
|
||||||
|
return ErrInvalidLengthHdr
|
||||||
|
}
|
||||||
|
if postIndex > l {
|
||||||
|
return io.ErrUnexpectedEOF
|
||||||
|
}
|
||||||
|
m.Key = append(m.Key[:0], dAtA[iNdEx:postIndex]...)
|
||||||
|
if m.Key == nil {
|
||||||
|
m.Key = []byte{}
|
||||||
|
}
|
||||||
|
iNdEx = postIndex
|
||||||
|
default:
|
||||||
|
iNdEx = preIndex
|
||||||
|
skippy, err := skipHdr(dAtA[iNdEx:])
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if skippy < 0 {
|
||||||
|
return ErrInvalidLengthHdr
|
||||||
|
}
|
||||||
|
if (iNdEx + skippy) < 0 {
|
||||||
|
return ErrInvalidLengthHdr
|
||||||
|
}
|
||||||
|
if (iNdEx + skippy) > l {
|
||||||
|
return io.ErrUnexpectedEOF
|
||||||
|
}
|
||||||
|
iNdEx += skippy
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if iNdEx > l {
|
||||||
|
return io.ErrUnexpectedEOF
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
func skipHdr(dAtA []byte) (n int, err error) {
|
||||||
|
l := len(dAtA)
|
||||||
|
iNdEx := 0
|
||||||
|
depth := 0
|
||||||
|
for iNdEx < l {
|
||||||
|
var wire uint64
|
||||||
|
for shift := uint(0); ; shift += 7 {
|
||||||
|
if shift >= 64 {
|
||||||
|
return 0, ErrIntOverflowHdr
|
||||||
|
}
|
||||||
|
if iNdEx >= l {
|
||||||
|
return 0, io.ErrUnexpectedEOF
|
||||||
|
}
|
||||||
|
b := dAtA[iNdEx]
|
||||||
|
iNdEx++
|
||||||
|
wire |= (uint64(b) & 0x7F) << shift
|
||||||
|
if b < 0x80 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
wireType := int(wire & 0x7)
|
||||||
|
switch wireType {
|
||||||
|
case 0:
|
||||||
|
for shift := uint(0); ; shift += 7 {
|
||||||
|
if shift >= 64 {
|
||||||
|
return 0, ErrIntOverflowHdr
|
||||||
|
}
|
||||||
|
if iNdEx >= l {
|
||||||
|
return 0, io.ErrUnexpectedEOF
|
||||||
|
}
|
||||||
|
iNdEx++
|
||||||
|
if dAtA[iNdEx-1] < 0x80 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case 1:
|
||||||
|
iNdEx += 8
|
||||||
|
case 2:
|
||||||
|
var length int
|
||||||
|
for shift := uint(0); ; shift += 7 {
|
||||||
|
if shift >= 64 {
|
||||||
|
return 0, ErrIntOverflowHdr
|
||||||
|
}
|
||||||
|
if iNdEx >= l {
|
||||||
|
return 0, io.ErrUnexpectedEOF
|
||||||
|
}
|
||||||
|
b := dAtA[iNdEx]
|
||||||
|
iNdEx++
|
||||||
|
length |= (int(b) & 0x7F) << shift
|
||||||
|
if b < 0x80 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if length < 0 {
|
||||||
|
return 0, ErrInvalidLengthHdr
|
||||||
|
}
|
||||||
|
iNdEx += length
|
||||||
|
case 3:
|
||||||
|
depth++
|
||||||
|
case 4:
|
||||||
|
if depth == 0 {
|
||||||
|
return 0, ErrUnexpectedEndOfGroupHdr
|
||||||
|
}
|
||||||
|
depth--
|
||||||
|
case 5:
|
||||||
|
iNdEx += 4
|
||||||
|
default:
|
||||||
|
return 0, fmt.Errorf("proto: illegal wireType %d", wireType)
|
||||||
|
}
|
||||||
|
if iNdEx < 0 {
|
||||||
|
return 0, ErrInvalidLengthHdr
|
||||||
|
}
|
||||||
|
if depth == 0 {
|
||||||
|
return iNdEx, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0, io.ErrUnexpectedEOF
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
ErrInvalidLengthHdr = fmt.Errorf("proto: negative length found during unmarshaling")
|
||||||
|
ErrIntOverflowHdr = fmt.Errorf("proto: integer overflow")
|
||||||
|
ErrUnexpectedEndOfGroupHdr = fmt.Errorf("proto: unexpected end of group")
|
||||||
|
)
|
23
sign/hdr.proto
Normal file
23
sign/hdr.proto
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
syntax="proto3";
|
||||||
|
|
||||||
|
//import "gogoproto/gogo.proto"
|
||||||
|
|
||||||
|
package sign;
|
||||||
|
|
||||||
|
//option (gogoproto.marshaler_all) = true;
|
||||||
|
//option (gogoproto.sizer_all) = true;
|
||||||
|
//option (gogoproto.unmarshaler_all) = true;
|
||||||
|
//option (gogoproto.goproto_getters_all) = false;
|
||||||
|
|
||||||
|
message header {
|
||||||
|
uint32 chunk_size = 1;
|
||||||
|
bytes salt = 2;
|
||||||
|
repeated wrapped_key keys = 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
message wrapped_key {
|
||||||
|
bytes pk_hash = 1; // hash of Ed25519 PK
|
||||||
|
bytes pk = 2; // curve25519 PK
|
||||||
|
bytes nonce = 3; // AEAD nonce
|
||||||
|
bytes key = 4; // AEAD encrypted key
|
||||||
|
}
|
23
sign/sign.go
23
sign/sign.go
|
@ -77,6 +77,9 @@ type Signature struct {
|
||||||
const sk_algo = "scrypt-sha256"
|
const sk_algo = "scrypt-sha256"
|
||||||
const sig_algo = "sha512-ed25519"
|
const sig_algo = "sha512-ed25519"
|
||||||
|
|
||||||
|
// Length of Ed25519 Public Key Hash
|
||||||
|
const PKHashLength = 16
|
||||||
|
|
||||||
// Scrypt parameters
|
// Scrypt parameters
|
||||||
const _N = 1 << 17
|
const _N = 1 << 17
|
||||||
const _r = 16
|
const _r = 16
|
||||||
|
@ -132,7 +135,7 @@ type signature struct {
|
||||||
|
|
||||||
func pkhash(pk []byte) []byte {
|
func pkhash(pk []byte) []byte {
|
||||||
z := sha256.Sum256(pk)
|
z := sha256.Sum256(pk)
|
||||||
return z[:16]
|
return z[:PKHashLength]
|
||||||
}
|
}
|
||||||
|
|
||||||
// Generate a new Ed25519 keypair
|
// Generate a new Ed25519 keypair
|
||||||
|
@ -220,7 +223,6 @@ func MakePrivateKey(yml []byte, pw string) (*PrivateKey, error) {
|
||||||
return nil, fmt.Errorf("can't decode YAML:Verify: %s", err)
|
return nil, fmt.Errorf("can't decode YAML:Verify: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
sk := &PrivateKey{}
|
|
||||||
|
|
||||||
// We take short passwords and extend them
|
// We take short passwords and extend them
|
||||||
pwb := sha512.Sum512([]byte(pw))
|
pwb := sha512.Sum512([]byte(pw))
|
||||||
|
@ -240,11 +242,24 @@ func MakePrivateKey(yml []byte, pw string) (*PrivateKey, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Everything works. Now, decode the key
|
// Everything works. Now, decode the key
|
||||||
sk.Sk = make([]byte, len(esk.Esk))
|
skb := make([]byte, len(esk.Esk))
|
||||||
for i := 0; i < len(esk.Esk); i++ {
|
for i := 0; i < len(esk.Esk); i++ {
|
||||||
sk.Sk[i] = esk.Esk[i] ^ xork[i]
|
skb[i] = esk.Esk[i] ^ xork[i]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
edsk := Ed.PrivateKey(skb)
|
||||||
|
edpk := edsk.Public().(Ed.PublicKey)
|
||||||
|
|
||||||
|
pk := &PublicKey{
|
||||||
|
Pk: []byte(edpk),
|
||||||
|
hash: pkhash([]byte(edpk)),
|
||||||
|
}
|
||||||
|
sk := &PrivateKey{
|
||||||
|
Sk: skb,
|
||||||
|
pk: pk,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
return sk, nil
|
return sk, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -306,6 +306,8 @@ Commands:
|
||||||
generate, g Generate a new Ed25519 keypair
|
generate, g Generate a new Ed25519 keypair
|
||||||
sign, s Sign a file with a private key
|
sign, s Sign a file with a private key
|
||||||
verify, v Verify a signature against a file and a public key
|
verify, v Verify a signature against a file and a public key
|
||||||
|
encrypt, e Encrypt an input file to one or more recipients
|
||||||
|
decrypt, d Decrypt a file with a private key
|
||||||
`, Z, Z)
|
`, Z, Z)
|
||||||
|
|
||||||
os.Stdout.Write([]byte(x))
|
os.Stdout.Write([]byte(x))
|
||||||
|
|
1
version
Normal file
1
version
Normal file
|
@ -0,0 +1 @@
|
||||||
|
0.2.0
|
Loading…
Add table
Reference in a new issue