Module: HexaPDF::Encryption::AES::ClassMethods

Defined in:
lib/hexapdf/encryption/aes.rb

Overview

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.

Instance Method Summary collapse

Instance Method Details

#decrypt(key, data) ⇒ Object

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.



113
114
115
116
117
118
# File 'lib/hexapdf/encryption/aes.rb', line 113

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

#decryption_fiber(key, source) ⇒ Object

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.



124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
# File 'lib/hexapdf/encryption/aes.rb', line 124

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

#encrypt(key, data) ⇒ Object

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.



80
81
82
83
# File 'lib/hexapdf/encryption/aes.rb', line 80

def encrypt(key, data)
  iv = random_bytes(BLOCK_SIZE)
  iv << new(key, iv, :encrypt).process(pad(data))
end

#encryption_fiber(key, source) ⇒ Object

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.



89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
# File 'lib/hexapdf/encryption/aes.rb', line 89

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

#random_bytes(n) ⇒ Object

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.



152
153
154
# File 'lib/hexapdf/encryption/aes.rb', line 152

def random_bytes(n)
  SecureRandom.random_bytes(n)
end