Compare commits
No commits in common. "master" and "v3.0.2" have entirely different histories.
25 changed files with 1403 additions and 1545 deletions
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -31,4 +31,4 @@ sigtool
|
||||||
*.pub
|
*.pub
|
||||||
*.key
|
*.key
|
||||||
*.sig
|
*.sig
|
||||||
releases/*
|
|
||||||
|
|
|
@ -1,2 +0,0 @@
|
||||||
[tools]
|
|
||||||
golang = "1.24"
|
|
|
@ -40,7 +40,7 @@ You need two things:
|
||||||
|
|
||||||
Next, build sigtool:
|
Next, build sigtool:
|
||||||
|
|
||||||
git clone https://git.rgst.io/homelab/sigtool/v3
|
git clone https://github.com/opencoff/sigtool
|
||||||
cd sigtool
|
cd sigtool
|
||||||
make
|
make
|
||||||
|
|
||||||
|
@ -101,10 +101,6 @@ 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
|
||||||
|
|
||||||
|
|
||||||
You can also pass a public key as a string (instead of a file):
|
|
||||||
|
|
||||||
sigtool verify iF84Dymq/bAEnUMK6DRIHWAQDRD8FwDDDfsgFfzdjWM= archive.sig archive.tar.gz
|
|
||||||
|
|
||||||
Note that signing and verifying can also work with OpenSSH ed25519
|
Note that signing and verifying can also work with OpenSSH ed25519
|
||||||
keys.
|
keys.
|
||||||
|
|
||||||
|
|
203
build
203
build
|
@ -4,7 +4,7 @@
|
||||||
#
|
#
|
||||||
# - it tacks on a version number for use by the individual tools
|
# - it tacks on a version number for use by the individual tools
|
||||||
# - it supports git and mercurial version#
|
# - it supports git and mercurial version#
|
||||||
#
|
#
|
||||||
# NB:
|
# NB:
|
||||||
# o the attempt at decoding dirty repo state for mercurial is
|
# o the attempt at decoding dirty repo state for mercurial is
|
||||||
# borked. It doesn't know about untracked files
|
# borked. It doesn't know about untracked files
|
||||||
|
@ -13,13 +13,12 @@
|
||||||
#
|
#
|
||||||
# License: GPLv2
|
# License: GPLv2
|
||||||
#
|
#
|
||||||
Progs="src:sigtool"
|
Progs=".:sigtool"
|
||||||
|
|
||||||
# Relative path to protobuf sources
|
# Relative path to protobuf sources
|
||||||
# e.g. src/foo/a.proto
|
# e.g. src/foo/a.proto
|
||||||
Protobufs="internal/pb/hdr.proto"
|
Protobufs="internal/pb/hdr.proto"
|
||||||
|
|
||||||
#set -x
|
|
||||||
|
|
||||||
# -- DO NOT CHANGE ANYTHING AFTER THIS --
|
# -- DO NOT CHANGE ANYTHING AFTER THIS --
|
||||||
|
|
||||||
|
@ -29,10 +28,8 @@ PWD=`pwd`
|
||||||
Static=0
|
Static=0
|
||||||
Dryrun=0
|
Dryrun=0
|
||||||
Prodver=""
|
Prodver=""
|
||||||
Repover=""
|
|
||||||
Verbose=0
|
Verbose=0
|
||||||
Go=`which go`
|
Go=`which go`
|
||||||
Bindir=$PWD/bin
|
|
||||||
|
|
||||||
die() {
|
die() {
|
||||||
echo "$Z: $@" 1>&2
|
echo "$Z: $@" 1>&2
|
||||||
|
@ -50,56 +47,18 @@ case $BASH_VERSION in
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
|
|
||||||
getvcs_version() {
|
|
||||||
local rev=
|
|
||||||
local prodv=
|
|
||||||
local git=`which git`
|
|
||||||
local hg=`which hg`
|
|
||||||
|
|
||||||
if [ -n "$git" ]; then
|
|
||||||
local xrev=$(git describe --always --dirty --long --abbrev=12) || exit 1
|
|
||||||
rev="git:$xrev"
|
|
||||||
prodv=$(git tag --list | sort -V | tail -1)
|
|
||||||
elif [ -n "$hg" ]; then
|
|
||||||
local xrev=$(hg id --id) || exit 1
|
|
||||||
local brev=${xrev%+}
|
|
||||||
if [ "$brev" != "$xrev" ]; then
|
|
||||||
rev="hg:${brev}-dirty"
|
|
||||||
else
|
|
||||||
rev="hg:${brev}"
|
|
||||||
fi
|
|
||||||
prodv=$(hg log -r "branch(stable) and tag()" -T "{tags}\n" | sort -V | tail -1)
|
|
||||||
else
|
|
||||||
warn "no git or hg found; can't get VCS info"
|
|
||||||
rev="UNKNOWN-VER"
|
|
||||||
fi
|
|
||||||
|
|
||||||
[ -n "$Prodver" ] && prodv=$Prodver
|
|
||||||
|
|
||||||
echo "$rev $prodv"
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
read -r Repover Prodver <<< $(getvcs_version)
|
|
||||||
|
|
||||||
|
|
||||||
usage() {
|
usage() {
|
||||||
declare -a progv=($Progs)
|
|
||||||
declare n=${#progv[@]}
|
|
||||||
declare pstr=
|
|
||||||
|
|
||||||
for ((i=0; i < n; i++)); do
|
|
||||||
local ent=${progv[$i]}
|
|
||||||
local dir=${ent%%:*}
|
|
||||||
local tool=${ent##*:}
|
|
||||||
pstr=$(printf "$pstr\n\t%s $Prodver $Repover (from ./%s)" $tool $dir)
|
|
||||||
done
|
|
||||||
|
|
||||||
cat <<EOF
|
cat <<EOF
|
||||||
$0 - A Go production build tool that adds git-repository information,
|
$0 - A Go production build tool that adds git-repository information,
|
||||||
product version, build-timestamp etc. It supports cross-compilation,
|
product version, build-timestamp etc. It supports cross-compilation,
|
||||||
static linking and generating protobuf output.
|
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.
|
Build output is in bin/\$OS-\$CPU for a given OS, CPU combination.
|
||||||
|
|
||||||
Usage: $0
|
Usage: $0
|
||||||
|
@ -108,14 +67,13 @@ Usage: $0
|
||||||
Where OS-ARCH denotes one of the valid OS, ARCH combinations supported by 'go'.
|
Where OS-ARCH denotes one of the valid OS, ARCH combinations supported by 'go'.
|
||||||
And, PROGS is one or more go programs.
|
And, PROGS is one or more go programs.
|
||||||
|
|
||||||
With no arguments, $0 builds: $pstr
|
With no arguments, $0 builds: $Progs (source in ./src/)
|
||||||
|
|
||||||
The repository's latest tag is used as the default version of the software being
|
The repository's latest tag is used as the default version of the software being
|
||||||
built. The current repository version is $Repover.
|
built.
|
||||||
|
|
||||||
Options:
|
Options:
|
||||||
-h, --help Show this help message and quit
|
-h, --help Show this help message and quit
|
||||||
-b D, --bindir=D Put the binaries in the directory 'D' [$Bindir]
|
|
||||||
-s, --static Build a statically linked binary [False]
|
-s, --static Build a statically linked binary [False]
|
||||||
-V N, --version=N Use 'N' as the product version string [$Prodver]
|
-V N, --version=N Use 'N' as the product version string [$Prodver]
|
||||||
-a X, --arch=X Cross compile for OS-CPU 'X' [$hostos-$hostcpu]
|
-a X, --arch=X Cross compile for OS-CPU 'X' [$hostos-$hostcpu]
|
||||||
|
@ -198,14 +156,6 @@ do
|
||||||
ac_prev=Arch
|
ac_prev=Arch
|
||||||
;;
|
;;
|
||||||
|
|
||||||
-b|--bindir)
|
|
||||||
ac_prev=Bindir
|
|
||||||
;;
|
|
||||||
|
|
||||||
--bindir=*)
|
|
||||||
Bindir=$ac_optarg
|
|
||||||
;;
|
|
||||||
|
|
||||||
--version=*)
|
--version=*)
|
||||||
Prodver=$ac_optarg
|
Prodver=$ac_optarg
|
||||||
;;
|
;;
|
||||||
|
@ -273,65 +223,30 @@ hosttool() {
|
||||||
local bindir=$2
|
local bindir=$2
|
||||||
local src=$3
|
local src=$3
|
||||||
|
|
||||||
p=$bindir/$tool
|
local p=$(type -P $tool)
|
||||||
if [ -x $p ]; then
|
if [ -n "$p" ]; then
|
||||||
|
echo $p
|
||||||
return 0
|
return 0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
local tmpdir=/tmp/$tool.$$
|
# from here - we want this dir to find all build artifacts
|
||||||
mkdir $tmpdir || die "can't make $tmpdir"
|
PATH=$PATH:$bindir
|
||||||
|
export PATH
|
||||||
|
|
||||||
# since go1.20 - install uses env vars to decide where to put
|
p=$bindir/$tool
|
||||||
# build artifacts. Why are all the google tooling so bloody dev
|
if [ -x $p ]; then
|
||||||
# hostile! WTF is wrong with command line args?!
|
echo $p
|
||||||
export GOBIN=$bindir
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
# build it and stash it in the hostdir
|
# build it and stash it in the hostdir
|
||||||
echo "Building tool $tool from $src .."
|
echo "Building tool $tool from $src .."
|
||||||
(
|
$e $Go get -d $src || exit 1
|
||||||
cd $tmpdir
|
$e $Go build -o $p $src || exit 1
|
||||||
$e $Go install $src@latest || die "can't install $tool"
|
echo $p
|
||||||
)
|
|
||||||
$e rm -rf $tmpdir
|
|
||||||
|
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
# protobuf gen
|
|
||||||
buildproto() {
|
|
||||||
local pbgo=protoc-gen-go
|
|
||||||
local vtgo=protoc-gen-go-vtproto
|
|
||||||
local vtgo_src=github.com/planetscale/vtprotobuf/cmd/protoc-gen-go-vtproto
|
|
||||||
local pc
|
|
||||||
local args="$*"
|
|
||||||
|
|
||||||
local pgen=$(type -p protoc)
|
|
||||||
local gogen=$(type -p $pbgo)
|
|
||||||
local vt=$Hostbindir/$vtgo
|
|
||||||
|
|
||||||
[ -z $pgen ] && die "install protoc tools"
|
|
||||||
[ -z $gogen ] && die "install protoc-gen-go"
|
|
||||||
|
|
||||||
# now install the vtproto generator
|
|
||||||
hosttool $vtgo $Hostbindir $vtgo_src
|
|
||||||
|
|
||||||
for f in $args; do
|
|
||||||
local dn=$(dirname $f)
|
|
||||||
local bn=$(basename $f .proto)
|
|
||||||
|
|
||||||
|
|
||||||
$e $pgen \
|
|
||||||
--go_out=. --plugin protoc-gen-go=$gogen \
|
|
||||||
--go-vtproto_out=. --plugin protoc-gen-go-vtproto="$vt" \
|
|
||||||
--go-vtproto_opt=features=marshal+unmarshal+size \
|
|
||||||
$f || die "can't generate protobuf output for $f .."
|
|
||||||
done
|
|
||||||
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
# the rest has to execute in the context of main shell (not funcs)
|
|
||||||
|
|
||||||
hostos=$($Go env GOHOSTOS) || exit 1
|
hostos=$($Go env GOHOSTOS) || exit 1
|
||||||
hostcpu=$($Go env GOHOSTARCH) || exit 1
|
hostcpu=$($Go env GOHOSTARCH) || exit 1
|
||||||
|
@ -387,25 +302,72 @@ fi
|
||||||
|
|
||||||
|
|
||||||
# This is where build outputs go
|
# This is where build outputs go
|
||||||
Outdir=$Bindir/$cross
|
Bindir=$PWD/bin/$cross
|
||||||
Hostbindir=$Bindir/$hostos-$hostcpu
|
Hostbindir=$PWD/bin/$hostos-$hostcpu
|
||||||
export PATH=$Hostbindir:$PATH
|
|
||||||
|
|
||||||
[ -d $Outdir ] || mkdir -p $Outdir
|
[ -d $Bindir ] || mkdir -p $Bindir
|
||||||
[ -d $Hostbindir ] || mkdir -p $Hostbindir
|
[ -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
|
||||||
|
if [ -z "$Prodver" ]; then
|
||||||
|
Prodver=$(hg log -r "branch(stable) and tag()" -T "{tags}\n" | tail -1)
|
||||||
|
fi
|
||||||
|
elif [ -d "./.git" ]; then
|
||||||
|
xrev=$(git describe --always --dirty --long --abbrev=12) || exit 1
|
||||||
|
rev="git:$xrev"
|
||||||
|
if [ -z "$Prodver" ]; then
|
||||||
|
Prodver=$(git tag --list | tail -1)
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
rev="UNKNOWN-VER"
|
||||||
|
echo "$0: Can't find version info" 1>&2
|
||||||
|
fi
|
||||||
|
|
||||||
|
|
||||||
# Do Protobufs if needed
|
# Do Protobufs if needed
|
||||||
if [ -n "$Protobufs" ]; then
|
if [ -n "$Protobufs" ]; then
|
||||||
set +e
|
set +e
|
||||||
buildproto $Protobufs
|
slick=$Hostbindir/protoc-gen-gogoslick
|
||||||
|
slicksrc=github.com/gogo/protobuf/protoc-gen-gogoslick
|
||||||
|
for pc in protoc protoc-c; do
|
||||||
|
pc=$(type -p $pc)
|
||||||
|
[ -n "$pc" ] && break
|
||||||
|
done
|
||||||
|
|
||||||
|
[ -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
|
||||||
|
|
||||||
|
export PATH=$PATH:$Hostbindir
|
||||||
|
|
||||||
|
for f in $Protobufs; do
|
||||||
|
dn=$(dirname $f)
|
||||||
|
bn=$(basename $f .proto)
|
||||||
|
of=$dn/${bn}.pb.go
|
||||||
|
if [ $f -nt $of ]; then
|
||||||
|
echo "Running $pc .."
|
||||||
|
$e $pc --gogoslick_out=. $f || exit 1
|
||||||
|
fi
|
||||||
|
done
|
||||||
set -e
|
set -e
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Get git/hg version info for the build
|
repover="main.RepoVersion=$rev"
|
||||||
repover="main.RepoVersion=$Repover"
|
|
||||||
prodver="main.ProductVersion=$Prodver"
|
prodver="main.ProductVersion=$Prodver"
|
||||||
ldflags="-ldflags \"-X $repover -X $prodver $ldflags -buildid=\""
|
date="main.Buildtime=`date -u '+%Y-%m-%dT%H:%M.%SZ'`"
|
||||||
|
ldflags="-ldflags \"-X $repover -X $prodver -X $date $ldflags\""
|
||||||
vflag=""
|
vflag=""
|
||||||
|
|
||||||
[ $Verbose -gt 0 ] && vflag="-v"
|
[ $Verbose -gt 0 ] && vflag="-v"
|
||||||
|
@ -434,11 +396,9 @@ case $Tool in
|
||||||
all="$@"
|
all="$@"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
[ -z "$all" ] && die "No programs specified. Try '$Z --help'"
|
echo "Building $Prodver ($rev), $cross $msg .."
|
||||||
|
|
||||||
echo "Building $Prodver ($Repover), $cross $msg .."
|
for p in $all; do
|
||||||
|
|
||||||
for p in $all; do
|
|
||||||
if echo $p | grep -q ':' ; then
|
if echo $p | grep -q ':' ; then
|
||||||
out=${p##*:}
|
out=${p##*:}
|
||||||
dir=${p%%:*}
|
dir=${p%%:*}
|
||||||
|
@ -446,15 +406,8 @@ case $Tool in
|
||||||
out=$p
|
out=$p
|
||||||
dir=$p
|
dir=$p
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Add .exe suffix to out if needed
|
|
||||||
if [ "$GOOS" = "windows" ]; then
|
|
||||||
base=${out%%.exe}
|
|
||||||
out="${base}.exe"
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo " $dir: $out .. "
|
echo " $dir: $out .. "
|
||||||
$e eval $Go build $vflag -trimpath -o $Outdir/$out $isuffix "$ldflags" ./$dir || exit 1
|
$e eval $Go build $vflag -o $Bindir/$out $isuffix "$ldflags" ./$dir || exit 1
|
||||||
done
|
done
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
|
|
|
@ -20,10 +20,9 @@ import (
|
||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"git.rgst.io/homelab/sigtool/v3/sign"
|
|
||||||
"github.com/opencoff/go-fio"
|
|
||||||
"github.com/opencoff/go-utils"
|
"github.com/opencoff/go-utils"
|
||||||
flag "github.com/opencoff/pflag"
|
flag "github.com/opencoff/pflag"
|
||||||
|
"github.com/opencoff/sigtool/sign"
|
||||||
)
|
)
|
||||||
|
|
||||||
// sigtool encrypt [-i|--identity my.key] to.pub [to.pub] [ssh.pub] inputfile|- [-o output]
|
// sigtool encrypt [-i|--identity my.key] to.pub [to.pub] [ssh.pub] inputfile|- [-o output]
|
||||||
|
@ -141,11 +140,7 @@ func encrypt(args []string) {
|
||||||
mode = ist.Mode()
|
mode = ist.Mode()
|
||||||
}
|
}
|
||||||
|
|
||||||
var opts uint32
|
sf, err := utils.NewSafeFile(outfile, force, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, mode)
|
||||||
if force {
|
|
||||||
opts |= fio.OPT_OVERWRITE
|
|
||||||
}
|
|
||||||
sf, err := fio.NewSafeFile(outfile, opts, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, mode)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
Die("%s", err)
|
Die("%s", err)
|
||||||
}
|
}
|
||||||
|
@ -307,11 +302,7 @@ func decrypt(args []string) {
|
||||||
mode = ist.Mode()
|
mode = ist.Mode()
|
||||||
}
|
}
|
||||||
|
|
||||||
var opts uint32
|
sf, err := utils.NewSafeFile(outfile, force, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, mode)
|
||||||
if force {
|
|
||||||
opts |= fio.OPT_OVERWRITE
|
|
||||||
}
|
|
||||||
sf, err := fio.NewSafeFile(outfile, opts, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, mode)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
Die("%s", err)
|
Die("%s", err)
|
||||||
}
|
}
|
26
go.mod
26
go.mod
|
@ -1,25 +1,17 @@
|
||||||
module git.rgst.io/homelab/sigtool/v3
|
module github.com/opencoff/sigtool
|
||||||
|
|
||||||
go 1.24.0
|
go 1.21
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/dchest/bcrypt_pbkdf v0.0.0-20150205184540-83f37f9c154a
|
github.com/dchest/bcrypt_pbkdf v0.0.0-20150205184540-83f37f9c154a
|
||||||
github.com/opencoff/go-fio v0.5.14
|
github.com/gogo/protobuf v1.3.2
|
||||||
github.com/opencoff/go-mmap v0.1.5
|
github.com/opencoff/go-utils v0.7.2
|
||||||
github.com/opencoff/go-utils v1.0.2
|
github.com/opencoff/pflag v1.0.6-sh1
|
||||||
github.com/opencoff/pflag v1.0.7
|
golang.org/x/crypto v0.15.0
|
||||||
github.com/planetscale/vtprotobuf v0.6.0
|
gopkg.in/yaml.v2 v2.4.0
|
||||||
golang.org/x/crypto v0.36.0
|
|
||||||
google.golang.org/protobuf v1.36.5
|
|
||||||
gopkg.in/yaml.v3 v3.0.1
|
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/pkg/xattr v0.4.10 // indirect
|
golang.org/x/sys v0.14.0 // indirect
|
||||||
github.com/puzpuzpuz/xsync/v3 v3.5.1 // indirect
|
golang.org/x/term v0.14.0 // indirect
|
||||||
golang.org/x/sys v0.31.0 // indirect
|
|
||||||
golang.org/x/term v0.30.0 // indirect
|
|
||||||
)
|
)
|
||||||
|
|
||||||
//replace github.com/opencoff/go-mmap => ../go-mmap
|
|
||||||
//replace github.com/opencoff/go-utils => ../go-utils
|
|
||||||
|
|
76
go.sum
76
go.sum
|
@ -1,39 +1,47 @@
|
||||||
github.com/dchest/bcrypt_pbkdf v0.0.0-20150205184540-83f37f9c154a h1:saTgr5tMLFnmy/yg3qDTft4rE5DY2uJ/cCxCe3q0XTU=
|
github.com/dchest/bcrypt_pbkdf v0.0.0-20150205184540-83f37f9c154a h1:saTgr5tMLFnmy/yg3qDTft4rE5DY2uJ/cCxCe3q0XTU=
|
||||||
github.com/dchest/bcrypt_pbkdf v0.0.0-20150205184540-83f37f9c154a/go.mod h1:Bw9BbhOJVNR+t0jCqx2GC6zv0TGBsShs56Y3gfSCvl0=
|
github.com/dchest/bcrypt_pbkdf v0.0.0-20150205184540-83f37f9c154a/go.mod h1:Bw9BbhOJVNR+t0jCqx2GC6zv0TGBsShs56Y3gfSCvl0=
|
||||||
github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
|
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
|
||||||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
|
||||||
github.com/opencoff/go-fio v0.5.14 h1:PGi4XLLO4RSuc3m5exY0G2vweov6w3UThhScehBfM8c=
|
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
|
||||||
github.com/opencoff/go-fio v0.5.14/go.mod h1:hoSySYpavRnfQUsxzUgadk31kYiNQhMDvA2MObsXKf8=
|
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||||
github.com/opencoff/go-mmap v0.1.5 h1:RKPtevC4mOW5bi9skBPPo4nFTIH4lVWAL20Tff+FjLg=
|
github.com/opencoff/go-utils v0.7.2 h1:FK250pZ9UH+zdp1DlGyRARq7nULHEIkTVbpITTwwVXk=
|
||||||
github.com/opencoff/go-mmap v0.1.5/go.mod h1:y/6Jk/tDUc00k3oSQpiJX++20Nw7xFSlc5kLkhGnRXw=
|
github.com/opencoff/go-utils v0.7.2/go.mod h1:8hMC3uc+N0wUMxpmW2yzM6FuhlCCxRST1Wj+cYntqFA=
|
||||||
github.com/opencoff/go-utils v1.0.2 h1:BANRL8ZxgHpuo8gQBAzT3M9Im3aNFhaWW28jhc86LNs=
|
github.com/opencoff/pflag v1.0.6-sh1 h1:6RO8GgnpH928yu6earGDD01FnFT//bDJ1hCovcVVqY4=
|
||||||
github.com/opencoff/go-utils v1.0.2/go.mod h1:eZkEVQVzNfuE8uGepyhscMsqcXq7liGbBHYYwgYaoy8=
|
github.com/opencoff/pflag v1.0.6-sh1/go.mod h1:2bXtpAD/5h/2LarkbsRwiUxqnvB1nZBzn9Xjad1P41A=
|
||||||
github.com/opencoff/pflag v1.0.7 h1:o5cQIuX75bDcdJ6AXl68gzpA72a3CJ2MPStaMnEuwi4=
|
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||||
github.com/opencoff/pflag v1.0.7/go.mod h1:2bXtpAD/5h/2LarkbsRwiUxqnvB1nZBzn9Xjad1P41A=
|
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||||
github.com/pkg/xattr v0.4.10 h1:Qe0mtiNFHQZ296vRgUjRCoPHPqH7VdTOrZx3g0T+pGA=
|
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||||
github.com/pkg/xattr v0.4.10/go.mod h1:di8WF84zAKk8jzR1UBTEWh9AUlIZZ7M/JNt8e9B6ktU=
|
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
github.com/planetscale/vtprotobuf v0.6.0 h1:nBeETjudeJ5ZgBHUz1fVHvbqUKnYOXNhsIEabROxmNA=
|
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||||
github.com/planetscale/vtprotobuf v0.6.0/go.mod h1:t/avpk3KcrXxUnYOhZhMXJlSEyie6gQbtLq5NM3loB8=
|
golang.org/x/crypto v0.15.0 h1:frVn1TEaCEaZcn3Tmd7Y2b5KKPaZ+I32Q2OA3kYp5TA=
|
||||||
github.com/puzpuzpuz/xsync/v3 v3.5.1 h1:GJYJZwO6IdxN/IKbneznS6yPkVC+c3zyY/j19c++5Fg=
|
golang.org/x/crypto v0.15.0/go.mod h1:4ChreQoLWfG3xLDer1WdlH5NdlQ3+mwnQq1YTKY+72g=
|
||||||
github.com/puzpuzpuz/xsync/v3 v3.5.1/go.mod h1:VjzYrABPabuM4KyBh1Ftq6u8nhwY5tBPKP9jpmh0nnA=
|
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||||
golang.org/x/crypto v0.35.0 h1:b15kiHdrGCHrP6LvwaQ3c03kgNhhiMgvlhxHQhmg2Xs=
|
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||||
golang.org/x/crypto v0.35.0/go.mod h1:dy7dXNW32cAb/6/PRuTNsix8T+vJAqvuIy5Bli/x0YQ=
|
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
golang.org/x/crypto v0.36.0 h1:AnAEvhDddvBdpY+uR+MyHmuZzzNqXSe/GvuDeob5L34=
|
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
golang.org/x/crypto v0.36.0/go.mod h1:Y4J0ReaxCR1IMaabaSMugxJES1EpwhBHhv2bDHklZvc=
|
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
golang.org/x/sys v0.0.0-20220408201424-a24fb2fb8a0f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||||
golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc=
|
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sys v0.31.0 h1:ioabZlmFYtWhL+TRYpcnNlLwhyxaM9kWTDEmfnprqik=
|
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
|
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/term v0.29.0 h1:L6pJp37ocefwRRtYPKSWOWzOtWSxVajvz2ldH/xi3iU=
|
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/term v0.29.0/go.mod h1:6bl4lRlvVuDgSf3179VpIxBF0o10JUpXWOnI7nErv7s=
|
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/term v0.30.0 h1:PQ39fJZ+mfadBm0y5WlL4vlM7Sx1Hgf13sMIY2+QS9Y=
|
golang.org/x/sys v0.14.0 h1:Vz7Qs629MkJkGyHxUlRHizWJRG2j8fbQKjELVSNhy7Q=
|
||||||
golang.org/x/term v0.30.0/go.mod h1:NYYFdzHoI5wRh/h5tDMdMqCqPJZEuNqVR5xJLd/n67g=
|
golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
|
golang.org/x/term v0.14.0 h1:LGK9IlZ8T9jvdy6cTdfKUCltatMFOehAQo9SRC46UQ8=
|
||||||
|
golang.org/x/term v0.14.0/go.mod h1:TySc+nGkYR6qt8km8wUhuFRTVSMIX3XPR58y2lC8vww=
|
||||||
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
|
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
|
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
|
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||||
|
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||||
|
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||||
|
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
|
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
google.golang.org/protobuf v1.36.5 h1:tPhr+woSbjfYvY6/GPufUoYizxw1cF/yFoxJ2fmpwlM=
|
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
google.golang.org/protobuf v1.36.5/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
|
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
||||||
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.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
||||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,8 +1,13 @@
|
||||||
syntax="proto3";
|
syntax="proto3";
|
||||||
|
|
||||||
|
//import "gogoproto/gogo.proto"
|
||||||
|
|
||||||
option go_package = "internal/pb";
|
package pb;
|
||||||
|
|
||||||
|
//option (gogoproto.marshaler_all) = true;
|
||||||
|
//option (gogoproto.sizer_all) = true;
|
||||||
|
//option (gogoproto.unmarshaler_all) = true;
|
||||||
|
//option (gogoproto.goproto_getters_all) = false;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Every encrypted file starts with a header describing the
|
* Every encrypted file starts with a header describing the
|
||||||
|
|
|
@ -1,512 +0,0 @@
|
||||||
// Code generated by protoc-gen-go-vtproto. DO NOT EDIT.
|
|
||||||
// protoc-gen-go-vtproto version: v0.6.0
|
|
||||||
// source: internal/pb/hdr.proto
|
|
||||||
|
|
||||||
package pb
|
|
||||||
|
|
||||||
import (
|
|
||||||
fmt "fmt"
|
|
||||||
protohelpers "github.com/planetscale/vtprotobuf/protohelpers"
|
|
||||||
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
|
||||||
io "io"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
// Verify that this generated code is sufficiently up-to-date.
|
|
||||||
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
|
|
||||||
// Verify that runtime/protoimpl is sufficiently up-to-date.
|
|
||||||
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
|
|
||||||
)
|
|
||||||
|
|
||||||
func (m *Header) MarshalVT() (dAtA []byte, err error) {
|
|
||||||
if m == nil {
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
size := m.SizeVT()
|
|
||||||
dAtA = make([]byte, size)
|
|
||||||
n, err := m.MarshalToSizedBufferVT(dAtA[:size])
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return dAtA[:n], nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *Header) MarshalToVT(dAtA []byte) (int, error) {
|
|
||||||
size := m.SizeVT()
|
|
||||||
return m.MarshalToSizedBufferVT(dAtA[:size])
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *Header) MarshalToSizedBufferVT(dAtA []byte) (int, error) {
|
|
||||||
if m == nil {
|
|
||||||
return 0, nil
|
|
||||||
}
|
|
||||||
i := len(dAtA)
|
|
||||||
_ = i
|
|
||||||
var l int
|
|
||||||
_ = l
|
|
||||||
if m.unknownFields != nil {
|
|
||||||
i -= len(m.unknownFields)
|
|
||||||
copy(dAtA[i:], m.unknownFields)
|
|
||||||
}
|
|
||||||
if len(m.Keys) > 0 {
|
|
||||||
for iNdEx := len(m.Keys) - 1; iNdEx >= 0; iNdEx-- {
|
|
||||||
size, err := m.Keys[iNdEx].MarshalToSizedBufferVT(dAtA[:i])
|
|
||||||
if err != nil {
|
|
||||||
return 0, err
|
|
||||||
}
|
|
||||||
i -= size
|
|
||||||
i = protohelpers.EncodeVarint(dAtA, i, uint64(size))
|
|
||||||
i--
|
|
||||||
dAtA[i] = 0x2a
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if len(m.Sender) > 0 {
|
|
||||||
i -= len(m.Sender)
|
|
||||||
copy(dAtA[i:], m.Sender)
|
|
||||||
i = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Sender)))
|
|
||||||
i--
|
|
||||||
dAtA[i] = 0x22
|
|
||||||
}
|
|
||||||
if len(m.Pk) > 0 {
|
|
||||||
i -= len(m.Pk)
|
|
||||||
copy(dAtA[i:], m.Pk)
|
|
||||||
i = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Pk)))
|
|
||||||
i--
|
|
||||||
dAtA[i] = 0x1a
|
|
||||||
}
|
|
||||||
if len(m.Salt) > 0 {
|
|
||||||
i -= len(m.Salt)
|
|
||||||
copy(dAtA[i:], m.Salt)
|
|
||||||
i = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Salt)))
|
|
||||||
i--
|
|
||||||
dAtA[i] = 0x12
|
|
||||||
}
|
|
||||||
if m.ChunkSize != 0 {
|
|
||||||
i = protohelpers.EncodeVarint(dAtA, i, uint64(m.ChunkSize))
|
|
||||||
i--
|
|
||||||
dAtA[i] = 0x8
|
|
||||||
}
|
|
||||||
return len(dAtA) - i, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *WrappedKey) MarshalVT() (dAtA []byte, err error) {
|
|
||||||
if m == nil {
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
size := m.SizeVT()
|
|
||||||
dAtA = make([]byte, size)
|
|
||||||
n, err := m.MarshalToSizedBufferVT(dAtA[:size])
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return dAtA[:n], nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *WrappedKey) MarshalToVT(dAtA []byte) (int, error) {
|
|
||||||
size := m.SizeVT()
|
|
||||||
return m.MarshalToSizedBufferVT(dAtA[:size])
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *WrappedKey) MarshalToSizedBufferVT(dAtA []byte) (int, error) {
|
|
||||||
if m == nil {
|
|
||||||
return 0, nil
|
|
||||||
}
|
|
||||||
i := len(dAtA)
|
|
||||||
_ = i
|
|
||||||
var l int
|
|
||||||
_ = l
|
|
||||||
if m.unknownFields != nil {
|
|
||||||
i -= len(m.unknownFields)
|
|
||||||
copy(dAtA[i:], m.unknownFields)
|
|
||||||
}
|
|
||||||
if len(m.Nonce) > 0 {
|
|
||||||
i -= len(m.Nonce)
|
|
||||||
copy(dAtA[i:], m.Nonce)
|
|
||||||
i = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Nonce)))
|
|
||||||
i--
|
|
||||||
dAtA[i] = 0x12
|
|
||||||
}
|
|
||||||
if len(m.DKey) > 0 {
|
|
||||||
i -= len(m.DKey)
|
|
||||||
copy(dAtA[i:], m.DKey)
|
|
||||||
i = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.DKey)))
|
|
||||||
i--
|
|
||||||
dAtA[i] = 0xa
|
|
||||||
}
|
|
||||||
return len(dAtA) - i, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *Header) SizeVT() (n int) {
|
|
||||||
if m == nil {
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
var l int
|
|
||||||
_ = l
|
|
||||||
if m.ChunkSize != 0 {
|
|
||||||
n += 1 + protohelpers.SizeOfVarint(uint64(m.ChunkSize))
|
|
||||||
}
|
|
||||||
l = len(m.Salt)
|
|
||||||
if l > 0 {
|
|
||||||
n += 1 + l + protohelpers.SizeOfVarint(uint64(l))
|
|
||||||
}
|
|
||||||
l = len(m.Pk)
|
|
||||||
if l > 0 {
|
|
||||||
n += 1 + l + protohelpers.SizeOfVarint(uint64(l))
|
|
||||||
}
|
|
||||||
l = len(m.Sender)
|
|
||||||
if l > 0 {
|
|
||||||
n += 1 + l + protohelpers.SizeOfVarint(uint64(l))
|
|
||||||
}
|
|
||||||
if len(m.Keys) > 0 {
|
|
||||||
for _, e := range m.Keys {
|
|
||||||
l = e.SizeVT()
|
|
||||||
n += 1 + l + protohelpers.SizeOfVarint(uint64(l))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
n += len(m.unknownFields)
|
|
||||||
return n
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *WrappedKey) SizeVT() (n int) {
|
|
||||||
if m == nil {
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
var l int
|
|
||||||
_ = l
|
|
||||||
l = len(m.DKey)
|
|
||||||
if l > 0 {
|
|
||||||
n += 1 + l + protohelpers.SizeOfVarint(uint64(l))
|
|
||||||
}
|
|
||||||
l = len(m.Nonce)
|
|
||||||
if l > 0 {
|
|
||||||
n += 1 + l + protohelpers.SizeOfVarint(uint64(l))
|
|
||||||
}
|
|
||||||
n += len(m.unknownFields)
|
|
||||||
return n
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *Header) UnmarshalVT(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 protohelpers.ErrIntOverflow
|
|
||||||
}
|
|
||||||
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 protohelpers.ErrIntOverflow
|
|
||||||
}
|
|
||||||
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 protohelpers.ErrIntOverflow
|
|
||||||
}
|
|
||||||
if iNdEx >= l {
|
|
||||||
return io.ErrUnexpectedEOF
|
|
||||||
}
|
|
||||||
b := dAtA[iNdEx]
|
|
||||||
iNdEx++
|
|
||||||
byteLen |= int(b&0x7F) << shift
|
|
||||||
if b < 0x80 {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if byteLen < 0 {
|
|
||||||
return protohelpers.ErrInvalidLength
|
|
||||||
}
|
|
||||||
postIndex := iNdEx + byteLen
|
|
||||||
if postIndex < 0 {
|
|
||||||
return protohelpers.ErrInvalidLength
|
|
||||||
}
|
|
||||||
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 Pk", wireType)
|
|
||||||
}
|
|
||||||
var byteLen int
|
|
||||||
for shift := uint(0); ; shift += 7 {
|
|
||||||
if shift >= 64 {
|
|
||||||
return protohelpers.ErrIntOverflow
|
|
||||||
}
|
|
||||||
if iNdEx >= l {
|
|
||||||
return io.ErrUnexpectedEOF
|
|
||||||
}
|
|
||||||
b := dAtA[iNdEx]
|
|
||||||
iNdEx++
|
|
||||||
byteLen |= int(b&0x7F) << shift
|
|
||||||
if b < 0x80 {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if byteLen < 0 {
|
|
||||||
return protohelpers.ErrInvalidLength
|
|
||||||
}
|
|
||||||
postIndex := iNdEx + byteLen
|
|
||||||
if postIndex < 0 {
|
|
||||||
return protohelpers.ErrInvalidLength
|
|
||||||
}
|
|
||||||
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 4:
|
|
||||||
if wireType != 2 {
|
|
||||||
return fmt.Errorf("proto: wrong wireType = %d for field Sender", wireType)
|
|
||||||
}
|
|
||||||
var byteLen int
|
|
||||||
for shift := uint(0); ; shift += 7 {
|
|
||||||
if shift >= 64 {
|
|
||||||
return protohelpers.ErrIntOverflow
|
|
||||||
}
|
|
||||||
if iNdEx >= l {
|
|
||||||
return io.ErrUnexpectedEOF
|
|
||||||
}
|
|
||||||
b := dAtA[iNdEx]
|
|
||||||
iNdEx++
|
|
||||||
byteLen |= int(b&0x7F) << shift
|
|
||||||
if b < 0x80 {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if byteLen < 0 {
|
|
||||||
return protohelpers.ErrInvalidLength
|
|
||||||
}
|
|
||||||
postIndex := iNdEx + byteLen
|
|
||||||
if postIndex < 0 {
|
|
||||||
return protohelpers.ErrInvalidLength
|
|
||||||
}
|
|
||||||
if postIndex > l {
|
|
||||||
return io.ErrUnexpectedEOF
|
|
||||||
}
|
|
||||||
m.Sender = append(m.Sender[:0], dAtA[iNdEx:postIndex]...)
|
|
||||||
if m.Sender == nil {
|
|
||||||
m.Sender = []byte{}
|
|
||||||
}
|
|
||||||
iNdEx = postIndex
|
|
||||||
case 5:
|
|
||||||
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 protohelpers.ErrIntOverflow
|
|
||||||
}
|
|
||||||
if iNdEx >= l {
|
|
||||||
return io.ErrUnexpectedEOF
|
|
||||||
}
|
|
||||||
b := dAtA[iNdEx]
|
|
||||||
iNdEx++
|
|
||||||
msglen |= int(b&0x7F) << shift
|
|
||||||
if b < 0x80 {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if msglen < 0 {
|
|
||||||
return protohelpers.ErrInvalidLength
|
|
||||||
}
|
|
||||||
postIndex := iNdEx + msglen
|
|
||||||
if postIndex < 0 {
|
|
||||||
return protohelpers.ErrInvalidLength
|
|
||||||
}
|
|
||||||
if postIndex > l {
|
|
||||||
return io.ErrUnexpectedEOF
|
|
||||||
}
|
|
||||||
m.Keys = append(m.Keys, &WrappedKey{})
|
|
||||||
if err := m.Keys[len(m.Keys)-1].UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
iNdEx = postIndex
|
|
||||||
default:
|
|
||||||
iNdEx = preIndex
|
|
||||||
skippy, err := protohelpers.Skip(dAtA[iNdEx:])
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if (skippy < 0) || (iNdEx+skippy) < 0 {
|
|
||||||
return protohelpers.ErrInvalidLength
|
|
||||||
}
|
|
||||||
if (iNdEx + skippy) > l {
|
|
||||||
return io.ErrUnexpectedEOF
|
|
||||||
}
|
|
||||||
m.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)
|
|
||||||
iNdEx += skippy
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if iNdEx > l {
|
|
||||||
return io.ErrUnexpectedEOF
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
func (m *WrappedKey) UnmarshalVT(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 protohelpers.ErrIntOverflow
|
|
||||||
}
|
|
||||||
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: WrappedKey: wiretype end group for non-group")
|
|
||||||
}
|
|
||||||
if fieldNum <= 0 {
|
|
||||||
return fmt.Errorf("proto: WrappedKey: illegal tag %d (wire type %d)", fieldNum, wire)
|
|
||||||
}
|
|
||||||
switch fieldNum {
|
|
||||||
case 1:
|
|
||||||
if wireType != 2 {
|
|
||||||
return fmt.Errorf("proto: wrong wireType = %d for field DKey", wireType)
|
|
||||||
}
|
|
||||||
var byteLen int
|
|
||||||
for shift := uint(0); ; shift += 7 {
|
|
||||||
if shift >= 64 {
|
|
||||||
return protohelpers.ErrIntOverflow
|
|
||||||
}
|
|
||||||
if iNdEx >= l {
|
|
||||||
return io.ErrUnexpectedEOF
|
|
||||||
}
|
|
||||||
b := dAtA[iNdEx]
|
|
||||||
iNdEx++
|
|
||||||
byteLen |= int(b&0x7F) << shift
|
|
||||||
if b < 0x80 {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if byteLen < 0 {
|
|
||||||
return protohelpers.ErrInvalidLength
|
|
||||||
}
|
|
||||||
postIndex := iNdEx + byteLen
|
|
||||||
if postIndex < 0 {
|
|
||||||
return protohelpers.ErrInvalidLength
|
|
||||||
}
|
|
||||||
if postIndex > l {
|
|
||||||
return io.ErrUnexpectedEOF
|
|
||||||
}
|
|
||||||
m.DKey = append(m.DKey[:0], dAtA[iNdEx:postIndex]...)
|
|
||||||
if m.DKey == nil {
|
|
||||||
m.DKey = []byte{}
|
|
||||||
}
|
|
||||||
iNdEx = postIndex
|
|
||||||
case 2:
|
|
||||||
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 protohelpers.ErrIntOverflow
|
|
||||||
}
|
|
||||||
if iNdEx >= l {
|
|
||||||
return io.ErrUnexpectedEOF
|
|
||||||
}
|
|
||||||
b := dAtA[iNdEx]
|
|
||||||
iNdEx++
|
|
||||||
byteLen |= int(b&0x7F) << shift
|
|
||||||
if b < 0x80 {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if byteLen < 0 {
|
|
||||||
return protohelpers.ErrInvalidLength
|
|
||||||
}
|
|
||||||
postIndex := iNdEx + byteLen
|
|
||||||
if postIndex < 0 {
|
|
||||||
return protohelpers.ErrInvalidLength
|
|
||||||
}
|
|
||||||
if postIndex > l {
|
|
||||||
return io.ErrUnexpectedEOF
|
|
||||||
}
|
|
||||||
m.Nonce = append(m.Nonce[:0], dAtA[iNdEx:postIndex]...)
|
|
||||||
if m.Nonce == nil {
|
|
||||||
m.Nonce = []byte{}
|
|
||||||
}
|
|
||||||
iNdEx = postIndex
|
|
||||||
default:
|
|
||||||
iNdEx = preIndex
|
|
||||||
skippy, err := protohelpers.Skip(dAtA[iNdEx:])
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if (skippy < 0) || (iNdEx+skippy) < 0 {
|
|
||||||
return protohelpers.ErrInvalidLength
|
|
||||||
}
|
|
||||||
if (iNdEx + skippy) > l {
|
|
||||||
return io.ErrUnexpectedEOF
|
|
||||||
}
|
|
||||||
m.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)
|
|
||||||
iNdEx += skippy
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if iNdEx > l {
|
|
||||||
return io.ErrUnexpectedEOF
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
|
@ -1,16 +0,0 @@
|
||||||
// helper routines to maintain backwards compat with gogo
|
|
||||||
|
|
||||||
package pb
|
|
||||||
|
|
||||||
|
|
||||||
func (m *Header) Size() int {
|
|
||||||
return m.SizeVT()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *Header) MarshalTo(buf []byte) (int, error) {
|
|
||||||
return m.MarshalToVT(buf)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *Header) Unmarshal(buf []byte) error {
|
|
||||||
return m.UnmarshalVT(buf)
|
|
||||||
}
|
|
54
mk-rel.sh
54
mk-rel.sh
|
@ -1,54 +0,0 @@
|
||||||
#! /usr/bin/env bash
|
|
||||||
|
|
||||||
Z=`basename $0`
|
|
||||||
die() {
|
|
||||||
echo "$Z: $@" 1>&2
|
|
||||||
exit 1
|
|
||||||
}
|
|
||||||
|
|
||||||
warn() {
|
|
||||||
echo "$Z: $@" 1>&2
|
|
||||||
}
|
|
||||||
|
|
||||||
case $BASH_VERSION in
|
|
||||||
4.*|5.*) ;;
|
|
||||||
|
|
||||||
*) die "I need bash 4.x to run!"
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
|
|
||||||
Rel=$PWD/releases
|
|
||||||
Bindir=$Rel/bin
|
|
||||||
mkdir -p $Bindir || die "can't make $Bindir"
|
|
||||||
|
|
||||||
pkgit() {
|
|
||||||
local os=$1
|
|
||||||
local cpu=$2
|
|
||||||
local rev=$3
|
|
||||||
local arch="$os-$cpu"
|
|
||||||
local tgz="$Rel/sigtool-${rev}_${arch}.tar.gz"
|
|
||||||
local bindir=$Bindir/$arch
|
|
||||||
local bin=sigtool
|
|
||||||
|
|
||||||
if [ "$os" = "windows" ]; then
|
|
||||||
bin=${bin}.exe
|
|
||||||
fi
|
|
||||||
|
|
||||||
./build -V $rev -b $Bindir -s -a $arch || die "can't build $arch"
|
|
||||||
(cd $bindir && tar cf - $bin) | gzip -9 > $tgz || die "can't tar $tgz"
|
|
||||||
}
|
|
||||||
|
|
||||||
xrev=$(git describe --always --dirty --abbrev=12) || exit 1
|
|
||||||
if echo $xrev | grep -q dirty; then
|
|
||||||
die "won't build releases; repo dirty!"
|
|
||||||
true
|
|
||||||
fi
|
|
||||||
|
|
||||||
os="linux windows openbsd darwin"
|
|
||||||
arch="amd64 arm64"
|
|
||||||
|
|
||||||
for xx in $os; do
|
|
||||||
for yy in $arch; do
|
|
||||||
pkgit $xx $yy $xrev
|
|
||||||
done
|
|
||||||
done
|
|
|
@ -1,3 +0,0 @@
|
||||||
{
|
|
||||||
"$schema": "https://docs.renovatebot.com/renovate-schema.json"
|
|
||||||
}
|
|
|
@ -1,10 +1,10 @@
|
||||||
[](https://godoc.org/git.rgst.io/homelab/sigtool/v3/sign)
|
[](https://godoc.org/github.com/opencoff/sigtool/sign)
|
||||||
|
|
||||||
# sigtool/sign - Ed25519 signature calculation and verification
|
# sigtool/sign - Ed25519 signature calculation and verification
|
||||||
|
|
||||||
This is a small library that makes it easier to create and serialize Ed25519 keys, and sign,
|
This is a small library that makes it easier to create and serialize Ed25519 keys, and sign,
|
||||||
verify files using those keys. The library uses mmap(2) to read and process very large files.
|
verify files using those keys. The library uses mmap(2) to read and process very large files.
|
||||||
|
|
||||||
The companion program [sigtool](https://git.rgst.io/homelab/sigtool/v3) uses this library.
|
The companion program [sigtool](https://github.com/opencoff/sigtool) uses this library.
|
||||||
## License
|
## License
|
||||||
GPL v2.0
|
GPL v2.0
|
||||||
|
|
|
@ -70,14 +70,13 @@ import (
|
||||||
"crypto/subtle"
|
"crypto/subtle"
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"golang.org/x/crypto/curve25519"
|
||||||
|
"golang.org/x/crypto/hkdf"
|
||||||
"hash"
|
"hash"
|
||||||
"io"
|
"io"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
"golang.org/x/crypto/curve25519"
|
"github.com/opencoff/sigtool/internal/pb"
|
||||||
"golang.org/x/crypto/hkdf"
|
|
||||||
|
|
||||||
"git.rgst.io/homelab/sigtool/v3/internal/pb"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Encryption chunk size = 4MB
|
// Encryption chunk size = 4MB
|
||||||
|
|
|
@ -1,67 +0,0 @@
|
||||||
// iomisc.go -- misc i/o functions
|
|
||||||
//
|
|
||||||
// (c) 2016 Sudhi Herle <sudhi@herle.net>
|
|
||||||
//
|
|
||||||
// Licensing Terms: GPLv2
|
|
||||||
//
|
|
||||||
// If you need a commercial license for this work, please contact
|
|
||||||
// the author.
|
|
||||||
//
|
|
||||||
// This software does not come with any express or implied
|
|
||||||
// warranty; it is provided "as is". No claim is made to its
|
|
||||||
// suitability for any purpose.
|
|
||||||
|
|
||||||
package sign
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/binary"
|
|
||||||
"fmt"
|
|
||||||
"github.com/opencoff/go-fio"
|
|
||||||
"github.com/opencoff/go-mmap"
|
|
||||||
"hash"
|
|
||||||
"os"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Simple function to reliably write data to a file.
|
|
||||||
// Does MORE than ioutil.WriteFile() - in that it doesn't trash the
|
|
||||||
// existing file with an incomplete write.
|
|
||||||
func writeFile(fn string, b []byte, ovwrite bool, mode uint32) error {
|
|
||||||
var opts uint32
|
|
||||||
if ovwrite {
|
|
||||||
opts |= fio.OPT_OVERWRITE
|
|
||||||
}
|
|
||||||
sf, err := fio.NewSafeFile(fn, opts, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, os.FileMode(mode))
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
defer sf.Abort()
|
|
||||||
if _, err = sf.Write(b); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return sf.Close()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Generate file checksum out of hash function h
|
|
||||||
func fileCksum(fn string, h hash.Hash) ([]byte, error) {
|
|
||||||
fd, err := os.Open(fn)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("can't open %s: %s", fn, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
defer fd.Close()
|
|
||||||
|
|
||||||
sz, err := mmap.Reader(fd, func(b []byte) error {
|
|
||||||
h.Write(b)
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
var b [8]byte
|
|
||||||
binary.BigEndian.PutUint64(b[:], uint64(sz))
|
|
||||||
h.Write(b[:])
|
|
||||||
|
|
||||||
return h.Sum(nil)[:], nil
|
|
||||||
}
|
|
82
sign/keys.go
82
sign/keys.go
|
@ -25,14 +25,18 @@ import (
|
||||||
"crypto/sha256"
|
"crypto/sha256"
|
||||||
"crypto/sha512"
|
"crypto/sha512"
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
|
"encoding/binary"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"hash"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"math/big"
|
"math/big"
|
||||||
|
"os"
|
||||||
|
|
||||||
Ed "crypto/ed25519"
|
Ed "crypto/ed25519"
|
||||||
|
|
||||||
"golang.org/x/crypto/scrypt"
|
"golang.org/x/crypto/scrypt"
|
||||||
"gopkg.in/yaml.v3"
|
"gopkg.in/yaml.v2"
|
||||||
|
|
||||||
|
"github.com/opencoff/go-utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Private Ed25519 key
|
// Private Ed25519 key
|
||||||
|
@ -180,14 +184,14 @@ func makePrivateKeyFromBytes(sk *PrivateKey, buf []byte) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
// Make a private key from 64-bytes of extended Ed25519 key
|
// Make a private key from 64-bytes of extended Ed25519 key
|
||||||
func PrivateKeyFromBytes(buf []byte) (*PrivateKey, error) {
|
func PrivateKeyFromBytes(buf []byte) (*PrivateKey, error) {
|
||||||
var sk PrivateKey
|
var sk PrivateKey
|
||||||
if err := makePrivateKeyFromBytes(&sk, buf); err != nil {
|
|
||||||
return nil, err
|
return makePrivateKeyFromBytes(&sk, buf)
|
||||||
}
|
|
||||||
return &sk, nil
|
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
// Given a secret key, return the corresponding Public Key
|
// Given a secret key, return the corresponding Public Key
|
||||||
func (sk *PrivateKey) PublicKey() *PublicKey {
|
func (sk *PrivateKey) PublicKey() *PublicKey {
|
||||||
|
@ -370,29 +374,6 @@ func MakePublicKey(yml []byte) (*PublicKey, error) {
|
||||||
return &pk, nil
|
return &pk, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make a public key from a string
|
|
||||||
func MakePublicKeyFromString(s string) (*PublicKey, error) {
|
|
||||||
// first try to decode it as a openssh key
|
|
||||||
if pk2, err := parseEncPubKey([]byte(s), "command-line-pk"); err == nil {
|
|
||||||
return pk2, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Now try to decode as an sigtool key
|
|
||||||
b64 := base64.StdEncoding.DecodeString
|
|
||||||
|
|
||||||
pkb, err := b64(s)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
var pk PublicKey
|
|
||||||
err = makePublicKeyFromBytes(&pk, pkb)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return &pk, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func makePublicKeyFromBytes(pk *PublicKey, b []byte) error {
|
func makePublicKeyFromBytes(pk *PublicKey, b []byte) error {
|
||||||
if len(b) != 32 {
|
if len(b) != 32 {
|
||||||
return fmt.Errorf("public key is malformed (len %d!)", len(b))
|
return fmt.Errorf("public key is malformed (len %d!)", len(b))
|
||||||
|
@ -405,14 +386,14 @@ func makePublicKeyFromBytes(pk *PublicKey, b []byte) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
// Make a public key from a byte string
|
// Make a public key from a byte string
|
||||||
func PublicKeyFromBytes(b []byte) (*PublicKey, error) {
|
func PublicKeyFromBytes(b []byte) (*PublicKey, error) {
|
||||||
var pk PublicKey
|
var pk PublicKey
|
||||||
if err := makePublicKeyFromBytes(&pk, b); err != nil {
|
|
||||||
return nil, err
|
makePublicKeyFromBytes(&pk, b)
|
||||||
}
|
|
||||||
return &pk, nil
|
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
// Serialize a PublicKey into file 'fn' with a human readable 'comment'.
|
// Serialize a PublicKey into file 'fn' with a human readable 'comment'.
|
||||||
// If 'ovwrite' is true, overwrite the file if it exists.
|
// If 'ovwrite' is true, overwrite the file if it exists.
|
||||||
|
@ -518,6 +499,41 @@ func (pk *PublicKey) UnmarshalBinary(yml []byte) error {
|
||||||
|
|
||||||
// -- Internal Utility Functions --
|
// -- Internal Utility Functions --
|
||||||
|
|
||||||
|
// Simple function to reliably write data to a file.
|
||||||
|
// Does MORE than ioutil.WriteFile() - in that it doesn't trash the
|
||||||
|
// existing file with an incomplete write.
|
||||||
|
func writeFile(fn string, b []byte, ovwrite bool, mode uint32) error {
|
||||||
|
sf, err := utils.NewSafeFile(fn, ovwrite, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, os.FileMode(mode))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer sf.Abort() // always cleanup on error
|
||||||
|
|
||||||
|
sf.Write(b)
|
||||||
|
return sf.Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generate file checksum out of hash function h
|
||||||
|
func fileCksum(fn string, h hash.Hash) ([]byte, error) {
|
||||||
|
fd, err := os.Open(fn)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("can't open %s: %s", fn, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
defer fd.Close()
|
||||||
|
|
||||||
|
sz, err := utils.MmapReader(fd, 0, 0, h)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var b [8]byte
|
||||||
|
binary.BigEndian.PutUint64(b[:], uint64(sz))
|
||||||
|
h.Write(b[:])
|
||||||
|
|
||||||
|
return h.Sum(nil)[:], nil
|
||||||
|
}
|
||||||
|
|
||||||
func clamp(k []byte) []byte {
|
func clamp(k []byte) []byte {
|
||||||
k[0] &= 248
|
k[0] &= 248
|
||||||
k[31] &= 127
|
k[31] &= 127
|
||||||
|
|
|
@ -27,8 +27,7 @@ import (
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
|
|
||||||
Ed "crypto/ed25519"
|
Ed "crypto/ed25519"
|
||||||
|
"gopkg.in/yaml.v2"
|
||||||
"gopkg.in/yaml.v3"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// An Ed25519 Signature
|
// An Ed25519 Signature
|
||||||
|
|
360
sigtool.go
Normal file
360
sigtool.go
Normal file
|
@ -0,0 +1,360 @@
|
||||||
|
// sigtool.go -- Tool to generate, manage Ed25519 keys and
|
||||||
|
// signatures.
|
||||||
|
//
|
||||||
|
// (c) 2016 Sudhi Herle <sudhi@herle.net>
|
||||||
|
//
|
||||||
|
// Licensing Terms: GPLv2
|
||||||
|
//
|
||||||
|
// If you need a commercial license for this work, please contact
|
||||||
|
// the author.
|
||||||
|
//
|
||||||
|
// This software does not come with any express or implied
|
||||||
|
// warranty; it is provided "as is". No claim is made to its
|
||||||
|
// suitability for any purpose.
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"os"
|
||||||
|
"path"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/opencoff/go-utils"
|
||||||
|
flag "github.com/opencoff/pflag"
|
||||||
|
"github.com/opencoff/sigtool/sign"
|
||||||
|
)
|
||||||
|
|
||||||
|
var Z string = path.Base(os.Args[0])
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
|
||||||
|
var ver, help, debug bool
|
||||||
|
|
||||||
|
mf := flag.NewFlagSet(Z, flag.ExitOnError)
|
||||||
|
mf.SetInterspersed(false)
|
||||||
|
mf.BoolVarP(&ver, "version", "v", false, "Show version info and exit")
|
||||||
|
mf.BoolVarP(&help, "help", "h", false, "Show help info exit")
|
||||||
|
mf.BoolVarP(&debug, "debug", "", false, "Enable debug mode")
|
||||||
|
mf.Parse(os.Args[1:])
|
||||||
|
|
||||||
|
if ver {
|
||||||
|
fmt.Printf("%s - %s [%s; %s]\n", Z, ProductVersion, RepoVersion, Buildtime)
|
||||||
|
os.Exit(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
if help {
|
||||||
|
usage(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
args := mf.Args()
|
||||||
|
if len(args) < 1 {
|
||||||
|
Die("Insufficient arguments. Try '%s -h'", Z)
|
||||||
|
}
|
||||||
|
|
||||||
|
cmds := map[string]func(args []string){
|
||||||
|
"generate": gen,
|
||||||
|
"sign": signify,
|
||||||
|
"verify": verify,
|
||||||
|
"encrypt": encrypt,
|
||||||
|
"decrypt": decrypt,
|
||||||
|
|
||||||
|
"help": func(_ []string) {
|
||||||
|
usage(0)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
words := make([]string, 0, len(cmds))
|
||||||
|
for k := range cmds {
|
||||||
|
words = append(words, k)
|
||||||
|
}
|
||||||
|
|
||||||
|
ab := utils.Abbrev(words)
|
||||||
|
canon, ok := ab[strings.ToLower(args[0])]
|
||||||
|
if !ok {
|
||||||
|
Die("Unknown command %s", args[0])
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd := cmds[canon]
|
||||||
|
if cmd == nil {
|
||||||
|
Die("can't map command %s", canon)
|
||||||
|
}
|
||||||
|
|
||||||
|
if debug {
|
||||||
|
sign.Debug(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd(args[1:])
|
||||||
|
|
||||||
|
// always call Exit so that at-exit handlers are called.
|
||||||
|
Exit(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Run the generate command
|
||||||
|
func gen(args []string) {
|
||||||
|
|
||||||
|
var nopw, help, force bool
|
||||||
|
var comment string
|
||||||
|
var envpw string
|
||||||
|
|
||||||
|
fs := flag.NewFlagSet("generate", flag.ExitOnError)
|
||||||
|
fs.BoolVarP(&help, "help", "h", false, "Show this help and exit")
|
||||||
|
fs.BoolVarP(&nopw, "no-password", "", false, "Don't ask for a password for the private key")
|
||||||
|
fs.StringVarP(&comment, "comment", "c", "", "Use `C` as the text comment for the keys")
|
||||||
|
fs.StringVarP(&envpw, "env-password", "E", "", "Use passphrase from environment variable `E`")
|
||||||
|
fs.BoolVarP(&force, "overwrite", "", false, "Overwrite the output file if it exists")
|
||||||
|
|
||||||
|
fs.Parse(args)
|
||||||
|
|
||||||
|
if help {
|
||||||
|
fs.SetOutput(os.Stdout)
|
||||||
|
fmt.Printf(`%s generate|gen|g [options] file-prefix
|
||||||
|
|
||||||
|
Generate a new Ed25519 public+private key pair and write public key to
|
||||||
|
FILE-PREFIX.pub and private key to FILE-PREFIX.key.
|
||||||
|
|
||||||
|
Options:
|
||||||
|
`, Z)
|
||||||
|
fs.PrintDefaults()
|
||||||
|
os.Exit(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
args = fs.Args()
|
||||||
|
if len(args) < 1 {
|
||||||
|
Die("Insufficient arguments to 'generate'. Try '%s generate -h' ..", Z)
|
||||||
|
}
|
||||||
|
|
||||||
|
bn := args[0]
|
||||||
|
|
||||||
|
pkn := fmt.Sprintf("%s.pub", path.Clean(bn))
|
||||||
|
skn := fmt.Sprintf("%s.key", path.Clean(bn))
|
||||||
|
|
||||||
|
if !force {
|
||||||
|
if exists(pkn) || exists(skn) {
|
||||||
|
Die("Public/Private key files (%s, %s) exist. won't overwrite!", skn, pkn)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var err error
|
||||||
|
var pw []byte
|
||||||
|
|
||||||
|
if !nopw {
|
||||||
|
var pws string
|
||||||
|
if len(envpw) > 0 {
|
||||||
|
pws = os.Getenv(envpw)
|
||||||
|
} else {
|
||||||
|
pws, err = utils.Askpass("Enter passphrase for private key", true)
|
||||||
|
if err != nil {
|
||||||
|
Die("%s", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pw = []byte(pws)
|
||||||
|
}
|
||||||
|
|
||||||
|
sk, err := sign.NewPrivateKey()
|
||||||
|
if err != nil {
|
||||||
|
Die("%s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = sk.Serialize(skn, comment, force, pw); err != nil {
|
||||||
|
Die("%s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
pk := sk.PublicKey()
|
||||||
|
if err = pk.Serialize(pkn, comment, force); err != nil {
|
||||||
|
Die("%s", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Run the 'sign' command.
|
||||||
|
func signify(args []string) {
|
||||||
|
var nopw, help, force bool
|
||||||
|
var output string
|
||||||
|
var envpw string
|
||||||
|
|
||||||
|
fs := flag.NewFlagSet("sign", flag.ExitOnError)
|
||||||
|
fs.BoolVarP(&help, "help", "h", false, "Show this help and exit")
|
||||||
|
fs.BoolVarP(&nopw, "no-password", "", false, "Don't ask for a password for the private key")
|
||||||
|
fs.StringVarP(&envpw, "env-password", "E", "", "Use passphrase from environment variable `E`")
|
||||||
|
fs.StringVarP(&output, "output", "o", "", "Write signature to file `F`")
|
||||||
|
fs.BoolVarP(&force, "overwrite", "", false, "Overwrite previous signature file if it exists")
|
||||||
|
|
||||||
|
fs.Parse(args)
|
||||||
|
|
||||||
|
if help {
|
||||||
|
fs.SetOutput(os.Stdout)
|
||||||
|
fmt.Printf(`%s sign|s [options] privkey file
|
||||||
|
|
||||||
|
Sign FILE with a Ed25519 private key PRIVKEY and write signature to FILE.sig
|
||||||
|
|
||||||
|
Options:
|
||||||
|
`, Z)
|
||||||
|
fs.PrintDefaults()
|
||||||
|
os.Exit(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
args = fs.Args()
|
||||||
|
if len(args) < 2 {
|
||||||
|
Die("Insufficient arguments to 'sign'. Try '%s sign -h' ..", Z)
|
||||||
|
}
|
||||||
|
|
||||||
|
kn := args[0]
|
||||||
|
fn := args[1]
|
||||||
|
outf := fmt.Sprintf("%s.sig", fn)
|
||||||
|
|
||||||
|
var err error
|
||||||
|
|
||||||
|
if len(output) > 0 {
|
||||||
|
outf = output
|
||||||
|
}
|
||||||
|
|
||||||
|
var fd io.WriteCloser = os.Stdout
|
||||||
|
|
||||||
|
if outf != "-" {
|
||||||
|
sf, err := utils.NewSafeFile(outf, force, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0644)
|
||||||
|
if err != nil {
|
||||||
|
Die("can't create sig file: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// we unlink and remove temp on any error
|
||||||
|
AtExit(sf.Abort)
|
||||||
|
defer sf.Abort()
|
||||||
|
fd = sf
|
||||||
|
}
|
||||||
|
|
||||||
|
sk, err := sign.ReadPrivateKey(kn, func() ([]byte, error) {
|
||||||
|
if nopw {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var pws string
|
||||||
|
if len(envpw) > 0 {
|
||||||
|
pws = os.Getenv(envpw)
|
||||||
|
} else {
|
||||||
|
pws, err = utils.Askpass("Enter passphrase for private key", false)
|
||||||
|
if err != nil {
|
||||||
|
Die("%s", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return []byte(pws), nil
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
Die("%s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
sig, err := sk.SignFile(fn)
|
||||||
|
if err != nil {
|
||||||
|
Die("%s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
sigbytes, err := sig.MarshalBinary(fmt.Sprintf("input=%s", fn))
|
||||||
|
fd.Write(sigbytes)
|
||||||
|
fd.Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify signature on a given file
|
||||||
|
func verify(args []string) {
|
||||||
|
var help, quiet bool
|
||||||
|
|
||||||
|
fs := flag.NewFlagSet("verify", flag.ExitOnError)
|
||||||
|
fs.BoolVarP(&help, "help", "h", false, "Show this help and exit")
|
||||||
|
fs.BoolVarP(&quiet, "quiet", "q", false, "Don't show any output; exit with status code only")
|
||||||
|
|
||||||
|
fs.Parse(args)
|
||||||
|
|
||||||
|
if help {
|
||||||
|
fs.SetOutput(os.Stdout)
|
||||||
|
fmt.Printf(`%s verify|v [options] pubkey sig file
|
||||||
|
|
||||||
|
Verify an Ed25519 signature in SIG of FILE using a public key PUBKEY.
|
||||||
|
|
||||||
|
Options:
|
||||||
|
`, Z)
|
||||||
|
fs.PrintDefaults()
|
||||||
|
os.Exit(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
args = fs.Args()
|
||||||
|
if len(args) < 3 {
|
||||||
|
Die("Insufficient arguments to 'verify'. Try '%s verify -h' ..", Z)
|
||||||
|
}
|
||||||
|
|
||||||
|
pn := args[0]
|
||||||
|
sn := args[1]
|
||||||
|
fn := args[2]
|
||||||
|
|
||||||
|
sig, err := sign.ReadSignature(sn)
|
||||||
|
if err != nil {
|
||||||
|
Die("Can't read signature '%s': %s", sn, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
pk, err := sign.ReadPublicKey(pn)
|
||||||
|
if err != nil {
|
||||||
|
Die("%s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !sig.IsPKMatch(pk) {
|
||||||
|
Die("Wrong public key '%s' for verifying '%s'", pn, sn)
|
||||||
|
}
|
||||||
|
|
||||||
|
ok, err := pk.VerifyFile(fn, sig)
|
||||||
|
if err != nil {
|
||||||
|
Die("%s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
exit := 0
|
||||||
|
if !ok {
|
||||||
|
exit = 1
|
||||||
|
}
|
||||||
|
|
||||||
|
if !quiet {
|
||||||
|
if ok {
|
||||||
|
fmt.Printf("%s: Signature %s verified\n", fn, sn)
|
||||||
|
} else {
|
||||||
|
fmt.Printf("%s: Signature %s verification failure\n", fn, sn)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
os.Exit(exit)
|
||||||
|
}
|
||||||
|
|
||||||
|
func usage(c int) {
|
||||||
|
x := fmt.Sprintf(`%s is a tool to generate, sign and verify files with Ed25519 signatures.
|
||||||
|
|
||||||
|
Usage: %s [global-options] command [options] arg [args..]
|
||||||
|
|
||||||
|
Global options:
|
||||||
|
-h, --help Show help and exit
|
||||||
|
-v, --version Show version info and exit
|
||||||
|
--debug Enable debug (DANGEROUS)
|
||||||
|
|
||||||
|
Commands:
|
||||||
|
generate, g Generate a new Ed25519 keypair
|
||||||
|
sign, s Sign a file with a private 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)
|
||||||
|
|
||||||
|
os.Stdout.Write([]byte(x))
|
||||||
|
os.Exit(c)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return true if $bn.key or $bn.pub exist; false otherwise
|
||||||
|
func exists(nm string) bool {
|
||||||
|
if _, err := os.Stat(nm); err == nil {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// This will be filled in by "build"
|
||||||
|
var RepoVersion string = "UNDEFINED"
|
||||||
|
var Buildtime string = "UNDEFINED"
|
||||||
|
var ProductVersion string = "UNDEFINED"
|
||||||
|
|
||||||
|
// vim: ft=go:sw=8:ts=8:noexpandtab:tw=98:
|
100
src/gen.go
100
src/gen.go
|
@ -1,100 +0,0 @@
|
||||||
// gen.go -- generate keys
|
|
||||||
//
|
|
||||||
// (c) 2016 Sudhi Herle <sudhi@herle.net>
|
|
||||||
//
|
|
||||||
// Licensing Terms: GPLv2
|
|
||||||
//
|
|
||||||
// If you need a commercial license for this work, please contact
|
|
||||||
// the author.
|
|
||||||
//
|
|
||||||
// This software does not come with any express or implied
|
|
||||||
// warranty; it is provided "as is". No claim is made to its
|
|
||||||
// suitability for any purpose.
|
|
||||||
|
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"os"
|
|
||||||
"path"
|
|
||||||
|
|
||||||
"git.rgst.io/homelab/sigtool/v3/sign"
|
|
||||||
"github.com/opencoff/go-utils"
|
|
||||||
flag "github.com/opencoff/pflag"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Run the generate command
|
|
||||||
func gen(args []string) {
|
|
||||||
var nopw, help, force bool
|
|
||||||
var comment string
|
|
||||||
var envpw string
|
|
||||||
|
|
||||||
fs := flag.NewFlagSet("generate", flag.ExitOnError)
|
|
||||||
fs.BoolVarP(&help, "help", "h", false, "Show this help and exit")
|
|
||||||
fs.BoolVarP(&nopw, "no-password", "", false, "Don't ask for a password for the private key")
|
|
||||||
fs.StringVarP(&comment, "comment", "c", "", "Use `C` as the text comment for the keys")
|
|
||||||
fs.StringVarP(&envpw, "env-password", "E", "", "Use passphrase from environment variable `E`")
|
|
||||||
fs.BoolVarP(&force, "overwrite", "", false, "Overwrite the output file if it exists")
|
|
||||||
|
|
||||||
fs.Parse(args)
|
|
||||||
|
|
||||||
if help {
|
|
||||||
fs.SetOutput(os.Stdout)
|
|
||||||
fmt.Printf(`%s generate|gen|g [options] file-prefix
|
|
||||||
|
|
||||||
Generate a new Ed25519 public+private key pair and write public key to
|
|
||||||
FILE-PREFIX.pub and private key to FILE-PREFIX.key.
|
|
||||||
|
|
||||||
Options:
|
|
||||||
`, Z)
|
|
||||||
fs.PrintDefaults()
|
|
||||||
os.Exit(0)
|
|
||||||
}
|
|
||||||
|
|
||||||
args = fs.Args()
|
|
||||||
if len(args) < 1 {
|
|
||||||
Die("Insufficient arguments to 'generate'. Try '%s generate -h' ..", Z)
|
|
||||||
}
|
|
||||||
|
|
||||||
bn := args[0]
|
|
||||||
|
|
||||||
pkn := fmt.Sprintf("%s.pub", path.Clean(bn))
|
|
||||||
skn := fmt.Sprintf("%s.key", path.Clean(bn))
|
|
||||||
|
|
||||||
if !force {
|
|
||||||
if exists(pkn) || exists(skn) {
|
|
||||||
Die("Public/Private key files (%s, %s) exist. won't overwrite!", skn, pkn)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var err error
|
|
||||||
var pw []byte
|
|
||||||
|
|
||||||
if !nopw {
|
|
||||||
var pws string
|
|
||||||
if len(envpw) > 0 {
|
|
||||||
pws = os.Getenv(envpw)
|
|
||||||
} else {
|
|
||||||
pws, err = utils.Askpass("Enter passphrase for private key", true)
|
|
||||||
if err != nil {
|
|
||||||
Die("%s", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pw = []byte(pws)
|
|
||||||
}
|
|
||||||
|
|
||||||
sk, err := sign.NewPrivateKey()
|
|
||||||
if err != nil {
|
|
||||||
Die("%s", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err = sk.Serialize(skn, comment, force, pw); err != nil {
|
|
||||||
Die("%s", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
pk := sk.PublicKey()
|
|
||||||
if err = pk.Serialize(pkn, comment, force); err != nil {
|
|
||||||
Die("%s", err)
|
|
||||||
}
|
|
||||||
}
|
|
116
src/sign.go
116
src/sign.go
|
@ -1,116 +0,0 @@
|
||||||
// sign.go -- 'sign' command implementation
|
|
||||||
//
|
|
||||||
// (c) 2016 Sudhi Herle <sudhi@herle.net>
|
|
||||||
//
|
|
||||||
// Licensing Terms: GPLv2
|
|
||||||
//
|
|
||||||
// If you need a commercial license for this work, please contact
|
|
||||||
// the author.
|
|
||||||
//
|
|
||||||
// This software does not come with any express or implied
|
|
||||||
// warranty; it is provided "as is". No claim is made to its
|
|
||||||
// suitability for any purpose.
|
|
||||||
|
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"io"
|
|
||||||
"os"
|
|
||||||
|
|
||||||
"git.rgst.io/homelab/sigtool/v3/sign"
|
|
||||||
"github.com/opencoff/go-fio"
|
|
||||||
"github.com/opencoff/go-utils"
|
|
||||||
flag "github.com/opencoff/pflag"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Run the 'sign' command.
|
|
||||||
func signify(args []string) {
|
|
||||||
var nopw, help, force bool
|
|
||||||
var output string
|
|
||||||
var envpw string
|
|
||||||
|
|
||||||
fs := flag.NewFlagSet("sign", flag.ExitOnError)
|
|
||||||
fs.BoolVarP(&help, "help", "h", false, "Show this help and exit")
|
|
||||||
fs.BoolVarP(&nopw, "no-password", "", false, "Don't ask for a password for the private key")
|
|
||||||
fs.StringVarP(&envpw, "env-password", "E", "", "Use passphrase from environment variable `E`")
|
|
||||||
fs.StringVarP(&output, "output", "o", "", "Write signature to file `F`")
|
|
||||||
fs.BoolVarP(&force, "overwrite", "", false, "Overwrite previous signature file if it exists")
|
|
||||||
|
|
||||||
fs.Parse(args)
|
|
||||||
|
|
||||||
if help {
|
|
||||||
fs.SetOutput(os.Stdout)
|
|
||||||
fmt.Printf(`%s sign|s [options] privkey file
|
|
||||||
|
|
||||||
Sign FILE with a Ed25519 private key PRIVKEY and write signature to FILE.sig
|
|
||||||
|
|
||||||
Options:
|
|
||||||
`, Z)
|
|
||||||
fs.PrintDefaults()
|
|
||||||
os.Exit(0)
|
|
||||||
}
|
|
||||||
|
|
||||||
args = fs.Args()
|
|
||||||
if len(args) < 2 {
|
|
||||||
Die("Insufficient arguments to 'sign'. Try '%s sign -h' ..", Z)
|
|
||||||
}
|
|
||||||
|
|
||||||
kn := args[0]
|
|
||||||
fn := args[1]
|
|
||||||
outf := fmt.Sprintf("%s.sig", fn)
|
|
||||||
|
|
||||||
var err error
|
|
||||||
|
|
||||||
if len(output) > 0 {
|
|
||||||
outf = output
|
|
||||||
}
|
|
||||||
|
|
||||||
var fd io.WriteCloser = os.Stdout
|
|
||||||
|
|
||||||
if outf != "-" {
|
|
||||||
var opts uint32
|
|
||||||
if force {
|
|
||||||
opts |= fio.OPT_OVERWRITE
|
|
||||||
}
|
|
||||||
sf, err := fio.NewSafeFile(outf, opts, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0644)
|
|
||||||
if err != nil {
|
|
||||||
Die("can't create sig file: %s", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// we unlink and remove temp on any error
|
|
||||||
AtExit(sf.Abort)
|
|
||||||
defer sf.Abort()
|
|
||||||
fd = sf
|
|
||||||
}
|
|
||||||
|
|
||||||
sk, err := sign.ReadPrivateKey(kn, func() ([]byte, error) {
|
|
||||||
if nopw {
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
var pws string
|
|
||||||
if len(envpw) > 0 {
|
|
||||||
pws = os.Getenv(envpw)
|
|
||||||
} else {
|
|
||||||
pws, err = utils.Askpass("Enter passphrase for private key", false)
|
|
||||||
if err != nil {
|
|
||||||
Die("%s", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return []byte(pws), nil
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
Die("%s", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
sig, err := sk.SignFile(fn)
|
|
||||||
if err != nil {
|
|
||||||
Die("%s", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
sigbytes, err := sig.MarshalBinary(fmt.Sprintf("input=%s", fn))
|
|
||||||
fd.Write(sigbytes)
|
|
||||||
fd.Close()
|
|
||||||
}
|
|
129
src/sigtool.go
129
src/sigtool.go
|
@ -1,129 +0,0 @@
|
||||||
// sigtool.go -- Tool to generate, manage Ed25519 keys and
|
|
||||||
// signatures.
|
|
||||||
//
|
|
||||||
// (c) 2016 Sudhi Herle <sudhi@herle.net>
|
|
||||||
//
|
|
||||||
// Licensing Terms: GPLv2
|
|
||||||
//
|
|
||||||
// If you need a commercial license for this work, please contact
|
|
||||||
// the author.
|
|
||||||
//
|
|
||||||
// This software does not come with any express or implied
|
|
||||||
// warranty; it is provided "as is". No claim is made to its
|
|
||||||
// suitability for any purpose.
|
|
||||||
|
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"os"
|
|
||||||
"path"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"git.rgst.io/homelab/sigtool/v3/sign"
|
|
||||||
"github.com/opencoff/go-utils"
|
|
||||||
flag "github.com/opencoff/pflag"
|
|
||||||
)
|
|
||||||
|
|
||||||
var Z string = path.Base(os.Args[0])
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
var ver, help, debug bool
|
|
||||||
|
|
||||||
mf := flag.NewFlagSet(Z, flag.ExitOnError)
|
|
||||||
mf.SetInterspersed(false)
|
|
||||||
mf.BoolVarP(&ver, "version", "v", false, "Show version info and exit")
|
|
||||||
mf.BoolVarP(&help, "help", "h", false, "Show help info exit")
|
|
||||||
mf.BoolVarP(&debug, "debug", "", false, "Enable debug mode")
|
|
||||||
mf.Parse(os.Args[1:])
|
|
||||||
|
|
||||||
if ver {
|
|
||||||
fmt.Printf("%s - %s [%s]\n", Z, ProductVersion, RepoVersion)
|
|
||||||
os.Exit(0)
|
|
||||||
}
|
|
||||||
|
|
||||||
if help {
|
|
||||||
usage(0)
|
|
||||||
}
|
|
||||||
|
|
||||||
args := mf.Args()
|
|
||||||
if len(args) < 1 {
|
|
||||||
Die("Insufficient arguments. Try '%s -h'", Z)
|
|
||||||
}
|
|
||||||
|
|
||||||
cmds := map[string]func(args []string){
|
|
||||||
"generate": gen,
|
|
||||||
"sign": signify,
|
|
||||||
"verify": verify,
|
|
||||||
"encrypt": encrypt,
|
|
||||||
"decrypt": decrypt,
|
|
||||||
|
|
||||||
"help": func(_ []string) {
|
|
||||||
usage(0)
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
words := make([]string, 0, len(cmds))
|
|
||||||
for k := range cmds {
|
|
||||||
words = append(words, k)
|
|
||||||
}
|
|
||||||
|
|
||||||
ab := utils.Abbrev(words)
|
|
||||||
canon, ok := ab[strings.ToLower(args[0])]
|
|
||||||
if !ok {
|
|
||||||
Die("Unknown command %s", args[0])
|
|
||||||
}
|
|
||||||
|
|
||||||
cmd := cmds[canon]
|
|
||||||
if cmd == nil {
|
|
||||||
Die("can't map command %s", canon)
|
|
||||||
}
|
|
||||||
|
|
||||||
if debug {
|
|
||||||
sign.Debug(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
cmd(args[1:])
|
|
||||||
|
|
||||||
// always call Exit so that at-exit handlers are called.
|
|
||||||
Exit(0)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Verify signature on a given file
|
|
||||||
|
|
||||||
func usage(c int) {
|
|
||||||
x := fmt.Sprintf(`%s is a tool to generate, sign and verify files with Ed25519 signatures.
|
|
||||||
|
|
||||||
Usage: %s [global-options] command [options] arg [args..]
|
|
||||||
|
|
||||||
Global options:
|
|
||||||
-h, --help Show help and exit
|
|
||||||
-v, --version Show version info and exit
|
|
||||||
--debug Enable debug (DANGEROUS)
|
|
||||||
|
|
||||||
Commands:
|
|
||||||
generate, g Generate a new Ed25519 keypair
|
|
||||||
sign, s Sign a file with a private 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)
|
|
||||||
|
|
||||||
os.Stdout.Write([]byte(x))
|
|
||||||
os.Exit(c)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Return true if $bn.key or $bn.pub exist; false otherwise
|
|
||||||
func exists(nm string) bool {
|
|
||||||
if _, err := os.Stat(nm); err == nil {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
// This will be filled in by "build"
|
|
||||||
var RepoVersion string = "UNDEFINED"
|
|
||||||
var ProductVersion string = "UNDEFINED"
|
|
||||||
|
|
||||||
// vim: ft=go:sw=8:ts=8:noexpandtab:tw=98:
|
|
|
@ -1,96 +0,0 @@
|
||||||
// verify.go -- Verify signatures
|
|
||||||
//
|
|
||||||
// (c) 2016 Sudhi Herle <sudhi@herle.net>
|
|
||||||
//
|
|
||||||
// Licensing Terms: GPLv2
|
|
||||||
//
|
|
||||||
// If you need a commercial license for this work, please contact
|
|
||||||
// the author.
|
|
||||||
//
|
|
||||||
// This software does not come with any express or implied
|
|
||||||
// warranty; it is provided "as is". No claim is made to its
|
|
||||||
// suitability for any purpose.
|
|
||||||
|
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"os"
|
|
||||||
|
|
||||||
"git.rgst.io/homelab/sigtool/v3/sign"
|
|
||||||
flag "github.com/opencoff/pflag"
|
|
||||||
)
|
|
||||||
|
|
||||||
func verify(args []string) {
|
|
||||||
var help, quiet bool
|
|
||||||
|
|
||||||
fs := flag.NewFlagSet("verify", flag.ExitOnError)
|
|
||||||
fs.BoolVarP(&help, "help", "h", false, "Show this help and exit")
|
|
||||||
fs.BoolVarP(&quiet, "quiet", "q", false, "Don't show any output; exit with status code only")
|
|
||||||
|
|
||||||
fs.Parse(args)
|
|
||||||
|
|
||||||
if help {
|
|
||||||
fs.SetOutput(os.Stdout)
|
|
||||||
fmt.Printf(`%s verify|v [options] pubkey sig file
|
|
||||||
|
|
||||||
Verify an Ed25519 signature in SIG of FILE using a public key PUBKEY.
|
|
||||||
The pubkey can be one of:
|
|
||||||
- a file: either OpenSSH ed25519 pubkey or a sigtool pubkey
|
|
||||||
- a string: the raw OpenSSH or sigtool pubkey
|
|
||||||
|
|
||||||
%s will first parse it as a string before trying to parse it as a file.
|
|
||||||
|
|
||||||
Options:
|
|
||||||
`, Z, Z)
|
|
||||||
fs.PrintDefaults()
|
|
||||||
os.Exit(0)
|
|
||||||
}
|
|
||||||
|
|
||||||
args = fs.Args()
|
|
||||||
if len(args) < 3 {
|
|
||||||
Die("Insufficient arguments to 'verify'. Try '%s verify -h' ..", Z)
|
|
||||||
}
|
|
||||||
|
|
||||||
pn := args[0]
|
|
||||||
sn := args[1]
|
|
||||||
fn := args[2]
|
|
||||||
|
|
||||||
// We first try to read the public key as a base64/openssh string
|
|
||||||
pk, err := sign.MakePublicKeyFromString(pn)
|
|
||||||
if err != nil {
|
|
||||||
pk, err = sign.ReadPublicKey(pn)
|
|
||||||
if err != nil {
|
|
||||||
Die("%s", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
sig, err := sign.ReadSignature(sn)
|
|
||||||
if err != nil {
|
|
||||||
Die("Can't read signature '%s': %s", sn, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if !sig.IsPKMatch(pk) {
|
|
||||||
Die("Wrong public key '%s' for verifying '%s'", pn, sn)
|
|
||||||
}
|
|
||||||
|
|
||||||
ok, err := pk.VerifyFile(fn, sig)
|
|
||||||
if err != nil {
|
|
||||||
Die("%s", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
exit := 0
|
|
||||||
if !ok {
|
|
||||||
exit = 1
|
|
||||||
}
|
|
||||||
|
|
||||||
if !quiet {
|
|
||||||
if ok {
|
|
||||||
fmt.Printf("%s: Signature %s verified\n", fn, sn)
|
|
||||||
} else {
|
|
||||||
fmt.Printf("%s: Signature %s verification failure\n", fn, sn)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
os.Exit(exit)
|
|
||||||
}
|
|
27
tests.sh
27
tests.sh
|
@ -77,35 +77,26 @@ spk2=$ssk2.pub
|
||||||
$keygen -q -C 'ssk1@foo' -t ed25519 -f $ssk1 -N ""
|
$keygen -q -C 'ssk1@foo' -t ed25519 -f $ssk1 -N ""
|
||||||
$keygen -q -C 'ssk2@foo' -t ed25519 -f $ssk2 -N ""
|
$keygen -q -C 'ssk2@foo' -t ed25519 -f $ssk2 -N ""
|
||||||
|
|
||||||
# extract the pk string
|
$bin s --no-password $ssk1 -o $sig $0 || die "can't sign with $ssk1"
|
||||||
spk1_str=$(cat $spk1 | awk '{ print $2 }')
|
$bin v -q $spk1 $sig $0 || die "can't verify with $spk2"
|
||||||
|
|
||||||
$bin s --no-password $ssk1 -o $sig $0 || die "can't sign with $ssk1"
|
$bin e --no-password -o $encout $spk2 $0 || die "can't encrypt to $spk2 with $ssk1"
|
||||||
$bin v -q $spk1 $sig $0 || die "can't verify with $spk2"
|
$bin d --no-password -o $decout $ssk2 $encout || die "can't decrypt with $ssk2"
|
||||||
$bin v -q $spk1_str $sig $0 || die "can't verify with $spk2_str"
|
|
||||||
|
|
||||||
$bin e --no-password -o $encout $spk2 $0 || die "can't encrypt to $spk2 with $ssk1"
|
|
||||||
$bin d --no-password -o $decout $ssk2 $encout || die "can't decrypt with $ssk2"
|
|
||||||
|
|
||||||
# cleanup state
|
# cleanup state
|
||||||
rm -f $sig $encout $decout
|
rm -f $sig $encout $decout
|
||||||
|
|
||||||
|
|
||||||
# generate keys
|
# generate keys
|
||||||
$bin g -E FOO $bn || die "can't gen keypair $pk, $sk"
|
$bin g -E FOO $bn || die "can't gen keypair $pk, $sk"
|
||||||
$bin g -E FOO $bn 2>/dev/null && die "overwrote prev keypair"
|
$bin g -E FOO $bn 2>/dev/null && die "overwrote prev keypair"
|
||||||
$bin g -E FOO --overwrite $bn || die "can't force gen keypair $pk, $sk"
|
$bin g -E FOO --overwrite $bn || die "can't force gen keypair $pk, $sk"
|
||||||
$bin g -E FOO $bn2 || die "can't force gen keypair $pk2, $sk2"
|
$bin g -E FOO $bn2 || die "can't force gen keypair $pk2, $sk2"
|
||||||
|
|
||||||
# extract pk string
|
|
||||||
pk_str=$(cat $pk | grep 'pk:' | sed -e 's/^pk: //g')
|
|
||||||
pk2_str=$(cat $pk2 | grep 'pk:' | sed -e 's/^pk: //g')
|
|
||||||
|
|
||||||
# sign and verify
|
# sign and verify
|
||||||
$bin s -E FOO $sk $0 -o $sig || die "can't sign $0"
|
$bin s -E FOO $sk $0 -o $sig || die "can't sign $0"
|
||||||
$bin v -q $pk $sig $0 || die "can't verify signature of $0"
|
$bin v -q $pk $sig $0 || die "can't verify signature of $0"
|
||||||
$bin v -q $pk_str $sig $0 || die "can't verify signature of $0"
|
$bin v -q $pk2 $sig $0 2>/dev/null && die "bad verification with wrong $pk2"
|
||||||
$bin v -q $pk2 $sig $0 2>/dev/null && die "bad verification with wrong $pk2"
|
|
||||||
$bin v -q $pk2_str $sig $0 2>/dev/null && die "bad verification with wrong $pk2"
|
|
||||||
|
|
||||||
# encrypt/decrypt
|
# encrypt/decrypt
|
||||||
$bin e -E FOO -o $encout $pk2 $0 || die "can't encrypt to $pk2"
|
$bin e -E FOO -o $encout $pk2 $0 || die "can't encrypt to $pk2"
|
||||||
|
@ -115,7 +106,7 @@ cmp -s $decout $0 || die "decrypted file mismatch with $0"
|
||||||
# now with sender verification
|
# now with sender verification
|
||||||
$bin e -E FOO --overwrite -o $encout -s $sk $pk2 $0 || die "can't sender-encrypt to $pk2"
|
$bin e -E FOO --overwrite -o $encout -s $sk $pk2 $0 || die "can't sender-encrypt to $pk2"
|
||||||
$bin d -E FOO --overwrite -o $decout -v $pk $sk2 $encout || die "can't decrypt with $sk2"
|
$bin d -E FOO --overwrite -o $decout -v $pk $sk2 $encout || die "can't decrypt with $sk2"
|
||||||
cmp -s $decout $0 || die "decrypted file mismatch with $0"
|
cmp -s $decout $0 || die "decrypted file mismatch with $0"
|
||||||
|
|
||||||
# Only delete if everything worked
|
# Only delete if everything worked
|
||||||
echo "$Z: All tests pass!"
|
echo "$Z: All tests pass!"
|
||||||
|
|
Loading…
Add table
Reference in a new issue