From 6c550a6488bd70daa137be7d81a1559809d35cf8 Mon Sep 17 00:00:00 2001 From: Vsevolod Stakhov Date: Sat, 9 Jun 2018 14:50:59 +0100 Subject: [PATCH] [Feature] Add tool to encrypt files --- lualib/rspamadm/keypair.lua | 123 ++++++++++++++++++++++++++++++++++++ src/lua/lua_cryptobox.c | 8 +-- 2 files changed, 127 insertions(+), 4 deletions(-) diff --git a/lualib/rspamadm/keypair.lua b/lualib/rspamadm/keypair.lua index 518c9e65f..8cbcc33de 100644 --- a/lualib/rspamadm/keypair.lua +++ b/lualib/rspamadm/keypair.lua @@ -19,6 +19,7 @@ local rspamd_keypair = require "rspamd_cryptobox_keypair" local rspamd_pubkey = require "rspamd_cryptobox_pubkey" local rspamd_signature = require "rspamd_cryptobox_signature" local rspamd_crypto = require "rspamd_cryptobox" +local rspamd_util = require "rspamd_util" local ucl = require "ucl" local logger = require "rspamd_logger" @@ -85,6 +86,32 @@ verify:option "-s --suffix" :argname "" :default("sig") +local encrypt = parser:command "encrypt crypt enc e" + :description "Encrypts a file using keypair (or a pubkey)" +encrypt:mutex( + encrypt:option "-p --pubkey" + :description "Load pubkey from the specified file" + :argname "", + encrypt:option "-P --pubstring" + :description "Load pubkey from the base32 encoded string" + :argname "", + encrypt:option "-k --keypair" + :description "Get pubkey from the keypair file" + :argname "" +) +encrypt:option "-s --suffix" + :description "Suffix for encrypted file" + :argname "" + :default("enc") +encrypt:argument "file" + :description "File to encrypt" + :argname "" + :args "*" +encrypt:flag "-r --rm" + :description "Remove unencrypted file" +encrypt:flag "-f --force" + :description "Remove destination file if it exists" + -- Default command is generate, so duplicate options parser:flag "-s --sign" :description "Generates a sign keypair instead of the encryption one" @@ -106,6 +133,26 @@ local function fatal(...) os.exit(1) end +local function ask_yes_no(greet, default) + local def_str + if default then + greet = greet .. "[Y/n]: " + def_str = "yes" + else + greet = greet .. "[y/N]: " + def_str = "no" + end + + local reply = rspamd_util.readline(greet) + + if not reply then os.exit(0) end + if #reply == 0 then reply = def_str end + reply = reply:lower() + if reply == 'y' or reply == 'yes' then return true end + + return false +end + local function generate_handler(opts) local mode = 'encryption' if opts.sign then @@ -245,6 +292,80 @@ local function verify_handler(opts) end end +local function encrypt_handler(opts) + if opts.file then + if type(opts.file) == 'string' then + opts.file = {opts.file} + end + else + parser:error('no files to sign') + end + + local pk + local alg = 'curve25519' + + if opts.keypair then + local ucl_parser = ucl.parser() + local res,err = ucl_parser:parse_file(opts.keypair) + + if not res then + fatal(string.format('cannot load %s: %s', opts.keypair, err)) + end + + local kp = rspamd_keypair.load(ucl_parser:get_object()) + + if not kp then + fatal("cannot load keypair: " .. opts.keypair) + end + + pk = kp:pk() + alg = kp:alg() + elseif opts.pubkey then + if opts.nist then alg = 'nist' end + pk = rspamd_pubkey.load(opts.pubkey, 'sign', alg) + elseif opts.pubstr then + if opts.nist then alg = 'nist' end + pk = rspamd_pubkey.create(opts.pubstr, 'sign', alg) + end + + if not pk then + fatal("cannot load keypair: " .. opts.keypair) + end + + for _,fname in ipairs(opts.file) do + local enc = rspamd_crypto.encrypt_file(pk, fname, alg) + + if not enc then + fatal(string.format("cannot encrypt %s\n", fname)) + end + + local out + if opts.suffix and #opts.suffix > 0 then + out = string.format('%s.%s', fname, opts.suffix) + else + out = string.format('%s', fname) + end + + if rspamd_util.file_exists(out) then + if opts.force or ask_yes_no(string.format('File %s already exists, overwrite?', + out), true) then + os.remove(out) + else + os.exit(1) + end + end + + enc:save_in_file(out) + + if opts.rm then + os.remove(fname) + io.write(string.format('encrypted %s (deleted) -> %s\n', fname, out)) + else + io.write(string.format('encrypted %s -> %s\n', fname, out)) + end + end +end + local function handler(args) local opts = parser:parse(args) @@ -256,6 +377,8 @@ local function handler(args) sign_handler(opts) elseif command == 'verify' then verify_handler(opts) + elseif command == 'encrypt' then + encrypt_handler(opts) else parser:error('command %s is not yet implemented', command) end diff --git a/src/lua/lua_cryptobox.c b/src/lua/lua_cryptobox.c index 62464ad3a..5f4908adf 100644 --- a/src/lua/lua_cryptobox.c +++ b/src/lua/lua_cryptobox.c @@ -1548,10 +1548,10 @@ lua_cryptobox_encrypt_memory (lua_State *L) GError *err = NULL; if (lua_type (L, 1) == LUA_TUSERDATA) { - if (rspamd_lua_check_udata (L, 1, "rspamd{cryptobox_keypair}")) { + if (rspamd_lua_check_udata_maybe (L, 1, "rspamd{cryptobox_keypair}")) { kp = lua_check_cryptobox_keypair (L, 1); } - else if (rspamd_lua_check_udata (L, 1, "rspamd{cryptobox_pubkey}")) { + else if (rspamd_lua_check_udata_maybe (L, 1, "rspamd{cryptobox_pubkey}")) { pk = lua_check_cryptobox_pubkey (L, 1); } } @@ -1630,10 +1630,10 @@ lua_cryptobox_encrypt_file (lua_State *L) GError *err = NULL; if (lua_type (L, 1) == LUA_TUSERDATA) { - if (rspamd_lua_check_udata (L, 1, "rspamd{cryptobox_keypair}")) { + if (rspamd_lua_check_udata_maybe (L, 1, "rspamd{cryptobox_keypair}")) { kp = lua_check_cryptobox_keypair (L, 1); } - else if (rspamd_lua_check_udata (L, 1, "rspamd{cryptobox_pubkey}")) { + else if (rspamd_lua_check_udata_maybe (L, 1, "rspamd{cryptobox_pubkey}")) { pk = lua_check_cryptobox_pubkey (L, 1); } } -- 2.39.5