# frozen_string_literal: true require 'openssl' require 'base64' class CryptSerializer attr_reader :cipher class << self # pulling from DB - return plain value def load value new.decrypt value end # saving to DB - return encrypted value def dump value new.encrypt value end end def initialize @cipher = OpenSSL::Cipher::AES.new(256, :CBC) end def encrypt(value) return value if value.nil? unless value.is_a?(String) raise "Attribute was supposed to be a `String`, but was instead a `#{value.class}`" end build_cipher value end def decrypt(value) return value if value.nil? parts = Marshal.load Base64.urlsafe_decode64(value) decode_cipher parts end private def build_cipher value cipher.encrypt parts = [cipher.random_key, cipher.random_iv, cipher.update(value) + cipher.final] Base64.urlsafe_encode64 Marshal.dump(parts) end def decode_cipher parts cipher.decrypt cipher.key = parts[0] cipher.iv = parts[1] cipher.update(parts[2]) + cipher.final end end