OOXML Encryption
Overview
OOXML Encryption provides encryption and decryption support for OOXML (Microsoft Excel / .xlsx
files) via full-spreadsheet password protection using AES encryption with SHA-512 hashes. This is a port of the encryption part of:
Using an input OOXML file generated by https://github.com/felixbuenemann/xlsxtream, encrypted output was tested on macOS 12.5 in Microsoft Excel 16.63.1, Apple Numbers 12.1 (and QuickLook from the Finder) and LibreOffice Vanilla 7.2.5.2, all of which prompted for a password, handled an incorrect password as expected and correctly opened the decrypted spreadsheet if given the correct password.
For low-level file format details, see:
- https://docs.microsoft.com/en-us/openspecs/office_file_formats/ms-offcrypto
- https://github.com/RIPAGlobal/simple_cfb/
Installation
Install the gem and add to the application's Gemfile
by executing:
$ bundle add ooxml_encryption
If bundler is not being used to manage dependencies, install the gem by executing:
$ gem install ooxml_encryption
Usage
Encrypting a spreadsheet
If you have read a file containing an unprotected OOXML file into unprotected_data
as a String using ASCII-8BIT
encoding, or if you have generated such a string in memory directly, then using a password
supplied as a String in an encoding of your choice:
require 'ooxml_encryption'
encryptor = OoxmlEncryption.new
encrypted_data = encryptor.encrypt(
unencrypted_spreadsheet_data: unprotected_data,
password: password
)
...then write encrypted_data
to a file using binary mode, e.g.:
File.open('/path/to/encrypted.xlsx', 'wb') do | file |
file.write(encrypted_data)
end
Decrypting a spreadsheet
If you have read a file containing an encrypted OOXML file into encrypted_data
as a String using ASCII-8BIT
encoding and have obtained a password
from the spreadsheet's owning user as a String in an encoding of your choice, then:
require 'ooxml_encryption'
decryptor = OoxmlEncryption.new
decrypted_data = decryptor.decrypt(
encrypted_spreadsheet_data: encrypted_data,
password: password
)
...then write decrypted_data
to a file using binary mode, e.g.:
File.open('/path/to/unprotected.xlsx', 'wb') do | file |
file.write(decrypted_data)
end
Resource overhead
Due to the nature of the underlying file format, which has various tables written at the start of the file that can only be built once the file contents are known, encrypted spreadsheets must be created or decoded in RAM. Streamed output or input is not possible. Attempting to create or read large spreadsheets is therefore not recommended - there could be very large RAM requirements arising.
Security concerns
The level of security this provides should be assessed relative to your requirements; numerous articles are available online which discuss the pros and cons. The quality of the password will also have a big impact on the overall security of an output file.
Development
Use bundle exec rspec
to run tests. Run bin/console
for an interactive prompt that will allow you to experiment.
To install this gem onto your local machine, run bundle exec rake install
. If you have sufficient RubyGems access to release a new version, update the version number and date in version.rb
, and then run bundle exec rake release
, which will create a git tag for the version, push git commits and the created tag, and push the .gem
file to rubygems.org.
Locally generated RDoc HTML seems to contain a more comprehensive and inter-linked set of pages than those available from rubydoc.info
. You can (re)generate the internal rdoc
documentation with:
bundle exec rake rerdoc
...yes, that's rerdoc
- Re-R-Doc - then open docs/rdoc/index.html
.
Contributing
Bug reports and pull requests are welcome on GitHub at https://github.com/RIPAGlobal/ooxml_encryption.