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)

Relund
  • 245
  • 2
  • 6
  • 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 Oct 28 '15 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 Oct 28 '15 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 Oct 28 '15 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 Oct 28 '15 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. – Christian Lindig Oct 28 '15 at 19:54

2 Answers2

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}
Symbol 1
  • 36,855
  • 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. – Christian Lindig Oct 28 '15 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 Oct 28 '15 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 Oct 29 '15 at 09:10
  • @LarsRelundNielsen According to the design of Enigma, you can encrypt and decrypt using the same process. I illustrate Enigma with only capital letters because that is how it worked in the history. Certainly one can have an "ASCII Enigma" or "Base64 Enigma". But it would be less romantic. – Symbol 1 Oct 29 '15 at 09:33
  • 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 Oct 29 '15 at 16:23
  • @KeksDose I added some explanation. – Symbol 1 Nov 01 '15 at 14:02
  • I am trying to get your example work with user input in Acrotex eforms here https://tex.stackexchange.com/q/372802/13173 – Léo Léopold Hertz 준영 Oct 05 '17 at 09:30
  • 1
    @Relund https://ctan.org/pkg/enigma (I fixed a few issues in https://github.com/loopspace/TeX-Encryption) – Andrew Stacey Oct 17 '23 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.

Keks Dose
  • 30,892
  • 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. – Steven B. Segletes Oct 28 '15 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 Oct 29 '15 at 09:17
  • I opened a thread motivated by your answer here https://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. – Léo Léopold Hertz 준영 Jun 01 '17 at 18:41