92 lines
2.5 KiB
Ruby
Executable File
92 lines
2.5 KiB
Ruby
Executable File
#!/usr/bin/env ruby
|
|
# frozen_string_literal: true
|
|
|
|
require 'openssl'
|
|
require 'base64'
|
|
require 'json'
|
|
|
|
class SecretBox
|
|
ALGORITHM = 'aes-256-gcm'.freeze
|
|
|
|
def initialize(master_key_content)
|
|
# Generar una clave de 32 bytes usando SHA256 sobre el contenido del master_key
|
|
@key = Digest::SHA256.digest(master_key_content.strip)
|
|
end
|
|
|
|
def encrypt(plaintext)
|
|
cipher = OpenSSL::Cipher.new(ALGORITHM)
|
|
cipher.encrypt
|
|
cipher.key = @key
|
|
iv = cipher.random_iv
|
|
|
|
ciphertext = cipher.update(plaintext.to_s) + cipher.final
|
|
auth_tag = cipher.auth_tag
|
|
|
|
# Base64 encodear las 3 partes para un JSON
|
|
payload = {
|
|
iv: Base64.strict_encode64(iv),
|
|
tag: Base64.strict_encode64(auth_tag),
|
|
data: Base64.strict_encode64(ciphertext)
|
|
}
|
|
|
|
Base64.strict_encode64(payload.to_json)
|
|
end
|
|
|
|
def decrypt(encrypted_payload)
|
|
parsed_payload = JSON.parse(Base64.strict_decode64(encrypted_payload), symbolize_names: true)
|
|
|
|
cipher = OpenSSL::Cipher.new(ALGORITHM)
|
|
cipher.decrypt
|
|
cipher.key = @key
|
|
cipher.iv = Base64.strict_decode64(parsed_payload[:iv])
|
|
cipher.auth_tag = Base64.strict_decode64(parsed_payload[:tag])
|
|
|
|
cipher.update(Base64.strict_decode64(parsed_payload[:data])) + cipher.final
|
|
rescue => e
|
|
raise "Error al desencriptar. Clave incorrecta o payload dañado. Detalles: #{e.message}"
|
|
end
|
|
end
|
|
|
|
if __FILE__ == $0
|
|
action = ARGV[0]
|
|
|
|
unless ['encrypt', 'decrypt'].include?(action)
|
|
puts "Uso:"
|
|
puts " ruby #{$0} encrypt <texto_plano>"
|
|
puts " ruby #{$0} decrypt <texto_encriptado>"
|
|
exit 1
|
|
end
|
|
|
|
text = ARGV[1]
|
|
if text.nil? || text.empty?
|
|
puts "Por favor, proporciona el texto a #{action}."
|
|
puts "Ejemplo:"
|
|
puts " ruby #{$0} encrypt \"MiSuperPassword\""
|
|
exit 1
|
|
end
|
|
|
|
# Buscar el archivo .master.key en el root del proyecto
|
|
key_path = File.join(File.expand_path('../..', __dir__), '.master.key')
|
|
|
|
unless File.exist?(key_path)
|
|
require 'securerandom'
|
|
File.write(key_path, SecureRandom.hex(32))
|
|
puts "⚠️ ATENCIÓN: Se ha creado una nueva clave maestra en '#{key_path}'"
|
|
puts " Asegúrate de NO subir este archivo a ningún repositorio (ya está cubierto por **/*.key en .gitignore)."
|
|
puts " Cualquiera que tenga este archivo podrá desencriptar los textos.\n\n"
|
|
end
|
|
|
|
box = SecretBox.new(File.read(key_path))
|
|
|
|
begin
|
|
if action == 'encrypt'
|
|
puts box.encrypt(text)
|
|
else
|
|
puts box.decrypt(text)
|
|
end
|
|
rescue => e
|
|
puts "Error: #{e.message}"
|
|
exit 1
|
|
end
|
|
end
|