class SecureJwt::JwtTokenImpl
Constants
- DEFAULT_KEY_ALGORITHM
Attributes
data_algorithm[R]
first_error[R]
jwt_algorithm[R]
master_key[R]
signing_key[R]
Public Class Methods
new(signing_key, options = {})
click to toggle source
# File lib/secure_jwt.rb, line 31 def initialize(signing_key, options = {}) @jwt_algorithm = options[:signing_algorithm] || DEFAULT_ALGORITHMS[:jwt] @jwt_algorithm = nil unless signing_key @signing_key = signing_key @data_algorithm = options[:data_algorithm] || DEFAULT_ALGORITHMS[:data] @master_key = options[:master_key] || SecureJwt.config.master_key || "none" end
Public Instance Methods
decrypt(jwt_token, options = {}, &data_key_decryptor)
click to toggle source
# File lib/secure_jwt.rb, line 63 def decrypt(jwt_token, options = {}, &data_key_decryptor) clear! unformatted_payload, header = decode_jwt jwt_token decrypted_data_key = decrypt_data_key header[:data_key], &data_key_decryptor rescue SecureRandom.random_bytes(12) ret = decrypt_payload unformatted_payload, { data_key: decrypted_data_key, iv: header[:iv], auth_tag: header[:tag], auth_data: options[:auth_data] || "" } first_error ? raise(first_error) : ret end
encrypt(payload, options = {}, &data_key_encryptor)
click to toggle source
# File lib/secure_jwt.rb, line 42 def encrypt(payload, options = {}, &data_key_encryptor) clear! data_key = generate_data_key &data_key_encryptor iv = SecureRandom.random_bytes 12 encrypted_payload, auth_tag = encrypt_payload payload, { key: data_key[:plain], iv: iv, auth_data: options[:auth_data] || "" } ret = encode_jwt encrypted_payload, { data_key: data_key[:encrypted], iv: iv, auth_tag: auth_tag, expires: options[:expires]&.to_i } first_error ? raise(first_error) : ret end
Private Instance Methods
clear!()
click to toggle source
# File lib/secure_jwt.rb, line 88 def clear! @first_error = nil end
decode_jwt(jwt_token)
click to toggle source
# File lib/secure_jwt.rb, line 109 def decode_jwt(jwt_token) begin payload, header = JWT.decode jwt_token, signing_key, !!jwt_algorithm, algorithm: jwt_algorithm, verify_expiration: true %w(data_key iv tag).each do |key| header[key] = Base64.urlsafe_decode64 header[key] rescue "" end return Base64.urlsafe_decode64(payload["data"]), header.transform_keys(&:to_sym) rescue JWT::VerificationError, JWT::IncorrectAlgorithm => e self.first_error = e return {"data": nil}, { } end end
decrypt_data_key(encrypted_key, &block)
click to toggle source
# File lib/secure_jwt.rb, line 170 def decrypt_data_key(encrypted_key, &block) data_key = block ? block.call(encrypted_key, master_key) : default_data_key_decryptor(encrypted_key) rescue nil return data_key unless data_key.nil? self.first_error = OpenSSL::Cipher::CipherError.new("bad decrypt") nil end
decrypt_payload(unformatted_payload, options = {})
click to toggle source
# File lib/secure_jwt.rb, line 142 def decrypt_payload(unformatted_payload, options = {}) begin cipher = OpenSSL::Cipher.new data_algorithm cipher.decrypt cipher.key = options[:data_key] || cipher.random_key cipher.iv = options[:iv] if cipher.authenticated? cipher.auth_tag = options[:auth_tag] cipher.auth_data = options[:auth_data] end return cipher.update(unformatted_payload) + cipher.final rescue Exception => e self.first_error = e nil end end
default_data_key_decryptor(encrypted_key)
click to toggle source
# File lib/secure_jwt.rb, line 188 def default_data_key_decryptor(encrypted_key) cipher = OpenSSL::Cipher.new DEFAULT_KEY_ALGORITHM cipher.decrypt cipher.key = Digest::SHA2.digest "key:#{master_key || "none"}" cipher.iv = Digest::MD5.digest "iv:#{master_key || "none"}" cipher.update(encrypted_key) + cipher.final end
default_data_key_encryptor(plain_key)
click to toggle source
# File lib/secure_jwt.rb, line 179 def default_data_key_encryptor(plain_key) cipher = OpenSSL::Cipher.new DEFAULT_KEY_ALGORITHM cipher.encrypt cipher.key = Digest::SHA2.digest "key:#{master_key}" cipher.iv = Digest::MD5.digest "iv:#{master_key}" cipher.update(plain_key) + cipher.final end
encode_jwt(encrypted_payload, options = {})
click to toggle source
# File lib/secure_jwt.rb, line 92 def encode_jwt(encrypted_payload, options = {}) headers = { data_key: Base64.urlsafe_encode64(options[:data_key]), key: master_key, iv: Base64.urlsafe_encode64(options[:iv]), } headers[:tag] = Base64.urlsafe_encode64(options[:auth_tag]) if options[:auth_tag] formatted_payload = { "data" => Base64.urlsafe_encode64(encrypted_payload), "exp" => options[:expires] }.compact JWT.encode formatted_payload, signing_key, jwt_algorithm, headers end
encrypt_payload(payload, options = {})
click to toggle source
# File lib/secure_jwt.rb, line 124 def encrypt_payload(payload, options = {}) cipher = OpenSSL::Cipher.new data_algorithm cipher.encrypt begin cipher.key = options[:key] cipher.iv = options[:iv] cipher.auth_data = options[:auth_data] if cipher.authenticated? encrypted_payload = cipher.update(payload) + cipher.final return encrypted_payload, cipher.authenticated? ? cipher.auth_tag : nil rescue Exception => e self.first_error = e return "", cipher.authenticated? ? "" : nil end end
first_error=(error)
click to toggle source
# File lib/secure_jwt.rb, line 197 def first_error=(error) return if @first_error @first_error = error end
generate_data_key(&block)
click to toggle source
# File lib/secure_jwt.rb, line 162 def generate_data_key(&block) plain_key = SecureRandom.random_bytes 32 encrypted_key = block ? block.call(plain_key, master_key) : default_data_key_encryptor(plain_key) { plain: plain_key, encrypted: encrypted_key, key: master_key } end