moved to codeberg

This commit is contained in:
2025-11-25 22:16:30 +01:00
parent a90d6e5c3c
commit e718c9c29d
7 changed files with 5 additions and 642 deletions

View File

@@ -1,89 +0,0 @@
# Copyright © 2023 Thomas von Dein
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
# no need to modify anything below
tool = gowipe
VERSION = $(shell grep VERSION main.go | head -1 | cut -d '"' -f2)
archs = darwin freebsd linux windows
PREFIX = /usr/local
UID = root
GID = 0
HAVE_POD :=
all: $(tool) buildlocal
buildlocal:
CGO_LDFLAGS='-static' go build -tags osusergo,netgo -ldflags "-extldflags=-static" -o $(tool)
install: buildlocal
install -d -o $(UID) -g $(GID) $(PREFIX)/bin
install -d -o $(UID) -g $(GID) $(PREFIX)/man/man1
install -o $(UID) -g $(GID) -m 555 $(tool) $(PREFIX)/sbin/
install -o $(UID) -g $(GID) -m 444 $(tool).1 $(PREFIX)/man/man1/
clean:
rm -rf $(tool) coverage.out
test:
go test -v ./...
singletest:
@echo "Call like this: ''make singletest TEST=TestPrepareColumns"
go test -run $(TEST)
cover-report:
go test ./... -cover -coverprofile=coverage.out
go tool cover -html=coverage.out
goupdate:
go get -t -u=patch ./...
buildall:
./mkrel.sh $(tool) $(VERSION)
release:
gh release create v$(VERSION) --generate-notes
show-versions: buildlocal
@echo "### gowipe version:"
@./gowipe -v
@echo
@echo "### go module versions:"
@go list -m all
@echo
@echo "### go version used for building:"
@grep -m 1 go go.mod
dir:
rm -rf a
mkdir -p a/b/c
date > a/filea
date > a/b/fileb
date > a/b/c/filec
bench: all
dd if=/dev/zero of=t/fileZ bs=1024 count=200000
dd if=/dev/zero of=t/fileM bs=1024 count=200000
dd if=/dev/zero of=t/fileS bs=1024 count=200000
dd if=/dev/zero of=t/fileE bs=1024 count=200000
/usr/bin/time -f "%S" ./gowipe -Z t/fileZ
/usr/bin/time -f "%S" ./gowipe -M t/fileM
/usr/bin/time -f "%S" ./gowipe -S t/fileS
/usr/bin/time -f "%S" ./gowipe -E t/fileE

View File

@@ -1,10 +1,12 @@
## gowipe - securely delete files and directories (not for SSD)
[![Actions](https://github.com/tlinden/gowipe/actions/workflows/ci.yaml/badge.svg)](https://github.com/tlinden/gowipe/actions)
[![License](https://img.shields.io/badge/license-GPL-blue.svg)](https://github.com/tlinden/gowipe/blob/master/LICENSE)
[![Go Report Card](https://goreportcard.com/badge/github.com/tlinden/gowipe)](https://goreportcard.com/report/github.com/tlinden/gowipe)
[![GitHub release](https://img.shields.io/github/v/release/tlinden/gowipe?color=%2300a719)](https://github.com/TLINDEN/gowipe/releases/latest)
## gowipe - securely delete files and directories (not for SSD)
> [!CAUTION]
> This software is now being maintained on [Codeberg](https://codeberg.org/scip/gowipe/).
## Description
`gowipe` is a simple self contained tool to securely wipe files and

200
crypto.go
View File

@@ -1,200 +0,0 @@
/*
Copyright © 2022-2025 Thomas von Dein
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package main
import (
"crypto/cipher"
cryptorand "crypto/rand"
"errors"
"fmt"
"io"
"math/big"
mathrand "math/rand"
"os"
"time"
"unsafe"
"golang.org/x/crypto/argon2"
chapo "golang.org/x/crypto/chacha20poly1305"
)
const (
SaltSize = 32 // in bytes
NonceSize = 24 // in bytes. taken from aead.NonceSize()
KeySize = uint32(32) // KeySize is 32 bytes (256 bits).
KeyTime = uint32(5)
KeyMemory = uint32(1024 * 64) // KeyMemory in KiB. here, 64 MiB.
KeyThreads = uint8(4)
chunkSize = 1024 * 32 // chunkSize in bytes. here, 32 KiB.
letters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890-"
letterIdxBits = 6 // 6 bits to represent a letter index
letterIdxMask = 1<<letterIdxBits - 1 // All 1-bits, as many as letterIdxBits
letterIdxMax = 63 / letterIdxBits // # of letter indices fitting in 63 bits
)
// via https://gist.github.com/dopey/c69559607800d2f2f90b1b1ed4e550fb
func AssertAvailablePRNG() {
// Assert that a cryptographically secure PRNG is available.
// Panic otherwise.
buf := make([]byte, 1)
_, err := io.ReadFull(cryptorand.Reader, buf)
if err != nil {
panic(fmt.Sprintf("crypto/rand is unavailable: Read() failed with %#v", err))
}
}
// GenerateRandomBytes returns securely generated random bytes.
// It will return an error if the system's secure random
// number generator fails to function correctly, in which
// case the caller should not continue.
func GenerateSecureRandomBytes(n int) ([]byte, error) {
b := make([]byte, n)
_, err := cryptorand.Read(b)
// Note that err == nil only if we read len(b) bytes.
if err != nil {
return nil, err
}
return b, nil
}
// GenerateRandomString returns a securely generated random string.
// It will return an error if the system's secure random
// number generator fails to function correctly, in which
// case the caller should not continue.
func GenerateSecureRandomString(n int) (string, error) {
ret := make([]byte, n)
for i := 0; i < n; i++ {
num, err := cryptorand.Int(cryptorand.Reader, big.NewInt(int64(len(letters))))
if err != nil {
return "", err
}
ret[i] = letters[num.Int64()]
}
return string(ret), nil
}
// via:
// https://stackoverflow.com/a/31832326
func GenerateMathRandomString(n int) string {
b := make([]byte, n)
var src = mathrand.NewSource(time.Now().UnixNano())
// A src.Int63() generates 63 random bits, enough for letterIdxMax characters!
for i, cache, remain := n-1, src.Int63(), letterIdxMax; i >= 0; {
if remain == 0 {
cache, remain = src.Int63(), letterIdxMax
}
if idx := int(cache & letterIdxMask); idx < len(letters) {
b[i] = letters[idx]
i--
}
cache >>= letterIdxBits
remain--
}
return *(*string)(unsafe.Pointer(&b))
}
func GetRandomKey() ([]byte, error) {
password, err := GenerateSecureRandomBytes(int(chapo.KeySize))
if err != nil {
return nil, err
}
salt, err := GenerateSecureRandomBytes(chapo.NonceSizeX)
if err != nil {
return nil, err
}
key := argon2.IDKey(password, salt, KeyTime, KeyMemory, KeyThreads, chapo.KeySize)
return key, nil
}
func Encrypt(c *Conf, filename string) error {
info, err := os.Stat(filename)
if err != nil {
return err
}
size := info.Size()
outfile, err := os.OpenFile(filename, os.O_RDWR|os.O_CREATE, 0666)
if err != nil {
return err
}
defer outfile.Close()
key, err := GetRandomKey()
if err != nil {
return err
}
aead, err := chapo.NewX(key)
if err != nil {
return err
}
for i := 0; i < c.count; i++ {
for {
if size < chunkSize {
if err := EncryptChunk(aead, outfile, size); err != nil {
return err
}
break
}
if err := EncryptChunk(aead, outfile, chunkSize); err != nil {
return err
}
size = size - chunkSize
if size <= 0 {
break
}
}
}
return nil
}
func EncryptChunk(aead cipher.AEAD, file *os.File, size int64) error {
chunk := make([]byte, size)
nonce, err := GenerateSecureRandomBytes(int(chapo.NonceSizeX))
if err != nil {
return err
}
cipher := aead.Seal(nil, nonce, chunk, nil)
n, err := file.Write(cipher[:size])
if err != nil {
return err
}
if int64(n) != size {
return errors.New("invalid number of bytes written")
}
return nil
}

14
go.mod
View File

@@ -1,14 +0,0 @@
module gowipe
go 1.20
require (
github.com/JojiiOfficial/shred v1.2.1
github.com/spf13/pflag v1.0.5
golang.org/x/crypto v0.15.0
)
require (
github.com/lu4p/shred v0.0.0-20201211173428-0347b645d724 // indirect
golang.org/x/sys v0.14.0 // indirect
)

10
go.sum
View File

@@ -1,10 +0,0 @@
github.com/JojiiOfficial/shred v1.2.1 h1:658CFVTqcAkYVg815vW+guYnyJTLOIoS15tMyPTYhNo=
github.com/JojiiOfficial/shred v1.2.1/go.mod h1:/OAxd6eYOhrXb3KW+2wmDog2BiFlUld8oJEKa+xblxU=
github.com/lu4p/shred v0.0.0-20201211173428-0347b645d724 h1:nLJRUakdvy2j7JsefrtAUqGRbfJUKKqRu/3BCRA9mIQ=
github.com/lu4p/shred v0.0.0-20201211173428-0347b645d724/go.mod h1:6b1kEKx7IPBboPSTnoJZE5sbSDjcNkHHO3Hii8TU8XY=
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
golang.org/x/crypto v0.15.0 h1:frVn1TEaCEaZcn3Tmd7Y2b5KKPaZ+I32Q2OA3kYp5TA=
golang.org/x/crypto v0.15.0/go.mod h1:4ChreQoLWfG3xLDer1WdlH5NdlQ3+mwnQq1YTKY+72g=
golang.org/x/sys v0.14.0 h1:Vz7Qs629MkJkGyHxUlRHizWJRG2j8fbQKjELVSNhy7Q=
golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=

261
main.go
View File

@@ -1,261 +0,0 @@
/*
Copyright © 2022-2025 Thomas von Dein
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package main
import (
"fmt"
"log"
"os"
"path/filepath"
"strings"
"time"
"github.com/JojiiOfficial/shred"
flag "github.com/spf13/pflag"
)
const VERSION string = "0.0.4"
const Usage string = `This is gowipe - destruct files in a non-recoverable way.
Usage: gowipe [-rcvz] <file|directory>...
Options:
-r --recursive Delete <dir> recursively
-c --count <num> Overwrite files <num> times
-m --mode <mode> Use <mode> for overwriting (or use -E, -S, -M, -Z)
-n --nodelete Do not delete files after overwriting
-N --norename Do not rename the files
-v --verbose Verbose output
-V --version Show program version
-h --help Show usage
Available modes:
zero Overwrite with zeroes (-Z)
math Overwrite with math random bytes (-M)
secure Overwrite with secure random bytes (default) (-S)
encrypt Overwrite with ChaCha2Poly1305 encryption (most secure) (-E)`
type Conf struct {
mode string
count int
recurse bool
nodelete bool
norename bool
verbose bool
files int
dirs int
size int64
}
func main() {
showversion := false
showhelp := false
optzero := false
optsecure := false
optmath := false
optencrypt := false
c := Conf{
verbose: false,
mode: `secure`,
count: 30,
recurse: false,
nodelete: false,
norename: false,
}
flag.BoolVarP(&showversion, "version", "V", showversion, "show version")
flag.BoolVarP(&showhelp, "help", "h", showversion, "show help")
flag.BoolVarP(&c.verbose, "verbose", "v", c.verbose, "verbose")
flag.StringVarP(&c.mode, "mode", "m", c.mode, "overwrite mode")
flag.BoolVarP(&optzero, "zero", "Z", optzero, "zero mode")
flag.BoolVarP(&optsecure, "secure", "S", optsecure, "secure mode")
flag.BoolVarP(&optmath, "math", "M", optmath, "math mode")
flag.BoolVarP(&optencrypt, "encrypt", "E", optmath, "encrypt mode")
flag.BoolVarP(&c.recurse, "recursive", "r", c.recurse, "recursive")
flag.BoolVarP(&c.nodelete, "nodelete", "n", c.nodelete, "don't delete")
flag.BoolVarP(&c.norename, "norename", "N", c.norename, "don't rename")
flag.IntVarP(&c.count, "count", "c", c.count, "overwrite count")
flag.Parse()
if showversion {
fmt.Printf("This is gowipe version %s\n", VERSION)
os.Exit(0)
}
if showhelp {
fmt.Println(Usage)
os.Exit(0)
}
if len(flag.Args()) == 0 {
fmt.Println(Usage)
os.Exit(0)
}
var option shred.WriteOptions
if optzero {
option = shred.WriteZeros
}
if optmath {
option = shred.WriteRand
}
if optsecure {
option = shred.WriteRandSecure
}
if optencrypt {
c.mode = "encrypt"
}
switch c.mode {
case `secure`:
option = shred.WriteRandSecure
case `math`:
option = shred.WriteRand
case `zero`:
option = shred.WriteZeros
case `encrypt`:
optencrypt = true
default:
option = shred.WriteRandSecure
}
shredder := shred.Shredder{}
shredconf := shred.NewShredderConf(&shredder, option, c.count, !c.nodelete)
start := time.Now()
for _, file := range flag.Args() {
Wipe(file, &c, shredconf)
}
if c.verbose {
fmt.Println()
fmt.Printf(" Dirs wiped: %d\n", c.dirs)
fmt.Printf(" Files wiped: %d\n", c.files)
fmt.Printf("Bytes deleted: %d\n", c.size)
fmt.Printf(" Time elapsed: %s\n", time.Since(start))
fmt.Printf(" Overwritten: %d times\n", c.count)
fmt.Printf(" Wipe mode: %s\n", c.mode)
fmt.Printf(" Recurse dirs: %t\n", c.recurse)
}
}
func Wipe(file string, c *Conf, wiper *shred.ShredderConf) {
if info, err := os.Stat(file); err == nil {
if info.IsDir() {
if !c.recurse {
fmt.Printf("-r not set, ignoring directory %s\n", file)
return
}
files, err := os.ReadDir(file)
if err != nil {
log.Fatal(err)
}
for _, entry := range files {
Wipe(filepath.Join(file, entry.Name()), c, wiper)
}
// delete dir
if !c.nodelete {
err = os.Remove(Rename(file, c))
if err != nil {
log.Fatal(err)
}
c.dirs++
}
} else {
if c.mode == "encrypt" {
if err := Encrypt(c, file); err != nil {
log.Fatal(err)
}
// delete encrypted file
if !c.nodelete {
err = os.Remove(Rename(file, c))
if err != nil {
log.Fatal(err)
}
}
} else {
if err := wiper.ShredFile(Rename(file, c)); err != nil {
log.Fatal(err)
}
}
c.size += info.Size()
}
if c.verbose {
fmt.Printf("Wiped %s (%d bytes)\n", file, info.Size())
}
c.files++
} else {
if os.IsNotExist(err) {
fmt.Printf("No such file or directory: %s\n", file)
} else {
fmt.Println(err)
}
os.Exit(1)
}
}
func Rename(file string, c *Conf) string {
var newname string
dir := filepath.Dir(file)
base := filepath.Base(file)
length := len(base)
for i := 0; i < c.count; i++ {
for {
switch c.mode {
case `secure`, `encrypt`:
new, err := GenerateSecureRandomString(length)
if err != nil {
log.Fatal(err)
}
newname = new
case `math`:
newname = GenerateMathRandomString(length)
case `zero`:
newname = strings.Repeat("0", length)
}
if newname != base {
break
}
}
err := os.Rename(filepath.Join(dir, base), filepath.Join(dir, newname))
if err != nil {
log.Fatal(err)
}
base = newname
}
return filepath.Join(dir, newname)
}

View File

@@ -1,65 +0,0 @@
#!/bin/bash
# Copyright © 2022-2025 Thomas von Dein
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
# get list with: go tool dist list
DIST="darwin/amd64
freebsd/amd64
linux/amd64
netbsd/amd64
openbsd/amd64
windows/amd64"
tool="$1"
version="$2"
if test -z "$version"; then
echo "Usage: $0 <tool name> <release version>"
exit 1
fi
rm -rf releases
mkdir -p releases
for D in $DIST; do
os=${D/\/*/}
arch=${D/*\//}
binfile="releases/${tool}-${os}-${arch}-${version}"
tardir="${tool}-${os}-${arch}-${version}"
tarfile="releases/${tool}-${os}-${arch}-${version}.tar.gz"
set -x
GOOS=${os} GOARCH=${arch} go build -o ${binfile} -ldflags "-X 'github.com/tlinden/tablizer/cfg.VERSION=${version}'"
mkdir -p ${tardir}
cp ${binfile} README.md LICENSE ${tardir}/
echo 'tool = gowipe
PREFIX = /usr/local
UID = root
GID = 0
install:
install -d -o $(UID) -g $(GID) $(PREFIX)/bin
install -d -o $(UID) -g $(GID) $(PREFIX)/man/man1
install -o $(UID) -g $(GID) -m 555 $(tool) $(PREFIX)/sbin/
install -o $(UID) -g $(GID) -m 444 $(tool).1 $(PREFIX)/man/man1/' > ${tardir}/Makefile
tar cpzf ${tarfile} ${tardir}
sha256sum ${binfile} | cut -d' ' -f1 > ${binfile}.sha256
sha256sum ${tarfile} | cut -d' ' -f1 > ${tarfile}.sha256
rm -rf ${tardir}
set +x
done