I put together a macro that takes two arguments. The first argument is a string of letters which defines a cipher. The second argument is a message to be encrypted using this cipher.
\documentclass{article}
\usepackage{geometry}
\setlength{\parindent}{0pt}
\setlength{\parskip}{2ex}
\makeatletter
%%---------------------------------------------------------------------
%% #1=replacement cipher
%% #2=text to be enciphered
%% starred version will group letters into collections
%% of five letters (stripping out previous space and punctuation)
\newif\if@regroup@letters@by@fives@
\def\makecryptogram{%%
\@ifstar{\@regroup@letters@by@fives@true\@makecryptogram}
{\@regroup@letters@by@fives@false\@makecryptogram}}
\def\@makecryptogram#1#2{%%
\bgroup
\@build@cipher{#1}%%
\if@regroup@letters@by@fives@
\expandafter\@build@groups@of@five\expandafter{#2}%%
\else
\edef\ae@encrypted@message{#2}%%
\fi
\ttfamily
\raggedright
\uppercase\expandafter{\ae@encrypted@message}%%
\par
\egroup}
%%---------------------------------------------------------------------
%% counter to assist in tracking and encoding letters of the
%% alphabet.
\newcounter{@letter@code}
%% #1=replacement cipher
\def\@build@cipher#1{%%
\setcounter{@letter@code}{64}%%
\@@build@cipher#1\relax}
%% #1=current letter representing encryption of nth letter
%% #2=placeholder to test end of content
%%
%% No error should be raised if the cipher has fewer than 26 letters.
%% In that case, only the initial portion of the alphabet will be
%% encrypted. If there are more than 26 letters for the cipher, do
%% nothing with the extras.
%%
%% Ignore the difference between upper and lower case letters of input
%% characters. Regardless of input, output is all upper case.
%%
\def\@@build@cipher#1#2{%%
\stepcounter{@letter@code}%%
\ifnum\value{@letter@code}<91\relax
\ifnum`#1>\number\numexpr`a-1\relax
\uccode\value{@letter@code}=\number\numexpr`#1-32\relax
\uccode\number\numexpr\value{@letter@code}+32\relax=\number\numexpr`#1-32\relax
\else
\uccode\value{@letter@code}=\number\numexpr`#1\relax
\uccode\number\numexpr\value{@letter@code}+32\relax=\number\numexpr`#1\relax
\fi
\ifx\relax#2\relax
\let\ae@continue@building@cipher\relax
\else
\let\ae@continue@building@cipher\@@build@cipher
\fi
\else
\let\ae@continue@building@cipher\relax
\fi
\ae@continue@building@cipher#2%%
}
%%---------------------------------------------------------------
\newcounter{@ae@letter@counter}
\newif\if@spaceOrPunctuation@
\def\@build@groups@of@five#1{%%
\def\ae@encrypted@message{}%%
\setcounter{@ae@letter@counter}{0}%%
\@@build@groups@of@five#1\relax}
%% <space>s are ignored merely by the manner in which TeX
%% grabs the next token for the arguments of a macro.
%% When gathering into groups of five letters, all punctuation
%% should be suppressed and dropped.
\def\@@build@groups@of@five#1#2{%%
\@spaceOrPunctuation@false
\if-#1\relax\@spaceOrPunctuation@true\fi
\if,#1\relax\@spaceOrPunctuation@true\fi
\if;#1\relax\@spaceOrPunctuation@true\fi
\if:#1\relax\@spaceOrPunctuation@true\fi
\if.#1\relax\@spaceOrPunctuation@true\fi
\if?#1\relax\@spaceOrPunctuation@true\fi
\if!#1\relax\@spaceOrPunctuation@true\fi
\if@spaceOrPunctuation@
\else
\stepcounter{@ae@letter@counter}%%
\xdef\ae@encrypted@message{\ae@encrypted@message#1}%%
\ifnum\value{@ae@letter@counter}=5\relax
\setcounter{@ae@letter@counter}{0}%%
\xdef\ae@encrypted@message{\ae@encrypted@message\space}%%
\fi
\fi
\ifx\relax#2\relax
\let\ae@continue@building@blocks@of@five\relax
\else
\let\ae@continue@building@blocks@of@five\@@build@groups@of@five
\fi
\ae@continue@building@blocks@of@five#2%%
}
\makeatother
\usepackage{environ}
\makeatletter
\NewEnviron{cryptopgram}[1]
{\@build@cipher{#1}%%
\expandafter\@build@groups@of@five\expandafter{\BODY}%%
\ttfamily
\raggedright
\uppercase\expandafter{\ae@encrypted@message}%%
\par
}
\makeatother
\begin{document}
From Bertrand Russell's \emph{Problems of Philosophy}.
\def\mypassage{%%'
Is there any knowledge in the world which is so certain that no
reasonable man could doubt it? This question, which at first sight
might not seem difficult, is really one of the most difficult that
can be asked. When we have realized the obstacles in the way of a
straightforward and confident answer, we shall be well launched on
the study of philosophy--for philosophy is merely the attempt to
answer such ultimate questions, not carelessly and dogmatically, as
we do in ordinary life and even in the sciences, but critically,
after exploring all that makes such questions puzzling, and after
realizing all the vagueness and confusion that underlie our ordinary
ideas.}
Without changing word boundaries:\par
%% --ABCDEFGHIJKLMNOPQRSTUVWXYZ--
\makecryptogram{BCDNXGHELOPUQASRVFWTYZIJKM}{\mypassage}
Collect letters into groups of five:\par
\makecryptogram*{BCDNXGHELOPUQASRVFWTYZIJKM}{\mypassage}
Pseudo-environment:\par
\begin{cryptopgram}{BCDNXGHELOPUQASRVFWTYZIJKM}
Is there any knowledge in the world which is so certain that no
reasonable man could doubt it? This question, which at first sight
might not seem difficult, is really one of the most difficult that
can be asked. When we have realized the obstacles in the way of a
straightforward and confident answer, we shall be well launched on
the study of philosophy--for philosophy is merely the attempt to
answer such ultimate questions, not carelessly and dogmatically, as
we do in ordinary life and even in the sciences, but critically,
after exploring all that makes such questions puzzling, and after
realizing all the vagueness and confusion that underlie our ordinary
ideas.
\end{cryptopgram}
\end{document}
There are a couple of things I would like to know how to do (if they're even feasible) which I'll raise as separately posted questions.
Here's the context for the first question:
My code works by taking the cipher, remapping the \uccode
s for each the letters of the alphabet, then calling \uppercase
with these new \uccode
values on the message. (The material to be encrypted should just be plain text without any mark up except for possible punctuation.)
I would like to consider a different approach that will not rely on using \uppercase
. I would like to be able to temporarily remap character codes within the confines of an environment. Of course, once the environment is over, the old character codes should be restored. So for example, instead of changing \uccode
s, I would like to remap character code of C
to that of N
, D
to O
, etc. as in the above cryptograms. In other words, when TeX sees the token C
with catcode=11, it behaves as though this were N
with catcode=11, and so on for all the text tokens with catcode=11.
However, I can't find any such mechanism for remapping character codes. In other words, is there a way of encrypting a cipher that can avoid changing the upper case codes?
NewEnviron
which just winds up acting like a macro with arguments masquerading as an environment.C
expanding toX
or whatever, or you could look to luatex...