11

Assume that you have some text in parts of your LaTeX document that you only want people with a password to see. A reason could e.g. be a case with an guiding answer. You want to make the case public but the answer only to teachers.

Anyone adware of a package that could do something like:

\usepackage[password=<my password>]{decrypt}
\begin{document} 
<Public text>
\begin{private}
<Private encrypted text>
\end{private}
\end{document} 

When running e.g. pdfLaTeX the encrypted text will be decrypted and show in the resulting pdf. I guess that some kind of preprocessing is needed to replace the private text with encrypted text. An idea could be to use R and knitr for this (an example online is http://textmechanic.com/Encryption-Generator.html)

5
  • 2
    Why not just omit the answer in the student version, for example? There are already several packages which handle this kind of case. When you take an exam, you don't expect an encrypted version of the answer to be there - that would just be distracting. You just get the question and the examiners' version includes the answer.
    – cfr
    Commented Oct 28, 2015 at 13:39
  • That's a option I use sometimes. However, if you want to distribute the source files public (e.g. using GitHub). It would be easier to send just a password to a teacher. Anyway the question is not if it is relevant or the best solution, but can it be done. Best.
    – Relund
    Commented Oct 28, 2015 at 14:57
  • 1
    From a practical point of view, you can encrypt the PDFs and then distribute the password to teachers. Standard protections enabled by Adobe etc. are sometimes trivial to break, though. (In some cases, really, really trivial in that you can break them by accident.)
    – cfr
    Commented Oct 28, 2015 at 18:06
  • You can always pass stuff over to external tools. With something like bashful you can include the output in the PDF. Obviously OS dependent, though.
    – cfr
    Commented Oct 28, 2015 at 18:09
  • Maybe there is a lesson to be learned from PostScript which provides the eexec operator that takes a stream (from the current source code), decodes, and executes it. Adobe used originally this to hide the design of its Type 1 fonts. I do believe, though, that such functionality would have to be implemented in a (Lua) TeX engine. Commented Oct 28, 2015 at 19:54

2 Answers 2

8

Updated answer

This is Enigma.

Notice that Enigma is symmetric. Thus you can encode and decode at the same place. In the following example, the first input AN ENIGMA MACHINE... comes from the Wikipedia article. And then I copied and pasted the output ISWXACOIOIGKAXHF...to be the second input. Thus we got ANENIGMAMACHINE as the second output, which is what we inputed at the beginning.

\documentclass{article}
\usepackage{pgfmath}

% These counters are registers. One needs to assign the initial values of \rotorphasecounts, which function as the password.

\newcount\crycount
\newcount\plugboardcount
\newcount\rotorcounti
\newcount\rotorcountii
\newcount\rotorcountiii
\newcount\rotorphasecounti
\newcount\rotorphasecountii
\newcount\rotorphasecountiii
\newcount\reflectorcount

% This is the main function. It reads characters until it reaches \end.

\def\private#1{%
    \ifx#1\end
        \expandafter\end
    \else

% First of all, convert capital letters to numbers. We want A becomes 0 and Z becomes 25.

        \crycount`#1
        \pgfmathsetmacro\crystringi{int(Mod(\crycount-65,26))}

% Now the number passes through the Plugboard, which is a part of the Enigma.

        \plugboard\crystringii\crystringi

% Now the number passes through the three Rotors. It could be four if you want to.

        \rotori\crystringiii\crystringii
        \rotorii\crystringiv\crystringiii
        \rotoriii\crystringv\crystringiv

% Now the number reaches the Reflector.

        \reflector\crystringvi\crystringv

% So then the number goes backwards, passing through the Rotors and the Plugboard.

        \inverserotoriii\crystringvii\crystringvi
        \inverserotorii\crystringviii\crystringvii
        \inverserotori\crystringix\crystringviii
        \plugboard\crystringx\crystringix

% Convert the number to the hexadecimal code of the corresponding capital letters. For instance 0 means A, so it should be ^^65.

        \pgfmathsetmacro\crystringxi{hex(\crystringx+65)}
        \xdef\crystring{\crystring\string^\string^\crystringxi\string\allowbreak{}}
        \expandafter\private
    \fi
}

% A Plugboard exchanges pairs of letters. In this case A and B are switched. So are C&D and E&F.

\def\plugboard#1#2{
    \plugboardcount#2\xdef#1{\ifcase\plugboardcount1\or0\or3\or2\or5\or4\or6\or7\or8\or9\or10\or11\or12\or13\or14\or15\or16\or17\or18\or19\or20\or21\or22\or23\or24\or25\fi}
}

% A Rotor permutes 26 letters in a fixed way. The funny part is, the first rotor rotates by 2π/26 every time a number passes by. The second rotates every time the first finishes a cycle. And so forth.

\def\rotori#1#2{
    \advance\rotorphasecounti1
    \pgfmathsetcount\rotorcounti{int(Mod(#2+\rotorphasecounti,26))}
    \xdef\rotortexti{\ifcase\rotorcounti1\or2\or3\or4\or0\or6\or7\or8\or9\or10\or11\or12\or13\or14\or15\or16\or17\or18\or19\or20\or21\or22\or23\or24\or25\or5\fi}
    \pgfmathsetmacro#1{int(Mod(\rotortexti-\rotorphasecounti,26))}
}
\def\rotorii#1#2{
    \ifnum\rotorphasecounti=26\rotorphasecounti0\advance\rotorphasecountii1\fi
    \pgfmathsetcount\rotorcountii{int(Mod(#2+\rotorphasecountii,26))}
    \xdef\rotortextii{\ifcase\rotorcountii1\or2\or3\or4\or0\or5\or6\or10\or11\or12\or7\or8\or9\or13\or14\or15\or16\or17\or18\or19\or20\or21\or22\or23\or24\or25\fi}
    \pgfmathsetmacro#1{int(Mod(\rotortextii-\rotorphasecountii,26))}
}
\def\rotoriii#1#2{
    \ifnum\rotorphasecountii=26\rotorphasecountii0\advance\rotorphasecountiii1\fi
    \pgfmathsetcount\rotorcountiii{int(Mod(#2+\rotorphasecountiii,26))}
    \xdef\rotortextiii{\ifcase\rotorcountiii1\or2\or3\or4\or0\or5\or6\or7\or8\or9\or10\or11\or12\or13\or14\or15\or16\or20\or21\or22\or23\or24\or25\or17\or18\or19\fi}
    \pgfmathsetmacro#1{int(Mod(\rotortextiii-\rotorphasecountiii,26))}
}

% The Reflector reflects the number. In the history it always reflected a number to a different one, and that made Enigma self-reciprocal, but unsafe.

\def\reflector#1#2{
    \reflectorcount#2\xdef#1{\ifcase\reflectorcount3\or10\or18\or0\or23\or11\or22\or8\or7\or19\or1\or5\or25\or20\or16\or24\or14\or21\or2\or9\or13\or17\or6\or4\or15\or12\fi}
}

% Physically there are only three rotors. But we still need to implement the macro for the opposite direction.

\def\inverserotoriii#1#2{
    \pgfmathsetcount\rotorcountiii{int(Mod(#2+\rotorphasecountiii,26))}
    \xdef\rotortextiii{\ifcase\rotorcountiii4\or0\or1\or2\or3\or5\or6\or7\or8\or9\or10\or11\or12\or13\or14\or15\or16\or23\or24\or25\or17\or18\or19\or20\or21\or22\fi}
    \pgfmathsetmacro#1{int(Mod(\rotortextiii-\rotorphasecountiii,26))}
}
\def\inverserotorii#1#2{
    \pgfmathsetcount\rotorcountii{int(Mod(#2+\rotorphasecountii,26))}
    \xdef\rotortextii{\ifcase\rotorcountii4\or0\or1\or2\or3\or5\or6\or10\or11\or12\or7\or8\or9\or13\or14\or15\or16\or17\or18\or19\or20\or21\or22\or23\or24\or25\fi}
    \pgfmathsetmacro#1{int(Mod(\rotortextii-\rotorphasecountii,26))}
}
\def\inverserotori#1#2{
    \pgfmathsetcount\rotorcounti{int(Mod(#2+\rotorphasecounti,26))}
    \xdef\rotortexti{\ifcase\rotorcounti4\or0\or1\or2\or3\or25\or5\or6\or7\or8\or9\or10\or11\or12\or13\or14\or15\or16\or17\or18\or19\or20\or21\or22\or23\or24\fi}
    \pgfmathsetmacro#1{int(Mod(\rotortexti-\rotorphasecounti,26))}
}

% Now we finish the definition.

\begin{document}

\def\crystring{}
\rotorphasecounti5
\rotorphasecountii8
\rotorphasecountiii13
\begin{private}
    AN ENIGMA MACHINE WAS A SERIES OF ELECTRO-MECHANICAL ROTOR CIPHER MACHINES DEVELOPED AND USED IN THE EARLY TO MID TWENTIETH CENTURY FOR COMMERCIAL AND MILITARY USAGE. ENIGMA WAS INVENTED BY THE GERMAN ENGINEER ARTHUR SCHERBIUS AT THE END OF WORLD WAR I.[1] EARLY MODELS WERE USED COMMERCIALLY FROM THE EARLY 1920S, AND ADOPTED BY MILITARY AND GOVERNMENT SERVICES OF SEVERAL COUNTRIES, MOST NOTABLY NAZI GERMANY BEFORE AND DURING WORLD WAR II.[2] SEVERAL DIFFERENT ENIGMA MODELS WERE PRODUCED, BUT THE GERMAN MILITARY MODELS ARE THE MOST COMMONLY RECOGNISED.
\end{private}
\newwrite\cryfile
\immediate\openout\cryfile=\jobname.cry
\immediate\write\cryfile{\crystring}
\immediate\closeout\cryfile
\input{\jobname.cry}

\bigskip

\def\crystring{}
\rotorphasecounti5
\rotorphasecountii8
\rotorphasecountiii13
\begin{private}
    ISWXACOIOIGKAXHFCQCQREARUMCRVRFMERXORFOIBAAIVBM UMEFASKWEOIFKABRPWRLRVMSNWQBAOMRWVBUKRMLEYLPUSV WPDNMPVSPKFXMPTULCXUFXKNHUVVBYRQOUBYVJWALMQMBSK SQVBURPBBYLEVLJVZGIJKVBVAURLVLBFLVGPUPJODPMFOVPGYA PUJJOSVLOHCNLPOZNUPYJPSFVUKJNJGZVOKNGSPARPUFLYYUSFW UOJMCSLYQZPGOMJHBZJLUCOXZOZAEQPZGHRWJWNOMHOTZJAX UMURPTNUPMLWWPUADJBLVPOVFAROSUWBOCYAJNTANOEPHTR MCKBAPRFHEBSVABRTZYMAYGNRBAPZARAYYCRKHFBOXARPZYG SBWVHIBHYZWRAVCBJFMXABUGVCPXRCSGPQVNRBMEWZVNVYV QZELWJNSYEZBSVKSWJEQDJKWJXYLBRLMWXTESFK
\end{private}
\newwrite\cryfile
\immediate\openout\cryfile=\jobname.cry
\immediate\write\cryfile{\crystring}
\immediate\closeout\cryfile
\input{\jobname.cry}

\end{document}

Comments

  • One can extend the macros so that one can use lower letters or even symbols in their text. At that time one needs to take care of category codes.
  • So far the \rotors I implemented are stupid. Because otherwise I have to calculate the \inverserotors carefully.
  • Enigma is by no means efficient. This is just an illustration of how complex could it be.

Old answer

I would like to propose my approach:

  • your ciphertext should be some unicode characters. (So you can compile it by XeLaTeX without password.)
  • One guesses the password by setting, say, \password="2600.
  • For every unicode character, \password is subtracted form its code point. For example =U+2655 becomes 55
  • the remaining number is printed to a file with ^^. That is, ^^55 is printed to a file
  • After all unicode characters are processed, the file is \inputed. Therefor finally becomes U.

Some efforts are left to you:

  • Now the decipher function D(♕,2600)='U' is quiet simple. You should be able to come up with a better one.
  • I am too lazy to pack macros. Do it yourself.

\documentclass{article}
\usepackage{fontspec}

\newcount\password
\newcount\crycount
\newcount\crycounta
\newcount\crycountb

\def\private#1{%
    \ifx#1\end
        \expandafter\end
    \else
        \crycount`#1
        % ↓↓↓ some math involving \crycount and \password
        \advance\crycount-\password
        \crycounta\crycount\crycountb\crycount\divide\crycounta16\multiply\crycounta16\advance\crycountb-\crycounta\divide\crycounta16
    \xdef\crychara{\ifcase\crycounta0\or1\or2\or3\or4\or5\or6\or7\or8\or9\or a\or b\or c\or d\or e\else f\fi}
    \xdef\crycharb{\ifcase\crycountb0\or1\or2\or3\or4\or5\or6\or7\or8\or9\or a\or b\or c\or d\or e\else f\fi}
        % ↑↑↑ some math involving \crycount and \password
        \xdef\crystring{\crystring\string^\string^\crychara\crycharb}
        \expandafter\private
    \fi
}

\begin{document}

If key is set to be 2600, you can see the hint below:
\password"2600
\def\crystring{}
\begin{private}
    ♕♳♥☠♭♡♴♨♥♭♡♴♩♣♡♬☠♩♮♤♵♣♴♩♯♮☠♯♮☠☤♜♬♡♭♢♤♡☤☮
\end{private}

\newwrite\cryfile
\immediate\openout\cryfile=\jobname.cry
\immediate\write\cryfile{\crystring}
\immediate\closeout\cryfile
\input{\jobname.cry}

If key is not 2600, you see random characters:
\password"0
\def\crystring{}
\begin{private}
    ♕♳♥☠♭♡♴♨♥♭♡♴♩♣♡♬☠♩♮♤♵♣♴♩♯♮☠♯♮☠☤♜♬♡♭♢♤♡☤☮
\end{private}

\newwrite\cryfile
\immediate\openout\cryfile=\jobname.cry
\immediate\write\cryfile{\crystring}
\immediate\closeout\cryfile
\input{\jobname.cry}

\end{document}
8
  • 2
    If I understand correctly, you are proposing a variant of a shift cypher: each code point is shifted by the same amount (like 2600). Such cyphers are easy to break using the known frequency distributions of letters in text. Commented Oct 28, 2015 at 19:32
  • 1
    @ChristianLindig Yes, but no. In this version, you only need to checkout the greatest and the least code point. No statistics. But the framework is clear now: one can "fill in" a nontrivial decipher functions such as Decipher(ciphertext,password) = floor [(last cipher text + ciphertext*password1 + password2)/10 ]. If you are passion enough, it is possible to implement Enigma in TeX .
    – Symbol 1
    Commented Oct 28, 2015 at 23:29
  • Nice solution. Which tool do you use to encrypt in the first solution? I guess that the enigma solution can be run under pdfLaTeX. But do it only works for letters A-Z, e.g. space is gone in the output? Now we only need one of you LaTeX gurus to make a nice package :-)
    – Relund
    Commented Oct 29, 2015 at 9:10
  • 1
    @Symbol1 I'm surprised, to put it mildly. Could you explain how your new solution works? Where is a password needed, how do I use the code?
    – Keks Dose
    Commented Oct 29, 2015 at 16:23
  • 1
    @Relund ctan.org/pkg/enigma (I fixed a few issues in github.com/loopspace/TeX-Encryption) Commented Oct 17, 2023 at 20:10
7

This is not an issue related to LaTeX. You simply ask, how to encrypt parts (!) of an ASCII file.

Some editors are able to do this. As an example, orgmode, a major mode of Emacs, provides encryption of sections, see here: http://orgmode.org/manual/org_002dcrypt_002eel.html

The whole process is cumbersome: you need the software on both sides to encrypt and decrypt and an additional effort to apply en- / decryption on parts of a file.

If everybody used Emacs, no problem, but in reality: trouble.

3
  • 1
    I see what you mean that an editor is really the tool that will do the ENcrypting. However, it might be possible to have a package do the DEcrypting on the fly. That would be cool. Commented Oct 28, 2015 at 17:41
  • @StevenB.Segletes this was my original question. After some thoughts I think I will use another solution where the encryption and decryption is done in a pre-processing step using R and e.g. package secure. But based on Symbol 1's answer it seems possible.
    – Relund
    Commented Oct 29, 2015 at 9:17
  • I opened a thread motivated by your answer here tex.stackexchange.com/q/372802/13173 I think Fido U2F decryption action can be started from PDF file, generated by Adobe Acrobat Javascript API + LaTeX. Commented Jun 1, 2017 at 18:41

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .