Method: Sequel::Plugins::ColumnEncryption::Cryptor#decrypt

Defined in:
lib/sequel/plugins/column_encryption.rb

#decrypt(data) ⇒ Object

Decrypt using any supported format and any available key.



375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
# File 'lib/sequel/plugins/column_encryption.rb', line 375

def decrypt(data)
  begin
    data = urlsafe_decode64(data)
  rescue ArgumentError
    raise Error, "Unable to decode encrypted column: invalid base64"
  end

  unless data.getbyte(1) == 0 && data.getbyte(3) == 0
    raise Error, "Unable to decode encrypted column: invalid format"
  end

  flags = data.getbyte(0)

  key, auth_data = @key_map[data.getbyte(2)]
  unless key
    raise Error, "Unable to decode encrypted column: invalid key id"
  end

  case flags
  when NOT_SEARCHABLE
    if data.bytesize < 65
      raise Error, "Decoded encrypted column smaller than minimum size"
    end

    data.slice!(0, 4)
  when SEARCHABLE, LOWERCASE_SEARCHABLE
    if data.bytesize < 97
      raise Error, "Decoded encrypted column smaller than minimum size"
    end

    data.slice!(0, 36)
  else
    raise Error, "Unable to decode encrypted column: invalid flags"
  end

  key_part = data.slice!(0, 32)
  cipher_iv = data.slice!(0, 12)
  auth_tag = data.slice!(0, 16)

  cipher = OpenSSL::Cipher.new("aes-256-gcm")
  cipher.decrypt
  cipher.iv = cipher_iv
  cipher.key = OpenSSL::HMAC.digest(OpenSSL::Digest::SHA256.new, key, key_part)
  cipher.auth_data = auth_data
  cipher.auth_tag = auth_tag
  begin
    decrypted_data = cipher.update(data) << cipher.final
  rescue OpenSSL::Cipher::CipherError => e
    raise Error, "Unable to decrypt encrypted column: #{e.class} (probably due to encryption key or auth data mismatch or corrupt data)"
  end

  # Remove padding
  decrypted_data.slice!(0, decrypted_data.getbyte(0) + 1)

  decrypted_data
end