PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : One-Time Pad implementierung, Kommentare?



Maledictus
13-03-2004, 11:32
Hi Leute,
ich hab aus lauter Spass an der Freude mal dieses kleine Programm geschmiedet.
Man kann es benutzen um Daten zu verschlüsseln.
Vorausgesetzt die Schlüsseldatei ist mindestens genauso groß wie die zu verschlüsselnden Daten, nennt man diese Verschlüsselungsart One-Time-Pad. Es ist die einzige Verschlüsselungsmethode, die mathematisch beweisbar 100% sicher ist. (Natürlich nur solange niemand den Schlüssel in die Hände bekommt :) )

Lasst mal euren Senf dazu ab, was meint ihr ist gut, was nicht so gut?
Benutzen dürft ihr es natürlich auch, steht schliesslich unter Beer-Ware Lizenz ;)

gruss
Male

P.S. leider hab ich die formatierung etwas zerschossen :(



/*
* ----------------------------------------------------------------------------
* "THE BEER-WARE LICENSE" (Revision 42):
* <skalla.raabjorn@gmx.de> wrote this file. As long as you retain this notice you
* can do whatever you want with this stuff. If we meet some day, and you think
* this stuff is worth it, you can buy me a beer in return. Skalla
* ----------------------------------------------------------------------------
*/

#include <stdio.h>
#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h>
#include <err.h>
#include <sys/stat.h>
#include <sys/param.h>
#include <sys/mman.h>

int
main(int argc, char *argv[])
{

int keyFile;
int inputBufferOffset = 0;
int inputBufferIndex = 0;
int keyLength = 0;
int keyIndex = 0;

char *inputBuffer = NULL;
char *keyBuffer = NULL;

ssize_t nRead, nWrite;
size_t inputBufferSize;

struct stat fileInfo;

if (argc != 2) {
errx(EXIT_FAILURE, "usage: xor keyfile");
}

/* read the keyfile in keyBuffer */
keyFile = open(argv[1], O_RDONLY);
if (keyFile < 0) {
err(EXIT_FAILURE, "keyfile");
}
if (fstat(keyFile, &fileInfo)) {
err(EXIT_FAILURE, "keyfile");
}
keyLength = fileInfo.st_size;
if (keyLength < 1) {
errx(EXIT_FAILURE, "keyfile size is zero");
}
keyBuffer = mmap(0, keyLength, PROT_READ, 0, keyFile, 0);
if (keyBuffer == MAP_FAILED) {
err(EXIT_FAILURE, "keyBuffer");
}
close(keyFile);

if (fstat(STDOUT_FILENO, &fileInfo)) {
err(EXIT_FAILURE, "stdout");
}
inputBufferSize = MAX(fileInfo.st_blksize, 1024);
inputBuffer = malloc(inputBufferSize);
if (inputBuffer == NULL) {
err(EXIT_FAILURE, "buffer");
}
while ((nRead = read(STDIN_FILENO, inputBuffer, inputBufferSize)) > 0) {

/* xor'ing inputBuffer with keyBuffer */
for (inputBufferIndex = 0; inputBufferIndex < nRead; inputBufferIndex++) {
inputBuffer[inputBufferIndex] ^= keyBuffer[keyIndex];
keyIndex++;
if (keyIndex == keyLength) {
keyIndex = 0;
}
}

/* writing the inputBuffer to stdout */
for (inputBufferOffset = 0; nRead; nRead -= nWrite, inputBufferOffset += nWrite) {
if ((nWrite = write(STDOUT_FILENO, inputBuffer + inputBufferOffset, nRead)) < 0) {
err(EXIT_FAILURE, "stdout");
}
}
}
if (nRead < 0) {
errx(EXIT_FAILURE, "stdin");
}
if (munmap(keyBuffer, keyLength)) {
err(EXIT_FAILURE, "keyBuffer");
}
return EXIT_SUCCESS;
}

wraith
13-03-2004, 12:25
Original geschrieben von Maledictus

Lasst mal euren Senf dazu ab, was meint ihr ist gut, was nicht so gut?

-Du gibst den Speicher von inputBuffer nicht wieder frei.
-Das hätte man doch komplett in Standard C schreiben können für maximale Portabilität :)
-Gut,du benutzt die einzigen beiden konformen Rückgabewerte von main.

RapidMax
13-03-2004, 14:14
Ui, um grössere Dateien zu verschlüsseln, musst du aber heftig in die Tastatur hauen und die Maus herumschubsen, um genügend Entropie in /dev/random zu bekommen ;) Alternativ könnte man auch einen Hardware-Random-Generator verwenden...

Gruss, Andy

bischi
13-03-2004, 15:24
Und den Schlüssel unbedingt nur einmal brauchen: Die USA hatten zu Zeit des kalten Krieges manche Schlüssel zwei mal gebraucht - viele der Nachrichten wurden vom KGB entschlüsselt!

MfG Bischi

nobody0
15-03-2004, 11:50
Ich hatte sowas mal gemacht als ich jung war:

http://www.random.linux-site.net/files/exor.c

Es ist nicht ganz optimal, weil nur byteweise exort wird, obwohl auf PC/MAC bis kurz vor'm Ende 32- bzw. 64-Bit-Blöcke optimal wären, aber es funktionert richtig.

Hardware, Patent, Marken usw. hatte ich auch mal dazu gemacht:

http://www.true-random.com/

Maledictus
15-03-2004, 20:54
Original geschrieben von wraith
-Du gibst den Speicher von inputBuffer nicht wieder frei.

danke, hab ich doch glatt vergessen, hat zwar keine auswirkungen, gehört aber zum guten stil


-Das hätte man doch komplett in Standard C schreiben können für maximale Portabilität :)

gehört für manche auch zum guten stil, aber mir ist das in diesem fall nicht so wichtig, da benutz ich lieber schöne sachen wie mmap :)


-Gut,du benutzt die einzigen beiden konformen Rückgabewerte von main.
natürlich

@nobody0
deine implementierung ist auch nicht schlecht, aber warum fängst du alle signale ab?

int statt char wäre schon besser für die schleife, werde ich vielleicht noch ändern.
bin nur im moment zu beschäftigt.
jemand auf die schnelle ne idee, wie man das problem löst, das der eingabe/schlüssel-puffer ja nicht notwendigerweise durch 4 bzw. 8 teilbar ist?

gruss und danke
Male

nobody0
16-03-2004, 21:42
Original geschrieben von Maledictus

@nobody0
deine implementierung ist auch nicht schlecht, aber warum fängst du alle signale ab?


Einfach so; man kann ja irgenwas in den Signal-Handler eintragen, da ist man flexibel. Beispielsweise mit nohup; so kann man eine Quit message in nohup.out schreiben.



Original geschrieben von Maledictus

int statt char wäre schon besser für die schleife, werde ich vielleicht noch ändern.
bin nur im moment zu beschäftigt.
jemand auf die schnelle ne idee, wie man das problem löst, das der eingabe/schlüssel-puffer ja nicht notwendigerweise durch 4 bzw. 8 teilbar ist?


Ganz einfach nach dem Geldwechsel-Algorithmus (größte zuerst):
Zuerst
sizeof(int) * (Dateigröße)/sizeof(int)
und dann den Rest von (Dateigröße)%sizeof(int).
Allerdings ist int auch auf 64-Bit-Prozessoren nur 32 Bit groß (zumind. beim gcc), so dass man es besser so macht:



#if defined(__msp430__)
# define BLOCKSIZE 2
#endif
#if defined(__arm3__)
# define BLOCKSIZE 3
#endif
#if defined(__i386__) || defined(__i486__) || defined(__i586__) || defined(__i686__)...
# define BLOCKSIZE 4
#endif
#if defined(__sparc64__) || defined(__amd64__) ...
# define BLOCKSIZE 8
#endif


// default
#ifndef BLOCKSIZE
# define BLOCKSIZE 1
#endif


Zur Dateigrößenbestimmung findet man ja auch etwas im Forum. Allgemein bleibt nur Die Datei bis zum Ende zu lesen, aber ich vermute, dass es Allgemein mittels bsearch schnell machbar ist, also für 1 GB nur 10 Lese-Zugriffe.

RapidMax
17-03-2004, 21:35
Original geschrieben von nobody0
Hardware, Patent, Marken usw. hatte ich auch mal dazu gemacht:

http://www.true-random.com/
Das ist auf deinem Mist gewachsen? Ich hatte vor einem Jahr eine Projektarbeit zum Thema: True Random Number Generator for Embedded Systems gemacht. Dabei bin ich u.a. natürlich auf auf die erwähnte Seite gestossen. (Link (http://home.zhwin.ch/~sna/PA/PA1_2003_Sna02.pdf))

Gruss, Andy

nobody0
18-03-2004, 01:34
Original geschrieben von RapidMax
Das ist auf deinem Mist gewachsen? Ich hatte vor einem Jahr eine Projektarbeit zum Thema: True Random Number Generator for Embedded Systems gemacht. Dabei bin ich u.a. natürlich auf auf die erwähnte Seite gestossen. (Link (http://home.zhwin.ch/~sna/PA/PA1_2003_Sna02.pdf))

Gruss, Andy

Das ist nicht von mir; sowas wäre mir zu langsam.
Meine "Kisten" liefern mind. 1 MBit/s und bis zu 160 MByte/s, wobei ich damit 2001 aufgehört habe.

Ich habe dazu diverse Messungen gemacht, unter anderem mit einem Frequenzanalysator, um viele theoretisch zu erwartenende Eigenschaften auch wirklich real zu messen.

Zu den Tests gehört beispielsweise der Coupon Collector Test, der zählt wie viele 32-Bit-Zahlen produziert werden bis alle Zahlen von 0x00000000 bis 0xffffffff mindestens einmal ausgegeben werden; das dauert ein paar Stunden (1 Wochenende) und erfordert im RAM ein Array von 2^(32) Bit. Und die Berechnung des theoretisch zu erwartenden Werts ist nicht trivial.

RapidMax
18-03-2004, 21:08
Nicht schlecht, der Test, vorausgesetzt man hat die Hardware ;)
Wir hatten dazumal den Universal Statistical Test von Ueli Maurer eingesetzt: http://www.crypto.ethz.ch/research/srt/

Gruss, Andy

nobody0
21-03-2004, 21:55
Aha.
Naja, ich habe auch Fips Pup Tests, oder wie die hießen, implementiert, aber die sind eigentlich ein Witz; die testen nur 10.000 Bit bis 10.000 Byte; da fängt Statistik gerade an.
Deshalb verwenden die Diehard-Tests mind. 10 Mio Bytes, aber eigentlich kann man erst ab einigen dutzend Gigabyte richtig testen, beispielsweise mit dem 32-Bit Coupon Collector Test, den ich erwähnte.

Als groben Test kann man aber schon Komprimierung z. B. mit zip oder bzip2 verwenden: Wenn sich (binäre) Zufallszahlen komprimieren lassen ist da ein deutliches und einfaches Muster drinn.