From fb0a4d1b3a01f657d21866449b986ccc6f5753c4 Mon Sep 17 00:00:00 2001 From: Philipp Gesang Date: Sat, 25 Feb 2012 01:23:03 +0100 Subject: interactive key input; [doc] new example --- doc/context/third/enigma/enigma_manual.tex | 44 +++++++ tex/context/third/enigma/enigma.lua | 196 +++++++++++++++++++---------- tex/plain/enigma/enigma.tex | 2 + 3 files changed, 179 insertions(+), 63 deletions(-) diff --git a/doc/context/third/enigma/enigma_manual.tex b/doc/context/third/enigma/enigma_manual.tex index efb4fe2..d136dc1 100644 --- a/doc/context/third/enigma/enigma_manual.tex +++ b/doc/context/third/enigma/enigma_manual.tex @@ -81,6 +81,50 @@ Encryption equals decryption. \stoptext \endinput \stopcontexttyping +\useURL[kgbuch] [http://de.wikipedia.org/wiki/Kenngruppenbuch] + [] [code book] +Now it’s certainly not wise to carry around the key to encrypted +documents as plain text within those documents. The keys will have to be +distributed via an independent channel, e.\,g. a \from[kgbuch]. +Keys in general don’t have to be supplied inside the document. If there +is none specified, the module will interrupt the \TEX\ run and +\emph{ask} for user input. Suppose Alice wanted to send an encrypted +file to Bob and already generated the cipher text as follows: + +\starttyping +mtxrun --script mtx-t-enigma \ + --setup="day_key =B I IV V 22 07 10 AZ DG IE YJ QM CW, \ + rotor_setting = bar, \ + verbose=0" \ + --text="I have nothing to hide. From the NSA, that is." +\stoptyping + +Alice would then include the result of this line in her \LATEX\ document +as follows: + +\startlatextyping +\documentclass{scrartcl} +\usepackage{enigma} +\defineenigma{decryption} +%% Encryption key not given in the setup. +\setupenigma{decryption}{ + rotor_setting = bar, + verbose = 3, +} +\begin{document} + +\startdecryption +usbatbwcaajhzgeyzkqskupzbmdhbdepccgeh +\stopdecryption + +\end{document} +\stoplatextyping + +She subsequently mails this file to Bob and conveys the key through a +secure channel. They only thing that will be left for Bob to do now, is +to enter the key at the prompt when compiling the document with +\LUALATEX. + \stopdocsection \stopdocchapter diff --git a/tex/context/third/enigma/enigma.lua b/tex/context/third/enigma/enigma.lua index 79aadc6..371ddd9 100644 --- a/tex/context/third/enigma/enigma.lua +++ b/tex/context/third/enigma/enigma.lua @@ -67,6 +67,7 @@ libraries. \stopparagraph --ichd]]-- +local ioread = io.read local iowrite = io.write local mathfloor = math.floor local mathrandom = math.random @@ -272,6 +273,8 @@ local pprint_new_machine local pprint_rotor local pprint_rotor_scheme local pprint_step +local polite_key_request +local key_invalid do local eol = "\n" @@ -463,9 +466,47 @@ and only then pushes the output. end return 0 end +--[[ichd-- +\startparagraph +The \luafunction{polite_key_request} will be called in case the +\identifier{day_key} field of the machine setup is empty at the time of +initialization. +\stopparagraph +--ichd]]-- + local s_request = "\n\n " + .. underline"This is an encrypted document." .. [[ + + + Please enter the document key for enigma machine + “%s”. + + Key Format: + +Ref R1 R2 R3 I1 I2 I3 [P1 ..] Ref: reflector A/B/C + Rn: rotor, I through V + In: ring position, 01 through 26 + Pn: optional plugboard wiring, upto 32 + +>]] + polite_key_request = function (name) + return stringformat(s_request, colorize(name, 33)) + end + + local s_invalid_key = colorize"Warning!" + .. " The specified key is invalid." + key_invalid = function () + return s_invalid_key + end end +--[[ichd-- +\startparagraph +The functions \luafunction{new} and \luafunction{ask_for_day_key} are +used outside their scope, so we declare them beforehand. +\stopparagraph +--ichd]]-- local new +local ask_for_day_key do --[[ichd-- \stopdocsection @@ -756,7 +797,6 @@ extraction of successive characters from the sequence. result[#result+1] = tmp end end - print(str) machine:processed_chars() return tableconcat(result) end @@ -812,25 +852,25 @@ extraction of successive characters from the sequence. local p_init = P{ "init", - init = Ct(V"do_init"), + init = V"whitespace"^-1 * Ct(V"do_init"), do_init = V"reflector" * V"whitespace" - * V"rotors" * V"whitespace" - * V"ring" - * (V"whitespace" * V"plugboard")^-1 - , + * V"rotors" * V"whitespace" + * V"ring" + * (V"whitespace" * V"plugboard")^-1 + , reflector = Cg(C(R("ac","AC")) / stringlower, "reflector"), rotors = Cg(Ct(V"rotor" * V"whitespace" - * V"rotor" * V"whitespace" - * V"rotor"), - "rotors") - , + * V"rotor" * V"whitespace" + * V"rotor"), + "rotors") + , rotor = Cs(V"roman_five" / roman_digits + V"roman_four" / roman_digits + V"roman_three" / roman_digits + V"roman_two" / roman_digits + V"roman_one" / roman_digits) - , + , roman_one = P"I" + P"i", roman_two = P"II" + P"ii", roman_three = P"III" + P"iii", @@ -838,10 +878,10 @@ extraction of successive characters from the sequence. roman_five = P"V" + P"v", ring = Cg(Ct(V"double_digit" * V"whitespace" - * V"double_digit" * V"whitespace" - * V"double_digit"), + * V"double_digit" * V"whitespace" + * V"double_digit"), "ring") - , + , double_digit = C(R"02" * R"09"), plugboard = Cg(V"do_plugboard", "plugboard"), @@ -858,7 +898,7 @@ extraction of successive characters from the sequence. -- * V"letter_combination") do_plugboard = Ct(V"letter_combination" * (V"whitespace" * V"letter_combination")^0) - , + , letter_combination = C(R("az", "AZ") * R("az", "AZ")), whitespace = S" \n\t\v"^1, @@ -1027,14 +1067,27 @@ consists of three elements: local processed_chars = function (machine) emit(1, pprint_machine_step, machine.step, machine.name) end - new = function (setup_string, pattern) - local raw_settings = lpegmatch(p_init, setup_string) + + local handle_day_key handle_day_key = function (dk, name, old) + local result + if not dk or dk == "" then + dk = ask_for_day_key(name, old) + end + result = lpegmatch(p_init, dk) + -- If we don’t like the key we’re going to ask again. And again.... + return result or handle_day_key(nil, name, dk) + end + + new = function (name, setup_string, pattern) + --local raw_settings = lpegmatch(p_init, setup_string) + local raw_settings = handle_day_key(setup_string, name) local rotors, ring = get_rotors(raw_settings.rotors, raw_settings.ring) local plugboard = raw_settings.plugboard and get_plugboard_substitution(raw_settings.plugboard) or get_plugboard_substitution{ } local machine = { + name = name, step = 0, -- n characters encoded init = { rotors = raw_settings.rotors, @@ -1068,6 +1121,7 @@ consists of three elements: emit(1, pprint_new_machine, machine) return machine end + end --[[ichd-- \stopdocsection @@ -1078,7 +1132,9 @@ end %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \startdocsection[title=Setup Argument Handling] %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - +--ichd]]-- +do +--[[ichd-- \startparagraph As the module is intended to work both with the Plain and \LATEX\ formats as well as \CONTEXT, we can’t rely on format dependent setups. @@ -1087,47 +1143,47 @@ as all the functionality resides in Lua. \stopparagraph --ichd]]-- -local p_args = P{ - "args", - args = Cf(Ct"" * (V"kv_pair" + V"emptyline")^0, rawset), - kv_pair = Cg(V"key" - * V"separator" - * (V"value" * V"final" - + V"empty")) - * V"rest_of_line"^-1 - , - key = V"whitespace"^0 * C(V"key_char"^1), - key_char = (1 - V"whitespace" - V"eol" - V"equals")^1, - separator = V"whitespace"^0 * V"equals" * V"whitespace"^0, - empty = V"whitespace"^0 * V"comma" * V"rest_of_line"^-1 - * Cc(false) - , - value = C((V"balanced" + (1 - V"final"))^1), - final = V"whitespace"^0 * V"comma" + V"rest_of_string", - rest_of_string = V"whitespace"^0 * V"eol_comment"^-1 * V"eol"^0 * V"eof", - rest_of_line = V"whitespace"^0 * V"eol_comment"^-1 * V"eol", - eol_comment = V"comment_string" * (1 - (V"eol" + V"eof"))^0, - comment_string = V"lua_comment" + V"TeX_comment", - TeX_comment = V"percent", - lua_comment = V"double_dash", - emptyline = V"rest_of_line", - - balanced = V"balanced_brk" + V"balanced_brc", - balanced_brk = V"lbrk" * (V"balanced" + (1 - V"rbrk"))^0 * V"rbrk", - balanced_brc = V"lbrc" * (V"balanced" + (1 - V"rbrc"))^0 * V"rbrc", - - -- Terminals - eol = P"\n\r" + P"\r\n" + P"\n" + P"\r", -- users do strange things - eof = -P(1), - whitespace = S" \t\v", - equals = P"=", - dot = P".", - comma = P",", - dash = P"-", double_dash = V"dash" * V"dash", - percent = P"%", - lbrk = P"[", rbrk = P"]", - lbrc = P"{", rbrc = P"}", -} + local p_args = P{ + "args", + args = Cf(Ct"" * (V"kv_pair" + V"emptyline")^0, rawset), + kv_pair = Cg(V"key" + * V"separator" + * (V"value" * V"final" + + V"empty")) + * V"rest_of_line"^-1 + , + key = V"whitespace"^0 * C(V"key_char"^1), + key_char = (1 - V"whitespace" - V"eol" - V"equals")^1, + separator = V"whitespace"^0 * V"equals" * V"whitespace"^0, + empty = V"whitespace"^0 * V"comma" * V"rest_of_line"^-1 + * Cc(false) + , + value = C((V"balanced" + (1 - V"final"))^1), + final = V"whitespace"^0 * V"comma" + V"rest_of_string", + rest_of_string = V"whitespace"^0 * V"eol_comment"^-1 * V"eol"^0 * V"eof", + rest_of_line = V"whitespace"^0 * V"eol_comment"^-1 * V"eol", + eol_comment = V"comment_string" * (1 - (V"eol" + V"eof"))^0, + comment_string = V"lua_comment" + V"TeX_comment", + TeX_comment = V"percent", + lua_comment = V"double_dash", + emptyline = V"rest_of_line", + + balanced = V"balanced_brk" + V"balanced_brc", + balanced_brk = V"lbrk" * (V"balanced" + (1 - V"rbrk"))^0 * V"rbrk", + balanced_brc = V"lbrc" * (V"balanced" + (1 - V"rbrc"))^0 * V"rbrc", + + -- Terminals + eol = P"\n\r" + P"\r\n" + P"\n" + P"\r", -- users do strange things + eof = -P(1), + whitespace = S" \t\v", + equals = P"=", + dot = P".", + comma = P",", + dash = P"-", double_dash = V"dash" * V"dash", + percent = P"%", + lbrk = P"[", rbrk = P"]", + lbrc = P"{", rbrc = P"}", + } --[[ichd-- @@ -1138,7 +1194,6 @@ a sanitizer routine and, if so, apply it to its value. \stopparagraph --ichd]]-- -do local boolean_synonyms = { ["1"] = true, doit = true, @@ -1155,7 +1210,7 @@ do local ans = alpha + digit + space local p_ans = Cs((ans + (1 - ans / ""))^1) local alphanum_or_space = function (str) - if type(str) ~= "string" then return "" end + if type(str) ~= "string" then return nil end return lpegmatch(p_ans, str) end local ensure_int = function (n) @@ -1188,6 +1243,21 @@ do end return args end +--[[ichd-- +\startparagraph +If the machine setting lacks key settings then we’ll go ahead and ask +the user directly, hence the function \luafunction{ask_for_day_key}. +\stopparagraph +--ichd]]-- + ask_for_day_key = function (name, old) + if old then + emit(0, key_invalid) + end + emit(0, polite_key_request, name) + local result = ioread() + iowrite("\n") + return alphanum_or_space(result) or ask_for_day_key(name) + end end --[[ichd-- @@ -1279,10 +1349,10 @@ end enigma.save_raw_args = save_raw_args enigma.retrieve_raw_args = retrieve_raw_args + local new_machine = function (args, name) verbose_level = args.verbose - local machine = new(args.day_key, args.rotor_setting) - machine.name = name + local machine = new(name, args.day_key, args.rotor_setting) return machine end diff --git a/tex/plain/enigma/enigma.tex b/tex/plain/enigma/enigma.tex index 5b15a8d..7c0981e 100644 --- a/tex/plain/enigma/enigma.tex +++ b/tex/plain/enigma/enigma.tex @@ -69,6 +69,7 @@ \def\do_define_enigma#1{% \@EA\gdef\csname start\enigmaid\endcsname{% + \endgraf \bgroup% \directlua{% if packagedata.enigma and packagedata.enigma.machines["#1"] then @@ -82,6 +83,7 @@ }% }% \@EA\gdef\csname stop\enigmaid\endcsname{% + \endgraf \directlua{ luatexbase.remove_from_callback("pre_linebreak_filter", "#1") packagedata.enigma.machines["#1"]:processed_chars() -- cgit v1.2.3