mirror of
https://codeberg.org/scip/gowipe.git
synced 2025-12-16 20:20:58 +01:00
Compare commits
16 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| f7aabc75be | |||
| 88febcf664 | |||
|
|
8dc372a222 | ||
| a90d6e5c3c | |||
| ed4ad2340b | |||
| f7b0cfa905 | |||
| b914fdfcdf | |||
| f2116f39ef | |||
| 5907c5b2be | |||
| 8dbdebee46 | |||
| daabdc5c9b | |||
| f4b1ba5863 | |||
| eaca5ad181 | |||
| 5ca1be594b | |||
| aa03ba5281 | |||
| 74c801b914 |
65
.goreleaser.yaml
Normal file
65
.goreleaser.yaml
Normal file
@@ -0,0 +1,65 @@
|
||||
# vim: set ts=2 sw=2 tw=0 fo=cnqoj
|
||||
|
||||
version: 2
|
||||
|
||||
before:
|
||||
hooks:
|
||||
- go mod tidy
|
||||
|
||||
gitea_urls:
|
||||
api: https://codeberg.org/api/v1
|
||||
download: https://codeberg.org
|
||||
|
||||
builds:
|
||||
- env:
|
||||
- CGO_ENABLED=0
|
||||
goos:
|
||||
- linux
|
||||
- freebsd
|
||||
|
||||
archives:
|
||||
- formats: [tar.gz]
|
||||
# this name template makes the OS and Arch compatible with the results of `uname`.
|
||||
name_template: >-
|
||||
{{ .ProjectName }}_
|
||||
{{- title .Os }}_
|
||||
{{- if eq .Arch "amd64" }}x86_64
|
||||
{{- else if eq .Arch "386" }}i386
|
||||
{{- else }}{{ .Arch }}{{ end }}
|
||||
{{- if .Arm }}v{{ .Arm }}{{ end }}_{{ .Tag }}
|
||||
# use zip for windows archives
|
||||
format_overrides:
|
||||
- goos: windows
|
||||
formats: [zip]
|
||||
- goos: linux
|
||||
formats: [tar.gz,binary]
|
||||
files:
|
||||
- src: "*.md"
|
||||
strip_parent: true
|
||||
- src: Makefile.dist
|
||||
dst: Makefile
|
||||
wrap_in_directory: true
|
||||
|
||||
changelog:
|
||||
sort: asc
|
||||
filters:
|
||||
exclude:
|
||||
- "^docs:"
|
||||
- "^test:"
|
||||
groups:
|
||||
- title: Improved
|
||||
regexp: '^.*?(feat|add|new)(\([[:word:]]+\))??!?:.+$'
|
||||
order: 0
|
||||
- title: Fixed
|
||||
regexp: '^.*?(bug|fix)(\([[:word:]]+\))??!?:.+$'
|
||||
order: 1
|
||||
- title: Changed
|
||||
order: 999
|
||||
|
||||
release:
|
||||
header: "# Release Notes"
|
||||
footer: >-
|
||||
|
||||
---
|
||||
|
||||
Full Changelog: [{{ .PreviousTag }}...{{ .Tag }}](https://codeberg.org/scip/gowipe/compare/{{ .PreviousTag }}...{{ .Tag }})
|
||||
36
.woodpecker/build.yaml
Normal file
36
.woodpecker/build.yaml
Normal file
@@ -0,0 +1,36 @@
|
||||
matrix:
|
||||
platform:
|
||||
- linux/amd64
|
||||
goversion:
|
||||
- 1.24
|
||||
|
||||
labels:
|
||||
platform: ${platform}
|
||||
|
||||
steps:
|
||||
build:
|
||||
when:
|
||||
event: [push]
|
||||
image: golang:${goversion}
|
||||
commands:
|
||||
- go get
|
||||
- go build
|
||||
|
||||
linter:
|
||||
when:
|
||||
event: [push]
|
||||
image: golang:${goversion}
|
||||
commands:
|
||||
- curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/HEAD/install.sh | sh -s -- -b $(go env GOPATH)/bin v2.5.0
|
||||
- golangci-lint --version
|
||||
- golangci-lint run ./...
|
||||
depends_on: [build]
|
||||
|
||||
test:
|
||||
when:
|
||||
event: [push]
|
||||
image: golang:${goversion}
|
||||
commands:
|
||||
- go get
|
||||
- go test -v -cover
|
||||
depends_on: [build,linter]
|
||||
15
.woodpecker/release.yaml
Normal file
15
.woodpecker/release.yaml
Normal file
@@ -0,0 +1,15 @@
|
||||
# build release
|
||||
|
||||
labels:
|
||||
platform: linux/amd64
|
||||
|
||||
steps:
|
||||
goreleaser:
|
||||
image: goreleaser/goreleaser
|
||||
when:
|
||||
event: [tag]
|
||||
environment:
|
||||
GITEA_TOKEN:
|
||||
from_secret: DEPLOY_TOKEN
|
||||
commands:
|
||||
- goreleaser release --clean --verbose
|
||||
4
Makefile
4
Makefile
@@ -55,8 +55,8 @@ goupdate:
|
||||
buildall:
|
||||
./mkrel.sh $(tool) $(VERSION)
|
||||
|
||||
release: buildall
|
||||
gh release create v$(VERSION) --generate-notes releases/*
|
||||
release:
|
||||
gh release create v$(VERSION) --generate-notes
|
||||
|
||||
show-versions: buildlocal
|
||||
@echo "### gowipe version:"
|
||||
|
||||
18
Makefile.dist
Normal file
18
Makefile.dist
Normal file
@@ -0,0 +1,18 @@
|
||||
# -*-make-*-
|
||||
|
||||
.PHONY: install all
|
||||
|
||||
tool = rpn
|
||||
PREFIX = /usr/local
|
||||
UID = root
|
||||
GID = 0
|
||||
|
||||
all:
|
||||
@echo "Type 'sudo make install' to install the tool."
|
||||
@echo "To change prefix, type 'sudo make install PREFIX=/opt'"
|
||||
|
||||
install:
|
||||
install -d -o $(UID) -g $(GID) $(PREFIX)/bin
|
||||
install -d -o $(UID) -g $(GID) $(PREFIX)/share/doc
|
||||
install -o $(UID) -g $(GID) -m 555 $(tool) $(PREFIX)/sbin/
|
||||
install -o $(UID) -g $(GID) -m 444 *.md $(PREFIX)/share/doc/
|
||||
57
README.md
57
README.md
@@ -1,5 +1,56 @@
|
||||
## gowipe - securely delete files and directories (not for SSD)
|
||||
|
||||
[](https://ci.codeberg.org/repos/15612)
|
||||
[](https://codeberg.org/scip/gowipe/raw/branch/main/LICENSE)
|
||||
[](https://goreportcard.com/report/codeberg.org/scip/gowipe)
|
||||
|
||||
## Description
|
||||
|
||||
`gowipe` is a simple self contained tool to securely wipe files and
|
||||
directories. By default it renames and overwrites files and
|
||||
directories 30 times and uses the `secure` mode, which uses strong
|
||||
random bytes for the overwriting process. Gowipe writes as much bytes
|
||||
into a file as its original size.
|
||||
|
||||
You can tweak mode and round numbers. Other modes are `zero`, which
|
||||
uses zeroes for overwriting (not recommended) or `encrypt` which
|
||||
encrypts the data using ChaCha20Poly1305 and a strong random key. This is the most
|
||||
secure but also to slowest mode.
|
||||
|
||||
Although you can use `gowipe` on SSD disks, it doesn't make much
|
||||
sense. To wipe such a disk you have to resort to other means. But you
|
||||
can savely use it on magnetic discs or usb drives.
|
||||
|
||||
Of course there are many other such tools available, this one is
|
||||
insofar special as you can download a pre-compiled binary without any
|
||||
library dependencies. This allows you to wipe files on systems, where
|
||||
you cannot install a wiper via some package management (such as
|
||||
appliance systems or vm's).
|
||||
|
||||
## Example
|
||||
|
||||
Overwrite the directory `vhs` recursively 50 times using strong
|
||||
encryption and verbose output:
|
||||
|
||||
```shell
|
||||
gowipe -c 50 -E -r -v vhs
|
||||
Wiped vhs/help.png (355011 bytes)
|
||||
Wiped vhs/rec.Dockerfile (348 bytes)
|
||||
Wiped vhs/rec.gif (3533338 bytes)
|
||||
Wiped vhs/rec.tape (852 bytes)
|
||||
Wiped vhs (4096 bytes)
|
||||
|
||||
Dirs wiped: 1
|
||||
Files wiped: 5
|
||||
Bytes deleted: 3889549
|
||||
Time elapsed: 426.286639ms
|
||||
Overwritten: 50 times
|
||||
Wipe mode: encrypt
|
||||
Recurse dirs: true
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
```
|
||||
Usage: gowipe [-rcvz] <file|directory>...
|
||||
|
||||
@@ -22,12 +73,12 @@ encrypt Overwrite with ChaCha2Poly1305 encryption (most secure) (-E)
|
||||
|
||||
## Getting help
|
||||
|
||||
Although I'm happy to hear from tablizer users in private email,
|
||||
Although I'm happy to hear from gowipe users in private email,
|
||||
that's the best way for me to forget to do something.
|
||||
|
||||
In order to report a bug, unexpected behavior, feature requests
|
||||
or to submit a patch, please open an issue on github:
|
||||
https://github.com/TLINDEN/gowipe/issues.
|
||||
https://codeberg.org/scip/gowipe/issues.
|
||||
|
||||
## Copyright and license
|
||||
|
||||
@@ -39,4 +90,4 @@ T.v.Dein <tom AT vondein DOT org>
|
||||
|
||||
## Project homepage
|
||||
|
||||
https://github.com/TLINDEN/gowipe
|
||||
https://codeberg.org/scip/gowipe
|
||||
|
||||
78
crypto.go
78
crypto.go
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
Copyright © 2022 Thomas von Dein
|
||||
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
|
||||
@@ -22,6 +22,7 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"math/big"
|
||||
mathrand "math/rand"
|
||||
"os"
|
||||
@@ -119,7 +120,7 @@ func GetRandomKey() ([]byte, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
salt, err := GenerateSecureRandomBytes(chapo.NonceSize)
|
||||
salt, err := GenerateSecureRandomBytes(chapo.NonceSizeX)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -141,7 +142,11 @@ func Encrypt(c *Conf, filename string) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer outfile.Close()
|
||||
defer func() {
|
||||
if err := outfile.Close(); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}()
|
||||
|
||||
key, err := GetRandomKey()
|
||||
if err != nil {
|
||||
@@ -156,11 +161,17 @@ func Encrypt(c *Conf, filename string) error {
|
||||
for i := 0; i < c.count; i++ {
|
||||
for {
|
||||
if size < chunkSize {
|
||||
EncryptChunk(aead, outfile, size)
|
||||
if err := EncryptChunk(aead, outfile, size); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
break
|
||||
}
|
||||
|
||||
EncryptChunk(aead, outfile, chunkSize)
|
||||
if err := EncryptChunk(aead, outfile, chunkSize); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
size = size - chunkSize
|
||||
|
||||
if size <= 0 {
|
||||
@@ -174,7 +185,7 @@ func Encrypt(c *Conf, filename string) error {
|
||||
|
||||
func EncryptChunk(aead cipher.AEAD, file *os.File, size int64) error {
|
||||
chunk := make([]byte, size)
|
||||
nonce, err := GenerateSecureRandomBytes(int(chapo.NonceSize))
|
||||
nonce, err := GenerateSecureRandomBytes(int(chapo.NonceSizeX))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -192,58 +203,3 @@ func EncryptChunk(aead cipher.AEAD, file *os.File, size int64) error {
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
/*
|
||||
func Encrypt(c *Conf, filename string) error {
|
||||
salt, err := GetRand(KeySize)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
salt1, err := GetRand(KeySize)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
outfile, err := os.OpenFile(filename, os.O_RDWR|os.O_CREATE, 0666)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer outfile.Close()
|
||||
|
||||
key := argon2.IDKey(salt1, salt, KeyTime, KeyMemory, KeyThreads, KeySize)
|
||||
|
||||
aead, err := chacha20poly1305.NewX(key)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
buf := make([]byte, chunkSize)
|
||||
ad_counter := 0 // associated data is a counter
|
||||
|
||||
for {
|
||||
if n > 0 {
|
||||
// Select a random nonce, and leave capacity for the ciphertext.
|
||||
nonce := make([]byte, aead.NonceSize(), aead.NonceSize()+n+aead.Overhead())
|
||||
if m, err := cryptorand.Read(nonce); err != nil || m != aead.NonceSize() {
|
||||
return err
|
||||
}
|
||||
|
||||
msg := buf[:n]
|
||||
// Encrypt the message and append the ciphertext to the nonce.
|
||||
encryptedMsg := aead.Seal(nonce, nonce, msg, []byte(string(ad_counter)))
|
||||
outfile.Write(encryptedMsg)
|
||||
ad_counter += 1
|
||||
}
|
||||
|
||||
if err == io.EOF {
|
||||
break
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
log.Println("Error when reading input file chunk :", err)
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
9
go.mod
9
go.mod
@@ -3,9 +3,12 @@ module gowipe
|
||||
go 1.20
|
||||
|
||||
require (
|
||||
github.com/JojiiOfficial/shred v1.2.1 // indirect
|
||||
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
|
||||
github.com/spf13/pflag v1.0.5 // indirect
|
||||
golang.org/x/crypto v0.15.0 // indirect
|
||||
golang.org/x/sys v0.14.0 // indirect
|
||||
)
|
||||
|
||||
59
main.go
59
main.go
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
Copyright © 2022 Thomas von Dein
|
||||
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
|
||||
@@ -18,17 +18,17 @@ package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/JojiiOfficial/shred"
|
||||
flag "github.com/spf13/pflag"
|
||||
)
|
||||
|
||||
const VERSION string = "0.0.2"
|
||||
const VERSION string = "0.0.4"
|
||||
const Usage string = `This is gowipe - destruct files in a non-recoverable way.
|
||||
|
||||
Usage: gowipe [-rcvz] <file|directory>...
|
||||
@@ -56,6 +56,9 @@ type Conf struct {
|
||||
nodelete bool
|
||||
norename bool
|
||||
verbose bool
|
||||
files int
|
||||
dirs int
|
||||
size int64
|
||||
}
|
||||
|
||||
func main() {
|
||||
@@ -84,7 +87,7 @@ func main() {
|
||||
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(&optmath, "encrypt", "E", optmath, "encrypt 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")
|
||||
@@ -139,21 +142,33 @@ func main() {
|
||||
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 := ioutil.ReadDir(file)
|
||||
files, err := os.ReadDir(file)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
@@ -162,28 +177,42 @@ func Wipe(file string, c *Conf, wiper *shred.ShredderConf) {
|
||||
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" {
|
||||
err := Encrypt(c, file)
|
||||
if err != nil {
|
||||
if err := Encrypt(c, file); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
Rename(file, c)
|
||||
// delete encrypted file
|
||||
if !c.nodelete {
|
||||
err = os.Remove(Rename(file, c))
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
wiper.ShredFile(Rename(file, c))
|
||||
if err := wiper.ShredFile(Rename(file, c)); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
c.size += info.Size()
|
||||
}
|
||||
|
||||
if c.verbose {
|
||||
fmt.Printf("Wiped %d times: %s\n", c.count, file)
|
||||
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)
|
||||
@@ -204,7 +233,7 @@ func Rename(file string, c *Conf) string {
|
||||
for i := 0; i < c.count; i++ {
|
||||
for {
|
||||
switch c.mode {
|
||||
case `secure`:
|
||||
case `secure`, `encrypt`:
|
||||
new, err := GenerateSecureRandomString(length)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
@@ -220,12 +249,6 @@ func Rename(file string, c *Conf) string {
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
if c.verbose {
|
||||
fmt.Printf("renaming %s/%s => %s/%s\n", dir, base, dir, newname)
|
||||
}
|
||||
*/
|
||||
|
||||
err := os.Rename(filepath.Join(dir, base), filepath.Join(dir, newname))
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
|
||||
6
mkrel.sh
6
mkrel.sh
@@ -1,6 +1,6 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Copyright © 2022 Thomas von Dein
|
||||
# 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
|
||||
@@ -43,10 +43,10 @@ for D in $DIST; do
|
||||
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}'"
|
||||
GOOS=${os} GOARCH=${arch} go build -o ${binfile} -ldflags "-X 'codeberg.org/scip/tablizer/cfg.VERSION=${version}'"
|
||||
mkdir -p ${tardir}
|
||||
cp ${binfile} README.md LICENSE ${tardir}/
|
||||
echo 'tool = tablizer
|
||||
echo 'tool = gowipe
|
||||
PREFIX = /usr/local
|
||||
UID = root
|
||||
GID = 0
|
||||
|
||||
Reference in New Issue
Block a user