local rspamd_secretbox = require "rspamd_cryptobox_secretbox"
if not header or header == '' then
- logger.errx(rspamd_config, "Header: %s is empty or nil", header)
+ logger.errx(rspamd_config, "Header is empty or nil. Header: %s", header)
return nil
elseif settings[prefix .. '_encrypt'] then
local key = settings[prefix .. '_key']
if not key or key == '' then
- logger.errx(rspamd_config, "Key: %s is empty or nil", key)
+ logger.errx(rspamd_config, "Key is empty or nil. Key: %s", key)
return header
end
local cryptobox = rspamd_secretbox.create(key)
else
encrypted_header = cryptobox:encrypt(header, nonce)
end
- return encrypted_header, nonce
+ encrypted_header = nonce .. encrypted_header
+ return encrypted_header
end
end
local rspamd_secretbox = require "rspamd_cryptobox_secretbox"
if not encrypted_header or encrypted_header == '' then
- logger.errx(rspamd_config, "Encoded header: %s is empty or nil")
+ logger.errx(rspamd_config, "Encrypted header is empty or nil. Encrypted header: %s", encrypted_header)
return nil
elseif settings[prefix .. '_encrypt'] then
local key = settings[prefix .. '_key']
if not key or key == '' then
- logger.errx(rspamd_config, "Key: %s is empty or nil")
+ logger.errx(rspamd_config, "Key is empty or nil. Key: %s", key)
return encrypted_header
end
local cryptobox = rspamd_secretbox.create(key)
--- /dev/null
+local util = require 'lua_util'
+local rspamd_util = require 'rspamd_util'
+local argparse = require 'argparse'
+
+local parser = argparse()
+ :name "secretbox"
+ :description "Encrypt/decrypt given text with given key and nonce"
+ :help_description_margin(32)
+ :command_target('command')
+ :require_command(true)
+
+parser:mutex(
+ parser:flag '-R --raw'
+ :description('Encrypted text(and nonce if it is there) will be given in raw'),
+ parser:flag '-H --hex'
+ :description('Encrypted text(and nonce if it is there) will be given in hex'),
+ parser:flag '-b --base32'
+ :description('Encrypted text(and nonce if it is there) will be given in base32'),
+ parser:flag '-B --base64'
+ :description('Encrypted text(and nonce if it is there) will be given in base64')
+)
+
+local decrypt = parser:command 'decrypt'
+ :description 'Decrypt text with given key and nonce'
+
+decrypt:option "-t --text"
+ :description("Encrypted text(Base 64)")
+ :argname("<text>")
+decrypt:option "-k --key"
+ :description("Key used to encrypt text")
+ :argname("<key>")
+decrypt:option "-n --nonce"
+ :description("Nonce used to encrypt text(Base 64)")
+ :argname("<nonce>")
+ :default(nil)
+
+local encrypt = parser:command 'encrypt'
+ :description 'Encrypt text with given key'
+
+encrypt:option "-t --text"
+ :description("Text to encrypt")
+ :argname("<text>")
+encrypt:option "-k --key"
+ :description("Key to encrypt text")
+ :argname("<key>")
+encrypt:option "-n --nonce"
+ :description("Nonce to encrypt text(Base 64)")
+ :argname("<nonce>")
+ :default(nil)
+
+local function set_up_encoding(args, type, text)
+ local function fromhex(str)
+ return (str:gsub('..', function (cc)
+ return string.char(tonumber(cc, 16))
+ end))
+ end
+
+ local function tohex(str)
+ return (str:gsub('.', function (c)
+ return string.format('%02X', string.byte(c))
+ end))
+ end
+
+ local output = text
+
+ if type == 'encode' then
+ if args.hex then
+ output = tohex(text)
+ elseif args.base32 then
+ output = rspamd_util.encode_base32(text)
+ elseif args.base64 then
+ output = rspamd_util.encode_base64(text)
+ end
+ elseif type == 'decode' then
+ if args.hex then
+ output = fromhex(text)
+ elseif args.base32 then
+ output = rspamd_util.decode_base32(text)
+ elseif args.base64 then
+ output = rspamd_util.decode_base64(text)
+ end
+ end
+
+ return output
+end
+
+local function decryption_handler(args)
+ local settings = {
+ prefix = 'dec',
+ dec_encrypt = true,
+ dec_key = args.key
+ }
+
+ local decrypted_header = ''
+ if(args.nonce ~= nil) then
+ local decoded_text = set_up_encoding(args, 'decode', tostring(args.text))
+ local decoded_nonce = set_up_encoding(args, 'decode', tostring(args.nonce))
+
+ decrypted_header = util.maybe_decrypt_header(decoded_text, settings, settings.prefix, decoded_nonce)
+ else
+ local text_with_nonce = set_up_encoding(args, 'decode', tostring(args.text))
+ local nonce = string.sub(tostring(text_with_nonce), 1, 24)
+ local text = string.sub(tostring(text_with_nonce), 25)
+
+ decrypted_header = util.maybe_decrypt_header(text, settings, settings.prefix, nonce)
+ end
+
+ if decrypted_header ~= nil then
+ print(decrypted_header)
+ else
+ print('The decryption failed. Please check the correctness of the arguments given.')
+ end
+end
+
+local function encryption_handler(args)
+ local settings = {
+ prefix = 'dec',
+ dec_encrypt = true,
+ dec_key = args.key,
+ }
+
+ if args.nonce ~= nil then
+ settings.dec_nonce = set_up_encoding(args, 'decode', tostring(args.nonce))
+ end
+
+ local encrypted_text = util.maybe_encrypt_header(args.text, settings, settings.prefix)
+
+ if encrypted_text ~= nil then
+ print(set_up_encoding(args, 'encode', tostring(encrypted_text)))
+ else
+ print('The encryption failed. Please check the correctness of the arguments given.')
+ end
+end
+
+local command_handlers = {
+ decrypt = decryption_handler,
+ encrypt = encryption_handler,
+}
+
+local function handler(args)
+ local cmd_opts = parser:parse(args)
+
+ local f = command_handlers[cmd_opts.command]
+ if not f then
+ parser:error(string.format("command isn't implemented: %s",
+ cmd_opts.command))
+ end
+ f(cmd_opts)
+end
+
+
+return {
+ name = 'secret_box',
+ aliases = { 'secretbox', 'secret_box' },
+ handler = handler,
+ description = parser._description
+}
\ No newline at end of file
Library ${RSPAMD_TESTDIR}/lib/rspamd.py
Resource ${RSPAMD_TESTDIR}/lib/rspamd.robot
+*** Variables ***
+${TEXT} text
+${KEY} 12345678901234567890123456789012
+${NONCE} 9pyeEd986hrjcpozCIZ41jEo6dCDbgjg
+${ENCRYPTED_TEXT} 8KGF6VLI7vnweUdR8FuQZuT+ID8=
+${PYTHON_SCRIPT} ${RSPAMD_TESTDIR}/../../utils/encrypt_decrypt_header.py
+
*** Test Cases ***
Config Test
${result} = Rspamadm configtest
Should Match Regexp ${result.stderr} ^$
Should Match Regexp ${result.stdout} hello world\n
Should Be Equal As Integers ${result.rc} 0
+
+SecretBox rspamadm encrypt/decrypt
+ ${result} = Rspamadm secret_box -B encrypt -t ${TEXT} -k ${KEY} -n ${NONCE}
+ Should Match Regexp ${result.stderr} ^$
+ Should Be Equal As Strings ${result.stdout} ${NONCE}${ENCRYPTED_TEXT}
+ ${result1} = Rspamadm secret_box -B decrypt -t ${ENCRYPTED_TEXT} -k ${KEY} -n ${NONCE}
+ Should Match Regexp ${result.stderr} ^$
+ Should Be Equal As Strings ${result1.stdout} ${TEXT}
+
+SecretBox python encrypt/decrypt
+ ${result} = Run Process python3 ${PYTHON_SCRIPT} -B encrypt -t ${TEXT} -k ${KEY} -n ${NONCE}
+ Should Match Regexp ${result.stderr} ^$
+ Should Be Equal As Strings ${result.stdout} ${NONCE}${ENCRYPTED_TEXT}
+ ${result1} = Run Process python3 ${PYTHON_SCRIPT} -B decrypt -t ${NONCE}${ENCRYPTED_TEXT} -k ${KEY}
+ Should Match Regexp ${result.stderr} ^$
+ Should Be Equal As Strings ${result1.stdout} ${TEXT}
+
+SecretBox encrypt python with nonce decrypt rspamadm
+ ${result} = Run Process python3 ${PYTHON_SCRIPT} -B encrypt -t ${TEXT} -k ${KEY} -n ${NONCE}
+ ${result1} = Rspamadm secret_box -B decrypt -t ${result.stdout} -k ${KEY}
+ Should Match Regexp ${result.stderr} ^$
+ Should Be Equal As Strings ${TEXT} ${result1.stdout}
+
+SecretBox encrypt python without nonce decrypt rspamadm
+ ${result} = Run Process python3 ${PYTHON_SCRIPT} -B encrypt -t ${TEXT} -k ${KEY}
+ ${result1} = Rspamadm secret_box -B decrypt -t ${result.stdout} -k ${KEY}
+ Should Match Regexp ${result.stderr} ^$
+ Should Be Equal As Strings ${TEXT} ${result1.stdout}
+
+SecretBox encrypt rspamadm with nonce decrypt python
+ ${result} = Rspamadm secret_box -B encrypt -t ${TEXT} -k ${KEY} -n ${NONCE}
+ ${result1} = Run Process python3 ${PYTHON_SCRIPT} -B decrypt -t ${result.stdout} -k ${KEY}
+ Should Match Regexp ${result.stderr} ^$
+ Should Be Equal As Strings ${TEXT} ${result1.stdout}
+
+SecretBox encrypt rspamadm without nonce decrypt python
+ ${result} = Rspamadm secret_box -B encrypt -t ${TEXT} -k ${KEY}
+ ${result1} = Run Process python3 ${PYTHON_SCRIPT} -B decrypt -t ${result.stdout} -k ${KEY}
+ Should Match Regexp ${result.stderr} ^$
+ Should Be Equal As Strings ${TEXT} ${result1.stdout}
assert_true(false, 'Failed to encrypt header')
end
- local decrypted_header = util.maybe_decrypt_header(encrypted_header, settings, settings.prefix)
+ local text = string.sub(tostring(encrypted_header), 6)
+ local decrypted_header = util.maybe_decrypt_header(text, settings, settings.prefix)
if decrypted_header == encrypted_header or decrypted_header == nil then
assert_true(false, 'Failed to decrypt header')
end
prefix_key = 'key'
}
- local encrypted_header, nonce = util.maybe_encrypt_header(header, settings, settings.prefix)
+ local encrypted_header = util.maybe_encrypt_header(header, settings, settings.prefix)
if encrypted_header == header or encrypted_header == nil then
assert_true(false, 'Failed to encrypt header')
end
- local decrypted_header = util.maybe_decrypt_header(encrypted_header, settings,
- settings.prefix, nonce)
+ local nonce = string.sub(tostring(encrypted_header), 1, 24)
+ local text = string.sub(tostring(encrypted_header), 25)
+ local decrypted_header = util.maybe_decrypt_header(text, settings, settings.prefix, nonce)
+
if decrypted_header == encrypted_header or decrypted_header == nil then
assert_true(false, 'Failed to decrypt header')
end
--- /dev/null
+import argparse
+import base64
+
+import nacl.encoding
+from nacl.secret import SecretBox
+from nacl.hash import blake2b
+
+
+def create_secret_box(key):
+ key = blake2b(key, encoder=nacl.encoding.RawEncoder)
+ box = SecretBox(key)
+ return box
+
+def encrypt_text(header, key, nonce):
+ box = create_secret_box(key)
+ if nonce is not None:
+ encrypted_header = box.encrypt(header, nonce=nonce)
+ else:
+ encrypted_header = box.encrypt(header)
+ return encrypted_header
+
+def decrypt_text(encrypted_header, key):
+ box = create_secret_box(key)
+ decrypted_header = box.decrypt(encrypted_header)
+ return decrypted_header
+
+def set_encoding(args, type_, text):
+ output = text
+ if type_ == 'encode':
+ if args.hex:
+ output = base64.b16encode(text)
+ elif args.base32:
+ output = base64.b32encode(text)
+ elif args.base64:
+ output = base64.b64encode(text)
+ elif type_ == 'decode':
+ if args.hex:
+ output = base64.b16decode(text)
+ elif args.base32:
+ output = base64.b32decode(text)
+ elif args.base64:
+ output = base64.b64decode(text)
+ return output
+
+def set_up_parser_args():
+ new_parser = argparse.ArgumentParser(description="Encrypt or Decrypt a text.")
+ enc_group = new_parser.add_mutually_exclusive_group()
+
+ enc_group.add_argument("-r", "--raw", action="store_true",
+ help="Encrypted text(and nonce if it is there) will be given in raw")
+ enc_group.add_argument("-H", "--hex", action="store_true",
+ help="Encrypted text(and nonce if it is there) will be given in hex")
+ enc_group.add_argument("-b", "--base32", action="store_true",
+ help="Encrypted text(and nonce if it is there) will be given in base32")
+ enc_group.add_argument("-B", "--base64", action="store_true",
+ help="Encrypted text(and nonce if it is there) will be given in base64")
+
+ subparsers = new_parser.add_subparsers(dest="command", help="encrypt or decrypt")
+
+ encrypt_parser = subparsers.add_parser("encrypt", help="Encrypt a text")
+ encrypt_parser.add_argument("-t", "--text", type=str, required=True, help="Text to encrypt")
+ encrypt_parser.add_argument("-k", "--key", type=str, required=True, help="Encryption key")
+ encrypt_parser.add_argument("-n", "--nonce", type=str, required=False, help="Encryption nonce")
+
+ decrypt_parser = subparsers.add_parser("decrypt", help="Decrypt a text")
+ decrypt_parser.add_argument("-t", "--encrypted_text", type=str, required=True, help="Encrypted text")
+ decrypt_parser.add_argument("-k", "--key", type=str, required=True, help="Decryption key")
+
+ args = new_parser.parse_args()
+ return args
+
+def main():
+ args = set_up_parser_args()
+
+ if args.command == "encrypt":
+ text = args.text.encode()
+ key = args.key.encode()
+ if args.nonce is not None:
+ nonce = set_encoding(args, 'decode', args.nonce)
+ else:
+ nonce = None
+
+ encrypted_text = encrypt_text(text, key, nonce)
+ if args.raw:
+ print(set_encoding(args, 'encode', encrypted_text))
+ else:
+ print(set_encoding(args, 'encode', encrypted_text).decode())
+
+ elif args.command == "decrypt":
+ encrypted_text = set_encoding(args, 'decode', args.encrypted_text)
+ key = args.key.encode()
+
+ decrypted_text = decrypt_text(encrypted_text, key)
+ print(decrypted_text.decode())
+
+if __name__ == "__main__":
+ main()
\ No newline at end of file