![更新答案](https://linux22.com/image/321789/%E6%9B%B4%E6%96%B0%E7%AD%94%E6%A1%88.png)
假设您的 LaTeX 文档的某些部分包含一些文本,您只希望有密码的人可以看到。例如,原因可能是带有指导性答案的案例。您希望将案例公开,但答案仅供教师查看。
有谁知道有一个软件包可以做类似的事情:
\usepackage[password=<my password>]{decrypt}
\begin{document}
<Public text>
\begin{private}
<Private encrypted text>
\end{private}
\end{document}
例如,运行 pdfLaTeX 时,加密文本将被解密并显示在生成的 pdf 中。我猜需要进行某种预处理才能将私人文本替换为加密文本。一个想法可能是使用 R 和 knitr 来实现这一点(网上的一个示例是http://textmechanic.com/Encryption-Generator.html)
答案1
更新答案
这是谜。
注意,Enigma 是对称的。因此,你可以在同一个地方编码和解码。在下面的例子中,第一个输入AN ENIGMA MACHINE...
来自 Wikipedia 文章。然后我复制并粘贴输出ISWXACOIOIGKAXHF...
作为第二个输入。这样我们就得到了ANENIGMAMACHINE
第二个输出,也就是我们在开始时输入的内容。
\documentclass{article}
\usepackage{pgfmath}
% 这些计数器是寄存器。需要指定\rotorphasecount
s 的初始值,其功能与密码相同。
\newcount\crycount
\newcount\plugboardcount
\newcount\rotorcounti
\newcount\rotorcountii
\newcount\rotorcountiii
\newcount\rotorphasecounti
\newcount\rotorphasecountii
\newcount\rotorphasecountiii
\newcount\reflectorcount
% 这是主要函数。它读取字符直到达到\end
。
\def\private#1{%
\ifx#1\end
\expandafter\end
\else
% 首先,将大写字母转换为数字。我们希望A
变成0
和Z
变成25
。
\crycount`#1
\pgfmathsetmacro\crystringi{int(Mod(\crycount-65,26))}
% 现在数字通过了接线板,它是 Enigma 密码机的一部分。
\plugboard\crystringii\crystringi
% 现在数字通过三个转子。如果你愿意,也可以是四个。
\rotori\crystringiii\crystringii
\rotorii\crystringiv\crystringiii
\rotoriii\crystringv\crystringiv
% 现在数字已经到达反射器。
\reflector\crystringvi\crystringv
% 因此数字会向后移动,穿过转子和插线板。
\inverserotoriii\crystringvii\crystringvi
\inverserotorii\crystringviii\crystringvii
\inverserotori\crystringix\crystringviii
\plugboard\crystringx\crystringix
% 将数字转换为对应大写字母的十六进制码。例如0
表示A
,所以应该是^^65
。
\pgfmathsetmacro\crystringxi{hex(\crystringx+65)}
\xdef\crystring{\crystring\string^\string^\crystringxi\string\allowbreak{}}
\expandafter\private
\fi
}
% 接线板交换字母对。在本例中,A
和被交换。 &和&也是B
如此。C
D
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}
}
% 转子以固定方式排列 26 个字母。有趣的是,每当一个数字经过时,第一个转子就会旋转 2π/26。每当第一个转子完成一个循环时,第二个转子就会旋转。依此类推。
\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))}
}
% 反射器反映数字。在历史上,它总是反映一个数字到一个不同的一,这使得 Enigma 具有自互易性,但不安全。
\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}
}
% 物理上只有三个转子。但我们仍需要实现相反方向的宏。
\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))}
}
% 现在我们完成定义。
\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}
评论
- 可以扩展宏,以便在文本中使用小写字母甚至符号。此时需要注意类别代码。
- 到目前为止,
\rotor
我实现的 s 很愚蠢。因为否则我必须\inverserotor
仔细计算 s。 - Enigma 绝对不高效。这只是一个例证,说明了它到底有多复杂。
旧答案
我想提出我的方法:
- 你的密文应该是一些unicode字符。(这样你就可以在不使用密码的情况下用XeLaTeX编译它。)
- 通过设置来猜测密码,例如
\password="2600
。 - 对于每个 Unicode 字符,
\password
从其代码点中减去。例如♕
=U+2655 变为55
- 剩余数字用 打印到文件中
^^
。也就是说,^^55
打印到文件中 - 处理完所有unicode字符后,文件就被
\input
编辑了。因此♕
最终变成U
。
还有一些努力需要你去做:
- 现在解密函数
D(♕,2600)='U'
非常简单。你应该能想出一个更好的。 - 懒得打包宏,自己做吧。
\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}
答案2
这不是与 LaTeX 相关的问题。你只需问如何加密 ASCII 文件的某些部分 (!)。
有些编辑器可以做到这一点。例如,Emacs 的主要模式 orgmode 提供了对节的加密,请参见此处:http://orgmode.org/manual/org_002dcrypt_002eel.html
整个过程非常麻烦:您需要双方的软件来加密和解密,并且需要额外的努力来对文件的各个部分进行加密/解密。
如果每个人都使用 Emacs,那就没问题了,但实际上:麻烦。