improved and tested both Mconf encryptor and decryptor

This commit is contained in:
Felipe Cecagno 2013-02-08 16:10:28 -02:00
parent ee1bfee1fb
commit 25c495d123
4 changed files with 120 additions and 83 deletions

View File

@ -31,83 +31,92 @@ BigBlueButton.logger = Logger.new("/var/log/bigbluebutton/decrypt.log",'daily' )
bbb_props = YAML::load(File.open('../../core/scripts/bigbluebutton.yml')) bbb_props = YAML::load(File.open('../../core/scripts/bigbluebutton.yml'))
mconf_props = YAML::load(File.open('mconf.yml')) mconf_props = YAML::load(File.open('mconf.yml'))
privatekey_path = mconf_props['privatekey_path']
xml_url = mconf_props['get_recordings_url'] private_key = mconf_props['private_key']
get_recordings_url = mconf_props['get_recordings_url']
recording_dir = bbb_props['recording_dir'] recording_dir = bbb_props['recording_dir']
rawdir = "#{recording_dir}/raw" raw_dir = "#{recording_dir}/raw"
archived_dir = "#{recording_dir}/status/archived" archived_dir = "#{recording_dir}/status/archived"
xml_data = Net::HTTP.get_response(URI.parse(xml_url)).body doc = Nokogiri::XML(Net::HTTP.get_response(URI.parse(get_recordings_url)).body)
doc = REXML::Document.new(xml_data) returncode = doc.xpath("//returncode")
if returncode.empty? or returncode.text != "SUCCESS"
files_url = [] raise "getRecordings didn't return success"
types = []
keys_url = []
md5_server_side = []
doc.elements.each('response/recordings/recording/download/format/type') do |type|
types << type.text
end
doc.elements.each('response/recordings/recording/download/format/url') do |url|
files_url << url.text
end
doc.elements.each('response/recordings/recording/download/format/md5') do |md5|
md5_server_side << md5.text
end
doc.elements.each('response/recordings/recording/download/format/key') do |key|
keys_url << key.text
end end
types.each_with_index do |eachtype, idx| doc.xpath("//recording").each do |recording|
if (eachtype == "encrypted") then record_id = recording.xpath("recordID").text
url = files_url[idx] recording.xpath("//download/format").each do |format|
k_url = keys_url[idx] type = format.xpath("type").text
encrypted_file = url.split("/").last BigBlueButton.logger.info("type = #{type}")
match = /(.*).dat/.match encrypted_file if type == "encrypted"
meeting_id = match[1] meeting_id = record_id
if not File.exist?("#{archived_dir}/#{meeting_id}.done") then file_url = format.xpath("url").text
Dir.chdir(rawdir) do key_file_url = format.xpath("key").text
md5_value = format.xpath("md5").text
writeOut = open(encrypted_file, "wb") BigBlueButton.logger.info("recordID = #{record_id}")
writeOut.write(open(url).read) BigBlueButton.logger.info("file_url = #{file_url}")
writeOut.close BigBlueButton.logger.info("key_file_url = #{key_file_url}")
BigBlueButton.logger.info("md5_value = #{md5_value}")
md5sum = Digest::MD5.file(encrypted_file) encrypted_file = file_url.split("/").last
decrypted_file = File.basename(encrypted_file, '.*') + ".zip"
if not File.exist?("#{archived_dir}/#{meeting_id}.done") then
Dir.chdir(raw_dir) do
BigBlueButton.logger.info("Decrypting the recording #{meeting_id}")
if (md5sum == md5_server_side[idx]) then BigBlueButton.logger.info("Downloading the encrypted file to #{encrypted_file}")
key_file = k_url.split("/").last writeOut = open(encrypted_file, "wb")
writeOut = open(key_file, "wb") writeOut.write(open(file_url).read)
writeOut.write(open(k_url).read) writeOut.close
writeOut.close
command = "openssl rsautl -decrypt -inkey #{privatekey_path} < #{key_file} > key.txt" md5_calculated = Digest::MD5.file(encrypted_file)
BigBlueButton.logger.info(command)
Open3.popen3(command) do | stdin, stdout, stderr|
BigBlueButton.logger.info("command= #{command}") #{$?.exitstatus}")
end
command = "openssl enc -aes-256-cbc -d -pass file:key.txt < #{encrypted_file} > #{meeting_id}.zip"
BigBlueButton.logger.info(command)
Open3.popen3(command) do | stdin, stdout, stderr|
BigBlueButton.logger.info("command= #{command}") #{$?.exitstatus}")
end
BigBlueButton::MconfProcessor.unzip(rawdir, "#{meeting_id}.zip")
if md5_calculated == md5_value
BigBlueButton.logger.info("The calculated MD5 matches the expected value")
key_file = key_file_url.split("/").last
decrypted_key_file = File.basename(key_file, '.*') + ".txt"
archived_done = File.new("#{archived_dir}/#{meeting_id}.done", "w") BigBlueButton.logger.info("Downloading the key file to #{key_file}")
archived_done.write("Archived #{meeting_id}") writeOut = open(key_file, "wb")
archived_done.close writeOut.write(open(key_file_url).read)
writeOut.close
BigBlueButton.logger.info("Removing files")
ZIPFILE = "#{meeting_id}.zip"
[encrypted_file, key_file, "key.txt", ZIPFILE].each { |file| FileUtils.rm_f(file)}
else
FileUtils.rm_f(encrypted_file)
end
end
end
end if key_file != decrypted_key_file
command = "openssl rsautl -decrypt -inkey #{private_key} < #{key_file} > #{decrypted_key_file}"
status = BigBlueButton.execute(command)
if not status.success?
raise "Couldn't decrypt the random key with the server private key"
end
FileUtils.rm_r "#{key_file}"
else
BigBlueButton.logger.info("No public key was used to encrypt the random key")
end
command = "openssl enc -aes-256-cbc -d -pass file:#{decrypted_key_file} < #{encrypted_file} > #{decrypted_file}"
status = BigBlueButton.execute(command)
if not status.success?
raise "Couldn't decrypt the recording file using the random key"
end
BigBlueButton::MconfProcessor.unzip("#{raw_dir}/#{meeting_id}", decrypted_file)
archived_done = File.new("#{archived_dir}/#{meeting_id}.done", "w")
archived_done.write("Archived #{meeting_id}")
archived_done.close
[ "#{encrypted_file}", "#{decrypted_file}", "#{decrypted_key_file}" ].each { |file|
BigBlueButton.logger.info("Removing #{file}")
FileUtils.rm_r "#{file}"
}
else
BigBlueButton.logger.error("The calculated MD5 doesn't match the expected value")
FileUtils.rm_f(encrypted_file)
end
end
end
end
end
end end

View File

@ -1,2 +1,2 @@
get_recordings_url: http://143.54.10.141/bigbluebutton/api/getRecordings?checksum=890f03ce56424120dc467f3bbf310a54fd05b541 get_recordings_url: http://143.54.10.52/bigbluebutton/api/getRecordings?checksum=39ebeadb772553a206d43857f6287b4536b1c32c
privatekey_path: /home/mconf/key.pem private_key: /home/mconf/dev/bigbluebutton/record-and-playback/key.pem

View File

@ -45,12 +45,15 @@ meeting_raw_presentation_dir = "#{raw_presentation_src}/#{meeting_id}"
meeting_process_dir = "#{recording_dir}/process/mconf/#{meeting_id}" meeting_process_dir = "#{recording_dir}/process/mconf/#{meeting_id}"
if not FileTest.directory?(meeting_process_dir) if not FileTest.directory?(meeting_process_dir)
FileUtils.mkdir_p "#{meeting_process_dir}/presentation_raw" FileUtils.mkdir_p "#{meeting_process_dir}"
# Create a copy of the raw archives # Create a copy of the raw archives
BigBlueButton.logger.info("Copying the recording raw files from #{meeting_raw_dir} to #{meeting_process_dir}") BigBlueButton.logger.info("Copying the recording raw files from #{meeting_raw_dir} to #{meeting_process_dir}")
FileUtils.cp_r Dir.glob("#{meeting_raw_dir}/*"), meeting_process_dir FileUtils.cp_r Dir.glob("#{meeting_raw_dir}/*"), meeting_process_dir
BigBlueButton.logger.info("Copying the recording presentation from #{meeting_raw_presentation_dir}/#{meeting_id} to #{meeting_process_dir}/presentation_raw")
FileUtils.cp_r Dir.glob("#{meeting_raw_presentation_dir}/#{meeting_id}/*"), "#{meeting_process_dir}/presentation_raw" # There's no need to backup the presentation raw folder now
# FileUtils.mkdir_p "#{meeting_process_dir}/presentation_raw"
# BigBlueButton.logger.info("Copying the recording presentation from #{meeting_raw_presentation_dir}/#{meeting_id} to #{meeting_process_dir}/presentation_raw")
# FileUtils.cp_r Dir.glob("#{meeting_raw_presentation_dir}/#{meeting_id}/*"), "#{meeting_process_dir}/presentation_raw"
process_done = File.new("#{recording_dir}/status/processed/#{meeting_id}-mconf.done", "w") process_done = File.new("#{recording_dir}/status/processed/#{meeting_id}-mconf.done", "w")
process_done.write("Processed #{meeting_id}") process_done.write("Processed #{meeting_id}")

View File

@ -62,20 +62,41 @@ done_files.each do |df|
# encrypt files # encrypt files
command = "openssl enc -aes-256-cbc -pass file:#{meeting_id}.txt < #{meeting_id}.zip > #{meeting_id}.dat" command = "openssl enc -aes-256-cbc -pass file:#{meeting_id}.txt < #{meeting_id}.zip > #{meeting_id}.dat"
BigBlueButton.execute(command) status = BigBlueButton.execute(command)
if not status.success?
raise "Couldn't encrypt the recording file using the random key"
end
FileUtils.rm_f "#{meeting_id}.zip"
key_filename = "" key_filename = ""
if metadata.has_key?('public_key') if metadata.has_key?('public-key')
key_filename = "#{meeting_id}.enc" key_filename = "#{meeting_id}.enc"
BigBlueButton.logger.info("Unescaping public key") #BigBlueButton.logger.info("Unescaping public key")
public_key_decoded = CGI::unescape("#{metadata[:public_key.to_s]}") #public_key_decoded = CGI::unescape("#{metadata['public-key'].to_s}")
public_key = File.new("public_key.pem","w") # The key is already unescaped in the metadata!!
public_key_decoded = "#{metadata['public-key'].to_s}"
public_key_filename = "public-key.pem"
public_key = File.new("#{public_key_filename}", "w")
public_key.write "#{public_key_decoded}" public_key.write "#{public_key_decoded}"
public_key.close public_key.close
command = "openssl rsautl -encrypt -pubin -inkey public-key.pem < #{meeting_id}.txt > #{meeting_id}.enc" public_key = File.new("#{public_key_filename}", "r")
BigBlueButton.execute(command) counter = 0
FileUtils.rm_f "#{meeting_id}.txt" while (line = public_key.gets)
BigBlueButton.logger.info "#{counter}: #{line}"
counter = counter + 1
end
public_key.close
command = "openssl rsautl -encrypt -pubin -inkey #{public_key_filename} < #{meeting_id}.txt > #{meeting_id}.enc"
status = BigBlueButton.execute(command)
if not status.success?
raise "Couldn't encrypt the random key using the server public key passed as metadata"
end
# Comment it for testing
FileUtils.rm_f ["#{meeting_id}.txt", "#{public_key_filename}"]
else else
key_filename = "#{meeting_id}.txt" key_filename = "#{meeting_id}.txt"
BigBlueButton.logger.warn "No public key was found in the meeting's metadata" BigBlueButton.logger.warn "No public key was found in the meeting's metadata"
@ -86,9 +107,6 @@ done_files.each do |df|
BigBlueButton.logger.info("Creating metadata.xml") BigBlueButton.logger.info("Creating metadata.xml")
# TODO: create a flag to indicate if the file .enc is encrypted or not
# due to the presence the public key in the meeting's metadata
# Create metadata.xml # Create metadata.xml
b = Builder::XmlMarkup.new(:indent => 2) b = Builder::XmlMarkup.new(:indent => 2)
metaxml = b.recording { metaxml = b.recording {
@ -128,6 +146,13 @@ done_files.each do |df|
BigBlueButton.logger.info("Removing published files: #{meeting_publish_dir}") BigBlueButton.logger.info("Removing published files: #{meeting_publish_dir}")
FileUtils.remove_entry_secure meeting_publish_dir, :force => true, :verbose => true FileUtils.remove_entry_secure meeting_publish_dir, :force => true, :verbose => true
# Remove all the recording flags
FileUtils.rm_f [ "#{recording_dir}/status/processed/#{meeting_id}-mconf.done",
"#{recording_dir}/status/sanity/#{meeting_id}.done",
"#{recording_dir}/status/recorded/#{meeting_id}.done",
"#{recording_dir}/status/archived/#{meeting_id}.done" ]
# Comment it for testing
BigBlueButton.logger.info("Removing the recording raw files: #{meeting_raw_dir}") BigBlueButton.logger.info("Removing the recording raw files: #{meeting_raw_dir}")
FileUtils.remove_entry_secure meeting_raw_dir, :force => true, :verbose => true FileUtils.remove_entry_secure meeting_raw_dir, :force => true, :verbose => true
BigBlueButton.logger.info("Removing the recording presentation: #{meeting_raw_presentation_dir}") BigBlueButton.logger.info("Removing the recording presentation: #{meeting_raw_presentation_dir}")