rfick_rb by SkyOut || Project Folder

#!/usr/bin/env/ruby

#Author: SkyOut
#Date: June 2007
#Contact: skyout[-at-]smash-the-stack[-dot-]net
#Websites: http://www.smash-the-stack.net/
#
#RFICK, which stands for Ruby File Integrity ChecKer is
#a simple proof-of-concept ruby script, that saves hash
#values in a specified directory (which you have to set
#before using it) and afterwards can check whether the
#hashvalues have changed. If so a warning will be displayed
#to make you recognize the change!
#
#DO NOT FORGET TO MODIFY THE VARIABLE 'homepath', in
#this directory a folder 'rfick' will be created, where
#the files 'md5.txt' and/or 'sha1.txt' and/or 'rmd160.txt'
#will be stored. They contain the hashvalues and the paths
#to the files of those values. Afterwards they will be used
#to check if the hashvalue has changed, the most important
#part of the script.
#
#To start the script the first time you for example do something
#like:
#
#$ ruby rfick.rb -create MD5 /home/user
#
#This will store the hashvalues of the files in your home
#directory to 'homepath'/rfick/md5.txt! To recheck those
#values later you just have to type:
#
#$ ruby rfick.rb -check MD5
#
#and all values will be compared with the current hashvalues
#of the files. If anything has changed you will get a warning.

require 'digest/md5'
require 'digest/sha1'
require 'digest/rmd160'

# Display the usage dialogue
def usage()
	puts ""
	puts "-----------------------------------------"
	puts "| Ruby File Integrity ChecKer by SkyOut |"
	puts "-----------------------------------------"
	puts ""
	puts "-----------------------------------------------------------------------"
	puts "| Usage: ruby rfick.rb [-check|-create] [MD5|SHA1|RMD160] [directory] |"
	puts "-----------------------------------------------------------------------"
	puts ""
	exit(0)
end

# Check if the right parameters have been set
if (ARGV[0] == nil) || (ARGV[1] == nil)
	usage
end

if (ARGV[0] == "-create") && (ARGV[2] == nil)
	usage
end

###############################################
# HAS TO BE SET BY THE USER AT FIRST USE!!!   #
###############################################
# WILL CREATE A FOLDER "rfick" FOR THE FILES  #
###############################################
homepath = "/home/user"                       #
###############################################

# Create the directory to store our files
if !File.exist?("#{homepath}/rfick")
	Dir.mkdir("#{homepath}/rfick")
end

# Check whether the MD5, SHA1 or RMD160 has been chosen
if (ARGV[0] == "-create")
	if (ARGV[1] == "MD5")
		md5hash   = File.open("#{homepath}/rfick/md5.txt", File::WRONLY|File::TRUNC|File::CREAT, 0777)
	elsif (ARGV[1] == "SHA1")
		sha1hash   = File.open("#{homepath}/rfick/sha1.txt", File::WRONLY|File::TRUNC|File::CREAT, 0777)
	elsif (ARGV[1] == "RMD160")
		rmd160hash   = File.open("#{homepath}/rfick/rmd160.txt", File::WRONLY|File::TRUNC|File::CREAT, 0777)
	else
		usage
	end
end

# Create the file with the hash values
if (ARGV[0] == "-create")

	Dir.open(ARGV[2]) do |dir|
		dir.each do |file|

			next if file == "." || file == ".."

			if (ARGV[2] == "/")
				path = ARGV[2] + file
			else
				path = ARGV[2] + "/" + file
			end

			if !File.directory?("#{path}")
				if (ARGV[1] == "MD5")
					md5 = Digest::MD5.hexdigest(File.open("#{path}", "rb") { |f| f.read })
					md5hash.puts "#{path} | MD5 | " + md5
				elsif (ARGV[1] == "SHA1")
					sha1 = Digest::SHA1.hexdigest(File.open("#{path}", "rb") { |f| f.read })
					sha1hash.puts "#{path} | SHA1 | " + sha1
				else (ARGV[1] == "RMD160")
					rmd160 = Digest::RMD160.hexdigest(File.open("#{path}", "rb") { |f| f.read })
					rmd160hash.puts "#{path} | RMD160 | " + rmd160
				end
			end

		end
	end

# Check whether the hash values have changed or not
elsif (ARGV[0] == "-check")

	# Check for MD5 ('md5.txt')
	if (ARGV[1] == "MD5")

		# Make sure the file 'md5.txt' really exists
		if !File.exist?("#{homepath}/rfick/md5.txt")
			puts "FILE \'md5.txt\' DOES NOT EXIST IN THE SPECIFIED DIRECTORY!"
			puts "EXITING ..."
			exit(0)
		end

		warnings = 0
		md5hash2 = File.open("#{homepath}/rfick/md5.txt", File::RDONLY)

		begin
		puts ""
		puts "--- STARTING FILE INTEGRITY CHECK USING MD5 ---"
		puts ""
		while (line = md5hash2.readline)

				$filepath = line
				$filepath = $filepath.split(" ")
				$filepath = $filepath.fetch(0)
			
				$hash = line
				$hash = $hash.split(" ")
				$hash = $hash.fetch(4)

				$currenthash = Digest::MD5.hexdigest(File.open("#{$filepath}", "rb") { |f| f.read})
				
				# Compare the current hash with the saved hash
				if ($hash == $currenthash)
					next
				elsif
					warnings += 1
					puts "(!)WARNING(!) HASH CHANGED FOR #{$filepath}"
				end
		end
		rescue EOFError
			md5hash2.close
		end

		puts ""
		puts "--- FILE INTEGRITY CHECK FINISHED ---"
		puts "WARNING(S): #{warnings}"
		puts ""

	# Check for SHA1 ('sha1.txt')
	elsif (ARGV[1] == "SHA1")

		# Make sure the file 'sha1.txt' really exists
		if !File.exist?("#{homepath}/rfick/sha1.txt")
			puts "FILE \'sha1.txt\' DOES NOT EXIST IN THE SPECIFIED DIRECTORY!"
			puts "EXITING ..."
			exit(0)
		end

		warnings = 0
		sha1hash2 = File.open("#{homepath}/rfick/sha1.txt", File::RDONLY)

		begin
		puts ""
		puts "--- STARTING FILE INTEGRITY CHECK USING SHA1 ---"
		puts ""
		while (line = sha1hash2.readline)

				$filepath = line
				$filepath = $filepath.split(" ")
				$filepath = $filepath.fetch(0)
			
				$hash = line
				$hash = $hash.split(" ")
				$hash = $hash.fetch(4)

				$currenthash = Digest::SHA1.hexdigest(File.open("#{$filepath}", "rb") { |f| f.read})
				
				# Compare the current hash with the saved hash
				if ($hash == $currenthash)
					next
				elsif
					warnings += 1
					puts "(!)WARNING(!) HASH CHANGED FOR #{$filepath}"
				end
		end
		rescue EOFError
			sha1hash2.close
		end

		puts ""
		puts "--- FILE INTEGRITY CHECK FINISHED ---"
		puts "WARNING(S): #{warnings}"
		puts ""

	# Check for RMD160 ('rmd160.txt')
	elsif (ARGV[1] == "RMD160")

		# Make sure the file 'rmd160.txt' really exists
		if !File.exist?("#{homepath}/rfick/rmd160.txt")
			puts "FILE \'rmd160.txt\' DOES NOT EXIST IN THE SPECIFIED DIRECTORY!"
			puts "EXITING ..."
			exit(0)
		end

		warnings = 0
		rmd160hash2 = File.open("#{homepath}/rfick/rmd160.txt", File::RDONLY)

		begin
		puts ""
		puts "--- STARTING FILE INTEGRITY CHECK USING RMD160 ---"
		puts ""
		while (line = rmd160hash2.readline)

				$filepath = line
				$filepath = $filepath.split(" ")
				$filepath = $filepath.fetch(0)
			
				$hash = line
				$hash = $hash.split(" ")
				$hash = $hash.fetch(4)

				$currenthash = Digest::RMD160.hexdigest(File.open("#{$filepath}", "rb") { |f| f.read})
				
				# Compare the current hash with the saved hash
				if ($hash == $currenthash)
					next
				elsif
					warnings += 1
					puts "(!)WARNING(!) HASH CHANGED FOR #{$filepath}"
				end
		end
		rescue EOFError
			rmd160hash2.close
		end

		puts ""
		puts "--- FILE INTEGRITY CHECK FINISHED ---"
		puts "WARNING(S): #{warnings}"
		puts ""

	end

else
	usage
end

# Check whether MD5, SHA1 or RMD160 has been chosen
# and close the file handler finally
if (ARGV[0] == "-create")
	if (ARGV[1] == "MD5")
		md5hash.close
	elsif (ARGV[1] == "SHA1")
		sha1hash.close
	else (ARGV[1] == "RMD160")
		rmd160hash.close
	end
end

exit(0)