class Rack::Session::Encryptor
def initialize(secret, opts = {})
* HMAC - 32 bytes HMAC-SHA-256 of all preceding data, plus the purpose
* IV - 16 bytes random initialization vector
* random_data - 32 bytes used for generating the per-message secret
* version - 1 byte and is currently always 0x01
Where:
urlsafe_encode64(version + random_data + IV + encrypted data + HMAC)
Cryptography and Output Format:
if keys are reused.
security enhancement to prevent message reuse from different contexts
Limit messages to a specific purpose. This can be viewed as a
* :purpose
padding.
(default: 32). This can be between 2-4096 bytes, or +nil+ to disable
Pad encrypted message data, to a multiple of this many bytes
* :pad_size
viewed as a security enhancement.
Use JSON for message serialization instead of Marshal. This can be
* :serialize_json
Options may include:
for an HMAC key.
will be used for the encryption cipher key. The remainder will be used
The secret String must be at least 64 bytes in size. The first 32 bytes
def initialize(secret, opts = {}) raise ArgumentError, "secret must be a String" unless String === secret raise ArgumentError, "invalid secret: #{secret.bytesize}, must be >=64" unless secret.bytesize >= 64 case opts[:pad_size] when nil # padding is disabled when Integer raise ArgumentError, "invalid pad_size: #{opts[:pad_size]}" unless (2..4096).include? opts[:pad_size] else raise ArgumentError, "invalid pad_size: #{opts[:pad_size]}; must be Integer or nil" end @options = { serialize_json: false, pad_size: 32, purpose: nil }.update(opts) @hmac_secret = secret.dup.force_encoding('BINARY') @cipher_secret = @hmac_secret.slice!(0, 32) @hmac_secret.freeze @cipher_secret.freeze end