module HexaPDF::Encryption::AES::ClassMethods
Convenience methods for decryption and encryption that operate according to the PDF specification.
These methods will be available on the class object that prepends the AES
module.
Public Instance Methods
Decrypts the given data
using the key
.
It is assumed that the initialization vector is included in the first BLOCK_SIZE bytes of the data. After the decryption the PKCS#5 padding is removed.
See: PDF1.7 s7.6.2.
# File lib/hexapdf/encryption/aes.rb, line 115 def decrypt(key, data) if data.length % BLOCK_SIZE != 0 || data.length < 2 * BLOCK_SIZE raise HexaPDF::EncryptionError, "Invalid data for decryption, need 32 + 16*n bytes" end unpad(new(key, data.slice!(0, BLOCK_SIZE), :decrypt).process(data)) end
Returns a Fiber object that decrypts the data from the given source fiber with the key
.
Padding and the initialization vector are handled like in decrypt
.
# File lib/hexapdf/encryption/aes.rb, line 126 def decryption_fiber(key, source) Fiber.new do data = ''.b while data.length < BLOCK_SIZE && source.alive? && (new_data = source.resume) data << new_data end algorithm = new(key, data.slice!(0, BLOCK_SIZE), :decrypt) while source.alive? && (new_data = source.resume) data << new_data next if data.length < 2 * BLOCK_SIZE new_data = data.slice!(0, data.length - BLOCK_SIZE - data.length % BLOCK_SIZE) Fiber.yield(algorithm.process(new_data)) end if data.length < BLOCK_SIZE || data.length % BLOCK_SIZE != 0 raise HexaPDF::EncryptionError, "Invalid data for decryption, need 32 + 16*n bytes" end unpad(algorithm.process(data)) end end
Encrypts the given data
using the key
and a randomly generated initialization vector.
The data is padded using the PKCS#5 padding scheme and the initialization vector is prepended to the encrypted data,
See: PDF1.7 s7.6.2.
# File lib/hexapdf/encryption/aes.rb, line 82 def encrypt(key, data) iv = random_bytes(BLOCK_SIZE) iv << new(key, iv, :encrypt).process(pad(data)) end
Returns a Fiber object that encrypts the data from the given source fiber with the key
.
Padding and the initialization vector are handled like in encrypt
.
# File lib/hexapdf/encryption/aes.rb, line 91 def encryption_fiber(key, source) Fiber.new do data = random_bytes(BLOCK_SIZE) algorithm = new(key, data, :encrypt) Fiber.yield(data) data = ''.b while source.alive? && (new_data = source.resume) data << new_data next if data.length < BLOCK_SIZE new_data = data.slice!(0, data.length - data.length % BLOCK_SIZE) Fiber.yield(algorithm.process(new_data)) end algorithm.process(pad(data)) end end
Returns a string of n random bytes.
The specific AES
algorithm class can override this class method to provide another method for generating random bytes.
# File lib/hexapdf/encryption/aes.rb, line 154 def random_bytes(n) SecureRandom.random_bytes(n) end
Private Instance Methods
Pads the data to a muliple of BLOCK_SIZE using the PKCS#5 padding scheme and returns the result.
See: PDF1.7 s7.6.2
# File lib/hexapdf/encryption/aes.rb, line 164 def pad(data) padding_length = BLOCK_SIZE - data.size % BLOCK_SIZE data + padding_length.chr * padding_length end
Removes the padding from the data according to the PKCS#5 padding scheme and returns the result.
In case the padding is not correct as per the specification, it is assumed that there is no padding and the input is returned as is.
See: PDF1.7 s7.6.2
# File lib/hexapdf/encryption/aes.rb, line 176 def unpad(data) padding_length = data.getbyte(-1) if padding_length > BLOCK_SIZE || padding_length == 0 || data[-padding_length, padding_length].each_byte.any? {|byte| byte != padding_length } data else data[0...-padding_length] end end