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.



116
117
118
119
120
121
# File 'lib/hexapdf/encryption/aes.rb', line 116

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.



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

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.



83
84
85
86
# File 'lib/hexapdf/encryption/aes.rb', line 83

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.



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

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.



155
156
157
# File 'lib/hexapdf/encryption/aes.rb', line 155

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