fish

- file shredder and crypter for Darwin, Solaris and Linux (WARNING: might be deemed subversive in some places)

Short description

fish [-cdefmnqsyYzvVhi] file name(s)

fish overwrites files repeatedly with shrewdly chosen data before they are (optionally) deleted. The point of this action is making the retrieval of the file's original content expensive, which might be a good idea when it's information one does not want to share.
If file name is a directory, or the list of filename arguments contains one such, the whole file tree underneath the directory gets overwritten (and, if so desired, deleted).

If file name is "-", then fish en/decrypts from stdin to stdout.

Options:
-c N: (cache) disk drive cache size is N MB
-d: (delete) files are deleted after overwriting
-e: (empty) overwrite empty storage, too
-f File: overwrite with File in last pass
-m: (modest) sets priority to lower value
-n: (noaction) files remain untouched, write to /dev/null
-q N: (quick) overwrite files just N times
-s: (silent) no console messages on stdout or stderr
-y: (crypt) obfuscate/decipher files using one-time pad
-Y: (CRYPT) en/decrypt files
-z: (zero) write zeroes in last pass to hide shredding
-v: (verbose) generate messages to show progress
-V: (very verbose) generate more messages
-h: (help) generate a short usage description
-i: (info) print out path of secret key if used

When fish -[yY] is used for obfuscation, and there exists a file called ".fish_key" (or whatever the environment variable _FISH_KEY says) in the current directory or the user's home directory, then the contents of this file are used to modify the random number generator (current overrides home directory!). An attempt to decipher a file so obfuscated requires a bit-exact copy of the ".fish_key" file to reside in the appropriate directory of the decrypting user's file tree.
If _FISH_KEY contains the string "stdin" then the secret key is retrieved from stdin (e.g. keyboard input). NOT AVAILABLE IN LINUX

A few desultory words of explanation:

File shredding utilities seem to be all the rage these days, what with folks selling used hard drives on eBay, and interesting data being stored on such drives...
I should like to point out a few things that distinguish fish from a couple of other file shredders:
First, it is decently fast on big files (as fast as the disk drive will go). On a G4 or G5 Mac (sigh). Yes, there IS a use for those AltiVec registers after all.
Second, it doesn't do a sloppy job. It's good at shredding small files, which might escape their fate by the workings of a large hard drive cache, and it sort of shreds the file names as well. And, after I had learned that Mac resource forks need special attention, they get that, too. Btw, if so desired, all the free space on a device can be shredded, too - although this may take days (but it has the added benefit of forcing the file system to overwrite files in place)..
Third, it is command-line, so it may be used in shell scripts like this one:
#!/bin/csh
#this script cleans out all my trashes (including mounted external drives)
foreach i ( ~/.Trash /Volumes/*?/.Trashes/$uid )
chdir $i
fish -dmz * &
end
exit 0

or, for the select few who prefer (ba)sh:

#!/bin/sh
for directory in ${HOME}/.Trash /Volumes/*?/.Trashes/${UID}; do
#assuming the fish resides in the user's private file tree
${HOME}/bin/fish -dmzc 8 ${directory}/* &
#note: the -c 8 switch is only necessary if you have a drive with 8 MB cache
done
exit 0

And 4th, I can show off my vectorized Kirkpatrick-Stoll pseudo-random number generator...
Last and least, I could not care less if Windows users can delete their files good and proper, so I did not attempt to make the code windows-friendly.

NOTE: The possession (or, god forbid, the use) of this software might be regarded as subversive or even illegal in some countries. Therefore, I provide the programme strictly for educational purposes.

HINWEIS: Der Besitz (oder gar der Gebrauch) dieser Software wird möglicherweise in manchen Ländern als subversiv oder sogar gesetzwidrig eingestuft. Deshalb stelle ich dieses Programm ausschließlich als Anschauungsmaterial zur Verfügung.

Kurzbeschreibung:

fish [-cdefmnqsyYzvVhi] Dateiname(n)

fish überschreibt Dateien mehrfach mit pfiffig gewählten Daten, bevor es sie (optional) löscht. Sinn dieser Aktion ist, die Wiederherstellung der Inhalte zu erschweren, z.B. bei vertraulich zu behandelnden Informationen.
Ist Dateiname ein Verzeichnis, bzw. enthält die Liste der Dateinamen ein solches, wird der gesamte darunterliegende Dateibaum überschrieben und ggf. gelöscht.

Ist Dateiname = "-", ver/entschleiert fish von stdin nach stdout.

Optionen:
-c N: (cache) Cache size ist N MB
-d: (delete) Datei(en) nach dem Überschreiben löschen
-e: (empty) Leeren Speicherplatz im Filesystem auch überschreiben
-f File: im letzten Durchlauf mit File überschreiben
-m: (modest) setzt Priorität auf niedrigen Wert
-n: (noaction) Datei(en) nicht verändern, alles nach /dev/null
-q N: (quick) Dateien nur N mal überschreiben
-s: (silent) keine Meldungen
-y: (crypt) Dateien mit Wegwerf-Schlüssel ent/verschleiern
-Y: (CRYPT) Dateien ent/verschlüsseln
-z: (zero) im letzten Durchlauf Datei mit Nullen überschreiben
-v: (verbose) Fortschritt darstellen
-V: (very verbose) etwas detaillierter darstellen
-h: (help) kurze Benutzerführung ausgeben
-i: (info) Pfad des verwendeten Geheimschlüssels anzeigen

Wenn fish -[yY] für die Verschleierung einer Datei benutzt wird, und im aktuellen oder Heim-Verzeichnis des Benutzers befindet sich eine Datei ".fish_key" (bzw. die in der Umgebungsvariablen _FISH_KEY bezeichnete Datei), dann wird mit dem Inhalt dieser Datei der Zufallsgenerator modifiziert. Die Datei kann dann nur entschleiert werden, wenn sich eine exakte Kopie der zum Verschleiern benutzten Schlüssel-Datei ".fish_key" im aktuellen oder im Heim-Verzeichnis des Anwenders befindet.
Wenn in _FISH_KEY die Zeichenkette "stdin" steht, wird der Geheimschlüssel von stdin (z.B. Tastatur) eingelesen. GEHT NICHT IN LINUX

inspired by/inspiriert von :

Peter Claus Gutmann, Dept.CS,University of Auckland
( pgut001@cs.auckland.ac.nz )
"Secure Deletion of Data from Magnetic and Solid-State Memory",
Sixth USENIX Security Symposion Proceedings,
San Jose, California, July 22-25, 1996

NOTE: if you read the paper, don't skip the epilogue ;->

The pseudo-random number generator used here is based upon:
Der verwendete Pseudo-Zufallszahlengenerator basiert auf :

Kirkpatrick,S., and E.Stoll,
"A Very Fast Shift-Register Sequence Random Number Generator",
Journal of Computational Physics, V.40, pp. 517-526, 1981

NOTA BENE : fish does not work reliably in non-local, distributed (or
journaled ?) file systems, because it assumes direct access
to a local storage device and overwriting in place. Encrypted
file systems are not so good, either. I dunno. And fish doesn't
shred files which the user has no write privileges for.

HINWEIS: fish ist in Filesystemen wie AFS oder einigen NFS-Versionen
nicht sehr wirksam, da nur lokale Kopien der Dateien über-
schrieben werden. Und Dateien, für die der Anwender keine
Schreibrechte hat, überschreibt fish auch nicht.

Das Programm ist unter Solaris, Darwin und Linux verwendbar. In Darwin wird es mit "gcc -O3 -faltivec fish.c" übersetzt.
fish runs in Solaris, Darwin and Linux. In Darwin, compile with "gcc -faltivec -O3"




Note:
I learned about srm in 2004, when the shredder was almost finished; I found a few useful ideas there. I did not, however, try to make fish's usage syntax like rm(1)'s, because IMHO the shredder should never ever be used casually, but always with extreme prejudice.
I do admit that fish's code is much more complex than srm's, but I swear it's not bloated.



TODO: further improve AltiVec code: make parallel vector ops
- - - Make it work on USB sticks, too!

Benötigte

swac

- Feld kopieren und dabei Bytes vertauschen (swap and copy)

Kurzbeschreibung:

void *swac(to,from,ln,size)
void *to,*from; size_t ln,size;

swac kopiert das Feld from in das Feld to und vertauscht dabei die Bytes, sodaß aus "BIG ENDIAN" "LITTLE ENDIAN" wird und umgekehrt.
from und to können vom Typ short oder long sein; die Wortlänge wird mit size spezifiziert. Es werden ln Worte bearbeitet. Wird to == NULL übergeben, setzt swac to = from.
Der Zeiger auf den Zielpuffer wird als Funktionswert zurückgegeben. Falls sz einen ungeeigneten Wert hat, gibt swac NULL zurück.

Es werden Wortlängen ( sz) 1 (char), 2 (short), 4 (long) und 8 (long long) unterstützt. Wenn sz nicht mit dem Variablentyp übereinstimmt, auf den from und to zeigen, gibt es Alignment-Fehler.

Benötigte Unterprogramme: memcpy (libc)

smp_rand - simpler one-shot Zufallsgenerator

Kurzbeschreibung:

int32_t smp_rand()

smp_rand liefert bei jedem Aufruf eine andere 32-bit-Integer-Zahl zurück, vorausgesetzt, der letzte Aufruf liegt um mindestens einen System Clock Tick zurück. Da es nur einmal pro Programmstart aufgerufen wird, kann man getrost davon ausgehen.
Benötigte Unterprogramme: gettimeofday,getpid (libc); bitrv (hier)

r_init

- Initialization: select sequence and range

Kurzbeschreibung:

int32_t r_init(int32_t seed)

The ring buffer rbuff is allocated and initialized with a sequence of pseudo-random numbers. These numbers are created from seed with a modified multiplicative convergence algorithm. Then the bit columns of the ring buffer are orthogonalized.
The choice of seed influences the result space of the random number generator proper: seed < 0 enables the generation of signed 32-bit numbers, seed >= 0 will only generate positive numbers.
Each of the possible 2^32-1 values for seed determines a distinct, reproducible sequence of pseudo-random numbers. The sequences have a period length of 2^250-1 (about 10^75), which is good enough for the shredder.
And it is good enough for the crypter. So there.

Der Ringpuffer rbuff wird bereitgestellt und mit einer Folge von Pseudo-Zufallszahlen vorbesetzt. Diese Zahlen werden aus seed mit Hilfe eines modifizierten Multiplikativ-Konvergenz-Verfahrens gewonnen. Dann wird dafür gesorgt, daß die Spalten des Ringpuffers bitweise orthogonal sind. Die Auswahl von seed beeinflußt den Wertebereich der später ausgeführten eigentlichen Zufallsgeneratoren: für seed < 0 liefern sie 32bit-Zahlen mit und ohne Vorzeichenbit (positiv und negativ), für seed >= 0 nur 32bit-Zahlen ohne Vorzeichenbit (positiv).
Jeder der 2^32-1 möglichen Werte für seed bestimmt eine eigene, reproduzierbare, von allen anderen möglichen Sequenzen unterschiedliche Pseudo-Zufallszahlen-Sequenz. Die Periode einer Sequenz ist 2^250-1 (ungefähr 10^75 oder eine Duodezilliarde), was für den Shredder ausreichend gut ist.

Zusätzliche Schnittstelle:

void r_kimp(u_char key,size_t klen)

r_kimp importiert den Schlüssel key der Länge klen Bytes. Dieser modifiziert die Initialisierung des Ringpuffers in reproduzierbarer Weise.

r_vect

- make a vector of random bytes


Kurzbeschreibung:

int32_t r_vect(u_char *vect,int leng)

r_vect füllt einen Puffer vect mit leng pseudo-zufälligen Bytes. Die Zahlen werden als 32bit-Integers erzeugt, deshalb muß der Puffer auf einer Wortgrenze beginnen.
NOTA BENE: r_vect ist NICHT thread-safe !

Der verwendete Algorithmus ist eine Variante des "distributed feedback" Generators: Die Pseudo-Zufallszahl entsteht aus einer XOR-Operation mit den um 103 bzw. 250 Schritte zurückliegenden Pseudo-Zufallszahlen. Mit den hier verwendeten Offsets 103 und 250 verhält sich der Generator besonders günstig bezüglich Periodenlänge und statistischer Eigenschaften der erzeugten Zahlenfolge.

Diese Implementierung verwendet auf der Powerpc-Architektur die ggf. vorhandenen Vektorregister, was die Geschwindigkeit merklich erhöht. Allerdings muß dann vect auf einer durch 16 teilbaren Adresse beginnen. Es gibt überhaupt gut Spaß mit Alignment :-P