Skip to content

Commit

Permalink
v7.2
Browse files Browse the repository at this point in the history
  • Loading branch information
circulosmeos committed Aug 20, 2015
1 parent 9a1914e commit 963b226
Show file tree
Hide file tree
Showing 3 changed files with 131 additions and 26 deletions.
19 changes: 19 additions & 0 deletions Changes.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
v7.2

* Binary files can be used as passwords: for example jpg images, etc. Caution: do not lose this 'password' file and do not modify it!


v7.1 (initial release):

* Code can be compiled with any C99 compiler, no matter platform, endianness or word size (32-64 bits): it has been tested on Windows, linux, Solaris, HP-UX OS's and Intel/AMD, ARM and Itanium processors.
* Same content produces different encrypted outputs every time. This is attained with a random initialization vector (IV) stored within the encrypted file.
* Files are (by default) encrypted/decrypted on-the-fly, so content is overwritten. This is interesting from a security point of view, as no clear content is left on disk.
* When decrypting, if password is not the one used for encrypting, the process is aborted, so the file cannot be rendered unusable. This behaviour is achieved thanks to a password hash stored within the encrypted file. (This hash can optionally be erased when encrypting: in this case the file could end up being decrypted with an incorrect password, so its contents could be irrecoverable.)
* Mentioned hash used to check that the password for decryption is correct is *not* the same used to encrypt (obviously!). Separate hashes are used for both purposes, though both are derived via different ways from the password, using some 500-1000 concatenated KECCAK hashes.
* File modification time is maintained. File dates are important!
* Encrypted files are appended the extension .$#3 to filename, so they can be recognized.
* Password can be obtained from keyboard, command line or from a file. Caution: usually text files end with a "return" (line feed, \n, \r\n, \r) which will be used as the rest of chars in the file as part of the password. (Use $ cat > password + Ctrl+D to avoid this). Also note that there's a limit on the number of characters that will be read from the file... that'd be about two hundred chars at least (!).
* Speed is extremely high, as CHACHA20 is a very fast encryption algorithm: it is as fast as RC4.
* Reduced program size: < 100 kiB on all platforms.
* easily portable to Android as a JNI library. Check "ANDROID_LIBRARY" in the source code.
* Licensed as GPL v3.
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ triops: a simple command line tool for encryption/decryption of files.

It uses [CHACHA20](http://en.wikipedia.org/wiki/Salsa20#ChaCha_variant) as algorithm for encryption/decryption and [KECCAK](http://en.wikipedia.org/wiki/SHA-3)-512 as hash algorithm.

Executables for some platforms (linux, Windows, HP-UX and Solaris) are available [here](https://circulosmeos.wordpress.com/2015/05/18/triops-a-multiplatform-cmdline-encryption-tool-using-chacha20-keccak).
Executables for v7.1 on some platforms (linux, Windows, HP-UX and Solaris) are available [here](https://circulosmeos.wordpress.com/2015/05/18/triops-a-multiplatform-cmdline-encryption-tool-using-chacha20-keccak).

Features:

Expand All @@ -16,6 +16,7 @@ Features:
* Password can be obtained from keyboard, command line or from a file. Caution: usually text files end with a "return" (line feed, \n, \r\n, \r) which will be used as the rest of chars in the file as part of the password. (Use $ cat > password + Ctrl+D to avoid this). Also note that there's a limit on the number of characters that will be read from the file... that'd be about two hundred chars at least (!).
* Speed is extremely high, as CHACHA20 is a very fast encryption algorithm: it is as fast as RC4.
* Reduced program size: < 100 kiB on all platforms.
* Binary files can be used as passwords (from v7.2): for example jpg images, etc. Caution: do not lose this 'password' file and do not modify it!
* easily portable to Android as a JNI library. Check "ANDROID_LIBRARY" in the source code.
* Licensed as GPL v3.

Expand Down
135 changes: 110 additions & 25 deletions triops.c
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@
// an incorrect password, so content could be irrecoverable).
// This hash is *not* the same used to encrypt!
// * File modification time is maintained. File dates are important!
// * Files can be used as passwords: for example jpg images, etc.
// (do not lose this 'password' file and do not modify it!)
//
// Type ./triops to obtain command line help.
//
Expand Down Expand Up @@ -62,6 +64,7 @@ int getch(void);

#include "ecrypt-sync.h"
#include "crypto_hash.h"
#include "sph_keccak.h"



Expand All @@ -72,11 +75,15 @@ int getch(void);



#define BUFFERSIZE 16384 // for CHACHA20: multiple of 64 bytes to avoid bad implementation (http://goo.gl/DHCLz1)
#define BUFFERSIZE 16384
#define KEYSIZE_v3 32 // KEYSIZE_v3 is for CHACHA20 = 256 bits (256/8=32 bytes)
#define IVSIZE_v3 8 // IVSIZE_v3 is for CHACHA20 = 64 bits ( 64/8= 8 bytes)
#define HASHSIZE_v3 64 // HASHSIZE_v3 is for KECCAK-512=512 bits (512/8=64 bytes)

#define MAX_PASSWORD_LENGTH 261 // maximum length of a password introduced with keyboard:
// 260+1(\n) at minimum to make this value (user&code') backwards compatible:
// MAX_PASSWORD_LENGTH must be >= MAX_PATH (260) > HASHSIZE_v3

typedef enum { CheckKeyIsValid_FALSE=0,
CheckKeyIsValid_TRUE=1,
CheckKeyIsValid_TRUE_BUT_EMPTY=2
Expand Down Expand Up @@ -226,11 +233,11 @@ int local_triops (int argc, char* argv[])
FILE * hFile;
FILE * hFileOut;
FILE * hFileTail;
char szFile [MAX_PATH];
char szNewFile [MAX_PATH];
char szPass [MAX_PATH];
char szPassFile [MAX_PATH];
BYTE lpFileBuffer [BUFFERSIZE];
char szFile [MAX_PATH];
char szNewFile [MAX_PATH];
char szPass [MAX_PASSWORD_LENGTH];
char szPassFile [MAX_PATH];
BYTE lpFileBuffer[BUFFERSIZE];
//BOOL bOutputToTheSameFile; // defined as global above
BOOL bEncrypt;
BOOL bDoNotStorePasswordHash;
Expand Down Expand Up @@ -321,7 +328,7 @@ int local_triops (int argc, char* argv[])
// obtain password from file:
if (!obtainPassword (szPassFile, szPass))
{
printf ("\nCould not open %s.\n\n", szPassFile);
printf ("\nCould not obtain password.\nAborted.\n\n");
return 1;
}

Expand Down Expand Up @@ -750,17 +757,20 @@ truncateFileBySize ( LPBYTE szFile, unsigned long long bytesToTruncate )

}

// returns the string contained in the file passed as a fs path.
// the string is supossed to be "short": the password.
// only MAX_PATH bytes are read from the file.
// modification for using binary files as passwords:
// returns the hash calculated from the contents
// of the file passed as a fs path.
// if the fs path passed starts and ends with '_' char,
// the enclosed string is the password itself.
BOOL
obtainPassword (LPBYTE szFile, LPBYTE szPass)
{
FILE * hFile;
DWORD nBytesRead;
BYTE lpFileBuffer [BUFFERSIZE];
int i, c;
unsigned long long lFileSize;
sph_keccak512_context mc;

if (szFile[0]=='_' && szFile[strlen(szFile)-1]=='_') { // strlen(szFile)>0 always

Expand All @@ -770,7 +780,7 @@ obtainPassword (LPBYTE szFile, LPBYTE szPass)
printf("\n\nEnter password and press [enter]: ");
fflush(stdout); // flash stdout
i=0;
while (i<MAX_PATH && (c = getch()) != 13) { // read chars until "\n"
while ( i<(MAX_PASSWORD_LENGTH-1) && (c = getch()) != 13 ) { // read chars until "\n"
if (c!=8 && c!=127) {
szPass[i]=(char)c;
i++;
Expand All @@ -791,39 +801,106 @@ obtainPassword (LPBYTE szFile, LPBYTE szPass)
// delusion eavesdropping password length!
for (i = 0; i < strlen(szPass); i++, putchar(8), putchar(32), putchar(8));
printf("\n\n");
// if password length reaches MAX_PASSWORD_LENGTH, input ends abruptly, warn it!
if ( i==(MAX_PASSWORD_LENGTH-1) ) {
printf ("WARNING: password exceeded max length, and it was truncated to %i chars.\n",
MAX_PASSWORD_LENGTH);
printf ("Should process continue (y/n)? : ");
c=getch();
if (c!=121) { // anything different from "y"
printf ("n\n\n");
return FALSE;
} else { // ok, continue
printf ("y\n\n");
}
}
} else {
// ! (strlen(szFile)==2)
#endif
memcpy(szPass, szFile+1, strlen(szFile)-2); // done !!!
szPass[strlen(szFile)-2]=0x0; // important !!! to mark the end of the string

} // else ends ( if (strlen(szFile)==2) )
// But:
// #ifndef ANDROID_LIBRARY => if (szFile[0]=='_' && szFile[strlen(szFile)-1]=='_') {...}

// and now, directly calculate hash here:
if (triopsVersion == TRIOPS_V3) {
crypto_hash((unsigned char *)szPass, (unsigned char *)szPass, strlen(szPass));
/* DEBUG: check value:
printf ("calculated hash from file: ");
for (i=0; i<16; i++) printf(" %08lx",((LPDWORD)szPass)[i]);
*/
}


#ifndef ANDROID_LIBRARY
} else {
// ! (szFile[0]=='_' && szFile[strlen(szFile)-1]=='_')

hFile = fopen(szFile, "rb" );
if (hFile == NULL)
{
printf ("\nError opening %s\n", szFile);
fclose (hFile);
printf ("\nError opening '%s'\n", szFile);
return FALSE;
}

nBytesRead=fread(szPass, MAX_PATH, 1, hFile);
if (feof(hFile)) {
// read size unknown: it must be all the file (<MAX_PATH):
nBytesRead=(DWORD)FileSize(szFile);
lFileSize=(unsigned long long)FileSize(szFile);
if (lFileSize == 0)
{
fclose (hFile);
printf ("\nError: file '%s' is empty!\n", szFile);
return FALSE;
}

if (nBytesRead == 0)
{
printf ("\nEmpty password!!!. But process continues as it'd be '0x0'.\n");
// prepare environment to read the contents of the file used as password,
// and calculate its hash.
unsigned long long lBlockTotal; // counts total number of <=BUFFERSIZE blocks in hFile
unsigned long long lBlockNumber; // counts number of <=BUFFERSIZE blocks processed in hFile
lBlockNumber=0;
lBlockTotal=lFileSize/(unsigned long long)BUFFERSIZE; // this truncates result so:
if ( lFileSize % (unsigned long long)BUFFERSIZE != 0 )
lBlockTotal++;

if (triopsVersion == TRIOPS_V3) {
sph_keccak512_init(&mc);
}

// read the contents of the file used as password.
// it can contain plain text password (no final \n or it'll be included) or binary data.
do
{
lBlockNumber++;
// size_t fread(void *ptr, size_t size, size_t n, FILE *stream);
nBytesRead=fread(lpFileBuffer, BUFFERSIZE, 1, hFile);
if (nBytesRead || feof(hFile) )
{
if (feof(hFile)) {
nBytesRead = lFileSize % (unsigned long long)BUFFERSIZE;
} else {
// real nBytesRead, because nBytesRead is now just '1'
nBytesRead = nBytesRead * (unsigned long long)BUFFERSIZE;
}
if (triopsVersion==TRIOPS_V3) {
sph_keccak512(&mc, lpFileBuffer, nBytesRead);
}

// capital!: string must end with 0x0 !!!:
szPass[nBytesRead]=0x0;
}
} while (lBlockNumber<lBlockTotal);

if (triopsVersion==TRIOPS_V3) {
sph_keccak512_close(&mc,szPass);
/* DEBUG: check value:
printf ("calculated hash from file: ");
for (i=0; i<16; i++) printf(" %08lx",((LPDWORD)szPass)[i]);
*/
}

fclose (hFile);
}

} // else ends ( if (szFile[0]=='_' && szFile[strlen(szFile)-1]=='_') )

#endif

return TRUE;
Expand All @@ -839,8 +916,10 @@ void EliminatePasswords(LPBYTE szPassFile, LPBYTE szPass)

// both variables are filled: szPassFile isn't needed anymore anyway.
for (i=0; i++; i<MAX_PATH) {
szPassFile[i]=0x0;
szPass[i]=0x0;
szPassFile[i]=0xff;
}
for (i=0; i++; i<MAX_PASSWORD_LENGTH) {
szPass[i]=0xff;
}

}
Expand Down Expand Up @@ -997,18 +1076,24 @@ CheckKeyIsValid_v3 (LPSTR szPass, LPBYTE lpKey, LPBYTE lpIV, LPDWORD lpHashedKey
while (*hex) { sscanf(hex, "%2hhx", byte++); hex += 2; }*/

// calculate the theoretical hashedkey from the IV and passed password:
/*
crypto_hash(testKey.keyB, (unsigned char *)szPass, strlen(szPass));
*/

/* DEBUG: KECCAK-512:*/
/*printf ("KECCAK-512: ");
for (i=0; i<16; i++) printf(" %08lx",testKey.keyW[i]);*/

// copy the key
/*
memcpy(lpKey, testKey.keyB, HASHSIZE_v3);
*/
memcpy(lpKey, (LPBYTE)szPass, HASHSIZE_v3);
memcpy(testKey.keyB, (LPBYTE)szPass, HASHSIZE_v3);

/* DEBUG: check value:
printf ("calculated: ");
for (i=0; i<8; i++) printf(" %08lx",testKey.keyW[i]);
for (i=0; i<16; i++) printf(" %08lx",testKey.keyW[i]);
*/

// .................................................
Expand Down

0 comments on commit 963b226

Please sign in to comment.