pcrypt

Antivirus, forensics, intrusion detection, cryptography, etc.
Message
Author
User avatar
rufwoof
Posts: 3690
Joined: Mon 24 Feb 2014, 17:47

#21 Post by rufwoof »

Here's a newer script that I name 'vc' (One Time Pad is another name for Vernam Cipher).

The script produces .vc and .vk files, and you decrypt again by running the vc script against the .vc file. No matter what the clear text file, both .vc and .vk are random (high entropy/cannot be compressed), such that the clear text remains hidden (frequency and/or shift xoring analysis wont reveal any detail).

Handy in that no passwords have to be remembered, when separated the content is secure, only by bringing both the .vc and .vk files back together again can the clear text content to revealed. Store one on a server, another on your laptop, and if either the laptop or server are cracked then the content is safe. Nor will faster/more powerful systems in the future be able to brute force the content either (future proof).

Note that both .vc and .vk are interchangeable, both are in effect the key to the other, so it doesn't matter which you might store on a server/elsewhere. Storing say the key file .vk on a remote ssh server, and storing the .vc locally, you might boot, sshfs mount the ssh server (where the .vk file(s) is (are) stored) and then drag/drop (or whatever) move the .vk file to be alongside (same folder) as the .vk file, and then open the content (run the vc script). Moving the .vk file will remove it off the server. Later you might encrypt the file again, and move the (newer) .vk file back to the server.

Code: Select all

#!/bin/ash

# Rufwoof Dec 2019
#
# Requires xor (C program binary)


if [ -z $1 ]; then
	echo
	echo "Usage : $0 <filename>"
	echo
	echo "If filename has a .vc suffix then decrypts"
	echo
	echo "One-Time-Pad (Vernam Cipher) style encryption"
	echo
	exit
fi


if [ ! -f $1 ]; then
	if [ ! -L $1 ]; then
	    echo "File $1 not found"
	    exit
	fi
fi


xor >/dev/null 2>&1
RC=$?
if [ $RC -ne 2 ]; then
	echo "xor program as required by this script not found"
	exit
fi


if [ -L $1 ]; then # if a sym link read filesize of actual
	FILESIZE=$(stat -c%s "$(readlink -f $1)")
else
	FILESIZE=$(stat -c%s "$1")
fi
filename=$(basename "$1")
ext="${filename##*.}"


if [ "$ext" = "vk" ]; then
	B="${filename%.*}"
	if [ -f ${B}.vc ]; then
	    if [ -L ${B}.vc ]; then
		FS=$(stat -c%s "$(readlink -f ${B}.vc)")
	    else
		FS=$(stat -c%s "${B}.vc")
	    fi
	    if [ $FILESIZE -eq $FS ]; then
		echo "Hmm! Are you sure you want to encrypt a .vk file"
		echo "Suspect you actually want to decrypt ${B}.vc"
		C=1
		while [ $C -ne 0 ]; do
		    echo -n "decrypt (d) or continue and encrypt (e) d/e : "
		    read -n1 ans; echo
		    case $ans in
			d|D) filename="${B}.vc"; ext="vc"; C=0 ;;
			e|E) C=0 ;;
			*) echo "Answer should be d or e ... try again" ;;
		    esac
		done
	    fi
	fi
fi


if [ "$ext" = "vc" ]; then # decrypt

	echo Decrypting
	B="${filename%.*}"

	if [ -f $B ]; then
	    echo -n "Output file $B already exists, overwrite y/n : "
	    read -n1 ans; echo
	    if [ "$ans" = "y" ] || [ $ans = "Y" ]; then
		rm $B
	    else
	        echo exiting
	        exit
	    fi
	fi

	xor $B.vc $B.vk
	RC=$?
	if [ $RC -ne 0 ]; then
	    echo "Error occurred whilst running xor"
	    exit
	fi

	# if a sym link then we also remove the source file
	if [ -L $B.vk ]; then
	    rm "$(readlink -f $B.vk)"
	fi
	rm $B.vk
	if [ -L $B.vc ]; then
	    mv $(readlink -f ${B}.vc) ${B}
	    rm ${B}.vc
	else
	    mv $B.vc $B
	fi


else # encrypt


	if [ -f ${filename}.vk ] || [ -f ${filename}.vc ]; then
	    echo "Output file(s) ${filename}.vc"
	    echo "and/or ${filename}.vk"
	    echo -n "already exist, overwrite y/n : "
	    read -n1 ans; echo
	    if [ "$ans" = "y" ] || [ $ans = "Y" ]; then
		if [ -f ${filename}.vk ]; then
		    rm ${filename}.vk
		fi
		if [ -f ${filename}.vc ]; then
		    rm ${filename}.vc
		fi
	    else
	        echo exiting
	        exit
	    fi
	fi

	echo "Generating high entropy random bytes keyfile"
	dd if=/dev/random bs=32 iflag=fullblock | pv --bytes | head -c $FILESIZE >${filename}.vk

	KEYFILESIZE=$(stat -c%s "${filename}.vk")
	if [ $FILESIZE -gt $KEYFILESIZE ]; then # error in random file generation
		echo "Mis-match between generated random key filesize and clear-text filesize"
		echo "exiting"
		rm ${filename}.vk
		exit
	fi	

	echo "Encrypting ..."
	xor ${filename} ${filename}.vk
	RC=$?
	if [ $RC -ne 0 ]; then
	    echo "Error occurred whilst running xor"
	    exit
	fi

	if [ -L ${filename} ]; then
	    mv $(readlink -f ${filename}) ${filename}.vc
	    rm ${filename}
	else
	    mv ${filename} ${filename}.vc
	fi

fi

sync
For faster xor'ing I'm using the following xor.c program (load devx and gcc xor.c -o xor). Where that uses a trick of writing the output to the input file, which avoids having to use a third transitional file. i.e. xor file1 file2 where file2 has the random data will result in file1 original content being replaced with the xor'd output. Run a second time to restore it back as before.

Code: Select all

#include <stdio.h>
#include <unistd.h>
#include <stdbool.h>
#include <err.h>

/*
   No error checking etc. intended to be called/run from
   a wrapper shell script that does all the checks

   Fast (buffers 32K blocks) XOR'ing of two files, where
   the output file is the input file i.e. overwrites it
   (saves on having to use a transitory file).

   Rufwoof 2019
*/

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

	char *in_n, *key_n, *out_n;
	FILE *in_fp, *key_fp, *out_fp;
	unsigned char data[32768], key[32768];
	size_t in_l, key_l = 0, key_i = 0, data_i;
	
	if (argc == 1) { 
	    fprintf(stdout, "For usage see vc shell wrapper script\n");
	    return 2; 
	}
	
	in_fp  = fopen(argv[1],"rb");
	key_fp = fopen(argv[2],"rb");
	out_fp = fopen(argv[1],"rb+");
	
	while (1)
	{
	    data_i = 0;
	    in_l = fread(data, sizeof(unsigned char), sizeof(data), in_fp);
	    if (ferror(in_fp)) { return 1; }
	    if (in_l) {
		while (data_i < in_l)
		{
		    if (key_i >= key_l) {
			key_i = 0;
			key_l = fread(key,
				sizeof(unsigned char),sizeof(key), key_fp);
			if (ferror(key_fp)) { return 1; }
		    }
		    data[data_i] ^= key[key_i];data_i++;key_i++;
		}
		fwrite(data, sizeof(unsigned char), in_l, out_fp);
		if (ferror(out_fp)) { return 1; }
	    }
	    else if (!in_l && feof(in_fp)) { return 0; }
	                     /* End of in_fp, exit OK */
	}
	fclose(in_fp);
	fclose(out_fp);
	fclose(key_fp);
}
Little/no error checking in that as its solely intended to be called by the vc script - that does all the checking.

Fundamentally in Linux based systems the CSPRNG (Crytographically Secure Pseudo Random Number Generator) that derives its pool of random bytes from the likes of /dev/hwrng and the least significant bits of interrupts timestamps (hardware activity) sources both /dev/random and /dev/urandom. A difference however is that /dev/random will block if the kernels estimate of entropy is too low.

Large seemingly random sequences of numbers do not always have high entropy. You can take a small random number and turn it into a large random number and the entropy remains the same. For example, take a random number from 1 to 16 and compute its cryptographic hash with an algorithm like SHA-1 - the resulting 160 bit number looks very random, but it is one of only 16 possible such numbers. Guessing the number is just as easy as guessing a random number from 1 to 16. urandom will output low entropy (more predictable) data when the approximated entropy is low, and when removing (reading) long sequences of random bytes quickly entropy will tend to be low - and as such urandom random data tends to be significantly more predictable than /dev/random random data. One time pad (Vernam Cipher) requires that even if all possible valid ineligible clear text solutions are derived then the actual/correct solution remains obscure - cannot be differentiated. With /dev/urandom sourced random data that is much less assured than when using /dev/random random data.

It is important to use cryptographically secure random data as pure random could for instance yield all zeros as being a 'valid' random data sequence, that in turn would result in OTP yielding the same 'encrypted' output as the clear-text input. Our random data must exhibit the qualities of appearing random, and in the case of OTP the random data must also have relatively high entropy (otherwise even just cracking one/few bytes of clear text could highlight one overall most probable (or actual) solution.

A downside of using high entropy CSPRNG random data (/dev/random) is that it is much much slower to be produced compared to /dev/urandom. That is the price paid for higher security.
[size=75]( ͡° ͜ʖ ͡°) :wq[/size]
[url=http://murga-linux.com/puppy/viewtopic.php?p=1028256#1028256][size=75]Fatdog multi-session usb[/url][/size]
[size=75][url=https://hashbang.sh]echo url|sed -e 's/^/(c/' -e 's/$/ hashbang.sh)/'|sh[/url][/size]

User avatar
rufwoof
Posts: 3690
Joined: Mon 24 Feb 2014, 17:47

#22 Post by rufwoof »

For cross reference purposes, there's another post here http://www.murga-linux.com/puppy/viewto ... 50#1045950 that may be of interest. Based on Deniable Encryption. Basically it creates a apparently valid One Time Pad style pair of Crypted file and Key file, where when de-crypted reveals a valid clear text content ... however that's just a disguise and another entirely different clear text content is also hidden within that and can be de-crypted using another Key.

So if a adversary sees a encrypted file and one way or another pressures you to release the key ... then you can comply and they will see the 'fake' apparently valid content, not the real content (which is only accessible via another key, and without that key there is no indication of that hidden content).
[size=75]( ͡° ͜ʖ ͡°) :wq[/size]
[url=http://murga-linux.com/puppy/viewtopic.php?p=1028256#1028256][size=75]Fatdog multi-session usb[/url][/size]
[size=75][url=https://hashbang.sh]echo url|sed -e 's/^/(c/' -e 's/$/ hashbang.sh)/'|sh[/url][/size]

Post Reply