Compare commits
20 commits
Author | SHA1 | Date | |
---|---|---|---|
aa96303d43 | |||
8d3686eb14 | |||
6b2e5526b2 | |||
d128cfa7ce | |||
3f6b9cd2af | |||
6a16789886 | |||
1823aaa5e0 | |||
810aa02bdd | |||
|
1786734c0a | ||
|
d47a4596ef | ||
|
fc94d7cd7d | ||
|
2e6d92c753 | ||
|
5c6152b4ed | ||
|
e3053142f5 | ||
|
d49f732c71 | ||
|
15053202a1 | ||
|
c5400a6b18 | ||
|
eae20abd24 | ||
|
c4f79962c9 | ||
|
a538ac8e5c |
26 changed files with 1585 additions and 1556 deletions
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -31,4 +31,4 @@ sigtool
|
|||
*.pub
|
||||
*.key
|
||||
*.sig
|
||||
|
||||
releases/*
|
||||
|
|
2
.mise.toml
Normal file
2
.mise.toml
Normal file
|
@ -0,0 +1,2 @@
|
|||
[tools]
|
||||
golang = "1.24"
|
|
@ -40,7 +40,7 @@ You need two things:
|
|||
|
||||
Next, build sigtool:
|
||||
|
||||
git clone https://github.com/opencoff/sigtool
|
||||
git clone https://git.rgst.io/homelab/sigtool/v3
|
||||
cd sigtool
|
||||
make
|
||||
|
||||
|
@ -101,6 +101,10 @@ e.g., to verify the signature of *archive.tar.gz* against
|
|||
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
|
||||
keys.
|
||||
|
||||
|
|
209
build
209
build
|
@ -4,7 +4,7 @@
|
|||
#
|
||||
# - 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
|
||||
|
@ -13,12 +13,13 @@
|
|||
#
|
||||
# License: GPLv2
|
||||
#
|
||||
Progs=".:sigtool"
|
||||
Progs="src:sigtool"
|
||||
|
||||
# Relative path to protobuf sources
|
||||
# e.g. src/foo/a.proto
|
||||
Protobufs="internal/pb/hdr.proto"
|
||||
|
||||
#set -x
|
||||
|
||||
# -- DO NOT CHANGE ANYTHING AFTER THIS --
|
||||
|
||||
|
@ -28,9 +29,10 @@ PWD=`pwd`
|
|||
Static=0
|
||||
Dryrun=0
|
||||
Prodver=""
|
||||
Repover=""
|
||||
Verbose=0
|
||||
GoRoot=$HOME/go
|
||||
Go=$GoRoot/bin/go
|
||||
Go=`which go`
|
||||
Bindir=$PWD/bin
|
||||
|
||||
die() {
|
||||
echo "$Z: $@" 1>&2
|
||||
|
@ -48,18 +50,56 @@ case $BASH_VERSION in
|
|||
;;
|
||||
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() {
|
||||
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
|
||||
$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
|
||||
|
@ -68,13 +108,14 @@ Usage: $0
|
|||
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/)
|
||||
With no arguments, $0 builds: $pstr
|
||||
|
||||
The repository's latest tag is used as the default version of the software being
|
||||
built.
|
||||
built. The current repository version is $Repover.
|
||||
|
||||
Options:
|
||||
-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]
|
||||
-V N, --version=N Use 'N' as the product version string [$Prodver]
|
||||
-a X, --arch=X Cross compile for OS-CPU 'X' [$hostos-$hostcpu]
|
||||
|
@ -83,7 +124,7 @@ Options:
|
|||
-v, --verbose Build verbosely (adds "-v" to go tooling) [False]
|
||||
--vet Run "go vet" on modules named on the command line [False]
|
||||
--mod Run "go mod ..." [False]
|
||||
--go-root=G Use Go in GOROOT 'G' [$GoRoot]
|
||||
--go=G Use Go in 'G' [$Go]
|
||||
-x Run in debug/trace mode [False]
|
||||
--print-arch Print the target architecture and exit
|
||||
EOF
|
||||
|
@ -157,6 +198,14 @@ do
|
|||
ac_prev=Arch
|
||||
;;
|
||||
|
||||
-b|--bindir)
|
||||
ac_prev=Bindir
|
||||
;;
|
||||
|
||||
--bindir=*)
|
||||
Bindir=$ac_optarg
|
||||
;;
|
||||
|
||||
--version=*)
|
||||
Prodver=$ac_optarg
|
||||
;;
|
||||
|
@ -217,7 +266,6 @@ done
|
|||
|
||||
# let every error abort
|
||||
set -e
|
||||
Go=$GoRoot/bin/go
|
||||
|
||||
# build a tool that runs on the host - if needed.
|
||||
hosttool() {
|
||||
|
@ -225,30 +273,65 @@ hosttool() {
|
|||
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
|
||||
|
||||
local tmpdir=/tmp/$tool.$$
|
||||
mkdir $tmpdir || die "can't make $tmpdir"
|
||||
|
||||
# since go1.20 - install uses env vars to decide where to put
|
||||
# build artifacts. Why are all the google tooling so bloody dev
|
||||
# hostile! WTF is wrong with command line args?!
|
||||
export GOBIN=$bindir
|
||||
|
||||
# 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
|
||||
(
|
||||
cd $tmpdir
|
||||
$e $Go install $src@latest || die "can't install $tool"
|
||||
)
|
||||
$e rm -rf $tmpdir
|
||||
|
||||
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
|
||||
hostcpu=$($Go env GOHOSTARCH) || exit 1
|
||||
|
@ -304,72 +387,25 @@ fi
|
|||
|
||||
|
||||
# This is where build outputs go
|
||||
Bindir=$PWD/bin/$cross
|
||||
Hostbindir=$PWD/bin/$hostos-$hostcpu
|
||||
Outdir=$Bindir/$cross
|
||||
Hostbindir=$Bindir/$hostos-$hostcpu
|
||||
export PATH=$Hostbindir:$PATH
|
||||
|
||||
[ -d $Bindir ] || mkdir -p $Bindir
|
||||
[ -d $Outdir ] || mkdir -p $Outdir
|
||||
[ -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
|
||||
if [ -n "$Protobufs" ]; then
|
||||
set +e
|
||||
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
|
||||
buildproto $Protobufs
|
||||
set -e
|
||||
fi
|
||||
|
||||
repover="main.RepoVersion=$rev"
|
||||
# Get git/hg version info for the build
|
||||
repover="main.RepoVersion=$Repover"
|
||||
prodver="main.ProductVersion=$Prodver"
|
||||
date="main.Buildtime=`date -u '+%Y-%m-%dT%H:%M.%SZ'`"
|
||||
ldflags="-ldflags \"-X $repover -X $prodver -X $date $ldflags\""
|
||||
ldflags="-ldflags \"-X $repover -X $prodver $ldflags -buildid=\""
|
||||
vflag=""
|
||||
|
||||
[ $Verbose -gt 0 ] && vflag="-v"
|
||||
|
@ -398,9 +434,11 @@ case $Tool in
|
|||
all="$@"
|
||||
fi
|
||||
|
||||
echo "Building $Prodver ($rev), $cross $msg .."
|
||||
[ -z "$all" ] && die "No programs specified. Try '$Z --help'"
|
||||
|
||||
for p in $all; do
|
||||
echo "Building $Prodver ($Repover), $cross $msg .."
|
||||
|
||||
for p in $all; do
|
||||
if echo $p | grep -q ':' ; then
|
||||
out=${p##*:}
|
||||
dir=${p%%:*}
|
||||
|
@ -408,8 +446,15 @@ case $Tool in
|
|||
out=$p
|
||||
dir=$p
|
||||
fi
|
||||
|
||||
# Add .exe suffix to out if needed
|
||||
if [ "$GOOS" = "windows" ]; then
|
||||
base=${out%%.exe}
|
||||
out="${base}.exe"
|
||||
fi
|
||||
|
||||
echo " $dir: $out .. "
|
||||
$e eval $Go build $vflag -o $Bindir/$out $isuffix "$ldflags" ./$dir || exit 1
|
||||
$e eval $Go build $vflag -trimpath -o $Outdir/$out $isuffix "$ldflags" ./$dir || exit 1
|
||||
done
|
||||
;;
|
||||
esac
|
||||
|
|
26
go.mod
26
go.mod
|
@ -1,17 +1,25 @@
|
|||
module github.com/opencoff/sigtool
|
||||
module git.rgst.io/homelab/sigtool/v3
|
||||
|
||||
go 1.20
|
||||
go 1.24.0
|
||||
|
||||
require (
|
||||
github.com/dchest/bcrypt_pbkdf v0.0.0-20150205184540-83f37f9c154a
|
||||
github.com/gogo/protobuf v1.3.2
|
||||
github.com/opencoff/go-utils v0.4.1
|
||||
github.com/opencoff/pflag v1.0.6-sh1
|
||||
golang.org/x/crypto v0.7.0
|
||||
gopkg.in/yaml.v2 v2.4.0
|
||||
github.com/opencoff/go-fio v0.5.14
|
||||
github.com/opencoff/go-mmap v0.1.5
|
||||
github.com/opencoff/go-utils v1.0.2
|
||||
github.com/opencoff/pflag v1.0.7
|
||||
github.com/planetscale/vtprotobuf v0.6.0
|
||||
golang.org/x/crypto v0.36.0
|
||||
google.golang.org/protobuf v1.36.5
|
||||
gopkg.in/yaml.v3 v3.0.1
|
||||
)
|
||||
|
||||
require (
|
||||
golang.org/x/sys v0.6.0 // indirect
|
||||
golang.org/x/term v0.6.0 // indirect
|
||||
github.com/pkg/xattr v0.4.10 // indirect
|
||||
github.com/puzpuzpuz/xsync/v3 v3.5.1 // 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
|
||||
|
|
77
go.sum
77
go.sum
|
@ -1,48 +1,39 @@
|
|||
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/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
|
||||
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
|
||||
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
|
||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||
github.com/opencoff/go-utils v0.4.1 h1:Ke4Q1Tl2GKMI+dwleuPNHH713ngRiNMOFIkymncHqXg=
|
||||
github.com/opencoff/go-utils v0.4.1/go.mod h1:c+7QUAiCCHcNH6OGvsZ0fviG7cgse8Y3ucg+xy7sGXM=
|
||||
github.com/opencoff/pflag v1.0.6-sh1 h1:6RO8GgnpH928yu6earGDD01FnFT//bDJ1hCovcVVqY4=
|
||||
github.com/opencoff/pflag v1.0.6-sh1/go.mod h1:2bXtpAD/5h/2LarkbsRwiUxqnvB1nZBzn9Xjad1P41A=
|
||||
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20190618222545-ea8f1a30c443/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.7.0 h1:AvwMYaRytfdeVt3u6mLaxYtErKYjxA2OXjJ1HHq6t3A=
|
||||
golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU=
|
||||
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ=
|
||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.6.0 h1:clScbb1cHjoCkyRbWwBEUZ5H/tIFu5TAXIqaZD0Gcjw=
|
||||
golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U=
|
||||
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=
|
||||
github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
|
||||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/opencoff/go-fio v0.5.14 h1:PGi4XLLO4RSuc3m5exY0G2vweov6w3UThhScehBfM8c=
|
||||
github.com/opencoff/go-fio v0.5.14/go.mod h1:hoSySYpavRnfQUsxzUgadk31kYiNQhMDvA2MObsXKf8=
|
||||
github.com/opencoff/go-mmap v0.1.5 h1:RKPtevC4mOW5bi9skBPPo4nFTIH4lVWAL20Tff+FjLg=
|
||||
github.com/opencoff/go-mmap v0.1.5/go.mod h1:y/6Jk/tDUc00k3oSQpiJX++20Nw7xFSlc5kLkhGnRXw=
|
||||
github.com/opencoff/go-utils v1.0.2 h1:BANRL8ZxgHpuo8gQBAzT3M9Im3aNFhaWW28jhc86LNs=
|
||||
github.com/opencoff/go-utils v1.0.2/go.mod h1:eZkEVQVzNfuE8uGepyhscMsqcXq7liGbBHYYwgYaoy8=
|
||||
github.com/opencoff/pflag v1.0.7 h1:o5cQIuX75bDcdJ6AXl68gzpA72a3CJ2MPStaMnEuwi4=
|
||||
github.com/opencoff/pflag v1.0.7/go.mod h1:2bXtpAD/5h/2LarkbsRwiUxqnvB1nZBzn9Xjad1P41A=
|
||||
github.com/pkg/xattr v0.4.10 h1:Qe0mtiNFHQZ296vRgUjRCoPHPqH7VdTOrZx3g0T+pGA=
|
||||
github.com/pkg/xattr v0.4.10/go.mod h1:di8WF84zAKk8jzR1UBTEWh9AUlIZZ7M/JNt8e9B6ktU=
|
||||
github.com/planetscale/vtprotobuf v0.6.0 h1:nBeETjudeJ5ZgBHUz1fVHvbqUKnYOXNhsIEabROxmNA=
|
||||
github.com/planetscale/vtprotobuf v0.6.0/go.mod h1:t/avpk3KcrXxUnYOhZhMXJlSEyie6gQbtLq5NM3loB8=
|
||||
github.com/puzpuzpuz/xsync/v3 v3.5.1 h1:GJYJZwO6IdxN/IKbneznS6yPkVC+c3zyY/j19c++5Fg=
|
||||
github.com/puzpuzpuz/xsync/v3 v3.5.1/go.mod h1:VjzYrABPabuM4KyBh1Ftq6u8nhwY5tBPKP9jpmh0nnA=
|
||||
golang.org/x/crypto v0.35.0 h1:b15kiHdrGCHrP6LvwaQ3c03kgNhhiMgvlhxHQhmg2Xs=
|
||||
golang.org/x/crypto v0.35.0/go.mod h1:dy7dXNW32cAb/6/PRuTNsix8T+vJAqvuIy5Bli/x0YQ=
|
||||
golang.org/x/crypto v0.36.0 h1:AnAEvhDddvBdpY+uR+MyHmuZzzNqXSe/GvuDeob5L34=
|
||||
golang.org/x/crypto v0.36.0/go.mod h1:Y4J0ReaxCR1IMaabaSMugxJES1EpwhBHhv2bDHklZvc=
|
||||
golang.org/x/sys v0.0.0-20220408201424-a24fb2fb8a0f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc=
|
||||
golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.31.0 h1:ioabZlmFYtWhL+TRYpcnNlLwhyxaM9kWTDEmfnprqik=
|
||||
golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
|
||||
golang.org/x/term v0.29.0 h1:L6pJp37ocefwRRtYPKSWOWzOtWSxVajvz2ldH/xi3iU=
|
||||
golang.org/x/term v0.29.0/go.mod h1:6bl4lRlvVuDgSf3179VpIxBF0o10JUpXWOnI7nErv7s=
|
||||
golang.org/x/term v0.30.0 h1:PQ39fJZ+mfadBm0y5WlL4vlM7Sx1Hgf13sMIY2+QS9Y=
|
||||
golang.org/x/term v0.30.0/go.mod h1:NYYFdzHoI5wRh/h5tDMdMqCqPJZEuNqVR5xJLd/n67g=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
google.golang.org/protobuf v1.36.5 h1:tPhr+woSbjfYvY6/GPufUoYizxw1cF/yFoxJ2fmpwlM=
|
||||
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/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
||||
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,13 +1,8 @@
|
|||
syntax="proto3";
|
||||
|
||||
//import "gogoproto/gogo.proto"
|
||||
|
||||
package pb;
|
||||
option go_package = "internal/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
|
||||
|
|
512
internal/pb/hdr_vtproto.pb.go
Normal file
512
internal/pb/hdr_vtproto.pb.go
Normal file
|
@ -0,0 +1,512 @@
|
|||
// 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
|
||||
}
|
16
internal/pb/helpers.go
Normal file
16
internal/pb/helpers.go
Normal file
|
@ -0,0 +1,16 @@
|
|||
// 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
Executable file
54
mk-rel.sh
Executable file
|
@ -0,0 +1,54 @@
|
|||
#! /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
|
3
renovate.json
Normal file
3
renovate.json
Normal file
|
@ -0,0 +1,3 @@
|
|||
{
|
||||
"$schema": "https://docs.renovatebot.com/renovate-schema.json"
|
||||
}
|
|
@ -1,10 +1,10 @@
|
|||
[](https://godoc.org/github.com/opencoff/sigtool/sign)
|
||||
[](https://godoc.org/git.rgst.io/homelab/sigtool/v3/sign)
|
||||
|
||||
# sigtool/sign - Ed25519 signature calculation and verification
|
||||
|
||||
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.
|
||||
|
||||
The companion program [sigtool](https://github.com/opencoff/sigtool) uses this library.
|
||||
The companion program [sigtool](https://git.rgst.io/homelab/sigtool/v3) uses this library.
|
||||
## License
|
||||
GPL v2.0
|
||||
|
|
|
@ -70,13 +70,14 @@ import (
|
|||
"crypto/subtle"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"golang.org/x/crypto/curve25519"
|
||||
"golang.org/x/crypto/hkdf"
|
||||
"hash"
|
||||
"io"
|
||||
"os"
|
||||
|
||||
"github.com/opencoff/sigtool/internal/pb"
|
||||
"golang.org/x/crypto/curve25519"
|
||||
"golang.org/x/crypto/hkdf"
|
||||
|
||||
"git.rgst.io/homelab/sigtool/v3/internal/pb"
|
||||
)
|
||||
|
||||
// Encryption chunk size = 4MB
|
||||
|
@ -753,7 +754,8 @@ func (d *Decryptor) verifySender(key []byte, senderPk *PublicKey) error {
|
|||
}
|
||||
|
||||
// Wrap data encryption key 'k' with the sender's PK and our ephemeral curve SK
|
||||
// basically, we do a scalarmult: Ephemeral encryption/decryption SK x receiver PK
|
||||
//
|
||||
// basically, we do a scalarmult: Ephemeral encryption/decryption SK x receiver PK
|
||||
func (e *Encryptor) wrapKey(pk *PublicKey) (*pb.WrappedKey, error) {
|
||||
rxPK := pk.ToCurve25519PK()
|
||||
sekrit, err := curve25519.X25519(e.encSK, rxPK)
|
||||
|
|
67
sign/iomisc.go
Normal file
67
sign/iomisc.go
Normal file
|
@ -0,0 +1,67 @@
|
|||
// 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,18 +25,14 @@ import (
|
|||
"crypto/sha256"
|
||||
"crypto/sha512"
|
||||
"encoding/base64"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"hash"
|
||||
"io/ioutil"
|
||||
"math/big"
|
||||
"os"
|
||||
|
||||
Ed "crypto/ed25519"
|
||||
"golang.org/x/crypto/scrypt"
|
||||
"gopkg.in/yaml.v2"
|
||||
|
||||
"github.com/opencoff/go-utils"
|
||||
"golang.org/x/crypto/scrypt"
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
// Private Ed25519 key
|
||||
|
@ -184,14 +180,14 @@ func makePrivateKeyFromBytes(sk *PrivateKey, buf []byte) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
/*
|
||||
// Make a private key from 64-bytes of extended Ed25519 key
|
||||
func PrivateKeyFromBytes(buf []byte) (*PrivateKey, error) {
|
||||
var sk PrivateKey
|
||||
|
||||
return makePrivateKeyFromBytes(&sk, buf)
|
||||
if err := makePrivateKeyFromBytes(&sk, buf); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &sk, nil
|
||||
}
|
||||
*/
|
||||
|
||||
// Given a secret key, return the corresponding Public Key
|
||||
func (sk *PrivateKey) PublicKey() *PublicKey {
|
||||
|
@ -374,6 +370,29 @@ func MakePublicKey(yml []byte) (*PublicKey, error) {
|
|||
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 {
|
||||
if len(b) != 32 {
|
||||
return fmt.Errorf("public key is malformed (len %d!)", len(b))
|
||||
|
@ -386,14 +405,14 @@ func makePublicKeyFromBytes(pk *PublicKey, b []byte) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
/*
|
||||
// Make a public key from a byte string
|
||||
func PublicKeyFromBytes(b []byte) (*PublicKey, error) {
|
||||
var pk PublicKey
|
||||
|
||||
makePublicKeyFromBytes(&pk, b)
|
||||
if err := makePublicKeyFromBytes(&pk, b); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &pk, nil
|
||||
}
|
||||
*/
|
||||
|
||||
// Serialize a PublicKey into file 'fn' with a human readable 'comment'.
|
||||
// If 'ovwrite' is true, overwrite the file if it exists.
|
||||
|
@ -499,41 +518,6 @@ func (pk *PublicKey) UnmarshalBinary(yml []byte) error {
|
|||
|
||||
// -- 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 := 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 {
|
||||
k[0] &= 248
|
||||
k[31] &= 127
|
||||
|
|
124
sign/safefile.go
124
sign/safefile.go
|
@ -1,124 +0,0 @@
|
|||
// safefile.go - safe file creation and unwinding on error
|
||||
//
|
||||
// (c) 2021 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 (
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
)
|
||||
|
||||
// SafeFile is an io.WriteCloser which uses a temporary file that
|
||||
// will be atomically renamed when there are no errors and
|
||||
// caller invokes Close(). Callers are advised to call
|
||||
// Abort() in the appropriate error handling (defer) context
|
||||
// so that the temporary file is properly deleted.
|
||||
type SafeFile struct {
|
||||
*os.File
|
||||
|
||||
// error for writes recorded once
|
||||
err error
|
||||
name string // actual filename
|
||||
|
||||
closed bool // set if the file is closed properly
|
||||
}
|
||||
|
||||
var _ io.WriteCloser = &SafeFile{}
|
||||
|
||||
// NewSafeFile creates a new temporary file that would either be
|
||||
// aborted or safely renamed to the correct name.
|
||||
// 'nm' is the name of the final file; if 'ovwrite' is true,
|
||||
// then the file is overwritten if it exists.
|
||||
func NewSafeFile(nm string, ovwrite bool, flag int, perm os.FileMode) (*SafeFile, error) {
|
||||
if _, err := os.Stat(nm); err == nil && !ovwrite {
|
||||
return nil, fmt.Errorf("safefile: won't overwrite existing %s", nm)
|
||||
}
|
||||
|
||||
// forcibly unlink the old file - so previous artifacts don't exist
|
||||
os.Remove(nm)
|
||||
|
||||
tmp := fmt.Sprintf("%s.tmp.%d.%x", nm, os.Getpid(), randu32())
|
||||
fd, err := os.OpenFile(tmp, flag, perm)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
sf := &SafeFile{
|
||||
File: fd,
|
||||
name: nm,
|
||||
}
|
||||
return sf, nil
|
||||
}
|
||||
|
||||
// Attempt to write everything in 'b' and don't proceed if there was
|
||||
// a previous error or the file was already closed.
|
||||
func (sf *SafeFile) Write(b []byte) (int, error) {
|
||||
if sf.err != nil {
|
||||
return 0, sf.err
|
||||
}
|
||||
|
||||
if sf.closed {
|
||||
return 0, fmt.Errorf("safefile: %s is closed", sf.Name())
|
||||
}
|
||||
|
||||
var z, nw int
|
||||
n := len(b)
|
||||
for n > 0 {
|
||||
if nw, sf.err = sf.File.Write(b); sf.err != nil {
|
||||
return z, sf.err
|
||||
}
|
||||
z += nw
|
||||
n -= nw
|
||||
b = b[nw:]
|
||||
}
|
||||
return z, nil
|
||||
}
|
||||
|
||||
// Abort the file write and remove any temporary artifacts
|
||||
func (sf *SafeFile) Abort() {
|
||||
// if we've successfully closed, nothing to do!
|
||||
if sf.closed {
|
||||
return
|
||||
}
|
||||
|
||||
sf.closed = true
|
||||
sf.File.Close()
|
||||
os.Remove(sf.Name())
|
||||
}
|
||||
|
||||
// Close flushes all file data & metadata to disk, closes the file and atomically renames
|
||||
// the temp file to the actual file - ONLY if there were no intervening errors.
|
||||
func (sf *SafeFile) Close() error {
|
||||
if sf.err != nil {
|
||||
sf.Abort()
|
||||
return sf.err
|
||||
}
|
||||
|
||||
// mark this file as closed!
|
||||
sf.closed = true
|
||||
|
||||
if sf.err = sf.Sync(); sf.err != nil {
|
||||
return sf.err
|
||||
}
|
||||
|
||||
if sf.err = sf.File.Close(); sf.err != nil {
|
||||
return sf.err
|
||||
}
|
||||
|
||||
if sf.err = os.Rename(sf.Name(), sf.name); sf.err != nil {
|
||||
return sf.err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
|
@ -27,7 +27,8 @@ import (
|
|||
"io/ioutil"
|
||||
|
||||
Ed "crypto/ed25519"
|
||||
"gopkg.in/yaml.v2"
|
||||
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
// An Ed25519 Signature
|
||||
|
@ -38,8 +39,9 @@ type Signature struct {
|
|||
|
||||
// Sign a prehashed Message; return the signature as opaque bytes
|
||||
// Signature is an YAML file:
|
||||
// Comment: source file path
|
||||
// Signature: Ed25519 signature
|
||||
//
|
||||
// Comment: source file path
|
||||
// Signature: Ed25519 signature
|
||||
func (sk *PrivateKey) SignMessage(ck []byte, comment string) (*Signature, error) {
|
||||
h := sha512.New()
|
||||
h.Write([]byte("sigtool signed message"))
|
||||
|
|
360
sigtool.go
360
sigtool.go
|
@ -1,360 +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"
|
||||
"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 := sign.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:
|
|
@ -20,9 +20,10 @@ import (
|
|||
"os"
|
||||
"strings"
|
||||
|
||||
"git.rgst.io/homelab/sigtool/v3/sign"
|
||||
"github.com/opencoff/go-fio"
|
||||
"github.com/opencoff/go-utils"
|
||||
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]
|
||||
|
@ -35,8 +36,8 @@ func encrypt(args []string) {
|
|||
|
||||
var outfile string
|
||||
var keyfile string
|
||||
var szstr string = "128k"
|
||||
var envpw string
|
||||
var szstr string = "128k"
|
||||
var envpw string
|
||||
var nopw, force bool
|
||||
var blksize uint64
|
||||
|
||||
|
@ -140,7 +141,11 @@ func encrypt(args []string) {
|
|||
mode = ist.Mode()
|
||||
}
|
||||
|
||||
sf, err := sign.NewSafeFile(outfile, force, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, mode)
|
||||
var opts uint32
|
||||
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 {
|
||||
Die("%s", err)
|
||||
}
|
||||
|
@ -302,7 +307,11 @@ func decrypt(args []string) {
|
|||
mode = ist.Mode()
|
||||
}
|
||||
|
||||
sf, err := sign.NewSafeFile(outfile, force, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, mode)
|
||||
var opts uint32
|
||||
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 {
|
||||
Die("%s", err)
|
||||
}
|
100
src/gen.go
Normal file
100
src/gen.go
Normal file
|
@ -0,0 +1,100 @@
|
|||
// 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
Normal file
116
src/sign.go
Normal file
|
@ -0,0 +1,116 @@
|
|||
// 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
Normal file
129
src/sigtool.go
Normal file
|
@ -0,0 +1,129 @@
|
|||
// 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:
|
96
src/verify.go
Normal file
96
src/verify.go
Normal file
|
@ -0,0 +1,96 @@
|
|||
// 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)
|
||||
}
|
79
tests.sh
79
tests.sh
|
@ -1,32 +1,44 @@
|
|||
#! /usr/bin/env bash
|
||||
|
||||
|
||||
# simple round-trip tests to verify the tool
|
||||
# Usage:
|
||||
# $0 [bin=/path/to/sigtool] [tmpdir=/path/to/workdir]
|
||||
|
||||
# Use cmdline flag to get go-root
|
||||
|
||||
GoRoot=$HOME/go
|
||||
|
||||
if [ -n "$1" ]; then
|
||||
GoRoot=$1
|
||||
fi
|
||||
|
||||
arch=`./build --go-root=$GoRoot --print-arch`
|
||||
bin=./bin/$arch/sigtool
|
||||
Z=`basename $0`
|
||||
|
||||
# workdir
|
||||
tmpdir=/tmp/sigtool$$
|
||||
|
||||
die() {
|
||||
echo "$Z: $@" 1>&2
|
||||
echo "$Z: Test output in $tmpdir .." 1>&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
# cmd line args processing
|
||||
for a in $*; do
|
||||
key=${a%=*}
|
||||
val=${a#*=}
|
||||
case $key in
|
||||
bin)
|
||||
bin=$val
|
||||
;;
|
||||
|
||||
tmpdir)
|
||||
tmpdir=$val
|
||||
;;
|
||||
|
||||
*)
|
||||
echo "Ignoring $key .."
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
if [ -z "$bin" ]; then
|
||||
arch=`./build --print-arch`
|
||||
bin=./bin/$arch/sigtool
|
||||
|
||||
[ -x $bin ] || ./build || die "can't find & build sigtool"
|
||||
fi
|
||||
|
||||
[ -z "$tmpdir" ] && tmpdir=/tmp/sigtool$$
|
||||
|
||||
mkdir -p $tmpdir || die "can't mkdir $tmpdir"
|
||||
[ -x $bin ] || ./build || die "Can't build sigtool for $arch"
|
||||
|
||||
# env name for reading the password
|
||||
passenv=FOO
|
||||
|
@ -38,9 +50,9 @@ FOO=bar
|
|||
#trap "rm -rf $tmpdir" EXIT
|
||||
|
||||
bn=$tmpdir/foo
|
||||
sig=$tmpdir/$Z.sig
|
||||
pk=$bn.pub
|
||||
sk=$bn.key
|
||||
sig=$tmpdir/$Z.sig
|
||||
bn2=$tmpdir/bar
|
||||
pk2=$bn2.pub
|
||||
sk2=$bn2.key
|
||||
|
@ -65,26 +77,35 @@ spk2=$ssk2.pub
|
|||
$keygen -q -C 'ssk1@foo' -t ed25519 -f $ssk1 -N ""
|
||||
$keygen -q -C 'ssk2@foo' -t ed25519 -f $ssk2 -N ""
|
||||
|
||||
$bin s --no-password $ssk1 -o $sig $0 || die "can't sign with $ssk1"
|
||||
$bin v -q $spk1 $sig $0 || die "can't verify with $spk2"
|
||||
# extract the pk string
|
||||
spk1_str=$(cat $spk1 | awk '{ print $2 }')
|
||||
|
||||
$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"
|
||||
$bin s --no-password $ssk1 -o $sig $0 || die "can't sign with $ssk1"
|
||||
$bin v -q $spk1 $sig $0 || die "can't verify with $spk2"
|
||||
$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
|
||||
rm -f $sig $encout $decout
|
||||
|
||||
|
||||
# generate keys
|
||||
$bin g -E FOO $bn || die "can't gen keypair $pk, $sk"
|
||||
$bin g -E FOO $bn && die "overwrote prev keypair"
|
||||
$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 --overwrite $bn || die "can't force gen keypair $pk, $sk"
|
||||
$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
|
||||
$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 $pk2 $sig $0 && die "bad verification with wrong $pk2"
|
||||
$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_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_str $sig $0 2>/dev/null && die "bad verification with wrong $pk2"
|
||||
|
||||
# encrypt/decrypt
|
||||
$bin e -E FOO -o $encout $pk2 $0 || die "can't encrypt to $pk2"
|
||||
|
@ -94,7 +115,7 @@ cmp -s $decout $0 || die "decrypted file mismatch with $0"
|
|||
# now with sender verification
|
||||
$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"
|
||||
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
|
||||
echo "$Z: All tests pass!"
|
||||
|
|
Loading…
Add table
Reference in a new issue