Commits

Adam Olsen committed 75dfa08

adding python version

  • Participants
  • Parent commits 76be75e

Comments (0)

Files changed (10)

Makefile

-CXX = g++
-
-all: prog
-
-prog:
-	$(CXX) -g -I . -o hider main.cpp aolib/bfcryptfile.cpp -lcrypto
-
-clean:
-	rm hider
-
-install: prog
-	cp hider /usr/bin
+Couple of homegrown encryption utilities that I wrote a while ago.  Probably
+useless at this point, but I keep them around for posterity.

aolib/bfcryptfile.cpp

-/*
-    Copyright (C) 2004 Adam Olsen
-
-	This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 1, or (at your option)
-    any later version.
-
-    This program is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with this program; if not, write to the Free Software
-    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-*/
-
-
-#include <aolib/bfcryptfile.hpp>
-#include <openssl/sha.h>
-#include <stdlib.h>
-
-namespace aolib
-{
-	// set up the magic numbers
-	const unsigned char BFCryptFile::encsig[25] = { 0, 2, 144, 4, 3, 4, 5, 6, 3, 12, 144, 134, 5, 6, 24, 2, 0, 3, 4, 3, 4, 3, 88, 4, 5 };
-
-	std::string BFCryptFile::hashPassOnce( const char *pass )
-	{
-		std::string hash;
-
-		unsigned char md_value[EVP_MAX_MD_SIZE] = { '\0' };
-		char temp[2] = { '\0' };
-		EVP_MD_CTX mdctx;
-		unsigned int md_len;
-
-		// initialize the SHA1 algorithm
-		EVP_DigestInit( &mdctx, EVP_sha1() );
-
-		// hash the pass
-		EVP_DigestUpdate( &mdctx, pass, strlen( pass ) );
-
-		// finalize the hash
-		EVP_DigestFinal( &mdctx, md_value, &md_len );
-
-		bzero( temp, 2 );
-		sprintf( temp, "%02x", md_value[0] );
-		hash +=  temp;
-		sprintf( temp, "%02x", md_value[1] );
-		hash +=  temp;
-
-		return hash;
-	}
-
-	std::string BFCryptFile::hashPass( const char *pass, unsigned char *salt )
-	{
-		std::string hash;
-
-		char temp[2] = { '\0' };
-		unsigned char out[SHA_DIGEST_LENGTH] = { '\0' };
-
-		// hash the password 10000 times using the salt
-		PKCS5_PBKDF2_HMAC_SHA1( pass, strlen( pass ), salt, 8, 10000, SHA_DIGEST_LENGTH, out );
-
-		// convert the result into a hex-string representation
-		for( int i = 0; i < SHA_DIGEST_LENGTH; i++ )
-		{
-			bzero( temp, 2 );
-			sprintf( temp, "%02x", out[i] );
-			hash += temp;
-		}
-
-		return hash;
-	}
-
-	bool BFCryptFile::checkSig( std::string inFile )
-	{
-		char user[1024] = { '\0' };
-		char pass[5] = { '\0' };
-		char salt[8] = { '\0' };
-		char ivec[8] = { '\0' };
-		unsigned char checksig[25];
-		std::ifstream in( inFile.c_str(), std::ios::binary );
-
-		if( !in.is_open() )
-		{
-			throw( BFCryptException( "Could not open input file." ) );
-		}
-
-		// get the various required bytes from the file for decryption
-		in.getline( user, 1024 );
-		in.getline( pass, 5 );
-		in.read( (char *)checksig, 25 );
-		in.read( salt, 8 );
-		in.read( ivec, 8 );
-		in.close();
-
-		// check to make sure the magic numbers were present
-		if( strcmp( (char *)encsig, (char *)checksig ) != 0 )
-		{
-			return true;
-		}
-
-		return false;
-	}
-
-	void BFCryptFile::decryptFile( std::string username, std::string password, std::string inFile, std::string outFile )
-	{
-		char user[1024] = { '\0' };
-		char pass[5] = { '\0' };
-		char salt[8] = { '\0' };
-		char ivec[8] = { '\0' };
-		unsigned char checksig[25];
-
-		std::ifstream in( inFile.c_str(), std::ios::binary );
-
-		in.seekg( 0, std::ios::end );
-		int fileLength = in.tellg();
-		in.seekg( 0, std::ios::beg );
-
-		if( !in.is_open() )
-		{
-			throw( BFCryptException( "Could not open input file." ) );
-		}
-
-		// get the various required bytes from the file for decryption
-		in.getline( user, 1024 );
-		in.getline( pass, 5 );
-		in.read( (char *)checksig, 25 );
-		in.read( salt, 8 );
-		in.read( ivec, 8 );
-
-		// check to make sure the magic numbers were present
-		if( strcmp( (char *)encsig, (char *)checksig ) != 0 )
-		{
-			throw( BFCryptException( "This file does not appear to be an encrypted file, or it has been corrupted." ) );
-		}
-
-		// do a light check to make sure the password at least appears to be correct
-		if( strcmp( hashPassOnce( password.c_str() ).c_str(), pass ) != 0 )
-		{
-			throw( BFCryptException( "You have entered an invalid username and/or password." ) );
-		}
-
-		// make sure the username is correct
-		if( strcmp( username.c_str(), user ) != 0 )
-		{
-			throw( BFCryptException( "You have entered an invalid username and/or password." ) );
-		}
-
-		std::ofstream out( outFile.c_str(), std::ios::binary );
-		if( !out.is_open() )
-		{
-			throw( BFCryptException( "Could not open temp file for writing." ) );
-		}
-
-		#ifndef WIN32
-			chmod( outFile.c_str(), 0600 );
-		#endif
-
-		// and decrypt the file using the salt and ivec found in the file
-		cryptFile( in, out, password, (unsigned char *)salt, (unsigned char *)ivec, 0, fileLength );
-	}
-
-	void BFCryptFile::encryptFile( std::string username, std::string password, std::string inFile, std::string outFile )
-	{
-		char salt[8] = { '\0' };
-		char ivec[8] = { '\0' };
-
-		// create a random ivec and salt
-		RAND_bytes( (unsigned char *)salt, 8 );
-		RAND_bytes( (unsigned char *)ivec, 8 );
-
-		std::ifstream in( inFile.c_str(), std::ios::binary );
-		in.seekg( 0, std::ios::end );
-		int fileLength = in.tellg();
-		in.seekg( 0, std::ios::beg );
-
-		if( !in.is_open() )
-		{
-			throw( BFCryptException( "Could not open input file for reading." ) );
-		}
-
-		std::ofstream out( outFile.c_str(), std::ios::binary );
-		if( !out.is_open() )
-		{
-			throw( BFCryptException( "Could not open input file for writing." ) );
-		}
-
-		// write the username, the hashed password, the salt, the encryption
-		// signature, and the ivec to the file
-		out << username << std::endl;
-		out << hashPassOnce( password.c_str() ) << std::endl;
-		out.write( (char *)encsig, 25 );
-		out.write( salt, 8 );
-		out.write( ivec, 8 );
-
-		#ifndef WIN32
-			chmod( outFile.c_str(), 0600 );
-		#endif
-
-		// encrypt the rest of the data and write it to the output file
-		cryptFile( in, out, password, (unsigned char *)salt, (unsigned char *)ivec, 1, fileLength );
-	}
-
-	void BFCryptFile::cryptFile( std::ifstream &ifile, std::ofstream &ofile, std::string pass, unsigned char *salt,
-		unsigned char *ivec, int encordec, int fileLength )
-	{
-		unsigned char in[1042];
-		unsigned char out[1024 + EVP_MAX_BLOCK_LENGTH];
-		unsigned long size = 0;
-		int outlen = 0;
-		int progressCounter = 0;
-
-		std::string typeString = "Encrypting";
-		if( !encordec ) typeString = "Decrypting";
-
-		pass = hashPass( pass.c_str(), salt );
-
-		EVP_CIPHER_CTX ctx;
-		EVP_CIPHER_CTX_init( &ctx );
-
-		// initialize the encrypt functions to use blowfish
-		if( !EVP_CipherInit( &ctx, EVP_bf_cbc(), NULL, NULL, encordec ) )
-		{
-			throw( BFCryptException( "OpenSSL error setting ctx key." ) );
-		}
-
-		// set the blowfish key length
-		EVP_CIPHER_CTX_set_key_length( &ctx, pass.length() );
-
-		// set the key and the initialization vector
-		if( !EVP_CipherInit( &ctx, NULL, (unsigned char *)pass.c_str(), ivec, encordec ) )
-		{
-			throw( BFCryptException( "OpenSSL error setting ctx key." ) );
-		}
-
-		int markCount = 40;
-		int marker = fileLength / markCount;
-		int markers = 0;
-		int mark = 0;
-		int currentSize = 0;
-		int updateCount = -1;
-
-		float percent = 0.0;
-
-		while( !ifile.eof() )
-		{
-			bzero( in, 1024 );
-			bzero( out, 1024 );
-			// read in data from the in file
-
-			ifile.read( (char *)in, 1024 );
-			size = ifile.gcount();
-
-			if( size )
-			{
-				// encrypt/decrypt the data
-				if( !EVP_CipherUpdate( &ctx, out, &outlen, in, size ) )
-				{
-					throw( BFCryptException( "OpenSSL error while decrypting/encrypting file.  It's possible that your password was bad, or the file was corrupted." ) );
-				}
-
-				// write the new data to the output file
-				ofile.write( (char *)out, outlen );
-
-				currentSize += size;
-			}
-
-			percent = ( (float)currentSize / (float)fileLength );
-			if( !size || ifile.eof() ) percent = 1;
-
-			mark += size;
-			if( mark > marker )
-			{
-				markers++;
-				mark = 0;
-			}
-
-			if( markers == markCount - 1 ) percent = 1;
-
-			if( updateCount > 100 || updateCount == -1 )
-			{
-				std::cout << "\r" + typeString + ": [";
-				for( int i = 0; i <= markers; i++ ) std::cout << "#";
-				for( int i = markers; i < markCount - 1; i++ ) std::cout << " ";
-				std::cout << std::flush << "] " << (int)( percent * 100 ) << "\%\r";
-				updateCount = 0;
-			}
-			updateCount++;
-		}
-
-		std::cout << "\r" + typeString + ": [";
-		for( int i = 0; i <= markCount; i++ ) std::cout << "#";
-		std::cout << "] " << (int)( percent * 100 ) << "\%\r";
-
-		// finalize the encryption (this adds padding where it is needed
-		if( !EVP_CipherFinal( &ctx, out, &outlen ) )
-		{
-			throw( BFCryptException( "OpenSSL error while decrypting/encrypting file.  It's possible that your password was bad, or the file was corrupted." ) );
-		}
-
-		// write the finalized/padded info to the file
-		ofile.write( (char *)out, outlen );
-
-		EVP_CIPHER_CTX_cleanup( &ctx );
-		ifile.close();
-		ofile.close();
-	}
-
-	void BFCryptFile::shredFile( const char *file )
-	{
-		std::ifstream in( file, std::ios::binary );
-		if( !in.is_open() ) return;
-
-		// find out the file size
-		in.seekg( 0, std::ios::end );
-		unsigned int fileLength = in.tellg();
-		in.seekg( 0, std::ios::beg );
-		in.close();
-
-		// write zeros the length of the file
-		std::ofstream out( file, std::ios::binary );
-		if( !out.is_open() ) return;
-
-		for( unsigned int i = 0; i < fileLength; i++ )
-		{
-			out.put( '\0' );
-		}
-
-		out.close();
-
-		// delete the file
-		unlink( file );
-	}
-}

aolib/bfcryptfile.hpp

-/*
-    Copyright (C) 2004 Adam Olsen
-
-	This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 1, or (at your option)
-    any later version.
-
-    This program is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with this program; if not, write to the Free Software
-    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-*/
-#ifndef BFCRYPT_FILE_HPP
-#define BFCRYPT_FILE_HPP
-
-#include <openssl/rand.h>
-#include <openssl/evp.h>
-#include <sys/stat.h>
-#include <fstream>
-#include <iostream>
-#include <unistd.h>
-#include <string>
-#include <string.h>
-#include <sstream>
-
-#ifndef EVP_MAX_BLOCK_LENGTH
-#define EVP_MAX_BLOCK_LENGTH 32
-#endif
-
-namespace aolib
-{
-	/**
-	 * Takes the specified file "inFile" and encrypts or decrypts it to "outFile", using the specified
-	 * password as the key.  Each time the file is encrypted, a new initialization vector for Blowfish and a new
-	 * salt for SHA-1 are created from random bits and written out to the encrypted file. These two are then read off of the top
-	 * of the file for decryption.
-	 * @author Adam Olsen
-	**/
-	class BFCryptFile
-	{
-		private:
-			/**
-			 * Encrypts or decrypts ifile to ofile according to encordec, using pass, salt, and ivec.  If any problems occur,
-			 * a BFCryptException will be thrown
-			**/
-			static void cryptFile( std::ifstream &ifile, std::ofstream &ofile, std::string pass, unsigned char *salt,
-				unsigned char *ivec, int encordec, int fileLength );
-
-		public:
-			/**
-			 * The encsig is an implemntation of "magic numbers".  25 bytes of seemingly random characters
-			 * are written to the top of an encrypted file.  When decrypting, if these bytes aren't found,
-			 * then we know that it's not an encrypted file (at least not one encrypted by this class).
-			**/
-			static const unsigned char encsig[];
-
-			/**
-			 * Hashes the specified string "pass" one time with sha-1, and passes back only the first 16 bits for
-			 * storeage in the encrypted file.  What this does is it leads to any dictionary attacks appearing to
-			 * be accepted (1 out of 65536 will appear correct) until the decryption fails
-			**/
-			static std::string hashPassOnce( const char *pass );
-
-			/**
-			 * Hashes the specified string "pass" 10000 times with SHA-1 using "salt" as the salt.
-			**/
-			static std::string hashPass( const char *pass, unsigned char *salt );
-
-			/**
-			 * Zeros out a file by writing '\0' to every byte, and then unlinks it
-			**/
-			static void shredFile( const char *file );
-
-			/**
-			 * Encrypts inFile to outFile. If any errors occur, a BFCryptException will be thrown
-			**/
-			static void encryptFile( std::string username, std::string password, std::string inFile, std::string outFile );
-
-			/**
-			 * Decrypts inFile to outFile.If any errors occur, a BFCryptException will be thrown
-			**/
-			static void decryptFile( std::string username, std::string password, std::string inFile, std::string outFile );
-
-			static bool checkSig( std::string file );
-	};
-
-	class BFCryptException
-	{
-		private:
-			std::string message;
-		public:
-			BFCryptException( const char *error ) { this->message = error; }
-			BFCryptException( std::string error ) { this->message = error; }
-			std::string what() { return message; }
-	};
-}
-
-#endif // BFCRYPT_FILE_HPP

cpp/hider/Makefile

+CXX = g++
+
+all: prog
+
+prog:
+	$(CXX) -g -I . -o hider main.cpp aolib/bfcryptfile.cpp -lcrypto
+
+clean:
+	rm hider
+
+install: prog
+	cp hider /usr/bin

cpp/hider/aolib/bfcryptfile.cpp

+/*
+    Copyright (C) 2004 Adam Olsen
+
+	This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 1, or (at your option)
+    any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+
+#include <aolib/bfcryptfile.hpp>
+#include <openssl/sha.h>
+#include <stdlib.h>
+
+namespace aolib
+{
+	// set up the magic numbers
+	const unsigned char BFCryptFile::encsig[25] = { 0, 2, 144, 4, 3, 4, 5, 6, 3, 12, 144, 134, 5, 6, 24, 2, 0, 3, 4, 3, 4, 3, 88, 4, 5 };
+
+	std::string BFCryptFile::hashPassOnce( const char *pass )
+	{
+		std::string hash;
+
+		unsigned char md_value[EVP_MAX_MD_SIZE] = { '\0' };
+		char temp[2] = { '\0' };
+		EVP_MD_CTX mdctx;
+		unsigned int md_len;
+
+		// initialize the SHA1 algorithm
+		EVP_DigestInit( &mdctx, EVP_sha1() );
+
+		// hash the pass
+		EVP_DigestUpdate( &mdctx, pass, strlen( pass ) );
+
+		// finalize the hash
+		EVP_DigestFinal( &mdctx, md_value, &md_len );
+
+		bzero( temp, 2 );
+		sprintf( temp, "%02x", md_value[0] );
+		hash +=  temp;
+		sprintf( temp, "%02x", md_value[1] );
+		hash +=  temp;
+
+		return hash;
+	}
+
+	std::string BFCryptFile::hashPass( const char *pass, unsigned char *salt )
+	{
+		std::string hash;
+
+		char temp[2] = { '\0' };
+		unsigned char out[SHA_DIGEST_LENGTH] = { '\0' };
+
+		// hash the password 10000 times using the salt
+		PKCS5_PBKDF2_HMAC_SHA1( pass, strlen( pass ), salt, 8, 10000, SHA_DIGEST_LENGTH, out );
+
+		// convert the result into a hex-string representation
+		for( int i = 0; i < SHA_DIGEST_LENGTH; i++ )
+		{
+			bzero( temp, 2 );
+			sprintf( temp, "%02x", out[i] );
+			hash += temp;
+		}
+
+		return hash;
+	}
+
+	bool BFCryptFile::checkSig( std::string inFile )
+	{
+		char user[1024] = { '\0' };
+		char pass[5] = { '\0' };
+		char salt[8] = { '\0' };
+		char ivec[8] = { '\0' };
+		unsigned char checksig[25];
+		std::ifstream in( inFile.c_str(), std::ios::binary );
+
+		if( !in.is_open() )
+		{
+			throw( BFCryptException( "Could not open input file." ) );
+		}
+
+		// get the various required bytes from the file for decryption
+		in.getline( user, 1024 );
+		in.getline( pass, 5 );
+		in.read( (char *)checksig, 25 );
+		in.read( salt, 8 );
+		in.read( ivec, 8 );
+		in.close();
+
+		// check to make sure the magic numbers were present
+		if( strcmp( (char *)encsig, (char *)checksig ) != 0 )
+		{
+			return true;
+		}
+
+		return false;
+	}
+
+	void BFCryptFile::decryptFile( std::string username, std::string password, std::string inFile, std::string outFile )
+	{
+		char user[1024] = { '\0' };
+		char pass[5] = { '\0' };
+		char salt[8] = { '\0' };
+		char ivec[8] = { '\0' };
+		unsigned char checksig[25];
+
+		std::ifstream in( inFile.c_str(), std::ios::binary );
+
+		in.seekg( 0, std::ios::end );
+		int fileLength = in.tellg();
+		in.seekg( 0, std::ios::beg );
+
+		if( !in.is_open() )
+		{
+			throw( BFCryptException( "Could not open input file." ) );
+		}
+
+		// get the various required bytes from the file for decryption
+		in.getline( user, 1024 );
+		in.getline( pass, 5 );
+		in.read( (char *)checksig, 25 );
+		in.read( salt, 8 );
+		in.read( ivec, 8 );
+
+		// check to make sure the magic numbers were present
+		if( strcmp( (char *)encsig, (char *)checksig ) != 0 )
+		{
+			throw( BFCryptException( "This file does not appear to be an encrypted file, or it has been corrupted." ) );
+		}
+
+		// do a light check to make sure the password at least appears to be correct
+		if( strcmp( hashPassOnce( password.c_str() ).c_str(), pass ) != 0 )
+		{
+			throw( BFCryptException( "You have entered an invalid username and/or password." ) );
+		}
+
+		// make sure the username is correct
+		if( strcmp( username.c_str(), user ) != 0 )
+		{
+			throw( BFCryptException( "You have entered an invalid username and/or password." ) );
+		}
+
+		std::ofstream out( outFile.c_str(), std::ios::binary );
+		if( !out.is_open() )
+		{
+			throw( BFCryptException( "Could not open temp file for writing." ) );
+		}
+
+		#ifndef WIN32
+			chmod( outFile.c_str(), 0600 );
+		#endif
+
+		// and decrypt the file using the salt and ivec found in the file
+		cryptFile( in, out, password, (unsigned char *)salt, (unsigned char *)ivec, 0, fileLength );
+	}
+
+	void BFCryptFile::encryptFile( std::string username, std::string password, std::string inFile, std::string outFile )
+	{
+		char salt[8] = { '\0' };
+		char ivec[8] = { '\0' };
+
+		// create a random ivec and salt
+		RAND_bytes( (unsigned char *)salt, 8 );
+		RAND_bytes( (unsigned char *)ivec, 8 );
+
+		std::ifstream in( inFile.c_str(), std::ios::binary );
+		in.seekg( 0, std::ios::end );
+		int fileLength = in.tellg();
+		in.seekg( 0, std::ios::beg );
+
+		if( !in.is_open() )
+		{
+			throw( BFCryptException( "Could not open input file for reading." ) );
+		}
+
+		std::ofstream out( outFile.c_str(), std::ios::binary );
+		if( !out.is_open() )
+		{
+			throw( BFCryptException( "Could not open input file for writing." ) );
+		}
+
+		// write the username, the hashed password, the salt, the encryption
+		// signature, and the ivec to the file
+		out << username << std::endl;
+		out << hashPassOnce( password.c_str() ) << std::endl;
+		out.write( (char *)encsig, 25 );
+		out.write( salt, 8 );
+		out.write( ivec, 8 );
+
+		#ifndef WIN32
+			chmod( outFile.c_str(), 0600 );
+		#endif
+
+		// encrypt the rest of the data and write it to the output file
+		cryptFile( in, out, password, (unsigned char *)salt, (unsigned char *)ivec, 1, fileLength );
+	}
+
+	void BFCryptFile::cryptFile( std::ifstream &ifile, std::ofstream &ofile, std::string pass, unsigned char *salt,
+		unsigned char *ivec, int encordec, int fileLength )
+	{
+		unsigned char in[1042];
+		unsigned char out[1024 + EVP_MAX_BLOCK_LENGTH];
+		unsigned long size = 0;
+		int outlen = 0;
+		int progressCounter = 0;
+
+		std::string typeString = "Encrypting";
+		if( !encordec ) typeString = "Decrypting";
+
+		pass = hashPass( pass.c_str(), salt );
+
+		EVP_CIPHER_CTX ctx;
+		EVP_CIPHER_CTX_init( &ctx );
+
+		// initialize the encrypt functions to use blowfish
+		if( !EVP_CipherInit( &ctx, EVP_bf_cbc(), NULL, NULL, encordec ) )
+		{
+			throw( BFCryptException( "OpenSSL error setting ctx key." ) );
+		}
+
+		// set the blowfish key length
+		EVP_CIPHER_CTX_set_key_length( &ctx, pass.length() );
+
+		// set the key and the initialization vector
+		if( !EVP_CipherInit( &ctx, NULL, (unsigned char *)pass.c_str(), ivec, encordec ) )
+		{
+			throw( BFCryptException( "OpenSSL error setting ctx key." ) );
+		}
+
+		int markCount = 40;
+		int marker = fileLength / markCount;
+		int markers = 0;
+		int mark = 0;
+		int currentSize = 0;
+		int updateCount = -1;
+
+		float percent = 0.0;
+
+		while( !ifile.eof() )
+		{
+			bzero( in, 1024 );
+			bzero( out, 1024 );
+			// read in data from the in file
+
+			ifile.read( (char *)in, 1024 );
+			size = ifile.gcount();
+
+			if( size )
+			{
+				// encrypt/decrypt the data
+				if( !EVP_CipherUpdate( &ctx, out, &outlen, in, size ) )
+				{
+					throw( BFCryptException( "OpenSSL error while decrypting/encrypting file.  It's possible that your password was bad, or the file was corrupted." ) );
+				}
+
+				// write the new data to the output file
+				ofile.write( (char *)out, outlen );
+
+				currentSize += size;
+			}
+
+			percent = ( (float)currentSize / (float)fileLength );
+			if( !size || ifile.eof() ) percent = 1;
+
+			mark += size;
+			if( mark > marker )
+			{
+				markers++;
+				mark = 0;
+			}
+
+			if( markers == markCount - 1 ) percent = 1;
+
+			if( updateCount > 100 || updateCount == -1 )
+			{
+				std::cout << "\r" + typeString + ": [";
+				for( int i = 0; i <= markers; i++ ) std::cout << "#";
+				for( int i = markers; i < markCount - 1; i++ ) std::cout << " ";
+				std::cout << std::flush << "] " << (int)( percent * 100 ) << "\%\r";
+				updateCount = 0;
+			}
+			updateCount++;
+		}
+
+		std::cout << "\r" + typeString + ": [";
+		for( int i = 0; i <= markCount; i++ ) std::cout << "#";
+		std::cout << "] " << (int)( percent * 100 ) << "\%\r";
+
+		// finalize the encryption (this adds padding where it is needed
+		if( !EVP_CipherFinal( &ctx, out, &outlen ) )
+		{
+			throw( BFCryptException( "OpenSSL error while decrypting/encrypting file.  It's possible that your password was bad, or the file was corrupted." ) );
+		}
+
+		// write the finalized/padded info to the file
+		ofile.write( (char *)out, outlen );
+
+		EVP_CIPHER_CTX_cleanup( &ctx );
+		ifile.close();
+		ofile.close();
+	}
+
+	void BFCryptFile::shredFile( const char *file )
+	{
+		std::ifstream in( file, std::ios::binary );
+		if( !in.is_open() ) return;
+
+		// find out the file size
+		in.seekg( 0, std::ios::end );
+		unsigned int fileLength = in.tellg();
+		in.seekg( 0, std::ios::beg );
+		in.close();
+
+		// write zeros the length of the file
+		std::ofstream out( file, std::ios::binary );
+		if( !out.is_open() ) return;
+
+		for( unsigned int i = 0; i < fileLength; i++ )
+		{
+			out.put( '\0' );
+		}
+
+		out.close();
+
+		// delete the file
+		unlink( file );
+	}
+}

cpp/hider/aolib/bfcryptfile.hpp

+/*
+    Copyright (C) 2004 Adam Olsen
+
+	This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 1, or (at your option)
+    any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+#ifndef BFCRYPT_FILE_HPP
+#define BFCRYPT_FILE_HPP
+
+#include <openssl/rand.h>
+#include <openssl/evp.h>
+#include <sys/stat.h>
+#include <fstream>
+#include <iostream>
+#include <unistd.h>
+#include <string>
+#include <string.h>
+#include <sstream>
+
+#ifndef EVP_MAX_BLOCK_LENGTH
+#define EVP_MAX_BLOCK_LENGTH 32
+#endif
+
+namespace aolib
+{
+	/**
+	 * Takes the specified file "inFile" and encrypts or decrypts it to "outFile", using the specified
+	 * password as the key.  Each time the file is encrypted, a new initialization vector for Blowfish and a new
+	 * salt for SHA-1 are created from random bits and written out to the encrypted file. These two are then read off of the top
+	 * of the file for decryption.
+	 * @author Adam Olsen
+	**/
+	class BFCryptFile
+	{
+		private:
+			/**
+			 * Encrypts or decrypts ifile to ofile according to encordec, using pass, salt, and ivec.  If any problems occur,
+			 * a BFCryptException will be thrown
+			**/
+			static void cryptFile( std::ifstream &ifile, std::ofstream &ofile, std::string pass, unsigned char *salt,
+				unsigned char *ivec, int encordec, int fileLength );
+
+		public:
+			/**
+			 * The encsig is an implemntation of "magic numbers".  25 bytes of seemingly random characters
+			 * are written to the top of an encrypted file.  When decrypting, if these bytes aren't found,
+			 * then we know that it's not an encrypted file (at least not one encrypted by this class).
+			**/
+			static const unsigned char encsig[];
+
+			/**
+			 * Hashes the specified string "pass" one time with sha-1, and passes back only the first 16 bits for
+			 * storeage in the encrypted file.  What this does is it leads to any dictionary attacks appearing to
+			 * be accepted (1 out of 65536 will appear correct) until the decryption fails
+			**/
+			static std::string hashPassOnce( const char *pass );
+
+			/**
+			 * Hashes the specified string "pass" 10000 times with SHA-1 using "salt" as the salt.
+			**/
+			static std::string hashPass( const char *pass, unsigned char *salt );
+
+			/**
+			 * Zeros out a file by writing '\0' to every byte, and then unlinks it
+			**/
+			static void shredFile( const char *file );
+
+			/**
+			 * Encrypts inFile to outFile. If any errors occur, a BFCryptException will be thrown
+			**/
+			static void encryptFile( std::string username, std::string password, std::string inFile, std::string outFile );
+
+			/**
+			 * Decrypts inFile to outFile.If any errors occur, a BFCryptException will be thrown
+			**/
+			static void decryptFile( std::string username, std::string password, std::string inFile, std::string outFile );
+
+			static bool checkSig( std::string file );
+	};
+
+	class BFCryptException
+	{
+		private:
+			std::string message;
+		public:
+			BFCryptException( const char *error ) { this->message = error; }
+			BFCryptException( std::string error ) { this->message = error; }
+			std::string what() { return message; }
+	};
+}
+
+#endif // BFCRYPT_FILE_HPP

cpp/hider/main.cpp

+#include <unistd.h>
+#include <errno.h>
+#include <iostream>
+#include <aolib/bfcryptfile.hpp>
+#include <string>
+#include <map>
+#include <stdlib.h>
+#include <stdio.h>
+#include <fstream>
+#include <time.h>
+#include <sstream>
+
+
+using namespace std;
+
+map<string, string> options;
+map<string, string> settings;
+const string VERSION = ".01b";
+
+void error( string message )
+{
+	cout << message << endl << endl;
+	exit( -1 );
+}
+
+void setUpOptions()
+{
+	options["h"] = "-";
+	options["help"] = "-";
+	options["X"] = "-";
+	options["v"] = "-";
+	options["o"] = "reqoption";
+	options["p"] = "optionaloption";
+	options["u"] = "reqoption";
+	options["S"] = "-";
+	options["d"] = "-";
+}
+
+void showUseage()
+{
+	cout << "Useage: hider [options] inputfile" << endl;
+	cout << "Valid options are:" << endl << endl;
+	cout << "\t-o\tThe output file (not required, an automatic one \n\t\twill be generated)" << endl << endl;
+	cout << "\t-p\tThe password (if not specified on the command line, you \n\t\twill be prompted)" << endl << endl;
+	cout << "\t-u\tThe username.  It is not required, and if not \n\t\tyou will be provided a default will be used ";
+	cout << "\n\t\t(this does not effect security much.  You should \n\t\treally be trying to choose a good password)\n\t\t" << endl;
+	cout << "\t-h\tThis will simply show you this message." << endl << endl;
+	cout << "\t-v\tShow the version number of this software," << endl << endl;
+	cout << "\t-d\tDelete the input file after the output file is created.\n\t\tThis is simply done with an unlink.";
+	cout << "If you require \n\t\tmore security, use -S instead." << endl << endl;
+	cout << "\t-X\tWrite output to the original file \n\t\t(can only be used if you did not specify -o) " << endl << endl;
+	cout << "\t-S\tShreds the input file leaving only the output file.  \n\t\tNote that this can take a long time depending on\n\t\tthe file size.  It normally takes ";
+	cout << "about the same amount \n\t\tof time it took to encrypt the file." << endl << endl;
+
+	cout << endl;
+	exit( -1 );
+}
+
+bool fileExists( string filename )
+{
+	ifstream in( filename.c_str(), ios::in );
+	bool exists = false;
+
+	if( in.is_open() )
+	{
+		exists = true;
+		in.close();
+	}
+	return exists;
+}
+
+void showVersion()
+{
+	cout << "Adam's encryptor v" << VERSION << " (c)2004" << endl << endl;
+	exit( 0 );
+}
+
+bool checkOption( string arg, int &num, int argc, char **argv, int &argcount )
+{
+	if( arg == "h" ) showUseage();
+	if( arg == "v" ) exit( 0 );
+	string type = options[arg];
+	if( type == "" ) error( "Invalid option: \"" + arg + "\".  Please try -h for help." );
+
+	if( type.find( "option" ) != string::npos )
+	{
+		if( num < argc && argv[num + 1][0] != '-' )
+		{
+			settings[arg] = argv[num + 1];
+			argcount--;
+		}
+		else if( type.find( "reqoption" ) == string::npos ) return false;
+	}
+	else settings[arg] = "_ ok _";
+
+	return true;
+}
+
+void checkPasswords()
+{
+	if( settings["u"] == "_ ok _" && settings["u"] != "" )
+	{
+		cout << "Enter the username for this archive: ";
+		cin >> settings["u"];
+	}
+
+	if( settings["p"] == "" )
+	{
+		string courtesy = "";
+
+		if( settings["method"] == "encrypt" ) courtesy = "you would like to use";
+
+		char *pass = getpass( ( "Please enter the password " + courtesy + "for this archive: " ).c_str() );
+		string password = pass;
+		if( password == "" ) error( "Don't enter an empty password." );
+
+		if( settings["method"] == "encrypt" )
+		{
+			pass = getpass( "For security sake, please verify your new password: " );
+			string verify = pass;
+			if( password != verify )
+			{
+				cout << "Password and verification don't match." << endl << endl;
+				checkPasswords();
+			}
+		}
+
+		settings["p"] = password;
+	}
+}
+
+void parseArgs( int argc, char **argv )
+{
+	if( argc <= 1 ) showUseage();
+
+	int argCount = -1;
+	for( int i = 1; i < argc; i++ )
+	{
+		string arg = argv[i];
+		if( arg.substr( 0, 1 ) == "-" )
+		{
+			string temp;
+
+			for( int a = 1; a < arg.length(); a++ )
+			{
+				temp += arg[a];
+			}
+
+			bool ok = checkOption( temp, i, argc, argv, argCount );
+			if( !ok ) error( "Sorry, but the argument \"" + arg + "\" requires a parameter." );
+		}
+		else argCount++;
+	}
+
+	string infile = argv[argc - 1];
+	if( infile == "" || argCount ) error( "Invalid syntax.  Try -h" );
+
+	settings["i"] = infile;
+
+	if( argCount > 0 ) showUseage();
+
+	try {
+		if( aolib::BFCryptFile::checkSig( settings["i"] ) )
+		{
+			settings["method"] = "encrypt";
+		}
+		else settings["method"] = "decrypt";
+	}
+	catch( aolib::BFCryptException ex )
+	{
+		error( ex.what() );
+	}
+
+	if( settings["method"] == "encrypt" )
+	{
+		cout << "This is not an encrypted file.  Using encryption mode." << endl;
+	}
+	else {
+		cout << "This is an encrypted file.  Using decryption mode." << endl;
+	}
+
+	if( settings["X"] != "" )
+	{
+		if( settings["o"] != "" ) error( "Sorry, you cannot specify an output file in conjunction with the -X option." );
+		settings["o"] = ".tmp__" + settings["i"];
+	}
+
+	if( settings["o"] == "" )
+	{
+		if( settings["method"] == "encrypt" ) settings["o"] = settings["i"] + ".enc";
+		else settings["o"] = settings["i"] + ".dec";
+	}
+
+	if( fileExists( settings["o"] ) ) error( "The output file \"" + settings["o"] +
+		"\". already exists.\nI won't overwrite it so I'm bailing out.\nTry using the -o switch to specify a different file name." );
+
+	map<string, string>::iterator i;
+	for( i = options.begin(); i != options.end(); i++ )
+	{
+		string key = i->first;
+		string value = i->second;
+
+		if( value.substr( 0, 2 ) == "r " && settings[key] == "" )
+		{
+			cout << "Required parameter " + key + " was not specified." << endl;
+			showUseage();
+		}
+	}
+
+	if( settings["u"] == "" ) settings["u"] = "defaultusername";
+	checkPasswords();
+}
+
+int main( int argc, char **argv )
+{
+	// a quick blurb about who wrote the app
+	cout << "Blowfish encryption utility v" + VERSION + " (c)2004 by Adam Olsen (synic)" << endl << endl;
+
+	setUpOptions();
+	parseArgs( argc, argv );
+
+	try {
+		if( settings["method"] == "encrypt" ) aolib::BFCryptFile::encryptFile( settings["u"], settings["p"], settings["i"], settings["o"] );
+		else aolib::BFCryptFile::decryptFile( settings["u"], settings["p"], settings["i"], settings["o"] );
+	}
+	catch( aolib::BFCryptException ex )
+	{
+		cout << "*** Failed." << endl;
+		cout << "Sorry, there was an error " + settings["method"] + "ing your file." << endl;
+		cout << ex.what() << endl << endl;
+		return -1;
+	}
+
+	cout << endl;
+
+	if( settings["X"] != "" )
+	{
+		int res = rename( settings["o"].c_str(), settings["i"].c_str() );
+
+		if( res == -1 )
+		{
+			cout << "Failed to rename temp file \"" + settings["o"] + "\".  Error code: " << errno << endl;
+			exit( -1 );
+		}
+
+		settings["o"] = settings["i"];
+	}
+	else if( settings["S"] != "" )
+	{
+		cout << "Shredding original input file - one moment..." << endl;;
+		aolib::BFCryptFile::shredFile( settings["i"].c_str() );
+		cout << "Done." << endl;
+	}
+	else if( settings["d"] != "" ) unlink( settings["i"].c_str() );
+
+	cout << endl << "Success!  Your " + settings["method"] + "ed output was saved to " + settings["o"] << endl << endl;
+
+	return 0;
+}

main.cpp

-#include <unistd.h>
-#include <errno.h>
-#include <iostream>
-#include <aolib/bfcryptfile.hpp>
-#include <string>
-#include <map>
-#include <stdlib.h>
-#include <stdio.h>
-#include <fstream>
-#include <time.h>
-#include <sstream>
-
-
-using namespace std;
-
-map<string, string> options;
-map<string, string> settings;
-const string VERSION = ".01b";
-
-void error( string message )
-{
-	cout << message << endl << endl;
-	exit( -1 );
-}
-
-void setUpOptions()
-{
-	options["h"] = "-";
-	options["help"] = "-";
-	options["X"] = "-";
-	options["v"] = "-";
-	options["o"] = "reqoption";
-	options["p"] = "optionaloption";
-	options["u"] = "reqoption";
-	options["S"] = "-";
-	options["d"] = "-";
-}
-
-void showUseage()
-{
-	cout << "Useage: hider [options] inputfile" << endl;
-	cout << "Valid options are:" << endl << endl;
-	cout << "\t-o\tThe output file (not required, an automatic one \n\t\twill be generated)" << endl << endl;
-	cout << "\t-p\tThe password (if not specified on the command line, you \n\t\twill be prompted)" << endl << endl;
-	cout << "\t-u\tThe username.  It is not required, and if not \n\t\tyou will be provided a default will be used ";
-	cout << "\n\t\t(this does not effect security much.  You should \n\t\treally be trying to choose a good password)\n\t\t" << endl;
-	cout << "\t-h\tThis will simply show you this message." << endl << endl;
-	cout << "\t-v\tShow the version number of this software," << endl << endl;
-	cout << "\t-d\tDelete the input file after the output file is created.\n\t\tThis is simply done with an unlink.";
-	cout << "If you require \n\t\tmore security, use -S instead." << endl << endl;
-	cout << "\t-X\tWrite output to the original file \n\t\t(can only be used if you did not specify -o) " << endl << endl;
-	cout << "\t-S\tShreds the input file leaving only the output file.  \n\t\tNote that this can take a long time depending on\n\t\tthe file size.  It normally takes ";
-	cout << "about the same amount \n\t\tof time it took to encrypt the file." << endl << endl;
-
-	cout << endl;
-	exit( -1 );
-}
-
-bool fileExists( string filename )
-{
-	ifstream in( filename.c_str(), ios::in );
-	bool exists = false;
-
-	if( in.is_open() )
-	{
-		exists = true;
-		in.close();
-	}
-	return exists;
-}
-
-void showVersion()
-{
-	cout << "Adam's encryptor v" << VERSION << " (c)2004" << endl << endl;
-	exit( 0 );
-}
-
-bool checkOption( string arg, int &num, int argc, char **argv, int &argcount )
-{
-	if( arg == "h" ) showUseage();
-	if( arg == "v" ) exit( 0 );
-	string type = options[arg];
-	if( type == "" ) error( "Invalid option: \"" + arg + "\".  Please try -h for help." );
-
-	if( type.find( "option" ) != string::npos )
-	{
-		if( num < argc && argv[num + 1][0] != '-' )
-		{
-			settings[arg] = argv[num + 1];
-			argcount--;
-		}
-		else if( type.find( "reqoption" ) == string::npos ) return false;
-	}
-	else settings[arg] = "_ ok _";
-
-	return true;
-}
-
-void checkPasswords()
-{
-	if( settings["u"] == "_ ok _" && settings["u"] != "" )
-	{
-		cout << "Enter the username for this archive: ";
-		cin >> settings["u"];
-	}
-
-	if( settings["p"] == "" )
-	{
-		string courtesy = "";
-
-		if( settings["method"] == "encrypt" ) courtesy = "you would like to use";
-
-		char *pass = getpass( ( "Please enter the password " + courtesy + "for this archive: " ).c_str() );
-		string password = pass;
-		if( password == "" ) error( "Don't enter an empty password." );
-
-		if( settings["method"] == "encrypt" )
-		{
-			pass = getpass( "For security sake, please verify your new password: " );
-			string verify = pass;
-			if( password != verify )
-			{
-				cout << "Password and verification don't match." << endl << endl;
-				checkPasswords();
-			}
-		}
-
-		settings["p"] = password;
-	}
-}
-
-void parseArgs( int argc, char **argv )
-{
-	if( argc <= 1 ) showUseage();
-
-	int argCount = -1;
-	for( int i = 1; i < argc; i++ )
-	{
-		string arg = argv[i];
-		if( arg.substr( 0, 1 ) == "-" )
-		{
-			string temp;
-
-			for( int a = 1; a < arg.length(); a++ )
-			{
-				temp += arg[a];
-			}
-
-			bool ok = checkOption( temp, i, argc, argv, argCount );
-			if( !ok ) error( "Sorry, but the argument \"" + arg + "\" requires a parameter." );
-		}
-		else argCount++;
-	}
-
-	string infile = argv[argc - 1];
-	if( infile == "" || argCount ) error( "Invalid syntax.  Try -h" );
-
-	settings["i"] = infile;
-
-	if( argCount > 0 ) showUseage();
-
-	try {
-		if( aolib::BFCryptFile::checkSig( settings["i"] ) )
-		{
-			settings["method"] = "encrypt";
-		}
-		else settings["method"] = "decrypt";
-	}
-	catch( aolib::BFCryptException ex )
-	{
-		error( ex.what() );
-	}
-
-	if( settings["method"] == "encrypt" )
-	{
-		cout << "This is not an encrypted file.  Using encryption mode." << endl;
-	}
-	else {
-		cout << "This is an encrypted file.  Using decryption mode." << endl;
-	}
-
-	if( settings["X"] != "" )
-	{
-		if( settings["o"] != "" ) error( "Sorry, you cannot specify an output file in conjunction with the -X option." );
-		settings["o"] = ".tmp__" + settings["i"];
-	}
-
-	if( settings["o"] == "" )
-	{
-		if( settings["method"] == "encrypt" ) settings["o"] = settings["i"] + ".enc";
-		else settings["o"] = settings["i"] + ".dec";
-	}
-
-	if( fileExists( settings["o"] ) ) error( "The output file \"" + settings["o"] +
-		"\". already exists.\nI won't overwrite it so I'm bailing out.\nTry using the -o switch to specify a different file name." );
-
-	map<string, string>::iterator i;
-	for( i = options.begin(); i != options.end(); i++ )
-	{
-		string key = i->first;
-		string value = i->second;
-
-		if( value.substr( 0, 2 ) == "r " && settings[key] == "" )
-		{
-			cout << "Required parameter " + key + " was not specified." << endl;
-			showUseage();
-		}
-	}
-
-	if( settings["u"] == "" ) settings["u"] = "defaultusername";
-	checkPasswords();
-}
-
-int main( int argc, char **argv )
-{
-	// a quick blurb about who wrote the app
-	cout << "Blowfish encryption utility v" + VERSION + " (c)2004 by Adam Olsen (synic)" << endl << endl;
-
-	setUpOptions();
-	parseArgs( argc, argv );
-
-	try {
-		if( settings["method"] == "encrypt" ) aolib::BFCryptFile::encryptFile( settings["u"], settings["p"], settings["i"], settings["o"] );
-		else aolib::BFCryptFile::decryptFile( settings["u"], settings["p"], settings["i"], settings["o"] );
-	}
-	catch( aolib::BFCryptException ex )
-	{
-		cout << "*** Failed." << endl;
-		cout << "Sorry, there was an error " + settings["method"] + "ing your file." << endl;
-		cout << ex.what() << endl << endl;
-		return -1;
-	}
-
-	cout << endl;
-
-	if( settings["X"] != "" )
-	{
-		int res = rename( settings["o"].c_str(), settings["i"].c_str() );
-
-		if( res == -1 )
-		{
-			cout << "Failed to rename temp file \"" + settings["o"] + "\".  Error code: " << errno << endl;
-			exit( -1 );
-		}
-
-		settings["o"] = settings["i"];
-	}
-	else if( settings["S"] != "" )
-	{
-		cout << "Shredding original input file - one moment..." << endl;;
-		aolib::BFCryptFile::shredFile( settings["i"].c_str() );
-		cout << "Done." << endl;
-	}
-	else if( settings["d"] != "" ) unlink( settings["i"].c_str() );
-
-	cout << endl << "Success!  Your " + settings["method"] + "ed output was saved to " + settings["o"] << endl << endl;
-
-	return 0;
-}
+#!/usr/bin/env python
+
+from Crypto.Cipher import Blowfish
+from Crypto.Hash import SHA
+from Crypto import Random
+from optparse import OptionParser
+import sys
+import struct
+import os.path
+import os
+
+_MAGIC = bytearray([0, 2, 144, 4, 3, 4, 5, 6, 3, 12, 144, 134, 5, 6, 24, 2, 0, 3, 4, 3, 4, 3, 88, 4, 5])
+
+def check_file(f):
+    h = open(f, 'r')
+    test = h.read(len(_MAGIC))
+    h.close()
+    return test == _MAGIC
+
+def encrypt_file(inf, outf, password):
+    infile = open(inf, 'r')
+    outfile = open(outf, 'w')
+
+    iv = Random.get_random_bytes(Blowfish.block_size)
+    bf = Blowfish.new(SHA.new(password).hexdigest(), Blowfish.MODE_CBC, iv)
+
+    filesize = os.path.getsize(inf)
+
+    outfile.write(str(_MAGIC))
+    outfile.write(struct.pack('<Q', filesize))
+    outfile.write(iv)
+    outfile.write(bf.encrypt(str(_MAGIC)))
+
+    while True:
+        chunk = infile.read(8192)
+        if len(chunk) == 0:
+            break
+        elif len(chunk) % 16 != 0:
+            chunk += ' ' * (16 - len(chunk) % 16)
+
+        outfile.write(bf.encrypt(chunk))
+
+    outfile.close()
+    infile.close()
+
+def decrypt_file(inf, outf, password):
+    infile = open(inf, 'r')
+    outfile = open(outf, 'w')
+
+    test = infile.read(len(_MAGIC))
+    if test != _MAGIC:
+        raise Exception("This is not an encrypted file")
+
+    origsize = struct.unpack('<Q', infile.read(struct.calcsize('Q')))[0]
+    iv = infile.read(Blowfish.block_size)
+    bf = Blowfish.new(SHA.new(password).hexdigest(), Blowfish.MODE_CBC, iv)
+    testdecrypt = bf.decrypt(infile.read(len(_MAGIC)))
+    if testdecrypt != _MAGIC:
+        raise Exception("Failure decrypting file.")
+
+    while True:
+        chunk = infile.read(8192)
+        if len(chunk) == 0:
+            break
+
+        outfile.write(bf.decrypt(chunk))
+
+    outfile.truncate(origsize)
+
+    outfile.close()
+    infile.close()
+
+def main():
+    usage = "Usage: %prog [options] file"
+    parser = OptionParser(usage)
+    parser.add_option("-i", "--input", dest="infile")
+    parser.add_option("-o", "--output", dest="outfile")
+
+    (options, args) = parser.parse_args()
+
+    if not options.infile:
+        if len(args) != 1:
+            parser.error("Incorrect number of arguments")
+        infile = args[0]
+    else:
+        if args:
+            parser.error("Incorrect number of arguments")
+        infile = options.infile
+
+    outfile = options.outfile 
+    
+    if check_file(infile):
+        print "File is to be decrypted."
+        if not outfile: outfile = "%s.dec" % infile
+        decrypt = True
+    else:
+        print "File is to be encrypted."
+        if not outfile: outfile = "%s.enc" % infile
+        decrypt = False
+
+    os.system("stty -echo")
+    print "Please enter your password: ",
+    password = sys.stdin.readline().strip()
+    os.system("stty echo")
+    print ""
+    if decrypt:
+        decrypt_file(infile, outfile, password)
+    else:
+        encrypt_file(infile, outfile, password)
+
+    print "Done.\n"
+
+if __name__ == '__main__':
+    main()