diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1d3b10c --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +./bin \ No newline at end of file diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..aaa53e4 --- /dev/null +++ b/LICENSE @@ -0,0 +1,13 @@ +Copyright 2023 David Valin + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. \ No newline at end of file diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..d8ae558 --- /dev/null +++ b/Makefile @@ -0,0 +1,13 @@ +build: + @echo " - Building..." + @mkdir -p bin + @gcc -o bin/otp src/otp.c + @echo " - Built!" + @echo " - Testing..." + @sh test/otp.test.sh + @echo " - Tested!" + +install: + @echo " - Installing..." + @mv ./bin/otp /usr/local/bin/otp + @echo " - Installed! You can use "otp" now" diff --git a/README.md b/README.md new file mode 100644 index 0000000..5f202ed --- /dev/null +++ b/README.md @@ -0,0 +1,24 @@ +## One Time Pad "otp" command + +This program takes stdin, xor's it with a key file and outputs to stdout. +When it finishes it writes a new file containing the part of the key file that was not used, ending with ".next". When using one time pad, remember to never reuse the keys, that is why a new key file is created with the part that wasn't used. You should always remove the key that you have used once. + +### Tutorial + +[![YouTube](http://i.ytimg.com/vi/AE1kFnRsTuY/hqdefault.jpg)](https://www.youtube.com/watch?v=AE1kFnRsTuY) + +### Install + +* Build and test: `make` +* Install: `sudo make install` + +#### How to use it + +* Create a key file: `echo -n "mysupersecretkey" > key.txt` +* Encrypt using key: `echo -n "hello" | otp key.txt > cipher.txt` +* Decrypt using key: `cat cipher.txt | otp key.txt > plain.txt` + +#### Next key + +Everytime you run the command it will create a new file with the same name as the key file ending with ".next". You should never reuse keys once they are used (one time pad algorithm requirements), therefore you should remove the original key file and use the new key file generated next time. + diff --git a/diagram.png b/diagram.png new file mode 100644 index 0000000..19f221a Binary files /dev/null and b/diagram.png differ diff --git a/src/otp.c b/src/otp.c new file mode 100755 index 0000000..8d606b7 --- /dev/null +++ b/src/otp.c @@ -0,0 +1,81 @@ +#include +#include +#include +#include +#include +#include + +int min( int a, int b) {if (a cipher.txt\n decrypt\tcat cipher.txt | otp KEY_FILE.txt > plain.txt\n\n"; + if (argc == 1) { + puts(instructions); + exit(0); + } + + char outfileunused[1024]; + sprintf(outfileunused, argv[optind]); + time_t t = time(NULL); + struct tm tm = *localtime(&t); + sprintf(outfileunused+strlen(argv[optind]), ".%d-%02d-%02d_%02d:%02d:%02d.next", tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec); + + struct stat buffer; + if (stat (outfileunused, &buffer) == 0) { + fputs("\n A file named %s already exists, please remove it\n\n", stderr); + return -1; + } + + FILE *infile; + FILE *unused_infile_file_part; + unsigned char filebuffer; + unsigned char stdinbuffer; + int nreadfile, nreadfile2, nreadstdin; + int i; + + infile=fopen(argv[optind], "r"); + unused_infile_file_part = fopen(outfileunused, "w"); + + if (infile == NULL) { + fputs("Error opening input key file, check that it exist\n", stderr); + return -1; + } + if (unused_infile_file_part == NULL) { + fputs("Error opening next input key file\n", stderr); + return -1; + } + + while(1) { + nreadstdin=fread(&stdinbuffer, 1, sizeof(unsigned char), stdin); + if (nreadstdin==1) { + nreadfile=fread(&filebuffer, 1, sizeof(unsigned char), infile); + if (nreadfile==1) { + stdinbuffer^=filebuffer; + fwrite(&stdinbuffer, 1, sizeof(unsigned char), stdout); + fflush(stdout); + continue; + } else { + printf("\n Error! Key file not as long as stdin input.\n"); + return -1; + } + } else { + break; + } + } + + // produce new file excluding the part of the key that was used + while(1) { + nreadfile2=fread(&filebuffer, 1, sizeof(unsigned char), infile); + if (nreadfile2==1) { + fwrite(&filebuffer, 1, sizeof(unsigned char), unused_infile_file_part); + fflush(unused_infile_file_part); + } else { + break; + } + } + + fclose(stdin); + fclose(stdout); + fclose(infile); + fclose(unused_infile_file_part); +} diff --git a/test/otp.test.sh b/test/otp.test.sh new file mode 100644 index 0000000..95a414d --- /dev/null +++ b/test/otp.test.sh @@ -0,0 +1,46 @@ +#!/bin/sh + +# plain: 16ag +# key: abcdefghijklmn (first 4 bytes in ./test_data/test.txt file) +# expected cipher: PT +# expected next key: efghijklmn (last 4 bytes in ./test_data/test.txt file) +export PLAIN='16ag' +export OUTPUT=`echo -n $PLAIN | ./bin/otp ./test/test_data/test.txt` +export EXPECTED_OUTPUT='PT' +export EXPECTED_NEXT_KEY="efghijklmn" +export NOW=`date +"%Y-%m-%d_%H:%M:%S"` + +if [[ "$OUTPUT" = "$EXPECTED_OUTPUT" ]]; then + echo " - PASS - output is correct" +else + echo " ! FAIL : Expected $EXPECTED_OUTPUT but got $OUTPUT" + exit -1 +fi + +if test -f "./test/test_data/test.txt.$NOW.next"; then + echo " - PASS - next key file was created" +else + echo " - FAIL : next key file was NOT created!" + exit -1 +fi + +export NEXT_KEY=`cat ./test/test_data/test.txt.$NOW.next` +if [[ "$NEXT_KEY" = "$EXPECTED_NEXT_KEY" ]]; then + echo " - PASS - next key file has correct key (content)" +else + echo " ! FAIL : next key file has WRONG key (content), expected '$EXPECTED_NEXT_KEY' but got '$NEXT_KEY'" + exit -1 +fi + +rm ./test/test_data/test.txt.$NOW.next + +export ORIGINAL=`echo -n $OUTPUT | ./bin/otp ./test/test_data/test.txt` +if [[ "$ORIGINAL" = "$PLAIN" ]]; then + echo " - PASS - decryption (content) is correct" +else + echo " ! FAIL : decryption (content) is incorrect, expected '$PLAIN' but got '$ORIGINAL'" + exit -1 +fi + + +exit 0 diff --git a/test/test_data/test.txt b/test/test_data/test.txt new file mode 100644 index 0000000..1accfe8 --- /dev/null +++ b/test/test_data/test.txt @@ -0,0 +1 @@ +abcdefghijklmn diff --git a/tutorial.mp4 b/tutorial.mp4 new file mode 100644 index 0000000..364da58 Binary files /dev/null and b/tutorial.mp4 differ