密钥密码学-全-
密钥密码学(全)
原文:
annas-archive.org/md5/b5abcf9a07e32fc6f42b907f001224a1译者:飞龙
前言
序言
从秘密解码环到政府政策声明,隐藏和发现信息的挑战长期以来一直吸引着智慧。密码学是一个引人入胜的主题,几乎每个学童都有一些实践经验。然而,出于良好的原因,它是一个被深度保密包裹的学科,并被政府用来保护其最敏感的武器。密码学在军事和外交事务中的作用一直非常严肃。毫不夸张地说,密码学的成功和失败塑造了战争的结局和历史的进程;而且毫不夸张地说,密码学的成功和失败正在制定我们当前的历史进程。
回想一下美国南北战争中的安提塔姆战役,发生在 1862 年 9 月,当时乔治·麦克莱兰指挥联盟军对抗罗伯特·E·李的南方联盟军,位于马里兰州夏普斯堡附近。几天前,两名联盟士兵在他们的营地附近发现了一张纸条,结果证明这是李发出的一份详细说明马里兰入侵计划的命令副本。这份命令没有加密。凭借其中的信息,麦克莱兰准确地知道了李散兵游勇的位置,并在他们重新联合之前摧毁了李的军队。
密码学的成功和失败也塑造了更近期的历史。1914 年 8 月,俄罗斯在坦尼斯堡的可怕失败是德军截获俄罗斯通讯的直接结果。令人惊讶的是,俄罗斯的通讯完全是明文的,因为俄罗斯没有为其野战指挥官配备密码和密钥。因此,俄罗斯无法安全地协调各军中邻近单位的活动。
第二次世界大战后即将发生的 50 年冷战也是由一个密码学失误引起的,这次是在 1942 年中途岛战役中对日本人的失败。美国密码分析员破译了日本的密码,并阅读了大量联合舰队的消息。这类故事属于古典密码学的范畴。秘钥密码学就是在这个领域中发挥作用的。
没有人比 Frank Rubin 博士更能启发对古典娱乐性密码学各个方面感兴趣的读者,从其数学传承到社会学影响。Frank Rubin 博士的教育背景是数学和计算机科学。他在 IBM 的设计自动化领域工作了 30 年,并从事密码学工作超过 50 年。Frank Rubin 博士曾担任《Cryptologia》等出版物的编辑。他撰写了数十种数学和计算机算法,并创建了数千个数学谜题。
秘钥密码学 不仅仅是 Helen F. Gaines 的经典作品 Elementary Cryptanalysis 的更新。它涵盖了从古代到量子计算时代的领域。秘钥密码学 提出了新的方法和“破译”技术。最后,它解释了一种测量密码强度的独特方法。^(1,2)
这本书出版在密码学发展史上一个战略性的时刻。它为理解这一关键技术提供了及时而重要的贡献。无论读者是寻求关于密码学本身的启迪,还是信息安全从业者,这些页面中包含的知识的深度和广度都将是一份有用的信息来源和图书馆的宝贵补充。
——Randall K. Nichols,DTM
Randall K. Nichols 是美国密码协会(ACA)的前任主席、贵族和书评编辑;堪萨斯州立大学萨利纳分校无人机系统网络安全证书课程的主任;以及尤蒂卡学院研究生网络安全与取证的名誉教授。
参考文献
Gaines, H. F.(1956)。密码分析:密码及其解决方案研究。纽约市:Dover。
LANAKI.(1998)。古典密码学课程 Vol. I.。加州拉古纳山:爱琴海公园出版社。
LANAKI.(1999)。古典密码学课程 Vol. II。加州拉古纳山:爱琴海公园出版社。
Nichols, R. K.(1999)。ICSA 密码学指南。纽约市:麦格劳希尔。
Rubin, F.(2022)。秘钥密码学。纽约州 Shelter Island:Manning Books。
Schneier, B.(1995)。应用密码学:C 语言协议、算法和源代码。纽约:John Wiley & Sons。
前言
写这本书有几个线索。让我们从我的高中朋友查理·罗斯开始。查理在学校书店工作。有一天,在为商店订购书籍时,他注意到了 Helen F. Gaines 的书 Cryptanalysis。查理想要这本书,他也想要员工折扣。但出现了一个问题。商店最少订购数量是三本。
查理需要让其他两个人购买这本书。他承诺我们会一起阅读这本书,然后制作其他人解密的密码。我买了这本书,读了它,然后制作了密码,但查理失去了兴趣。
Cryptanalysis 的封底上给出了美国密码协会(www.cryptogram.org)的一个长期不更新的街道地址,但我找到了他们并加入了。我开始解决他们在业余爱好者通讯 The Cryptogram 中发布的各种类型的密码,几年后我成为了一名助理编辑。我在那里是会员超过 40 年。
1977 年,一个更专业的密码学期刊Cryptologia开始发行。你可以在www.tandfonline.com/toc/ucry20/current找到它。我开始阅读这些文章,然后贡献文章,最终成为一名编辑。不知何故,我成了“疯子处理者”。所有那些文章都送到了我手上,我不得不摸索出其中的道理,看看是否隐藏着一个好主意。仅有一个案例符合条件。我把它写成了一篇文章发表在The Cryptogram上。作者非常感激,他以我的名义在以色列种了一棵树。
这段经历教会了我如何区分那些只是写得很糟糕的文章,或者作者简单地高估了密码强度的文章,与那些真正离谱的文章。我学到了这个:用一个弱密码的业余爱好者可以描述密码并写出步骤。真正的疯子无法将他们模糊而宏大的想法写在纸上。他们可以滔滔不绝地写自己的密码有多么精彩,但他们无法写出步骤。他们无法将他们的初步想法转化为具体的算法。
大约在 2005 年左右,我开始在马里斯特学院 CLS(继续生活学习)上课。不久后,我开始就数独、SumSum 和其他谜题(我写了三本数独谜题书)进行讲座;我的坦桑尼亚和蒙古之行;帝国大厦的建造;艾伦·图灵的一生;以及其他主题。我成为了课程委员会的一员。
2018 年,我自愿为一门两学期的密码学课程做讲师。在为课程准备近 450 张幻灯片的过程中,我意识到我有足够的材料写一本书。幸运的是,我发现一年前我已经开始写了这样一本书。就是这本。
致谢
几天前,我无意中听到妻子米里亚姆在电话里对朋友说:“就像我和弗兰克和这本书住在一个ménage à trois里一样。”谢谢你,米里亚姆,在写这本书花了 18 个月的时间里,一年寻找出版社,6 个月找文学经纪人,一年看文学经纪人毫无进展,最后一个月才在 Manning 找到了这本书的归属。再加上 18 个月的审阅、修改、编辑、修订、排版、修订、索引、撰写营销文案等等。
我要感谢所有在 Manning 出版社帮助过我这本书的人,特别是迈克尔·斯蒂芬斯,他冒了险给了我一个合同,并在整个过程的每个阶段都给予了帮助;玛丽娜·迈克尔斯为她的许多编辑改进;丽贝卡·莱因哈特为平滑道路;詹·霍尔和苏珊·霍尼韦尔为插图工作;蒂凡尼·泰勒在语法和标点方面提出了许多宝贵的建议;保罗·威尔斯和凯里·哈尔斯为书的制作工作;萨姆·伍德为营销文案;丹尼斯·达林尼克为排版;当然,还有出版商马尔金·巴斯。
特别感谢 Randall K. Nichols 教授在极短时间内撰写本书前言并在《密码》杂志上进行评论。同时也感谢 Enigma 博物馆的 Thomas Perera 教授提供 Fialka 图像。
感谢那些阅读手稿并提出许多建议和有用批评的审稿人:Christopher Kardell、Alex Lucas、Gabor Hajba、Michal Rutka、Jason Taylor、Roy Prins、Matthew Harvell、Riccardo Marotti 和 Paul Love。你们的建议帮助使这本书更加优秀。
最后,我必须感谢李·哈维·奥斯瓦尔德,他那令人发指的暗杀总统约翰·F·肯尼迪的行为阻止了我去联邦调查局总部进行安全面试,这也使我无法加入国家安全局,否则我写这本书就会成为一种重罪。
关于本书
谁应该阅读这本书?
本书面向广泛的读者群体:一般读者、密码学爱好者、历史爱好者、计算机科学学生、电气工程师、数学家和专业的密码学家。这使得我的工作变得更加困难,因为不可能使书中的每一部分都适合每一类读者。对于某些读者来说,书中的某些部分可能需要太多的数学知识。对于某些读者来说,有些部分可能太基础了。在本节中,我试图引导读者找到我认为最适合他们的材料。
-
一般读者可以直接阅读至第八章结束。只需跳过数学太难或技术性太强的部分。从第九章开始,情况开始变得棘手。从这一点开始,他们可以略读,并挑选感兴趣的主题。他们可能想阅读第十二章以获取一般概念,而不深入细节。
-
密码学爱好者可能会想阅读整本书,然后再仔细研究第 4.2 至 5.11 节,第 6.1 至 6.5 节,第 6.7 节,大部分第七章以及第 9.1 至 9.9 节,加上有趣的页面和挑战页面。
-
历史爱好者可以阅读整本书,忽略数学部分,以了解每种方法是何时以及由谁开发的时间线。
-
计算机科学学生可能会特别重视第 5.6 至 5.11 节,第八章和第 11 至 16 章。
-
电气工程师将寻找实用方法。他们应首先阅读第二章和第四章以建立基础,然后阅读第 7.2 至 7.8 节,第九章和第 11 至 16 章,特别强调第十二章。
-
数学家对第 4.5 节,第 5.6 至 5.12 节,第 10.4 至 10.7 节,第 11.7 至 11.10 节,第 12.3 至 12.6 节,第 13 至 16 章,特别是第 16.4.6 节和第十八章最感兴趣。
-
专业的密码学家对第 7.8、8.2、10.5、10.7、11.4、12.3 至 12.6、13.8、13.15、14.2、14.4、15.4 至 15.14、16.4、16.5 和 18.12 节最感兴趣。
关于密码学
我包含了一些有趣的密码和挑战密码,供想尝试解决的读者使用。 有趣的密码使用书中描述的标准方法。
挑战密码使用我自己发明的方法。 它们非常简单,以至于业余爱好者既可以猜测方法,又可以解决它们。 我试图做到公平,以便感兴趣的读者可以解决它们。 没有奇怪或复杂的东西。 没有奇怪的词语或扭曲的字母频率。 而且提供足够的材料来解决它们。
您可能会注意到一些以粗体 ***** 开头并以 ***** 结尾的部分。 这些是可选部分,可能包含计算机算法或更深层次的数学。 一些读者可能选择跳过这些部分。
liveBook 讨论论坛
购买 密钥密码学 包括免费访问 liveBook,Manning 的在线阅读平台。 使用 liveBook 的独家讨论功能,您可以将评论附加到全书或特定部分或段落。 为自己做笔记,提出和回答技术问题,并从作者和其他用户那里获得帮助,都是轻而易举的。 要访问论坛,请转到 livebook.manning.com/book/secret-key-cryptography/discussion。 您还可以在 livebook.manning.com/discussion 上了解有关 Manning 论坛和行为规则的更多信息。
Manning 对我们的读者的承诺是提供一个有意义的对话场所,个别读者之间以及读者与作者之间可以进行对话。 这并不是对作者参与的任何特定数量的承诺,他在论坛上的贡献仍然是自愿的(并且无报酬)。 只要这本书还在印刷中,论坛和以前讨论的档案将可以从出版商的网站访问。
其他在线资源
您可以在作者的网站 www.mastersoftware.biz 上找到作者的密码学产品。
作者简介

弗兰克·鲁宾拥有数学学士和硕士学位以及计算机科学博士学位。他在 IBM 工作了 28 年,从事设计自动化领域,在那里他设计并编写了专门用于设计计算机和电路的软件,IBM 工程师使用这些软件。他是 Master Software Corp.的所有者,该公司生产密码软件。弗兰克已获得四项关于密码方法的美国专利。弗兰克在密码学、计算机电路、图论和纯数学等领域发表了约 50 篇经过同行评议的期刊论文,以及几本(用户手册和项目规范)在 IBM 内部出版的书籍。在密码学领域,他以解决杰斐逊密码轮而闻名。在计算机科学领域,弗兰克以算术编码而闻名,这现在是文本压缩的标准方法之一,以及他的寻找哈密顿路径的算法。在纯数学领域,他可能以引入有限状态识别器概念而闻名。弗兰克有三本数独谜题书和两本自出版的 SumSum 谜题书。他是The Cryptogram,Technology Review和Journal of Recreational Mathematics等刊物上发表的超过 3500 个谜题的作者,他是唯一一个被授予专门为他自己的谜题而献给的JRM特刊的人。
关于封面插图
秘钥密码学封面上的图案是“Le Garçon de Bureau”,或者“办公室助理”,取自路易·库尔默编辑的一本 1841 年出版的书。每幅插图都是精心绘制和手工上色的。
在那些日子里,人们很容易通过他们的服装来辨认他们住在哪里,以及他们的行业或社会地位是什么。曼宁通过基于几个世纪前地区文化的丰富多样性的书籍封面,再现了今天计算机业的创造力和主动性,这些插图来自于这样的收藏品。
^(1.) R. K. 尼科尔斯的ICSA 密码学指南和 Bruce Schneier 的应用密码学都介绍了密码强度和随机性方法。前者集中在古典密码学上,后者集中在现代密码(尼科尔斯,1999;Schneier,1995)。
^(2.) 秘钥密码学的定义和写作比我前两本关于古典密码学的书更好,即古典密码学课程第一卷和第二卷(LANAKI,1998;1999)。
第一章:介绍
我从事密码学已经超过 50 年了。在这段时间里,我学到了很多东西。在这本书中,我试图将这些知识传授给下一代密码学家。其中很多是新的发现,在文献中找不到。
我知道已经有许多密码学书籍可供阅读。如果我希望人们阅读我的书,我需要提供其他书籍没有的想法,其他作者不知道的想法,或者认为不可能的想法。我需要让这本书轰动。让我们开始吧。我将
-
用简单的非技术性语言告诉你如何构建一个不可破解的密码。
-
提供了 140 种可直接使用的密码。其中有 30 种被评为不可破解。
-
给你一套工具和技术,让你可以结合并加强它们。
-
描述一个可以精确测量密码强度并保证其不可破解的计算方法。
-
展示如何构建和整合数据压缩代码。
-
揭示了实现不可破解一次性密码本密码的实用方法。
-
告诉如何批量生成真随机数。
-
展示如何构建大素数和安全素数。
-
教你如何向密码添加一个不可检测的后门。
-
揭示了量子密码学中可能存在的致命缺陷。
-
解释如何击败可能在未来几十年内开发的假设的超级计算机。(或者,可能已经存在,但是被列为机密。)
我在整本书中都使用对话的语气,就好像你和我面对面交谈一样。当我说“我们”或“我们”时,那意味着你,读者,和我,作者,一起合作解决问题或保守秘密。
这不是一本学术性的著作。我在了解来源时会给予方法和想法以及尽可能接近的日期,但我所学到的大部分都是非正式获得的。书中几乎没有参考文献、脚注或博学的注释。这本书是为了实用而写的。遵循它的建议,你将制作出一个安全的密码。保证。
我还会不时插入一些历史趣闻,部分是为了缓和气氛,部分是为了纠正历史记录。我知道像密码学这样的沉重主题可能会让人感到困难。我希望使用第一人称,一些小轶事和一点幽默可以让读者更容易吸收。
这本书中的许多材料都是新的。它包含了构建密码和破译密码的方法,这些方法以前从未被公开过。甚至还有一些我自己的数学发现。你只能在这本书中找到它们。书中还有很多关于如何做事情的实用技巧,以及一些可以更快或使用更少存储空间的计算机方法。
本书的重点是高安全性密码学。你有需要保密的信息,面对可能拥有超级计算机甚至量子计算机的对手。这本书告诉你如何做到。我提供了一套方法工具箱,包括新的和历史悠久的方法,可以以各种方式组合,制作出任意强大的密码。密码学学生和开发人员将找到最广泛的实用方法,可用于开发新的密码产品和服务。
话虽如此,我希望这些材料对专业人士和业余爱好者都能够轻松理解。有很多方法可以手工完成,只需纸和铅笔即可。你可以在第 9.6.1 节的末尾找到这样一种方法。这些方法适用于现场使用,当电力和电子设备可能不可用时。甚至有一些儿童可以使用的密码。
任何人都可以创建一个不可破解的密码。
你可以创建一个不可破解的密码。你所需要的只是正确的知识。如果你能阅读并理解这本书,甚至只是其中一半,那么你就可以创建一个不可破解的密码。这本书教会任何有愿望的人如何构建一个能够经受住受过训练的密码学家和超级计算机的严格攻击的密码。没有其他书能做到这一点。事实上,你甚至可以使用纸和铅笔方法开发自己的安全密码。我从 15 世纪开始构建了大量的方法和概念,教会你哪些组合可以加强你的密码,哪些只是徒劳无功。我将为你提供一系列经过验证的技术,以及新颖的技术,让你可以构建一个坚不可摧的堡垒。
提前警告:我是一名受过数学训练的数学家,职业是计算机科学家,所以我倾向于自由使用数学符号和数学概念。这本书面向更广泛的受众,不仅仅是工程师和科学家。我会尽力解释所有需要的数学知识,使得这本书是自包含的。如果你理解下标和指数,并且能够阅读包含括号的表达式,那么你所需的数学背景就差不多了。我会解释所有超出这个范围的数学知识,比如质数、模运算,以及更高级章节中的矩阵运算和数学环。
如果你不理解某个数学概念,你有三个选择:(1)相信我的话,(2)完全跳过该部分,或者(3)不使用相关的密码方法。仍然有很多方法。一定有适合你需求的方法。
或者,直接深入阅读数学部分。你可能会惊讶于自己学到了多少。如果你不理解某个主题,不要灰心。你可能会觉得下一个主题很容易。即使是专业数学家也不会理解每个主题。
第二章:什么是密码学?
本章涵盖
-
密码学中使用的基本术语
-
什么是不可破解的密码?
-
有哪些不同类型的密码学?
密码学通常被称为“秘密写作的艺术”。它不仅仅是那样。它涵盖了从隐形墨水到通过光子的量子纠缠传输消息的所有内容。特别是,密码学包括制作和破译代码和密码。
不同的作者以不一致的方式使用密码学术语,因此让我们首先就一些基本术语达成一致。
明文 或 纯文本 是你希望保密的消息或文档。在传统密码学中,消息是发送者和接收者都知道的某种语言编写的文本。在计算机环境中,这可以是任何类型的文件,例如 PDF(文本)、JPG(图像)、MP3(音频)或 AVI(多媒体)。
密码 是一种用于使消息变得不可读的方法,或 算法:例如,通过改变字符的顺序或用不同的字符替换一些字符。通常,密码对文本中的单个字符或字符组进行操作,而不考虑它们的含义。
密钥 是仅知道发送者和合法接收者的秘密信息,用于选择每条消息使用的转换的信息。例如,如果密码(方法)是改变消息中字母的顺序,密钥可能指定当天消息使用的顺序。密钥可以是字母、单词或短语、数字或字母、单词和数字的序列。密码的强度高度依赖于它使用的密钥的总大小。
关键字 或 关键短语 是用作密钥的单词或短语。
加密 或 加密 是将明文变成不可读杂乱的过程,合法发送者知道密钥。
密文 是结果杂乱不可读的消息或文档,将被传输或存储。
解密 或 解密 是合法接收者使用的过程,合法接收者知道方法和密钥,将杂乱的密文转换回原始明文消息。
代码 也是一种使消息变得不可读的方法。与密码相比,代码通常是对消息中的单词或短语进行操作。典型的代码用数字或字母组成的组替换单词或短语。(令人困惑的是,“代码”这个词也用来表示字母的标准化表示,例如莫尔斯电码。希望从上下文中可以清楚地理解其含义。)
密码学 是对密码学的形式化研究,用于构建和解决密码的数学和方法论。学者们研究密码学;破译者研究密码分析。
密码分析 是研究代码和密码的专门目的,以识别弱点并找到突破它们或相反,加强它们的方法。
破译是指通过没有密钥并且可能不知道加密方法的第三方(敌人或对手)解决加密消息的过程。这可以通过数学方法或通过耐心地收集和整理拦截来完成,但实际上通常归结为三个 B:贿赂、勒索和入侵。
2.1 无法破解的密码
现在我们有了一些共同的语言,让我来解决主要问题。我所说的“无法破解”到底是什么意思?首先,我指的是一个密码不能通过密码学手段破解。这排除了入侵、贿赂、胁迫、叛变、敲诈勒索、诱捕等手段。这些超出了我们的范围。其次,我指的是密码在实践中无法被破解。任何对手都有有限的资源和有限的时间来投入到破译任务中。在选择密码时,你需要对你的潜在对手可能用来破解你的密码的人力资源和计算机资源有一定的了解。做一个保守的猜测,考虑计算机的改进,增加安全边际,然后选择一个数字。然后,当你选择一个密码时,你就有了一个目标。达到这个目标,你的密码就是有效无法破解的。
记住,许多消息的寿命有限。如果你的消息是攻击在黎明时分,而你的敌人在中午读到了你的消息,那就太晚了。你已经发动了攻击。一个在 12 小时内可以被破解的密码,在你的对手没有 12 小时的情况下是无法被破解的。
只是为了让这个概念更加清晰,当我说一个密码已经被破解时,我是指对手可以读取使用该密码发送的消息。即使对手只能读取 1%或 0.01%的消息,该密码也被破解了。但是有一个截止点。如果对手只有在拦截了许多使用相同密钥加密的相同长度的消息,或者其中 63 个密钥位为零时才能读取消息,则密码仍然未破解。对手没有先验的方法来确定哪些消息使用了哪些密钥,或者哪些密钥几乎全为零。你可能永远不会发送两条相同长度且使用相同密钥的消息,或者其中 63 个密钥位中有 64 个为零的消息。
如果你的密码使用了一个 256 位的密钥,而一个敌方密码分析家找到了一个将其减少到 200 位甚至 150 位的数学或计算方法,那么该密码可能会被削弱,但如果你选择的安全级别是 128 位,它仍然未被破解。使用 256 位密钥来实现 128 位安全级别提供了巨大的安全保障。
当政府决定旧的数据加密标准不再安全时,它举行了一场新密码的国际竞赛。在全球范围内征集提案。数十种密码被提交。数百名密码学家评估了这些候选密码的安全性、速度和易于实施性。从 1997 年到 2000 年 4 月,进行了三轮淘汰,直到选出了一个获胜者。当你的密码将成为政府、银行、工业和军事的全球标准时,你需要做的就是这样。如果你决定参加下一次的竞赛,这本书将帮助你做好准备。
大多数读者不会尝试那样做。他们的密码会有更有限的范围。他们可能会信任自己的判断,或者他们设计的任何验证过程,来评估他们的密码。第十二章的原则将帮助他们做出明智和自信的决定。
2.2 密码学的类型
密码学有许多不同的类型。过去使用的一些类型是
-
隐藏消息:例如,信使可以吞下消息,或将其藏在靴子跟或马鞍中,或者简单地记住它。在古代,让信使把消息以他们不理解的语言的发音记忆是很常见的。
-
秘密方法,比如凯撒密码,其中字母表中的每个字母都被替换为后面 3 个位置的字母。也就是说,A 变成了 D,B 变成了 E,C 变成了 F,依此类推。
-
伪装消息,其中消息被制成看起来像其他东西,比如信使的衣服设计。
-
隐形信息,如微点或在加热或暴露于酸性物质时变得可见的隐形墨水。
-
误导:例如,签名或纸张的形状和颜色是真正的消息,而其他一切都是干扰或虚假信息。
所有隐藏消息的方法统称为隐写术,最早在 1499 年本笃会修士约翰内斯·特里特米乌斯(Johannes Trithemius)的著作《隐写术》(Steganographia)中描述,特里特米乌斯出生于约翰内斯·海登贝格。特里特米乌斯的书本身就是一种隐写术,因为它伪装成一本魔法书。
这些隐写术方法有现代对应物。例如,可以通过仅使用每个像素的低阶位在 JPEG 图像文件中隐藏消息。另一个例子是使用随机数生成器来选择文件的每个字节中的特定位。所选位包含消息,其余位可以是随机的无用信息。
在描述现代密码之前,让我介绍一个有用的简化方法。一条消息从发送者发送给接收者,加密的目的是阻止某个敌人阅读消息。为了简洁起见,我将发送者称为桑德拉,预期接收者称为莉娃,敌人称为艾米丽。这比艾丽斯、鲍勃和卡罗尔更自然,不是吗?

通常桑德拉在本地对消息进行加密,然后再发送给莉娃。消息可以通过任何方式发送:信件、电话、互联网、短波无线电、阿尔迪斯灯、微气泡、电报、光纤电缆、信号旗、量子纠缠,甚至如果有直线视野的话,还可以使用烟信号。为了使这个图像更加完整,密码可能需要一个密钥以及明文,可能会有敌人在监听。这是一个更完整的图像。

现代密码通常分为三大类:秘钥、公钥和个人钥匙。它们的主要区别如下。
秘钥:桑德拉有一个秘密密钥,用于加密消息。莉娃有一个对应的秘密密钥,用于解密这些消息。这可能是相同的密钥或者一个反向密钥。通常情况下,桑德拉控制着密钥。当桑德拉更改密钥时,她必须将新密钥或其反向密钥发送给莉娃。这是经典密码学的标准范例。
公钥:莉娃有一个公共加密密钥,她向所有人公开。每当桑德拉想要给莉娃发送消息时,她都会使用莉娃的公钥对其进行加密。莉娃还有一个秘密解密密钥,只有她自己知道,她可以用来解密她收到的消息。要使这个方案工作,重要的是没有其他人可以从公共信息计算出这个秘密密钥。主要的公钥方法是由罗纳德·里韦斯特、阿迪·沙米尔和伦·阿德曼于大约 1975 年发明的 RSA 算法。
个人钥匙:桑德拉和莉娃各自拥有一个个人钥匙,不与任何人分享,甚至不与彼此分享。由于从未传输或分享任何密钥,个人密钥密码学有时被称为无密钥密码学。它是如何工作的:(第一步)桑德拉用她的个人密钥对消息进行加密,并将加密的消息发送给莉娃。 (第二步)莉娃用她的个人密钥对该消息进行再次加密,并将这个双重加密的消息发送回给桑德拉。 (第三步)桑德拉使用她的个人密钥对该消息进行解密,并将其发送回给莉娃。 现在消息只使用莉娃的密钥加密,她可以使用该密钥来阅读消息。
这里的棘手之处在于桑德拉的加密和莉娃的加密需要交换律。也就是说,无论桑德拉先加密还是莉娃先加密,它们都必须产生相同的结果。符号上,我们将其表示为 SRM=RSM,其中 M 是消息,S 和 R 分别是桑德拉和莉娃的加密。个人密钥加密的优势在于,任何人都可以与任何其他人安全地通信,而无需预先安排任何密钥或传输任何密钥,因此不存在密钥被拦截的可能性。
个人密钥密码学也称为三次传递协议。协议只是用于某种目的(如传输消息)的一系列步骤。换句话说,协议就是一种算法。三次传递协议的基本思想是由 Adi Shamir 在大约 1975 年发明的,我在本书中介绍的具体方法则是我自己的。
2.3 对称与非对称密码学
许多书籍指出,密码学可以分为两种类型:对称和非对称密码。其观点是,在秘密密钥密码学中,Sandra 和 Riva 使用相同的密钥来加密和解密消息,而在公钥密码学中,Sandra 使用一个密钥,而 Riva 使用其逆密钥。这种二分法忽视了个人密钥密码学,既不对称也不对称,以及第 2.2 节开头描述的各种经典方法。此外,对称/非对称分类并不总是准确的。在第 15.1 节中,我描述了 希尔密码,一种加密方法,其中加密是通过密钥乘以消息来完成的,而解密是通过乘以逆密钥来完成的——就像公钥密码学一样。
将密码作为对称或非对称的分类并不特别有用。它未能捕捉到秘密密钥和公钥密码学之间的本质区别,即在秘密密钥密码学中,所有密钥都保持秘密,而在公钥密码学中,每个参与方都保持一个密钥秘密,并将一个密钥公开并提供给所有人。
公钥密码学和个人密钥密码学都诞生于 1975 年左右。公钥密码学引发了人们的想象力,因此自那时以来,秘密密钥和个人密钥方法受到了少数关注。许多书籍对公钥密码学有详尽的介绍。本书主要关注秘密密钥密码学,这是密码学的主要支柱和基石。
2.4 块密码与流密码
另一种分类是将密码分为块密码和流密码。块密码对消息中的字符块进行操作,比如 5 个字符的块。通常所有的块大小都相同,并且每个块都使用相同的密钥。
流密码是一次处理消息的一个字符。每个字符都有自己的密钥,称为字符密钥,通常取自称为消息密钥的较大密钥。在旧的流密码中,消息密钥被重复使用。例如,如果消息密钥大小为 10 个字符,那么第一个密钥字符将用于加密消息的第 1、11、21、31 等字符,第二个密钥字符将用于加密消息的第 2、12、22、32 等字符,依此类推。使用定期重复密钥的密码称为周期性密码。在较新的流密码中,消息密钥通常与消息本身一样长,并称为密钥流。这种非周期性或非周期性的加密方式称为一次性密码本。在第十三章中,将讨论如何生成密钥流。
区块/流分类并不是互斥的。还有混合密码,其中消息被分成块,但不同的块用不同的密钥加密,因此密码是对一系列块而不是一系列字符进行操作。
2.5 机械与数字
密码也可以根据产生它们的方法进行分类。最早的密码完全是手工完成的。不是用铅笔和纸,而是用尖笔和羊皮纸,或尖笔和粘土板。
第一种机械加密手段是由古希腊人和斯巴达人使用的天线或斯底尔(发音为 SKIT-a-lee),可能早在公元前 700 年就已经存在了。它由一个棒状物组成,周围缠绕着一条窄窄的皮革或羊皮纸条,以便每个转的边缘与相邻转的边缘完全匹配。换句话说,没有间隙,也没有重叠。消息的字母被写在带子的两个或更多转上。当带子解开时,只有断断续续的字母片段可见,以便敌人不会意识到其中包含一条消息。还可以添加额外的波纹或颜色斑块,使其看起来像是装饰品。
发件人保留棒以供阅读和编写未来的消息。信使可以将带子当作腰带佩戴,或用来扎头发或勒马鞍。收件人需要一个与之直径相同的棒来重建消息。当然,信使们不会被告知带子或鞍带的目的。它甚至可能被偷偷地缝进他们的衣服中而不被察觉。
在乔瓦尼·巴蒂斯塔·波尔塔(Giovanni Battista Porta)的 1593 年版《关于隐秘文字记号》中有一张关于天线的图片。它展示了每个希腊字母是如何跨越几个转的皮带的。这是一个现代版本。

希腊人保守了 skytale 的秘密约 700 年。然而,罗马人并不那么成功。最终,他们在北欧的敌人了解了这些棒子的意义和用途。因此,罗马人发明了一种特殊的测量工具,由一个空心的黄铜或青铜十二面体组成,这是一个具有 12 个相同五边形面的固体形状,每个面上有一个圆孔。这些孔允许他们制作精确直径的木棍。当派驻需要穿越敌对领土的总督(satrap)、大使或间谍时,携带这种工具比携带可能被捕获的实际 skytale 更安全。这 12 个孔具有不同的直径,以便与其他总督、大使和间谍进行安全通信:例如,伦敦(现为伦敦)的小孔,里昂(现为里昂)的中等孔,以及塔拉戈纳(现为加泰罗尼亚的塔拉戈纳)的大孔。
据所知,这些十二面体的用途从未被北欧人或现代考古学家发现。考古学家为这些物品提出了许多荒谬的目的,如儿童玩具、鞍饰、铁匠的练习作品、烛台、火炮测距器,或者最后的答案,宗教物品。
这是在比利时最古老的城镇汤根附近发现的一枚青铜罗马十二面体,并展示在加洛-罗马博物馆。

这里有一个有趣的注释:如果你在维基百科和其他网站上查找 skytale,它说 skytale 被用来通过在带子的一个转动内写每个字母来生成换位密码。这是错误的。这样的带子很容易被识别为密码信息。无论敌人能否读懂这条消息,他们肯定不会让信使传递它。关于整个字母与断开字母问题的彻底审查可以在 cryptiana.web.fc2.com/code/scytale.htm 找到。1841 年,埃德加·爱伦·坡,一个才华横溢的密码学家,写了一篇名为“关于秘密写作的几句话”的论文,其中描述了 skytale 和他通过匹配断裂字母碎片来解密这些消息的方法。
要进一步弄错,如果你在维基百科中查找“换位密码”,它说 skytale 被用来制造“栅栏密码”,也称为“锯齿密码”。栅栏密码有交替向上和向下的列。在棒子上写信息不涉及任何方向的改变。因此,如果使用 skytale 生成换位密码,结果可能是列置换,而不是栅栏。 (我在维基百科上更正了这些错误,但我的更正被删除了。我已经放弃了试图成为维基百科警察。)
20 世纪 60 年代的一种天线是对一叠计算机打孔卡进行排序,用铅笔在卡片的外表面写下消息,然后彻底洗牌,只留下零散的点。当卡片通过卡片分类机时,卡片将恢复到原始顺序,消息可以被读取。程序员们广泛讨论了这个想法,但我不知道它是否被实践过。另一个现代等价物是在拼图的空白背面写下消息,然后打乱拼图块。接收者需要解决拼图,然后翻转它以阅读消息。
另一种机械密码是托马斯·杰斐逊在 1790 年至 1793 年间发明的杰斐逊轮密码机。它由 36 个相同大小的木制圆盘穿在一根铁棒上形成一个木制圆柱。在每个盘的外缘,按某种乱序写有 26 个字母。盘可以独立旋转以拼写任何消息。使用盘或纸条的杰斐逊密码的版本直到 20 世纪 60 年代仍在使用。
从 15 世纪到 19 世纪,许多类型的盘式密码机被发展出来。最常见的类型使用几个薄平面同心圆盘,可以围绕中心枢轴旋转。每个盘的上表面边缘写有字母或某些数字或符号,按某种顺序。盘逐渐变小,以便同时看到所有字母表。盘被对齐在某个位置,加密包括在一个盘上找到明文字母,然后使用另一个盘上对应的字母或符号作为密文字母。后来的盘式密码机在每个字母被加密后,手动或通过钟表机构推进内盘。
这是奥古斯托·布纳法尔切绘制的莱昂·巴蒂斯塔·阿尔贝蒂密码盘的图片,取自他 1467 年的著作De compendis cifri。(图片由维基共享资源分发。)

从 1915 年开始,一系列长期的电机机械转子密码机被发明出来。最著名的是 20 世纪 20 年代由德国工程师阿瑟·谢比乌斯开发的恩尼格玛机。直到计算机时代开始,几十种类型的密码机被推出市场。它们都产生流密码。基本思想是,字母的替代品由电流通过一系列旋转转子的路径确定。每个字母被加密后,一些转子转动,由各种凸轮、齿轮、凸耳和爪控制,以各种方式改变替代品。因此,如果单词 INFANTRY 变成PMRNQGFW,可能在数十亿次转动后不会再次发生。
自 1960 年代以来,密码学变得越来越计算机化和数字化。数据加密标准(DES)是由 IBM 在 1975 年开发的,并在 1977 年获得了国家标准局的认证。这引发了一系列带有名称的分组密码,如 Serpent 和 Twofish,最终以 2001 年由国家标准技术研究所(NIST)采用的高级加密标准(AES)告终。这类密码在第十一章中涵盖。
进展已经从手动 ➔ 机械 ➔ 电动机械 ➔ 数字化。
为什么选择秘密密钥?
在这个公钥密码学时代,自然会产生一个问题,为什么有人会选择秘密密钥密码学?有几个原因。
秘密密钥密码学速度更快。即使是最强大、最复杂的秘密密钥方法,其速度也往往是领先的公钥方法的数百甚至数千倍。事实上,公钥密码学的主要用途是为秘密密钥密码学加密密钥。密钥是使用公钥方法发送的,但消息本身是使用秘密密钥方法发送的。
公钥密码学(PKC)需要公钥基础设施。必须有公钥服务器将公钥分发给潜在的通信者。PKC 受到各种中间人和欺骗攻击的影响,对手冒充发送者、和/或接收者和/或密钥服务器,因此 PKC 需要大量的身份验证和验证。请求公钥的人必须证明与接收者在同一网络中。包含公钥的消息必须经过验证,以确保其来自服务器。接收者在首次在服务器上发布公钥时和每次更改时必须进行身份验证。当向网络中添加新方时,必须对授权新方的人进行身份验证。当将新网络添加到服务器时,必须对所涉及的每一方进行身份验证。接收者必须验证接收到的消息未经第三方篡改或替换。所有这些都导致了大量的消息。
秘钥密码学可以在没有任何行政负担的情况下运作。两个个体可以交换秘密密钥消息,而不需要涉及任何其他人或任何中间系统。当几个人交换秘密密钥消息时,唯一需要的授权是每个参与方都有当前的密钥。未经授权的人将没有密钥,也无法阅读消息。
交换消息并不是密码学的唯一用途。同样重要的作用是保护存储在计算机上、外部设备(如闪存驱动器)或云存储中的数据文件的机密性,通常需要很长时间。PKC 不能用于此目的。只有秘密密钥方法适用于保持数据文件机密。
当需要向许多接收者同时广播消息时,可以很容易地使用秘钥方法来实现。每个参与方只需拥有秘钥即可。他们可以使用一个特殊的广播秘钥,与他们的个人秘钥分开。或者,每个参与方可以通过使用一个单独的秘钥传输秘钥来发送消息秘钥。使用公钥方法,您需要获取所有接收者的个人公钥,以及所有相关的授权和验证。这不能事先安排,因为参与者可以随时更改他们的公钥。
最常见的公钥方法是 RSA 方法。该方法的强度取决于目前很难分解大数的事实(见第 3.4 节)。给定一个没有小质因数的 200 位十进制数,目前没有可行的方法来分解它。然而,当量子计算机可用时,这一切都会改变。麻省理工学院教授彼得·肖尔开发了一个可以轻松分解那么大数字的量子算法。当这发生时,存储在计算机上的所有 RSA 消息都将能够被读取。
到目前为止,尚无已知方法可以利用量子计算机来破解秘钥密码。如果量子计算机是一个问题,秘钥密码学是唯一的选择。
为什么要自己构建?
如果您是一个密码爱好者,为什么要构建自己的密码是显而易见的。您构建自己的密码是因为这是您的爱好。模型火车爱好者设计、构建和运行模型火车。模型飞机爱好者设计、构建和飞行模型飞机。密码爱好者设计、构建和解密密码。
如果您是一个密码学学生,构建自己的密码是很好的训练。这是学习如何构建和评估密码的最佳方式。当前标准密码 AES(第 11.5 节)不会永远持续下去,必须有人设计它的替代品。如果您想成为这一努力的一部分,这本书可能是您最好的起点。
如果您是一名负责保护高价值数据和通信的严肃密码学家,您可能会出于对政府批准的密码是否像您的政府声称的那样安全的健康怀疑而构建自己的密码。让我给您一个故事来支持您的怀疑。
大约在 1975 年,IBM 提出了现在称为 DES 的密码,即数据加密标准。它成为了全球标准的秘钥加密。正如 IBM 最初设计的那样,DES 具有 64 位秘钥。国家安全局(NSA)要求将秘钥从 64 位减少到 56 位,并将其他 8 位用作校验和。
这毫无意义。如果真的需要一个校验和,那么秘钥可以从 64 位增加到 72 位。人们普遍认为,NSA 提出这一要求的真正原因是它知道如何破解使用 56 位秘钥的消息,但不知道如何破解使用 64 位秘钥的消息。这被证明是真实的。
你可以合理地得出结论,NSA 绝不会批准任何它无法破解的加密标准。在这种情况下,你可以推断 NSA 可以破解所有不同形式的 AES。如果 NSA 可以破解 AES,那么它的俄罗斯和中国的对手很可能也可以破解 AES。
只有少数几位专家构建候选密码,从中选择全球标准密码。众所周知,这些专家在马里兰州的 NSA 总部 Fort Meade 接受简报。在这些会议期间,NSA 人员向他们提供可能加强或削弱密码的技术。可能隐藏在推荐方法中的是一些后门,让 NSA,只有 NSA,能够轻松解决这些密码。NSA 还可能提供工作、合同和研究资助,可能诱使专家采用那些脆弱的方法。
这里有很多猜测,但密码学家往往非常保守。如果你能想象出一个可能的弱点或漏洞,无论你的对手是否真的能够利用它,最好在能够时防范。
最后,你可能只是追求速度、更简单的实现或更便宜的硬件。你可能想构建自己的密码来实现这些目标而不放弃安全性。你会在这本书中找到可以帮助你做到这一点的方法。
话虽如此,请记住存在许多陷阱。不要仅仅创建一个密码并假设它足够“强大”。许多密码最终被发现存在意想不到的弱点。即使是最强大的密码也可能被操作员的错误所击败,比如每条消息都以标准头部开始,频繁重用密钥,或者使用不同密钥发送相同消息。例如,许多德国消息在二战期间被解密,因为它们都以“希特勒万岁”开始。
这本书包含了构建不可破解密码所需的所有信息,但请记住,仅阅读一本关于密码学的书并不会让你一夜之间成为专家。一定要使用第十二章详细介绍的原则来检查你的密码的强度。
第三章:初步概念
本章涵盖
-
位和字节
-
函数和布尔运算符
-
素数和模算术
在我们深入主题之前,让我们先看一些初步概念。我会快速地介绍这些主题,因为如今许多这些想法甚至在低年级就开始教授。更多这些基本概念将在书中后面根据需要给出。
3.1 位和字节
数据以位的形式存储在计算机中,这是二进制数字的简称。一个位只是一个可以取值为 0 或 1 的数字。一个位可以以几种方式存储在计算机中。开关可以是打开或关闭的。磁铁的北极可以朝上或朝下。光可以是顺时针或逆时针极化的。电脉冲可以具有小幅度或大幅度。
这些二进制数字可以用来形成二进制数。以下是 3 位二进制数及其十进制等价物。这些 3 位数被称为八进制数,意味着它们是基数为 8 的数:

位也用于表示计算机逻辑中的逻辑值或真值。0 表示逻辑值假,1 表示逻辑值真。
一个字符,比如字母或数字,可以用一个 8 位二进制数表示,这被称为字节。术语字节是由 IBM 的 Werner Buchholz 在 1954 年创造的。由于每个位有 2 个可能的值,8 位可以表示 2⁸个不同的字符:也就是 2 的 8 次方,即 256。这足以表示 26 个小写字母、26 个大写字母、10 个十进制数字、33 个标点符号,如=和$,再加上一些控制字符,如制表符和换行符。
有几种方案可以表示额外的字符,比如西里尔字母Ж,阿拉伯字母س,甚至中文是,每个表意符号最多使用 4 个字节。这对我们来说并不相关。密码可以处理字符串而不考虑它们的含义。被加密的字节可能是表示某个中文表意符号的 4 个字节中的第三个是无关紧要的。
对于我们的目的,一个字节有 3 个身份:(1)它是一个包含 8 个逻辑真/假值的字符串;(2)它是一个 8 位二进制数,因此是一个介于 0 和 255 之间的整数,包括 0 和 255;(3)它是某个字符的表示,比如字母、数字、标点符号或表意符号的一部分。
3.2 函数和运算符
数学函数现在在小学阶段就开始教授,所以我相信我不需要解释这个概念,但建立一些符号和术语是有帮助的。一个函数接受一个或多个值,并产生另一个值作为结果。被接受的值称为函数的输入或参数,返回的值称为输出或结果。我们说你应用函数到参数上以产生结果。
一个函数可以用符号表示,例如+或字母。当使用符号时,它被称为运算符,因此+和×是运算符,参数被称为操作数。当函数有一个参数时,符号可以放在参数前面,如-5 或√9,或者在参数后面,如 5!(5 的阶乘,即 1×2×3×4×5 = 120)。如果有两个参数,符号就放在它们之间,如 3+4 或 6×7。当符号是一个字母时,参数被括在括号中,如 f(x)。函数由 f 表示,参数由 x 表示。如果有多个参数,则用逗号分隔,如 f(a,b,c)。一些关于计算机语言的书籍区分参数和参数,但这在这里并不重要。
3.3 布尔运算符
正如加法、减法、乘法等函数对数字进行操作一样,当位表示真值时,有几个函数对位进行操作。这些函数被称为逻辑运算符,或者为了英国数学家乔治·布尔而称之为布尔运算符。
如果 A 和 B 是真值,则逻辑函数not,and,or和xor定义如下:
not A 如果 A 为假,则为真,如果 A 为真,则为假。
如果 A 和 B 都为真,则 A and B 为真,否则为假。
如果 A 或 B 或两者都为真,则 A or B 为真,否则为假。
如果 A 或 B 中只有一个为真,则 A xor B 为真,否则为假。
换句话说,如果 A 为真且 B 为假,或者如果 B 为真且 A 为假,则 A xor B 为真。xor被称为异或运算符。它通常用符号⊕表示,里面有一个带加号的圆圈。and和or运算符通常用符号∧和∨表示。很容易记住哪个是哪个,因为and的符号∧看起来像一个没有横杠的大写 A。
这里是四个布尔函数的值的表格形式:

这四个运算符可以通过对应的位对操作来将单个位扩展为位字符串。如果 A 是 0011,表示逻辑值为 false,false,true,true,如果 B 是 0101,表示逻辑值为 false,true,false,true,则应用四个布尔运算符得到

异或运算符在密码学中被广泛使用。例如,一次性密码本的简单实现(见第十四章)是将消息的字节与密钥流的字节进行异或运算,如下所示:

3.4 数字进位制
在普通算术中,数字用十进制表示。这种表示法是印度人和阿拉伯人在 5 至 7 世纪之间发明的。因此十进制数字也称为阿拉伯数字。这个系统由比萨的列奥纳多(列奥纳多·皮萨诺)引入欧洲,他在他那个时代被称为斐波那契。
历史趣闻
在莱昂纳多的时代,大约 1175-1250 年,滑动块拼图是风靡一时的。 (有些人认为这个谜题与据说是由诺伊斯·查普曼(Noyes Chapman)于 1874 年发明的十五拼图相同。)公开竞赛并奖金丰厚。莱昂纳多在这个谜题上是一个天才。他每次都赢。他的竞争对手给了他一个嘲笑的名字“斐波那契”,意思是“笨蛋”,莱昂纳多接受了这个名字。斐波那契在整个意大利都出名了。当斐波那契在 1202 年写了他的《计算之书》(Liber Abaci)时,他想让人们知道其作者是著名的斐波那契。直接说出这样的话会显得自夸和不体面,所以在封面上他写着Filius Bonacci,这可以理解为“幸运之子”或“Bonacci 之子”。
后来的作者没有理解这个意图,并拒绝认为伟大的莱昂纳多·皮萨诺应该被称为“笨蛋”。他们猜测莱昂纳多的姓可能是 Bonacci。出于同样的原因,为了提醒他的读者他是著名的斐波那契,莱昂纳多在他的私人文集中有时会狡猾地称自己为莱昂纳多·博纳奇(Lucky Leonardo)。
随着时间的推移,人们忘记了数学谜题天才斐波那契的名字和声誉,直到 1836 年,当书籍爱好者和臭名昭著的书籍盗窃犯古古列尔莫·利布里(Guglielmo Libri)将碎片拼凑在一起,并领悟到Filius + Bonacci = Fibonacci。术语斐波那契数和斐波那契数列是由法国数学家爱德华·卢卡斯(Edouard Lucas)于 1870 年左右创造的。
好的,回到工作上。为了解释十进制数,我们使用指数表示法。指数意味着一个数字乘以自身指定的次数。例如,5³表示 5 乘以自身 3 次,即 5×5×5,等于 125。在指数表达式 B^E 中,读作“B 的 E 次方”,或简称“B 的 E 次方”,B 称为底数,E 称为指数。如果 N 是任何数字,则 N¹是 N 本身。按照惯例,除了 0 之外的任何数字 N⁰均为 1。术语 0⁰没有定义的值,因为对 0⁰进行不同的计算会得到不同的结果。
当我们写一个十进制或者十进制,即底数为 10 的数,比如 3456 时,它表示 3×1000+4×100+5×10+6×1。使用指数表示法,这等同于 3×10³+4×10²+5×10¹+6×10⁰。从右边开始,低位数字,即此处的 6,乘以 1,下一个数字,即 5,乘以 10,接下来的数字分别乘以 10²,然后是 10³,依此类推。如果有 50 位数,左边的高位数字将乘以 10⁴⁹。
在其他数制中也是一样的。例如,二进制系统使用基数 2。二进制数 11001 被计算为 1×2⁴+1×2³+0×2²+0×2¹+1×2⁰,即 16+8+0+0+1,等于 25。计算机工作中常用的一种数制是十六进制,或基数 16。十六进制中使用的数字是 0123456789ABCDEF,或 0123456789abcdef。我更喜欢使用大写字母 ABCDEF,因为这样所有的十六进制数字高度都一样,更容易阅读。十六进制数 9AB 被计算为 9×16²+10×16¹+11×16⁰,即 9×256+10×16+11,等于十进制表示的 2475。
数制在密码学中的一个用途是将文本转换为数字。将字母表的 26 个字母与 26 进制的数字自然地关联起来,如下所示:

单词WORK可以表示为数字 22×26³+14×26²+17×26+10,即 396,588。这个值可以像任何数字一样进行操作,例如加法、减法或乘法。
大数可以用指数表示法,也称为科学表示法,例如:1.23×10⁷。这是 1.23 与 10⁷的乘积,即 10,000,000,所以 1.23×10⁷是 12,300,000。这与将 1.23 移动小数点 7 位的操作相同。
3.5 素数
数字,特别是大于 1 的整数,被分类为素数或合数。如果一个数是两个较小的正整数的乘积,则称为合数;否则它是素数。最初的几个合数是 4 = 2×2,6 = 2×3,8 = 2×4 和 9 = 3×3。最初的几个素数是 2、3、5、7 和 11。数 1 既不是素数也不是合数。
素数的一个重要性质是任何数都可以唯一地写成素数的乘积(除了因子的顺序)。例如,由于 30 = 2×3×5,除了 2、3 或 5 之外的素数都不能整除 30。这里的 2、3 和 5 被称为 30 的素数因子。任何整数的素数因子集合是唯一的。确定整数的素数因子称为因数分解或因式分解。
如果两个整数 A 和 B 没有共同的素数因子,则它们被称为互质或互素。例如,20 和 27 是互质的。如果 N 是一个整数,则 N 和 1 总是互质,而 N 和 0 只有当 N = 1 时互质。N 和 N+1 总是互质。
使用正整数时,当任何数 A 被另一个称为除数的数 B 除时,结果是一个商和一个余数。称商为 Q,余数为 R。然后 Q 被定义为最大的整数,使得 QB 不超过 A。余数指示剩余的量,即 R = A-QB。注意 0 ≤ R < N。例如,假设 A 是 40,B 是 11。不超过 40 的 11 的最大倍数是 33,因此商是 3,因为 3×11 = 33。余数是 7,因为 40-33 = 7。
3.6 模算术
残余的研究被称为模运算。模运算由哥廷根大学的数学家卡尔·弗里德里希·高斯于 1801 年引入。在模运算中,商被忽略,除数称为模数,余数称为剩余。在前面的例子中,模数是 11,剩余是 7。如果模数是 N,而两个数字 X 和 Y 有相同的剩余,我们说 X 和 Y 在模 N 下是同余的,或者等价地说,X 和 Y 在模 N 下属于同一个剩余类。这表示为 X≡Y (mod N)。例如,40≡7 (mod 11),因此 40 和 7 在模 11 下属于同一个剩余类。只要 X-Y 是 N 的倍数,或者等价地,只要 X = Y+aN 对某个整数 a 成立,X 和 Y 就在模 N 下是同余的。
剩余类遵循与普通整数相同的算术规则,例如

我们将-a 称为a 的加法逆元。记号 a-b 可以被看作 a+(-b)的简写。
乘法逆元的情况更为复杂。同余方程 ax≡b (mod N)有 3 种情况需要考虑:(1) 当 a 和 N 互质时,(2) 当 a 和 N 有一个不整除 b 的公因数 d 时,以及(3) 当 a、b 和 N 都能被公因数 d 整除时。
-
假设 a 和 N 互素。那么存在唯一的剩余 a',它是模 N 的乘法逆元,使得 aa'≡1 (mod N)且 a'a≡1 (mod N)。如果 a'存在,那么同余方程 ax≡b (mod N)可以轻松求解为 x≡a'b (mod N)。在第 15.3.2 节中,我介绍了当 N 很大时计算 a'的高效方法。
-
如果 a 和 N 有一个大于 1 的公因数 d,则 a 在模 N 下没有乘法逆元。就是说不存在一个 a'使得 aa'≡1 (mod N)。如果 b 不能被 d 整除,则同余方程 ax≡b (mod N)没有解。例如,4x≡5 (mod 12)没有解。
-
假设 d 是 a 和 N 的最大公约数,记为 gcd(a,N)。也就是说,d 是能够同时整除 a 和 N 的最大整数。如果 a、b 和 N 都能被 d 整除,则可以通过将 a、b 和 N 除以 d 来简化同余方程,即(a/d)x≡(b/d) (mod N/d)。
让我们看一个例子。考虑同余方程 8x≡4 (mod 12)。通过除以 4 得到简化的同余方程 2x≡1 (mod 3)。这个同余方程的解为 x≡2 (mod 3),意味着 x 可以是任何形式为 3n+2 的整数。回到原始同余方程,x 是模 12 的一个剩余,因此 x 必须在 0 到 11 的范围内。落在此范围内的形式为 3n+2 的数字是 2、5、8 和 11。这意味着 x 可以有值 2、5、8 或 11。因此,同余方程 8x≡4 (mod 12)有 4 个解。
在本书的后文中,mod被用作算术运算符。表达式 x mod y,其中 x 是整数,y 是正整数,表示 x 除以 y 的余数。因此 27 mod 3 是 0,27 mod 4 是 3,27 mod 5 是 2。
第四章:密码学家的工具箱
本章涵盖
-
用于密码的评级系统
-
替换密码
-
置换密码
-
分数化,将字母分解为更小的单元
-
伪随机数生成器
秘钥密码是由几个基本元素构建的。您可以将这些视为行业工具。要构建一个强大的密码,您希望在工具箱中拥有所有这些工具。这并不意味着您应该在每个密码中使用每个元素。这可能会导致过度复杂化而没有安全性的改善。您的密码会变得更慢,但没有任何额外的好处。本章涵盖了替换、置换、分数化和随机数等工具。我在第十章介绍了其他工具,如文本压缩,第十一章介绍了块链。
在讨论元素之前,让我们谈谈强度。密码的强度以比特为单位衡量。每个比特代表一个二进制选择。如果有一个密码,每个密文只能代表两种可能的明文之一,那么该密码的强度将为 1 比特。例如,
0 = 我们输了。
1 = 我们赢了。
密钥的大小是确定密码强度的限制因素。如果一个密码使用 64 位密钥,那么它的强度最多可以达到 64 位,但如果密码弱,则强度可能会更低。

4.1 评级系统
为了让您对本书中描述的密码的强度有一个大致了解,我使用了一个从一到十的评级标准。这些是我个人的评级,基于我的经验和我对使用我所知道的最佳技术来破解密码所需的努力以及密码之间以及与历史密码的比较,无论是实际上被破解还是未被破解。我在每个评级前面的部分中给出了大部分分析:
-
One 表示一个初学者可以仅使用纸和铅笔以及适度的努力来破解的密码。
-
Two 表示一个经验丰富的业余爱好者可以仅使用纸和铅笔破解的密码。
-
Three 是一个熟练的业余密码学家可以用手工方法破解的密码。
-
Four 或 Five 意味着需要计算机、训练有素的密码学家或两者兼而有之。
-
从六到九表示专家对手需要多少计算能力。
-
Ten 表示一个密码可以抵抗拥有大量训练有素的密码学家和当今最大超级计算机的国家加密机构。
有时我会超出这个范围。零表示该密码可以在不需要纸和铅笔的情况下理解,例如 Pig Latin 或 GNITIRW EHT SDROW SDRAWKCAB。十一的评级意味着该密码将能够抵御未来潜在的比我们目前构想的量子计算机或超级计算机更强大得多的超级计算机。
通过查看我对不同密码的评价,您可以了解如何评价您在其他地方看到的或您自己可能发明的密码的要点。每个评分只是一个估计,而不是强度的保证。保证来自于执行第十二章中描述的分析。
4.2 替代
密码学家工具箱中的第一个工具是替代。在文本中,一个单位被另一个单位替换。明文单位可以是单个字母、字母对或更长的块。密文单位可以是字母、字母块、数字块或字母数字组合。当所有单位都是单个字母时,该密码称为简单替换或单字母替代。在计算机密码学中,单位可以是位、字节或任意长度的位或字节块。本节给出了一个快速的预览。在第 5 和第六章中有一个全面的讨论。
已知的最古老的替代密码之一是凯撒密码,由尤利乌斯·凯撒使用并可能发明,其中字母表中的每个字母都被替换为后面第 3 个位置的字母。在现代使用中,这个数字可能是之前或之后的任何固定数字。凯撒密码被评为 One。
并非所有明文单位都要求具有相同的长度。假设密码采用字母表的字母并替换为 2 位数字对。字母表只有 26 个字母,但是 100 个可能的数字对。这意味着密码学家可以使用其他 74 对数字来进行其他用途。一个已经使用了数百年的方法是提供常见字母对的替代,例如 TH、ER、ON、AS 和 NT,以及可能的短词,如 THE 和 AND,除了单个字母。然后,明文单位将是 1、2 或 3 个字母长。这使得数字对的频率更加均匀。由于字母频率的差异可以用于解密密码,使频率更加均匀可以使密码更加强大。
另一种方法是使用额外的对提供某些常见字母的附加替代。这称为同音替代。例如,您可以为 E 提供 10 个替代品,为 T 提供 8 个替代品,依此类推。给定字母的多个替代称为同音字。这类似于同音字 F 和 PH 在英语中代表相同的音素的方式。提供多个替代品使得 100 个数字对的频率更加均匀。当然,字母对和同音替代两种方法可以结合起来,以获得更加均匀的数字对频率。换句话说,这些方法防止对手使用频率分析。
4.2.1 霍夫曼编码
在计算机环境中,密文单元可以是比特串。 一个很好的例子是哈夫曼编码,由 David A. Huffman 在 1952 年在麻省理工学院时开发。 我不会涵盖优化代码集的方法,我只会给出一般概念,作为可变长度二进制代码的示例。 在哈夫曼编码中,最常见的字母获得短代码,而较少见的字母获得长代码,基于底层字母频率表。 因此,需要更少的位来表达消息。 这被称为文本压缩。 在第 10.7 节中甚至有更强大的文本压缩方法。
英语中最常见的字母是 E 和 T,每个字母大约出现 1/8 的时间。 由于 8 = 2³,我们使用 3 位来表示 E 和 T。 我们可以任意选择任何 3 位值,比如 E = 100 和 T = 111。 我称这种方法为混合哈夫曼。 接下来最常见的是 A,O,I,N,S,R,H。 每个字母大约每 16 次出现一次,因此我们为每个字母使用 4 位。 我们可以使用任何 4 位代码,除了以 100 或 111 开头的代码,因为这些代码已经被使用。 下一组字母是 D,L,U,C,M,F,Y,每个字母大约每 32 次出现一次,因此需要 5 位代码。 依此类推。
这是我根据 15 万个英文文本字母计数创建的一组混合哈夫曼代码。 其他语言有所不同。 哈夫曼代码具有前缀属性,即没有代码是任何更长代码的前缀。 例如,如果 ABCD 是一个代码,那么对于任何二进制数字 A,B,C,D,E,ABCD 都不能是代码。 前缀属性最早由数学家埃米尔·莱昂·波斯特在 1920 年描述。

使用这些代码组,单词 STYLE 将被编码为0110 111 11011 01000 100。 将这些重新编写为 4 位组得到0110 1111 1011 0100 0100,这是十六进制6FB44。
尽管对于艾米莉,桑德拉的敌人,来说,要识别密文中每个字母的代码组几乎是不可能的,但艾米莉可以搜索更长的重复比特串。 这些将代表常见的字母对,称为双字母组,字母三元组,称为三字母组,或单词。 例如,任何给定的 10 位比特串应该大约每 2¹⁰,或 1024 次出现一次。 如果一个 10 位比特串在 1024 个字符串中出现 20 次或更多次,那么它几乎肯定代表单词 THE,这是英语中最常见的单词。 如果你在文本中识别出单词 THE,那么你可以寻找类似 THERE 或 THESE 的扩展,因为 E 的重复很容易发现。 混合哈夫曼评为三级。
4.3 转位
第二个主要的加密工具是转位,改变消息中字符的顺序。 最简单的方法是路由转位。 消息的字母按一定顺序写入���格中,然后按不同的顺序读取。 本节只是一个快速的概述。 全面讨论在第七章中。
例如,消息 THERE IS NO LOVE AMONG THIEVES,有 25 个字母,从左到右跨行写入到这个 5×5 网格中,并且从上到下跨列读出。在这个网格中,从上到下读取时,最左边的一列是TIOOI。

将字母写入网格和从网格中读出字母的常见路径包括直接穿过行,要么向左要么向右,直接向上或向下列,交替向左和向右穿过行,交替向上和向下列,对角线从任何角开始,交替方向对角线,或者顺时针或逆时针螺旋,要么向内要么向外。路由置换密码评定为 One。
4.4 分数化
分数化是将字符分割成较小单位。我们已经看到一种方式,将字符表示为二进制数。该二进制数的每一位可以作为一个单独的单位进行操作,替换或转置。本节介绍了分数化。第九章和第十章有详细讨论。
表示字母为两位数字的古典方式是Polybius Square,由希腊历史学家波利比乌斯在公元前二世纪发明。这是一个使用关键字 SAMPLE 的 5×5 方格。请注意,字母 I 和 J 共享一个单元格,以便将 26 个字母的字母表适合到 25 个单元格的网格中。

由于 A 在第 2 行第 3 列,它由 23 表示。B 是 33,C 是 34,依此类推,通过 Z 由 21 表示。I 和 J 都由 44 表示。然后可以以各种方式进行替换、转置和重新分组这些数字。可以使用这个网格或另一个按不同混合顺序排列的 Polybius 方格将数字对转换为字母。
现代版本将每个字符替换为其 ASCII 或 UTF-8 代码中的十六进制表示。因此 A = 41,B = 42,C = 43,一直到 Z = 5A。这些十六进制数字可以类似地被替换、转置、重新分组并重新转换为字节。
一个有趣的例子是M. E. Ohaver在 1910 年发明的分数化摩尔斯。Ohaver 总是使用 M.E.,因为他不喜欢自己的名字,这个名字是 Merle。
历史注解
在克雷格·鲍尔的《秘密历史:密码学故事》第 241 页的脚注中提到,M.E. Ohaver 是多产的低俗小说作家肯德尔·福斯特·克罗森的化名之一。这是不正确的。克罗森有时使用希伯来语的 mechaber,מחבר,意思是 作者,的化名 M.E. Chaber。
在分数化摩尔斯中,字母按固定大小的组,比如 7,被替换为它们的摩尔斯代码等效项,使用/作为字母分隔符。然后,代码组的长度被反转,调整大小后的组被转换回字母。

摩尔斯电码是由阿尔弗雷德·维尔于 1840 年发明的,以他的雇主塞缪尔·F·B·摩尔斯的名字命名。
这种密码有几个明显的弱点。因为它使用标准的摩尔斯字母表,所以唯一的密钥是字母组的长度,这只需要几次尝试就能猜到。明文字母经常被它们自己替换。有 30 个不同的摩尔斯代码组,但只有 26 个字母,所以需要 4 个额外的字符。奥哈弗使用了日耳曼语的ä、ë、ö和ü。分数化摩尔斯评级为一级。
这些问题可以通过两个变化来部分修复:(1) 仅使用长度为 1、3 和 4 的摩尔斯组。有 26 个这样的组,完全符合 26 个字母的字母表。(2) 打乱字母表的顺序,或者等价地打乱摩尔斯代码组的顺序。我称这个增强版为FR-Actionated Morse。例如,使用关键词 MIXEDALPHBT 来混合字母表,摩尔斯组按标准顺序排列,你会得到

即使有了这些改进,FR-Actionated Morse 的评级仍然只有二级。
4.5 随机数生成器
随机数生成器可以是任何在给定范围内产生数字序列的东西。数字可以是单个位、8 位字节、十进制数字,或者是任何其他所需范围内的数字。例如,范围在 0 到 25 之间的数字,对应于 26 个字母表中的字母,对某些加密目的是有用的。本节介绍了该主题。完整的讨论在第十三章中。
重要的是要认识到“随机数”这种东西是不存在的。你不能说 51 是一个随机数,而 52 不是,反之亦然。但是,你可以说序列 51,52,53,54,...不是随机的。那个序列是完全可预测的。随机性是序列或生成器的属性,而不是序列中的个别数字的属性。说“一系列随机数”比说“随机数序列”更准确。
生成器可能是一种物理过程,比如宇宙射线、盖革计数器的嗒嗒声、计算机按键的精确时间、风中飘扬的旗帜、海浪拍打的水花或者人们赶着赶火车的景象。大多数物理来源都不够快以用于加密目的,但数字序列可能会被存储在计算机文件中以供日后使用。
生成器也可以是一个数学函数或计算机程序,在每次调用时产生一个数字。由数学算法产生的随机数被称为伪随机数,以区别于真随机数。它们被认为比真随机数弱,因为确定随机序列的一部分的对手可能能够计算出前后的数字,从而读取消息。真随机数永远不能由数学函数产生。在第 13.8 节中,我展示了生成密码安全的伪随机数序列的方法,设计用于防止对手扩展序列的部分。
伪随机序列和真随机序列之间的一个关键区别是,伪随机序列最终会重复,而真随机序列永远不会重复。序列在重复之前的项数称为其周期。例如,序列 3,1,9,2,4,3,1,9,2,4,3,1,9,2,4,...的周期为 5,以下划线标出。一般来说,周期越长,密码越强。
仅仅因为一串数字是随机的,并不意味着这些数字是等概率的。例如,假设你观察到穿过繁忙桥梁的汽车的颜色。颜色是随机的,但某些颜色比其他颜色更常见。白色、黑色、银色和红色比橙色、紫红色或嫩黄色要常见得多。同样,在 crap 游戏中,如果骰子是公平的,那么每次掷骰子都是随机的,然而掷出 7 的可能性是掷出 12 的六倍。
在第 13.14.1 节和第 13.14.2 节中,我讨论了如何“收获”这种序列中的随机性,以获得数字具有基本相等概率的序列。从现在开始,我将假定任何随机数生成器都产生具有相等概率的数字。这被称为均匀分布或等概率分布。通过一个良好的随机数生成器,生成的数字对、三元组等也将具有均匀的概率,甚至可能达到八元组或更多。
4.5.1 链数字生成器
让我用纸和铅笔轻松完成的样本伪随机数生成器来结束这一节。不需要电脑。我们将其称为链数字生成器。首先写下任意 7 位的十进制数。这 7 位数字称为种子,或初始值,或初始化向量。它们可以被视为任何使用此生成器的密码的密钥,或密钥的一部分。要获得第一个伪随机数字,只需将第一个数字和最后一个数字相加。将这个新数字添加到序列中,并将第一个数字涂黑。所以,从 3920516 开始,我们将 3+6 加起来得到 9。

任何时候,如果总和超过 9,我们就去掉十位数。也就是说,加法是模 10 的。这有时被称为不进位加法。要获得第二个伪随机数字,我们重复这个过程。这里 9+9 得到 18。我们去掉十位数得到 8。

这个过程可以重复,以获得所需的伪随机十进制数字。

结果得到的伪随机序列是9800562199940232...。
注意,如果种子中的所有数字都是偶数,则生成的所有数字都将是偶数。同样,如果所有数字都可被 5 整除,即为 0 或 5,则生成的所有数字都将是 5 的倍数。在这种情况下,周期最多只能为 128,因为种子中有 7 个数字,而且只有 2⁷ = 128 种 0 和 5 的组合。由于这种种子无法产生长周期,因此它们被称为不合格的。对于链式数字生成器,合格的种子必须至少包含一个奇数数字和一个不是 5 的倍数的数字。例如,2222225 是合格的种子,但 2222222 和 5555555 不合格。使用合格的 7 位数字种子,周期将始终为 2,480,437。
这个生成器具有自制伪随机数生成器的典型行为。有 10⁷个可能的 7 位数字种子。如果你从任意种子开始,生成器将循环一些数字序列,直到再次产生该种子,因此 7 位数字的集合被分割成几个离散的周期,每个周期都有自己的周期。如果选择一个合格的种子,那么周期将始终具有最大可能的 2,480,437 个数字的周期。这种长度有 4 个单独的周期,再加上一些由不合格种子产生的远比这个短的周期。
对于其他大小的种子,行为类似。即使最大周期非常短,也经常有很高的概率获得最大周期,因为可能有许多最大周期。此表显示使用合格种子获得给定长度周期的概率:
| 数字 | 周期 | 概率 |
|---|---|---|
| 4 | 1,560 | 100% |
| 5 | 168 | 86.7% |
| 6 | 196,812 | 99.974% |
| 7 | 2,480,437 | 100% |
| 8 | 15,624 | 98.817% |
| 9 | 28,515,260 | 79.999% |
| 至少 2,851,526 | 99.9988% | |
| 10 | 1,736,327,236 | 86.9% |
| 至少 248,046,748 | 99.31% | |
| 至少 13,671,868 | 100% |
表格显示,5 位和 8 位数字种子长度不安全。它们产生了大量非常短的周期。7 位和 10 位数字种子长度最好,因为你总是保证有一个长周期。
这个随机数生成器严格来说只是一个演示模型,只是展示了使用简单手工方法可以实现什么。它不适用于高安全性工作。
4.6 有用的组合,浪费的组合
本章的 4 种基本技术可以以无数种方式组合,我将在本书的剩余部分中进行探讨。然而,首先要认识到并非每种组合都是有益的。一些组合会增加工作量而不增加强度。
考虑一种一些初学者尝试的想法。他们对一条消息进行简单替换,然后对结果文本进行第二次简单替换,然后第三次,依此类推,进行 5、10,甚至 100 轮。这是一种浪费精力的做法。进行两次简单替换与进行一次相同,但使用不同的混合字母表,因此进行多次简单替换不会增加任何强度。这里有一个例证。两次替换使用了关键字 FIRST 和 SECOND。第三次替换等同于先进行第一次替换,然后进行第二次替换。

让我们来看一个例子。如果我们使用第一个替换对EXAMPLE进行加密,结果是IUXEJDI。如果IUXEJDI使用第二个替换进行加密,结果是CLQYOXC。你可以自行验证,使用等效替换对EXAMPLE进行加密会得到CLQYOXC。
进行一次加密,然后再进行第二次加密被称为组合这两次加密。前面的例子表明,组合两个简单的替换只会产生另一个简单的替换。如果第一个加密使用了代码,那么在代码后面跟着一个密码被称为超加密。最常见的超加密形式是非进位加法,或者模 10 加法,其工作原理如下:

4.6.1 巴泽里 4 型密码
让我们看看相反的情况。让我们看一个使用替换步骤后跟着一个非常简单的置换产生了更强大密码的密码。
这种密码是由才华横溢、易怒且辱骂性的法国密码学家埃蒂安·巴泽里于 1898 年提出的。我不知道巴泽里给这种密码起了什么名字。我称之为Bazeries Type 4,因为这是他在 1890 年代向外交密码局提出的 4 种密码中的最后一种。这种密码可以很容易地手工完成。
巴泽里 4 型密码由一个简单的替换后跟着一个简单的置换组成,我称之为逐段反转。置换根据一个由小整数序列组成的密钥,对文本的短片段进行反转。这里有一个使用关键字 BAZERIS 混合替换字母表,以及关键字 4,2,3 进行置换的示例。

这种置换可以用来加强许多不同类型的密码,因此它值得拥有自己的名称。让我们称之为逐段反转。你可以通过混合一些正常顺序的文本段来加强这种置换,也许可以使用数值密钥中的负数。这里有一个使用数值密钥 3, 4, -3, 2 的示例。请注意,这个密钥等同于 3, 4, 1, 1, 1, 2。

密码学家们在密码局无法解决巴泽里斯提供的任何样本消息。尽管付出了相当大的努力,这些消息仍然在 40 年内未解决,直到著名建筑师和业余密码学家罗萨里奥·卡德拉解决了它们,并写了一本关于他是如何做到的书(巴泽里斯指挥官的军事密码,卡尔丹纳斯出版社:纽约,1938 年)。
然而,卡德拉无法直接解密这些消息。相反,他确定并利用了巴泽里斯从密钥生成替换字母表的方式中存在的弱点。如果巴泽里斯使用了更强大的方法来混合密码字母表,卡德拉就无法解密这些消息。因此,使用混合良好的字母表的巴泽里斯 4 型被评为五级。将两种分别评为一级的方法结合起来是相当不错的。
历史小贴士
卡德拉是哥伦比亚建筑学院的毕业生,所以他计划在哥伦比亚大学出版他的书。威廉·F·弗里德曼,当时是美国密码学家的院长,得知此事后,秘密阻止了出版。这再次证明了巴泽里斯 4 型密码的强大。
第五章:替换密码
本章包括
-
简单替换和多字母替换密码
-
使用 Kasiski 检测和重合指数解决多字母替换密码
-
自密钥和流动密钥密码以及解决它们的方法
-
模拟转子密码机
我们现在已经准备好更深入地探讨上一章描述的基本工具。在我开始描述所有不同的密码之前,让我明确陈述一下这些密码试图实现的目标。荷兰语言学家和博学家奥古斯特·克尔克霍夫斯(Auguste Kerckhoffs)首次在 1883 年的《军事科学杂志》上发表了这些原则的一对文章:
-
即使在理论上不可破解,密码在实践中也应该是无法破解的。
-
即使敌人了解了系统,这也应该成立。
-
密钥应该容易记忆(无需笔记)且易于更改。
-
应该能够通过电报传输加密的消息。
-
仪器和文件应该方便一个人携带和操作。
-
密码应该易于使用;不应有复杂的规则或计算。
规则 4 可能会更新为“数字方式传输加密的消息”。否则,这些原则今天仍然像 1883 年一样有效。
第二个原则的一个推论是,密码的强度应该完全取决于密钥。克尔克霍夫斯还相信只有密码学家有资格评判密码的安全性。太多时候,选择使用哪种密码的决定是由缺乏密码学专业知识的政府官员做出的,有时会造成灾难性的后果。
5.1 简单替换
简单 替换,也称为单字母替换,是你在报纸和杂志的谜题部分看到的熟悉类型的密码。在简单替换中,消息中的每个字母都被另一个字母一致且均匀地替换。因此,如果字母 M 在一个地方被 T 替换,那么消息中的每个 M 都将被 T 替换,而密码文中的每个 T 将表示一个 M。
由于大多数人熟悉解决简单替换密码的技巧,我只会简单提一下:字母频率、首字母频率、末字母频率、双字母频率、字母对频率、短单词、常见前缀和后缀、元音和辅音的分布、模式单词以及利用标点符号。
对于报纸中的简单密码,通常只需要查看短单词。如果你发现 AB 和 CBA,这些单词可能是 TO 和 NOT,而 AB 和 BAC 最常见是 OF 和 FOR。模式 ABCA 很可能是 THAT,ABCDC 暗示着 THERE,而 ABCDB 可能是 WHICH。如果你在互联网上搜索,你可能会找到出售模式单词列表的网站,或者会根据你提供的模式找到匹配的单词的网站。
对于更难的密码,像 FOXY PIXY MANX AXED TOXIC LUXURY ONYX SPHINX 这样的文本,需要更有组织的方法。
我将使用以下样本密码演示该过程。已知语言为英语。文本有 73 个字母和 11 个单词,平均每个单词长度为 6.64 个字母,而正常的英语为 5.0 个字母。缺少少于 5 个字母的短单词以及缺少模式单词表明这个密码已经被故意构造得很困难。

第一阶段是识别元音和辅音。首先计算每个字母的出现次数以获得频率计数。在样本密码中,A 的字母计数为 0,B 为 3,C 为 3,以此类推。完整的频率计数如下:

注意这里只有两个高频字母,L 和 S,出现的频率分别为 8 和 7。在正常的英文文本中,元音字母占 40%。这个百分比很稳定,即使字母频率被故意操纵也通常保持不变。在这个密码中有 73 个字母,应该有 29 个元音。这几乎要求 L 和 S 都代表元音,除非频率被严重扭曲。
接下来,你需要制作一个联系表格,将字母垂直地列在页面的中心。在密码中出现的每个不同的字母都有自己的行。在每一行上,出现在中心字母之前的每个字母都列在其左侧,而出现在中心字母之后的每个字母都列在其右侧。例如,表格的第一行,EO B DWZ,表示在密码中字母 B 分别被 E 和 O 前导一次,分别被 D、W 和 Z 后导一次。以下是这个密码的完整联系表格(为节省空间显示为 3 列)。

联系表格用于识别元音和辅音。一般来说,元音与左右两侧的字母有广泛的联系,而辅音则往往与有限数量的不同字母有联系。从联系表格中我们可以确定 4 个可能的元音,L、Q、S 和 V,以及 4 个可能的辅音,E、O、R 和 U。让我们用 ° 标记这些元音字母,用 ˟ 标记这些辅音字母,并看看分布是否合理。

在第 3 个单词EYXDO、第 7 个单词KIGXG和第 8 个单词YIWZ中都有 3 个长的没有元音的字母串。这表明I和/或X可能是元音。虽然它们都有很多不同的接触点,但X代表元音的可能性极小,因为那样的话第 11 个单词将以 3 个元音字母开头并以元音结尾。这在英语中很罕见。我找到的唯一例子是 OUIJA。(SQXMV不能是 AIOLI,因为 I 重复了。)因此,I很可能是元音,而X是辅音。
让我们再次尝试区分元音和辅音。在密码中有 5 对暂定元音,VL、VS、VQ、QL和SQ。在英语中,双元音并不常见,因此很可能V或Q实际上是辅音。很可能不是Q,因为那样的话第 10 个单词将以 5 个辅音结尾。我知道的唯一这样的 6 个字母单词是 ANGSTS。
让我们将I作为元音,将V和X作为辅音,看看我们的情况如何。

看起来是正确的。从第 3 个单词中,我们现在可以确定D是元音,从第 11 个单词中,M很可能是元音。现在所有 6 个元音都已找到,所以其他每个字母必须是辅音。以下是辅音和元音的完整分布。

第二阶段是识别单个字母。以下字母接触表显示了英语字母的接触特征。不同的语言会有不同的特征。例如,字母 M、V 和 Z 通常都是前导和后跟元音,而字母 N 通常是前导元音,但后跟辅音。我使用古腾堡计划的英语语料库编制了这个表。

在密码中,有一个很好的 H 明文候选者,即密文U。然而,U在以 US 结尾的双字母组中出现两次,因此这是不太可能的。
在密码中,有两个强有力的 N 候选者,即密文E和O。E和O都代表总是由元音前导和辅音后跟的辅音。然而,O是更强的选择,因为它的频率更高,并且因为它在单词ZLORUS中的两个已知辅音之前。在英语中,3 个辅音组合通常以 N 开头,例如NST和NTH。更有可能O代表 N。这产生了

现在可以尝试找到符合某些模式的可能单词。我找到了 67 个符合ZLORUS ˟°N˟˟°的单词。其中 32 个以 E 结尾,27 个以 Y 结尾。我找到了 37 个符合SQXMV °°˟°˟且不包含 N 的单词。其中 15 个以 Y 开头,但只有 1 个以 E 开头。因此,密文S最有可能代表明文 Y。这给了我们

密文单词 IVQOR 和 ZLORUS 都包含双字母 OR。让我们试着识别一下。知道 IVQOR °˟°N˟ 不含有 Y,剩下的有可能的单词只有 24 个。其中,有 12 个以 G 结尾,有 8 个以 S 结尾,因此密文 OR 可能是 NG 或者 NS。现在,对于 ZLORUS ˟°N˟˟Y 的可能明文单词减少到了 26 个。在这些中,第四个字母是 G 的有 8 次,是 T 的有 6 次,但是只有 1 次是 S。因此,密文 OR 最可能的选择是明文 NG。现在我们有了

对于第一个单词 RULEYS 有 8 种可能性。这些只包含双字母 UL 的 6 种可能性。对于这些选择中的每一个,让我们来看看单词 ZLORUS 的可能性。

选择 ZLORUS = JUNGLY 可以立即被排除,因为 KSYIWZ 将呈现出 ˟Y˟°˟J 的形式。在英语中没有这样的单词。这意味着 RULEYS 表示 GRUMPY,ZLORUS 表示 HUNGRY。填入这些新字母后得到

其余的字母可以凭眼识别填入。现在显然第二个单词是 PUDGY,第三个单词是 BUMPKIN,这使得第八个单词成为 BYPATH,等等。
完成的密码读起来是 GRUMPY PUDGY BUMPKIN CLUMSILY STUMBLED ALONG BACKCOUNTRY BYPATH,HUNGRY UNSHOD YOKEL。
简单替换被评为 One。当字母频率和接触频率被故意扭曲时,就像这个例子一样,评级可以达到 Two 或可能 Three。这是一个很好的谜题,但对于一般通信是无用的。
5.2 混合字母表
简单替换需要一个混合字母表。有几种传统的纸笔方法可以做到这一点。获得混合字母表的一种方法是使用一个关键词。在最简单的情况下,您只需从某个位置开始写入关键词,然后在其后填入剩余的字母,根据需要进行环绕。剩余的字母可以向前或向后填写。以下是三个示例:

这种方法最早由 Argenti 家族使用,他们是约 1600 年教皇和主教的密码秘书。这些字母表混合得不太好。一种稍微好一些的方法是使用两个关键词,就像这样:

列混合
将字母写入一个块中。将关键词写在顶行,其余的字母写在需要的行数中。较长的关键词可以提供更好的混合效果。然后从块中读出字母,沿着列向下读取。在这个例子中,关键词 SAMPLE 已经写在顶行。第一列向下读取是 SBIRY,第二列是 ACJTZ,依此类推。如果愿意,可以交替地沿着列向上和向下读取,或者使用其他路径。

SkipMix
在我上高中的时候,我发明了另一种适合纸笔密码学的方法,我称之为SkipMix。它使用一串称为跳数的小数字作为混合字母表的密钥,例如 3, 1, 4。从标准字母表开始。跳过 3 个字母并取下一个字母,即为 D。

删除该字母,然后跳过 1 个字母并取下一个字母,即为 F。

删除该字母,然后跳过 4 个字母并取下一个字母,即为 K。

然后重复 3,1,4 的循环。跳过 3 个字母并取下一个字母,即为 O。

继续重复键数的循环,直到选择了所有 26 个字母。生成的混合字母表是

SkipMix 可以与关键词一起使用。假设关键词是 SAMPLE。将每个字母替换为它在字母表中的位置,即 19,1,13,16,12,5。可选地,将任何 2 位数替换为其各位数字,即 1,9,1,1,3,1,6,1,2,5。使用这串跳数作为混合密钥。注意,0 是一个有效的值。
SkipMix 非常适合计算机使用。在这种情况下,字母表是 256 个不同的 8 位字符代码。跳数可以是从 0 到 255 的任何整数。数字密钥仍然可以由关键词派生而来。使用关键词而不仅仅是一串整数的优点是人们更容易记住和准确输入。再次假设关键词是 SAMPLE。这些字母在 ASCII 码中的数值等价于 83, 65, 77, 80, 76 和 69。这些值落在从 65 到 90 的窄范围内,这导致混合程度较低。为了将字母代码分散到更广泛的范围内,它们可以乘以某个常数值模 256。乘数可以是介于 7 到 39 之间的任何奇数。例如,关键词 SAMPLE 的 ASCII 码乘以 17 模 256 的结果是 131, 81, 29, 80, 12 和 149。这覆盖了一个范围为 149-12 = 137 的范围,远比原始范围 83-65 = 18 要宽。
跳数仍然只有 26 个可能的值。获得更大的值集合的一种方法是将相邻的数字进行模 256 的乘法。然后,跳数序列为 83×65, 65×77, 77×80, 80×76, 76×69 和 69×83,全部取模 256。因此,83×65 = 5395≡19 (mod 256)。数字密钥变为 19, 141, 16, 192, 124, 95,覆盖了范围 192-16 = 176。
产生更大的跳数集合的另一种方法是将关键词的第一个字母乘以 7,第二个字母乘以 9,第三个字母乘以 11,依此类推,所有乘法都在模 256 下进行。
由于将关键词转换为数字密钥将由计算机而不是人类操作员完成,因此可以使用任意复杂的计算。我建议使用二次函数而不是线性函数,以使对手在获得一些消息的明文后更难推断关键词。例如,如果 N[i]是数字密钥的项,K[i]是关键词中字符的数字值,则一个合适的函数可能是

当下标超过关键词的长度时会循环。例如,如果关键词有 10 个字符,则 K[11]会循环到 K[1],K[12]会循环到 K[2],依此类推。
函数 K[i]K[i+1]+K[i+2]K[i+3]的强度不会那么强。如果关键词的长度为 L,则只会有 L 个不同的二次项。艾米莉可以将这些视为 L 个变量,并解出一组 L 个线性方程以找到 L 个乘积 K[1]K[2],K[2]K[3],K[3]K[4],... K[L]K[1]的值。然后很容易找到各个 K[i]的值。*
在本书中,我展示了字母表与简单关键词混合在一起,这样您可以一目了然地看到它们是如何形成的,例如,字母表
样本 BCDFGHIJKNOQRTUVWXYZ
这非常薄弱。实践中不要这样做。我在这里这样做是为了帮助读者。由于您不希望帮助您的对手,始终使用混合良好的字母表,使用列混合、SkipMix 或其他强大的混合功能。有关其他方法,请参见第 12.3.8 节。
5.3 代号书
从 15 世纪到 18 世纪,替代密码的国王是代号书,被国王、教皇、外交官和间谍们广泛使用。每个代号书都有数百甚至数千个项目的列表,单个字母、数字、双字母、音节、单词和名称,为每个提供多达 25 个替代品。代号书更像是代码而不是密码,因此不在本书的范围之内。
5.4 多字母替换
解决简单替换的技术涉及字母频率和字母接触。如果要设计一个密码来抵御这种攻击,一个好的起点是破坏字母频率和字母接触。
假设不是使用相同的字母表对每个字母进行加密,而是使用两个不同的字母表。使用第一个字母表对奇数位置的字母进行加密,并使用第二个字母表对偶数位置的字母进行加密。也就是说,第一个字母表将加密消息中的第一个、第三、第五...个字母,而第二个字母表用于加密第二、第四、第六...个字母。
现在,密文字母的频率一半来自第一个字母表,一半来自第二个字母表。它们是两组频率的平均值。一个密文字母只有在它同时代表两个字母表中的高频字母时才会有高频率。例如,密文K可能代表第一个字母表中的 E,代表第二个字母表中的 A,因此其频率将介于正常文本中 E 的频率和 A 的频率之间。
相反,密文中的一个字母只有在它同时代表两个字母表中的低频字母时才会有低频率,比如第一个字母表中的 K 和第二个字母表中的 V。因此,密文中的高频字母和低频字母会比正常文本少。如果你制作一个字母频率的柱状图,或者直方图,峰值会更低,谷值会更浅。因此,使用两个字母表会使频率计数变得更平坦。
联系频率也会发生同样的情况。任何常见的二字母组合,比如 TH,大约一半时间会在消息中的奇数位置开始,另一半时间会在偶数位置开始。一半时间,T 会与第一个字母表一起加密,而 H 会与第二个字母表一起加密,另一半时间则相反。因此,联系频率也会变得更平坦。
使用的字母表越多,频率就变得越平坦。实际上,从大约美国内战到第一次世界大战期间,使用大约 20 个字母表是很典型的。有一个统计测试可以测量字母频率的平坦度,并使用它来估计字母表的数量,但它不太准确,特别是对于超过 10 个字母表的情况。更好的方法在 5.6 和 5.7 节中描述。
让我们来看看多表密码的历史发展。多表密码的早期形式由利昂·巴蒂斯塔·阿尔贝蒂(Leon Battista Alberti)于 1467 年和约翰内斯·特里西米乌斯(Johannes Trithemius)于 1499 年开发(但直到 1606 年才发表)。多表密码在 1553 年出版的La cifra del Sig. Giovan Battista Belaso一书中开始采用现代形式。
5.5 贝拉索密码
由乔凡·巴蒂斯塔·贝拉索(Giovan Battista Belaso)于 1553 年发明的贝拉索密码使用了 26 个不同的字母表,每个字母表只是标准字母表移位了一定数量的位置。这 26 个密码字母表可以显示为一个表格,其中每个水平行包含一个移位后的字母表,就像这样:

每行的第一个字母标识字母表,所以顶行是 A 字母表,第二行是 B 字母表,依此类推。Belaso 是第一个使用密钥选择消息中哪个字母使用哪个字母表的人。(相比之下,Argenti 家族使用关键字来混合字母表。)Belaso 会水平书写消息。在明文字母的上方,他会重复写入所需次数的密钥。要加密一个字母,他会在表格的顶行找到该字母,使用密钥字母选择表格的行,并将明文字母替换为所选行中直接位于它下面的密文字母。以下是如何使用密钥字母 C 对明文字母 S 进行加密的示例:

我们在表格的顶行找到了字母 S。它的密钥是 C,因此使用表格的第三行进行加密。在第三行,直接在 S 下面,我们找到了字母 U。所以 S 被替换为U。
使用前述表格,使用密钥 CAB 对单词 SAMPLE 进行加密,S 被替换为U。

消息中的下一个字母是 A,使用 A 作为密钥,所以 A 使用顶行进行加密。它被加密成A。样本中的 M 使用密钥 B,它使用第二行加密,变成了N,依此类推。最终的密文是UANRLF。
与使用表格不同,可以使用St. Cyr slide进行加密,该幻灯片以法国圣西尔军校命名。幻灯片在 M 位置显示。

你可以用木头、硬纸板或塑料制作自己的幻灯片。顶部的双宽行固定在原位,而单宽底行滑动。橡皮筋可以使其保持紧绷并处于正确位置。两个字母表中的一个或两个都可以混合。
Belaso 密码是对称的,因为使用密钥 K 加密字母 X 与使用密钥 X 加密字母 K 完全相同。基于将密钥添加到明文或使用异或运算密钥和明文的密码在这个意义上倾向于是对称的。
由于我无法理解的原因,Belaso 密码现在被称为Vigenère Cipher,而由 Blaise de Vigenère 发明的密码,描述在 5.8.2 节中,现在称为Autokey密码。为了给予应有的认可,我将继续称由 Belaso 发明,使用标准字母表的密码为 Belaso 密码。使用混合字母表的密码我将称之为 Vigenère 密码。我将由 Vigenère 发明的自密钥密码称为Vigenère Autokey。
将 Belaso 密码归因于维吉尼亚密码是斯蒂格勒命名法则的一个例子,斯蒂芬·M·斯蒂格勒认为,没有重要的科学发现是以其发现者命名的。一些密码学的例子包括由查尔斯·韦斯顿发明的 Playfair 密码和由阿尔弗雷德·维尔发明的摩尔斯电码。斯蒂格勒法则本身是由罗伯特·K·默顿提出的,他将其命名为马太效应,以纪念圣马太。
5.6 卡西斯基方法
300 多年来,Belaso 密码被认为是无法破解的。法国人称之为Le Chiffre Indéchiffrable,即无法破译的密码。转折点出现在 1863 年,当时普鲁士步兵军官弗里德里希·W·卡西斯基少校出版了一本详细介绍如何确定多表密码周期的书。这就是现在所称的卡西斯基方法或卡西斯基测试。有证据表明查尔斯·巴贝奇可能在 1846 年使用了这种方法,但没有公开发表。丹麦技术大学的奥勒·伊曼纽尔·弗兰克森,他对巴贝奇及其差分机写了大量文章,写了一本名为巴贝奇先生的秘密的书,提出了这一说法。
这个想法是在密文中寻找重复的字母序列。一些序列可能是偶然发生的,尤其是双字母组,但大多数重复序列将是由明文中相同字母被密钥的相同部分加密产生的。重复序列越长,发生偶然性的概率就越低。如果同一密钥部分用于加密两个重复的字母序列,那么它们之间的距离必须是密钥长度的倍数。距离是从一个出现的第一个字符到另一个出现的第一个字符的距离。考虑使用关键词 EXAMPLE 的密码片段。

密文三字母组PTR出现了 3 次,分别在位置 5、12 和 33。所有这三次出现都是由明文 AIN 用密钥字符 PLE 加密产生的。也就是说,它们都是由相同的明文三字母组用密钥的相同部分加密产生的。
明文三字母组 AIN,从位置 21 开始,产生了不同的密文三字母组EMK,因为它是由不同部分的密钥 EEX 加密的。同样,明文三字母组 THE,在位置 1 和 29 出现,以及明文三字母组 INS,在位置 8 和 13 出现,不会产生重复的密文三字母组,因为它们是用密钥的不同部分加密的。
在这个片段中,重复的三字母组之间的距离为 12-5 = 7,33-5 = 28 和 33-12 = 21。这些距离,7、21 和 28,都是 7 的倍数,而 7 是关键词 EXAMPLE 的长度。卡西斯基展示了如何利用这些重复来揭示加密的周期。
让我们看另一个例子,一个密码。

这是一段普通英语文本的贝拉索加密。在搜索重复的字母序列时,我们发现EK位于位置 10、64 和 90,RYR位于位置 17 和 53,等等。重复字母序列的完整列表是:

我们立即注意到两个重复的四元组YHCI和YXYR。重复的四元组几乎不会出现偶然。两个YHCI出现之间的距离是 79-43 = 36,而两个YXYR出现之间的距离是 69-57 = 12。距离 12 和 36 暗示着密钥长度为 4、6 或 12。我们可以通过查看一些其他重复序列来缩小范围。
RYR的距离为 36,ZHZ的距离为 6。另外两个重复的三元组HCI和XYR只是两个重复的四元组YHCI和YXYR的一部分,所以它们不提供额外的信息。这个密码的最可能周期是 6。
好吧,这太容易了。让我们看看在更困难的情况下会发生什么。其他书籍推荐的一种方法是取所有重复序列之间的距离,并找出它们的所有因数。他们声称,最频繁的因子将是周期。例如,如果距离是 36,那么因子是 1、2、3、4、6、9、12、18 和 36。这可能会以几种方式误导你。
首先,你可能会错误地得出周期是其实际值的两倍。这是因为大约一半的距离仅仅是偶然的。有效距离的一半,即由重复的明文序列引起的距离,将是周期的偶数倍。对于某些消息来说,这些周期的偶数倍将超过那些周期的奇数倍的距离。同样,一半的偶然重复的密文序列将有偶数的距离。可能会出现许多偶然的距离。同样,1/3 的距离会偶然成为 3 的倍数。
当你计算距离的因数数量时,你应该将因子 2 出现的次数减少 1/2,将因子 3 出现的次数减少 1/3,依此类推。这样会给你一个更准确的比较。例如,如果距离 3 出现了 6 次,那么将其减少 1/3 到 4 次,因为这 6 次中有 2 次很可能是纯粹的偶然。
第二,当重复的序列出现多次时,这些重复之间的距离可能会误导人。如果有 N 个重复,则对这些重复的成对数量为 N(N-1)/2。在示例密文中,有 4 个YR的出现,因此有 6 对,即 4×3/2 对。因此,有 6 个成对的距离,54-18 = 36,59-18 = 41,71-18 = 53,59-54 = 5,71-54 = 17 和 71-59 = 12。这些中的哪一个,如果有的话,是周期的倍数?假设密文XYZ出现了 5 次,其中有 3 次重复是由相同的明文造成的。将会有 10 个距离,其中只有 3 个是由重复的明文造成的,而其他 7 个是虚假的。
你不想因为无法区分有效重复和偶然重复而将其抛弃。你可以做以下事情。假设你有一个周期候选者。例如,假设你怀疑周期是 6。将重复序列出现的位置减去 6 的模数。(还记得模数算术吗?如果不记得,再看一下第 3.5 节。)
让我们尝试一下模数法。再次看看YR的 4 次出现,并将它们的位置减去 5、减去 6 和减去 7,看看会发生什么。

所有 4 个模 7 余数都不同。如果周期是 7,那么YR的所有重复都是偶然的。模 5 余数只有 2 个相等。如果周期是 5,那么 4 次出现中只有 2 次来自重复的明文。但是如果周期是 6,那么我们现在看到YR的 4 次出现来自明文中的 2 个不同的重复双字母组,一个双字母组在明文的位置 18 和 54 处,距离为 36,另一个双字母组在明文的位置 59 和 71 处,距离为 12。
那是怎么发生的?回顾一下重复序列的列表。你可以看到重复的双字母组YR在重复的三字母组RYR和重复的四字母组YXYR中出现。每个重复都贡献了一个重复。
让我们看看第二种确定多表密码周期的方法。如果重复序列的证据不足以得出结论,那么有备用计划是很好的。
5.7 巧合指数
巧合指数由美国密码分析专家威廉·F·弗里德曼于 1922 年发明。这个想法非常简单,但其重要性深远。想象一下,使用多表密码编写了两条消息,但使用了不同的密钥,可能还有不同的周期。如果逐字比较两个密文,两个对应字母相同的概率是 26 分之 1,约为 0.0385。如果两条消息都是 52 个字符长,你期望有 52/26=2 对相应字母相等。在这里,我使用密钥分别为火星和金星的 Belaso 密码编写了 52 字母的明文“春日少年的幻想变成了棒球”。两个相同的字母已经被突出显示。(两对相同字母都是 F 纯属偶然。)

现在想象一下两条消息被同一个密钥加密。每对相应的字母都被相同的密钥字符加密,所以如果明文字母相同,那么密文字母也将相同。A 的频率约为 0.08,所以明文字母都是 A 的概率为 0.08²,约为 0.0064。它们都是 B 的概率约为 0.015² = 0.000225,依此类推通过字母表。所有 26 个字母的总和约为 0.0645 到 0.0675,约为 1/15,取决于你使用的字母频率表。当使用相同密钥时,两个相应的密码文字母相等的机会大约是 1/15,比不同密钥时的 1/26 机会高出约 73%。
这个事实可以被利用来确定多表密码的密钥长度。让我们给密文中的字符编号为 C[1]、C[2]、C[3],...,并且让密钥的长度为 L。我们可以将密文中的字符与同一字符移动了一定数量的位置后的字符进行比较,比如移动了 S 个位置。也就是说,我们将 C[1] 与 C[1+S]、C[2] 与 C[2+S]、C[3] 与 C[3+S] 进行比较,依此类推。
当移位 S 是 L 的倍数时,对于每个位置 i,C[i] 就会被与 C[i+S] 相同的字母表进行加密,因此两个相应的密码文字符相等的机会是 1/15。如果移位不是 L 的倍数,则相应的字符将不会被相同的字母表进行加密,它们相等的机会只有 1/26。当 S = L,S = 2L 时,相等字符的数量应该最多。尝试几种不同的移位应该能够清晰地显示这种模式。产生最多匹配的移位通常会是周期的倍数。
尝试许多不同的移位听起来像是计算机的工作,但实际上可以手动完成而不需要太多的努力。将密码文写在两张长条纸上。然后将一条纸滑动到另一条上,并计算每次移位时相等字符的数量。你需要均匀地间隔字母以便正确对齐。这很容易通过使用格子纸或者在写字时在每条纸旁边放置尺子来实现。

相关性指数还有另一种用途,对于密码分析师来说非常有价值。它可以检测出两条消息是否使用相同的密钥进行了加密。想象一下,艾米莉正在使用一个机器密码,它生成一个具有非常长周期的多表密码,比如说 100,000。作为对比,德国军队在第二次世界大战中使用的恩尼格玛机的周期是 26×25×26 = 16,900。假设你有数千条拦截到的消息。每条消息都使用了这个长密钥的一部分进行了加密。将每条消息与其他消息进行比较,并使用相关性指数和重复的密码文序列,你可以检测出被同一密钥部分加密的不同消息段落。
当你找到足够多重叠的密钥片段时,你可以开始将这些片段拼接在一起,以获得更长的片段。一旦找到足够多使用相同密钥片段加密的消息,你就可以开始通过通常的方法解读这些消息,比如字母频率、字母组合频率、识别常见词等。
5.8 再次关于巧合指数
还有另一种估算多表密码周期的方法,也称为巧合指数,同样由威廉·F·弗里德曼提出。这种方法计算了当有 2 个字母表、3 个字母表等时,两个字母相等的概率。这些概率提前计算并保存在表中。其思想是计算给定消息的相同统计数据,并将该数字与表格进行比较。最接近的匹配应该是密码的周期。在实践中,这种方法通常很接近,但通常会偏离 1、2 或 3。当周期超过 10 时,该方法无效。这种方法不比随机猜测好多少,因此没有必要解释细节。
Belaso 和 Vigenère 密码在 1880 年代仍然被广泛使用。随着 Kasiski 方法的知名度逐渐增加,它们的使用减少了,并且在巧合指数发布后基本消失了。然而,直到今天,它仍然是最受欢迎的业余密码之一。有好几次,当我告诉人们我正在写一本关于密码学的书时,他们会告诉我他们知道一种无法破解的密码。这总是指 Belaso 密码,他们称之为 Vigenère。然后我不得不证明它是可以被破解的,通过解读他们编造的密码。这些密码被搞得一团糟,以至于我不得不创建一个网页 mastersoftware.biz/vigenere.htm 来确保密码的正确性。
5.9 解密多表密码
一旦你使用 Kasiski 方法或巧合指数法找到周期,下一步就是解读各个字母。首先让我们看一下最简单的情况,即 Belaso 密码。
5.9.1 解密 Belaso 密码
使用 Belaso 密码,所有替换字母表都只是标准字母表按一定数量的位移。确定这个数量,你就解开了密码。第一步是将使用每个密钥字母加密的字符分开。让我们再次看一下第 5.5 节中的示例。由于我们已经确定周期是 6,让我们将密文写成 6 个一组。

这些组中的每个字母的第一个字母都已经用密钥的第一个字母加密,每个组中的第二个字母都由密钥的第二个字母加密,依此类推。如果我们将密文垂直地写在 6 列中,就像这样

那么第一列字母将用密钥的第一个字母加密,第二列字母将用第二个密钥字母加密,依此类推。
分别考虑每个字母列。每列都将具有正常的英文字母频率,但根据其密钥字母进行了偏移。如果我们能够确定偏移量,那么我们就解密了密码。我将描述两种方法,一种是手工解决方案,一种是计算机解决方案。我们先看看纸和铅笔的方法。
对于每一列,我们可以进行频率统计。这将给我们 26 个数字。对于纸和铅笔解决方案,最好将频率显示为直方图(条形图)。密文的第一列直方图将是

只有 18 个字母,这相当稀疏,但已足够。让我们将其与标准英文字母频率的直方图进行比较,接下来显示,并尝试找出偏移量。

这个频率分布的一些视觉特征是(1)E 是远远最高的峰值;(2)有三个均匀间隔为 4 列的峰,即 A,E,I,其中 I 有伴随 H;(3)在 N,O 有双峰;(4)在 R,S,T 有三重峰。
让我们尝试将这个直方图与密文直方图匹配。我们首先寻找一个可能代表 E 的高峰。有两个高峰,R 和 Y,分别对应密钥字母 N 和 U。也就是说,如果 E 被 N 加密,则结果是 R,如果 E 被 U 加密,则结果是 Y。
接下来,让我们寻找间隔为 4 个空格的 3 个峰。有两个候选者,G,K,O 和 N,R,V,分别对应密钥字母 G 和 N。双峰呢?可能的候选者是 N,O 和 Y,Z,分别对应密钥字母 A 和 L。三重峰呢?只有一个选择,X,Y,Z 的三重峰。这对应于密钥字母 G。
第一列最可能的密钥是 G,它产生A,E,I峰和R,S,T三重峰。第二可能的密钥是 N,它使得 E 成为最常见的字母,并且有N,O双峰。
让我们把注意力转向密文的第二列。字母频率直方图是

这次密文字母 S 引起了我们的注意。如果 S 代表明文 E,则密钥必须是 O。让我们通过比较密文直方图和偏移字母表来检查这一点。

你可以看到密文中所有高频字母,即 C,G,H 和 S,分别对应于高频明文字母,即 O,S,T 和 E。这是一个很好的匹配,第二个密钥字母很可能是 O。关键词以 GO 开始。
另外 4 个关键字母的确定方式相同。关键词是 GOVERN,明文是 THE LEGISLATURE SHALL BE DIVIDED INTO TWO CHAMBERS THE UPPER CALLED THE SENATE AND THE LOWER IS THE HOUSE OF REPRESENTATIVES。
这就是手动方法:通过使用直方图使频率分布可视化,然后通过目视匹配分布。对于计算机解决方案,我们需要一种数值方法来目测分布以找到匹配项。在每本讨论多字母密码的书籍中都可以找到的标准方法是使用相关系数,具体来说是 Pearson 积差相关系数,以 Karl Pearson,现代统计学的创始人命名。
如果你懂统计学,这会很熟悉。毫无疑问,你已经有一个带有此功能的统计软件包。好好使用它。对于其他人,我将向你展示一种更简单、更快速——而且准确无误的方法。
当我们通过目视将两个频率分布进行匹配时,我们试图将一个直方图中最高的峰与另一个直方图中最高的峰进行匹配。如果我们将它们的高度相乘,我们试图获得最大的乘积。如果你沿着字母表向下走,并添加 26 个乘积,那么当高峰与另一个高峰对齐时,总和将最高,当最高峰与最低谷对齐时,总和将最低。
这就是想法。尝试 26 种可能的移位。将密文的字母频率与标准英语的移位频率对齐,并加总 26 个乘积。最高总和将指示最有可能的移位。这告诉你最可能的关键字母。第二高的总和是第二可能的移位,依此类推。我称这种技术为Tall Peaks方法。
Belaso 密码评级为 Two。
5.9.2 解密 Vigenère 密码
在 Belaso 之后大约 30 年,Blaise de Vigenère 对 Belaso 密码进行了两项改进。第一个是在表格的外部添加指南。这样做的效果是产生了一个混合字母表,而不需要混合表格。以下是一个示例,使用水平指南中的关键词 FIRST LOVE,以及垂直指南中的关键词 YOUTH。第二项改进,自动关键字,请参阅第 5.10 节。

要使用关键字 U 加密字母 B,找到左边或右边的行中的关键字 U,在列的顶部或底部的字母指南中找到明文字母 B。密文字母是 U 行和 B 列中的字母,即M。要解密,使用关键字找到行,找到该行上的密文字母,并从顶部或底部的字母指南中获取明文。
如果你是手动加密,我建议每 4 或 5 行和列绘制水平和垂直规则。或者,使用透明的塑料 L 型工具精确找到交点。
这是使用这种形式的维吉尼亚密码加密的样本消息。其周期为 5。

这种密码有一个严重的弱点。由于表中的每一行都是标准字母表移位了一些位置,因此每个密码字母表将与所有其他密码字母表移位了一些位置相同。您无法将密码字母表与标准字母表有用地比较,因为它们是按混合顺序排列的,但是,您可以通过直接比较密码字母表或使用 Tall Peaks 方法来确定移位。
下图显示了 5 个密码字母表的直方图,将它们移位以匹配它们的峰值和谷值。第一列(阴影)中的所有密文字母代表相同的明文字母。这意味着第一个字母表中的 S,第二个字母表中的 C 和第四个字母表中的 L 都代表相同的字母。将所有这些替换为 A。第二列中没有字母。在第三列中,第三个字母表中的 M 和第五个字母表中的 T 代表相同的明文字母。将所有这些替换为 C,依此类推。第 26 列中的密文字母将全部替换为 Z。

这将把密文转换为一个简单的替换,现在可以使用第 5.1 节的方法解决。维吉尼亚密码的评级为 Two。
5.9.3 解决一般多表密码
也可以使用表格来完成一般的多表密码。表格的行可以根据任何方案混合,彼此独立地进行。值得注意的是,行数不必与列数相同。对于计算机密码,将表格宽度设置为 256 个字符,深度设置为 512 行,以便每个密文字符在每列中出现两次。这将使已获得密文及其相应明文的对手难以确定密钥。以下是 100 行表格的部分示例:

该表将与数值键一起使用,其中 2 位小数将用于选择用于加密的行。20 位数字键将产生周期为 10 的多表密码。
解决一般多表密码与解决单表密码非常相似。您首先进行频率统计,并为每一列制作一个接触表。在这种情况下,列 C 的联系将在 C-1 和 C+1 列中,必要时从最右边的列绕到第一列。每列中的每个字母的出现次数会减少,因此您需要从较少的数据中进行推断。这需要很多经验来自的灵感猜测。
让我们从这个多表密码开始。

快速检查此密文显示两个长重复序列,位置分别为 13 和 93 的YSUZONSOO,以及位置分别为 39 和 124 的SNZYYZK。在这两种情况下,两次出现之间的距离是 5 的倍数,证实了周期为 5。这些长重复可能代表常见的单词或短语,或者是与消息主题相关的单词。
每个 5 个关键字母的联系图表如下。为了更容易解释推断,我将使用数字标记每个密文字母,指定其字母编号。所以C1表示字母C在字母表 1 中的密文字母(即使用密钥的第一个字母进行加密),H3表示字母H在字母表 3 中的密文字母(使用密钥的第三个字母),依此类推。
请记住,两边有许多不同接触的字母倾向于是元音,而具有较少不同接触的字母倾向于是辅音。

根据这些联系,我们可以暂时将G2,K2,O2,P2,H3,K5识别为元音,将R1,Z1,K3,N3,D4,S4,O5识别为辅音。基于其高频率,S4可能代表明文 T。
您的操作步骤与简单替换一样。您更新联系图表以显示已被识别为元音和辅音的字母,并且还将带有标记的元音和辅音的密文写下。您使用这个来完善和修复元音/辅音的识别,并识别单个字母。
我不会重复 5.1 节中所采取的所有步骤。逻辑是相同的,但增量步骤更小,更多,需要更多的回溯。一般的多字母密码评定为三。
5.10 自动关键字
您可能还记得我在 5.9.2 节中提到维吉尼亚对贝拉索密码进行了两项改进。第一个改进是将指南放在表的边缘以产生混合字母表。第二个改进是自动关键字。
自动关键字使用消息的明文作为密钥来加密消息的其余部分。早期版本是由意大利医生/数学家/占星家吉罗拉莫·卡尔达诺发明的。在卡尔达诺的系统中,每个字母都使用自身作为密钥进行加密。这仅在您拥有具有奇数字母的字母表时才有效。使用 26 个字母的英文字母表,A 会产生一个A,而 N 也会产生一个A,所以受信者必须弄清楚哪一个是指的。即使使用了奇数大小的字母表,卡尔达诺自动关键字也仅仅产生了简单的替换。
Vigenère 通过使用滞后改进了 Cardano 方法。Vigenère 使用一个字母密钥来加密第一个字母,使用第一个明文字母来加密第二个字母,使用第二个明文字母来加密第三个字母,依此类推。在现代实践中,使用关键词来加密第一组字母,然后使用该组明文字母来加密第二组字母,依此类推。这个例子使用了关键词 SAMPLE 和 Belaso 表,即未混合的字母表。

使用未混合的字母表,解密是直接的。在第 5.7 节中描述的重合指数可以用来确定关键词的长度。当密文偏移了密钥长度的倍数时,指数通常会显著增加,就像这样:

假设你已经发现关键词有 6 个字母。尝试字母表中的每个字母作为密钥的第一个字母。从 A 开始。由于第一个密文字母是 L,第一个明文字母也必须是 L。这也将是消息第 7 个字母的密钥。由于第 7 个密文字母是 X,第 7 个明文字母必须是 M。
按照这种方式进行,对于第一个密钥字母的每个猜测都会给出明文的第 1、7、13、19、25 和 31 个字符。也就是说,它会给出每 6 个明文字母。有 26 组字母,每个可能的密钥字母对应一组。这些 6 个字母的一些组会有正常的英文字母频率,一些则不太可能。对第二个密钥字母重复这个过程。对于第二个密钥字母的每个猜测都会给出明文的第 2、8、14、20、26 和 32 个字符。
现在,取出第 1、7、13 等 5 个字母的最有可能的选择,并将它们与第 2、8、14 等 5 个字母的最有可能的选择配对。这将给出 25 组双字母组合。其中一些可能性很高,一些则不太可能。取出其中最合理的 10 组,并将它们与第三个密钥字母的 5 个最可能的选择配对。这将给出 50 组三字母组合。选择其中最合理的 10 组,并将它们与第四个密钥字母的 5 个最佳选择配对。到这一步,一些明文单词将开始出现,正确的密钥字母选择将变得明显。
如果你是通过计算机进行这个过程,请跳过双字母组合。直接尝试前 3 个密钥字母的所有 26³种组合,然后直接进入三字母组合。然后对第 2、3 和 4 个密钥字母重复这个过程。前 3 个密钥字母和后 3 个密钥字母的最可能选择会有重叠。第三组和第四组密钥字母也会发生同样的情况。这将迅速缩小到正确的关键词。
使用标准字母表的 Vigenère 自动密钥被评为 Three。
5.11 运行密钥
运行密钥类似于自动密钥,但是不是使用一个简短的关键词或短语,而是使用一个密钥文本,它可能和消息本身一样长。运行密钥从未在实践中被广泛使用,因为它要求双方都完全正确地获得密钥文本。如果一方记住或复制了密钥为“MINE EYES HAVE SEEN THE GLORY OF THE COMING OF THE LORD”,而另一方记住了“MY EYES HAVE SEEN THE GLORY OF THE COMING OF THE LORD”,那么他们将无法进行通信。解决这个问题的一种方法是使用双方都有的印刷书籍中的密钥文本,尽管他们必须随身携带这本书。对于计算机通信来说,这不是问题,因为计算机可以存储成千上万本书籍。
假设使用标准的英文字母表构成的贝拉索表,运行密钥的解密方法虽然直截了当,但也很费力。有一种技巧,适用于自动密钥和运行密钥,就是猜测文本中可能出现的一个合适的单词。这个单词可能出现在密钥文本中,也可能出现在明文中。密码学家稍后需要解开这个谜。这个可能的单词,或者暗语,可能是一个常见的英文单词,比如 THE 或 AND,也可能是与疑似主题相关的词。例如,如果消息涉及贸易谈判,那么可能的单词可能是 TARIFF、SHIPPING、REPRESENTATIVE、BARGAINING 等。
思路是在消息中尝试可能的单词的所有可能位置。这被称为词拖拽。知道明文单词和相应的密文可以给你一个密钥的片段。如果单词放置正确,那么这个片段看起来就像正常的英语。可能的单词越长,你就越有信心它是正确的。一旦找到一个单词,你就尝试猜测字母,然后是文本中在它之前或之后的单词,以扩大漏洞。
还有一种技术,适用于计算机求解。这需要一个新的数学概念,叫做条件概率。这是事件 A 在事件 B 发生时发生的概率。单个事件 A 的概率用 P(A)表示,给定事件 B 发生的条件下事件 A 的条件概率用 P(A|B)表示。如果 AB 表示事件“A 和 B”,那么给定 B 的条件下 A 的条件概率是 P(A|B) = P(AB)/P(B)。这意味着 P(AB) = P(A|B)P(B)。
举个例子来帮助澄清这个问题。如果你掷两个标准骰子,掷出 12 的概率是 1/36。然而,如果你掷第一个骰子,结果是 6,那么掷出 12 的机会变成了 1/6。令 A 表示“掷出 12”,B 表示“第一次掷出 6”。那么 P(A) = 1/36,P(B) = 1/6。P(AB) 意味着第一次掷出 6 时掷出 12。P(AB) 也是 1/36,因为如果你掷出 12,第一次掷出的一定是 6。使用条件概率符号,P(A|B) = P(AB)/P(B) = (1/36)/(1/6) = 1/6。因此,当第一次掷出 6 时掷出 12 的条件概率是 1/6。
让我们使用条件概率来解密一个流动密钥密码。所需的工具是单个字母、二字母和三字母概率表。这些可以通过统计大量文本中的字母、二字母和三字母来编制。你可以在古腾堡计划网站 www.gutenberg.org 上找到许多这样的文本。选择明文选项。你也可以在互联网上找到一些统计表。
你需要为每个可能的二字母和三字母分配一个概率,而不仅仅是在那个文本中找到的。对于二字母组,这是显而易见的。如果 AB 是一个没有出现在计数中的二字母组,你可以设置 P(AB) = P(A)P(B),然而,我建议将其设置得更低,简单地因为 AB 从未被发现。我使用 P(AB) = P(A)P(B)/3。一旦你有了完整的二字母组概率集合,你可以通过将 P(ABC) 设置为 P(A)P(BC) 和 P(AB)P(C) 中较大的一个来扩展到三字母组。同样,我建议将它们设置得更低,因为三字母组 ABC 从未出现过。例如,将 P(ABC) 设置为 P(A)P(BC)/3 和 P(AB)P(C)/3 中较大的一个。这些人为的概率意味着所有二字母组和所有三字母组的总概率都大于 1。数学上来说这是无意义的,但它没有实际影响。
现在我们有了必要的工具,可以解决一个流动密钥密码。选择消息中的一个起始位置,比如 s,并尝试位置为 s,s+1,s+2 的所有可能的关键三字母组。查看相应的明文三字母组。将关键三字母组和文本三字母组的概率相乘以获得该位置的概率。保留这些位置中的前 10000 个,并丢弃其余的。对于每个选择的三字母组,尝试 s+3 位置的所有可能的关键字母,并查看相应的明文字母是什么。假设关键三字母组是 JKL,下一个关键字母是 M,相应的明文四字母组是 ABCD。您可以使用条件概率 P(KLM|KL) 来估计关键四字母组 JKLM 的概率,这是 M 跟在 KL 后面的概率。这是根据三字母组的概率计算出来的,如 P(KLM)/P(KL),这是三字母组 KLM 的概率除以二字母组 KL 的概率。因此,四字母组的概率被估计为 P(JKL)P(KLM|KL)。这对于关键四字母组和明文四字母组都是如此。
通过将关键四字母组和明文四字母组的概率相乘来估计这个位置的概率。同样,保留前 10,000 个,丢弃其余的。一直持续到解决方案变得明显为止。所有这些都可以由计算机完成,无需任何人的监督。
使用标准字母表的维吉尼亚运行密钥评为四级。
*5.12 模拟转子机
多表密码的必不可少之物是从 20 世纪 20 年代开始使用的电机械转子机。这些机器的周期可以达到数十亿或数万亿,或者如果转子的运动取决于明文或密文字符,则根本没有周期。从大约 1915 年到二战后,至少生产了 70 种不同类型的机器。有几个网站有这些机器的图片和描述。
每台机器都有一个或多个转子,通常为 3 到 6 个,但有时多达 10 个。每个转子执行简单的替换。在每个字母被加密后,一些转子会转动,以便下一个字母使用不同的替换。各种齿轮、凸缘、凸轮、杠杆和棘轮的系统使得转子以不可预测的方式转动。也就是说,对于你的对手来说是不可预测的。

如果我们用数字替换字母表中的字母,描述转子机器会更容易。对于机械转子机器,每个转子有 26 个位置对应于字母表的 26 个字母,我们用数字代替 A 为 0,B 为 1,C 为 2,直到 Z,其被 25 代替。换句话说,我们使用经典的数字系统减去 1。对于计算机模拟,我们使用 8 位字节,并用一些标准化系统(如 UTF-8 编码)中的数字代码替换字符。在这个系统中,A 是 65,B 是 66,C 是 67,直到 Z,其为 90。其他字符,如小写字母、数字和标点符号,也被它们的 UTF-8 字符代码替换。
既然我们在处理数字,我们可以对它们进行算术运算,例如加法和取模 26 或 256 的余数,视情况而定。如果你想复习模数算术,请参考第 3.6 节。
生产了多达 16 个转子的密码机。这是俄罗斯制造的菲阿尔卡机器的 10 个转子组件,它从 1956 年直到 1990 年代被华沙条约国家使用。照片由保罗·哈德森提供,并根据 CC BY 2.0 许可证授权。

5.12.1 单转子机
让我们从一个单独的机械转子开始。转子执行简单的替换,因此可以通过替换表 S 进行模拟。表 S 只是一个乱序的字母表,就像一个表的一行。列表中的条目从 0 到 25 编号,对应于字母表的 26 个字母。替换表中的第 N 个条目,表示为 S(N),是字母表的第 N 个字母的替换。因此,S(0) 是 A 的替换,S(1) 是 B 的替换,依此类推。
当转子转动时,它们会改变位置。位置可以用一个数字 P 来表示,它的范围是从 0 到 25。当一个转子转动了 26 个位置时,它会回到起始位置,即位置 0。当转子处于位置 P 时,第 N 个字母的替代是 S(N+P)。因此,当转子处于位置 5 时,S(5) 是 A 的替代,S(6) 是 B 的替代,依此类推。我们理解 N+P 会循环,所以 S(26) 和 S(0) 是相同的,S(27) 和 S(1) 是相同的,依此类推。换句话说,N+P 实际上是 (N+P) mod 26 的简写。
在机械转子机器中,每个字母加密后,转子的转动量不同。这种不规则的运动可以通过使用一个 步数序列 来模拟,比如 (a,b,c,d,e)。在第一个周期,转子向前推进 a 个位置。在第二个周期,它向前推进 b 个位置,依此类推。第六个周期序列重复。因此,如果转子从位置 P 开始,经过一个周期后,它将处于位置 P+a。经过两个周期后,它将处于位置 P+a+b。经过 5 个周期后,它将处于位置 P+a+b+c+d+e。经过 6 个周期后,转子将处于位置 P+2a+b+c+d+e。在机械设备中,每个转子通常只转动几个位置,通常是 0 或 1 个位置,具体取决于特定凸轮的位置是上还是下。在计算机模拟中,我们没有这样的限制。在模拟机械转子时,步数可以是从 0 到 25 个位置,或者使用 8 位字节来表示字符时,可以是从 0 到 255 个位置。
由于我们选择了 5 步的密钥,这台单转子机器将在 5×26 = 130 个周期后重复。当 a+b+c+d+e 是偶数时,机器将在 65 个周期后重复,如果 a+b+c+d+e 是 13 的倍数,机器将在仅 10 个周期后重复。显然,一个转子不能提供太多安全性。单转子机器密码被评为 Three。
5.12.2 三转子机器
让我们来看看如何模拟一种更实用的转子机器。这台机器有 3 个转子,使用 8 位 UTF-8 代码。三个转子需要 3 个替换表,S[1]、S[2] 和 S[3]。当转子处于位置 P[1]、P[2] 和 P[3] 时,字母表的第 N 个字母被加密为 S3+P[2])+P[3])。
每个 3 个替换表都有自己的步骤列表:假设 S[1] 有步骤 (a[1],a[2],a[3],...,a[i]),S[2] 有步骤 (b[1],b[2],b[3],...,b[j]),而 S[3] 有步骤 (c[1],c[2],c[3],...,c[k])。如果每个转子的步数之和是奇数,并且 i、j 和 k 是互质的,那么该机器的周期是 256ijk。例如,如果 i = 10,j = 11,k = 13,则 ijk 为 1430,周期为 1430×256 = 366,080。效果就像是有一个多表代换密码,其表格有 366,080 行,每个周期只使用一次每行。
假设已知三个替换表和步骤序列,例如,假设它们已经在一个大型网络上标准化。一个可能想象的是,艾米丽只需要尝试 256³ = 1.67×10⁷个初始转子设置就能破解每个消息。这可能在当前的个人电脑上只需要几秒钟。这是误导性的。
考虑机器的两种不同状态。两个状态的转子处于相同的位置,但它们处于步进序列的不同部分。从这两个状态开始加密将会产生不同的密码字母序列,因此相同的消息将会被加密成不同的样子。通过穷举搜索来破解此密码将需要尝试所有可能的转子设置和步骤序列中的所有可能位置,总共为 256³×1430,或 2.40×10¹⁰个情况。这仍然可以使用个人电脑来完成,但需要几个小时,而不是几秒钟。
对于已知转子和已知步骤序列,这个三转子密码的等级是 Four。
如果转子和步骤序列是保密的,那么艾米丽必须回到一般多表密码的技术上,即收集大量拦截并将它们匹配起来找出使用相同设置加密的部分。为了区分真实匹配和偶然匹配,需要对长重叠进行重合指数测试(第 5.7 节)。建议至少 200 个字符。匹配应仅尝试长于 200 个字符的消息。对于长度为 L 个字符的消息,其中 L ≥ 200,可匹配位置的数量为 L-199。当所有拦截消息的可匹配位置的组合总数 M 超过√2.40×10¹⁰ = 1.55×10⁵时,可以开始检测文本部分的匹配。
这似乎不算什么,但是检测这些重叠的工作是按 M²量级的。此外,单个重叠远远不够。你需要足够的重叠,以便开始区分高频字母,并将元音与辅音分开。这将需要一台大型机和一些有才华的密码分析员。未知转子和未知步骤序列的三转子机的等级是 Six。
5.12.3 八转子机器
三个转子是一个很好的开始。为了真正提高模拟转子机的强度,让我们将转子的数量从 3 增加到 8。让转子的步数为 11、13、17、19、23、25、27 和 31,按某种顺序,并且使每个转子的步数总和为奇数。这台机器的周期约为 5.69×10¹²。
如果这是一个硬件设备,转子的内部布线和步骤序列可能已经内置。即使是这种情况,也不可能像我们在 3 转子版本中那样匹配消息。这是因为现在有 256⁸ = 1.84×10¹⁹个 8 个转子的可能初始位置。由于周期为 5.69×10¹²,机器的总状态数变为(1.84×10¹⁹)×(5.69×10¹²) = 1.05×10³²。当转子和步进序列无法更改时,这个 8 转子机器被评为九级。
让我们再深入一点。假设我们有 16 个可能的转子供应。对于每个消息,我们以某种顺序选择其中的 8 个转子。有 5.19×10⁸种这样的排列。对于每种排列,有 1.84×10¹⁹个可能的初始转子位置和 5.69×10¹²个步进序列位置,总共有 5.43×10⁴⁰个状态。
即使艾米丽以某种方式知道所有 16 个转子的替换表和步进序列,使用这台机器加密的消息也不可能被破解,即使使用世界上最大最快的超级计算机也不行。(目前世界上最快的超级计算机是 Summit 计算机,最高可达 200 petaflops。)这个 8 转子密码被评为十级。
如果替换表和步进序列的内容保密,或者经常更改,这个具有 8 个可互换转子的转子密码应该在未来 10、20 或甚至 30 年内仍远远超出最大超级计算机的能力范围。
由于这是一个转子机器的软件模拟,转子可以随意更改。可以通过使用密钥来混合每个 8 个转子字母表,为每个消息更换转子,而不是固定的 16 个转子集合。这将大大增加安全性,但需要为每个消息进行单独的设置阶段。中等安全级别是使用 16 个转子集合中的 7 个标准转子,以及为每个消息独立生成字母表的 1 个转子。这将减少 87%的设置时间。
即使这个密码已经获得了十级评价,你可能仍希望加强它。你可能不相信我的评价,或者你认为你的对手拥有惊人的计算能力。一种方法是使用一些转子的输出来修改操作。我建议在加密过程中的中途取第四个转子的输出,并使用该字符来推进第一个转子。可以直接使用字符,也可以对字符进行简单的替换以获得推进第一个转子的位置数。除了消息中的第一个字符外,第一个转子被推进两次,一次来自其步进序列,一次使用第四个转子的反馈。
这种双步进不会影响当前字符的加密。使用这种修改后的设置对下一个消息字符进行加密。在硬件转子机器上实现双步进可能会很困难,但在模拟机器上可以很容易地完成,因为转子是依次模拟的。
顺便说一下,使用第八转子的输出似乎会更强大,但这是不正确的。第八转子的输出是密文字符,这对窃听者是已知的。中间两个转子的输出,即第四和第五转子,对窃听者的获取是最困难的,因此最安全。
第四转子的反馈使得模拟的 8 转子机器是非周期性的。无论发送多少消息,埃米莉都永远找不到具有相同转子设置序列的两条消息。
第六章:对策
本章内容包括
-
双重加密
-
空字符和空位
-
同音字
-
在图像或计算机文件中隐藏消息
总结第 5.9 节,多表密码可以通过两步过程解决。首先,使用 Kasiski 方法或 Coincidence 指数确定周期或密钥长度。这将把密文分成几个较小的文本,每个文本只有一个字母的密钥。其次,使用标准的简单替换密码方法对这些单独的文本进行解密,包括频率和接触。
让我们把它反过来。密码分析者可以采取哪些措施来防止多表密码被这两个步骤破解?我们将看几种对策。
6.1 双重加密
如果一条消息使用一个周期为 P 的多表密码加密,然后使用周期为 Q 的第二个多表密码加密结果中间文本,那么结果等同于一个周期为 P 和 Q 的最小公倍数的多表密码,表示为lcm(P,Q)。也就是说,周期是 P 和 Q 的最小整数倍数。例如,如果 P 为 10,Q 为 11,那么双重加密将具有 110 的周期,但如果 P 为 10,Q 为 12,那么双重加密将具有 60 的周期,因为 60 是 10 和 12 的倍数。
双重加密中的每个个体字母都是第一次和第二次加密中的两个字母的组合,如第 11.7.4 节所述。如果这些是移位标准字母表,那么结果也是移位标准字母表。如果这些是混合字母表,那么结果很可能是更彻底混合的字母表。
尽管双重加密仍然是多表加密,但它可能比单个多表加密更强,因为周期更长,每个密钥字符将加密的字母更少。这种类型的双重加密评为三级。
如果两个多表加密是自动键、流动密钥或一个键,双重加密将是流动密钥加密。然而,密钥不会是英文文本,所以第 5.11 节的单词拖拽技术无法使用。那节的概率技术,尽管如此,可以用于两个流动密钥。
如果加密使用直接字母表,即使用 Belaso 表,那么加密顺序并不重要。用流动密钥 R 加密消息 M,然后用流动密钥 S 重新加密与用流动密钥 S 加密流动密钥 R 以获取新的复合流动密钥 C,然后用该复合流动密钥 C 加密消息 M 是相同的。
通过用一个流动密钥对另一个流动密钥进行加密而派生的密钥并不是随机的。它们具有自己的特征字母频率和接触频率。有常见的序列,比如 THE 被 THE 加密,或者 AND 被 THE 加密。所有这些都可以列成表。如果将长短语(如 UNITED STATES OF AMERICA 或 NEGOTIATING STRATEGY)拖过文本,您可以寻找符合此分布的流动密钥部分。因此,双流动密钥加密可以通过计算机解决。
使用未混合字母表,两个自动密钥和/或流动密钥加密的组合被评为四。使用混合良好的密钥字母表,该组合被评为六。
6.2 空字符
空字符是阻止敌人破译代码的一种历史悠久的方法。它们至少可以追溯到 15 世纪的阿根提家族。空字符是插入到消息中以迷惑敌方密码分析员的无意义字符。它们最常与代码一起使用。对于多表密码,它们可以污染频率计数并破坏卡西斯基或重合指数分析。
空字符可以有几种使用方式。最直接的方法是向字母表中添加一个空字符。这通常表示为一个星号。然后可以将此字符散布到明文中。应该适度使用,以免显眼和明显。约 3%至 6%的空字符是合理的。使用空字符的一个有用方法是将它们插入高频词中以迷惑卡西斯基攻击。这应该是随机的。如果您将每个* THE 更改为 THE,则正在通过提供 4 个字符重复来帮助 Emily。最好一半时间使用 THE,四分之一时间使用 THE,四分之一时间使用 THE。使用THE 或 THE*并不有益,因为 THE 三字母组保持完整。
加密表将变为 27 列宽,并且星号将出现在密文中。您可能会认为这将透露正在使用空字符,但有一种称为三重密码的密码,描述在第 9.9 节中,它利用了一个 27 字符的字母表。Emily 可能会认为您的多表密码是三重密码(不要与约翰·温德姆 1951 年小说《三脚怪植物的末日》中的三条腿怪物植物混淆)。
以这种方式使用空字符相当薄弱。它不会显著改变字母频率,并且不会对卡西斯基或重合指数产生不良影响。该方法被评为三。
使用空字符的第二种方法是在明文中插入一些特定的空字母序列。这些序列需要容易识别。我建议从一小部分中频字母(如 C、D 和 P)形成空序列。双字母组 CC、DD 和 PP 可以用来表示字母 C、D 和 P,这些字母的其他 6 个双字母组合将成为空字符。这种方法也被评为三。
6.3 中断密钥
使用空字符的更强大的方法是将空字符插入到密文中,以打破重复周期。这样做的简单方法首先是以正常方式使用多表密码加密消息。然后每次在密文中发生某些触发事件,例如某个选择的字母或双字母时,在其后插入一个空字符。空字符可以是任何字母,甚至是双字母。触发器的存在标记它为一个空字符。
这种空字符插入类型可能相当复杂。你可以插入一个空字符
-
在密文中每个 W 之后的 4 个字符,例如密文NPGWSOVKLEWPIDF可能变为NPGWSOVTKLEWPIDCF,
-
在密文中每第二个 H 之后,
-
在密文中每个跟随 Q 的第一个 A 之后,
-
第一个 V 之后的 1 个位置,然后下一个 B 之后的 2 个位置,下一个 L 之后的 3 个位置,然后重复 V、B、L、V、B、L、...,
-
在密文中每个双字母之后,或在连续 3 个元音之后,或在字母表中按升序或降序连续 4 个字母之后,
或者这些的组合。唯一的限制是你的想象力。只是不要让它变得太复杂,以至于桑德拉和里瓦无法快速准确地加密和解密。如果桑德拉应该在每第二个 K 之后插入一个空字符,以及每第三个 M 之后,而她错过了一个,或者在第四个 M 之后放置了空字符,那么里瓦可能无法解密消息。
这种插入空字符的方法使用标准字母评为四,使用混合字母评为五,前提是,如常,混合字母保密。
还有几种打破关键周期重复的方法。一种方法是在明文中发生某些触发器时重新启动关键。这比前一种方法更安全,因为触发器在密文中,艾米丽可以看到密文,但看不到明文。另一方面,对于合法的接收者来说更困难。当触发器在密文中时,里瓦只需扫描并通过眼睛删除空字符。当触发器在明文中时,里瓦必须逐个解密字符,注意触发器。
触发器可以类似于刚才提到的密文触发器,只不过在明文中,而不是在密文中。触发器发生后所采取的行动可能是
-
跳过关键中特定数量的字符,或
-
重复关键中特定数量的字符,或
-
从第一个字符重新启动关键,或
-
切换方向,通过关键向后走。
这里是使用关键 SAMPLE 和触发字母 A 的这 4 种类型的关键中断的示例:

这种形式的关键中断使用直接字母评为五,使用混合字母评为六。关键不应该经常重新启动,否则关键的第一个字符将被过度使用,而关键的最后一个字符可能会被忽略。
更强的关键中断形式是使用两个不同长度的密钥。当密钥长度互质时,此密码最强。当触发器发生时,您从一个密钥切换到另一个密钥。当混合字母表混合良好时,此方法评为六。这是一个使用密钥 FIRST 和 SECOND 以及触发器 A 的示例:

此密码会跟踪上次使用的密钥字母。当你切换到另一个字母表时,加密将继续使用密钥的下一个字母。例如,明文 MA 使用密钥字母 FI 进行加密,因此下一个密钥字母是 R。在使用第二个密钥 SECO 加密 RYHA 后,加密将在第一个密钥 RS 的密钥字母中继续。
这样,每个密钥中的所有字母大致相同的次数。
6.4 同音字替换
同音字替换,介绍在 4.2 节中,为了平坦化字母频率,为每个明文字母提供几个替代字。最常见的方法是扩大密文字母表以提供额外的替代字。由于经典的多字母密码使用固定的 26 个字母表,至少对于英语来说,它们通常不使用同音字替换。
对于使用 8 位字节的计算机实现,同音字替换很容易实现。一个字节有 256 个可能的值。26 个大写字母,26 个小写字母,10 个数字,以及可能的 32 个标点符号只使用了 256 个值中的 94 个。如果包括制表符、退格、换行和回车,就有 98 个。这样就留下了 158 个字符,可以用于空字符、双字母组合和三字母组合以及关键中断。
让我们看看如何使用纸和笔以及正常的 26×26 混合表进行同音字替换。如果您将一个字母保留为触发字母,那么该字母的频率将非常高,很容易被发现。同样,使用 2 个触发字母也是可能的。我建议使用 3 个触发字母,每个字母的频率都低于 4%。让我们称这个密码为Trig3。字母 BCDFGJKLMPQUVWXYZ 是合适的。假设您选择了 B、C 和 D。以这 3 个字母开头的双字母组合有 78 个,即 3×26。您不会使用包含高频字母 AEINORST 的双字母组合,因为那会增加它们的频率,这与平坦化字母频率的目标相悖。这样就留下了 54 个可以用作空字符、同音词和关键中断的双字母组合。这里是一组可能的双字母组合:

这里的-代表空字符,所以明文 BD、BL、CC 等都是空的。Codes +1、+2 和+3 是关键中断符,意思是跳过 1 个、跳过 2 个和跳过 3 个关键字母。同音词集包括 6 个双字母组合,AN、ER、IN、ON、RE 和 TH 以及单个字母。
保持平衡很重要。如果你过度使用这些替代字符,那么字母 B、C 和 D 的频率就会过高,很容易被发现作为触发器。如果你使用得太少,那么它们就不会有任何有用的影响。大约 10%是正确的,使用 B、C 和 D 的双字母组合频率大致相等,每个约为 3%。记住,使用这种密码时不能单独使用字母 B、C 和 D,必须使用它们的替代品 DM、CD 和 CG。
如果正确使用,使用混合得很好的键入字母表,Trig3 密码的评级为五。
6.4.1 密码 5858
在转向双字母组合替换之前,让我再介绍一个密码。我称之为Cipher 5858。这是一个使用 5 位字符的计算机密码。五位字符给出 32 个字符的字母表,足够 26 个字母、3 个空字符和 3 个同音字使用。(1)明文被写成一个混合字母的 5 位字符序列。(2)插入空字符和同音字,每个约占明文的 3%,总共占明文的 18%。最好是以随意的方式使用它们,而不是以系统化的方式。(3)明文被填充,使其长度成为 8 的倍数,如果需要,添加一个空字符,并最多添加 4 个随机位。(4)填充后的消息被视为 8 位字节的字符串,并进行混合替换。例如,如果消息包含 80 个 5 位字符,则将按顺序取 400 位,作为 50 个 8 位字节。(5)将消息再次视为 5 位字符的字符串。选择其中的三个字符作为键中断器+1、+2 和+3,就像 Trig3 密码一样。(6)使用一个通用的多表多字母密码和一个混合得很好的 32×32 的 5 位字符表对消息进行加密。(7)5 位字符的字符串然后重新分组成 8 位字节,并进行第二次 8 位替换。
总之,密码 5858 使用 4 个替换步骤,一个初始的 5 位替换,一个 8 位替换,一个带有键中断的 5 位通用多字母替换,以及最后一个 8 位替换。这个密码的评级为七。
6.5 双字母组合和三字母组合替换
防止 Emily 使用字母和联系频率破解您的密码的另一种方法是对双字母组合甚至三字母组合进行替换。最简单的方法是使用一个表格。对于双字母组合,您可以使用一个 26×26 的表格,其中每个条目都是一个双字母组合。以下是这样一个表格的开头:

AA 的替代品将是BL,AB 的替代品将是TC,依此类推。对于三字母组合替换,您可以使用一个小册子,其中包含 26 个这样的表格,每个表格对应三字母组合的第一个字母。
这种替换方法可以单独使用,也可以与另一种方法结合使用,例如多表替换。单独使用时,二元替换评为三,三元替换评为四。二元替换后跟着使用混合良好的秘密字母表的多表替换评为五,三元替换后跟着使用混合良好的秘密字母表的多表替换评为六。
*6.6 在图像中隐藏消息
一个有趣的想法,可以追溯到大约 1999 年,是将消息隐藏在计算机上各种类型的数据文件中。这是隐写术(第 2.2 节)的现代版本。让我们看看其中一种方法,将消息隐藏在位图或 BMP 文件中。位图是以像素为单位存储的图像。最常见的位图格式通过 3 个字节表示每个像素,指定图像上单个点的蓝色、绿色和红色色深度。 (这是微软位图图像标准中的设备无关顺序。如果你记不住顺序,注意蓝色、绿色和红色按字母顺序排列。)例如,0,0,0 表示没有颜色,因此是纯黑色,255,255,255 表示所有 3 种颜色的最大深度,因此是白色,255,0,0 将是纯蓝色。
像素通常用十六进制表示,因此纯蓝色将是 FF0000。在一些计算机语言中,这样写$FF0000 或 X'FF0000'甚至 0xFF0000,因为十进制 255 在十六进制中是 FF。在一些语言中,颜色组件的顺序是相反的。例如,在 HTML 中,纯蓝色将是#0000FF。
整个图像可能包含数百或数千行像素,每行包含数百或数千个像素。一个位图包含 3000 行,每行包含 4000 个像素并不罕见。这样的图像将有 12,000,000 个像素,并且需要 36,000,000 字节的存储空间,再加上 54 字节的头部信息。这就是为什么许多高分辨率图像会迅速填满计算机的内存。
诀窍是使用像素的每个组件中的低阶位来携带一位消息。这可能不会被察觉,因为 FF0000 和 FE0000 甚至 FE0101 之间的差异对肉眼几乎是不可察觉的。在大图像的单个像素中,这将在视觉上是不可察觉的。此外,一半的位不会改变值。在图像中隐藏消息时,关键是传输包含图像的文件时必须完全准确。图像不得放大、缩小、裁剪、旋转、倾斜、压缩或转换为另一种图像格式。
消息可以用任何方法加密。但是,如果 Emily 怀疑你是以这种方式隐藏消息,那么它不会增加任何额外的安全性。你将为每个消息位传输 8 位数据而不获得任何相应的好处。如果你简单地依次取每个像素的低阶位,评级将与你选择的加密方法相同。
从这种方案中获得额外安全性的一种方法是不使用所有位,而是以某种循环顺序从每个像素中选择特定位。为此,您可以使用一串八进制数字(请参阅第 3.1 节中的表)作为选择消息位的密钥,例如 1,3,7,4,6。这可以称为选择密钥。它有 5 个八进制数字,因此有 15 个选择位。从图像的第一个像素和选择密钥的第一个数字开始。如果该数字的第一个位为 1,则将消息的一位放入像素的蓝色分量的低阶位,否则将低阶位随机设置为 0 或 1。如果第二个密钥位为 1,则对绿色分量执行相同操作,如果第三位为 1,则对红色分量执行相同操作。然后对第二个像素和选择密钥的第二个数字重复此操作。依此类推。
有人可能会认为,当密钥位为 0 时,最好保持图像对应位不变。这样会导致图像失真较小,并且使得 Emily 更难检测到其中包含隐藏消息。没错,但如果 Emily 怀疑你在使用这种方法,那么就可能确定选择密钥。
假设情况如此。Emily 拦截了包含位图图像的消息。进一步假设 Emily 在互联网上进行了图像搜索,并找到了原始图像。Emily 可以逐像素和颜色分量地将两个图像进行匹配。这使得 Emily 能够制作出两个图像版本之间差异的地图。在低阶位匹配的地方,Emily 可以在地图中标记一个 X,而在不匹配的地方,Emily 可以标记一个 |。然后,Emily 可以尝试每个可能的选择密钥长度。当选择正确长度 L,并且标记以 L 像素间隔对齐时,那么每一列选择位为 0 的地方将包含所有的 X,而选择位为 1 的列将包含一半的 X 和一半的 |。例如,再次使用选择密钥 1,3,7,4,6,你可能会看到

对于每一列包含 | 的情况,选择密钥的对应位必须为 1。选择密钥的所有其他位可能为 0。随着差异图中行数的增加,概率会变得更高。
因此,无论选择位是 0 还是 1,颜色分量的低阶位都应该随机设置。使用循环选择密钥,隐藏消息的这种方法在底层密码的评级为 1 到 4 时添加 2,或者在评级为 5 到 8 时添加 1。
选择密钥也可以使用第 4.5 节的链式数字伪随机生成器生成,使用 7、9 或 10 位数的合格种子。使用从 0 到 7 生成的数字作为选择数字。如果生成的数字是 8 或 9,则丢弃它并生成下一个数字。这里不重要伪随机数字是否具有统计随机性。重要的性质是生成的数字序列比消息更长,以比特为单位衡量,这样艾米丽就不能匹配具有相同选择密钥的密文部分。
使用链式数字选择密钥,如果底层密码的评级为一到四,则此隐藏消息的方法添加 3,如果评级为五到七,则添加 2,如果评级为八,则添加 1。
6.7 添加空位
将消息的位与空位的这种混合思想也可以在不嵌入消息于图像或其他文件中的情况下实现,并且可以手工完成。首先使用简单替换法或您选择的任何方法对消息进行加密。将这个初步的密文写成二进制形式,比如 5 位二进制。简单替换和转换为二进制可以一步完成。您可以只是按一些混合顺序替换字母表的 26 个字母为 5 位二进制数,就像这样:

注意,除了字母表的 26 个字母外,还有 6 个十进制数字。省略了数字 0、1、2 和 5,以防止手写时与字母 O、I、Z 和 S 混淆。这给了您将 5 位数转换回符号以进行传输所需的 32 个字符。
现在,消息以位串的形式给出,可以添加空位了。选择密钥用于指定插入空位的位置。选择密钥的形式是 m1,n1,m2,n2,m3,n3,...,表示取 m[1] 位消息并插入 n1 个空位,再取 m2 位消息并添加 n2 个空位,再取 m3 位消息并添加 n3 个空位,依此类推。以下是使用选择密钥 2,1,3,1,4,2,3,2 的示例。

使用此方案,消息被加密为Q9JIF PGUFF F。四个空位(阴影部分)被附加以完成最后一组 5 位。这称为填充或空填充。
选择密钥也可以以二进制形式给出,比如 110111011110011100。密钥中的每个 1 位表示取下一个消息位,而每个 0 位表示插入一个空位。
当使用两个不同的字母表来将字母转换为比特和将比特转换回字母时,此方案更加强大。使用可变长度的替代品,如第 10.4 节中描述的哈夫曼编码,也可以提高强度。为此,代码的长度不需要与字母的频率相对应,但它们仍然必须具有前缀属性,以便里瓦能够解密消息。
你可以通过两种方式避免在第二次替换时添加额外字符,即从比特到字母的替换。 (1) 你可以每次取 4 个比特,并且只使用字母表的 16 个字母,或者使用 16 个十六进制数字,或者 (2) 你可以使用一个具有六个 4 比特代码组和二十个 5 比特代码组的可变长度编码。同样,这些代码组必须具有前缀属性。以下是一个示例:

注意,我为 6 个最高频率的字母使用了 4 比特的替代物。这将使这 6 个字母在密文中的频率大约是其他 20 个字母的两倍。这可能会使一个不警惕的对手认为这是一种完全不同类型的密码。
添加空位适用于许多类型的加密。由于空位和其他任何比特都无法区分,因此添加空位比添加空字符更强大。它可以使密码的评级提高高达三分。
让我们看一个具体的例子。称之为Cipher Null5。和之前一样,有 3 个步骤,将字母转换为比特,添加空位,然后将比特转换回字母。字母被转换为比特,使用从字母到 5 比特组的同音替换。为每个字母 E、T、A、O、I、N 提供了两个替代物。空位通过使用选择密钥插入,如第 6.6 节所示。比特通过类似于上表的 4 比特/5 比特替换转换回字母。
Cipher Null5 的评级为六。
6.8 合并多个消息
二进制形式的密钥也可以作为合并密钥来合并两个消息。也就是说,两个消息的比特会交错以形成单个消息。基数为 3 或 4 的合并密钥可以用来合并 3 或 4 个消息。基数为 4 的合并密钥同样可以合并 3 个消息加空位。
合并多个消息的两个优点是,你不会像使用空位一样增加太多额外长度,而且可以使用更简单、更快速的加密。如果你使用一个长的合并密钥交替四个消息,并且对每个消息使用不同的简单替换,那么单单这一步就能获得五分的评价。如果你对合并的消息再进行一次简单替换,评价就会提升到八分。
合并消息的密钥可以采用两种形式,一种是比特计数形式,一种是选择形式。在比特计数形式中,消息会轮流被取出。密钥的每一位指定了从每个连续消息中取出多少比特。在选择形式中,消息可以按任意顺序被取出,但每次只取出一个比特。密钥的每一位指定了从哪个消息中取出下一个比特。以下示例展示了如何通过比特计数方法使用密钥 123123 合并消息 010101111010001101011 和 11101010011011100110,以及如何通过选择方法使用密钥 12122112 合并消息。

合并多条消息时,如果这些消息长度不同可能会显得混乱。除了最长的消息外,其他消息都需要有一个消息结束标记。另一种处理长度不匹配的方法是平衡合并。首先,将所有消息依次写在一起,用某个预留的字符或字符序列分隔开。然后简单地将这个长字符串分成相等的部分。例如,如果消息长度分别为 50、60、70 和 80 个字符,总共是 260 个字符,再加上 3 个分隔符共 263 个字符。你可以将它分成 4 条长度分别为 66、66、66 和 65 个字符的子串。如果使用的是 8 位字节,你可以将 263×8 = 2104 位分成 4 条每条 526 位的子串。不需要在比特字符串上按照偶数字节边界进行分割,但是你应该选择从每条子串中取相等位数的密钥。
顺便说一下,消息数和子串数是独立的。可以只有一条消息,也可以有多条消息,子串数从 2 开始。例如,一条消息可以分成 3 个子串,也可以有 3 条消息分成 2 个子串。
平衡是解决方案的一半。另一半在合并过程接近尾声时出现。最终,你将会合并来自其中一条字符串的所有比特,而其他字符串还剩下一些比特。如果合并密钥指定了另一条没有剩余比特的字符串的另一个比特,则跳到下一个比特选择。
让我们把所有内容汇总成一个密码,称为 Merge8。Merge8 密码作用于一个或多个连接在一起的消息。在基于 26 进制的版本中,26 个字母使用类似于第 6.7 节中的 4 比特/5 比特编码转换为二进制。消息分隔符可以是一串字母,如 XXX 或 END。在基于 256 进制的版本中,对 ASCII 码应用混合良好的简单置换。生成的比特字符串被分成 8 个长度相等的比特串。使用 32 个八进制数字的密钥来合并这 8 条比特串。每个 8 进制值在密钥中出现 4 次,因此有 32!/(4!)⁸ = 2.39×10²⁴ 种可能的合并密钥。对生成的字符串执行第二个简单的置换。基于 26 进制和基于 256 进制的版本都使用 8 比特置换。Merge8 评级为六。
6.9 在文件中嵌入消息
当将消息隐藏在图片文件中时,每个消息比特至少有 7 个图像比特。这相当低效。如果不试图让它看起来像其他东西,你可以在文件中隐藏更多的消息比特。它是密文,就让它看起来像密文。有数十种方法可以在文件中隐藏明文消息。我将简单列举一些选项。与第 6.6 节一样,对于文件的每个字节,一定数量的明文比特被隐藏在其中的 8 比特中。
-
每次取固定数量的明文比特或可变数量的明文比特。
-
每个字节内的位可以放置在固定的位位置或可变的位位置。
-
位按顺序放置,或者重新排列。
-
明文位可以原样插入,也可以轻微加密,例如通过简单的替换。
-
密文位可以原样保留,也可以轻微加密,例如通过简单替换。
位的数量、位的位置和位的顺序可以由周期性密钥或某些随机序列控制。根据所选择的选项,这一类密码的评级可以从一到十不等。
这是一个这样密码的例子。 (1) 对消息执行混合良好的密钥简单替换。(2) 使用具有大内部状态的伪随机数生成器,在每个字节中选择 2 到 6 位位置。按顺序将消息的下一个 2 到 6 位放置到这些 2 到 6 位位置中。将剩余位位置设置为随机值。(3) 执行第二次混合良好的密钥简单替换。
这种称为EmbedBits的方法极其快速简单。缺点是密文长度约为明文的两倍。EmbedBits 被评为八分。要将评级提升到十分,可以将简单替换替换为双字母替换,例如 Two Square。
第七章:置换
本章涵盖
-
路径和列置换
-
随机数置换
-
密钥置换
-
多重变位词
在第五章和第六章,我们讨论了替换密码。秘密密钥加密方法的第二大类别是置换。置换意味着改变消息中元素的顺序。这些元素可以是单词、音节、字母或代表字母的个别数字或位。在本章中,我们将主要处理字母置换,但请记住,您可以使用相同的方法处理其他元素,例如第 7.2.2 节中的单词置换。本章将涵盖许多不同类型的置换密码。大多数这些置换密码只需用铅笔和纸就可以完成。
7.1 路径置换
路径 置换 是最简单、最古老的置换密码形式。没有涉及密钥。保密性来自路径或路径选择。
路径置换是让孩子们对密码学感兴趣的好方法。这是一个适合课堂、童子军团或其他俱乐部的活动。主要注意事项是孩子们必须以直立的列均匀地写字母,否则消息会混乱。可以通过使用间距较宽的方格纸来避免这种情况。
基本思想是将消息用一条路径写入矩形中,然后用另一条路径读出。例如,如果消息有 30 个字符,那么 5×6 的矩形最合适。如果消息有 29 个字符,只需添加一个空字符。用空字符填充消息,直到它适合合适大小的矩形。在开始填写之前,画出矩形的轮廓是有帮助的。如果消息很长,将其分成方便大小的块。例如,1000 个字符的消息可以分成二十个 5×10 的块。
我们已经在第 4.3 节看到了路径置换的一个示例。消息是水平地从左到右跨行写入 5×5 网格中,然后垂直地从上到下沿列读出。水平和垂直是两种路径。以下是更完整的列表。
-
水平方向,从左到右,从右到左,或交替左右
-
垂直方向,从上到下,从下到上,或交替上下
-
对角线方向,从左上到右下,从左下到右上,等等,或交替
-
螺旋,从任何一个角向内或从中心向外,顺时针或逆时针
你可以从矩形的任何一个角开始,使用任何路径写入消息,并使用任何其他路径读出消息。这里是一个花式路径的示例:

消息将按照数字指示的顺序写入网格中,并按列读出,即 1、36、37、39、42、2、6、38,...
对于路线置换,Emily 只需要猜测您用来读取消息的路线。在 Emily 将消息填入矩形之后,可以通过检查来读取。请注意,对于 Emily 来说,您是将消息水平写入 5×6 矩形还是垂直写入 6×5 矩形都无所谓。同样,您是从顶行向下工作还是从底行向上工作也无所谓。Emily 无法区分这两者之间的差异。
路线置换评为一级。
7.2 纵列置换
纵列 置换 是置换密码的主力军。自 17 世纪以来,它一直被军队、外交官和间谍使用。该方法首次在约翰·法尔科纳(John Falconer)于 1685 年撰写的《密信解密》(Cryptomenysis Patefacta)一书中描述。1688 年的光荣革命之后,约翰·法尔科纳跟随詹姆斯二世流亡到法国,在那里去世,而第二版于 1692 年以新标题《解释和解密各种秘密写作规则》(Rules for Explaining and Decyphering all Manner of Secret Writing)出版之前已经出版。
纵列置换使用的密钥可以是混合顺序的连续数字字符串,也可以是关键字或密语,通过将字母按字母表顺序编号来将其转换为数字字符串。考虑关键字 SAMPLE。字母 A 在字母表中最早,因此编号为 1。字母 E 在字母表中次序排在第二,编号为 2。然后是 L、M、P 和 S。因此 SAMPLE 转换为字符串 6,1,4,5,3,2。如果同一字母出现多次,则按从左到右的顺序编号。例如,ANACONDA 变为 1,6,2,4,8,7,5,3。

将消息从左到右水平写入网格。列数等于密钥的大小。如果密钥是 SAMPLE,则有 6 列。如果密钥是 ANACONDA,则有 8 列。像这样在网格上方写下数字密钥:

根据数字密钥从顶部到底部垂直读取消息,从编号为 1 的列开始,EKFHE,然后是列 2,ESRAT,列 3,NROW,直至列 8,YCYI,如图所示。
合法接收者 Riva 需要做一点算术才能阅读此消息。密钥长度为 8 个字母,消息长度为 35 个字母。35 除以 8 等于 4,余数为 3。这意味着数组将包含 4 行完整的 8 个字母,加上 3 个字母的短行。Riva 应该在开始填写列之前画出此数组的轮廓,以便将正确数量的字符放入其中。
艾米莉,敌人的任务有点困难。技巧是将每列的字母垂直写在一条纸条上,然后将这些条纸对齐以确定列的顺序。她寻找那些匹配字母形成常见双字母组合的条纸对。当她找到一个好的匹配时,她尝试在这两个条纸之前或之后添加第三个条纸。一旦正确匹配了 3 或 4 个条纸,短单词就开始出现,任务变得容易起来。
艾米莉不知道关键字的长度,所以她需要猜测。她可能从 5 开始并逐渐增加。假设她已经增加到 8,正确的长度。像丽娃一样,她将 35 除以 8。她知道有 5 个由 4 个字母组成的短列,和 3 个由 5 个字母组成的长列。艾米莉的问题是在哪里开始和结束每个条纸,以便至少包含一个完整的列。
第一条纸条从密文的第一个字符开始,如果第一列读出的数组是长列,则必须是 5 个字母长。第二条纸条从密文的第五个字母开始,如果第一列是短列,则在第十个字母结束。对于第三和第四条纸条也是如此。然后,艾米莉将对其他 4 条纸条做相反的操作,从密文的最后一个字母向中心反向工作。
然后,艾米莉将匹配这些条纸,将它们相互滑动以确定正确的对齐方式。所有这些都是凭眼睛完成的,所以艾米莉必须熟记最常见的双字母组合和三字母组合的频率。这也可以通过计算机以简单直接的方式完成。
针对这种匹配程序的最常见对策是,发送者桑德拉从上到下读出一些列,从下到上读出另一些列。这意味着艾米莉需要一套读取反向的第二套条纸。然后她将有两倍多的条纸来尝试匹配。
如果数组是矩形,则所有列向下读取时,列置换评为二,如果不是,则评为三。如果网格是矩形,或者列很长并且交替方向读取时,列置换评为三,否则为四。
列置换是一种为任何类型的替换密码增加强度的经过验证的方法。列置换与混合良好的简单替换相结合评为五。当与混合良好的一般多表密码相结合时,评为七。如果两个密钥的长度互质,则组合最强。
加强柱形置换的最常见技巧是使一些行的长度不同。这样会让艾米丽难以确定条带应该从哪里开始和结束。有四种这样的想法。其中,编号(4)是最强的,因为它在中间的一个不可预测的点破坏了条带,而不是在末端。更复杂的空白模式可能在某些列中有 2 个或更多的空白。
这些变种的柱形置换评分为四,前提是艾米丽不知道模式。如果密钥很长,并且列中有可变数量的空格,那么变种(4)的评分将提高到五。法国人在一战结束时使用了这样的系统。据信德国人能够读取其中至少一部分消息,主要是因为法国人多次重复使用了他们的密钥。

对数字(3)的两个进一步变种,楼梯,是(5)当你到达右边缘时从第一列开始,形成一个斜线模式,和(6)当你到达右边缘时反向,创建一个燕尾或之字形图案。这些模式的优点是每一行的字符数除了最后一行可能不同外,其他都相同,这样瑞娃很容易计算行数。以下是这两种变体的示例。

你也可以有两个或更多不同宽度的分开的楼梯,或者在对角线和反对角线方向上有楼梯 ** 和 /。
当你解密使用任何这些柱形置换变种发送的消息时,如果你有任何难以计算需要多少行,或者最后一行有多长的困难,这里有一个技巧。数一下消息中的字母,并从左到右用那么多的小点填写数组,按照桑德拉用来书写字母的相同模式。然后在点上填写字母。
例如,在变种(2)中,假设你已经同意你将始终从第一行开始使用 7 个字母。密文(2)有 38 个字母,所以你在第一行放置了 7 个点,第二行放置了 8 个点,直到你总共放置了 38 个点。然后你开始在它们的正确列中填写字母,像这样替换点:

使用有黑色方块的另一种方法是用空值填充它们。空值应该选择成为不常见的字母对,以使艾米丽更难匹配列。最好使用常见的字母而不是罕见的字母,这些字母可能很容易被识别为空值。这是一个例子。

有空格的柱形置换评为三。有固定的空格模式,评分为四。
7.2.1 Cysquare
历史趣闻:在第二次世界大战期间,英国使用了这个想法的一个变体,称为Cysquare,由约翰·H·蒂尔特曼准将于 1941 年发明。Cysquare 是一个具有大量涂黑的列置换密码。英国发行了 26×26 网格的填充物,大约 60%的方块以随机模式涂黑。每页有不同的模式。消息被写入横跨行的白方块中,然后以某种顺序垂直读出。网格是正方形的,因此可以以任何方向使用。
关键是填充物中的页码、方向以及网格内的起始和结束位置。密码员会在页面上画线标记消息区域。使用不同的区域可以让页面用于多条消息。
缺点在于需要分发如此多的填充物。为了最小化填充物的数量,英国人每天将每页用于可能多达 50 条消息。这意味着要写得很淡并且擦拭多次。页面变得难以阅读,最终密码员拒绝使用它们。Cysquare 在 1944 年被放弃了。
德国人在战争结束前从 1944 年开始使用这些填充物之一,连同说明书一起。他们开始自己使用这个系统,直到战争结束。他们称之为Rasterschlüssel,意思是网格密钥。然而,德国人在选择黑白方块时做得不好。他们使用了太多相邻的白方块,因此当他们将条带匹配时,英国人可以识别出二元组和三元组。这些消息成为英国情报的宝贵来源。Cysquare 评分为七分。Rasterschlüssel 评分为四分。
值得注意的是,在计算机时代,黑白方块可以作为比特模式传输,网格可以是任意大小,并且网格可以针对每条消息进行更改。我建议使用 65%到 75%的黑方块。这样做,cysquare 将被评为八分。
有一个简化版本的 cysquare 可供手动使用,不需要印刷网格,并且允许您使用数字密钥指定哪些方块被涂黑。这里有两种Blackout置换密码的变体,一种是左右交替版本,另一种是阶梯版本。两者都使用数字密钥 3174255 进行涂黑。涂黑密钥可以是重复的密钥,或者可以由伪随机数生成器生成。您将使用单独的密钥指定读取列的顺序。

加强列置换的另一种方法是将文本分成不规则大小的块。例如,如果消息长度为 150,您可以将其分成 37、71 和 42 个字母的块。这种方法被评为四分。如果您为每个块使用不同的密钥,评分将提高到五分。
将栏式置换与任何类型的替换密码结合在一起会极大增强其安全性。即使与简单的替换结合,等级也会提高到五级,因为匹配条变得更加困难。哪个先做都没有关系。将通用多表密码与至少 12 列的栏式置换结合会将等级提高到七级,即使多表密码的周期只有 3。这是因为您基本上消除了匹配条的可能性。
7.2.2 单词置换
Word transposition 是一个基于单词而不是字母的具有历史重要性的栏式置换。这是美国内战期间联邦军队使用的主要方法。这个想法来自安森·斯泰格(Anson Stager),一个后来创立了西联电报公司的联邦电报员。联邦军队的通信受到高传输错误率的影响。在许多情况下,指挥官们会放弃电报,而只是派遣步行或骑马的信使。斯泰格意识到,发送单词而不是单个字母将减少错误率,并减少重发消息的需要。
联邦密码员将消息逐字从左到右写成矩形数组,然后使用各种路线读出,例如交替上下读取列,或者交替从数组的左半部分和右半部分取列。空单词被大量使用。这里是一个例子。请注意第三行是空的。列按顺序读取为 1,3,5,2,4。

7.3 双栏式置换
如其名称所示,双栏式置换 意味着连续进行两次栏式置换,最好使用两个不同的密钥。这消除了匹配条的可能性。值得注意的是,1934 年,所罗门·库尔巴克(Solomon Kullback)找到了一个通用解决方案,并由信号情报局发布。这本 31 页的书在 1980 年解密,并由爱琴海公园出版社出版。爱琴海公园出版社多年来一直是密码学书籍的宝贵资源。在其创始人韦恩·G·巴克(Wayne G. Barker)去世后的 2001 年后不久,该公司停业,书籍不再可用。我很高兴地说,www.openlibrary.org 现在有这些书籍(2019 年 7 月访问)。
我不会在这里重复库尔巴克的分析,除了说它是基于确定每个明文字母在密文中出现的位置。相反,我将讨论 3 种打败库尔巴克解决方案的方法。(顺便说一句,库尔巴克和我父亲上了同一所高中,只是早了 6 年。)
一个简单的方法是通过涂黑几个方块来改变网格的形状。这些方块可以形成一个矩形,或者在一个角落,甚至在网格的中间形成其他形状。这里有一些例子:

黑掉的部分在两个置换步骤中可以具有不同的大小、形状或位置。黑掉的部分的大小、形状和位置可以附加到密钥中,以便为每个消息使用不同的黑掉。具有黑掉的双栏置换等级为 Five。
相反的方法称为NullBlock,也很有效。您可以将一块空字符块插入中间密文或最终密文,或两者都插入。将空块添加到明文中并不有助于加密。块的大小和位置可以由数字密钥指定。这些应该在消息之间变化。
将任何置换密码与任何替换密码结合使用会增强两者的安全性。双栏置换与简单替换的组合等级为 Six。双栏置换与通用多表替换的组合等级为 Eight。
7.4 循环栏置换
栏置换的另一种变体是循环栏置换。它有两种变体,水平循环和垂直循环。水平循环需要两个密钥,一个用于循环行,一个用于确定列顺序。首先,从左到右将消息写入矩形块的行。接下来,在行的左侧写入循环密钥。如果行数多于此密钥的长度,则根据需要重复使用该密钥。如果循环密钥是一个词或短语,请使用字母顺序将其转换为数字。
将循环密钥转换为数字形式后,将每行向左循环移动所指定的位置数。然后按列密钥指定的顺序垂直读出字母。以下是使用循环密钥 CYCLES 和列密钥 PAULREVERE 的示例。

解决栏置换所使用的匹配纸条方法也适用于循环栏置换。这只是稍微困难一点,因为每行的最后一个字母与第一个字母相邻,可能形成低频的二元组。这对 Emily 来说最多只是一个轻微的阻碍。具有水平循环的栏置换等级为 Three。
垂直循环类似。不是将块的行向左循环移动,而是将块的列向上循环移动。以下是使用关键字 CYCLE 来循环列和使用密钥短语 PAULREVERE 来选择列读取顺序的示例。

这种密码仍然可以通过匹配纸条来解决,就像普通的栏置换一样,但 Emily 需要为每个列使用两条纸条,一条用于顶部部分,一条用于底部部分。当每列循环时,某些字符从列的顶部移动到底部,并成为新的底部部分。剩下的字母向上移动,并成为新的顶部部分。在例子中,左列 ODYTEL 向上移动 1 个位置,所以 DYTEL 成为新的顶部部分,O 成为新的底部部分。这些部分需要放在不同的纸条上,因为 Emily 不知道这些字母是来自长列还是短列。这使得匹配过程变得相当困难。带有垂直循环的栏置换被评为 Four。
在这个区块上可以执行垂直和水平循环。这与双栏置换的强度相当。但请记住,你的密码越复杂,花费的时间就越长,而且正确地加密和解密也就越困难。双循环栏置换 被评为 Five。
7.5 随机数置换
让我们来看一个完全不同类型的置换。这种置换不涉及任何形式的数组或网格。相反,它只是随机对消息中的字母进行编号。
你可以使用任何随机数生成器。第十三章中介绍了几种随机数生成器。到目前为止,我只描述了第 4.5.1 节中的链式数字生成器,所以让我们使用那个生成器来说明。为消息的每个字母生成一个随机数字,像这样:

首先取所有从左到右编号为 1 的字母。这些是 C、V 和 I。

接下来取所有编号为 2 的字母。这些是 A、O 和 L。

然后取所有编号为 3 的字母,即 N、E、E 和 M。

持续这样做,直到所有的字母都被取走。
要解密这条消息,Riva 首先会生成随机数字。有三个 1,所以她会在三个 1 下面写下密文的前 3 个字母 CVI,像这样:

Riva 会将密文的下一个 3 个字母 AOL 写在 2 下面,像这样:

以此类推。
随机数置换被评为 Four。可以通过尝试所有可能的随机数生成器种子来破解它。
通过使用更长的种子或通过以 1、2、3、...以外的顺序选择明文中的字母来增强密码。 这相当于对随机数生成器的输出应用简单的替换。 例如,如果您想从标记为 4 的字母开始,那么您将把所有的 4 改为 1。 如果接下来想要取出所有标记为 7 的字母,那么您将把所有的 7 改为 2,依此类推。 然后按照描述的方式进行。 这将使可能的密钥数量增加到 10!,即 3,628,800。
通过这种改进,链式数字置换评级为五。 对于计算机版本,其中随机数生成器产生随机字节,该方法评级为七,因为重新排列 256 个不同字节的可能顺序太多。
7.6 选择器置换
由于我们正在研究随机数,让我们看看基于随机数的另一种置换密码,即选择器置换。 思路是将消息分成大致相等的部分,然后使用随机数序列合并这些部分。
假设明文有 100 个字符,你想将其分成 3 部分。 假设你有一个随机数生成器,以相等的概率产生数字 0、1 和 2,并且你已经选择了一个种子,它作为置换的密钥。 你需要知道如何将消息的每个部分做多大。 这很容易做到。 只需生成前 100 个随机数字,并计算产生的每个数字的数量。 假设有 36 个零,25 个一和 39 个二。 你将消息切成 3 部分,P0 有 36 个字母,P1 有 25 个字母,P2 有 39 个字母。
加密很容易。 每当生成器产生一个 0 时,从 P0 中取下一个字母。 每当生成器产生一个 1 时,从 P1 中取下一个字母。 每当生成器产生一个 2 时,从 P2 中取下一个字母。 解密甚至更容易,因为 Riva 不需要知道每个部分有多大。 每当她得到一个 0 时,她将下一个字母放入 P0 中。 每当她得到一个 1 时,她将下一个字母放入 P1 中。 每当她得到一个 2 时,她将下一个字母放入 P2 中。 然后她连接这 3 个部分,或者简单地忽略换行符读取消息。
当只用 2 部分完成时,Emily 可以轻松重构消息。 评级为一。 用 3 部分时稍微困难,评级为二。 用 20 个或更多部分时,评级为五。
7.7 密钥置换
有时,逐块移位消息是首选。用于置换块的最佳选择是 主要置换。在消息的字符上方写下数字密钥,然后将每个字符移动到其密钥编号指示的位置。在此示例中,块大小为 8,数字密钥为 41278563。第一个字母 R 的密钥编号为 4,因此将 R 移动到块中的第四个位置。第二个字母 U 的密钥编号为 1,因此将 U 移动到块中的第一个位置,依此类推。

主要置换可以用于明文、密文或两者。仅使用主要置换是弱的。根据块大小,主要置换的等级从一到三。
*****让我们深入了解置换。在数学中,置换被称为 排列。这里有一个例子。我用十六进制数字 A、B 和 C 来表示数字 10、11 和 12。在密码中,这些数字将代表被置换的位、字母或其他单元。

顶行是标准的。它表示置换之前的原始顺序。第二行是置换后的顺序。在本节的后面,第二行将用于描述置换。
在此置换中,位置 1 的数字移动到位置 4,位置 4 的数字移动到位置 7,位置 7 的数字移动到位置 12,位置 12 的数字移动到位置 3,位置 3 的数字移动到位置 1,完成循环 1➔4➔7➔C➔3➔1。循环可以表示为 (1,4,7,12,3)。
不在此循环中的第一个数字是 2。从位置 2 开始,我们找到循环 2➔A➔6➔9➔B➔8➔5➔2,可以表示为 (2,10,6,9,11,8,5)。整个置换可以表示为 (1,4,7,12,3) (2,10,6,9,11,8,5)。
这两个循环的周期分别为 5 和 7,因此此置换的周期为 35。也就是说,如果你将此置换一直应用到一个由 12 个字母组成的块上,它将产生 35 种不同的字母置换,而第 36 种置换将与原始明文相同。
假设你想要生成一个强大的块置换密码,其中每个块都有不同的置换。对于每个块分别应用先前的置换不足够,因为它每 35 个周期就重复一次。可以通过使用两个不同的置换并交替使用来解决这个问题。
让两个置换分别是 A 和 B。如果 A 和 B 被适当选择,那么你可以生成大量不同的置换 A、B、AA、AB、BA、BB、AAA、AAB、ABA,...。
理解排列的循环结构变得很重要。假设你选择了排列 (1,4,7,12,3) (2,10,6,9,11,8,5) 和 (1,4,3,12,7) (2,10,9,6,5,11,8)。这两个排列以相同的方式划分了 12 个单位的块,即 [1,3,4,7,12] 和 [2,5,6,8,9,10,11]。当你交替使用这两个排列时,[1,3,4,7,12] 的分区将与 [2,5,6,8,9,10,11] 的分区分别排列。也就是说,这两组数字之间没有相互作用。为了获得长周期,第二个排列的每个循环应尽可能与第一个排列的每个循环重叠。下面是一组适合的排列。
(1,4,7,12,3) (2,10,6,9,11,8,5)
(1,10,8) (4,6,5,12) (2,11,9,7,3)
这个转位密码被评为三。它可以通过尝试所有 12! 种可能的排列来简单解决第一个块。这只有 4.79×10⁸。对于为第一个块生成合理文本的每个排列,艾米莉可以尝试第二个块的 12! 种排列。实际上,这并不需要 (12!)² = 2.29×10¹⁷ 次尝试,因为仅查看块的前 3 或 4 个字符就可以消除许多不合理的组合。事实上,通过手工方法解决这个密码是可行的。随着块大小的增加,难度增加得很慢。
有几种增加密钥置换安全性的方法。一种方法是重叠块。例如,如果块大小为 16,则在消息中不是从位置 1、17、33、... 开始块,而是从位置 1、9、17、25、33、... 开始块。这样,每个块与前一个块重叠 8 个单位,并且与后一个块重叠 8 个单位。消息的最后 8 个单位可以与前 8 个单位组合成一个环绕块。这个密码被评为四。
重叠量可以是可变的。如果当前块从位置 P 开始,块长度为 L,则下一个块可以从位置 P+1 到位置 P+L 的任何位置开始。这个密码被评为五。如果使用两个不同的转位,并随机选择,评分将提高到七。
加强块置换密码的第二种方法是通过组合置换。如果 T 和 U 是转置,则 T 和 U 的组合,表示为 TU,是通过首先执行转置 U 然后执行 T 而形成的。结果的转置与使用 T 转置 U 然后使用结果的转置转置文本相同。让我们试试一个例子。假设 T 是419628573,U 是385917462。由于 U 是一个包含 10 个字符的块,您可以使用 T 来转置 U,就像您使用 T 来转置一个 10 字母的单词一样。将 T 写在顶行上用作置换键,并将 U 写在第二行上作为被转置的文本。结果的第一个数字是键中数字 1 下面的数字,即8(见阴影)。结果的第二个数字是键中数字 2 下面的数字,即1,依此类推。使用 T 来排列 U 得到812349675*。

通过这种方式组合转置,您可以生成一个转置序列,U,TU,TTU,TTTU,... 。此序列的周期与 T 的周期相同。对于块大小为 12,当循环的长度为 3、4 和 5 时,最长可能的周期为 3×4×5 = 60. 如果您的消息长于 60 个块,则可能需要更长的周期。这可以通过以某种重复或随机模式排列转置与 U 或 T 之一来完成,例如 U,TU,TTU,UTTU,UUTTU,... 这可以生成一个非常大的不同转置集合,前提是 T 和 U 各自具有较长的周期,并且 T 的循环重叠 U 的循环,如前文所述。
您可以使用累积测试来测试循环是否重叠足够。从 T 或 U 的任何一个循环开始。这形成一个只包含该循环的集合。将与其具有共同元素的 T 或 U 的任何其他循环添加到该集合中。现在将具有与您已选择的循环具有共同元素的 T 或 U 的任何其他循环添加到此较大的集合中。继续这样做,直到没有更多的共同元素为止。如果循环集现在包含 T 和 U 的所有循环,则具有很好的重叠。如果您决定使用超过两个转置,比如 T,U 和 V,则 T 和 U 应该重叠,T 和 V 应该重叠,U 和 V 也应该重叠。
这里有一个例子,使用本节早些时候的一些转置,T = (1,4,7,12,3) (2,10,6,9,11,8,5),U = (1,10,8) (4,6,5,12) (2,11,9,7,3)。从循环(1,4,7,12,3)开始。
(1,4,7,12,3)
这个与循环 U 的(1,10,8)共有元素 1,因此将该循环添加到集合中。
(1,4,7,12,3) (1,10,8)
这个与循环 U 的(4,6,5,12)共有元素 4,因此将该循环添加到集合中。
(1,4,7,12,3) (1,10,8) (4,6,5,12)
依此类推。因为这将包括 T 和 U 的所有循环,它们是很好的重叠对,当它们组合时会产生非常庞大的转置家族。******
7.8 分半置换
分半 置换 是我发明的一种计算机技术,使用二进制密钥交换可能是位或字节,或者可能是十六进制数字的单元。IBM 在公司的发明披露公告中发布了这一技术,并考虑将其纳入数据加密标准(DES)中。分半置换作用于块的大小为 2 的某个幂次方,通常为 32 或 64 个单元。对于 n 个单元的块,密钥将有 n-1 位。
让我们以 16 个字符的块大小为例。明文是乔治·华盛顿。置换将使用一个 15 位的密钥。密钥的第一位确定了块的左右 8 单元半部分是否交换。0 表示不交换,1 表示交换两部分。接下来的 2 位密钥位确定了这些半部分的 4 单元是否交换。如果密钥的第 2 位是 1,则块的第一季度与第二季度交换。如果密钥的第 3 位是 1,则块的第三季度与第四季度交换。密钥的接下来的 4 位确定了这些季度的半部分是否交换。例如,如果密钥的第四位是 1,则块的第一八分之一与第二八分之一交换。最后的 8 位控制了块的 16 分之一是否交换。例如,如果密钥的最后一位是 1,则块的最后 2 个单元,第 15 和第 16 个单元,字母 O 和 N 被交换。

要解密这个置换,步骤必须按相反顺序进行。也就是说,首先应该交换单元,然后是对、四个一组等。
7.9 多次变位
解决置换密码的一般技术,适用于许多类型的置换,即使类型未知,也是多次变位。要使用这种技术,您需要拦截几条相同长度的消息。如果这些消息使用相同的密钥进行置换,那么每条消息的第一个字母将在所有密码文本中的相同位置,第二个字母将在所有密码文本中的相同位置,依此类推。
我们可以利用这一事实。用所有密码文本中的第一个字母制作纸条 1。用所有密码文本中的第二个字母制作纸条 2,依此类推。制作与每个密码文本长度相同的纸条。这些纸条可以像解决列置换时那样匹配。可用的消息越多,纸条就越长,成功的机会就越大。通常认为需要至少 3 条消息。
让我们看一个例子。假设我们有这 3 个密码消息:

消息长度为 12。右侧显示了 12 条条带。
消息(1)包含一个 K。可能在 K 之前的字母有 C 和 N。消息(1)各包含一个。消息(2)包含一个 D。在 D 之前可能的字母是 N。消息(2)包含一个 N。让我们检查这些是否是合理的选择。我们有

在消息(2)中,最有可能在ND之前的字母是A或E。这给出 3 种可能性:

将这 3 个选择与剩下的 9 条纸条进行匹配,最佳匹配是与第 4 条纸条。

这与我们之前已经组合的第 5 列和第 10 列非常匹配。

现在这 3 条消息很容易完成,(1)黎明时攻击,(2)发送更多弹药,和(3)立即见我。
第八章:杰斐逊轮式密码
本章包括
-
托马斯·杰斐逊的轮式密码
-
使用已知单词解密轮式密码
-
当不知道任何单词时解密轮式密码
托马斯·杰斐逊(Thomas Jefferson)在 1790 年至 1793 年间发明了杰斐逊轮式密码,当时他担任乔治·华盛顿(George Washington)的国务卿。该装置由直径为 1/8 至 1/4 英寸,长为 6 到 8 英寸的铁棒或纺锤和直径约为 2 英寸,厚约为 1/6 英寸的 36 个木制圆盘组成。每个圆盘在中心都有一个与棒相同大小的孔,以便所有圆盘都可以紧密地放在棒上,形成一个木制圆筒。圆盘的平面面对着彼此,外圆的圆边可见。棒的一端有一个类似钉头的头部。另一端有螺纹,以便螺母可以拧紧到棒上,将圆盘牢固地固定在位。
圆盘的平面侧编号为 1 到 36。外圆边被分为 26 个相等的部分。字母表的 26 个字母以某种混乱的顺序写入或刻在这些 26 个部分中的每一个中,每个圆盘的顺序都不同。棒上圆盘的顺序是密码的关键,这种密码现在被称为复用密码。
这是位于马里兰州福特米德(Fort Meade)的国家密码博物馆(National Cryptologic Museum)展示的一台 26 片杰斐逊密码轮的复制品。(照片由 Daderot 拍摄,根据知识共享 CC0 1.0 许可证发布。)

使用该装置对消息进行加密的方法是首先按照密钥指定的顺序将圆盘放在轴上。螺母松开,以便可以转动各个圆盘。消息的第一个字母在第一个圆盘上找到,然后转动第二个圆盘,使消息的第二个字母紧挨着第一个字母。然后转动第三个圆盘,使消息的第三个字母紧挨着第二个字母,依此类推,直到消息的前 36 个字母排成一行。然后拧紧螺母以固定它们的位置。
转动圆筒,还有其他 25 行字母,所有这些都是无意义的混乱。桑德拉可以选择其中任意一行作为密文。里瓦重复这个过程,在圆筒的一行上设置密文。很明显,其他 25 行中哪一行是预期的信息。
杰斐逊显然从未将这种密码投入使用。这个概念一直搁置,直到 19 世纪 90 年代初由Étienne Bazeries 重新发明。它于 1901 年被法国采用。Bazeries 的版本有两个改进。它有一个支架,这样设备可以放在桌子上进行双手操作,并且有一个导轨,帮助用户将字母对齐并选择用于读出密文的行。1914 年,上校帕克·希特发明了一种使用 25 个铝盘的密码版本,并于 1922 年被美国陆军采用为 M-94,于 1926 年被美国海军采用为 CSP-488。希特的版本只有 4.25 英寸长,足够小,可以放在口袋里,盘片的平面面上有凹槽和齿,使得它们在对齐后不会滑动。
这是国家密码博物馆展示的一张 CSP-488 的照片。

1916 年,Hitt 发明了密码的平面版本,并于 1935 年被军方采用,称为 M-138。这个版本是一个带有 25 个通道的平面铝板,上面放置着可以前后滑动的纸条,以模拟盘片的旋转。每个纸条上都有两份乱序的字母表。这个设备更加安全,因为纸条可以很容易地更换,甚至在必要时可以在野外手写。这很快被 M138A 或海军的 CSP-845 所取代,后者有 30 个纸条槽。设备附带 100 条纸条,用 2 位数字编号,因此任何消息使用了 100 条中的 30 条。这样可以产生 100!/70!=7.79×10⁵⁷种可能的密钥。
M-138A 中间有一个铰链,可以折叠以便携带。每半部分都有一个独立的导轨,用于对齐纸条并读出密码的 15 个字母。这些改进显著增强了密码的安全性。
军方在 1942 年或 1943 年左右放弃了这种带纸条的密码,但海军仍将其作为备用,以防止电力故障使得无法使用任何电子或电机式密码设备。
如果 Emily 没有设备的副本并且不知道字母表,解密多路复用密码是不可行的。如果 Emily 拥有设备,如果她知道一些可能的单词,解密就相对容易。当 Emily 拥有设备的副本并且知道一些可能的单词时,杰斐逊密码轮的评级为四到五。如果没有已知的可能单词,评级为六到七。Emily 拥有的密文越多,评级越低。相反,如果设备有很多额外的盘片,评级就会提高。例如,如果设备有 30 个盘片,用户可以从 100 个盘片中选择,评级可以达到八。对于非常短的消息,少于两倍盘片数量,除非 Emily 拦截使用相同密钥的多个消息,否则解密可能是不可能的。如果发件人每天只更改盘片的顺序一次,这种情况可能会发生。
8.1 已知单词解答
当你有足够的文本,并且知道至少部分消息时,可以解密使用杰斐逊密码轮加密的消息。通常,只要知道一个单词就足够了。假设你知道 Sandra 正在使用 M-94 设备,它有 25 个盘片,并且你拦截到了一条消息:

假设你还知道明文消息以 URGENT 开始。这已经被转换成了密文 CLPOXF。由于 URGENT 在一行上,而 CLPOXF 在另一行上,因此相应字母对之间的距离必须相同。让我们将带有 URGENT 的行称为第 1 行,假设带有 CLPOXF 的行是第 8 行。明文的第一个字母 U 和密文的第一个字母 C 分别来自第一个盘片的第 1 行和第 8 行。因此,在第一个盘片上,从 U 到 C 的距离必须为 7. 在第二个盘片上,从 R 到 L 的距离必须为 7. 在第三个盘片上,从 G 到 P 的距离必须为 7,E 到 O 也是,N 到 X 也是,T 到 F 也是。
搜索的最简单方法是依次尝试从 1 到 25 的每个可能的距离。从距离为 1 开始。找出所有距离 U 到 C 的距离为 1 的盘片。换句话说,U 的下一个字母是 C 的盘片。如果没有这样的盘片,那么你知道距离不是 1. 然后找出所有距离 R 到 L 的距离为 1 的盘片。同样,如果没有,那么距离也不能是 1。
假设你已经找到了 12 组盘片,其中字母对的距离都是 1. 现在你需要测试这 12 组盘片,看看它们中是否有任何一组是正确的。假设第一组盘片是 18-4-21-9-13-11. 从密文的第二块开始测试,字母从 26 到 50. 这个块以 ESIWVI 开头。将盘片 18 设置为字母 E,盘片 4 设置为字母 S,盘片 21 设置为字母 I,依此类推。现在看其他 25 行。如果它们都是无意义的,比如 HNSAEI 或 TFPGUW,那么你就知道 18-4-21-9-13-11 不是正确的盘片顺序。另一方面,如果你看到一些像 NCONDI 这样的合理文本,它可能是 UNCONDITIONAL 的一部分,那么 18-4-21-9-13-11 可能是正确的盘片顺序。再次测试,使用以 GAFOEM 开头的密文的第三块。如果第三和第四块都导致合理的文本片段,那么 18-4-21-9-13-11 可能是正确的...但继续搜索,因为你可能会找到更好的盘片顺序。
如果你没有看到任何可能的文本片段,那么尝试其他 11 组盘片顺序。如果这些都不起作用,尝试距离为 2、距离为 3,... 直到距离为 25. 可能会有几百种盘片顺序和距离的组合需要测试。这很乏味,但手工仍然可行。如果没有任何组合有效,请返回查找其中 2 个测试给出合理文本的盘片顺序。
一旦你确定了前 6 个盘的最有可能的序列以及相应的距离,然后尝试将其扩展到第 7 个盘。对于每个已知的盘的选择,你已经知道了从明文到密文的距离,因此扩展过程会相当快速。
*8.2 仅密文解决方案
当没有已知单词时,也可以解密多重密码。这被称为仅密文解决方案。我是第一个找到这种解决方案的人(“解密多重密码的计算机方法。” Cryptologia 2 (1978 年 4 月), pp. 152-160)。在原始的 1978 年论文中,我使用了二元频率,并逐步发展到三元组。如今的计算机速度更快,存储更多,所以我们可以跳过二元组步骤。该方法假设你有一张表,列出了英语中每个可能三元组的概率。你可以自己编制这样一张表,或者只需从互联网上下载一个三元组表。以下是该方法的要点。
假设与之前一样,艾米莉正在使用具有 25 个密码字母表的 M-94 设备,并且我们拦截了至少 3 个区块或 75 个字母的消息。我们知道关于消息的一切就是它是用英语写的。例如,假设我们拦截到了

首先尝试前 3 个盘的所有可能选择。有 25×24×23 = 13,800 种这样的选择。对于每个选择,将盘设置为密文每个区块的前 3 个字母,即CLP,ESI和GAF。对于这些三字母组中的每一个,查看其他 25 行。这些行包含与密文三字母组对应的可能的明文三字母组。由于每个 3 行有 25 种选择,所以总的可能性数为 13800×25³ = 215,625,000。这可以很容易地通过台式电脑或甚至笔记本电脑处理。
对于每个 3 个盘和 3 行的组合,该组合的概率是 3 个明文三字母组的概率的乘积。等价地,概率的对数是 3 个三字母组概率的对数之和。这个想法是只保留最有可能的组合并丢弃其余的。例如,你可以只保留前 1%,或者你可以保留一定数量的好组合,也许是最好的 1,000,000 个。假设你选择保留前 2,000,000 个。
一种方法是生成所有 215,625,000 个组合,然后按概率对它们进行排序,并且去掉最低的 99%。这需要大量的存储空间。有更好的方法来做这件事。首先分配一个比你想要的组合数大 10%到 25%的表,比如说 2,500,000 个组合。开始生成这些组合并将它们放入表中。当表满了之后,需要将其减少大约 20%。
通过对表格进行排序并删除底部 20%,可以实现这一点。也就是说,你按照概率降序排序,然后将表格条目数量设置为 2,000,000。对 2,500,000 个项目进行排序比对 215,625,000 个项目进行排序要快得多,但有更快的方法。从表格中随机选择 10 个项目。(如果你不知道如何随机选择,那么选择距离表格 1/11、2/11、...、10/11 处的项目。)将这 10 个项目按照从最不可能到最可能的顺序排序。将这些排序好的项目命名为 a、b、c、d、e、f、g、h、i、j。设 P 为项目 b 的概率。删除表格中概率小于 P 的每个项目。
继续生成组合,但不要向表中添加任何概率小于或等于 P 的项目。每当表填满时,重复抽样、对样本进行排序并重新设置截止概率 P 的过程。
在所有这些步骤结束后,你将获得约 2,000,000 种由 3 个磁盘和 3 行组成的组合。下一步是将此扩展到 4 个磁盘。尝试所有 22 种可能的选择来选择第 4 个磁盘。这将给你约 44,000,000 个组合。现在查看由磁盘 2、3 和 4 形成的三元组。对于每种组合,将磁盘 1、2、3 上的三元组的概率乘以磁盘 2、3、4 上的三元组的概率,以获得所有 4 个磁盘上的四元组的近似概率。将对应于 3 个密文三元组CLPO、ESIW和GAFO的明文四元组的概率相乘。
这将为你提供 4 个磁盘和 3 行的 44,000,000 种组合的概率。同样,你可以保留最佳的 1% 来给你 440,000 组四元组。使用与三元组相同的方法。
以此方式继续获取五元组、六元组、七元组等。每次添加一个磁盘时,你可以保留的组合比上一次少。当你的组合数量少于 100 时,你可以通过眼睛直接选择出正确的组合,并手动完成解决方案。
可能导致此过程失败的一个问题是:即使在普通文本中,也可能出现在你的三元组表中概率为 0 的三元组。如果 Emily 使用了空值,这种情况可能经常发生。这可能导致合法明文被拒绝。
一种解决方案是调整三元组概率,使得 0 概率永远不会出现。让 P(x) 表示字符串 x 的概率。如果一个三元组,比如 XYZ,的概率为零,你可以使用 P(X)P(YZ) 和 P(XY)P(Z) 中较大的那个。我建议将这个值除以 3,比如说,因为 XYZ 从未在你的三元组计数中出现过。如果 XYZ 的概率仍然为 0,则使用各个字母。例如,将 P(XYZ) 设置为 P(X)P(Y)P(Z)/10。
另一种解决方案是不要将概率相乘,而是使用其他函数将它们组合起来。例如,你可以将概率的平方和相加。这将强烈奖励常见的三元组,而大部分忽略罕见的三元组。
如果所有这些方法都失败了,那么就从密文中的另一个起始点再次尝试该过程。例如,从第五个磁盘开始。
第九章:分数化
本章涵盖
-
Polybius 方阵
-
将一封信拆分成较小的部分,如比特或十六进制数字
-
混合和重新组合这些部分
密码学的前两个基本工具是替换和置换,这些内容涵盖在第 5 至 8 章。密码学的第三个基本元素是分数化。这意味着将语言的正常单位,即字母、音节和单词,拆分为较小的单位并对这些单位进行操作。较小的单位通常是比特、十进制数字、十六进制数字或其他进制的数字。本章涵盖了使用 2、3、5、6 和 16 进制的数字进行分数化,以及其他形式的分数化。
9.1 Polybius 方阵
可能是将字母表示为较小单位的最古老方法是Polybius 方阵,我们在第 4.4 节中看到过。在这里,每个字母由两个基数 5 位数字表示,共有 25 种可能的 2 位数字组合。(希腊人没有 0 的表示,因此他们的数字从 1 开始。)
这是第 4.4 节的 Polybius 方阵。每个字母都用方阵中的坐标表示,即通过其行号和列号表示。例如,字母 P 在第 2 行第 5 列,因此表示为 25。需要时,为了清晰起见,也可以写成 2,5。

Polybius 方阵本身可以产生多种不同的密码。例如,它可以通过用方阵中右边的字母(U 变成V)、下面的字母(U 变成Z)、下面和右边的字母(U 变成S)或左边的字母(U 变成P)等方式产生简单的替换。这个想法可以通过改变方向来扩展为多表密码,比如向右、向左、向下、向右、向左、向下等。你也可以走 2 个字母的距离或使用象棋中的骑士走法。
Polybius 方阵也可以用于生成Polybius Ripple密码。首先,将消息中的每个字母替换为其坐标,简单地写在一行中。从此列表中的第二个数字开始,将前一个数字加到当前数字上。如果总和超过 5,减去 5 以保持数字在 1 到 5 的范围内。然后再次使用 Polybius 方阵将这些数字转换回字母。

Polybius 涟漪密码评级为三。通过使用不同的 Polybius 方阵将坐标转换回字母,可以加强密码。
让我们看一下基于 Polybius 方阵的几种手写密码,涵盖在第 9.2 至 9.7 节。我在第 9.8 至 9.11 节中介绍了一些额外的手写方法。然后我在本章的其余部分讨论了一些计算机方法。
9.2 Playfair
普莱费尔密码是由查尔斯·维特斯通(发音为 WHIT-stun)于 1854 年发明的。维特斯通在电气工程师中以发明维特斯通电桥而闻名,该电桥用于测量电阻。维特斯通和威廉·库克在塞缪尔·摩尔斯发明他的键式电报几年前就发明了指针电报。库克在英格兰商业化了指针电报,比摩尔斯在美国成立电报公司早了几年。
维特斯通的密码被称为普莱费尔密码,因为维特斯通的长相类似的朋友利昂·普莱费尔男爵(两人都有红头发,身高约 5'2'')主张使用它,并说服英国外交部在外交通信中使用该密码。
历史插曲
由于这个密码并不被称为维特斯通密码,这使得维特斯通的名字可以用于他大约在 1860 年发明并在 1867 年巴黎世界博览会上展示的第二个密码。维特斯通密码机看起来像一个大口袋手表,由两个固定的硬纸板同心圆环和两个可移动的时钟指针组成,通过简单的钟表机制连接。内环可擦拭,每条消息都可以更改。这个环上有乱序的 26 个字母表,而外环有标准的 26 个字母表加一个空格,共 27 个位置。您将长时钟指针移动到外环上的明文字母位置,短指针移动到内环上的密文字母位置。当长时钟指针完成 27 个位置的一次旋转时,短指针也会移动 27 个位置,即完成一次完整的旋转再加上 1 个额外的字母位置。因此,短指针在每次旋转时都从不同的位置开始。相当于具有可移动环而没有指针的设备于 1817 年由军械长德西厄斯·沃兹沃斯制造,该设备基于托马斯·杰斐逊于 1790 年制定的计划,但维特斯通的名字永远与这个概念联系在一起。
照片由拉尔夫·辛普森提供。铭文如下
“密码学。C.维特斯通 Inv^r。”

普莱费尔密码基于波利比奥斯方阵,每次加密两个字母。也就是说,它加密的是双字母组。方阵可以通过使用第 5.2 节中的任何方法混合字母来准备。为了使字母适应 5×5 方阵,会省略一个低频字母,如 J、Q 或 Z。(在法语中,J、Q 和 Z 很常见,所以省略 W。在德语中,省略 Q、X 或 Y。)当省略的字母出现在消息中时,会选择其他字母替换它。在我们的例子中,每个 J 都被I替换。
下一步是将信息分成二元素,例如 ME ET ME TO MO RR OW。如果一个二元素是双字母的,则应该将其分开,通常是通过在中间插入一个 X 来实现。(这是不应该从方块中省略 X 的一个很好的理由。)另外,如果消息包含奇数个字母,则在末尾添加一个 X。消息变为 ME ET ME TO MO RX RO WX。现在我们准备好加密它了。
普莱菲尔有 3 条规则:(1)如果两个字母位于同一行,则每个字母都被其右侧的字母替换;(2)如果字母位于同一列,则每个字母都被其下方的字母替换;(3)对于所有其他字母,每个字母都被二元素的另一个字母所在的同一行中的字母替换。理解方块环绕,因此在第 9.1 节的方块中,Y 的右侧字母是 U,Q 下方的字母是 W。
这些规则可以用坐标来重新表述。让我们要加密的二元素是 r1c1 r2c2,因此第一个字母在第 r1 行第 c1 列,第二个字母在第 r2 行第 c2 列。现在这 3 条规则变为
-
如果 r1 = r2,那么将替换为 r1,c1+1 r2,c2+1。
-
如果 c1 = c2,那么将替换为 r1+1,c1 r2+1,c2。
-
否则替换为 r1,c2 r2,c1。
让我们对我们的样本信息 ME ET ME TO MO RX RO WX 进行加密,看看这些规则是如何起作用的。第一个二元素是 ME。M 和 E 位于不同的行和不同的列,因此适用规则 3。M 位于第 2 行第 4 列,E 位于第 3 行第 2 列。因此,M 被替换为同一行的字母,即第 2 行,与字母 E 相同的列,即第 2 列。第 2 行第 2 列的字母是 S,所以 M 被替换为S。同样,E 被替换为第 3 行第 4 列的字母,即C。
同样地,ET 被DO替换,第二个 ME 被SC替换。字母 T 和 O 位于同一行,因此适用规则 1。它们被替换为其右侧的字母。T 被N替换,O 被Q替换。所以 TO 被替换为NQ。
MO 按照规则 3 进行。它被替换为SR。R 和 X 位于同一列,因此适用规则 2。RX 被替换为XM。RO 和 WX 都使用规则 1,被替换为TQ和XY。因此整个消息变为SC DO SC NQ SR XM TQ XY,在重新分组后变为SCDOS CNQSR XMTQX Y。
这里有一些图表可以帮助你形象化地理解大二元素 LY、TO 和 RX 是如何被加密的。

普莱菲尔密码一直被军事和外交用途使用,至少持续到 1960 年。接下来,让我们简要地看一下普莱菲尔密码如何被解密。
9.2.1 解密普莱菲尔密码
请注意,每个字母只能由其所在行上的其他 4 个字母和其下方的字母替换。对于每个字母,在网格中有其他 24 个字母。其中,只有其所在列中的 4 个字母会导致该字母被其下方的字母替换。因此,被下方字母替换的概率为 4/24,或 1/6。因此,它被其所在行上的另一个字母替换的概率为 5/6。
由于方格中有 5 行,而英语字母中频率超过 5% 的有 9 个字母,因此至少有几行包含至少 2 个高频字母。如果这样的行少于 4 行,则必须至少有一行包含 3 个高频字母。这些行中的其他字母在密文中将比任何其他字母更频繁地出现。如果您有足够的密文,那么密文中出现频率最高的 3 到 5 个字母很可能在方格的同一行上。
如果我们去除包含这些字母的所有双字母组合,那么剩余双字母组合中出现频率最高的 3 到 5 个字母很可能在方格的同一行上。知道了 5 行中的 2 行上的高频字母就足以开始重建方格了。下一步是尝试放置一些可能的单词。
Playfair 密码的评级为三。有几种方法可以增强 Playfair 密码的强度。我就提几种。
9.2.2 强化 Playfair 密码
这里有几种更强的 Playfair 密码变体。
Nullfair 或 nofair
在密文中可以按照重复的间隔添加空值,就像这样:

Nullfair 的评级为五。
Playfair+1
这种超级简单的增强方式在 Playfair 密文中添加了重复的二进制密钥。在有 1 位的地方,使用字母表的下一个字母。如果二进制密钥的长度为奇数,则 Playfair+1 更强大。

Playfair+1 的评级为五。 Playfair+1 也可以用三进制数完成。加法密钥中的数字保持较小,因此可以在脑中进行加法,而不需要表格。
双 Playfair
Playfair 密码可以通过两次应用来加强。在第二轮中,成对字母应跨越第一轮创建的双字母组合。 (1) 使用 Playfair 密码对消息进行加密。 (2) 将第一个字母移到末尾,将最后一个字母移到开头,或在两端都添加一个空值。 (3) 应用另一轮 Playfair。如果第二个 Playfair 密码使用了不同的混合字母表,则这是最强的。双 Playfair 的评级为六。
Playfair 涟漪
这是双 Playfair 的一种变体,只需通过消息进行一次传递,而且只需要一个 Polybius 方块。让明文为 P[1]P[2]P[3]P[4] ... 从左端开始,使用 Playfair 对明文二元组 P[1]P[2] 进行加密,产生密文二元组 C[1]C[2]。然后将 C[2]P[3] 作为第二个二元组进行加密,得到 D[2]C[3]。注意,D[2] 已经加密了两次。接下来,你将 C[3]P[4] 进行加密,得到 D[3]C[4],依此类推,每一步向右移动一个字符。Playfair 波动被评为 Six。
由于密文的第一个字母 C[1] 和最后一个字母 C[n] 仅加密了一次,因此你可能希望将它们作为一个二元组加密以完成循环。

PolyPlayfair
使用两个不同的 Polybius 方块,并通过使用重复密钥在它们之间交替。例如,密钥为 11212 意味着在每个 5 个二元组的周期中,第一个、第二个和第四个二元组将使用方块 1 进行加密,而第三个和第五个二元组将使用方块 2 进行加密。这可以扩展到三个或更多方块,相应的设置时间会更长。使用两个方块和不超过 10 位数字的密钥,PolyPlayfair 的评级为 Five。如果密钥是由 Chained Digit 算法生成的,当数字为 0 到 4 时使用第一个方块,当数字为 5 到 9 时使用第二个方块,评级会增加到 Six。(注意:使用链式数字序列的奇偶性具有更短的周期,因此它更弱。)
转位
使用 Playfair 密码对明文进行加密后,可以对结果的密文进行转置。转置可以像第 7.2 节的栏转置那样复杂,也可以像第 4.6.1 节的 Bazeries 类型 4 密码那样简单。使用栏转置,Playfair 评为 Seven。使用分段反转,Playfair 评为 Five。
9.3 双方块
Two Square 密码,有时称为 双 Playfair,是 Playfair 密码的改进版本。它是由法国业余密码学家费利克斯·玛丽·德拉斯泰尔(Félix-Marie Delastelle)发明的,并在他的 1902 年著作 Traité Élémentaire de Cryptographie 中描述。顾名思义,它使用两个 Polybius 方块而不是一个,因此有两个混合字母表而不是一个。这两个方块可以水平并排放置,也可以垂直从底部到顶部放置。水平版本如图所示。在此示例中,使用关键词 FIRST 和 SECOND 混合了两个方块,并且省略了字母 Q 以适应 5×5 网格。

与 Playfair 一样,消息每次加密 2 个字母。也就是说,Two Square 加密双字母组。要加密双字母组 SO,我们在左方块中找到 S,在右方块中找到 O。S 的替代字母是右方块中与 S 同一行且与 O 同一列的字母,即T。O 的替代字母是左方块中与 O 同一行且与 S 同一列的字母,即K。因此,双字母组 SO 变成了TK。
与 Playfair 不同,不需要分开双字母。两个字母可以在两个方块的不同行上。例如,SS 变成MK。在大多数情况下,密文中的双��母不会对应于明文中的双字母。
这里是替换过程的可视化展示。

Two Square 密码的一个重要弱点是,当一个双字母组的两个字母在网格中的同一行时,替代字母就是这两个字母的反向。例如,ST 会变成TS。这种弱点被称为透明性,有时会导致整个单词泄露出来。例如,SU ND AY 会变成US DN YA。
为了防止这种情况,我提出了这个相同行规则:当两个字母在同一行上时,它们被它们下面的字母替换,必要时回到顶行。例如,ST 现在会变成DY,VI 会变成FP。
使用相同行规则,Two Square 评级为四。将这种变体称为Two Square B。
德国人字面上采用了“双 Playfair”这个名称。他们使用了 Two Square 密码对每个双字母组进行加密,然后再次使用相同的两个方块进行加密。结果基本上是一个通用的双字母替换(第 6.5 节)。
加强 Playfair 密码所使用的方法也可以用于加强 Two Square 密码,比如TwoSquare+1和Two Square Ripple,评级相同。这里是一个额外的变体。
Playfair TwoSquare
Two Square 密码使用了两个 Polybius 方块。这两个方块中的任何一个都可以用于 Playfair 密码。这提示了一种混合方法,将 Playfair 和 Two Square 结合起来。同样,我们将使用一个数字密钥来控制每个连续双字母组的加密。1 表示使用左方块中的 Playfair 加密双字母组,2 表示使用右方块中的 Playfair 加密双字母组,3 表示使用 Two Square 或 Two Square B 加密双字母组。最好是数字密钥至少包含每个数字。由于 Two Square 比 Playfair 更强大,3 应该比 1 或 2 在密钥中更频繁出现。大约 50% 是合适的。Playfair TwoSquare 评级为六。
9.4 三方块
Three Square 是我的独创想法。否则,它没有特别的优点。我在这里包括它只是因为我在为这本书做研究时阅读的一本书说 Two Square 不能扩展到超过两个方块。我喜欢挑战。
顾名思义,Three Square 使用三个 Polybius 方格。这些方格应该与独立的密钥混合得很好。Three Square 每次加密 3 个字母,也就是加密三字母组合。这比 Two Square 更强大。

基本思想是,每个字母都被其右侧方格中的一个字母替换。替换字母与原字母在同一行,但在下一个三字母组合中的列中。
假设我们希望加密三字母组合 THE。第一个字母是 T,第二个字母是 H,第三个字母是 E。我们使用第一个方格中的 T,第二个方格中的 H 和第三个方格中的 E 进行加密,就像这样。

T 的替代字母位于包含 T 的行,以及第二个方格中包含 H 的列,所以 T 被替换为V。H 的替代字母与第三个方格中包含 E 的列上的 H 在同一行,所以 H 被替换为R。E 的替代字母与第一个方格中包含 T 的列上的 E 在同一行,所以 E 被替换为Z。因此,THE 变成了VRZ。
这可以如下图所示:

解密是相反的过程。由于密文三字母组合VRZ的第一个字母来自第二个方格,我们从第二个方格开始解密,像这样:

Three Square 比 Two Square 更容易出现字母位于同一行的问题。在 XYZ 这样的三字母组合中,可能出现 X 和 Y 在同一行,Y 和 Z 在同一行,或者 Z 和 X 在同一行。这需要额外的两条规则来防止透明度,其中一个字母表示它自己。
规则 1: 如果三字母组合中连续的两个字母位于同一行,则这两个字母中的第一个被加密为第二个字母的右侧字母,如果需要则绕到左侧列。例如,在三字母组合 SUB 中,S 在第一个方格的顶行,而 U 在第二个方格的顶行。因此 S 被替换为V而不是U。类似地,在三字母组合 LET 中,T 在第三个方格的第三行,而 L 在第一个方格的第三行。所以 T 被替换为G而不是L。
这个图示说明了规则 1。没有规则 1,在三字母组合 SUB 中,S 将被U替换。相反,它被中间方格中 U 右侧的字母替换,即V。没有规则 1,在三字母组合 LET 中,T 将被L替换。相反,它被左方格中 L 右侧的字母替换。这从第 5 列绕到第 1 列,其中有字母G。

规则 2: 如果三元组中的所有三个字母都在同一行上,那么每个字母将被其下方的字母替换,如果需要,将回到顶行。因此,FUN 将被替换为AZV,而 WRE 将被替换为IXL。
根据这些规则,三方格被评为五。
Playfair ThreeSquare
三方格密码使用三个波利比斯方格。这些方格中的任何一个都可以用于 Playfair 密码。这表明了一种混合方法,将 Playfair 和三方格密码混合在一起。您可以使用数字密钥,例如 1,4,1,3,4,2,4 来控制每个连续的二元组或三元组的加密方式。1 表示使用第一个方格中的 Playfair 将下一个 2 个字母加密为二元组。2 表示使用第二个方格中的 Playfair 将下一个 2 个字母加密为二元组。3 表示使用第三个方格中的 Playfair 将下一个 2 个字母加密为二元组。4 表示使用三方格将下一个 3 个字母加密为三元组。最好是数字密钥至少包含每个数字。由于三方格比 Playfair 更强大,数字 4 应该比数字 1、2 或 3 更频繁地出现在数字密钥中。大约 50% 的频率是合适的。也就是说,4 应该与 1、2 和 3 的总和一样频繁出现。同样,生成从 1 到 6 的随机数,并使用 4、5 或 6 进行三方格加密。
由于 Playfair ThreeSquare 混合了二元组和三元组,大约一半的二元组和三分之二的三元组不会落在偶数边界上。这意味着强度的增加比 Playfair TwoSquare 的增加更大。Playfair ThreeSquare 被评为七。
可以将 Playfair、Two Square 和 Three Square 结合成一个更复杂的密码,毫无疑问具有更强的强度,但是 Playfair ThreeSquare 已经在推动人类代码员的极限。速度和准确性都会受到影响。
还有一种相反的方法,我称之为跨三方格。将明文分组成包含每行四个 3 个字符块的行。使用三方格密码对每个块进行加密。现在,取第一个块的最后一个字母和第二个块的第一个字母,并使用第一个波利比斯方格的 Playfair 密码对该二元组进行加密。取第二个块的最后一个字母和第三个块的第一个字母,并使用第二个波利比斯方格的 Playfair 密码对该二元组进行加密。取第三个块的最后一个字母和第四个块的第一个字母,并使用第三个波利比斯方格的 Playfair 密码对该二元组进行加密。这样可以提高三方格密码的强度,而不会增加太多复杂性或时间。始终使用相同行规则。
9.5 四方格
四方密码是由 Félix-Marie Delastelle 大约于 1890 年发明的,并在他于 1902 年去世后的 3 个月出版的书籍Traité Élémentaire de Cryptographie中描述。Delastelle 在四方密码之后发明了双方密码,作为简化且稍微不那么安全的版本。然而,使用第 9.3 节中描述的同行规则,可以认为这两种密码的强度相等。
如其名称所示,四方密码利用四个 Polybius 方块。其中两个方块包含标准字母表,另外两个方块包含使用独立密钥混合的字母表。消息以两个字母为一组进行加密,即四方加密二元组。
这是一个示例排列。

加密使用熟悉的矩形方案。您在标准字母表中定位两个明文字母,并将它们替换为矩形对角线上的字母,如下所示:

由于两个明文字母永远不可能在 10×10 网格的同一行或同一列中,因此无需特殊规则或分隔双字母。唯一需要空字符的情况是为了完成最后一个双字母组合。四方加密的评级为五。
循环方法
要获得更大的强度,您可以使用类似于第 4.6.1 节中的分段反转的简单换位。此换位使用重复的数字密钥,例如 1、3、1、4、2、6。将密文分成 7 个字符或任何其他奇数长度的块。在每个块的上方写下连续的密钥数字。然后将每个块左移其密钥数字指示的位置数。例如,如果密钥数字是 4,则将最左边的 4 位数字移动到块的右端。这是一个例子:

使用循环方法的四方加密的评级为六。
分半方法
加强四方加密的另一种方法是事先转置消息。假设消息是 AMBASSADOR WILKINS ASSASSINATED KABUL TODAY。这有 39 个字母。将 39 除以 2 并四舍五入得到 20。将消息写成两行,每行 20 个字母,并从垂直方向读取双字母组合。使用四方进行这些双字母组合的加密。

这些双字母组合不再具有正常的双字母组合频率或英语双字母组合的正常联系频率。使用分半方法的四方加密的评级为七。
9.6 双分
让我们再看一个基于 5×5 波利比乌斯方阵的历史手工密码。这是双重密码,也是在 19 世纪 90 年代由菲利克斯·玛丽·德拉斯特尔发明的。双重是一个 3 步密码,其中(1)字母被转换为它们的波利比乌斯坐标,(2)这些坐标被重新排列,(3)然后坐标被转换回字母。最初,德拉斯特尔将整个消息写出,坐标垂直写在每个字母下面,然后他将坐标对水平地读出,先横穿顶行,然后横穿底行。
现代方法是将消息分成固定大小的块。块大小应该是奇数,如 5、7 或 9。如果块大小是偶数,则艾米莉可以将块分成二元组。
第一步是将字母转换为波利比乌斯方阵中的坐标。假设块长度为 5。5 个明文字母可以表示为 X1、X2、X3、X4 和 X5。它们的行和列坐标可以表示为 R1C1、R2C2、R3C3、R4C4 和 R5C5。这些 R 和 C 符号各自是从 1 到 5 的数字,先是行坐标,然后是列坐标。这些坐标对是垂直地写在每个块的每个字母下面,像这样:

然后按照 R1R2、R3R4、R5C1、C2C3、C4C5 的顺序读取。这里是一个例子。使用关键词 SAMPLE 混合的波利比乌斯方阵对单词 MAJOR 进行了加密。

请注意,密文中的第三组字母坐标,R5C1,是一个行/列对。这意味着第三个密文字母将来自与第五个明文字母相同的行,R5,以及与第一个明文字母相同的列,C1。这个同时出现行坐标和列坐标的情况被称为自然。
由于方阵中每行有 5 个字母,每列有 5 个字母,所以第三个密文字母与第五个明文字母相同的概率为 1/5,第三个密文字母与第一个明文字母相同的概率也是 1/5。也就是说,R5C1与R5C5相同的概率是 20%,而R5C1与R1C1相同的概率也是 20%。在这个例子中,确实发生了这种情况。第五个明文字母是 R,第三个密文字母也是R。
现在看看第一个密文字母R1R2。这是一个行/行对,而不是一个行/列对。在这里,只有第一个坐标R1处于正确的位置,形成了一个行/列对。另一个坐标R2是列位置上的行坐标。这样的单一放置被称为半自然。它意味着第一个密文字母来自波利比奥斯方阵的与第一个明文字母相同的行。因此,第一个密文字母与第一个明文字母相同的机会为 20%。
第二、第四和第五个密文字母也是如此。它们中的每一个都落在明文字母的同一行或同一列中的一个。因此,它们每一个有 20%的机会与该明文字母相同。在这个例子中发生了这种情况,第二个密文字母J与第三个明文字母相同。
这是 bifid 密码的一个严重弱点,使得 Emily 能够猜测并放置可能的单词。另一方面,如果明文和密文字母不同,则知道它们位于同一行或列中。在本例中,第一个明文字母R1C1是 M,第一个密文字母R1R2是S。这意味着 M 和 S 必须在波利比奥斯方阵的同一行中。当 Emily 推断或猜测一个单词时,这提供了几个这样的等价物。这反过来又使得放置其他单词变得更容易。当积累了足够多的这些字母对时,Emily 可以重构方阵。
由于这些弱点,bifid 密码评分为三。
9.6.1 共轭矩阵 bifid
这些问题可以通过使用不同的 Polybius 方阵将坐标转换回字母来消除。例如,方阵 2 产生的密文是VBJEF。

两个单独的波利比奥斯方阵组成的双重 Polybius 方阵被称为共轭矩阵 Bifid。在这个上下文中,矩阵只是指一个字母或字符的矩形数组。共轭矩阵 bifid 密码评分为五。
有几种方法可以增强 bifid 密码的强度。一种方法是使用重复的数字密钥来改变块长度,例如 5、11、7。块长度将是该密钥的循环重复,即 5、11、7、5、11、7、5、... 如果您愿意,您可以通过使用链式数字生成器生成块长度,并将数字翻译为奇数块长度。一种可能性是

因此,如果生成器生成数字 3、6、2、7,...,那么块长度将为 11、7、9、9、...
使用短重复密钥和共轭矩阵的密码评分为六。使用长重复密钥或使用随机数生成器生成块长度的密码评分为七。
另一个类似的想法是从每个块的不同起点开始读出坐标。你可以使用一个数字密钥来指定起点的顺序。如果块的长度为 L,密钥中的每个数字可以是从 1 到 2L 的任何位置。从 1 到 L 的数字表示坐标顶行的起始位置,而从 L+1 到 2L 的数字表示底行的起始位置,就像这样:

坐标将成对地从左到右读取。这是使用数字密钥 4、9 读取坐标的顺序。起始位置 4 和 9 已经阴影化。

这种方法将评级提高到六。
加强双重栅栏密码的另一种方法是使用更强的置换来混合坐标。使用长度为 L 的标准双重栅栏将 2L 个坐标写入 2×L 块中。坐标被垂直写入块中,水平读出。我们将其识别为一个非常简单的路径置换,描述在第 7.1 节。在第七章中涵盖了几种更强的置换,尤其是列置换。这种密码的一个例子是由情报官尼布尔中尉发明并由德国人在第一次世界大战中使用的ADFGVX密码。在 ADFGVX 密码中,由字母 A、D、F、G、V、X 表示的坐标通过列置换混合,然后作为这些字母的字符串传输。这种密码的评级为五。
如果你使用更长的块,比如 20 个字符,那么将会得到 40 个坐标。(使用这种方法,块的长度可以是偶数也可以是奇数。)这足以有效地使用列置换来混合坐标。或者,你可以回到德拉斯泰尔的原始概念,并将整个消息的坐标作为单个块。无论哪种方式,使用共轭矩阵,此密码的评级为八。使用双列置换,密码的评级为十。假设有四个长的独立密钥和混合良好的字母表,这是一种无法破解的纸笔密码。称之为双列置换双重栅栏。
9.7 对角双重栅栏
对双重栅栏密码的变种是将波利比斯坐标垂直地写在每个字母下面,然后沿对角线从左下到右上(或从西南到东北)读取它们。这被称为左对角线或反对角线。(在纹章的冠上,它被称为邪恶的酒吧,并表示非婚生的出生。)对于最后一个字母,你会回到第一列(阴影部分的数字 1)。这样做的好处是没有自然数或半自然数可以帮助艾米莉猜测单词。这是一个例子。

对角 bifid 被评为 Four。与共轭矩阵一起,它被评为 Five。与共轭矩阵和定期变化的块大小一起,它被评为 Six。与古典 bifid 不同,对角 bifid 可以使用奇数和偶数块大小。
9.8 6×6 方阵
如果你的消息包含很多数字,使用 6×6 的 Polybius 方阵而不是 5×5 方阵可能会更有优势。6×6 方阵允许您使用完整的 26 个字母表以及从 0 到 9 的数字。不需要从字母表中省略 J 或 Q。如果你正在手动加密,这就需要额外小心地区分字母 O、I、Z、S 和 G 与数字 0、1、2、5 和 6。一些人采用特殊的惯例,例如在所有数字下划线。我觉得这样很麻烦且容易出错。我通常只是夸大区分这些字符与它们的同伴的特征,例如用额外宽的衬线写字母 I。
前面 5 节中的所有方法,即 Playfair、Two Square、Three Square、Four Square 和 Bifid,都可以与 6×6 方阵一起使用,以及它们的所有变体。
9.9 三重置
如果你喜欢方阵,那么立方体呢?另一种分数方法,也是在 1890 年代由 Félix-Marie Delastelle 发明的,是 Trifid 密码。与通过在基数 5(五进制数)中的两位数字来代表字母不同,每个字母由三位基数为 3 的数字(三进制数)表示。这给出了 3×3×3,或 3³,不同的 3 位数字组合。这足以表示字母表中的所有 26 个字母加上一个额外的字符。Delastelle 使用了一个 + 加号表示第 27 个字符。
额外的字符 + 可以用作标点符号的形式,或者它可能是一个信号,表示接下来的明文字母应该被解释为一个数字。对应关系 +A = 1, +B = 2, ... , +J = 0 可以被使用。字母表的其余部分也可以被用作特殊字符。例如,+K 可以表示句号,+L 可以表示逗号,等等。
就像 2 位数字组合可以显示为 5×5 字母方阵一样,3 位数字组合可以显示为 3×3×3 字母立方体。每个三元组中的 3 位数字可以被解释为该字母位于的立方体中的坐标。这些坐标通常称为层、行和列。
这里是 27 个三元组合,按顺序排列,字母等效通过使用关键词 EXAMPLE 弱混合,并交替列。例如,字母 N 由三元组 102 表示,因此它将位于 3×3×3 字母立方体的第 1 层、第 0 行和第 2 列。

三方加密器的工作原理与双重加密器类似。明文按固定大小的块写入。大小可以是任何不是 3 的倍数的数字。将这 3 位数字垂直写在每个消息字母下面,然后水平分组读取。然后使用相同的等价关系将它们转换回字母。这里有一个明文为 SEND HELP,块大小为 4 的示例。

用于双重加密器的相同分析和技术也可以应用于 trifid,并且具有相同的评级。您可以使用两个单独的替换表将字母转换为数字,然后将数字转换回字母。您可以变化块的大小。您可以从每个块的不同位置开始读取数字。您可以使用强大的置换来混合三进制数字。
一个自然的问题是是否有与对角双重加密器类似的对角 trifid 加密器。对角双重加密器比原始双重加密器的优势在于,对角版本不会产生削弱原始版本的半自然数。在类似的对角 trifid 中,每组的中间数字将是第三自然数,因此失去了优势。然而,如果您使用两个不同的混合字母表,一个用于数字的书写,另一个用于读取它们,则自然问题会消失。带有两个字母表的对角 trifid 的评分为五。
9.10 三方加密器
当我在打前面关于 trifid 加密器的段落时,我意识到 3×3×3 的立方排列非常适合于描述第 9.3 节中描述的双重加密器的三维类比。在两个维度中很容易想象双重加密器,但在三个维度中很难想象一个立方体,因此我将仅根据坐标描述新的加密器。让我们将此加密器称为 三方加密器。
两方加密器一次加密两个字母,使用两个替换表,因此三方加密器会一次使用三个替换表加密三个字母。这里是使用关键字 COLUMBIA、STANFORD 和 HOPKINS 很好地混合了的三个表。这三个替换表分别标记为 S、T 和 U。这里的 S 表示替换(Substitution),T 表示表(Table),U 表示字母表中的下一个字母。
替换表对应字母表的 26 个字母和字符 + 与 27 个三元组。

与 trifid 类似,三方加密器首先将每个字母的 3 位数字三元组垂直写在其下方。第一个字母的 3 位数字来自替换表 S,第二个字母的 3 位数字来自表 T,第三个字母的 3 位数字来自 U。该模式在此处显示,并由三元组 FLY 进行说明。

然后从左到右读出数字,并将这些水平三元组转换回字母。使用表 S 转换顶行,表 T 转换中行,表 U 转换底行似乎很自然。然而,这会导致顶行与左列相同的概率为 9 分之 1,因此第一个明文字母将被自身替换。也就是说,S1S2S3 与 S1T1U1 相同的可能性为 9 分之 1。中行和底行也是如此。让我们将这种情况称为部分自然。
为此,第二行使用替换表 S,第三行使用表 T,顶行使用表 U。这样就消除了自然性。以下是模式。

由于手动加密时很难保持清晰,我建议在每个数字三元组上面写上替换表的选择。这类似于使用贝拉索密码(第 5.5 节)时在每个明文字母上写上密钥字母。以下是使用明文消息 FLY TO ROME 的三方块加密的示例。

三方块密码的评级为七。
有一种简单的方法可以加强三方块密码。不再像刚才那样使用三个替换表严格轮换地将三元组转换回字母,而是使用一个密钥来设置读出表的顺序。该密钥将由字母 S、T 和 U 以某种打乱的顺序组成,例如 SUTUTTUUSTS。这个密钥的长度不应该是 3 的倍数。我将这个变种称为三方块加密。以下是使用这个读出密钥对 FLY TO ROME 进行加密的方法。

使用三方块加密,大约有三分之一的字母会有部分自然性。也就是说,三个填写数字中的一个将与三个读出数字中的一个相同。然而,艾米丽不会知道哪些字母有这种缺陷,也无法利用它。
三方块加密的评级为九。
因此,你可能会说,是否可能将评级提高到十,而不使密码对手工使用过于复杂?感谢你的提问。首先,让我们将替换表的数量从 3 增加到 6。让我们称它们为 S、T、U、V、W 和 X。我们将不再使用严格的 STU、STU、STU...轮换写入三元组,而是使用另一个字母密钥,该密钥由这 6 个字母以某种打乱的顺序组成。填写密钥可以是 TWXUSTTVWV,读出密钥可以是 VWTXXSUSVTU。理想情况下,这些密钥的长度应该是互质的,并且两者的长度都不可被 3 整除。在这里,长度分别为 10 和 11。我们将这个密码称为三方块超级密码。这是一个使用明文 FLY TO NEW YORK 的三方块超级密码的示例。

三方块超级密码的评级为十。这是另一种不可破解的手工加密。
9.11 矩形网格
到目前为止,我们只讨论了字母的方形和立方体阵列。在密码学中,没有要求字母网格的所有维度都相同的限制。英文字母表有 26 个字母基本上是历史的偶然。如果我们使用 33 个字母的俄语字母表,我们可能会选择 4×8 或 5×7 的矩形。
如果我们想要所有 26 个字母的字母表,那么 3×9 或 4×7 的矩形可能更可取。这些给您提供了完整的 26 个字母的字母表,再加上一个或两个额外字符。我们之前已经讨论过这些额外字符的使用,例如用于在字母和数字之间切换。基于波利比奥斯方格的大多数密码与 5×5 方格一样适用于 3×9 或 4×7 的矩形,假设所有矩形都以相同的方向排列。这些是 Playfair、Two Square、Three Square、Four Square 和对角线 bifid 密码。
实际上,当与那些矩形一起使用时,这 5 种密码可能更强大,因为字母表中的每个字母都有更多可能的替代字符。使用 Playfair 或 Two Square 时的缺点是,两个字母在同一行的概率较高,因此它们将被其下方或右侧的字母替换。
下面是使用 3×9 矩形进行 Playfair 密码的示例:

9.12 十六进制分数
到目前为止,本章仅专注于手动方法。这意味着仅使用大写字母的小数组。对于计算机使用,通常希望使用完整的字母表,包括大写和小写字母、数字、标点符号、特殊符号、音标,以及可能是多个字母表。简而言之,您可能希望拥有计算机的完整文本功能。做到这一点的最简单方法是使用标准计算机代码之一,如 UTF-8 或 UTF-16,将每个字符表示为一个 8 位字节。
将 8 位字节分数化的一种自然方式是将其拆分为两个 4 位十六进制数字,或十六进制数字。所有基于波利比奥斯方格的分数化方法也适用于 16×16 方格,即 Playfair、Two Square、Three Square、Four Square 和 bifid。如果 16×16 方格使用大密钥混合得很好,那么这些方法比使用 5×5 方格的同一方法更强大。这是因为 256 个字符的排列方式远远多于 25 个字符的排列方式,即 8.58×10⁵⁰⁶与 1.55×10²⁵。
使用十六进制分数化的简单方法是:(1)通过使用混合得很好的密钥替换表将消息的字符转换为十六进制数字,(2)使用一些置换密码对这些数字进行混淆,然后(3)使用第二个混合得很好的密钥替换表将十六进制数字的对转换回字节。
最简单的转位法就是将第一个十六进制数字移到末尾,这样 12 34 56 78 就会变成 23 45 67 81。这可能被称为 Cycle Hex。它本质上是对角线的二重置位(第 9.7 节),只不过是在基数为 16 而不是基数为 5 下进行的。Cycle hex 评级为 Five。你也可以使用第 4.6.1 节描述的逐段反转置换来打乱字母顺序。这可能被称为 Piecewise Hex。它也评级为 Five。一种更强大的方法是使用列转位密码来打乱十六进制数字。这可以称为 Columnar Hex。它评级为 Seven。使用双列转位置换后,评级增至 Ten。
这些方法可以用于对任何计算机文件进行加密。但是,如果文件是纯文本,则可以进一步增强这些方法。纯文本通常会使用少于 256 个可能的字节值中的 100 个以下。其余的字符代码可以用于空值、双字母组、三字母组和第 6.4 节描述的其他用途。如果做得好,这会将 cycle hex 的评级提升至 Six,piecewise hex 的评级提升至 Six,columnar hex 的评级提升至 Eight。
9.13 位级分数化
分数化也可以用于表示消息中代表字符的各个位。长度为 N 的字符块将由 8N 位表示。这些可以以几种方式形成矩形,例如 2×4N、4×2N、8×N 和 N×8。例如,5 个字母的块将由 40 位表示,可以写成 2 行 20 位、4 行 10 位、8 行 5 位或 5 行 8 位。这对手工操作来说很麻烦,但在计算机上很容易实现。
这是一个示例,展示了如何将 5 个字符水平写入一个 5×8 的块中,然后垂直读出。此示例使用标准的 UTF-8 字符代码。例如,大写字母 A 表示为 01000001。明文是单词 DELTA。

位按列向下读取。由于每列只包含 5 位,因此每个密文字节必须跨越两列或更多列。第一个密文字节的 8 位位于列 1 和列 2 中,并用中等高亮度显示。第一列包含 00000,第二列的前 3 位为 111,因此密文的第一个字节为 00000111,或十六进制 07。这是控制字符 BELL,可以追溯到电传打字机时代,当时会发出退格铃声。它现在已经没有图形表示。我会用符号 ♪ 来代表铃声字符。
第二个密文字节来自跨越列 2、3 和 4 的较暗突出部分。第二列的最后 2 位是 11,第三列包含 00000,第四列的第一位是 0。结合这些,第二个密文字节为 11000000。这代表字符 À,是一个带重音符号的大写字母 A。
密文的第 3 和第 4 个字节是“和x,即双引号和小写字母 x。第五个字节来自第 7 和第 8 列,即 000 和 01001。字节 00001001 代表HTAB,或水平制表符,是看不见的。我将使用箭头头部►来表示它。因此密文是♪À“x►。
这看起来很神秘,但这种方法很弱,因为它在将明文转换为比特和将比特转换回字符时使用了标准字母表。它被评为一。如果这些步骤使用了两个独立的混合密钥字母表,则此密码只是共轭矩阵双字母变体(9.6.1 节)的二进制版本。这种方法可以称为Hex Rectangle。它与共轭矩阵双字母变体密码具有相同的评级,即五。
自然地将八个 8 位字节形成一个 8×8 比特方块。使用一个混合字母表将每个字符的 8 位写入方块中,并使用另一个混合字母表水平地读取它们。这只是十六进制矩形的一个 8×8 方块版本,评级为六。
9.13.1 循环 8×N
提高此密码的强度很容易。对于任何 N 个字符的块,垂直地将它们的 8 位表示写入 8×N 的矩形中。将每行循环地向左移动 0 到 N-1 位位置。例如,abcdefgh 循环左移 2 个位置将得到 cdefghab。然后垂直地读取每个 8 位列。这里有一个使用 8×8 比特方块的示例。每行都按其左侧指示的量向左循环。

这种密码已经达到了手工操作的极限。它需要 3 个密钥,即两个用于混合两个字母表的密钥,以及一个用于指定位移量的 8 位数字密钥。它可以称为Cyclic 8×N。当 N 为 6 或更大时,它被评为七。随着块大小 N 的增加,密码变得更强大。
当矩形是正方形时,你可以同时旋转行和列,得到一个Bicyclic 8×8密码。你应该交替方向进行。水平写入位,垂直循环位,水平循环位,然后垂直读取字符。Bicyclic 8×8 被评为八。
循环 8×N 密码可以重复以获得双循环 8×N密码。这需要 5 个密钥,即 3 个用于混合 3 个字母表的密钥,以及两个用于控制 2 轮移位的 8 位密钥。共有 5 个步骤。(1)使用第一个字母表进行简单替换。生成的 N 个字节被垂直地写入 8×N 位的矩形中。(2)使用第一个移位密钥循环移动行。(3)使用第二个字母表对 N 列执行简单替换。(4)使用第二个移位密钥循环移动行。(5)使用第三个字母表对垂直列执行最终的简单替换。注意,所有的移位都是水平的,所有的替换都是垂直的。双重循环 8×N 密码的评级为九。
如果需要,可以继续进行三重、四重等等。所有这些变化都可以通过周期性地或使用随机数发生器来变化块大小来进一步增强。
9.14 其他分数
在第 9.12 和 9.13 节中,我们看过将一个字节分成两个十六进制数字或分成八个单独的位。将 8 位分成许多其他方式,如 3,2,3。如果将每个字符的 3,2,3 位表示垂直地写下来,然后将 3 行按某个位置数循环向左移动,那么每一列仍然会有 3,2,3 位的分布,因此 8 位可以被转换回字节。这里是一个例子。每一行按左边显示的位置数循环左移,即分别为 1 个位置,3 个位置和 2 个位置。

这里明文 RETEAT 已经被转换成了密文@w«θK_****╝。我们称之为BitCycle Substitution。这种方法的评级为五。与第 9.13.1 节中的循环 8×N 密码一样,这可以加倍、三倍或更多,并且块大小可以变化。
这个基本思想可以以两种强大的方式进行增强。
首先,字节可以被分成几种不同的方式,例如 1,3,2,2 或 2,4,2。例如,你可以首先使用 3,2,3 的分割方式对块进行加密,然后使用 1,3,2,2 的分割方式重新加密,然后再使用 2,4,2 的分割方式重新加密。这将涉及 7 个密钥和 7 个步骤。(1)使用第一个替换产生消息的 3,2,3 位表示。(2)使用第一个移位密钥移动 3 行。(3)使用第二个替换产生字节的 1,3,2,2 位表示。(4)根据第二个移位密钥移动 4 行。(5)使用第三个替换产生字节的 2,4,2 位表示。(6)根据第三个移位密钥移动 3 行。(7)使用第四个替换产生最终的密文字节。
其次,消息区块可以以几种不同的方式划分。假设你使用长的明文区块,比如 32 个字符。对于前一种技术的第 2 步,你可以将 32 字节分成 6、14 和 12 字节的组。对于第 4 步,你可以将 32 字节分成 11、8 和 13 字节的组。对于第 6 步,你可以将 32 字节分成 8、17 和 7 字节的组。每个组都将独立移位。这种划分对每条消息可能是不同的。
或者,你可以采取更包容的方法。对于第 2 步,将整个消息划分为大小为 X 的区块。对于第 4 步,将消息划分为大小为 Y 的区块。对于第 6 步,将消息划分为大小为 Z 的区块。X、Y 和 Z 的长度可以是从 6 字节到整个消息长度的任意长度。
我不会评价所有 BitCycle 替换的变体。可以说,评级可能从五到十不等。在第十二章中,我将描述如何验证一个区块密码是否真正值得得到十分评级。
9.15 更强大的区块
本章描述的几种密码技术适用于明文区块。有几种方法可以对明文区块进行处理,使你的密码对艾米莉来说稍微困难一些。以下是一些想法的简短列表:
-
周期性或伪随机地改变区块长度。
-
反转每个区块的前几个字母,周期性或伪随机地。
-
反转每个区块的最后几个字母,周期性或伪随机地。
-
周期性或伪随机地将每个区块向左或向右循环。
-
将区块的最后 N 个字母与下一个区块的前 N 个字母交换。
但要警告一句:如果你手动加密和解密,请谨慎使用这些方法。如果你使你的密码变得如此复杂以至于无法准确加密和解密,那么它就变得毫无价值。
第十章:可变长度分数化
本章涵盖
-
基于摩尔斯电码的密码
-
混合字母和双字母
-
可变长度二进制码字
-
基于文本压缩的密码
本章涵盖了一系列广泛的分数化密码,其中明文组和/或密文组具有可变长度。 这些包括单体-双体(第 10.2 节)、哈夫曼替代(第 10.4 节)和 Post 标签系统(第 10.5 节)。
在第 4.4 节中,我用 M. E. Ohaver 的分数化摩尔斯密码的两个版本描述了分数化的概念。 分数化摩尔斯是可变长度分数化的示例,因为它使用 1、3 和 4 个符号的摩尔斯组。 让我用一个类似于第 9.9 节中描述的三重密码的不同形式的摩尔斯分数化来开始可变长度分数化的更广泛讨论。 让我们称之为 Morse3。
10.1 Morse3
Morse3是一个分为 4 步的密码。(1)用摩尔斯码组替换消息的字母。 您可以使用标准摩尔斯码,也可以使用第 4.4 节中的混合摩尔斯字母。 (2)使用/符号分隔摩尔斯组。 使用双//来分隔单词并标记消息的结束。 (3)将符号分成 3 个组。 如果需要,附加额外的·或··以完成最后一个 3 个符号的组。 收件人将忽略在最后//之后的这些额外点。 (4)使用第二个混合字母表为每个 3 个符号组替换一个字母。
为了说明,我将使用第 4.4 节中的混合摩尔斯字母(在这里显示在左侧)来形成摩尔斯组。 这仅使用 1、3 和 4 个符号的组,但也可以使用 2 个符号的组,例如作为空或同音字。 从摩尔斯符号到字母的替换使用了一种类似于三合一密码的混合字母表,只是使用了摩尔斯符号· - /,而不是数字 0 1 2. 请注意,///永远不会出现,因此不必提供它的字母替代。 因此,只需要 26 个替代品。

让我们对样本消息 SEND AMMO 进行加密。

如果在替换步骤中使用了混合的键入字母表,则此密码被评为五。 Morse3 的一个缺点是密文比明文要长。 在此示例中,8 个字母的明文变成了 11 个字母的密文。
10.2 单体-双体
Monom-Binom,或Monome-Binome,是一类密码,其中每个字母都被单个数字或一对数字替换。 这些密码中最著名的是VIC密码,由俄罗斯间谍于大约 1920 年至 1960 年使用。 名称来自于联邦调查局给予克格勃间谍 Reino Häyhänen 的代号 VICTOR。 VIC 密码直到 1957 年 Häyhänen 叛逃到美国并泄露其细节之前从未被破解过。
VIC 密码有两部分,单-双替换和模 10 加上一串随机数字的部分。让我们从单-双替换开始。字母表中的每个字母都被 1 或 2 个十进制数字替换。为了让接收方 Riva 能够读取消息,两个数字被选为所有 2 位数对的第一个数字。假设发送方 Sandra 选择了 2 和 5。所有 2 位数的替代字母将以 2 或 5 开始,而其他所有数字都将是 1 位数的替代字母。每当消息中的下一个数字是 2 或 5 时,读者就知道这是 2 位数替代的开始,否则就是单个数字的替代。这些替换可以用一个名为 跨距校验板 的 3 行图表来表示。这个名字并不合适,因为图表不是方形的,不是 8×8 的,也没有交替的黑白方格模式。噢,而且它不是用来玩跳棋的。除此之外,这个名字完美无缺。下面是一个示例:

八个 1 位数的替代字母在顶行,而从 2 和 5 开始的二十个 2 位数的替代字母在第二和第三行。数字 2 和 5 不能用作 1 位数的替代字母,所以这些空格在顶行被涂黑了。例如,S 的替代字母是 4,U 的替代字母是 24,Y 的替代字母是 54。
由于有 28 个方格,而英文字母表只有 26 个字母,所以有 2 个额外的字符,我用 * 和 # 表示。通常使用 * 作为一种通用的标点符号,例如 . ? , “ 或任何其他使消息更易读的符号。# 用于在字母和数字之间切换。消息 600 TANKS ARRIVE 1800 TODAY 将被发送为 #600#TANKSARRIVE#1800#TODAY,并被加密为 57600 57730 21438 86251 57180 05779 58354。
这种类型的替换的一个明显的弱点是,超过 1/3 的替代字母(实际上是 10 个中的 28 个,或者 35.7%)以 2 开头,同样的百分比以 5 开头,因此所选的 2 位数比其他 8 位数要频繁得多。它们将像华尔兹比赛中的大象一样显眼。为了帮助缓解这个问题,将最频繁出现的 8 个字母放在顶行。它们是 ETAONIRS。为了帮助记忆它们,你可以使用 SERRATION 的记忆法,即去掉重复的 R 后剩下的 SERATION。或者,你可以使用我的最爱,RAT NOISE。对于最常见的字母使用 1 位数的替代字母也有助于减少密文的长度。
单独使用时,跨距校验板的评级为三级。
然而,VIC 密码增加了第二步。(在其最复杂的形式中还会对数字进行转置。)单项二项式替换的结果被视为中间密文。对于中间文本中的每个数字,都会添加一个密钥数字,取模 10,也就是说,不带进位地相加。这有两种风格。你可以简单地添加一个重复的数字密钥,比如 2793。它将像这样工作:

VIC 密码的这种形式被评为五级。
*****VIC 密码的一种更强形式是使用由随机数生成器产生的非重复数字密钥。为此,俄罗斯人使用了所谓的滞后斐波那契生成器。你可能已经熟悉斐波那契数列,它是一个整数序列,其中每一项是前两项的和。该序列从 x[0] = 0 和 x[1] = 1 开始。序列的其他项由以下数学公式生成:

也就是说,第 n 项是第 n-1 项和第 n-2 项的和。对于 VIC 密码,只有低位数字是相关的。这可以写成

滞后斐波那契生成器可以通过三种不同的方式推广。首先,它可以添加除最后两个以外的其他项,例如

注意,4.5.1 节中描述的链式数字生成器具有这种形式,其中 j = 1 并且 k = 7。
第二,这些数字可以用不同的模生成。最常见的模是某个素数 p 的某个幂 p^e:

第三,两个项可以使用除加法以外的二元运算符结合。常见的选择有减法、乘法和异或。这可以写成

其中 ● 可以表示 + - × ⊕ 或其他二元运算符。(也可以使用除法。它与乘以第二个操作数的乘法逆元相同。请参阅第 3.6 节。)实际上,最常用的是加法,因为加法生成器产生最长的周期。
使用这种形式的伪随机数字生成器,单项二项式评为七级。
10.3 周期长度
实现可变长度加密的一种简单方法是使用多个替换表,每个所需的块长度一个表。如果这些是字母块,替换表将很快变得庞大。相反,我们将使用位。让消息表示为位字符串。消息通过将其分成短位块并使用该长度的替换表替换相同长度的块来加密。块的长度可以使用重复的数字密钥进行周期性设置,或者可以由随机数生成器产生。
让我用一个小例子来演示。有三个用于 2、3 和 4 比特块的替代表。在实际密码中,我会使用 3、4、5 和 6 比特块,但如果你有存储空间,你可以增加到 16 比特,甚至更长。
对于这个简单的演示,我使用了一个标准字母表,通过从键盘的顶部行开始直接从左到右填充它到 32 个字符。

这三个替代表是

这里是使用重复密钥 3,2,2,4,2 的样本加密:

这个版本,我将其称为BitBlock SA,标准字母表,具有适度的强度。每个替代表的混合都有一个密钥,块大小序列还有一个额外的密钥。当只有少数替代表,所有块大小都很小,并且块大小序列很小时,BitBlock SA 被评为三级。否则评为四级。
强化这种密码的一种方法是使用混合密钥字母表将字母转换为比特,并将结果比特重新转换为字母。让我们将混合字母表版本称为BitBlock MA。它被评为七级。
10.4 霍夫曼替代
第 4.2 节描述了如何使用霍夫曼编码进行文本压缩。霍夫曼替代是一种可以使用霍夫曼编码进行加密的方式。霍夫曼替代使用两组编码。第二组的编码替换第一组的编码。这些可能是相同的编码集,但是顺序不同。
消息被表示为比特串,例如通过使用标准的计算机表示之一,如 UTF-8 或 Unicode。这个比特串被分割成来自第一组霍夫曼编码的代码串,然后这些代码被第二组的代码替换。霍夫曼替代并不压缩消息,尽管消息的长度(以比特为单位)可能会因为第一组中的代码与第二组中的替代代码的长度不同而发生变化。
请回忆一下,一组霍夫曼编码必须具有前缀属性。也就是说,一组中的霍夫曼编码不能以另一组中的霍夫曼编码开始。例如,你不能同时有1101和11011,因为如果你正在解码的字符串以11011开头,你就不知道第一个编码是 4 比特还是 5 比特。有了前缀属性,就不需要像摩尔斯码组那样在编码之间有一个分隔符。
让我们看看如何构建具有前缀属性的一组霍夫曼编码。首先列出单个比特,无论顺序是 0,1 还是 1,0。例如,

对于此列表中的每一项,要么将其接受为完整代码,要么通过将一个副本附加 0 和另一个副本附加 1 的方式将其扩展为两个更长的代码,再以任何顺序。例如,我们可以接受代码 1 作为完整的,并将代码 0 扩展为两个代码,00 和 01,如下所示:

这个过程可以根据需要重复进行。例如,我们可以接受代码 01 作为完成,但是将代码 00 再延长一步,使代码 000 和 001。

这个过程可以继续进行,直到你获得了所需数量的代码或所需长度范围。但是,对于这个例子,4 个代码就足够了。我们将接受代码 000 和 001 作为完整代码,组成完整的 4 个代码。
*****当我们使用这些代码对比特串进行加密时,可以估计平均代码的长度。字符串以 1 开头的概率为 1/2,因此代码长度为 1 位的概率为 1/2。字符串以 000 开头的概率为 1/8,以 001 开头的概率也为 1/8。无论哪种情况,代码都将是 3 位长。字符串以 01 开头的概率为 1/4,代码长度为 2 位。这是一个完整的代码集,因此没有其他可能性。将它们组合在一起得到预期的代码长度 1/2+3/8+3/8+2/4 = 14/8 = 1.75 位。
在第一个代码被替换后,下一个代码的概率相同,因此所有代码的期望长度都是 1.75 位。这比代码的平均长度小,平均长度为 2.25 位。******
这是 Huffman 替换的一个例子。有两组 Huffman 代码。左列中的代码被右列中的代码替换。两组代码都具有前缀属性。明文是用标准的 5 位表示 A = 00000,B = 000001,C = 00010 等编码的 LIBERTY。


5 位组的第一行是用标准方式编码的单词 LIBERTY,A = 00000,B = 00001 等等。二进制的第二行是相同的比特串,但是分为了来自 Set1 的 Huffman 编码。下划线下的数字 1 是填充,用于填充最后一个 Huffman 编码。二进制的第三行用 Set1 中的每个编码替换为相应的 Set2 中的编码,也就是说,第三行是替换步骤的结果。二进制的第四行是与第三行相同的比特串,但是分为 5 位组。请注意,第 4 行比第 1 行长了 4 位。最后一行是使用相同的标准 5 位表示法为字母加密的密文。密文的最后一个字母可能是 I 或 J,因为最后一个二进制组只有 4 位。
*****如果您正在使用计算机执行此操作,则无需逐个将比特串的前端与每个赫夫曼编码进行比较。假设最长的编码有 6 位。您可以制作一个包含所有 64 种可能的 6 位组合的表。表中的每个条目都将告诉编码的长度(以比特为单位),并给出其替代项。每次执行替换时,您都可以使用字符串的前 6 位直接查找表。
例如,假设第一个赫夫曼编码是 00000,其替代项是 0110。以该编码开头的字符串的前 6 位的可能值是 000000 和 000001。因此,表中的条目 000000 和 000001 都将给出编码长度为 5,以及该编码的替代项为 0110。要执行替换,您将删除字符串的前 5 位,并将 0110 附加到结果字符串中。******
10.5 波斯特标签系统
纽约大学 Courant 研究所的数学家埃米尔·莱昂·波斯特(Emil Leon Post)于 1920 年发明了波斯特标签系统。其基本思想非常简单。您从一串比特开始。然后,您从字符串的前面取一些比特,用不同的比特替换它们,并将它们放在字符串的末尾。您继续这样做。其中的一种情况会发生:要么字符串缩小直到您无法再这样做,要么您陷入无尽的重复周期,要么字符串永远增长。
历史背景
波斯特并未为密码学而创建他的波斯特标签。波斯特证明了字符串增长、缩小或重复的问题不能在标准数学框架内得到解答,然后他利用这一事实构建了对库尔特·哥德尔(Kurt Gödel)著名的不完备性定理的证明。我认为这是一个比阿兰·图灵(Alan Turing)使用符号写在无限带上的证明更简单、更优雅的证明,尽管波斯特的比特串与图灵的磁带之间的相似之处令人惊讶。
这个后替换与赫夫曼替换类似,只是你将替换移到了比特串的末尾。这个系统的优势在于,当你替换完整个字符串后,你可以继续进行下去。也就是说,你可以多次遍历字符串。这消除了赫夫曼编码之间的分割。
你从字符串前面取出的部分被称为标签。标签集必须被选择,以便每一步最多只能取一个标签。也就是说,替换过程是确定性的。这要求标签集具有前缀属性。这将允许你使用标签集来加密表示为比特字符串的消息。前缀属性在第 4.2.1 节中与 Huffman 编码一起讨论。简而言之,没有任何标签可以以任何其他标签开头。例如,你不能同时拥有 1101 和 11011,因为如果字符串以 11011 开头,你将不知道是取前 4 位还是前 5 位。有了前缀属性,就不需要在标签之间加上分隔符,就像莫尔斯电码组需要分隔一样。Huffman 编码和 Post 标签具有相同的形式,但它们的使用方式不同。首先,Huffman 编码用于缩短比特字符串,而 Post 标签则不是。
构建一组 Huffman 编码的方法在第 10.4 节中描述。
当你使用 Post 标签进行加密时,你会用另一个标签替换每个标签,并将新标签移到字符串的末尾。由于 Riva 将不得不从右边解密消息,替换标签将需要具有后缀属性,即与前缀属性相反。没有一个后缀标签可以以另一个后缀标签结尾。例如,如果 1011 是其中一个后缀标签,那么 01011 或 11011 都不能是后缀标签。
你可以以与构建前缀标签相同的方式构建后缀标签集,只是在左边扩展每个标签而不是右边。如果这让你困惑,你可以简单地构建第二组前缀标签,然后颠倒该集合中的位的顺序以获得后缀标签。后缀标签必须至少与前缀标签一样多。可以有更多。额外的标签可以用作同音字。例如,前缀标签 0111 可能被后缀标签 110 或 10101 的选择替换。
当后缀的预期长度小于前缀的预期长度时,字符串可能会缩短。也就是说,很可能有一些初始字符串会变短。相反,如果后缀比前缀长,那么一些初始字符串可能会变长。这通常发生在使用同音字时。预期长度的差异越大,初始字符串的缩短或延长就越多。然而,“可能”并不是保证。可以构建具有相反行为的前缀/后缀集。
要使用 Post 标签进行加密,首先将消息表示为一串比特,然后进行几次标签替换。如果你是手动加密,你将这些比特转换回字符。如果你是通过计算机加密,最后一步可能是不必要的;你只需传输生成的比特字符串。
10.5.1 相同长度的标签
在上一节描述的密码中存在一个问题,Riva 不知道如何将她收到的消息分成块。你可能需要为每个块设置一个单独的长度字段,或者将整个消息视为一个单独的块。当消息很长时,这可能会很笨重。解决这个问题的一种方法是用相同长度的后缀标签替换每个前缀标签。这样,块在整个过程中保持相同的长度,而且没有标记块的结束的问题。32 位或 64 位的块大小是典型的。
我建议对每个块进行固定数量的替换。你可以从最短长度和标签的预期长度确定适当的数量。假设块大小为 32 位,最短标签为 3 位,预期标签长度为 4.3 位。使用最短长度,如果至少进行 32/3 = 10.67 次替换,那么可以保证每个块中的每个比特至少被替换一次。将其四舍五入到 11。使用预期长度,平均需要 32/4.3 = 7.44 次替换,以便每个比特都被替换。
一个良好的安全保障是每个比特平均替换两次。将 7.44 倍于 2 并四舍五入得到 15 次替换步骤。这大于 11,因此可以确定每个比特至少被替换一次。平均每个比特替换两次。大约一半的时间,一些比特被替换 3 次。最重要的是,Emily 不会知道任何给定比特替换了多少次。
你可能已经注意到,我一直在说“每个 比特 被替换”而不是“每个 标签 被替换”。这可能会让人困惑。第一轮通过块时,每个标签都会被一个具有相同长度的新标签替换。所以,在第一轮中,被替换的是标签。但是当第二轮替换开始时,可能不会从一个偶数标签边界开始。也就是说,下一个标签可能横跨第一轮的两个或多个标签。
这里有一个迷你示例来说明使用 12 位块的观点。块的第一个比特被阴影覆盖,前缀标签被下划线划分。

经过四次替换后,第一个比特现在位于下一个前缀标签的中间位置,即 011。
对于手工使用,我建议将字母表编码为 5 位或 6 位组,使用 3 到 6 位的 20 到 30 对标签,32 位块和 16 次替换步骤,即大约通过块两次。将结果位串转换回字符,使用 4 位组表示字母 A 到 P 以某种混合顺序。这样的密码将被评为六级。
对于计算机使用,建议使用标准的 8 位表示,如 UTF-8,对消息中的字母、数字和特殊字符进行编码。使用 40 到 80 对标签,每个标签 4 到 8 位,64 位块和 32 次替换步骤。使用 32 步足以确保通过块的 3 次。在进行后标签替换之前,在字符上执行混合的关键替换,并在完成后标签替换后,在结果字节上进行第二个独立的关键替换。这个密码,称为Post64,将被评为十。它将有 4 个单独的密钥用于混合初始替换、最终替换、后标签及其替代物。
使用后标签替换的另一种方法是使用短重叠块。从消息的前 4 个字节开始,并执行 2 次后标签替换。假设标签每个为 4 到 8 位,这足以确保所有第一个字节中的位都已被替换。然后向右移动 1 字节。消息的下一个 4 字节块是字节 2、3、4 和 5。再次对这个块执行 2 次后标签替换。以此类推,直到消息的最后一个 4 字节块。最后的 3 个块将会回绕到消息的前面。这种方法称为PostOv,评级为六。
10.5.2 不同长度的标签
当每个标签的替代物长度不同时,会涉及到各种复杂性,每个块的长度可能会发生变化,并且块可能不会对齐在字节边界上。例如,一个 32 位的块可能会变成一个 35 位的块。这意味着 Riva 需要一种方法来分隔这些块。最简单的方法是传输每个块的长度。
简单地对一个块执行后标签替换,直到其长度再次成为 8 位的倍数,似乎是可行的。不幸的是,这可能需要数千甚至数百万次替换步骤,甚至可能永远不会发生。
最简单的解决方案是将整个消息作为一个单独的块进行编码。消息的长度告诉 Riva 块中有多少个字节。Sandra 只需要在消息中添加一个 3 位字段,告诉 Riva 最后一个字节有多少位,范围从 1 到 8 位。这可以放在消息的开头,也可以是最后一个字节的最后 3 位。长度字段可能需要额外的一个字节。
这里有一个不同长度的后标签编码的示例。每个前缀标签及其相应的后缀标签都有匹配的下划线。

*****看起来好像每次从前面删除标记时都需要移动整个消息。通过保持对消息的第一个位和最后一个位的指针来消除这些移位。每个指针只是一个整数,给出每个端点的位置。指针的低 3 位将给出字节内的位位置,高位将给出字节位置。分配一个长度为消息长度 4 倍的空间。将消息放在此空间的开头,并将其余部分清零。
要从字符串的前面删除一个标记,只需将前指针递增标记前缀的长度。要在末尾附加标记,只需将标记移动到所需的位位置,并与字符串的最后 2 个字节进行 OR 运算,然后递增结束指针。继续这个过程直到到达空间的末尾。这意味着 Post 替换步骤的数量取决于消息本身。
这就只剩下一个移位操作要在最后执行,将位字符串放在偶字节边界上。然而,这个长移位也可以通过在消息的第一个字节和最后一个字节中告诉你的对方起始和结束位位置来消除。这仅需要 6 位,可以打包到一个字节中,并放在消息的开头。我建议用简单的替换对这个字节进行加密,以免给 Emily 起始和结束位置。还要确保用随机位填充消息的第一个字节和最后一个字节的未使用部分。
仍然有一个问题:因为 Riva 不知道消息的原始长度,因此也不知道加密空间的原始大小,她如何知道何时停止解密?Riva 不知道进行了多少次替换步骤,她不能简单地分配一个长度为接收到的消息长度 4 倍的空间,因为这可能与发送的消息长度不同。
这就是方法。Riva 知道三件事:明文消息从一个字节边界开始,消息在一个字节边界结束,加密空间是原始消息长度的 4 倍。Riva 可以开始将接收到的消息放在长度为密文消息 5 倍的空间的末尾。那应该足够了。Riva 从后向前工作,直到满足三个条件,特别是直到部分解密消息的开始到解密空间末尾的距离恰好是消息长度的 4 倍。这只会发生一次。******
我建议您使用 50 到 80 对标签,每个标签长 4 到 8 位。原始标签的预期长度应该接近于替换标签的预期长度。大约 1/3 的替换标签应该比原始标签短,1/3 应该是相同大小的,1/3 的替换标签应该比原始标签长。不要坚持使每个标签与其替代品的长度不同。消息字符应该表示为混合良好的字母表中的 8 位字节。如果标签的预期长度为 T 位,消息的长度为 L 位,则至少应进行 3L/T 次替换步骤。也就是说,你要对整个消息进行 3 次或更多次处理。最终的位字符串,包括长度指示器,应该使用第二个、独立的、简单的替换键转换回字符。如果所有这些建议都遵循,则此密码称为PostDL,评级为十。
当您到达第 12.6 节时,您将会看到 PostDL 密码不符合保证不可破解的所有标准。之所以获得十分评级是因为 Emily 不知道明文位在密文中的任何给定位置。位置将在块与块之间不同。所以 Emily 不能建立明文位和密文位之间的对应关系,因此不能建立密文位与明文和密钥位之间的方程。
10.5.3 多字母表
有几种方法可以加强 Post 标记密码或 Huffman 替换密码。我们已经讨论过多轮替换的情况。另一个技巧是使用多个字母表。每个字母表将包括一组具有前缀属性的标签和相应的一组替换标签,这些替换标签必须具有后缀属性。你可以简单地轮流使用多个字母表,或者你可以使用关键字来在它们之间进行选择。如果你是手工操作,你不会想要超过 2 个,或者最多 3 个这样的字母表,所以我建议使用一个数值密钥,比如 01101011。
这些密码,可能称为PolyPost和PolyHuff,根据轮数、字母表数量和密钥长度的不同评为四到八。
10.5.4 短距离和长距离移动
到目前为止,我们假设当一个 Post 标记有 B 位时,这些 B 位被移动到块的末尾。然而,可以移动少于 B 位,或者多于 B 位。例如,您可以移动 B-1 位,留下 1 位作为下一个标签的一部分再次替换。这使得标签重叠。优点是它隐藏了标签之间的边界。缺点是每轮需要更多的替换步骤,使得密码变慢。
相反,当后缀标签有 B 位时,你可以将 B+1 位移动到块的末尾。这样留下一位不变,而这一位始终是块中的最后一位。如果密码有多轮,那么未更改的比特很可能在其他轮中被替换。仍然有可能某些比特完整地通过这个密码。如果 Emily 无法确定哪些是未更改的比特,这不是一个严重的问题。比特是匿名的。关于任何比特都没有说,“这个比特来自明文的第 5 个字节,第 2 位”。
最后,移动的比特数可以与标签长度无关。你可以有一个表格告诉你要移动的比特数。这可以少于、多于或等于标签的长度。你可以有多个这样的表格。
当移动的比特数与标签长度不同时,后缀属性不再适用于替代标签集。相反,实际移动的比特字符串集必须具有后缀属性。例如,如果标签 0110 被替换为 1101,但移动了 5 位,则后缀字符串集必须包括11010 和11011。
10.6 其他进制中的分数化
到目前为止,本章已经讨论了五进制中的单-双替换,以及二进制中的 Huffman 替换和 Post 替换。可变长度替换也可以在其他进制中进行。对于手工加密来说,在三进制或四进制中进行 Huffman 替换和 Post 替换比在二进制中更容易。然而,可变长度替换可以在任何进制中进行,甚至是奇怪的进制,比如 11 或 13。这可以给你额外的替代品,可以用于同音词或编码二元组。
当你使用十三进制时,你可以使用任意十六进制数字中的 13 个进行替换,将另外 3 个数字留为空。如果做得好,使得所有 16 个数字的频率和分布大致相等,Emily 将无法区分有效数字和空位。
10.7 文本压缩
第 4.2.1 节讨论了使用 Huffman 编码压缩文本的方法。几种强大的加密方案可以基于文本压缩。在本节中,我提出了几种更高级的文本压缩方案和一些基于 Huffman 编码的加密方案。第十章的其余部分是可选的。如果在任何时候数学变得太令人畏惧,可以直接跳到下一章。

10.7.1 Lempel-Ziv
Lempel-Ziv 文本压缩方案是由以色列计算机科学家亚伯拉罕·莱姆佩尔和雅各布·齐夫在 1977 年开发的,被称为 LZ77,并在 1978 年改进了一个版本,称为 LZ78。它基于与赫夫曼编码相同的基本概念,即字母和字母组合由二进制代码表示,即一组比特。然而,莱姆佩尔-齐夫采取了与此相反的方法。赫夫曼使用较短的代码以节省空间。莱姆佩尔-齐夫使用大致相同长度的代码,但有些代码表示较长的字母组合以节省空间。
在另一个意义上,赫夫曼和莱姆佩尔-齐夫是相反的。赫夫曼将代码的长度基于固定的预设字母频率表。莱姆佩尔-齐夫在编码文本时动态确定最常见的字母组合。这被称为 自适应编码。赫夫曼编码仅适用于单一语言的文本。不同的语言将具有不同的字母频率。即使从大写文本转换为大小写混合文本也需要不同的赫夫曼编码集。相比之下,莱姆佩尔-齐夫可用于任何类型的计算机文件,任何语言或混合语言的文本,计算机代码,图像,遥测,音乐视频等。
有几个版本的莱姆佩尔-齐夫。我在这里介绍的版本,称为 莱姆佩尔-齐夫-韦尔奇,或 LZW,是由斯佩里研究公司的特里·韦尔奇于 1984 年开发的。LZW 具有固定宽度和可变宽度版本。我展示的是可变宽度版本,易于用于加密。
所有版本的莱姆佩尔-齐夫都使用称为 字典 的字母和字母组合列表。字典随着算法在文件中的进行而实时构建。在 LZ77 和 LZ78 版本中,字典起始为空。给定任何字母组合的代码是它在字典中的位置。
LZW 首先为文件中的每个单个字符分配一个代码。LZW 的所有代码都具有相同数量的比特。例如,如果文件是一条用英语写成的消息,全为大写且没有标点或单词分隔,则您将需要 26 个代码,因此您可以使用 5 位代码。更常见的是从 256 个代码开始,每个代码对应一个 8 位字节的 256 个可能值之一。
随着算法在文件中进行,它寻找尚未在字典中的字母组合。找到一个后,将该组合添加到字典中。例如,假设算法在文件中找到了 THE,并且 THE 已经在字典中。假设文件中的下一个字母是 M,并且 THEM 不在字典中。它输出 THE 的代码,后跟 M 的代码,并将 THEM 添加到字典中。THEM 的代码是字典中的下一个可用位置,假设是 248。
由于 THE 已经在字典中,算法不会查找以 HE 或 E 开头的组合。它将从 M 开始查找另一个不在字典中的组合。如果该组合是 MOR,则将 MOR 放入字典条目 249 中,并具有代码 249。算法下次在文件中找到 THEM 时,将被编码为 248,并且下一个 MOR 的出现将被编码为 249。
当算法填满了所有 256 个 8 位代码的字典条目时,下一个分配的代码将需要 9 位。此时,算法将从 8 位代码切换到 9 位代码。THEM 仍然具有代码 248,但它将是 9 位代码 011111000,而不是 8 位代码 11111000。当算法填满了所有 512 个 9 位代码的字典槽时,THEM 的代码变为 10 位代码 0011111000,仍然是 248。请注意这些操作的顺序。当前字母组合的代码首先以旧大小输出,然后将新组合添加到字典中,并增加代码大小。Sandra 和 Riva 必须使用相同的顺序,否则消息将无法正确解压缩。通常在 12 位停止扩展代码。将代码大小从 12 位增加到 13 位通常不会改善压缩,并且甚至可能使其恶化。
让我们看一个例子。让我们使用此算法对单词 TETE-A-TETE 进行编码。假设字典以单个字母 A、E 和 T 以 2 位代码开头。让我们跟随字典的构建过程。每个阶段左边的位字符串显示编码的单词,右边的字母显示剩余部分的单词。

当 Riva 解压缩消息时,字典必须以完全相同的方式构建。请注意,仅仅是二进制字符串10 01 011 000 011 011本身不足以让 Riva 解压缩消息。她还需要知道代码00、01和10代表字符 A、E 和 T。
好的。这就是 Lempel-Ziv 压缩。这是一本关于密码学的书。Lempel-Ziv 压缩如何用于加密?
在构建字典时,Lempel-Ziv 按顺序分配代码。第 43 个字母或字母组合将获得代码 42(不是 43,因为代码从 0 开始)。要使用此方案进行加密,请向字典添加第二列。第一列包含字母组合,第二列包含相应的代码。不要使用字典中的位置作为每个字母组合的代码,而是使用字典的第二列中的数字。
假设字典以 256 个单字节字符开头。第一列包含字符。在第二列中,以某种乱序方式放置从 0 到 255 的数字。它们可以通过第 5.2 节中描述的任何方法进行混合。桑德拉和瑞娃必须使用相同的顺序,可以由关键字或随机数生成器的种子确定。当需要第一个 9 位编码时,下一个 256 个字典条目将以乱序方式获取代码从 256 到 511。同样,当您从 9 位代码转移到 10 位代码时,将一次分配下一个 512 个代码。批量分配代码比逐个分配代码更有效。
一种替代批量分配代码的方法是仅使用关键字或随机数序列分配前 256 个代码。之后,每个新代码通过在 256 个条目之前的代码上加 256 来计算。也就是说,X(N) = X(N-256)+256。
我将称之为Lempel-Ziv 替换的这个密码被评为 Three。评分很低是因为消息的前几个字符基本上是用简单的替换进行了加密。每个代码将代表一个单字符,直到出现第一个重复的双字母组为止。这可能要等到编码了 30、40 甚至更多个字符之后才会发生。即使在那之后,大多数的 9 位代码仍然表示单个字母。这些代码很容易区分,因为它们是以 0 开头的唯一的 9 位代码。艾米丽将有很多机会使用字母频率和接触频率来破译消息。
要使 Lempel-Ziv 替换变得强大,您可以添加第二个替换步骤。这个替换不应该在字节边界上进行。我建议使用 7 位组。这些组将不会与代码组重合,直到代码达到 14 位。这可能永远不会发生,因为代码通常限制为 12 位。Lempel-Ziv 替换后跟 7 位替换的评分为 Six。这两种替换可以在单向左到右的通道中完成。
10.7.2 算术编码
算术编码(发音为“a-rith-MET-ic”)是一种文本压缩方法,我在 1970 年代发明的(“使用固定精度寄存器的算术流编码”,IEEE 信息论杂志第 25 卷(1979 年 11 月),第 672-675 页)。它基于麻省理工学院的彼得·伊莱亚斯的一个聪明想法。
埃利亚斯的想法是将每个字符串编码为分数。想象一下,从 0 到 0.999 的所有可能的分数...省略号...表示该分数以无限的 9 序列结尾。现在根据字符串的第一个字符将此范围分割。为简单起见,假设字母表中有 25 个字符,就像一个 Polybius 方块字母表。每个字母将获得全范围的 1/25。那些以 A 开头的字符串将获得全范围的第 1/25,即 4%,范围为 0 到 0.04。以 B 开头的字符串将获得全范围的下一个 1/25,即 0.04 到 0.08。以 Z 开头的字符串将获得全范围的最后 1/25,即 0.96 到 0.999...(我使用十进制表示这个例子是为了更容易阅读。在计算机中,将使用二进制分数。)
对于第二个字符,你再次分割这个范围。以 AA 开头的字符串将在范围 0 到 0.0016 内。以 AB 开头的字符串将在范围 0.0016 到 0.0032 内。以 BA 开头的字符串将在范围 0.0400 到 0.0416 内。以此类推。以 ZZ 开头的字符串将在范围 0.9984 到 0.9999...内。
为了可视化,让我们使用一个小型的 5 个字母的字母表,其中 A 从 0 到 0.2,B 从 0.2 到 0.4,C 从 0.4 到 0.6,D 从 0.6 到 0.8,E 从 0.8 到 0.999...。使用这个字母表,让我们将单词 BED 编码。

BED 可以编码为任何满足 0.384 ≤ f < 0.392 的分数 f。随着添加更多字符,此间隔将继续缩小。
这就是概念。然而,将字符串编码为分数并没有提供任何压缩。需要另一个想法来实现压缩。与其给予字母表中的每个字母相同比例的分数,不如将分数与该字母的频率成比例。A 将获得 8.12%,B 将获得 1.49%,依此类推,直到 Z,Z 将获得 0.07%。A 的范围为 0 到 0.0812。B 的范围为 0.0812 到 0.0961。Z 的范围为 0.9993 到 0.9999...。
从理论上讲,这将根据各个字母的频率提供最佳压缩。不幸的是,存在一个实际问题。该方法产生的分数可能需要数千甚至数百万位数。如何在计算机中表示这样的分数?如何对它们进行算术运算?
因此,这个方法在理论上很好,但在实践中似乎不可行。它似乎需要无界精度的分数。增加和乘以长分数的时间(无论是十进制还是二进制)都会随着它们的长度增加而增加,所以即使有一种好的方法来表示这些分数,该方法也会变得难以忍受的缓慢。
我找到的解决方法是使用一个移动窗口,在其中进行所有的算术操作。这样可以使用普通的 32 位整数。不需要浮点运算。为了保持整数在 32 位大小内,字母频率被近似为 15 位整数,即形式为 N/2¹⁵ 或 N/32768 的分数。例如,字母 A 的频率是 8.12%。这可以表示为 2660/32768 或 665/8192。发现这个近似没有导致压缩程度的可检测减少。
这是一个十进制示例,展示了一个字母如何被编码以及移动窗口的工作原理。假设前几个字符已被编码,并且范围现在为 .784627 到 .784632。范围的起始和结束的前 4 位数字是相同的,即 .7846。这 4 位数字将被输出,并且窗口将向右移动 4 个数字以显示范围 .2700 到 .3200。

这个范围的宽度是 .0500。假设消息中的下一个字符的频率是 .0300,其范围是 .4050 到 .4350。这个字符被编码为当前范围 .2700 到 .3200 的那一部分。其宽度是 .0500×.0300,即 .0015。它将从 .2700+.0500×.4050 运行到 .2700+.0500×.4350,即 .29025 到 .29175。注意这个范围的宽度是 .0015,正如预期的那样。

由于这个范围的起始和结束都以数字 .29 开头,这些数字可以输出。已输出的数字现在是 784629。窗口现在可以再向右移动 2 个数字,使当前范围为 .0250 到 .1750。
算术编码非常适合用于加密,因为不再有每个字母或字母组合的离散编码。没有边界,可以将比特流分割为单独的代码。相反,每个字母的代码影响如何表示所有后续字母。
现在我们了解了算术编码方法的工作原理,下一步是看如何将其用于加密。我们不希望改变分配给每个字符的范围的百分比,因为那样会失去压缩。相反,我们可以改变字符的顺序,使得每个字符的范围都落在整个范围中不可预测的部分。也就是说,对于艾米莉来说是不可预测的。例如,仅使用字母 A、B、C、D、E,范围可能是:

这些区间可以用来编码消息的字母。我们将这种方法称为算术加密。由于艾米莉不知道任何范围的起始点或结束点,因此没有攻击的机会。艾米莉知道第一个范围从 .0 开始,最后一个范围结束于 .999...,但她不知道这些范围代表哪些字符。
算术编码存在一个尚未讨论的困难。使用正常的字母表,Riva 不知道消息何时结束。代表 ROTUND 的相同代码也可以代表 ROTUNDA、ROTUNDAA、ROTUNDAAA,依此类推,假设 A 的范围从 0 开始。使用传统算术编码,可以通过使用各种方法对消息长度进行编码并将该长度码附加到密文中,或者通过向字母表添加特殊的消息结束字符来解决此问题。此前没有讨论过这一点,因为算术加密不需要它。
使用算术加密时,您只需将罕见的字符分配给第一个范围,即从.0000 开始的范围。然后,当 Riva 看到 ROTUNDVVV...或 ROTUND###...时,消息的结束就显而易见了。
如本节所述,使用 26 字母表对算术加密评为 Five,或者使用 256 字符字母表评为 Six。这里可以使用所有常用的技巧,如空字符、同音字和双字母组。使用空字符会减少或破坏压缩,因此我不建议使用。使用同音字会将字母的范围分成两个或更多的单独范围。这使得字母的范围更加均匀,这相当于平衡了字母的频率。这可以在不影响压缩程度的情况下提高安全性。有时,使用双字母组甚至三字母组可以提高压缩水平同时提高安全性。使用同音字和双字母组,算术加密评为 Eight。
由于算术加密本身非常强大,所以只需很少的额外工作就可以将其提升到 Ten 的评级。我建议使用周期为 4 的一般多表密码,即使用四个独立混合良好的字母表以轮换方式使用的替换。使用周期为 4 或更高的一般多表加密后的算术加密评为 Ten。它让对手毫无线索可循,没有字母频率,没有联系频率,也没有利用可能的单词的方法。
10.7.3 自适应算术编码
Lempel-Ziv 给任何类型的文件提供了良好的压缩,因为它是自适应的。Huffman 编码和算术编码提供了更好的压缩,但只适用于字符频率与基础频率表相匹配的文件。有几种方法可以使 Huffman 编码和算术编码自适应,所有这些方法都使相应的加密方法更加强大。所有这些方法都涉及对文件中的字符进行计数,然后再对其进行编码。
字符计数与文件中的字符频率越接近,获得的压缩效果就越好。你可能会认为你可以简单地计算文件中的所有字符,然后使用实际的计数。问题是 Riva 不能统计文件中的字符。Riva 必须使用与 Sandra 相同的频率,否则她无法解密文件。解决这个困境的方法是 Sandra 在加密时计数字符,Riva 在解密时计数字符,这样他们在所有阶段都会拥有相同的计数。
所有字符计数从 1 开始。如果你事先知道字符的频率,即使它们只是粗略的估计,你也可以增加更频繁出现的字符的计数。例如,如果你使用的是 256 个字符集,并且你预计消息将包含约 1%的大写字母 E 和约 10%的小写字母 e,那么你可以将 E 的字符计数增加 2,将 e 的字符计数增加 25,即 256 的约 10%。每个字符的初始范围与其初始计数成比例。例如,如果 256 个字符计数总共为 500,并且小写字母 e 的初始计数为 25,那么 e 的范围将为 25/500,即 0.05。
调整代码有两种基本方法,字符模式和批处理模式。字符模式只适用于算术编码。在字符模式中,每当在文件中找到一个字符时,它的范围和两个相邻范围都会被调整。(当字符具有第一个或最后一个范围时,有一个相邻范围。对于 26 个字母的标准字母表,这意味着 A 或 Z。)
这里有一个例子。假设已经遇到了字母 T,并且相邻范围属于字母 S 和 U。(这可能不适用于算术加密。混合字母表可能不会按顺序包含 S、T、U。)假设 S、T 和 U 的字符计数分别为 15、20 和 5,因此它们总共为 40。假设 S、T 和 U 的范围分别为 0.062、0.074 和 0.024,因此它们总共为 0.160。这个合并范围按比例重新分配为 15:20:5。S 获得 0.160×15/40,即 0.060。T 获得 0.160×20/40,即 0.080。U 获得 0.160×5/40,即 0.020。随着时间的推移,字符的范围将收敛到正确的宽度。
字符模式在 26 个字母的字母表中效果还不错。但在 256 个字符的字母表中效果非常差。大多数 256 个字符不会与任何高频字符相邻,因此它们的频率将保持不变。这在所有字母都聚集在一起的标准 ASCII 表示中尤其明显。
批处理模式适用于算术编码和哈夫曼编码。在批处理模式下,在编码过程中的特定点调整整个范围。例如,在编码 64 个字符后,128 个字符后,256 个字符后等等可以调整范围。在这些点上,整个范围将根据当前字符计数重新分配。这比字符模式更快地收敛,但在重新分配之间,您正在使用旧的未调整频率。
在批处理模式下,可以计算二元组甚至三元组的频率。出现多次的二元组或三元组可以被赋予自己的哈夫曼代码或算术代码范围。通过这种改进,算术编码几乎总是比 Lempel-Ziv 提供更好的压缩。
计算二元组和三元组频率存在一个问题,即存储。对于一个 256 字符的字母表,有 65,536 个不同的二元组和 16,777,216 个不同的三元组。如果存储空间充足,这可能不是问题。如果存储空间有限,一个解决方案是仅计算包含最常见字母的二元组和三元组。例如,如果将二元组和三元组限制为最常见的 20 个字符,则只有 400 个二元组和 8,000 个三元组需要计算。为了确定最常见的字符,可以推迟计算二元组和三元组频率,直到编码了一定数量的单个字符,比如 256 或 1024 个字符。
实现这些受限制的计数的一种方法是仅在第一个批次中计算单个字符,以确定最常见的字符。在第二批次中使用这些高频字符计算二元组。在第三批次中,仅使用高频二元组加上高频字母计算三元组。一旦选择了高频二元组和三元组,它们将被赋予自己的哈夫曼代码或算术范围。换句话说,它们被视为单个字符处理。
对于算术编码,字符模式和批处理模式并不是互斥的。您可以在遇到每个单个字符时平衡各个字符的范围,并在每个批次结束时平衡扩展字符集以及二元组和三元组。
在进行哈夫曼加密或算术加密时,在每个批次结束时,字母表应在代码被替换或范围重新平衡之前重新洗牌。如果添加或删除了二元组或三元组,则特别需要这样做。这意味着艾米莉在代码改变之前只有有限的材料可以攻击。对于加密,最好使用不规则长度的批次,比如在 217 个字符后,然后在 503 个字符后,以此类推,这样艾米莉就不会知道代码何时改变。
对自适应编码的另一项改进是在重新平衡范围后将所有计数除以 2。这样可以让编码适应字符频率发生变化的情况。较旧的频率对范围的影响会减少,而较新的频率则会增加影响。例如,假设文本是一本由不同作者撰写的故事书。每个作者可能有不同的词汇或不同的主题,甚至用不同的语言书写。
当然,Sandra 和 Riva 必须事先就所有这些达成一致,这样 Riva 才能正确解密和解压消息。
第十一章:块密码
本章涵盖
-
DES 和 AES 加密标准
-
基于矩阵乘法的密码
-
对称密码,其中加密和解密是相同的
-
涟漪密码
-
块链
我们已经看到了几种对文本进行分块处理的密码。一些操作于仅由 2 或 3 个字符组成的小块,例如 Playfair、Two Square、Three Square 和 Four Square。一些操作于更长的块,但每次只更改 2 或 3 个字符,例如 bifid、trifid 或 FR-Actionated Morse。这些密码在每个块的一部分上进行局部操作。明文中的一个字符的变化通常最多会改变 2 或 3 个密文字符。
本章涉及更强大类型的块密码。在这些密码中,即使改变明文的一个比特,或者密钥的一个比特,也会改变大约一半的密文比特,以及几乎所有的密文字节。这表明密码是高度非线性的。这些密码仅适用于计算机使用,通常配有专用硬件来加速加密。
本书的大部分其余内容都与计算机密码和方法有关。如果您不关心计算机方法,只需跳过这些部分。
11.1 替代-置换网络
许多块密码采用替代-置换网络(SPN)的形式。这个想法首次由 IBM 的 Horst Feistel 于 1971 年描述。加密由几轮组成,每轮可能包括一个或多个替代步骤和/或一个或多个置换步骤。通常有一个主键来控制整体操作。
替代步骤的最常见选择是(1)简单替代,(2)用密钥的一部分与块的一部分进行异或,或者(3)在密钥的控制下进行多表替代。密钥可以由主密钥和/或未被替代的块的部分的位组成。例如,块中的奇数字节可以用作对偶数字节进行加密的密钥,反之亦然。一种稍微复杂的替代形式是从密钥中获取一些比特,将它们与块中相同数量的比特进行异或,并将结果用作替换块的另一部分的多表密钥。
替代字母表通常是预先选择的,永远不会改变。这些被称为S-boxes。它们可能是简单的替代,也可能是多表替代,因此 S-box 是计算机的等价物。它们通常需要 4 到 8 个关键位来选择表格的行,并以相同数量的位作为输入和输出。通常会有一些复杂的数学运算用于构建替代字母表。特别是,这些字母表被设计为非线性的,这在第 12.3 节中有详细说明。
每一轮的置换通常是预先确定且不变的。置换可以操作单个比特、4 位组或 8 位字节。在大多数分组密码中,置换没有密钥;它们是硬编码在软件中或硬连到加密芯片中的。
现代分组密码中最早的是Lucifer,由 IBM 的 Horst Feistel 设计。在 Feistel 最终确定 Lucifer 之前,名称已经多次更改,因为他想要一个体现设计的邪恶本质的名称。Feistel 还反复改变了 Lucifer 的设计,从最初的在 128 位块上工作的 48 位密钥到在 128 位块上工作的 128 位密钥。您可以在 derekbruff.org/blogs/fywscrypto/tag/lucifer (访问时间:2022 年 5 月) 上阅读有关 Lucifer 的更多信息。
这是一个微型置换-置换网络密码的图示。此密码接受 16 位明文并产生 16 位密文。它有 4 轮替换和 3 轮换位。替换和换位是固定的;它们内置到硬件中。使用了 4 种不同的替换,分别是 S[1]、S[2]、S[3] 和 S[4]。每个替换需要 4 个输入比特加上一个密钥,通常是 4、6 或 8 位,因此如果所有密钥都是独立的,则密码可能具有 64、96 或 128 位密钥。每一轮的换位都不同。

这个微型网络密码被评为三级,因为它相当于一个双字母替换,但它可以通过 6 轮替换从 16 位扩展到 64 位,评为八级,或者通过 8 轮替换从 16 位扩展到 128 位,评为十级。
最终版本的 Lucifer 设计直接导致了数据加密标准 (DES),该标准于 1977 年正式由国家标准局 (NBS) 采纳。因此,让我们直接进入它。
11.2 数据加密标准 (DES)
DES 是 1976 年在 IBM 开发的,通过削减当时的 Lucifer 版本实现。该版本使用了 128 位密钥,并且在消息的 128 位块上工作。块大小缩小为 64 位,这是可以接受的,因为这降低了硬件成本。IBM 想要使用 64 位密钥,但 NSA 坚持进一步减少密钥,降至 56 位,理由薄弱,声称额外的 8 位可以用作校验和。普遍认为,实际原因是 NSA 能够解决 56 位 DES,但无法解决 64 位 DES。
IBM 最初计划将 DES 设计为 6 轮密码。当 NSA 告诉 IBM 它可以破解 6 轮版本时,IBM 直接跳到 16 轮,与 Feistel 在他的 Lucifer 最终版本中使用的轮数相同。
DES 的一个新特性,在任何 Lucifer 版本中都找不到,就是在第一个和最后一个替换步骤之前进行位转置。这些是 8×8 列转置,其中列的顺序和行的顺序都被改变。对于初始置换,块的 64 位从左到右写入网格中。列按相反顺序读出,即 8、7、6、5、4、3、2、1。行按顺序读出,即 2、4、6、8、1、3、5、7。最终置换是其逆置。
这些置换对加密的价值是没有的。它们并没有增加 DES 的强度。它们之所以被添加,是因为 NSA 告诉 IBM,硬件加密应该很快,但在软件中模拟时应该很慢。其想法是通过软件尝试所有可能的密钥来使 Emily 破解密码更加耗时,即通过穷举法尝试破解密码。IBM 相信,置换位会使任何软件实现非常慢。IBM 可能设想了一种逐位提取比特并通过掩码进行位移的过程,然后将其移动到位。
结果证明这完全是错误的。首先,希望破解 DES 的敌人可以简单地通过代理购买加密芯片。其次,对于一些合法的应用程序,DES 需要嵌入软件中,因此软件必须快速。第三,位置换可以快速完成,而不必提取单个位或进行位移。我将在第 11.2.3 节中展示如何做到这一点。
在初始和最终置换之间,DES 有 16 个替换轮。64 位块分为两个 32 位的半块。在每一轮中,右半部分用于加密左半部分。首先,将右半部分从 32 位扩展到 48 位,如下所示。将 32 位视为八个 4 位组。这些组中的每个都通过附加前面和后面的位(来自相邻的组)从 4 位扩展到 6 位。例如,第三组将由第 9 到 12 位组成。这个 4 位组将通过在左边附加第 8 位和在右边附加第 13 位来从 4 位扩展到六位。换句话说,6 位组将是位 8、9、10、11、12、13。八个这样的 6 位组形成一个 48 位块。
然后,将此 48 位块与从 56 位密钥中取出的 48 位进行异或。确定每一轮使用哪 48 位由一个密钥调度确定,基本上是在每一轮后将完整的 56 位密钥向左或向右移动几个位置。然后,得到的八个 6 位组被输入到八个固定的 S 盒中,即替换。每个 S 盒给出一个 4 位结果,因此八个 4 位结果组成一个 32 位块。然后将此块与整个 64 位块的左半部分进行异或。
历史小插曲
IBM 并未设计 DES 以具有密钥调度。最初的想法是在每个 16 轮后将 64 位密钥循环移位 4 位位置。这样留下了密钥在其原始位置,准备加密下一个块。当 NSA 要求 IBM 将密钥大小减小到 56 位时,IBM 被迫引入了密钥调度。四位移位不再起作用。当然,IBM 将密钥调度称为“功能”。
查看每个 S-box 的另一种方法是将其想象为一个 4×16 的表格。像 Belaso 或 Vigenère 表格一样,每行都是 4 位组的替换表。附加到 4 位组的两个额外位用于选择表格的 4 行中的哪一行。
每个 S-box 都经过精心设计,以尽可能减少 6 个输入位和 4 个输出位之间的相关性。NSA 发现了一种最低相关性的设计 S-box 的绝密方法。由于 DES 如此重要,NSA 决定与 DES 的 IBM 设计者分享这个秘密。然而,在检查 IBM 设计后,NSA 发现 IBM 也发现了这种方法,并在其设计中使用了它。
每轮结束后,除了最后一轮外,64 位块的左半部分和右半部分被交换。
11.2.1 Double DES
从一开始就明白,56 位密钥对于强大的安全性来说太小了。仅在 DES 被采纳后的 4 个月,电子前沿基金会构建了一台名为 Deep Crack 的 25 万美元的专用计算机,仅用了 56 小时就解密了一条 DES 消息。
对这种明显的弱点的第一个提出的解决方案是使用两个不同的密钥两次使用 DES 加密消息。这个想法被拒绝了,因为从理论上讲可以发动一种中间相遇攻击来破解 DES。也就是说,你从明文向前工作,从密文向后工作,并在中间相遇。你通过获取已知明文的密文块来执行此操作。你使用所有 2⁵⁶ 可能的密钥加密明文,然后使用所有 2⁵⁶ 可能的密钥解密密文。您比较这些结果,无论您在哪里找到匹配项,您都有可能的密钥对。
这种攻击仅仅是理论性的。您需要存储 2 组 2⁵⁶ 解决方案,即 2⁶⁰ 字节,以进行所有比较。1970 年代的计算机都没有达到那个存储水平。此外,您预计将获得约 2⁴⁸ 个匹配项。所有这些都需要被检查。这是一个艰巨的任务。但是 IBM 和 NSA 希望 DES 能够持续 20 到 30 年,并且有可能在这段时间内这种攻击变得实用。可能会使用 Double DES,但从未被接受为标准。
11.2.2 Triple DES
三重 DES,或 3DES,是另一种补偿 DES 小 56 位密钥尺寸的尝试。它包括将一个 64 位块加密一个 DES 密钥,用第二个 DES 密钥解密,然后用第三个 DES 密钥加密。显然,这比普通 DES 花费的时间多 3 倍。它没有被广泛使用,因为这使它变得很慢。
提高 DES 安全性的更快方法是使用一个 64 位密钥在 DES 步骤之前对 64 位块进行异或操作,并在 DES 步骤之后使用另一个 64 位密钥进行异或操作。将有 3 个独立的密钥,两个 64 位异或密钥和 56 位 DES 密钥,总共 184 位。这种方法只比单个 DES 加密多花一点时间。
即使第二个异或密钥可以通过查看波形来确定,这仍然比单个 DES 更强大。你可以通过在 DES 步骤之前和之后执行键控简单的替换来消除波形撤销异或的危险。
*11.2.3 快速位换位
DES 的起始和结束都涉及位换位。这样做的朴素方式是逐个解压位,将它们移动到期望的位置,然后将它们 OR 到位。有一种更快的方法,大约在 1975 年,由我和 IBM 纽约约克镇研究中心的 David Stevenson 独立发明。我将用一个 32 位块的换位来演示这种技术。假设明文,以位形式表示,是

其中每个拉丁字母或希腊字母代表一个比特的值,即它可以是 0 或 1。让我们看看如何进行转置,使得 a 移动到第三个位置,b 移动到第六个位置,c 移动到第九个位置,依此类推。
通过使用 4 个特殊表,每个表都有 256 个条目,可以实现转位。每个条目都是一个 32 位块或计算机字。第一个表显示了 32 位块的第一个字节中 8 位的转置位置,如下所示:

第二个表显示了 32 位块的第二个字节中 8 位的位置:

第三个表显示了 32 位块的第三个字节中 8 位的位置:

第四个表显示了 32 位块的第四个字节中 8 位的位置:

点的存在使你能够轻松看到 32 位的放置位置。它们代表计算机字中的零。现在可以通过查找这些特殊表中的 4 个字节并将四个结果 32 位块进行 OR 运算来实现转置,就像这样:

这不需要移位和掩码。整个 32 位的置换只使用了 4 个表查找和 3 个 OR 操作。这种技术的一个用途是翻转一个 8×8 位的块。这可以使用 8 个 256 个条目的表,或者只是一个单表来完成,将位移动到每个字节内的正确位置,就像这样:

11.2.4 短块
在 DES 和其他块密码中遇到的一个问题是如何处理短块。对于 DES,所有的块必须恰好有 8 个字符。假设您的消息有 803 个字符,即 100 个 8 个字符的块加上 3 个多余的字符。你如何处理那最后的 3 个字符?
传统的解决方案是用空值填充最后一个块。使用纸和笔密码学时,一些常用的技术是在最后 5 个字符附加 XXXXX 或 NULLS。不幸的是,这给了 Emily 5 个已知明文字母。对于手动密码的一些更好的解决方案是使用标记,比如 XX 或 JQ,然后将剩余的填充字符随机选择,比如 XXESV,或者简单地使用任意组合的低频字符进行填充,比如 ZPGWV。解密取决于 Riva 能否识别真实消息的结束和填充的开始。
在计算机中,填充必须解决两个问题。首先,Riva 必须能够确定消息的结束位置,或者等效地说,填充有多少字节。其次,Sandra 希望尽可能少地给出已知明文。一些提议的方案在这两个方面都失败了。例如,有一种方案建议在消息的末尾填充以下内容之一:

当块大小为 32 时,这可能会给出高达 31 个字节的已知明文给 Emily。在一般文件中,最后一个块可以是以 01 结尾的完整块,甚至是 02 02,这可能会被误认为是填充。
更好的解决方案是在明文文件中的某个位置放置一个长度字段。这不必是文件中的字节数,这可能需要一个 4 字节的长度字段,它可以是最后一个块中填充字节的数量。对于 DES,这是一个从 0 到 7 的数字,因此只需要 3 位。长度字段可以放在文件的任何位置。最常见的地方是第一个字节、最后一个字节和最后一个块的第一个字节。填充字节本身可以随机选择。
为了避免给 Emily 甚至一个字节的已知明文,长度可以编码为长度指示符的低位或高位比特,并且其余未使用的比特可以是随机的。这样,长度指示符可以取值从 0 到 255。
顺便说一句,没有规定你必须在文件末尾填充。如果你想在文件开头、最后一个块的开头或第 13 个块的中间填充,随便你。只要桑德拉和里瓦同意,他们可以做任何他们认为会最大程度地阻碍艾米莉的事情。一种可能性是将填充字节分散开来。例如,如果文件需要 4 个填充字节,你可以将它们放在文件的第二、第四、第六和第八个块的末尾,只要里瓦能够知道添加了多少填充字节。
重叠方法是填充的一种替代方法。假设,再次,块大小 B 为 8,消息有 803 个字符,你将前 800 个字符加密为 8 个字符的 100 个块。然后你将第 796 到 803 个字符加密为第 101 个块。这样,消息的长度不会改变,但里瓦必须在解密第 100 个块之前解密第 101 个块。
11.3 矩阵乘法
我们将要看的下一个分组密码是高级加密标准(AES)。然而,AES 使用一种称为矩阵乘法的数学运算,这在本书中尚未涵盖。我在介绍中承诺会呈现每个需要的数学概念,因此我将在这里介绍矩阵乘法。这个概念在后面的几章中是必需的。除非你已经很熟悉矩阵乘法,最好不要跳过这部分。
矩阵只是一个称为标量的元素的矩形数组。一系列标量形成一个向量,因此矩阵的每一行和每一列都是一个向量。它们分别称为行向量和列向量。具有 m 行和 n 列的矩阵称为 m×n 矩阵。如果 m = n,则该矩阵称为方阵。这里是一个具有 3 行 5 列的矩阵 M 的示例,称为 3×5 矩阵。它有 15 个标量元素,用字母 a 到 o 表示。

在这个矩阵中,3 个行向量分别是[a,b,c,d,e],[f,g,h,i,j]和[k,l,m,n,o],5 个列向量分别是[a,f,k],[b,g,l],[c,h,m],[d,i,n]和[e,j,o]。矩阵的行从上到下编号,列从左到右编号。在 M 中找到的第 i 行第 j 列的元素表示为 M[ij],因此 M[11]是 a,M[15]是 e,M[31]是 k。
标量的类型包括整数、模 N 的整数、有理数、实数、复数和其他稍后描述的类型。矩阵乘法对于每种类型的数字都是相同的。
两个矩阵 X 和 Y 的乘积,记作 XY,是通过将 X 的行乘以 Y 的列得到的。让我们详细看看这是如何工作的。矩阵的行是向量,矩阵的列也是向量。长度相同的两个向量可以进行所谓的内积乘法,有时也称为点乘,因为向量乘法有时用 ● 点表示。这个操作将一个向量的元素与第二个向量的对应元素逐个相乘,然后取这些乘积的和。
假设第一个向量是 [a,b,c,d],第二个向量是 [e,f,g,h]。它们长度相同,都有 4 个元素,因此它们可以相乘。它们的内积是

设 X 和 Y 是 4×4 矩阵,P 是它们的乘积。也就是说,P = XY。假设 [a,b,c,d] 是 X 的第 i 行,[e,f,g,h] 是 Y 的第 j 列。它们的乘积记为 P[ij]。换句话说,第 i 行第 j 列的元素是 X 的第 i 行与 Y 的第 j 列的乘积。这可以用下标写成

对于其他矩阵大小也使用了类似的表达式。只要 b = c,大小为 a×b 和 c×d 的两个矩阵就可以相乘。
11.4 矩阵乘法
不,这个重复的章节标题并不是错误。除了数字之外,数学中还有许多其他可以进行加法和乘法的对象。一些例子包括向量、矩阵、多项式、四元数,以及更一般地,环的元素。甚至可以有矩阵的向量、多项式的矩阵等等。关于环的更多内容请参见第 15.6 至 15.8 节。矩阵乘法可以基于这些类型的元素及其乘法和加法规则。过程是相同的。你将 X 的第 i 行与 Y 的第 j 行进行内积,以得到乘积矩阵的第 i 行第 j 列的元素。
矩阵乘法不是交换的,这意味着当你将给定的方阵 X 与第二个方阵 A 左乘或右乘时通常会得到不同的结果。AX ≠ XA。这被称为方阵 X 左乘或右乘 A。
对于 AES,我们关注的是多项式的乘法和加法。我们在高中代数课上学过如何加和乘多项式。继续从事科学和工程职业的人可能仍然记得如何做。多项式也可以被除。这种除法可能会有余数,所以多项式也有与整数相同的模概念。(如果你想复习一下,可以回顾一下第 3.6 节。)
AES 中使用的标量乘法不是整数乘法,而是多项式乘法模另一个多项式。这可能是我们在这本面向普通读者的书中所能深入讨论的了。
11.5 高级加密标准(AES)
高级加密标准是一种新的分组密码,于 2001 年取代了 DES。最初被称为 Rijndael,以其发明者,比利时密码学家文森特·赖曼和乔安·达门命名。AES 最初有五种组合,包括 128 位或 256 位的块,以及 128 位、192 位或 256 位的密钥。然而,美国国家标准与技术研究院(NIST)确定了 128 位块大小的标准。轮数取决于密钥大小:128 位密钥为 10 轮,192 位密钥为 12 轮,256 位密钥为 14 轮。
每一轮使用一个由完整密钥中选择的 128 位组成的轮密钥,根据 密钥调度。在第一轮之前,执行初步操作 AddRoundKey,简单地将块与轮密钥进行异或运算。接下来的 9、11 或 13 轮中的每一轮都包括 4 个操作,SubBytes、ShiftRows、MixColumns 和 AddRoundKey。最后一轮没有 MixColumns 步骤。
将 128 位块视为字节的 4×4 矩阵,称为 列主序,这意味着字节是按列写入矩阵,而不是按行写入,如下所示:

每一轮中的第一步是 SubBytes。这是对每个字节分别执行的固定简单替换。替换被设计为高度非线性。线性性质在第 12.3.1 节中详细讨论。
下一步是 ShiftRows。这是一种置换,其中矩阵的行分别向左循环移动 0、1、2 和 3 个位置,像这样:

每轮的第三步,MixColumns,是矩阵乘法。这不是普通的整数矩阵乘法,如第 11.3 节所述。矩阵中的元素被视为多项式的系数。标量加法和乘法运算是在另一个多项式上做的多项式运算。所有这些都经过了精心设计,以便可以在硬件中快速执行这些操作。最后一轮省略了 MixColumns。
每一轮中的最后一步是 AddRoundKey。这只是块与由密钥调度确定的密钥部分进行位异或。
我发现最后的异或运算非常可疑。几位电气工程师告诉我,00 和 11 的异或产生的波形与 01 和 10 的异或产生的波形是不同的,因此窃听者可以分辨出两位的值。这可能向窃听者显示 128 位密钥。在进行高安全性加密时,我尽量避免使用异或运算。
当我被迫在加密结束时使用异或,例如当我正在实现一个标准化算法时,我确保每个密文位的位都被反转偶数次。我保留两个与块大小相同的随机位串 R1 和 R2,以及它们的异或 R3 = R1⊕R2。然后我首先将密文与 R1 进行异或,然后与 R2 进行异或,最后与 R3 进行异或。这将使位串恢复到其原始值,希望波形特征被抹去。
或者,您可以使用替换而不是异或来反转块的所有位。您需要这样做两次,因此您可以使用两个替换步骤来代替三个异或。如果您正在使用 AES,我强烈建议添加这个额外的最终步骤。
11.6 固定替换 vs. 带密钥替换
在本书的早期,所有替换都使用了使用关键字或数字密钥混合的字母表。本章中的密码,DES 和 AES,使用可以嵌入硬件 S 盒的固定替换。哪个更好?哪个更强大?
当您使用固定替换时,您可以使用复杂的数学来设计一个可以抵抗各种攻击的替换。例如,如果一些输出位与一些输入位有很强的相关性,那么 Emily 可以使用密码的统计攻击,例如我在第 8.2 节中对 Jefferson Wheel Cypher 使用的攻击。
不幸的是,固定替换对 Emily 来说是一个易受攻击的目标。她可以研究替换数月甚至数年,并可能发现设计师忽略的弱点。精心设计的替换往往具有数学规律性。替代物被表达为特定的数学函数。这本身可能是一个弱点,因为它为 Emily 提供了模拟您密码的捷径。
我更喜欢使用由可以为每条消息更改的密钥确定的替换。每个带有密钥的替换实例可能比固定替换更弱,但 Emily 无法利用这种弱点,因为她没有替换表供她研究。如果 Emily 设法获取明文,也许是通过间谍活动,她可能能够恢复替换并了解其弱点,但那时已经太迟了。了解弱点的唯一价值是解密消息并获取明文。如果 Emily 已经有了明文,那么密钥就不再有价值。这种弱点不会帮助她解密下一条消息,因为该消息将具有不同的密钥,因此如果有任何不同的弱点。
任何其他替换的实例,当字母表通过相同的方法混合但使用不同的密钥时,可能不会有相同的弱点。它可能具有相同类型的弱点,例如块的某些位和/或密钥的某些位与输出的某些位之间的相关性,但这些对于每个实例都是不同的位。
使用固定的 S 盒的一个论点是,它允许加密硬件的同步操作,其中一个消息紧跟另一个消息,没有间隙。使用混合字母可能需要暂停,而字母被混合。使用混合字母需要一个设置。如果可以并行混合字母,暂停可以被消除或至少减少。也就是说,下一条消息的字母可以在当前消息被加密或解密时被混合。或者,让用户混合字母,并将混合字母包含在长密钥的一部分中。
如果需要同步操作,并且并行混合字母不可行,则回退技术是对块进行与块大小相同的密钥进行两次 DES 或 AES 步骤前后的互斥。我称这种方法为XDESX或XAESX,视情况而定。这些互斥运算非常快速,并且提供了显著的安全性提升。总密钥大小为 184 位,比 3DES 大 16 位。我建议最终输出被反转两次以掩盖波形。
11.7 反身密码
反身密码是说“一个与自身相反的密码”的花哨说法。换句话说,加密和解密是相同的。如果使用反身密码(使用相同的密钥)进行两次加密,你将得到原始明文。这也被称为自反或自逆。我们已经见过一些反身密码。使用二进制密钥对明文进行异或运算是反身的(第 3.3 节)。Bazeries 类型 4 密码中的逐段反转置换(第 4.6.1 节)是反身的。翻转一个方阵,即将字符从左到右写入方形网格,然后从上到下读取,是反身的。以下是一个 3×3 方阵翻转的示例:

数学家称此操作为转置矩阵。由于在密码学中转置有不同的含义,我将称之为翻转矩阵。一个快速翻转矩阵的方法在第 11.2.3 节中已经描述过。
如果你正在硬件中构建你的密码,使用反身密码可以降低成本并简化操作。你的密码机不需要单独的加密和解密模式。
让我们看看如何构造一些类型的反身密码。
11.7.1 反身替换
在反身替换中,如果字母 X 变为 Y,那么 Y 必须变为 X。这意味着字母必须成对出现。要构造一个反身替换,首先列出所有字母或字符。选择任何一个字母,然后选择它的伙伴。划掉列表中的这些字母。然后选择另一个字母及其伙伴。划掉这些字母。继续这样做,直到大部分字母都成对出现。任何剩余的字母都是它们自己的逆。选择连续的字母可以使用数字密钥,就像 SkipMix 一样(第 5.2 节)。
可逆替换可以方便地用两行表示。顶部行的字母直接得到下面的替代,底部行的字母直接得到上面的替代。以下是使用关键词 WORDGAME 和 TULIP 形成的示例。在这个示例中,R 会变成 L,而 L 会变成 R。

换句话说,这个可逆替换的密钥是这个 2 行数组。
并非每个字母都必须与不同的字母配对。一些字母可能保持不变。这些被称为不变量或固定点。
可以通过相同的方法构造可逆的双字母替换。
11.7.2 可逆多表代换
要构造一个可逆的多表密码,只需使表格的每一行都是一个可逆替换。
11.7.3 可逆置换
如果消息被分成固定大小的块,那么构造可逆置换最容易。让我们假设。称固定块大小为 B。如果每个从位置 X 移动到位置 Y 的字母,位置 Y 的字母移动到位置 X,则置换是可逆的。换句话说,置换将由字母的成对交换组成。
要构造一个可逆置换,首先在列表中写下从 1 到 B 的数字。从列表中选择任意 2 个数字。它们是交换的第一对位置。从列表中删除这 2 个数字,并从列表中选择另一对数字。这是第二对。从列表中删除它们。继续这样做,直到列表最多只剩下 1 个数字。如果您选择在置换中有一些固定点,只需更早地停止配对。创建固定点的另一种方法是随机从列表中一次选择 2 个数字。如果这两个数字相同,那就成为一个固定点。
表示一般置换密码的一种方法是列出块中的所有位置,然后在它们下面显示它们的新位置。例如,

这是计算机使用的最佳格式。当一个人在进行置换时,将其折叠到半宽可能更方便,就像这样:

这是相同的置换,但是在一半的空间中。任何一种形式都可以用作置换的密钥。在这两种情况下,第一个位置的字母移动到第 13 个位置,而第 13 个位置的字母移动到第一个位置,第二个位置的字母移动到第 7 个位置,而第 7 个位置的字母移动到第二个位置,依此类推。
*11.7.4 可逆块密码
现在我们已经看到如何构造可逆替换和置换,我们准备将这些元素结合在一起制作一个可逆块密码。
此时,引入更多符号会有所帮助。设 M 是任意消息,可以是明文或密文。我们将将密码 C 应用于该消息表示为 CM。如果 D 是另一个密码,则将 D 应用于文本 CM 的表示为 DCM。这种表示看起来有点奇怪,因为 DCM 意味着先应用 C,然后是 D,但这很有效。你可以将 DCM 理解为 D(C(M)) 的简写。
DC 然后是通过使用 C 和 D 分别进行加密形成的密码。这个新密码被称为 D 和 C 的 组合。组合是一种将两个密码结合起来形成新密码的操作。(有些作者称之为 C 和 D 的 乘积,并用 C◦D 表示。)
例如,Bazeries 类型 4(第 4.6.1 节)将替换与转位结合起来。组合具有一个对于形成可逆密码而言很重要的数学属性:组合是结合的。这意味着如果 A、B 和 C 是密码,则 (AB)C = A(BC)。由于这个属性,多个密码的组合可以不带括号地写成 ABC 或甚至 ABCDEFGH。在这样的组合中可以插入括号而不改变结果。例如,ABCDEFGH 可以写成 A((BC)(DE))F(GH)。
令 I 代表 单位密码,即将每个明文转换为其本身的密码。也就是说,对于任何消息 M,IM = M。设 C 是任意密码。将其逆表示为 C'。(C 必须有一个逆,否则消息就无法阅读。)然后 CC' = C'C = I。当 C = C' 时,密码 C 是可逆的。
假设 T 是一个可逆密码,C 是任意密码。那么密码 CTC' 就是一个可逆密码。这是因为

类似地,如果 A 和 B 是任意密码,则 BCTC'B' 和 ABCTC'B'A' 都是可逆密码,依此类推。
11.7.5 例子,多重翻转
让我们看一个名为 多重翻转 的可逆分组密码的示例。这个密码对 64 位分组进行操作,其形式为 ABCTC'B'A',其中 A 和 C 是一般的多表密码,B 是对 64 位进行的列转置,T 是对 64 位方阵进行翻转。
密码 A 和 C 是周期为 8 的多表密码。也就是说,每个分组的每一行都有一个单独的字母表。每个密码的表格都将有 8 行,按顺序使用。没有用于选择表格行的密钥。相反,8 个密钥用于混合 8 个字母表。总共,A 和 C 需要 16 个不同的密钥,每个密钥可能是与 SkipMix 算法(第 5.2 节)一起使用的数字序列。我建议这 16 个密钥每个包含 3 到 8 个数字,每个数字的范围是 0 到 255。
Cipher B 是一种列置换密码,将 64 位块视为 4×16 网格,因此有 16! 种列的排列方式。64 位被写入网格,从左到右横穿行读出,从上到下竖直读出。列的顺序由一个关键字、关键短语或等效的 16 位数字字符串确定。
Poly triple flip 被评为 Ten.******
11.8 可变长度替换
块密码可以使用固定长度或可变长度替换来构建。VLA 和 VLB 是使用可变长度替换的块密码的示例。VLA 和 VLB 块密码都使用 128 位块,分别视为每个 32 位的 4 行。其思想是在行中使用可变长度替换,然后通过在列中执行 4 位替换来混合块。每个密码的密钥是用于混合标签集和 4 位替换的密钥。
VLA 和 VLB 使用相同长度的后标签替换,如第 10.5.1 节所述。因此,一个 4 位标签被一个 4 位替换所取代,一个 5 位标签被一个 5 位替换所取代,依此类推。这样,块中的每一行保持为恒定的 32 位长。每次替换后,新标签被移动到其行的末尾,并且行被左移以保持其在 4 字节边界上。标签应该平均长度至少为 6 位。
VLA 是更简单的版本。在每轮中,您首先对行的最左边(高位)进行 4 位替换。然后您对每行执行一次后标签替换,带有位移。这将重复 32 轮。整个加密使用 128 个可变长度替换和 32 个固定长度 4 位替换。这个密码评级为 Eight.
当平均标签长度为 6 位时,我建议 VLB 应该有 4 轮,每轮在第 1 行有 6 次替换步骤,在第 2 行有 7 次替换步骤,在第 3 行有 8 次替换步骤,在第 4 行有 9 次替换步骤。
列中的垂直替换应在第 1、2 和 3 轮之后进行。为了提高速度,不需要在每一列的每一轮都进行列替换。一个合理的选择是例如在第一轮后每 3 列进行一次替换,即在第 1,4,7, ... ,31 列,在第 2 轮后在第 2,5,8, ... ,32 列进行替换,在第 3 轮后在第 3,6,9, ... ,30 列进行替换。
VLB 被评为 Ten,可能是具有这个评级的最快密码。它需要 120 个可变长度替换,带有位移,并且 32 个垂直 4 位替换,因此比 VLA 稍快。
11.9 波纹密码
Ripple 密码,也称为 wraparound 密码或 end-around 密码,是基于本章前面的密码完全不同原理的块密码。其基本思想是,块中的每个 8 位字符都用作加密其右侧的下一个字符的密钥。然后再用这个字符来加密下一个字符,依此类推,一直到块的长度结束并在结尾处环绕。也就是说,块中的最后一个字符用作加密第一个字符的密钥。Ripple 密码最适合软件实现,因为它们几乎不提供并行操作的机会。
有各种各样的 Ripple 密码。它们的块长度可以从 2 开始,长度可以周期性地或随机变化。我建议最小的块长度为 5 个字符,但你可能更喜欢从 8 开始。例如,你可以使用链接的数字生成器来选择块长度。当生成器产生数字 D 时,你可以使下一个块的长度为 D+5,或者可能是 D+8,甚至是 20-D。
块可以重叠。例如,你可以使用固定的块长度为 8,块从位置 1、6、11、16、... 每 5 个字符开始。最后一个块可以环绕到消息的开头。当消息长度为 20 时,最后一个块可以由字符 16、17、18、19、20、1、2、3 组成。
Ripple 密码纯粹是替换密码;它们根本不涉及置换。Ripple 密码的最简单形式是对每个连续的字符进行异或,因此 x[n] 被替换为 x[n-1]⊕x[n]。然后 x[n+1] 被替换为 x[n]⊕x[n+1],依此类推,通过整个块进行波动。
有很多种方法可以利用前一个字符来对下一个字符进行加密。下面是部分列表。这里 A、B 和 C 是简单的替换密码,P 是一般的多表密码。A(x)、B(x) 和 C(x) 分别表示用 A、B 和 C 加密的字符 x,而 P(k,x) 表示用密钥 k 选择表格中的行来加密 x。
| xor | 异或 | x[n] 被替换为 x[n-1]⊕x[n]。 |
|---|---|---|
| sxor | 替换和异或 | 有三种变体,x[n] 可以被替换为 A(x[n-1])⊕x[n],或者 x[n-1]⊕B(x[n]),或者 A(x[n-1])⊕B(x[n])。 |
| xors | 异或和替换 | x[n] 被替换为 A(x[n-1]⊕x[n])。 |
| add | 加法 | x[n] 被替换为 x[n-1]+x[n]。如常,加法为模 256。 |
| madd | 乘法和添加,也称为 线性替换 | x[n] 被替换为 px[n-1]+x[n],或者 x[n-1]+qx[n],或者 px[n-1]+qx[n],其中 p 可以是任意整数,q 可以是任意奇数。(如果你使用的字母表大小与 256 不同,q 必须与字母表大小互质。) |
| sadd | 替换和添加 | x[n] 被替换为 A(x[n-1])+x[n],或者 x[n-1]+B(x[n]) 或者 A(x[n-1])+B(x[n])。 |
| adds | 加法和替换 | x[n] 被替换为 A(x[n-1]+x[n])。 |
| poly | 通用多表替换 | x[n]被 P(x[n-1], x[n])替换。 |
由于xor或sxor可能会泄露有关其操作数的信息,我建议改用xors,这样在执行异或操作后进行简单替换以掩盖波形,即 A(x[n-1]⊕x[n])。
请注意,madd只是sadd的一个特例。也就是说,px[n-1]只是 A(x[n-1])的一个特定选择。madd的优点在于它不需要预先设置阶段来混合替换字母表。同样地,请注意 P(A(x[n-1]), B(x[n]))只是对表格的行和列进行排列,因此等同于 P(x[n-1], x[n]),只是使用了不同的表格。
这些涟漪方法中最强大的是poly,其中前一个字符 x[n-1]被用作选择用于加密 x[n]的表格中的行的关键。我将这种方法称为关键涟漪。这将需要一个 256×256 字节的表格。如果这太大了,可以通过在使用它作为密钥之前对 x[n-1]应用减少替换来将 x[n-1]减小到更小的范围。例如,x 可以被减小为 x mod 16,或者为(13x+5) mod 32。适当的减小范围是 0 到 15,0 到 31 和 0 到 63。如果 R 是减少替换,P 是多表替换,那么 x[n]将被 Q(R(x[n-1]),x[n])替换,其中 Q 是一个由 P 的表格顶部 16、32 或 64 行组成的减少表的多表密码。
如果您无法使用多表密码,也许是因为即使减少表格也使用了太多空间,或者因为设置时间太长,那么下一个最佳选择是使用 3 个简单替换。将 x[n]替换为 A(B(x[n-1])+C(x[n])或 A(B(x[n-1])⊕C(x[n])。这被称为空间-时间权衡。这 3 个简单替换可能比单个多表替换需要更长的时间,但它们将空间需求从 65,536 字节减少到 768 字节,减少了 98.8%。
涟漪密码不限于仅使用前一个字符来加密当前字符。如果愿意,可以回溯几个字符,例如用 A(x[n-i]⊕x[n])替换 x[n],其中 i 可以是小于块大小的任何值。也可以使用多个先前的字符,例如 x[n-2]+x[n-1]+x[n]或更一般地 x[n-j]+x[n-k]+x[n]。使用通用多表替换,x[n]可以被 P(x[n-4]⊕x[n-2],x[n])替换,或者 P(x[n-5],P(x[n-1],x[n]))或其他无限组合。
正如我提到的,可以使用任何块大小。替换可以从块中的任何字符开始,并在块中的任何字符结束,只要每个字符至少被替换一次。如果需要,您可以绕块走几次,从最后一个字符到第一个字符。甚至可以重叠超过 2 个块,或者使一个块完全位于另一个块或一组块内。块大小、块内的起始位置、要替换的字符数以及与前一个和/或后一个块的重叠可以固定,可以定期变化,也可以随机生成。
涟漪密码甚至可以进一步发展。一条消息可以使用几轮涟漪密码进行加密。在每一轮中,消息可以被分成不同大小的块,以便块边界很少或从不对齐,并且加密在块中的不同点开始和结束。这会产生马赛克甚至万花筒效果。
涟漪密码的变体太多,无法一一列举。这些密码的评级可以从四到十不等。以下是一些示例。简单的xor涟漪使用固定大小的块,进行 2 轮替换,从块的第一个字节开始,以最后一个字节结束,并且只使用前一个字节作为替换密钥,评级为四。使用不同大小块的sadd涟漪密码,从块中的可变位置开始,进行至少 3 轮替换,以可变位置结束,并且使用前一个字节作为替换密钥,评级为七。使用不同大小块的poly涟漪密码,从块中的可变位置开始,进行至少 3 轮替换,以可变位置结束,并且使用前一个字节加上另一个从块到块变化的字节作为替换密钥,评级为十。马赛克方法比单层方法更强大。
11.10 块链接
块链接是一种增强任何块密码的有价值工具。块链接意味着使用每个块来帮助加密下一个块。实际上,链接是一个在块上操作的涟漪密码,而不是在单个字符上操作。从第 N 块传递到第 N+1 块的字节组称为链向量。由于消息中的第一个块没有前驱,大多数链接方案使用初始化向量(IV)来加密第一个块,就好像它是从某个虚构的前身块的链向量一样。初始化向量可以从加密密钥派生,也可以被视为加密的附加密钥。
旁注:比特币和其他加密货币使用的块链接是密码学中使用的块链接的一种专门形式。这就是他们得到这个想法的地方。

最常见的链接形式是逐字符将链向量与下一块结合起来。结合字符的最常见方法是独占或。然而,在第 11.8 节中描述的任何结合方法都可以使用。这通常以四种模式之一进行。
| 模式 | 描述 |
|---|---|
| PP | 第 N 块的明文在加密第 N+1 块之前与第 N+1 块的明文组合。 |
| PC | 第 N 块的明文在加密第 N+1 块之后与第 N+1 块的密文结合。 |
| CP | 第 N 块的密文在加密第 N+1 块之前与第 N+1 块的明文组合在一起。 |
| CC | 第 N 块的密文在加密第 N+1 块之后与第 N+1 块的密文结合。 |
为了最大的强度,链接操作应该是累积的。首先,将第 N-1 块的链向量与第 N 块组合。这个结果成为新的链向量,与第 N+1 块组合。链接模式 PP 最强,链接模式 PC 次之。模式 CP 和 CC 远远较弱,因为艾米丽可以看到链向量。我建议只有在使用 xors、adds 和 poly 这些组合函数时才使用模式 CP 和 CC。
虽然 CC 和 CP 模式较弱,但使用它们有优势。在 CC 和 CP 模式下,无需单独的初始化向量。桑德拉可以使用明文消息的最后一个块作为初始化向量。瑞娃可以简单地先解密最后一个块。事实上,瑞娃可以解密任何块,而无需解密前一个块。如果密码使用指示符(第 14.3 节),则这可能非常有价值。瑞娃会首先解密指示块。
让我们来看一些更强的块链接方式。
11.10.1 多表链接
独占或(Exclusive-OR)是一种将第 N 块与第 N+1 块结合的弱方法。一种更好的方法是 xors,即首先使用独占或,然后对结果字符进行简单的替换。比那更好的是使用 poly,一种通用的多表密码。使用链向量中的每个字符作为密钥,选择用于加密第 N+1 块中相应字符的表中的行。可以使用任何 4 种链接模式。模式 PP 最强大。
11.10.2 加密链接
链接的标准模式将第 N 块的明文或密文作为链向量使用,不进行修改。将某些加密应用于链向量会更强大。这可以是简单的,如简单的替换或分段反转(第 4.6 节)。如果替换或置换对于每个块都不同,这种简单的方法可能是有效的。钥匙脉冲很适合这个目的(第 11.8 节)。用于链向量的加密应具有自己独立的密钥。如果链向量更强加密,模式 CC 和 CP 将不再是弱项。
11.10.3 拖延链接
链接不仅限于前一个块。链接还可以利用更早的块。块 N 可以与块 N-i 或多个先前的块组合,例如块 N-i 和块 N-j。如果 i > j,则需要 i 个块的初始化向量。
同样,链接向量可以跨越多个先前的块。例如,链接向量可以来自第 N-2 块的后半部分和第 N-1 块的前半部分。
11.10.4 内部 tap
使用明文或密文作为链接向量的一个弱点是,这些内容可能为 Emily 所知。一个解决方案是对链接向量进行加密,如第 11.10.2 节所述。第二个解决方案是从块加密的某个中间轮获取链接向量。这称为 tap。例如,如果块密码有 10 轮,您可以使用第 5 轮的输出作为链接向量。在开始加密下一个块之前,将此链接向量与下一个块的明文组合。这是模式 IP。
这可以进一步发展。您可以使用多个 tap,它们可以与以下块的多个位置组合,可以与明文、密文或加密的轮之间组合。每个 tap 产生一个单独的链接向量,因此对于 N 个 tap,您必须有 N 个初始化向量。这些链接向量可以使用相同的密钥加密,或者每个都可以有自己独立的密钥。涟漪密码(第 11.8 节)非常适合加密链接向量。
11.10.5 密钥链接
通常,链接是在每个块的文本上进行的。但是,也可以将链接与密钥一起使用。假设您有一个块密码,其中每个块都使用相同的密钥 K。通过链接,可以极大地增强该密码。您使用 K 作为密钥对第一个块进行加密(初始化向量对于密钥链接是可选的)。然后,您可以使用 K●P[1]、K●C[1] 或 K●I[1] 作为密钥对第二个块进行加密,其中 ● 表示逐字节执行的某种组合函数,例如 xors 或 adds。同样,您可以使用 K●P[2]、K●C[2] 或 K●I[2] 作为密钥对第三个块进行加密,依此类推。这给您带来了三种新的链接模式,PK、CK 和 IK。可以同时使用密钥链接和块链接,例如 PK 与 IP。这是一种非常强大的组合。
11.10.6 链接模式总结
总共有 12 种可能的链接模式。链接向量可以来自三个来源之一:明文、内部阶段或当前块的密文。链接向量可以与四个目标之一结合使用:密钥、明文、内部阶段或下一个块的密文。
除了这些选择之外,链向量可以每次都新生成,也可以与前一个分组的链向量合并。链向量可以原样使用,也可以在与目标合并之前加密。链接可以作用于连续的分组,也可以滞后。有很多很多选择。
11.10.7 链接短分组
当消息中的最后一个分组较短,并且您使用重叠方法(11.2.4 节)来处理短分组时,不清楚如何链接重叠的分组。解决方法是从倒数第二个分组开始链接。如果有 N 个分组,则从第 N-2 个分组的链接向量用于第 N-1 个分组和第 N 个分组。
11.10.8 链接可变长度分组
在我们离开分组链接主题之前,还有一个问题需要解决,即可变分组大小。我建议链向量保持固定长度。如果消息分组的长度 L 小于链向量的长度,则将链向量的前 L 个字节与消息分组结合。替换链向量的这些 L 个字节,保持其余部分不变。例如,如果链向量为 1234567890,而分组为 SAMPLE,则将 123456 与 SAMPLE 结合。如果结果是 ZQm”w+,则分组变为 ZQm”w+,链向量变为 ZQm”w+7890。

如果链接向量短于消息分组,则使用所需数量的自身副本扩展此分组的链接向量。例如,如果链接向量为 123456,而分组为 CONVENTION,则将 1234561234 与 CONVENTION 结合。如果结果是 qA&Vm!7^oS,则分组变为 qA&Vm!7^oS,链接向量变为 qA&Vm!。

在两种情况下,分组在链接后仍保持相同的长度,链向量也保持相同的长度。
11.11 加强分组密码
一旦您拥有了强大的分组密码,就可以通过很少的额外工作进一步加固它。所需的只是在应用分组密码之前轻微地加密明文,并在完成分组密码后轻微地加密密文。我称之为三明治技术,额外的步骤称为预加密和后加密步骤。如果你感觉顽皮,你可以称之为鲁宾三明治。所谓“轻微地”,我是指使用简单的一轮一步密码,例如简单替换或密钥置换(7.6 节)。例如,您可以在分组密码之前使用简单替换,之后使用密钥置换,或者反之亦然。一种更强大但更快速的选择是将分组的前 8 个字节视为两个 32 位整数,并将每个整数乘以范围在 3 到 2³²-1 的奇数乘数模 2³²。
由于块密码已经足够强大,这些额外步骤的主要目的是增加总键大小,以阻止暴力破解攻击和中间人攻击。这在预密码和后密码步骤具有长键且与块密码键独立的情况下效果最佳。例如,如果预密码或后密码是简单的替代,它可能具有长的 SkipMix 密钥。
作为一个实际的例子,DES 使用了一个小的 56 位密钥。如果您添加了简单的替换预密码和后密码步骤,每个步骤都有一个独立的 64 位混合密钥,那么总密钥大小将达到 184 位。这比 3DES 更强大,几乎快 3 倍。
DES,然而,是没有任何设置阶段的设计。预密码可以轻松完成,没有设置。只需将一个 64 位的预密码密钥与明文进行异或运算。这将总键大小从 56 位增加到 120 位。这单独就比 2DES 更强大,更抵抗中间人攻击。后密码步骤有点棘手。我们希望避免使用异或作为最后一步,原因前面已经讨论过,并且我们也不想有设置。这可以通过使用固定的多表密码来实现。也就是说,表格是事先选择并内置到设备或软件中。
一个可能性是使用 16×16 的 4 位组表。64 位块被视为十六个 4 位组。每个 4 位组使用 64 位后密码键的 4 位进行加密。因此,总键大小再次为 184 位。这也比 3DES 更强大,几乎快 3 倍。
这种方法有效的原因是 DES 本身已经足够强大,以至于唯一实际的攻击是暴力破解。将额外的 128 位添加到密钥使暴力破解变得不可行。
第十二章:安全加密的原则
本章涵盖
-
安全加密的五个原则
-
大块和长密钥
-
混淆或非线性
-
扩散和饱和
让我们将在第十一章学到的一切汇总起来。在 12.1 到 12.5 节中,我们将概括出使块密码安全的 5 个基本原则。安全块密码的一个标志是,改变密钥中的任何位或明文中的任何位将导致密文块中约 50%的位发生变化,最好是以看似随机的模式。改变任何其他位也会导致密文块中约 50%的位发生变化,但是以不同的模式。让我们称之为五五开特性。本章将描述如何实现这一点。
12.1 大块
我们已经看到,双字母密码可以像简单替换密码一样解决,方法是编制双字母频率和接触频率。这也可以用于三字母和四字母,尽管需要大量的密文。对于手工完成的块密码,应考虑的最小块大小是 5 个字符。对于计算机密码,最小块大小是 8 字节。大块大小的一个目的是防止 Emily 像解码一样解决密码。也就是说,Emily 会找到重复的密文块,并从它们的频率和在消息中的位置推断它们的含义。以极端情况为例,如果块大小为 1 个字符,那么无论密钥有多大,使用了多少加密步骤,密码仍然只是一个简单的替换。
在英语中有许多 8 个字符的序列是足够常见的,以至于在长消息中会重复出现。以下是一打例子,使用省略号...表示空格。

如今的标准块大小是 16 字节。没有那么长的高频英文短语。可能会有一些长的上下文短语,比如 UNITED STATES GOVERNMENT,EXECUTIVE COMMITTEE,INTERNATIONAL WATERS 等等。然而,要产生重复的密文块,这些明文重复必须以相同的方式与块边界对齐。例如,16 字节的明文块 UNITED...STATES...GO 和 NITED...STATES...GOV 在使用强大的块密码时不会产生可识别的密文重复。
当您使用块链接(第 11.9 节)时,重复的密文块问题消失了。使用块链接时,可以使用任何大于等于 8 字节的块大小。
12.2 长密钥
我们知道,安全的密码必须具有一个大密钥以防止暴力破解攻击。当前的标准是 128 位密钥。如果您希望您的消息保密 20 年或更长时间,我建议最低使用 160 位。这相当于约 48 个十进制数字,40 个十六进制数字或 34 个单个字母。
如果你是手动输入密钥,我建议你以统一的方式构建你的密钥。用一致的格式将密钥分成相同大小的块。这里有两种统一结构密钥的样式。在第一种样式中,每个块中的所有字符都是相同类型的,大写字母、小写字母或数字。在第二种样式中,块的格式相同,有两个大写字母和三个数字。

这两个密钥中的第一个相当于约 191 位,第二个相当于约 174 位。对于这样长的密钥,你必须能够在输入时看到字符,以便在需要时进行复查和更正。当密钥完成时,应用程序应显示一个校验和,以便您验证密钥是否正确。
这种规律的一个好处是防止将字母 O 误认为数字 0,或者字母 I 误认为数字 1。我不建议随机混合字符,比如\(v94H;t}=Nd⁸**,因为这会导致错误。如果你使用密钥**\)v94H;t}=Nd⁸加密了一个数据文件,然后你用密钥$V94H;t}=Nd⁸解密它,那么该数据文件现在可能无法恢复。你可能永远都不知道出了什么问题以及如何解决。在你的密钥中使用统一的块有助于防止这种灾难发生。
另一种有助于防止输入错误的密钥形式是人工词。制造你自己的可以发音的字母组合,就像这样:

尽量避免模式,比如使用相同的元音组合,palek mafner vadel glabet之类的,所有单词都使用 A-E 元音模式。
这些字母数字密钥可以被软件转换成二进制形式。madd连锁密码(第 11.8 节)非常适合这个任务。
作为加密每条消息或数据文件的关键字的替代方案是使用一个关键字管理器,它生成关键字并将它们与消息或文件关联起来。关键字管理器可以安装在一个对桑德拉和里娃都可访问的网站上。这个话题不会在本书中涵盖。请注意,关键字管理器与密码管理器不同,因为桑德拉和里娃在不同的计算机上工作时必须为每个文件使用相同的关键字。
12.2.1 冗余密钥
在某些情况下,艾米丽可能会设计方程,将密文与明文和密钥相关联。如果艾米丽知道或能够猜测一些明文,这些方程可能使她能够确定密钥。例如,她可能知道一些消息以全大写字母 ATTENTION 开头。这可能足以使她在使用 8 字节块大小时解决 64 位密钥。
战胜这种潜在攻击的一种方法是扩大密钥。 例如,如果块大小为 64 位,但密钥大 32 位,即 96 位,则您可以期望,平均而言,会有大约 2³²个可能的密钥将已知的明文转换为密文。 艾米莉需要筛选这 2³²个解决方案以找到正确的解决方案。 这可能是一项困难的任务,因为超过 4,000,000,000 个可能性中的许多可能看起来像合理的文本。
扩大密钥会使艾米莉的任务变得更加困难,但不一定是不可能的。 如果她有两倍于已知明文的量,则可能使用两个密码块的方程式来解出密钥。 但是,拥有这么多已知明文是非常罕见的,解决两倍数量的方程可能需要的时间远远超过两倍。 根据艾米莉使用的方程式类型,解决一组 64 个方程可能是可行的,但解决一组 128 个方程可能是不可行的。
如果艾米莉没有可解的方程式,则冗余密钥可使暴力攻击变得更加困难和昂贵。 无论如何,冗余密钥都会使艾米莉工作更加艰难。
12.3 混淆
在 1945 年,信息论创始人克劳德·香农描述了强密码必须具备的两个属性。 他称这些为混淆和扩散。 通过混淆,香农指的是明文和密文之间不应有强相关性。 同样,密钥和密文之间也不应有强相关性。 通过扩散,香农指的是密文的每一部分都应该依赖于明文的每一部分和密钥的每一部分。
我将添加到香农两个属性的第三个属性。 我称这个属性为饱和。 这个想法是衡量密文的每一位或每一字节如何依赖于明文的每一位或每一字节以及密钥的每一位或每一字节。 饱和度越高,密码就越强。 本节以及接下来的两节将详细讨论这三个属性,混淆、扩散和饱和。
在分组密码中有两种替换类型,固定和键入。 键入的替换是可变的,可以为每个消息甚至每个块更改。 在第 11.6 节中讨论了这些方法的利弊。 如果您决定使用键入的替换,或者如果您发现本节中的数学很困难,那么您可以直接跳转到第 12.4 节。 您可以使用在第 5.2 节和 12.3.7 节中描述的 SkipMix 算法构建您的混合字母表或表,然后使用伪随机数生成器选择跳过的顺序。
在香农的理解中,混淆基本上是线性与非线性的问题。 如果您的分组密码使用固定的字母表或表格,线性性质至关重要。 整个线性代数领域都建立在线性概念上。 线性性 这个术语来自解析几何学。 一条直线的方程是 ax+by = c,其中 a、b 和 c 是常数,变量 x 和 y 表示直线上某点的笛卡尔坐标。 如果直线不与 y 轴平行,方程可以表示为 y = ax+b。 ax+by = c 和 y = ax+b 都是线性方程或线性关系的例子。
凯撒密码(第 4.2 节)是线性密码的一个例子。 凯撒密码可以被看作是将密钥加到明文上以获得密文,c = p+k。 这里 c 是密文字母,p 是明文字母,k 是密钥。 密钥是字母已经移动的量。 凯撒大帝使用了一个移位为 3 位的密码,这意味着字母表中的每个字母都被替换为后面 3 位的字母,c = p+3,字母接近字母表末尾的位置将被移到字母表的开头。
顺便说一句,凯撒的方法并不像听起来那样脆弱,因为凯撒用希腊字母写他的信息。 在凯撒时代,受过良好教育的上层罗马人,如凯撒及其将军,懂希腊语,就像 19 世纪的上层英国人学习拉丁语和贵族俄罗斯人说法语一样。
在涉及替换步骤和置换步骤的分组密码中,如果单个替换是非线性的,则整个密码是非线性的。 实际上,如果分组密码有多轮替换,那么只要有一个早期轮次是非线性的,整个密码就是非线性的,前提是该轮次涉及块中的所有单元。 一旦失去了线性性质,就无法在后来的轮次中重新获得它。 让每一轮都是非线性的将会更加强大,但是即使只有一个非线性轮次,特别是如果它出现在开始位置,也比没有强。
有线性和非线性的程度。 替换可以是高度线性的、弱线性的、弱非线性的或高度非线性的。 每种情况的一个例子应该可以说明问题。 我已经在明文字母表中的每个字母位置与密文字母表中的对应位置之间画了一条线。 你可以立即看到,随着替换变得更加非线性,字母表的混合程度有多好。

在接下来的讨论中,我将 S 盒的输入称为明文和密钥,将输出称为密文。这些术语指的是该单个 S 盒的明文和密文,并不一定是整个多轮分组密码的明文和密文。在某些分组密码中,S 盒没有密钥,它们仅执行简单的替换。在这种情况下,你可以想象 S 盒具有一个密钥,其常量值为 0,或者 S 盒密钥的长度为 0 位。
假设 Emily 能够测试 S 盒的线性度,因为密码已经发表,或者她已经获得了该设备的副本。如果 Emily 所拥有的仅仅是第一轮的输入和最后一轮的输出,那么线性度测试可能就不可行了。
12.3.1 相关系数
有一种既定的统计方法用于测试两个数值变量之间的相关性。例如,你可以测试温度和阳光之间的相关性,温度以摄氏度度量,阳光以小时为单位度量。温度和小时是数值变量。你可以进行多次试验,在某个固定的时间测量温度,并记录那天的阳光小时数。这将为你提供两个数字列表,一个列表用于温度,另一个列表用于相应的阳光小时数。该统计量衡量这两个数字列表之间的相关性。
在我们的情况下,两个变量是明文字母和密文字母。"试验"是字母在字母表中的位置。例如,第一个试验可以是"A",最后一个试验可以是"Z"。字母表中的字母需要以某种方式编号。编号将取决于字母表的大小。例如,一个 27 个字母的字母表可以使用 3 个三进制(基数 3)数字编号,就像我们在第 9.9 节中对三肽密码所做的那样。相关性可以是明文字母的任何三进制数字与密文字母的任何三进制数字之间的相关性。在接下来的两节中,我将详细讨论这一点,分别讨论 26 个字母的字母表和 256 个字符的字母表。
线性度通过计算两个变量之间的相关性来衡量。到目前为止,最广泛使用的相关性度量是由英国数学家卡尔·皮尔逊(Karl Pearson)开发的皮尔逊积差相关系数,他是生物统计学的奠基人,并于 1895 年发表,尽管这个公式本身在 1844 年由法国物理学家奥古斯特·布拉维斯(Auguste Bravais)发布,他以晶体学的工作而闻名。相关系数的目的是得到一个单一的数字,告诉我们两个变量的相关程度,这个数字的含义不受测量单位或所涉及的数字大小的影响。
如果两个变量具有线性关系,则相关性为 1。如果变量之间没有任何相关性,则相关性为 0。如果两者具有反向关系,则相关性为-1。例如,抛硬币 20 次中正面朝上的次数与反面朝上的次数将具有反向关系。相关性为 0.8 表示强烈的线性关系,而相关性为 0.2 表示关系高度非线性。
与大多数教科书一样,我不仅仅是呈现公式,我将解释它是如何以及为什么有效的。理解它的工作原理将帮助您正确和适当地使用它。
这里的目标是比较两个变量。这是通过比较一系列试验中的值来完成的。例如,我们可能想比较在伊斯法罕的凯萨里耶巴扎尔出售的魔毯价格与其尺寸。影响魔毯价格的因素有很多,包括纱线类型、结的密度、设计的复杂性,当然还有飞行速度。
居中
比较变量的第一步是将它们并排放置,就像您通过视觉比较它们一样。换句话说,您希望消除线性关系 P = mA+x 中的+x 项,其中 P 是价格,A 是面积。看起来您可以计算差值 P[i]-A[i],然后从 P 中减去平均差值。然而,这是没有意义的,因为 P 和 A 是以不同单位表示的。地毯面积 A 以平方阿尔萨尼(大约一米)为单位,而巴扎尔中的地毯价格 P 以图曼(波斯货币)计价。
您需要分别调整面积数字和价格数字,因为它们是以不同单位表示的。诀窍是取平均价格并从所有价格数字中减去以获得新的调整后的价格数字 P'。您通过将地毯价格相加并除以地毯数量来计算平均价格μ[P]。例如,如果价格分别为 1000、1200 和 1700 图曼,您将把这 3 个价格相加 1000+1200+1700,然后除以 3 得到平均价格 1300。您将从每个价格中减去 1300 以获得调整后的价格-300、-100 和 400。正如您所看到的,调整后的价格 P'相加为 0。在某种意义上,调整后的价格围绕 0 居中。
区域图形以相同的方式居中。您将所有区域相加,然后除以地毯数量得到平均面积。例如,如果面积分别为 10、12 和 17 平方阿尔萨尼,您将把这 3 个面积相加 10+12+17,然后除以 3 得到平均面积 13。然后,您将从每个面积中减去 13 以获得调整后的面积-3、-1 和 4。调整后的面积 A'也相加为 0。现在,调整后的面积和调整后的价格都围绕 0 居中。它们并排放置,准备进行比较。

缩放
下一步是将价格和面积放在同一尺度上。价格是以土曼为单位的,面积是以平方阿尔萨尼为单位的,而从土曼到平方阿尔萨尼的转换是不存在的。那就像是从蒲式耳到摄氏度的转换一样。皮尔逊,或者更确切地说是布拉维,使用了线性代数中的一个概念,称为归一化。
假设你有一个向量(a,b),你想找到一个指向同一方向的向量,但长度为 1。任何向量(a,b)的倍数,比如(ma,mb),都会指向同一方向。乘以一个向量会改变它的长度,但不会改变它的方向。如果你将向量除以它的长度,新向量(a/L,b/L)的长度将为 1,并且方向与原始向量相同。这也清除了单位。想象一下,向量的长度是用英尺来衡量的。如果你将向量除以它的长度,那么你得到的就是英尺除以英尺。结果只是一个数字,没有单位。它是无量纲的。当向量用土曼或平方阿尔萨尼来衡量时,情况也是如此。
向量的长度可以很容易地通过使用勾股定理找到,L = √(a² + b²)。这可以扩展到任意维度,L = √(a² + b² + c² + ...)。让我们试一个例子来看看这是否有效。尝试向量(3,4)。这个向量的长度是 √(3² + 4²) = √(9 + 16) = √25 = 5。归一化向量是 (3/5,4/5)。因此 √((3/5)² + (4/5)²) = √(9/25 + 16/25) = √25/25 = 1 是归一化向量的长度,如预期的那样。它有效。
P、A、P' 和 A' 都是数字列表,因此它们是向量。它们像任何向量一样有长度,并且可以像任何向量一样归一化。在几何学中,通过将向量除以其长度来归一化向量。任何归一化向量的长度始终为 1。
要将 P' 归一化,你只需对所有调整后的价格进行平方,然后将这些平方相加并取这个和的平方根。这给出了 P' 的长度。将调整后的价格 P' 除以长度得到归一化价格 P''。要将 A' 归一化,你只需对所有调整后的面积进行平方,然后将这些平方相加并取这个和的平方根。这给出了 A' 的长度。将所有调整后的面积 A' 除以长度得到归一化面积 A''。

总结一下,(1)通过减去平均值来将价格和面积居中,然后(2)通过除以长度来归一化价格和面积。结果是一个标准化的价格列表和一个标准化的面积列表,其中每个列表中项的总和为 0,每个列表中项的平方和为 1。
现在我们准备好使用公式了。将价格的归一化列表中的每一项乘以面积的归一化列表中的相应项,即 P''[i]×A''[i]。将这些乘积相加。这就是相关系数。(在线性代数中,这被称为归一化价格向量和归一化面积向量的内积或点积。)
让我们对此进行现实检验。想象我们正在测试摄氏温度和华氏温度之间的相关性。我们知道它们通过线性公式 F = 1.8C+32 相关,因此相关系数应该为 1。假设我们在上午 11 点、下午 3 点、晚上 7 点和 11 点测量温度,并发现摄氏温度分别为(14,24,6,0),华氏温度为(57.2,75.2,42.8,32)。摄氏温度的平均值为(14+24+6+0)/4 = 11,因此调整后的摄氏温度 C' 为(3,13,-5,-11),对应的调整后的华氏温度 F' 为(5.4,23.4,-9,-19.8)。摄氏温度 C' 的长度为 18。将 C' 除以 18 得到 C'',归一化后的摄氏温度(3/18,13/18,-5/18,-11/18)。调整后的华氏温度 F' 的长度为 32.4,归一化后的华氏温度 F'' 为(3/18,13/18,-5/18,-11/18)。
我们将 C'' 逐个元素与 F'' 相乘,然后将 4 个乘积相加以得到相关系数。这个和是(3/18)²+(13/18)²+(-5/18)²+(-11/18)²。总和为 1。这支持了先前描述的过程,即通过减去平均值进行居中,通过除以长度进行归一化,然后逐项相乘并求和,确实产生了有效的相关系数。
总结一下:通过计算相关系数来测试线性。本节向您展示了如何计算相关系数。计算结果为介于-1 和+1 之间的数字。以下是解释相关系数的图表。

12.3.2 基-26 线性
让我们从基于 26 个字符的字母表的替换开始调查线性。如果您正在设计机械或机电密码设备,或者正在模拟这样一个设备,这可能很有价值。这种机器中的每个转子都对一个包含 26 个字符的字母表进行替换。首先考虑一个没有密钥的 S-box。在使用 26 个字母表时,可能会出现多种形式的线性,这取决于字母的编号方式。可以从 3 种方式来看待字母表:将字母表视为一个 26 个字母的序列,将其视为一个 2×13 的字母数组,或者将其视为一个 13×2 的字母数组。这导致 3 种不同的字符编号方式:N1、N2 和 N3,如所示。对这 3 种编号方案的讨论使用模运算。如果您现在想复习模运算,请参阅第 3.6 节。

编号方案 N2 和 N3 遵循常规约定,使用字母 A、B 和 C 表示 9 以外的数字。也就是说,它们使用了 16 个十六进制数字中的前 13 个。在最简单的线性加密(Belaso 密码)中,密钥只是加到明文中。当将密钥加到明文字符中时,在 N1 编号方案中,它使用传统的模 26 加法。当将密钥加到 N2 编号方案中的明文字符时,第一个数字是模 2 加法,第二个数字是模 13 加法。相反,当将密钥加到 N3 编号方案中的明文字符时,第一个数字是模 13 加法,第二个数字是模 2 加法。以下是展示单词 THE 如何在每种方案中通过添加密钥 J 进行加密的示例。

如果纯文本、密钥和密文字母都使用 N1 方案编号,则线性替换或线性变换会将明文字符 p 转换成密文字符 c = mp+f(k),其中 m 是一个乘数,必须与 26 互质,f(k) 是任意整数值函数,算术运算是模 26 运算。例如,如果 m = 5,p = 10,k = 3,而 f(k) = k²+6,则 c = 13,因为 5×10+3²+6 = 65 ≡ 13 (mod 26)。常数 m 和函数 f(k) 可以构建到替换表中。
如果纯文本、密钥和密文字母都使用 N2 或 2×13 编号方案进行编号,则第一个数字或第二个数字或两个数字都可以是线性的。假设两个数字都是线性的。那么,一个明文字符 p = a,b 使用密钥 k 转换成密文字符 c = ma+f(k),nb+g(k),其中 m 必须与 2 互质,即 m = 1,n 必须与 13 互质,而 f(k) 和 g(k) 可以是任意整数值函数。分别进行模 2 和模 13 运算。常数 m 和 n,以及函数 f(k) 和 g(k) 可以构建到替换表中。
如果纯文本、密钥和密文字母都使用 N3 或 13×2 编号方案进行编号,则第一个数字或第二个数字或两个数字都可以是线性的。假设两个数字都是线性的。那么,一个明文字符 p = a,b 使用密钥 k 转换成密文字符 c = ma+f(k),nb+g(k),其中 m 必须与 13 互质,n 必须与 2 互质,即 n = 1,而 f(k) 和 g(k) 可以是任意整数值函数。分别进行模 13 和模 2 运算。常数 m 和 n,以及函数 f(k) 和 g(k),可以构建到替换表中。
平文和密文没有必要以相同的方式编号。在任何编号中,平文的任何数字与密文的任何数字之间都可能存在相关性。艾米莉可能会测试这些组合中的任何一个或全部,寻找可利用的弱点。因此,密码的设计者必须测试所有可能的编号和相关性,以验证没有这种弱点存在,或者了解必须采取哪些对策以防止艾米莉利用这种弱点。例如,您可以在分组密码的交替轮次中使用具有不同弱点的替换。在大多数情况下,每个替换都会减弱另一个的弱点。当然,您应该通过搜索明文和最终密文之间的线性关系来测试这一点,后者是由最后一轮产生的。
如果你想测试替换的线性性,就不能直接应用相关系数。这是因为所有这些替换都是使用模算术完成的。考虑一下使用 N1 编号方案进行的这种替换:

这几乎完全是 c = 2p,所以它非常线性。然而,使用该编号方案计算的明文和密文字母之间的相关系数为 0.55556,表明替换只是弱线性的。应该使用以下分布计算相关系数,该分布在模 26 下是等效的。

使用该编号的相关系数为 0.99987,正确显示了非常强的线性性。
这说明了在密码学中使用相关系数的困难。你总是在字母表的大小模下工作。要找到正确的相关性,你需要添加 26,然后是 52、78 等等,对于 N1 编号是这样,或者对于 N2 和 N3 编号是 13、26、39 等等。在前面的例子中,你需要开始添加 26 的地方是显而易见的。它是在密文编号变为22 24 1 3的地方。从 24 降到 1 就表明了这一点。
当密文字母表的线性性较低,即在一定程度上跳动时,可能更难以发现。例如,这种替换的相关性为 0.3265,具有中度非线性。

当通过这种方式调整时

相关性变为 0.9944,非常线性。我已经使用单个、双重和
下划线来显示在密文字符中添加了 26、52 和
,分别对应的是明文字符。在此要注意的一个重要特征是,在密文字符 2 处添加了 26,对应于明文字符 5,但没有添加到后续的密文字符 21 和 25。同样,对于密文字符 1,添加了 52,对应于明文字符 14,但没有添加到后续的密文字符 24。
当密文字母接近线性时,确定要添加的 26 的倍数相当容易。当密文字母行为不良时,这变得更加困难。但是...那没关系。当替代是非线性的时候,这就是您需要知道的全部。相关系数是 0.01 还是 0.35 都没有关系。在任一情况下,没有足够的相关性供 Emily 利用。不要浪费时间计算精确值。
处理没有密钥的情况。现在假设有一个密钥。如果替代是线性的,那么它将具有形式 d(p)+f(k),其中 p 是明文,k 是密钥,d 和 f 是整数值函数。加法可以在任何 3 个编号方案 N1、N2 或 N3 中进行。在这种情况下,密钥在测试线性方面没有任何作用。f(k)只是添加到密文的常量。添加常量对相关系数没有影响,因为当您从每个值列表中减去均值(居中操作)时,它只是被再次减去。很容易测试替换 S(k,p)是否采用形式 d(p)+f(k)。只需选择两个密钥 k[1]和 k[2],并取差异 S(k[1],0)-S(k[2],0),S(k[1],1)-S(k[2],1),S(k[1],2)-S(k[2],2),...如果 S-box 具有形式 d(p)+f(k),那么所有这些差异将相等。如果您对所有可能的密钥重复这样做,那么您可以确定 S(k,p)具有所需的形式,并且您可以在不考虑密钥的情况下测试线性。
12.3.3 256 进制线性
对于 26 进制线性的分析只是对 256 进制线性的热身,因为在 256 进制中可能会发生两种不同的线性形式。我们称它们为串行和压缩。在串行线性中,每组位代表一个整数。例如,3 位组 000、001、010、...,111 表示数字 0、1、2、...,7。可以将两种形式的线性结合起来,以制作混合形式的线性。这在第 12.3.6 节中讨论。
串行线性是我们在 26 进制中看到的。在 26 进制中,N1、N2 和 N3 编号之间可能存在任何组合和任何顺序的相关性,因此必须测试许多成对是否具有线性。在 256 进制中有更多的可能性。串行线性可能存在于明文字母和/或密钥与密文字母中的任何位组之间。这些位组的大小不必相同。从明文中取出的 4 位组,覆盖范围从 0 到 15,可能与覆盖范围从 0 到 7 的 3 位密文组高度相关,因此可能的配对数量更多。
事情变得更糟,那个 4 位组中的 4 位可能是明文字节中的任意位。按顺序的位 7、2、5、1 和位 1、2、3、4 一样有效。线性替换可能将这 4 位加到密钥字节的 4 个不同位上,取模 16。可能的组合数量变得巨大。总之,明文字符和密钥字符中任何顺序的任何位组合都可能与密文字符中任何顺序的任何位组合线性相关。这是一大堆需要测试的相关性。
在你伸手拿阿司匹林或者龙舌兰酒之前,这里有个好消息。你可能不需要测试它们中的任何一个。除非密码是专门设计成从一轮传递到下一轮保持这些值不变,否则这些相关性不会有所影响。它们会随着每一轮的进行而逐渐削弱,以至于从初始明文到区块密码的最后一轮都不会被检测出来。
添加后门
你可能已经注意到我说了“可能”。例外情况是当你怀疑一个密码可能有后门时,也就是说,它已经被故意设计成让知道秘密的人可以在不知道密钥的情况下阅读消息。例如,一个国家间谍机构可能会向其特工提供一个带有后门的密码,以便该机构可以监视他们的消息并检测叛徒。
此时,让我们换个角色。假设你是 Z,被委派设计这个密码的间谍大师。你需要构建一个看起来和表现得像一个强大的区块密码的密码,这样用户就不会起疑。例如,你希望你的密码具有五十五的属性,即仅改变密钥或明文中的一个比特就会导致大约一半的密文比特以随机的模式改变。如果你的区块密码中的替代不都是线性的,那就是一个强大的区块密码的确切迹象。你希望你的假密码模仿这种属性。
这里有一种方法可以在密码中隐藏后门。它基于串行线性性,所以让我们称之为 后门串行 方法来构建密码,并让使用这种方法构建的密码称为 后门串行 密码。Z 可以阅读使用后门串行密码发送的消息,而无需知道密钥,但是对于不知道后门工作原理的任何人来说,它们看起来像是强大的、安全的区块密码。该方法分为三个部分:伪装、隐藏 和 伪装。
伪装
后门串行密码将对十六进制数字进行线性替换。明文块和密钥的每个块都被视为一个 4 位十六进制数字的序列。加密操作是在消息块和密钥的十六进制数字上进行的模 16 加法。假设字节中的两个十六进制数字是 p[1] 和 p[2],用于对它们进行加密的密钥的十六进制数字是 k[1] 和 k[2]。线性替换将 p[1] 和 p[2] 替换为

系数 a、b、c、d、e、f、g、h、i 和 j 可以是从 0 到 15 的任意整数,而 ag-fb 必须是奇数。如果您的密码有多轮,这 10 个值可以每轮不同。
这种线性替换易于 Emily 发现。特别是,每个十六进制数位的低阶位纯粹是线性的,因此对线性的简单位对位测试将找到它。为了避免检测,我们可以伪装十六进制数位。首先,按某种乱序列出十六进制数位,就像这样:

要将两个伪装的十六进制数位相加,您将它们在乱序列表中的位置相加,以获得总和在乱序列表中的位置。例如,要计算 1+2,您发现数字 1 在位置 9,数字 2 在位置 F,因此您将 9+F 模 16 得到 8。总和在列表中的位置 8。位置 8 中的数字是 D,因此 1+2 = D。
同样地,要将两个伪装的十六进制数位相乘,您将它们在乱序列表中的位置相乘,以获得乘积在乱序列表中的位置。例如,要计算 2×3,您注意到数字 2 在位置 F,数字 3 在位置 2,因此您将 F×2 模 16 得到 E。该产品位于列表中的位置 E。位置 E 中的数字是 7,所以 2×3 = 7。
本质上,伪装是对十六进制数位进行的简单替换。如果替换是非线性的,则没有一个位将在明文和密文之间具有线性关系。这种伪装的线性性质对于 Emily 来说要难得多,但是要真正迷惑 Emily,您可以隐藏伪装的十六进制数位。
隐蔽性
如果十六进制数的位始终是每个字节的块和密钥的位 1-4 和位 5-8,那么 Emily 仍有可能发现线性性。为了使 Emily 的任务真正艰难,您可以隐藏每个字节中的位。而不是使用明文的位(1,2,3,4)和密钥的位(1,2,3,4),并将结果总和放入密文的位(1,2,3,4),您可以按顺序使用明文的位(2,7,4,1)的十六进制数位,以及密钥的位(4,8,3,5),并将结果总和放入密文字节的位(8,6,1,7)。您可以选择任意顺序的 4 位的任何组合,只要每个字节中的 2 个十六进制数位都使用了所有 8 位。
为了明确起见,我们并不是说 Sandra 从每个字节中提取这些位,解密伪装的线性置换,执行算术,然后以不同顺序重新打包结果位。那样太慢了,而且 Emily 会清楚地知道发生了什么。相反,Sandra 在构建替代表时进行了这项工作。为了加密,她只需使用密钥字节选择表中的一行,然后对明文字节执行替代。所有的伪装和隐蔽都内置在替代表中。
伪装
到目前为止,所描述的密码仅仅是一个非常复杂的多表密码。Emily 可以使用第 5.8.3 节的技术解密消息。为了使后门序列密码看起来像一个强大的区块密码,你需要一些伪装来隐藏其核心的多表密码。
一种方法是在每一轮后对块应用位转置。这将使密码看起来像是一个置换-置换网络(第 11.1 节)。为了保留隐藏的线性性,组成每个十六进制数字的 4 位必须最终位于一个字节中。它们不必在该字节中的相同位位置,也不必是连续的,但它们必须在一个字节中。换句话说,输入的每个字节都被分成两个十六进制数字,这些数字以某种转置顺序被馈送到下一轮的两个其他字节中。不幸的是,如果 Emily 能够获得后门序列密码的发布规范,她很可能会发现这种类型的伪装。
让我们看看另一种更难于 Emily 揭示的伪装方式。这种方法借鉴了数据加密标准(DES)的一个想法(第 11.2 节)。每个密码块被分为两半。在每一轮中,首先使用左半部分作为密钥来加密右半部分,然后使用右半部分作为密钥来加密左半部分。我们已经看到了如何将线性性质伪装并隐藏在替代表中,所以让我们利用这一点来制造一个强大的区块密码的幻觉。
每轮密码会包括四个步骤。(1) 左半部分中的每个字节都使用一个字节的密钥进行加密。(2) 右半部分的每个字节都使用左半部分的一个字节作为密钥进行加密。(3) 右半部分中的每个字节都使用一个字节的密钥进行加密。(4) 左半部分的每个字节都使用右半部分的一个字节作为密钥进行加密。
为了使其看起来非常强大,每个块的每个字节应在每一轮中使用不同的密钥字节进行加密,并且每个块的一半的每个字节应在每一轮中使用来自另一半的不同字节进行加密。您可以通过在每一轮中对块中的字节和密钥中的字节进行洗牌来使其更加复杂。您可以使密钥比块更大,以展示更强大的印象。然而,密码仍然是线性的,因为在每一轮的每一步中都保持了线性性。
存储
让我们来看看后门串行密码的机制。在密钥的每个字节中,明文和密文中都有两个十六进制数字。每个数字可以占据字节的任何 4 位,以任何顺序。让我们称这组有序的 4 位为十六进制数字的位配置,并且字节中的 2 个十六进制数字的组合为字节配置。密钥通常不会更改配置,但是明文和密文的字节配置可以在加密的任何阶段更改。
对于每个替换,有 6 种位配置,2 种用于密钥,2 种用于明文,2 种用于密文。对于每个十六进制数字,16 个十六进制值的排列(乱序)也可以不同,因此对于每个替换,每个位配置和排列也有 6 种排列,2 种用于密钥,2 种用于明文,2 种用于密文。这种 6 种配置和 6 种排列的组合确定了替换表。对于每个不同的位配置和排列组合,都需要一个单独的替换表。
每个表格使用 65,536 字节,因此存储可能会成为问题。如果这是一个问题,我建议最多使用 2 字节配置,并且对于每个位配置最多使用 2 种不同的排列,也许可以在每一轮中交替使用。为了进一步减少所需的存储量,您可以考虑每次使用任何给定的位配置时都使用相同的排列。
12.3.5 精简线性
在大多数情况下,您将不会在密码中构建后门,也不会关注串行线性性。让我们把注意力转向第二种线性性,即压缩线性性。在这种线性性形式中,一组位通过将它们进行异或运算压缩为单个位。因此,000、011、101 或 110 将被压缩为 0,而 001、010、100 或 111 将被压缩为 1。明文和/或密钥的任何位组合都可能与每个 S-box 的密文的位组合相关。如果块密码使用异或将 S-box 的输出与块的其余部分结合在一起,则此线性性可以从一轮传递到另一轮,并且原始第一轮明文与最终最后一轮密文之间将存在线性关系。密码的设计者必须避免以这种方式使用异或,或者必须进行彻底的检查,以确保 S-box 不包含任何这样的线性性。
假设 S-box 接受一个 8 位明文并产生一个 8 位密文。从明文中选择一组位有 255 种不同的方式,同样地,从密文中选择一组位也有 255 种方式。(位的顺序并不重要,因为 a⊕b = b⊕a。)这使得有 255² = 65,025 种不同的组配对需要测试。每个测试都是 256 个明文值与 256 个密文值之间的相关性。即使在个人电脑上,这也是很容易实现的。
如果 S-box 接受一个 8 位明文加上一个 8 位密钥并产生一个 8 位密文,那么从明文加密钥中选择一组位有 65,535 种不同的方式,同样地从密文中选择一组位也有 255 种方式。这使得有 65,535×255 = 16,711,425 种不同的配对需要测试。这在个人电脑上需要花费一段时间,因为每个相关性都涉及所有 65,536 个明文和密钥组合。这是需要居中、缩放和求和的超过 10¹²个值。
这是谈论如何高效进行这些测试的理想时间。有一些技巧可以大大加快这个过程。 (1) 为了选择一组位,使用一个从每个字节中选择这些位的掩码。例如,如果你想要第 2、4 和 7 位,使用掩码 01010010,它在位位置 2、4 和 7 上有 1。将这个掩码与每个明文字节进行 AND 运算,以选择所需的位。 (2) 要尝试所有可能的位组合,不要逐个构造掩码,只需将掩码步进到所有值 1 到 255。 (3) 要压缩位,不要每次都使用移位和 XOR。只需执行一次并构建压缩值的表。然后,通过表查找可以将位组合压缩。如果有一组密钥位和明文位,这些位可以通过异或在一起,然后使用表来压缩,这样您只需要一次表查找而不是两次。
12.3.6 混合线性性
为了完整起见,我要提到可以有一种混合形式的线性性,将串行和压缩线性结合起来是可能的。假设你将每个 8 位字节分成四个 2 位组。这些 2 位组可以通过加法模 4 串行线性。你可以通过将它们模 4 相加来压缩两个或多个这些组。同样的操作也可以用于模 8 的 3 位组或模 16 的 4 位组。
让我们坚持使用 2 位组。每个组可以由字节中的任何 2 位组成。例如,一个字节可以分解为 4 个组,位 (6,1),(4,8),(2,5) 和 (7,3)。你可以通过将几个 2 位组相加模 4 或取任意的线性组合模 4 来压缩几个 2 位组为一个 2 位组。例如,如果 2 位组是 A、B、C 和 D,你可以将它们组合成一个新的 2 位组 pA+qB+rC+sD+t (mod 4),其中 p、q、r、s 和 t 是固定整数,范围为 0 到 3,其中至少有一个是奇数。
这些类型的压缩组可能与密文中类似的混合组或正常位组或密文中的压缩位组相关联。如果你想要绝对彻底,那么所有可能的线性组、压缩组和混合组的配对都需要进行相关性测试。
12.3.7 构建 S 盒
有三种构建具有良好非线性特性的 S 盒的方法:时钟方法,SkipMix 和 Meld8 方法。
时钟方法
在一张纸上,将字母按照顺时针均匀间隔地排列在一个大圆圈周围,就像时钟表盘上的数字一样。选择一个起始字母和一个第二个字母,并从第一个字母到第二个字母之间画一条直线。然后选择一个第三个字母,并从第二个字母到第三个字母之间画一条直线,依此类推。将每条线的 跨度 定义为从每个字母顺时针移动到下一个字母的字母位置数。例如,使用 26 个字母的字母表,从 C 到 D 的跨度是 1,从 D 到 C 的跨度是 25。为了使替换尽可能非线性,使每个跨度长度都不同。
下面是具体操作。为字母表中的每个字母制作一个列表,其中包含可能跟随它的所有字母。当你开始时,每个字母的列表都会包含其他每个字母,所以你会得到 26 个含有 25 个字母的列表。每次选择一个字母并将其添加到混合字母表中时,从所有列表中删除该字母。如果从前一个字母到该字母的跨度是 s,则还要从所有列表中删除任何跨度为 s 的其他字母。例如,假设你已经将 P 和 R 添加到字母表中。从 P 到 R 的跨度是 2 个位置,PQR。因此,在 A 列表中,你会删除 C,在 B 列表中,你会删除 D,在 C 列表中,你会删除 E,依此类推。
最终,一些列表会变为空。如果只有一个字母的列表为空,那么该字母将成为混合字母表中的最后一个字母。如果有两个空列表,那么你已经陷入了僵局。重新开始,或者回溯并再试一次。每次选择要添加到字母表中的下一个字母时,选择一个列表较短的字母,但不要选择一个空列表的字母,除非那是剩下的最后一个字母。
历史背景
这种启发式方法称为 Warnsdorff 规则,以 H. C. von Warnsdorff 的名字命名,他在 1823 年用于在棋盘上构建骑士之旅。1965 年左右,加州大学圣克鲁斯分校的 Ira Pohl 提出了一个向前看 2 步的改进版本。
这是一个通过时钟方法构建的字母表示例:

有 5 种不同的编号需要测试,以检查该字母表的线性性:N1 编号,N2 编号的第一和第二位数字,以及 N3 编号的第一和第二位数字。每个都必须与标准拉丁字母表的相同 5 个编号相关联,总共有 25 个相关性。你希望所有相关性都在-.5 和+.5 之间。最好的情况是它们都在-.333 和+.333 之间。
这些测试的结果如下,25 个相关系数。

正如你所看到的,所有相关性都在-.226 和+.288 之间,其中有 6 个落在-.1 和+.1 之间,因此时钟方法是构建非线性替换的绝佳方法。
并不保证每次都能获得如此好的结果。你仍然需要测试线性性。
SkipMix
在本节(12.3)的前面,我提到可以使用 SkipMix 算法(第 5.2 节)与伪随机数生成器构建字母表。一般来说,随机选择字母表不会导致良好的非线性特性,所以让我更详细地描述如何最好地使用 SkipMix。这次我将以 256 个字符的字母表为例进行说明。
一如既往,你首先列出 256 个可用字符。在 1 到 256 的范围内生成一个随机数以选择第一个字符。假设那是字母表中的第 54 位。取出该字符,然后从列表中删除它。现在剩下 255 个字符。在 1 到 255 的范围内生成一个随机数。假设该数字是 231。下一个位置将是 54+231 = 285。由于这大于 255,你减去 255 得到 30。从位置 30 取下一个字符,并从列表中删除它。现在你已经取了 2 个字符,剩下 254 个字符,所以你在 1 到 254 的范围内生成一个随机数。依此类推。
生成的字母表具有良好的非线性特性,因为您每次生成不同范围的随机数。这与时钟方法中使所有跨度不同的情况类似。这是通过 SkipMix 的这个版本生成的一个 26 个字母的字母表示例。

这可以像测试时钟字母一样进行测试。结果如下:

这些结果很好。所有相关性都介于 -.127 和 +.344 之间,其中 5 个介于 -.1 和 +.1 之间,但是它们不如时钟方法的结果好。
Meld8 方法
这种方法基本上是一种特殊用途的伪随机数生成器。我将假设您正在使用的计算机语言能够操作 64 位整数。根据大整数的表示方式,您可以处理 2⁶² 或 2⁶³ 的整数。为了谨慎起见,我将假设 2⁶²。第一步是选择两个数字,一个乘数 m,位于 24 到 26 位之间,和一个模数 N,位于 35 到 37 位之间。模数必须是素数。如果 m 是 N 的原根,则最好,但由于我尚未解释那是什么,所以只需使 m 和 N 都是素数。
通过将它们相乘来测试您选择的 m 和 N。如果结果大于 2⁶²,约为 4.611×10¹⁸,则使 m 或 N 中的一个较小。
要生成随机数,从 2 到 N-1 之间选择任何整数 s 作为种子。将种子乘以 m,并对 N 取模以获得第一个伪随机数。将第一个随机数乘以 m 并对 N 取模以获得第二个随机数,依此类推。这给了你一个范围为 1 到 N-1 的随机数序列。您将使用这些随机数来生成字母。
假设 N 有 36 位。从高位开始,将 N 的位编号从 1 到 36。取每个随机数的前 8 位,位于 1 到 8 位。从高位开始删除它们,并将它们与下一个 8 位,即 9 到 16 位,进行异或。这就是 Meld8 操作。它的目的是使字符序列非线性。以下是一个示例:

下一步是使用 28 位随机数生成一个字符。这取决于您是要构建一个 26 个字符还是一个 256 个字符的字母表。对于 26 个字符的字母表,将此数字乘以 26 并除以 2²⁸(或向右移动 28 位)以获得下一个字符。对于 256 个字符的字母表,只需除以 2²⁰,或向右移动 20 位以获得下一个字符。
从空字母表开始,每次添加一个字符。如果这是一个新字符,则将其追加到字母表中。如果这是一个重复字符,则将其丢弃。由于您没有连续的随机数,因此这也适用于使字母表非线性。以下是使用模数 N = 90392754973、乘数 m = 23165801 和种子 s = 217934 生成的此类字母表的示例:

结果相关系数为

相关性范围从-.170 到+.267,其中有 11 个落在-.1 和+.1 之间。这是三个示例中最好的,然而,基于每种技术的单个示例得出 Meld8 是最佳方法的结论是愚蠢的。始终进行测试。
12.3.8 带有密钥的 S 盒
在第 12.3.7 节中,我们处理了没有密钥的 S 盒。它们执行简单的替换。当使用密钥时,S 盒执行一般的多表替换(第 5.8.3 节)。S 盒可以被视为一个表,其中每一行都是一个混合字母表。可以通过使用时钟方法、SkipMix 或 Meld8 构建每个混合字母表来生成 S 盒,或者通过任何组合方法。
如果使用时钟方法或 SkipMix,请每次使用不同的随机种子。如果使用 Meld8,则可以每次使用相同的模数,但使用不同的种子和不同的乘数。一如既往,测试,测试,测试。你的目标是避免密钥和明文与密文的组合之间存在任何线性关系。如果结果不佳,即许多相关系数在-.35 到+.35 范围之外,也许只需替换一个行或交换两个行的表就能解决问题。
12.4 扩散
香农的第二个特性是扩散。这个想法是密文的每一位或每一字节都应该依赖于明文和密钥的每一位或每一字节。
为了说明这一点,让我们回到第 9.6 节中描述的 Delastelle 的 bifid 密码。为了提醒你,bifid 是基于 Polybius 方阵的分组密码。如果块大小为 S,则消息的每个字母将被两个基于 5 的数字替换,并且这些数字被垂直写入一个 2×S 网格并水平读出。然后这些数字对再使用相同或不同的 Polybius 方阵转换回字母。
让块大小为 7,并将明文块中的字母称为 A、B、C、D、E、F、G。让表示这些字母的数字为 aa,bb,cc,dd,ee,ff,gg。我没有写下标,因为这里不重要哪个数字先出现,哪个数字后出现。那么块将是

当字母水平读出时,你会得到 ab,cd,ef,ga,bc,de,fg。请注意,密文的每个字母都取决于明文的两个字母。第一个密文字母取决于 A 和 B,第二个字母取决于 C 和 D,依此类推。
在这一点上,我需要引入一种特殊的符号来显示每个密文字母依赖于哪些明文字母。如果一个密文字母依赖于明文字母 P、Q 和 R,则它被指定为 pqr。使用这种符号,如果你再次加密字母 A、B、C、D、E、F、G,块会像这样:

将这些字母水平读出,你会得到 abcd,efga,bcde,fgab,cdef,gabc,defg。由于数字的顺序无关紧要,这也可以表示为 abcd,aefg,bcde,abfg,cdef,abcg,defg。经过两次加密后,每个密文字母都依赖于四个明文字母。
如果您使用双密码加密这个区块第三次,那么每个密文字母将取决于所有 7 个明文字符。对于区块大小为 7 的双密码,需要三轮加密才能实现完全扩散。如果区块大小为 9、11、13 或 15,那么需要四轮加密。(请回忆一下,双密码中的区块大小应始终为奇数。)
一般来说,要测试扩散,您首先使每个明文字符或位仅依赖于自身。如果密码操作的是整个字节或字符,则根据字节跟踪扩散。如果它操作十六进制数字、其他基数的数字或者单个位,则根据这些单元跟踪扩散。对于双密码,单元是 Polybius 方格坐标,或者是基数为 5 的数字。
为了追踪扩散,您需要一种方式来表示明文单元和密钥单元在区块密码的轮次中随着流动的方式。当只有少数明文单元时,就像双密码示例一样,仅列出它们就能很好地工作。当明文、密钥和密文单元的数量较大时,可能需要更紧凑的表示。一个好的策略是为每个密文单元创建一个二进制向量。让我们称之为依赖向量。依赖向量的每个元素将对应于一个输入,即明文或密钥单元。如果密文单元取决于该输入单元,则该依赖元素的值为 1,否则为 0。
当两个或多个输入单元组合成一个输出单元时,它们的依赖向量将被 OR 运算在一起,形成输出单元的依赖向量。为了说明这是如何工作的,让我们再次使用这种符号通过双密码示例。最初,每个字符仅依赖于自身。这由向量表示

在第一次应用双密码后,每个结果字母都依赖于两个明文字母。第一轮输出字节依赖于第一轮输入字节的前两个字节,因此你将它们的依赖向量进行 OR 运算得到 1100000。第二个输出字母依赖于第三和第四个明文字母,因此你将它们的依赖向量进行 OR 运算得到 0011000,依此类推。第一轮输出由向量表示

在第二轮的双重转置之后,第一个输出字母取决于第一轮的第一个和第二个输出,所以你将它们的依赖向量进行 OR 运算 1100000∨0011000 得到 1111000。第二个输出字母取决于第一轮的第三个和第四个输出,所以你将它们的依赖向量进行 OR 运算 0000110∨1000001 得到 1000111,依此类推。经过两轮的双重转置后,每个字母都取决于四个明文字母,表示为

在第三轮的双重转置之后,每个输出字母都取决于第一轮明文的所有 7 个字母,例如,1111000∨1000111 就是 1111111。第三轮的输出表示为

每当遇到一个 S 盒时,输出单元的依赖向量是通过对贡献到该输出的每个输入的向量进行 OR 运算形成的。让我们看看在块密码中可能发生的其他情况。
如果两个单元进行异或运算,输出单元的依赖向量是通过对每个输入的向量进行 OR 运算形成的。当使用任何组合函数(如sxor或madd)将多个单元组合在一起时,也是如此。
当块的单元使用密钥进行转置时,每个输出单元都依赖于该密钥的所有单元,因此密钥的向量与每个输出单元的向量进行 OR 运算。
假设一个 S 盒是通过使用密钥混合其字母表而创建的。如果 S 盒是固定的或静态的,比如通过嵌入硬件来实现,那么混合密钥将不再参与其中。如果 S 盒是可变的,也许每次加密都使用不同的密钥进行混合,那么该 S 盒的输出单元将依赖于该密钥的所有单元。密钥的向量与每个输出单元的向量进行 OR 运算。
可以将扩散表示为一个单一数字。从所有输出单元的依赖向量构建一个矩阵。矩阵中的每一行代表块密码最终轮的一个输出单元。矩阵中的每一列代表一个输入单元,可以是密钥或明文。扩散的度量,或扩散指数,是矩阵中这些元素中为 1 的部分。如果矩阵中的元素都是 1,那么就有完全扩散,扩散指数为 1。如果 S 盒是非线性的且密钥很长,这表明块密码很强大。
扩散并非全部。有些有效的密码设计中,扩散指数可能小于 1,但密码仍然很强大。一个例子是每轮都有单独密钥的块密码。早期轮次的密钥可能实现完全扩散,但晚期轮次,尤其是最后一轮的密钥可能不会。然而,如果完全扩散的密钥包含您所需的位数,则该密码很可能是安全的,而部分扩散的密钥只是一种保险。
这里有一个示例,可能有助于说明即使扩散不完全,密码也可以很强大。考虑一个具有 12 轮的密码,每轮具有独立的 24 位密钥。在这个密码中,需要 6 轮才能实现完全扩散,因此经过 6 轮后,明文和第一轮密钥完全扩散。经过 7 轮后,明文和第一轮和第二轮密钥完全扩散。依此类推。经过 12 轮后,明文和前 7 轮的密钥完全扩散。使用 24 位轮密钥,这是 168 位完全扩散的密钥。如果您的目标强度是 128 位密钥位,那么您已经超过了目标。第 8 至 12 轮的部分扩散密钥是额外的奖励。
12.5 饱和
混淆和扩散是安全框架的两大支柱。为了确保分组密码建立在坚实的基础上,我建议添加第三支柱,我称之为饱和。扩散仅表示给定输出单元是否依赖于给定输入单元。饱和度衡量给定输出单元依赖于给定输入单元的程度。我展示了如何计算类似于前一节扩散指数的饱和指数。饱和实质上是扩散的更精细版本。通过扩散,依赖性只能具有 0 或 1 的值,但通过饱和,依赖性可以具有任何非负值。
这里是饱和的简要解释。假设分组密码 X 由几轮替换组成。在每一轮中,消息的每个字节都与密钥的一个字节进行异或运算,然后对结果进行简单的替换。假设每一轮中使用不同的密钥字节,以便每个密钥字节每次用于每个分组字节。密码 X 的饱和度会很低,因为每个密文字节仅依赖于每个密钥字节一次。要获得更高的饱和度,每个输出字节需要多次依赖于每个输入字节。
另一个示例可能有助于更清晰地说明。想象一个在 48 位块上运行的密码,视为六个 8 位字节。这个密码的每一轮包括两个步骤:(1)块向左循环移动一个位位置,因此最左边的位移动到最右边的位置,然后(2)对每个 8 字节执行简单的替换 S。第一轮后,第一个输出字节C1依赖于第一个明文字节的最后 7 位和第二个明文字节的第一个位,如下所示:

密文字符C1依赖于明文字节P1的 7 位和明文字节P2的 1 位。可以说C1对P1依赖 7/8,对P2依赖 1/8。
让我们看看第二轮。将第二轮输出称为D1 ... D6。

密文字符 D1 对 C1 依赖程度为 7/8,对 C2 依赖程度为 1/8。在这里,C1 对 P1 依赖程度为 7/8,对 P2 依赖程度为 1/8,而 C2 对 P2 依赖程度为 7/8,对 P3 依赖程度为 1/8。P1 对 D1 的唯一贡献来自 C1。因为 D1 对 C1 的依赖程度为 7/8,C1 对 P1 的依赖程度为 7/8,因此可以合理地说 D1 对 P1 的依赖程度为 49/64。出于同样的原因,D1 对 P3 的依赖程度为 1/64。让我们称这些数字为 饱和系数,将这个计算称为 S1 计算,当存在单一依赖关系时。
图表可能会使配置更清晰。

P2 呢?D1 通过 C1 和 C2 从 P2 获取贡献。或许认为 D1 对 C1 的依赖程度为 7/8,对 P2 的依赖程度为 1/8,对 C2 的依赖程度为 1/8,而 C2 对 P2 的依赖程度为 7/8,因此 D1 对 P2 的依赖程度为 (7/8)(1/8)+(1/8)(7/8) = 14/64。这是一个合理的计算,它导致了扩散的更复杂版本。然而,使用这个计算,任何给定单位的总贡献总是 1。总数永远不会增长。如果这个计算重复多次,所有这些扩散数字将收敛到 1/48。这并不是饱和概念试图捕捉的内容。只要一个单位从多个不同的来源接收贡献,饱和度就应该增加。
当一个单位获得多个贡献时,使用不同的计算方法来确定饱和系数。假设两个来源的饱和系数分别为 a 和 b,其中 a ≥ b。那么合并后的饱和系数为 a+b/2。如果有三个贡献的饱和系数分别为 a、b 和 c,其中 a ≥ b ≥ c,那么合并后的饱和系数为 a+b/2+c/4。在每种情况下,组件饱和系数按降序排列,a ≥ b ≥ c ≥ d ≥ e... 。总之,当多个饱和系数被合并时,结果如下:

让我们称这个计算为 S2 计算,当存在多个依赖关系时使用 S2 计算。对于单一来源使用 S1 计算。
S2 计算可能看起来是临时的,甚至是古怪的,但它具有饱和计算所需的恰到好处的属性。首先,当一个单位依赖于多个前导时,它总是会增加。这是因为 a+b/2 总是大于 a。其次,它的增长速度不会太快。最多,饱和系数可以从一个回合翻倍到下一个回合。这是因为 a+a/2+a/4+...+a/2^n < 2a 对于任何 n 都成立。例如,1+1/2+1/4+1/8 = 15/8 = 1.875。
在当前情况下,D1依赖于P2,贡献系数分别为 7/8 和 1/8,因此组合系数为 7/8+(1/8)/2 = 15/16。 输出单元的饱和系数可以组成一个向量,就像扩散数一样。 因此,D1的饱和向量为(49/64, 15/16, 1/64, 0, 0, 0)。 然后,这些向量可以组成饱和矩阵。 饱和指数是饱和矩阵中最小的系数。
让我们看一个更现实的密码,这是文献中提出的一种密码,可能已经在实践中使用过。 我将其称为SFlip,简称Substitute and Flip。 它是第 11.7.5 节中多项式三次翻转的近亲。 如果您不记得矩阵翻转是什么意思,请参阅第 11.7 节。 SFlip 密码适用于一个 8 字节的块,并由几个轮次加上一个完成步骤组成。 每一轮都有两个步骤。(1)将简单的替换应用于八个 8 位字节。(2)8×8 比特位矩阵翻转。 完成步骤是再次为每个 8 位字节进行替换。
8×8 比特位矩阵需要一个 64×64 的依赖矩阵。 这个矩阵太大了,无法清晰显示,因此我将以微型形式显示密码。 让我们使用一个 3×3 的比特位矩阵,其具有 9×9 的依赖矩阵。 这个密码将被分析两次,一次使用扩散,一次使用饱和。 先进行扩散。 让我们从在文本块和依赖矩阵中标记比特位开始,就像这样:

在第一轮之前,每个比特位只依赖于自己,因此依赖矩阵看起来像(1)。 在第一轮替换之后,每个比特位依赖于其字符中的所有 3 位,因此依赖矩阵看起来像(2)。 在第一轮翻转之后,依赖矩阵看起来像(3)。 在第二轮替换之后,依赖矩阵看起来像(4)。

换句话说,此时密文的每一位都取决于明文的每一位。 这在第二轮翻转之后以及最后的替换之后仍然成立。 因此,如果我们仅依赖依赖计算,我们会得出结论,此密码在两轮后将是安全的。 这是不正确的。 阿迪·沙米尔已经证明两轮是不够的。
现在让我们使用饱和指数来分析 SFlip 密码。 在第一轮替换之后,密文的每个比特位都依赖于其对应的 3 个明文比特位中的 1/3。 饱和矩阵将看起来像(5)。 在第一轮翻转之后,饱和矩阵将看起来像(6)。

第二轮替换使得输出的每一位取决于第一轮明文的所有 9 位。饱和系数为 1/3+(1/3)/2+(1/3)/4 = 1/3+1/6+1/12 = 7/12,约为 0.583。饱和矩阵中的每个元素都将具有这个值,因此饱和指数将为 7/12。饱和指数的目标值为 1,尽管如果您想要更大的确定性,也可以将其设置得更高。以下是几轮后饱和指数的情况。

所以对于 3×3 密码,3 轮就足够了,但对于 8×8 密码,需要 5 轮。
现在让我们转向其他一些情况,其中输出单元取决于一个或多个输入单元。
当一个 S 盒同时具有明文和密钥输入时,例如 p 个明文单元和 k 个密钥单元,每个输出单元的依赖性将为 1/(p+k)。例如,如果输入为 6 个密钥位和 4 个明文位,则每个输出位的依赖性将为 1/10。如果 S 盒的输入本身依赖于先前的输入,则应根据需要使用 S1 或 S2 计算来计算饱和指数。
同样,如果使用异或或其他组合函数将两个或更多单元组合在一起,则依赖性为 n 个总输入的 1/n。计算饱和指数的方法与具有相同输入的 S 盒相同。
当使用 k 位密钥进行置换时,置换的每个输出单元对每个密钥位的依赖性为 1/k,并对明文输入的依赖性为 1。假设明文字符 p 通过置换从位置 a 移动到位置 b。置换后,p 的饱和向量将与置换前的饱和向量相同,除了那些对应于置换密钥位的列。在这些列中,饱和系数将由 S1 或 S2 计算确定。
这里有一个例子。假设 t 是置换密钥的位之一。如果 p 在置换之前对 t 没有依赖性,即其饱和向量的第 t 列为 0,则在置换之后,第 t 列的值将为 1/k。另一方面,如果 p 已经依赖于密钥位 t,则饱和系数将由 S2 计算确定。如果第 t 列中的系数为 x,则在置换之后,第 t 列中的饱和系数将为 x+1/2k(如果 x ≥ 1/k),或者为 1/k+x/2(如果 x < 1/k)。
当使用 k 位密钥来混合字母表或替代步骤的表时,混合的字母表或表对该密钥的每一位具有 1/k 的依赖性。每次使用该字母表替换一个字符时,输出字符对密钥的每一位都会增加 1/k 的依赖性。这与输入字符的依赖性(和替换密钥,如果有的话)结合使用 S1 或 S2 计算来获得输出字符的饱和系数。
摘要
如果一个块密码遵循所有这些规则,实际上是无法破解的:
-
它具有足够大的块大小。当前标准为 16 个字符或 128 位。
-
它具有足够大的密钥。当前标准为 128 到 256 位。密钥必须至少与块大小相同,最好更大。
-
要么使用强非线性的固定 S 盒,要么使用使用大密钥混合良好的可变替代表。
-
饱和指数至少为 1。
一如既往,要保守。建立一个安全的误差边界。使密钥更长,使用比所需更多的轮数,因为计算机变得更快,新攻击不断被发现。特别是,您可以将饱和指数的目标设定得比 1 更高,也许是 2、3 甚至 5。
第十三章:流密码
本章涵盖
-
伪随机数生成器
-
用于将随机数与消息组合的函数
-
生成真随机数
-
散列函数
流密码与分组密码相反。流密码中的字符在遇到时被加密,通常一次一个。基本概念是将一系列消息字符与一系列密钥字符结合起来,以产生一系列密文字符。这种范式非常适合连续操作,其中消息在一端持续加密和传输,另一端持续接收和解密,没有暂停,或者只有短暂的暂停来更换密钥。
我们已经看到了一些流密码。第 5.9 节中的自动密钥和流动密钥密码,第 5.10 节中的转子机器,第 10.4 节中的哈夫曼替换,以及第 10.7 节中基于文本压缩的密码都是流密码的示例。
13.1 组合函数
最常见的流密码类型使用一个密钥单元加密一个明文单元。这些单元通常是字母或字节,但十六进制数字甚至比特也可以使用。密钥单元与明文单元结合使用基本上与第 11.8 节中的涟漪密码使用的组合函数相同,但使用密钥单元代替前一个单元。以下是类似的方法,其中 x[n] 是消息的第 n 个单元,k[n] 是密钥的第 n 个单元,A 和 B 是简单的替换,P 是通用多表替换。替换 A、B 和 P 应该使用密钥混合,而不是固定或内置的。
| xor | 异或 | x[n] 被 k[n]⊕x[n] 替换。 |
|---|---|---|
| sxor | 替换并异或 | 有三种变体:x[n] 可以被 A(k[n])⊕x[n] 替换,或者 k[n]⊕B(x[n]) 或 A(k[n])⊕B(x[n])。也就是说,你可以替换 k[n] 或 x[n] 或两者都替换。(在已知明文的情况下,使用 A(k[n]) 而不是 k[n] 可以防止 Emily 恢复伪随机序列。) |
| xors | 异或并替换 | x[n] 被 A(k[n]⊕x[n]) 替换。 |
| add | 相加 | x[n] 被 k[n]+x[n] 替换。如常,加法是对字母表大小取模的。 |
| madd | 乘以并相加 | 也称为线性替换。x[n] 被 pk[n]+x[n] 替换,或者 k[n]+qx[n],或者 pk[n]+qx[n],其中 p 可以是任意整数,q 可以是任意奇整数。(如果你使用的字母表大小与 256 不同,q 必须与该大小互质。) |
| sadd | 替换并相加 | x[n] 被 A(k[n])+x[n] 替换,或者 k[n]+B(x[n]) 或 A(k[n])+B(x[n])。 |
| adds | 相加并替换 | x[n] 被 A(k[n]+x[n]) 替换。 |
| poly | 通用多表替换 | x[n] 被 P(k[n], x[n]) 替换。 |
由于xor或sxor可能会泄露关于其操作数的信息,我建议改用xors,这样在执行异或操作后进行简单替换以掩盖波形,即 A(k[n]⊕x[n])。
流密码也可以使用一个或多个先前的字符来加密当前字符。有许多组合方式。一个例子是 P(k[n]⊕x[n-i], x[n]),其中 i 是一个小整数。这种密码需要一个初始化向量来加密前 i 个字符。流密码也可以通过在几个组合函数之间切换来加强,例如周期性地在sadd的 3 种形式之间或madd之间进行切换,或者周期性地变化madd中的乘数 p 和 q。
13.2 随机数
前面表格中列出的流密码中使用的长密钥可以来自几个来源:
-
它们可能是一个数字列表,根据需要重复多次。这是从 16 世纪到 19 世纪的标准方法。
-
它们可能是通过数学过程生成的。这些数字称为pseudorandom,因为它们最终会重复,而不是真正的随机数,后者永远不会重复。生成这些数字的过程称为pseudorandom number generator(PRNG)。
-
它们可能是真正的随机数,可能是由一些物理过程生成的,例如来自爆炸星的伽马射线。这些过程通常对于密码学的需要来说太慢了,因此这些随机数通常会随着时间的推移而收集,并存储在计算机中以供以后使用。也就是说,它们可以连续收集,并且只在您需要发送消息时使用。
关于密码学的书籍和文章经常声称,你需要真正的随机数才能获得安全的密码。他们指出,已经数学证明了使用真正随机密钥的一次性密码本是不可破解的。这当然是正确的,前提是对于每个明文单元 p 和每个密文单元 c,都存在一个密钥单元 k 将 p 转换为 c,即 S(k, p) = c。真正的随机密钥足以使一次性密码本无法破解。然而,正如每个学过逻辑的人都知道的,条件可以是充分的,但不是必要的,反之亦然。
例如,要使一个整数成为质数,必须大于 1。这是必要的,但不充分,因为 4 是一个大于 1 的整数,但不是质数。要使一个整数成为合数,它必须是一个大于 1 的平方数。这是充分的,但不必要,因为 6 是合数,但不是平方数。
要求一次性密码本的密钥必须是真随机是过度的。为了使一次性密码本无法破解,密钥必须是不可预测的,也称为密码学安全的。使用真随机密钥,无论 Emily 知道多少个密钥单位,她都无法确定其他单位。使用不可预测的密钥,Emily 只需无法计算地确定其他单位。具体而言,Emily 需要做的工作量来确定另一个密钥单位必须大于 2^k,其中 k 是你选择的密钥大小(以比特为单位)。当密钥流仅为伪随机时,您无法再证明密码本是不可破解的,但这在实践中没有实际意义。
本章后面我将描述几种使伪随机数生成器具有密码学安全性的方案,并指出一个看起来安全但实际上是不安全的方案,即第 13.13 节中描述的 CG5。
之前列出的所有流密码都可以利用伪随机数生成器产生密钥流,因此让我们来看一些 PRNG 的变体,首先从上世纪 50 年代的一些经典方法开始。这些生成器使用一个小的初始值,称为种子或初始状态,以及一些简单的数学函数,从当前状态生成下一个状态,称为状态向量。常见的生成函数包括加法、乘法和异或。由于它们的速度快且易于实现,这些生成器今天仍然被广泛使用。
每个生成器都会产生一个整数序列,在依赖于种子的周期之后最终会重复。可能会有一个永远不会重复种子的重复数字序列,例如 1,2,3,4,5,4,5,4,5,4,5, ... ,但本书中的生成器都没有这种行为。周期受状态向量大小的限制。例如,一个状态向量为三个 31 位整数的生成器的周期不能超过 2⁹³。
13.3 乘法同余生成器
一个乘法同余伪随机数生成器使用两个参数,一个是乘数 m,一个是模数 p。从种子 s 开始,伪随机数序列 x[n] 通过递推生成。

换句话说,要获取下一个伪随机数,你需要将上一个数乘以 m,然后取模 p 的余数。种子可以是任何整数 1,2,3, ... ,p-1。模数 p 几乎总是选择为质数,因为质数产生最长的周期。选择 p 通常取决于您使用的计算机中寄存器的大小。对于 32 位寄存器,常见选择是素数 2³¹-1,即 2,147,483,647,这是由伯克利数论学家 Derrick H. Lehmer(不要与他的父亲伯克利数论学家 Derrick N. Lehmer 混淆)在 1949 年发布的这一类中的第一个 PRNG。
乘数 m 必须谨慎选择。乘法同余生成器的周期可以是任何均匀地整除 p-1 的整数。由于 p 是一个素数,且可能远大于 2,p-1 将是偶数,因此非常糟糕的选择 m,比如 p-1,可能会得到一个周期为 2 的结果。具有最长周期的乘数,即 p-1,称为 p 的 原根。这意味着 m、m²、m³、...、m^(p-1) 在模 p 下有不同的余数。对于乘法同余生成器,最好使 m 成为原根,以获得最长可能的周期。
幸运的是,这很容易做到。在范围为 2 到 p-2 的数中,平均约有不到 3/8 的数字是 p 的原根。这个确切的比率被称为 阿丁常数,以奥地利数学家埃米尔·阿丁(Emil Artin)的名字命名,他于 1937 年逃离纳粹德国,并在普林斯顿完成了他的职业生涯。它的值约为 .373956。如果您可以因式分解 p-1,那么很容易测试给定的乘数 m 是否是 p 的原根。我们知道 m 的周期必须整除 p-1,因此首先将 p-1 进行因式分解。假设 p-1 的不同素因子是 a、b、c 和 d。然后,您只需要测试 m^((p-1)/a) (mod p),m^((p-1)/b) (mod p),m^((p-1)/c) (mod p) 和 m^((p-1)/d) (mod p)。如果这些值中没有一个是 1,则 m 是一个原根。例如,如果 p = 13,则 p-1 的不同素因子为 2 和 3,因此您只需要测试指数 12/2 和 12/3,即 m⁶ 和 m⁴。例如,5 不是 13 的原根,因为 5⁴ = 625 ≡ 1 mod 13。
有有效的方法来通过连续的平方来计算 m^x。例如,要计算 m²¹,您可以连续计算 m²、m⁴、m⁸、m¹⁶、m²⁰、m²¹,只需进行 6 次乘法运算。您可以通过使用这些乘积来计算下一个幂值来获得进一步的效率。例如,如果要测试的下一个值是 m³⁷,您可以只使用 3 次乘法运算计算出 m³²、m³⁶、m³⁷。在每次乘法运算后计算模 p 的余数要比计算庞大的数 m²¹ 并在最后取余更有效。有更复杂的方案可以使用稍少的乘法运算,可能减少 10% 到 15%,但如果您只做几次,额外的努力是不值得的。
如果您使用的是乘法同余伪随机数生成器(PRNG),则重要的是要知道每个数字的大小显示出随机特性。要将生成器的输出 R 转换为范围在 0 到 N-1 的整数,正确的计算方式是⌊RN/p⌋,其中⌊x⌋表示“x 的地板”,意思是将 x 向下舍入到下一个较低的整数。例如,⌊27⌋是 27,⌊27.999⌋是 27。表达式⌊RN/p⌋略微偏向于较小的值,即,它会比较频繁地产生较小的数字。但是,当 p 远远大于 N,比如 p > 1000N 时,这对于加密目的并不重要。
历史旁注
顺便说一句,符号⌊x⌋和相应的⌈x⌉(读作“x 的 ceil”,意思是将 x 四舍五入到下一个更高的整数,因此⌈27.001⌉为 28)都是由肯尼斯·艾弗森(Kenneth Iverson)在 1962 年发明的,他是 APL 编程语言的创造者。APL 是第一种交互式编程语言。今天的计算机用户认为交互性理所当然。您按下一个键或点击鼠标,计算机就会执行某些操作。他们没有意识到这个概念必须被发明。在那之前,计算的标准模型是您通过卡片阅读器运行一叠卡片,计算机打印结果,几个小时后您得到一叠纸。
警告:不要使用(R mod N)作为您的随机数。R mod N 可能严重偏向低值。例如,如果模数 p = 11,N = 7,那么(R mod 7)的 11 个可能值为 0, 1, 2, 3, 4, 5, 6, 0, 1, 2, 3,因此 0, 1, 2 和 3 的生成频率是 4, 5 或 6 的两倍。
只要 m > √p,乘法同余生成器将具有良好的随机特性。最好是乘法逆 m' > √p。这意味着 m 的位数至少需要是 p 位数的一半。您希望 p 尽可能大,以便生成器具有长周期,同时希望 m 足够大,以便生成器是随机的。您可以走多远?m 和 p 的大小受计算机寄存器的大小限制。如果超过一个寄存器,速度将受到惩罚。
每个伪随机数 x[n]是通过将前一个数字 x[n-1]乘以 m 生成的。数字 x[n-1]可以有与 p 相同数量的位,因此如果 p 有 b 位,则 x[n-1]也可以有 b 位。由于 m 必须至少有 b/2 位,因此乘积 mx[n-1]可以有 3b/2 位。如果寄存器大小为 63 位,则 b 最多可以是 63 的 2/3,即 42,这意味着 m 最多可以有 21 位。最好使 m 大于√p。一个合理的折衷方案是 m 为 25 位,p 为 38 位。这样可以让周期长达 2³⁸。
使生成器不可预测所需的属性是生成的单位具有相等或均匀的频率,成对的单位具有相等的频率,三元组和四元组具有相等的频率,依此类推。实际上,您不需要超过八元组或最多十元组的字节。如果您想要绝对确定,可以将所需的密钥大小除以生成的单位的大小。例如,如果您的密钥大小为 128 位,PRNG 生成 4 位十六进制数字,则您可能需要使 n 元组在所有 n 值上的频率相等,直到 32。 (那些这样做的人显然是强迫症患者,应该寻求治疗。)即使对于 4 位随机数,也没有必要也没有用处超过 16 元组或最多 20 元组(sexdecuples 或 vigintuples),即 64 或 80 位。
Emily 需要超过 2⁶⁴或 2⁸⁰字节的已知明文才能利用这些不均匀的频率。即使 Sandra 从不更改她的密钥,Emily 也不可能积累那么多的材料。从长远来看,假设有一颗卫星以每秒 1 MB 的速率发送遥测数据。进一步假设,它同时使用两个不同的密钥流发送这些数据,而 Emily 拥有其中一个密钥。即使她以每秒 1 MB 的速度获取明文/密文对,她仍需要大约 585,000 年才能收集到 2⁶⁴字节。即使有 1000 颗卫星都使用相同的密钥,也需要 585 年。
如果对于每个 n 的所有值,n 元组的频率都相等,则您的生成器是真随机的。您已经找到了一种生成真随机数的数学算法。恭喜。去领取您的菲尔兹奖。
为了使元组频率在 n 元组中相等,通常需要生成器的种子本身至少是 n 元组。对于乘法同余生成器来说,单个单位和对频率是均匀的,但三元组频率从不均匀,而对于 n > 3 的 n 元组频率则远非均匀;其中大多数频率为 0。
如果你有几个已知明文字符,并且密码使得很容易从明文/密文对确定随机输出,即,如果组合函数是xor、add或madd,那么破解乘法同余密码就很简单。例如,如果密码通过对密钥字节和明文字节进行异或运算来获取密文字节,那么 Emily 所需要做的就是将明文字节与密文字节进行异或运算以获取密钥字节。
如果生成器有一个 31 位或 32 位的模,即使在个人电脑上,Emily 也可以尝试所有 2³¹或 2³²种种子的值。已知的明文字符仅用于验证。如果模数更大,例如 48 位或 64 位,则前 2 个或 4 个已知的明文字符用于限制搜索范围。第一个随机输出将当前生成器状态限制在一个窄范围内,即总范围的 1/256。第二个已知的明文字符给出第二个输出,将状态限制在该范围的 1/256,依此类推。
因此,单个乘法同余生成器在密码学上并不安全。可以使用更大的模数,使用卡拉兹巴或图姆-库克等大整数乘法技术,但这会牺牲这一类生成器的高速度。有更快的方法来生成密码安全的生成器,因此本书不会涉及大整数乘法方法。
13.4 线性同余生成器
线性同余生成器是对乘法同余生成器的扩展。它们在递推公式中添加一个线性常数项 c。从种子 s 开始,通过递推生成伪随机数序列 x[n] 的是公式是

换句话说,要获得下一个伪随机数,你将前一个数字乘以 m,加上 c,然后取该和对 P 的模。种子可以是任何整数 1、2、3、...、P-1。当满足以下三个条件时,生成器将具有最长可能的周期:
-
c 与 P 互质,
-
对于每个是 P 因子的素数 p,m 的形式为 pk+1,且
-
如果 P 是 4 的倍数,则 m 的形式为 4k+1,
其中 k 可以是任意整数。这些被称为 T. E. Hull 和 A. R. Dobell 在 1962 年发表的Hull-Dobell 条件。
例如,假设 P = 30,即 2×3×5。那么 m-1 必须是 2、3 和 5 的倍数。换句话说,m 必须是 1。所以,如果 s = 1,c = 7,伪随机序列将是 1、8、15、22、29、...。这是一个等差数列,一点也不随机。因此,通常选择模数 P 为质数的幂,最常见的是 2。找到产生良好随机特性的 m、c 和 P 的值是困难的。
然而,线性同余生成器有一个很好的用途。如果你想产生一个具有极长周期的生成器,你可以将两个或多个模数为不同质数幂的线性同余生成器的输出相加,以获得具有良好随机特性和周期等于这些模数乘积的生成器。例如,假设你添加了以下三个 PRNG 的输出。我选择了 3 个模数尽可能大,但仍适合于 32 位机器字,我选择了乘数和常数以满足 Hull-Dobell 条件。除此之外,我任意选择了它们。

让 w[n] = (x[n]+y[n]+z[n]) mod 2³¹。通过将其右移 23 位来选择 w[n] 的高阶字节,即 v[n] = w[n]/2²³。只要 (1) 三个乘数中至少有一个,以及它的乘法逆元,大于其对应模数的平方根,且 (2) 其余两个乘数都不是 1 或 P-1,那么 v[n] 序列将具有良好的随机特性。v[n] 序列的周期为 2³¹3¹⁹5¹³ = 3.0468×10²⁷。
13.5 链式异或生成器
最简单的链式异或生成器操作的是一串比特,例如 10111。基本思想是将第一个比特与最后一个比特进行异或操作,删除第一个比特,并将新比特附加到字符串的末尾,即 x[i] = x[i-1]⊕x[i-n]。由于 n 位字符串有 2^n 种可能的值,而且由于全零字符串产生一系列全零,链式异或生成器的最长周期为 2^n-1。让我们用 3 位字符串的一个小例子来看一下。

经过 7 步后,初始字符串 001 重复,因此该生成器的周期为 7。这称为完整周期生成器。当 n 为 2、3、4、6、7、15 或 22 时,链式异或生成器具有完整周期。对于 n = 37,该生成器接近于完整周期的概率为 0.00057%。也就是说,99.99943% 的所有 37 位值形成一个大循环,而其余的属于较短的循环。对于某些目的,n = 37 可能是一个不错的选择。对于大多数 n 值,存在若干个重复的比特序列,有些短,有些长。它们的总长度为 2^n-1。只有对于完整周期生成器才能谈论周期。否则会有多个循环,可能长度不同。
假设你需要一个周期长于 2²² 的生成器,并且不愿意冒获得短周期的 0.00057% 的风险。你可以怎么做?一个选择是尝试其他生成函数。而不是使用 x[i] = x[i-1]⊕x[i-n] 的递归关系,尝试使用 x[i] = x[i-1]⊕x[i-j]⊕x[i-k]⊕x[i-n] 的递归关系,其中 j 和 k 的值使得 1 < j < k < n。这些生成器中很有可能有一些具有完整周期。但是请注意,具有 3 项的 x[i] = x[i-1]⊕x[i-j]⊕x[i-n] 的生成器永远不会产生完整周期。项数必须是偶数。
无论你选择哪个生成器,结果都是一系列比特序列。要得到伪随机的字节序列,将比特按照 8 位一组取出,即比特 1 到 8,比特 9 到 16,比特 17 到 24,依此类推。这需要为每个字节生成 8 位比特。有一种更快的方法。不是逐比特进行异或操作,而是一次异或一个字节。实际上,您是同时运行 8 个单比特生成器。这样,每次操作就可以获得一个完整的字节。如果你的编程语言支持,你可以使用完整的 32 位字,并每次获取 4 个字节。
在 13.1 节列出的任何组合函数都可以用于将伪随机流与明文组合成密码。如果 Sandra 选择xor、add或madd作为组合函数,那么密码将很容易让 Emily 解密,前提是她拥有足够的已知明文。她可以轻松确定与明文字符对应的随机输出。这使她可以重构密钥流的一部分。这一部分可以向前和向后延伸,仅通过进行异或操作就可以重构整个密钥流。
Sandra 可以使用一个技巧来迷惑 Emily。假设生成器产生一系列 32 位字,Sandra 将其分成四个单独的字节。Sandra 不一定总是从高阶位开始,而是每次可以从不同位置开始。等效地,Sandra 可以将 32 位字循环左移或右移,位移数量不同。例如,ABCDEF 循环左移 2 位得到 CDEFAB。位移的长度可以是在 0 到 31 范围内的重复数字序列。这样,Emily 无法将生成器的连续输出匹配起来以重构密钥流。
13.6 链式加法生成器
链式加法生成器,也称为滞后斐波那契生成器,类似于链式异或生成器,只是它们使用加法而不是异或。加法被理解为模 2^w,其中 w 是位大小,x[i] = (x[i-1]+x[i-n]) mod 2^w。w 的典型值为 15、31 和 63,使用有符号加法,或者 16、32 和 64,使用无符号加法。另一种看待 mod 2^w 运算的方式是忽略高阶位的进位。
因为加法会从一个位位置产生进位到下一个更高位位置,所以高位的周期是低位的两倍。每个字中低阶位的周期与具有相同种子的异或生成器的周期相同。这是因为加法与带进位的异或相同。如果链式加法生成器中低阶位的周期为 P,则高阶位的周期为 2^(w-1)P。
链式加法生成器是一种简单的方法,可以在很少的额外工作量下获得更长的周期。只需找到一个具有长周期的链式异或生成器,最好是完整周期,然后将其从单比特宽度扩展到完整字宽度。与乘法同余生成器一样,输出序列中最随机的部分是高阶端。对于伪随机字节序列,只使用每个字的高阶 8 位。
再次,您可以使用第 13.1 节中的任何组合函数将伪随机流与明文组合成密码。
13.7 移位和异或生成器
另一类 PRNG 是由佛罗里达州立大学的 George Marsaglia 发明的移位和异或生成器。Marsaglia 最著名的是开发了 Diehard 随机数测试套件。这些生成器使用两个作用于整数的运算符。
-
<< 左移. 例如,80<<2 将整数 80 左移 2 位,得到值 320。
-
右移. 例如,80>>2 将整数 80 右移 2 位,得到值 20。
被移出计算机字的高位或低位的位将会丢失。例如,25>>1 是 12,而不是 12.5。这些操作与循环左移 <<< 和右移 >>> 相对应,其中被移出计算机字一端的位将被放置在相反端。例如,如果 32 位计算机字中的十六进制数字为 12345678,则 12345678<<<4 得到 23456781,而 12345678>>>12 得到 67812345,因为每个十六进制数字有 4 位。如果字包含在较大的计算机寄存器中,则未使用的位需要清零。
在这个类中有几种不同的生成器。必须仔细选择位移的长度和方向,以使生成器具有长周期。以下是 Marsaglia 设计的两个 Xorshift 生成器的示例。它们具有长周期和强大的随机特性,尽管它们未通过一些更敏感的随机性测试。每个生成器使用左-右-左的模式中的 3 次位移和异或步骤来生成序列中的下一个数字。变量 y 用于保存中间值。任何正整数都是合格的种子。

13.8 FRand
FRand,即快速随机生成器,是我自己的创建。FRand 使用一个宽度为 W 的 S 个二进制字的数组,也就是说,它使用数组中每个字的低位 W 位来保存无符号整数值。周期取决于 S 和 W 的值。我发现 W = 29 效果最好,而且 S = 40 和 S = 64 给出了非常长的周期。种子数组可以看作是一个 40×29 位的矩阵。每一行是一个种子,每一列代表种子字中的一个位位置。
对于 S = 40,周期为 2¹¹⁶⁰-2⁴⁰,约为 1.566×10³⁴⁹,对于合格种子。如果至少有一个 40 个种子字中的一个既不全为零也不全为一,则该种子是 合格 的。该生成器有一个弱点。如果种子数组几乎完全为零,则生成器可能会产生数十甚至数百个连续的输出,其中大部分是零。在极端情况下,当种子数组包含 1159 个零和仅 1 个一时,至少需要 1120 个周期才能在每列中至少有一个 1。
最好是初始种子包含大量随机模式中的 1 和 0。获取适当的种子数组的一种方法是将表达为 UTF-8 代码的助记符或数字密钥,并将其哈希为一个 1160 位值。一个合适的哈希函数是

生成器一旦被初始化,伪随机序列就可以通过递推公式生成。此生成器的递推公式使用索引或标记符号 n。

每次通过种子数组时,当 n = 40 时,索引会重置为 1,并且下一个伪随机数将由 x[1] = (x[1]⊕x[40])>>>1 生成。也就是说,第一个 29 位字 x[1] 循环向右移动一个位位置。
这个伪随机序列通过了许多随机性测试,但远远达不到密码学安全的要求。为了产生一个安全的序列,诀窍是从 29 位字的不同部分获取每个连续的输出字节。伪随机序列本身可以用来选择这些位置。假设下一个 3 个伪随机输出分别是 a、b 和 c。取 s = a mod 25。如果 s 在 0 到 21 的范围内,则将 b 向右移动 s 个位置并取低 8 位。在这种情况下只生成 a 和 b。c 将为下一个伪随机数生成。如果 s > 21,则将 s 位置向右移动会留下少于 8 位。在这种情况下丢弃 a 并取 s = b mod 22。将 c 向右移动 s 个位置并将低 8 位作为随机输出。代数表示如下,

该过程平均使用 2.12 个伪随机输出来产生每个安全密钥字节。这样,密钥字节大约一半的时间来自偶数输出,另一半的时间来自奇数输出。生成器会以不规则的方式大约每 8 个周期在奇数和偶数之间来回切换。
13.9 梅森推土机
梅森推土机 是任何 PRNG 类别中周期最长的。它由广岛大学的松本真和西村拓士于 1997 年开发。它以法国神学家马林·梅森(Marin Mersenne,1588-1648)的名字命名,他以形式为 2^n-1 的素数而闻名,并因传播伽利略、笛卡尔、帕斯卡和费马等人的作品而广为人知。
推土机 具有良好的随机特性,尽管它在一些随机性测试中失败。它比本章描述的其他随机数生成器要慢得多。它的主要重要性在于其庞大的周期,即梅森素数 2¹⁹⁹³⁷-1,该数在 1971 年由 IBM 纽约州约克敦的 IBM 研究院的 Bryant Tuckerman 发现。IBM 研究院为此发现感到非常自豪,将“2¹⁹⁹³⁷-1 是质数”印在了其信笺和邮资表上。
与 FRand 一样,梅森推土机也存在一个缺点,即如果初始状态大部分为零,则可能需要许多周期才能变得看起来随机。对于梅森推土机,通常需要 10,000 或甚至 50,000 个启动周期才能开始使用输出。相比之下,FRand 软件包有一个函数,它可以在不需要任何启动周期的情况下初始化生成器。
13.10 线性反馈移位寄存器
线性反馈移位寄存器(LFSR)是电气工程师的宠儿,因为它在数字电路中实现起来非常简单。LFSR 使用一系列位 x[1]、x[2]、...、x[n]。下一个位通过对前面的几个位进行异或运算来生成,例如

使用 3 个反馈。当然,反馈的数量不一定是 3,但是奇数个反馈通常会比偶数个反馈给出更长的周期。
假设 i < j < k,则此 LFSR 将有 k+1 位位置。生成每个新位后,低阶位被移出,新位被放置在高阶位置,因此寄存器始终包含伪随机序列的最新的 k+1 位。
使用 LFSR 的一个明显缺点是它们速度较慢,因为它们需要 8 个周期才能生成每个伪随机输出字节。LFSR 也是伪随机生成函数中最弱的,因为它们完全是线性的。如果 Emily 有一些已知的明文,并且能够确定相应的关键位,则她可以通过解一组线性方程来重构整个伪随机序列,这很容易。如果 Sandra 使用xor、add或madd作为组合函数,Emily 可以确定关键位。
因此,伪随机输出通常在与明文结合之前通过非线性替换。这可以通过两种方式进行,按位或按字节。非线性按位替换是可能的,因为在每个周期中,寄存器中有 k+1 个位可访问。用作非线性函数输入的位称为taps,可以从寄存器的任何位置获取。使用这些非线性函数使得 Emily 更难确定关键位。
一个合适的非线性函数是多数 函数。如果其输入位的大多数为 1,则此函数的值为 1,否则为 0。对于具有 3 个输入位 A、B 和 C 的情况,多数函数是 AB∨BC∨CA,其中 ∨ 是布尔 OR 函数。多数函数对于任何奇数个输入,如 3、5、7,等等,都是定义的。这个想法的一个扩展是使用 9 个 taps 和三个 3 位多数函数电路。9 位中的三个位进入每个电路。然后,将 3 个输出位通过第四个多数电路。
如果组合函数是sxor、sadd或poly,则字节替换是固有的。这些非线性替换的构造在第 12.3 节中详细讨论。可以将按位和按字节替换组合起来。生成输出字节中的每个 8 位都使用 taps 和非线性位函数,然后将这些电路的 8 个单个位输出馈入按字节替换中。
让我们看看 Emily 必须做些什么来破解一个 LFSR 密码。假设 Sandra 使用一个 40 位的硬件 LFSR, taps 位于位位置 3、6 和 9,进入到一个大多数功能电路 M 中,并且她天真地使用 xor 作为组合函数。进一步假设 Emily 有一些已知纯文本的字符,因此知道了一系列输出位。对于每个已知位,进入 M 的 3 个 LFSR taps 位置只缩小到了 8 个可能值中的 4 个。如果位是 0,则 3 个 taps 必须是 000、001、010 或 100。如果位是 1,则 3 个 taps 必须是 011、101、110 或 111。
经过 4 个周期,12 位已经进入了 3 个 taps,所以对于这 12 位有 4⁴ = 256 种可能的组合。这相比于 2¹² = 4096 种组合大大减少了。更好的是,从 Emily 的角度来看,最初位于位置 3 的位现在位于位置 6,而最初位于位置 6 的位现在已经移动到位置 9。这意味着一些 12 位组合可以被消除。可以消除的组合数量取决于输出位的序列。如果第一个和第四个输出位相同,则消除的组合较少。如果它们不同,则消除的组合较多。每个额外的已知输出位进一步减少了移位寄存器中可能组合的数量。
举个例子。假设 Sandra 使用一个 40 位的 LFSR,带有 3 个 taps,每个 taps 都进入到大多数功能中以产生每个输出位。还假设 Emily 知道设备的所有细节,并知道消息来自总部,所有消息都以 GHQ 开头。这给了她 24 位已知纯文本。如果她将这 24 位与密文的对应位进行异或运算,她就从设备中得到了 24 个输出位。对于这些输出位中的每一个,都有 4 种可能的 3 位输入组合来产生已知值。这就在 3 个 tap 位置产生了 72 位可能的位值。由于 LFSR 中的位每个周期向前移动一个位置,这些位组合会重叠,因此总的组合数量可以不断减少。
Sandra 应该从这个简要分析中学到什么?(1) 扩大移位寄存器,最好至少为 128 位。(2) 将 taps(触发器)远离得越远越好。(3) 不要均匀地分布 taps。在这里,3、6、9 是一个异常糟糕的选择。(4) 使用一种让对手难以确定关键位的组合函数。不要使用 xor、add 或 madd 作为组合函数。更好的选择是 xors 和 adds,但最佳选择是 poly。
13.11 估计周期
如果你是一个密码学爱好者,你可能想要尝试设计自己的伪随机生成器。本书不会涵盖如何测试 PRNG,这是一个很大的主题,但让我们看看你如何估计你的生成器的周期。该方法取决于状态向量的大小(第 13.2 节)。
如果状态向量很小,比如 31 位,您可以只运行您的生成器 2³¹个周期,看看何时重复。不幸的是,初始种子可能永远不会重复。有一个处理这种可能性的技巧。制作 2 个 PRNG 的副本,并使用相同的种子 S 进行初始化。然后逐步运行第一个副本,每次运行第二个副本 2 步。假设您发现在 3000 个周期后,这 2 个副本产生相同的状态向量。这意味着 R[3000] = R[6000],因此您的生成器的周期至少为 3000,使用种子 S。
如果状态向量较大,比如 64 位,那么运行您的生成器潜在地 2⁶⁴个周期是不可行的。您仍然可以通过抽样来估计周期。制作一个表,比如 T = 1,000,000 个条目。这个表中的第 N 个条目将保存您的生成器产生值 N 时的周期数。最初,将这个表中的所有条目都设置为零,因为尚未产生任何值。选择范围在 1 到 T-1 之间的种子,并运行您的生成器,也许是 G = 1,000,000,000 个周期。在每个周期,如果生成的值 N 小于 T,则记录表中的周期号 N。如果条目不为零,则表示有重复项,这告诉您周期。例如,如果值 12795 在第 33000 个周期和第 73500 个周期再次产生,则该种子的生成器周期为 73500-33000 = 40500。
如果您找不到任何重复项,那么您可以通过查看生成了多少个 T 值来估计周期。如果表中的 E 个条目不为零,则生成的条目比例为 E/T。由于您运行了 G 个周期的生成器,估计周期为 G/(E/T) = GT/E。
正如我们在链式数字生成器(第 4.5.1 节)中看到的,一个生成器可能有几个不同的循环,有些长,有些短。您应该对生成器的周期进行多次估计,使用不同的种子。一个好的策略是首先使用种子 1。对于第二个种子,使用第一个种子未生成的最低值。对于第三个种子,使用第一个或第二个种子未生成的最低值。您可以通过制作累积表来做到这一点。在估计运行之间不要将其重置为零。如果在大约 20 到 100 次这样的运行中周期的估计是一致的,那么您可以确信您的生成器对大多数种子具有长周期。
13.12 加强生成器
加强 PRNG 的一种方法是使用一个选择生成器,将生成数字的操作与选择数字的操作分开。 这可以通过在数组中保留 N 个数字来完成,比如 32、64 或 256 个数字。 数组中的每个数字应该是所需随机输出的大小。 例如,如果要生成随机字节,则数组应包含 8 位数字。 首先对 PRNG 运行 N 个周期以产生初始数字,这些数字按生成顺序放入数组中。 然后使用新种子重新启动 PRNG。 然后使用生成器生成范围为 1 到 N 的伪随机数序列。 每个数字用于选择数组的一个元素。 该元素成为下一个伪随机输出。 然后使用 PRNG 用新的伪随机数替换所选数组元素。
这意味着第一个、第三个、第五个,... 随机数用于选择,而第二个、第四个、第六个,... 数字用于替换数组中的数字。 使用两个具有不同种子的 PRNG 的两个独立副本可能很方便,但这不会增加周期。 更好的策略是使用两个周期互质的不同生成器。 然后,组合生成器的周期是它们周期的乘积。 例如,如果数字是由具有周期 2³¹-1 的乘法同余生成器生成的,而数字是由具有周期 2³¹的线性同余生成器选择的,那么组合生成器的周期是 2⁶²-2³¹,或 4.612×10¹⁸。
4.612×10¹⁸的周期对于密码工作已经足够长,但选择生成器仍然不具有密码学安全性。 这是因为艾米莉可以穷举选择器序列并尝试所有 2³¹种可能的种子。 有足够的已知明文,这可能会给她第一个生成器的输出序列,这足以解决问题。
有几种可能的解决方法。 (1) 使用像xors、adds或poly这样的组合函数,这样艾米莉就很难确定随机输出。 (2) 使选择器生成器更大,比如说 63 位而不是 31 位。 (3) 使选择器生成器的种子更大,例如通过使乘数和/或加法常数成为种子的一部分,即生成函数 x[n+1] = (mx[n]+c) mod P 中的 m 和 c。 (4) 使用下一节中的技术来构建一个具有更长周期的选择器。
13.13 组合生成器
伪随机数生成器可以以各种方式组合,以获得更长的周期或更好的随机性属性,或者变得具有密码学安全性。 这些改进通常是相辅相成的。 你不会为了实现另一个而牺牲一个。 如果增加周期,通常会同时改善随机性。 有两类组合生成器,固定组合和可变组合。
固定组合
在固定组合中,有几个 PRNG,最好是周期互质的。这些可以是乘法同余、线性同余或 Xorshift 生成器。这些生成器的输出可以按位或按字节组合。一种按位的方法是从每个生成器中取一组固定的位,并将它们输入到某个组合函数中。例如,可以从 8 个生成器中分别取高阶位,或者从 4 个生成器中分别取两个高阶位。然后,这 8 位将被输入到一个高度非线性的替换中。替换步骤防止 Emily 将每个生成器的输出分离并单独解决它们。
一种按字节的方法是从每个生成器中取高阶字节,并通过对它们进行模 256 相加或者异或来组合它们。两个生成器可以通过将它们的输出相乘并取乘积的中间 8 位来组合。另一种技术是取线性组合,例如 (a[1]x[1]+a[2]x[2]+a[3]x[3]+a[4]x[4]) mod 256,其中 x[1]、x[2]、x[3] 和 x[4] 是来自四个 PRNG 的 8 位输出,并且四个系数 a[1]、a[2]、a[3] 和 a[4] 可以是 1 到 255 之间的任意奇数整数。这些系数可以针对每条消息不同。
例如,四个 PRNG 可以使用素数模 2³¹-1 和 4 个不同但固定的乘数来生成。这四个 31 位种子加上四个 7 位系数组成了 152 位的组合种子。
三个 PRNG 可以通过使用循环移位操作(第 13.7 节)来组合。使用 32 位无符号生成器时,32 位输出可以使用 x[1] + (x[2] >>>11) + (x[3] >>>21) mod 2³² 来组合。最佳移位量是 32 位寄存器大小的 1/3 和 2/3。如果你希望使用超过 3 个生成器,请尽可能使移位量均匀。例如,使用 5 个生成器时,移位量应该是字长的 1/5、2/5、3/5 和 4/5,四舍五入到最接近的整数。
另一个固定生成器 CyGen,通过循环移位来组合两个生成器 C 和 G。C 可以是任何大小,但 G 应该是 32 位或 64 位。在每个周期中,分别从 C 中取 5 或 6 位,以获取移位量。然后,从 G 中取得的输出将向左循环移动该数量的位置,以获得 CyGen 的输出。这使得 Emily 无法从其输出序列重构 G。
没有限制线性组合。例如,可以使用 x[n]+y[n]z[n] 或 x[n]+y[n]²+z[n]z[n-1]z[n-3] 将 3 个生成器组合起来。至少求和中的一项应该是线性的。可能性是无限的,当然,你可以在多种方法之间进行切换。
可变组合
可变组合的一个示例是第 13.11 节中显示的选择生成器。但是,让我用一个警示故事开始这一节。这里有一个组合生成器 CG5,似乎是绝对安全的,但实际上不是。
组合生成器 CG5 使用 5 个乘法同余生成器,每个都有不同的乘数和不同的 31 位素数模数。将这些生成器称为 G0、G1、G2、G3 和 SEL。(或者,SEL 可以是一个线性同余或 Xorshift 生成器,具有 2³¹周期。)生产生成器 G0 到 G3 用于产生伪随机数,选择生成器 SEL 用于选择 G0-G3 中的哪一个用于产生下一个伪随机输出。具体来说,SEL 的高 2 位确定了在 G0-G3 中选择哪一个。假设 SEL 生成了 10,这选择了 G2。然后 G2 生成器运行 1 个周期,其输出成为 CG5 的下一个输出。组合生成器的周期约为 2¹⁵⁵,具有良好的随机特性...但不会是密码学安全的。原因如下:
假设艾米莉有足够的已知明文,并考虑从 CG5 中得到的前 17 个输出。这 17 个输出中至少有 5 个必须由同一个生成器产生。(如果 4 个生成器最多产生 4 个输出,那么最多只能有 16 个输出,而不是 17 个。)从 17 个中选择 5 个项目的方式只有 6188 种。艾米莉可以尝试所有这些方式。这样一来,就有大约 1.33×10¹³种放置加种子的组合需要测试,然而,这可以大大减少。艾米莉知道这 5 个选择输出的每个的高 8 位。她不应该从 17 个输出的第一个开始,而应该从 5 个选择输出的第一个开始。然后,她只需要尝试 2²³个值,而不是 2³¹个值。这样一来,她的工作量就减少到了可管理的 5.19×10¹⁰个组合。CG5 组合生成器并不安全。
让我们看一个更安全的生成器。我将其称为Gen5。再次,组合生成器使用 5 个乘法同余生成器,每个都有不同的乘数和不同的 31 位素数模数。模数和乘数是固定的,并且选择得具有良好的随机特性。这次让我们称这些生成器为 G1、G2、G4、G8 和 SEL。只使用选择器 SEL 的 4 个高阶位。在这个 4 位数中,第一个位上的 1 表示选择 G1,第二个位上的 1 表示选择 G2,第三个位上的 1 表示选择 G4,第四个位上的 1 表示选择 G8。当选择少于两个生成器时,SEL 将再运行一个周期以生成新的选择。只使用 SEL 生成的 16 个可能的 4 位输出值中的 11 个,因此 SEL 将额外运行一个周期的时间为 5/16,额外运行两个周期的时间为 25/256,依此类推。
当选择两个或更多发生器时,它们每个都会运行 1 个周期,它们的输出将模 2³¹ 加在一起,以产生 Gen5 伪随机输出。未选择的发生器不会运行,因此 4 个发生器会异步运行。该输出略微偏向较低的数字,但对 Emily 来说并不足以利用。如果您担心这种偏差,可以(1)丢弃高阶位并使用和为输出字节的高阶位 2 到 9,或者(2)使用 Meld8 操作(第 12.3.7 节)。也就是说,通过将和的高阶 8 位与和的第二个 8 位进行异或运算来从 Gen5 发生器形成输出字节,即将位 1 到 8 的异或位与位 9 到 16 的位进行异或。
*****Emily 再也无法分离出任何一个发生器。Emily 可能看起来可以分离出其中的 6 对 Gi+Gj 中的一个,其中 i 和 j 可以是 1、2、4 或 8。这样的一对可以被视为单个发生器处理,然后稍后可以将 Gi 与 Gj 分离出来。让我们首先看看这种方法。为了求解 Gi 和 Gj 的种子,至少需要来自 Gen5 的 9 个随机输出。由于这些配对每次只发生 1/11 的概率,Emily 可能需要查看 89 个或更多的消息字符。这是因为,仅仅由于偶然,3 个或 4 个发生器的 5 个组合可能比 2 个发生器的 6 个组合更频繁地发生。
对于 89 个物品中的 9 个物品,大约有 6.356×10¹¹ 种可能的放置方式,因此 Emily 只需尝试 SEL 发生器的所有约 2³¹ = 2.147×10⁹ 个种子,这样 Emily 就可以找到所有 6 对 Gi+Gj 的下一个 10 个位置。这也让她可以计算出 Gi 和 Gj 在每次出现时已经被使用了多少次。例如,假设 G2+G4 出现在 Gen5 的第 14 个周期。在这 14 个周期中,可能有 6 个周期中使用了 G2,而 9 个周期中使用了 G4。现在 Emily 知道了 G2 的第 6 个输出加上 G4 的第 9 个输出的值。
如果 Emily 可以为 G2+G4 这样的 10 个输出值组合起来,那么她可以在大约 2^(31+31-8) = 2⁵⁴ = 1.801×10¹⁶ 次试验中确定这两个发生器的种子。这必须对 SEL 的约 2³¹ 个种子进行操作,因此总工作量约为 2⁸⁵ = 3.869×10²⁵。这相比于 Gen5 的暴力解决方案需要 2¹⁵⁵ 次试验有了巨大的改进,但远远不及 2¹²⁸ 次试验的目标。此发生器被评为 Nine.******
现在我们已经准备好进行致命一击了。这是 Gen5 的升级版本,我将其称为 GenX。GenX 由伪随机数生成器和密码两部分组成。GenX PRNG 将生成一个 10 位伪随机输出序列,密码将把密钥字节 k[n] 与消息字节 x[n] 结合起来产生密文。这将使密码超出 128 位密钥大小。
GenX 生成器只是 Gen5 生成器的扩展版本。它使用四个生产生成器 G1、G2、G4 和 G8,以及一个选择生成器 SEL。SEL 的高阶 4 位用于选择 2 到 4 个生产生成器的某种组合。所选的生产生成器运行一个周期,它们的输出相加模 2³¹ 以产生一个和 G。G 的高阶 10 位与下一个 10 位的 G 进行异或运算以产生 10 位输出。10 位输出被分为一个 8 位密钥字节 k[n] 和一个 2 位控制位 c[n]。
GenX 密码器将密钥字节 k[n] 与消息字节 x[n] 根据控制位 c[n] 使用混合的键控替换 S 进行组合。控制位 c[n] 决定了每个明文字节使用哪种组合函数。解释这 2 个控制位的一种可能方式是

所有的和都是模 256。Cipher GenX 被评为十。该密码的密钥是用于 G1、G2、G4、G8 和 SEL 的五个 31 位种子以及用于混合替换 S 的密钥,例如 SkipMix 密钥。
13.14 真随机数
所有在本章讨论过的生成随机数的技术都产生伪随机数。我看过的每一本讨论随机数的书都重复着这样的观念,即使用软件产生真正的随机数是不可能的。这是因为他们将自己限制在了一种太狭窄的可能方法范围内。在本节中,我将介绍一种使用软件批量生成真正随机数的可行方法。
文献中所有用于生成真正随机数的方法都依赖于诸如宇宙射线、热噪声、振动、核衰变等物理现象。这些方法对于加密目的来说太慢了。
相反,你可以通过一个 3 步过程产生真正的随机数。 (1) 从自然界中获取大量真正的随机数。 (2) 使它们的概率分布均匀。 (3) 通过从这个语料库中选择和组合数字来生成随机数。接下来的几节将详细介绍如何完成这些步骤。
自然界充满了随机性。地球上每一棵植物和树上每片叶子的形状、颜色和位置都是随机的。它们是风和微风、阳光透过叶片、从根部流上的养分、打在叶片上的雨滴和冰雹、咬过叶片的昆虫、鸟类、松鼠、地面震动以及许多其他因素的结果。每一个海洋上的波浪、每一个沙漠中的植物和岩石、每一条河流上的涟漪、每朵云、每一个海滩上的贝壳在大小、形状、颜色、位置、方向甚至速度上都是随机的。
这些随机性的一部分可以通过简单地拍摄这些地点来捕捉。你甚至不需要离开家。只需拿一把爆米花撒在有图案的表面上。你还可以使用你认识的人和你去过的地方的照片。有些照片是你从网站和电子邮件中下载的。还有成千上万张照片被操作系统和你使用的应用程序放在了你的计算机上。你可以使用网络浏览器找到数十亿张照片。作为一个实验,我编造了一个伪单词 ZRMWKNV,并搜索了图片。我得到了超过 6,000 个与 ZRMWKNV 相关的搜索结果,其中一些网站包含了数百张图片。
滞后线性加法
每个这样的图像文件包含大量的随机性,特别是如果分辨率很高,但字节值的分布远非均匀,也远非独立。通过使用滞后线性加法,将整个图像文件,包括头部在内,视为长度为 L 的一个长字节字符串,可以使分布变得平坦。以下是一个示例:

下标总是循环的。如所示,三次传递足够了,但随时可以使用更多。你不希望频率太均匀,因为那将不再是随机的。如果你想使用简化版本,比如 x[n] = (x[n]+x[n-179]) mod 256,请注意需要五次传递。确保在每次传递中使用不同的滞后。
这些系数 7、31 等并没有什么特别之处,我是随意选择的。它们可以是从 1 到 255 的任意奇整数。对于每次传递,滞后 40、1581 等应该被选择得一个远大于另一个。小步长,大步长。一个想法是使较小的滞后约为∛L,而较大的滞后约为∛L²。例如,如果图像文件大小为 1,000,000 字节,你可以分别使滞后约为 100 和约为 10,000。较小的滞后可以在 50 和 200 之间选择,而较大的滞后可以在 5000 和 20,000 之间选择。在滞后线性加法之后使用一个带有密钥的简单替换,使得艾米莉更难重建图像文件。
图像分层
另一种构建真随机序列的方法是取两个图像,使用某种组合函数(如异或或加法,参见第 13.1 节)将它们层叠在一起。一个好的方法是在组合之前对每个图像进行一次滞后线性加法传递,然后在它们被组合后进行最后一次传递。
三个图像可以使用非线性大多数函数(第 13.10 节)逐位进行组合。同样,在组合之前,我建议对每个图像进行一次滞后线性加法的传递,然后在它们被组合之后进行最后一次传递。即使三个图像中没有一个大小相同,也可以使用这种方法。将一个短图像对齐到与最大图像相同的位置,并将另一个短图像对齐到与最长图像相同的位置,就像这样:

当只有两幅图像重叠时,按字节模 256 进行相加。当所有三幅图像重叠时,使用大多数函数逐位进行组合,或者使用模 256 的线性组合,如 c[n]=(113x[n]+57y[n]+225z[n]) mod 256。系数可以是从 1 到 255 的任意奇整数。
对齐图像的另一种替代方法是通过重复来扩展短图像。在这个例子中,x 图像有 22 个字节,y 图像有 33 个字节。通过重复 x 的前 11 个字节,可以将 x 图像扩展到 33 个字节。这样,大多数函数可以在所有 33 个字节位置使用。实际上,这些图像将有数百万个字节。
13.15 刷新随机字节
很好。现在我们有一个名为 T 的表,里面有几百万个真随机字节。它们是真正的随机字节,因为如果艾米丽拥有除了一个字节之外的所有字节,这并不会使她能够确定缺失的那一个字节。桑德拉和莉娃都有一份拷贝。那么呢?我们肯定不能每次发送消息都重复这个过程。
利用 T 的一种方法是将其划分为用于分组密码的密钥。一百万个随机字节可以制作出 62,500 个每个 128 位的密钥。最终这一百万字节将被用完。如果桑德拉正在使用一个强大的分组密码,或许这并不重要。她可以重复使用密钥,只要艾米丽无法知道哪些消息使用了相同的密钥进行了加密。当然,桑德拉不能对流密码重复使用密钥。
假设桑德拉不愿意冒再次使用密钥的风险。一个解决方案是刷新随机数列表。桑德拉可以添加另一幅图像,但这意味着莉娃也必须有同样的图像的拷贝。如果图像来自桑德拉和莉娃都可以访问的网站,那么这可能是一个不错的策略。如果传输的密钥可能被截获,这可能是一个很好的策略。
另一种方法是使用滞后线性加法(第 13.14.1 节)刷新 T。称刷新后的表为 T[1]。现在桑德拉只需要传输 9 个系数和 6 个滞后,她就有另外 62500 个密钥可用。假设每个系数需要 1 字节,每个滞后需要 2 字节,桑德拉只需传输 21 字节即可生成 T[1]。然后为了选择消息的密钥,只需要知道该消息密钥在 T[1]中的位置。对此,两个字节足够了,因为所有位置都是 16 的倍数。当 T[1]用尽时,可以使用新的系数和滞后来构造 T[2]等等。
在第 13.5 节和 13.6 节中,线性函数用于确保生成器具有长周期。这里没有周期,因此没有这样的约束。可以使用一些非线性函数,例如

这里下标循环,a 和 b 是从 1 到 255 的奇整数,i、j 和 k 是介于 1 和 L-1 之间的整数。S 可以是一个固定的非线性替换或者一个变量密钥混合替换。函数 E(x)定义为

当你取 E(x[n-j]x[n-k]) mod 256 时,实际上是将 x[n-j]x[n-k]的各个字节相加。这比仅仅使用 x[n-j]x[n-k]更强,因为 x[n-j]x[n-k]有 3/4 的概率是偶数。
或者,桑德拉可以通过按 1 字节、跳过 3 字节、取下一个字节、跳过 2 字节、取 2 字节、跳过 4 字节等一些周期序列中的步骤,从 T 获得密钥。跳过可以很小,因此 2 或 3 个跳过可以编码在一个密钥字节中。可能如果艾米莉获得了随机源 T,她可以确定小跳过的序列。为防止这种情况,跳过可以与在选定字节上添加一系列数字相结合,对 256 取模,同样周期性。如果跳过的数量和添加的数量是互质的,比如 12 个跳过和 11 个添加,那么是最安全的。使用这种方法,每个消息密钥将使用 2 字节作为起点,6 字节来编码 12 个跳过,再加上 11 个添加,总共 20 字节,或者 160 位。这种方法可以称为跳跃与添加。
在这种类型的系统中,Emily 无法重建 T 是至关重要的。例如,Emily 可能随着时间的推移获得了许多消息的明文并恢复了它们的密钥。如果她还知道这些密钥在 T 中的位置,也许是因为桑德拉在每条消息中将位置传输给了 Riva,那么她可能能够重建 T 的部分。因此,T 本身不应该用于密钥。应该保留 T 以构建 T[1]、T[2],...,然后可以将其划分为消息密钥。保留 T 可以保护桑德拉和 Riva,以防 T[i]中的任何一个丢失或损坏。T 可以称为基础密钥,T[1]、T[2],...可以称为派生密钥。
即使 Emily 可以以某种方式重建 T[1] 或 T[2],她也无法倒退恢复 T,因为 T 是真正的随机。如果 Emily 尝试所有可能的系数和滞后组合,没有任何东西能表明哪个是正确的随机字符串 T,因为有数以万计的字符串。
13.16 同步密钥流
在秘钥密码学中,Sandra 和 Riva 必须使用相同的密钥。通常这意味着要么(1)密钥被加密并与消息一起传输,要么(2)他们有一个密钥列表,并根据日期、时间或其他外部因素从列表中选择每个密钥。还有一种方法是流密码独有的。
Sandra 和 Riva 可以使用同步密钥流。这意味着 Sandra 和 Riva 都持续生成相同的密钥流。当 Sandra 加密一条消息时,她从她的密钥流中的下一个密钥字节开始,这也必须是 Riva 的密钥流中的下一个密钥字节。当 Riva 收到消息时,她必须从密钥流中的相同点开始。Sandra 和 Riva 必须在完全相同的时间从相同的初始种子开始生成。当 Sandra 和 Riva 之间有直接电缆连接,或者有视线塔到塔的连接,或者两者都从同一发射机接收过空中广播时,同步方法最为有用。它非常适合在狭小空间内传输数字化语音。
如果消息是通过具有节点或中继点有显著延迟的网络发送的,特别是分组交换网络,其中消息的部分可能通过不同路径到达并必须在接收端重新组装,发送方必须在传输开始时提供时间戳,比如在消息头中。
由于 Sandra 加密消息需要时间,消息从 Sandra 到 Riva 的传输也需要时间,似乎 Riva 必须比 Sandra 慢几微秒生成随机密钥。同样,当 Riva 发送消息给 Sandra 时,Sandra 也必须比 Riva 慢几微秒生成密钥。
有几种方法可以摆脱这一僵局。一种方法是让 Sandra 只在伪随机流中的特定周期开始消息。例如,Sandra 可能只在每 100,000 个周期开始一条消息。然后当 Riva 在第 123,456,789,123 个周期收到一条消息时,她知道密钥从第 123,456,700,000 个周期开始。如果消息接收时间更接近 100,000 的整数倍,比如第 123,456,701,234 个周期,Riva 可以尝试 123,456,700,000 和 123,456,600,000。Riva 需要存储最后两组 100,000 个伪随机数。100,000 个周期的数字可以根据 PRNG 的速度和两方之间的传输时间调整。
还有一个问题需要解决,即 Riva 如何检测到每个加密消息的起始和结束。如果通信通道有一个空闲状态,在该状态下既不传输零也不传输一,则没有问题。让通道在消息之间保持空闲。否则,让我们假设通道在空闲时发出一串稳定的零。在这种情况下,您需要在消息前后添加额外的 1 位,就像用引号括起消息一样,并要求在下一条消息开始之前必须传输至少 64 个零。在合法消息中发生 64 个零的几率微乎其微。 (此外,请注意,消息之间的平均时间实际上将超过 50,000 个周期;64 个周期只是最坏情况。)因此,当 Riva 检测到至少 64 个零后的 1 位时,她可以确信这是下一条消息的开始,当她发现 1 位后跟着 64 个或更多的零时,那标志着消息的结束。
13.17 哈希函数
哈希函数不是密码,但与密码密切相关,通常与密码学一起使用。在本节中,我将讨论哈希函数的两个用途,并为每个用途提供一个适用的哈希函数。
哈希函数经常用于搜索。假设您有一个人员列表,如客户、患者或学生,并且您经常需要搜索此列表以获取有关这些人的信息。哈希提供了一种快速搜索的方式,即通过将人的姓名转换为可以直接在表中找到的数字。例如,名称“John Smith”可以转换为数字 2307,其中表中的条目 2307 包含有关 John Smith 的信息。
这里有一个专为此目的设计的哈希。对于字母表中的每个字母 L,随机选择某个固定大小(例如 32 位)的二进制值 R(L)。要对名称进行哈希,只需对名称中每个字母的 32 位数字执行异或操作。该哈希的一个弱点是具有相同字母的名称将具有相同的哈希值。例如,ARNOLD、ROLAND 和 RONALD 的哈希值都相同。为了避免这个问题,在添加每个字母后,将哈希值向左循环移动 1 位位置。也就是说,

将最终的哈希值称为 H。H 可以通过缩放转换为大小为 T 的名称表的索引 I,公式为 I = ⌊HT/2³²⌋。例如,如果名称的哈希值为 917354668,表中有 5000 个条目,则索引为 ⌊917354668×5000/4294967296⌋ = ⌊1067.94⌋ = 1067。我们称这种哈希方法为 Hash32。
可能会有几个名称产生相同的索引。有各种方法用于处理这些索引冲突,例如使用一个单独的表来保存重复项,第二次对名称进行哈希以在表中选择不同的插槽,或将重复名称链接在一起。
哈希函数也用于消息认证。在这种情况下,整个消息被哈希为一个长的哈希值。假设是 16 个字节。这个哈希值必须以防篡改的方式发送给 Riva,例如通过一个可信赖的第三方,该第三方记录并加上时间戳的哈希值。然后 Riva 将对消息进行哈希处理并比较哈希值。如果它们不同,那么消息可能已被更改。用于此目的的哈希函数必须使得 Emily 无法修改消息而不改变哈希值成为不可行。也就是说,Emily 无法找到一个产生相同哈希值的不同消息。同样,Sandra 无法更改消息并声称她发送了更改后的消息,因为哈希值将不再匹配。
对于这个哈希函数,我们将使用 4 个高度非线性的替换,分别为 A、B、C 和 D。这些可能是公开已知的固定替换。值得花一些精力使这四个替换高度非线性且彼此之间的相关性最小化。基本操作是使用异或的组合函数将消息的每个字节与前 4 个字节进行组合,即执行异或操作,然后对结果进行简单的替换。让 H 是消息 M 的一个副本,以便消息在哈希处理过程中不被破坏。副本中的每个字符 H[n]都经过以下哈希处理:

这样,哈希的每个字节都依赖于前面的每个字节,并且每个后续的字节都依赖于它。
哈希需要一个初始化向量(第 11.10 节)以便对消息的前 16 个字节进行哈希处理。可以使用消息的前 16 个字节的副本。也就是说,最初字节 H[-15]到 H[0]与字节 H[1]到 H[16]相同,这些字节是消息的字节 M[1]到 M[16]相同。有了初始化向量,就可以将哈希从 H[1]传播到 H[L],其中 L 是消息的长度。
这使得最后几个字节的哈希相对较弱。Emily 可能很容易改变消息的最后几个字节。解决方法是在消息结束后继续哈希处理。为此,当我们对消息的前 16 个字节进行哈希处理时,我们保存这些哈希值以供以后使用。当我们到达消息的末尾时,我们附加这 16 个字节并继续哈希直到扩展消息的末尾。这最后的 16 个字节成为消息的哈希值。将此哈希方法称为Hash128。
对于某些机器,使用机器的 32 位算术函数,每次对消息进行 4 字节的哈希可能更快。消息和哈希值被视为 L 个 32 位字的列表,而不是 4L 字节。哈希数组 H 最初是消息的一个副本。如果消息长度不是 4 字节的偶数倍,则会附加多达 3 个字节以填充最后一个字。H 的前两个字的副本被附加到前面,即 H[-1] = H[1] 和 H[0] = H[2]。在对消息的前 4 个字进行哈希后,这 4 个字将附加到消息的末尾。
这种哈希,称为 HashPQ,使用两个素数 P = 2³²-5 = 4294967291 和 Q = 2³²-17 = 4294967279,以及魔法乘数 R = 77788888,它是 P 和 Q 的一个原根。哈希操作为

如果总和超过 2³²-1,则通过简单地忽略额外的高位比特来将值截断为 32 位。也就是说,我们可以自由得到模 2³² 运算。H 数组的最后 4 个字是 16 字节哈希值。与 Hash128 相比,HashPQ 使用的存储空间更少,因为它不需要 4 个简单的替换。
Hash32、Hash128 和 HashPQ 都具有良好哈希函数所需的理想属性,即对输入的任何位或位的组合进行更改会导致输出中大约一半的位发生更改。这三种哈希都很快,并且可以在单个从左到右的传递中完成。
第十四章:一次性密码
本章涵盖
-
一次性密码密码
-
伪一次性密码,它近似于一次性密码
-
Diffie-Hellman 密钥交换
-
构建 Diffie-Hellman 和公钥密码所需的大素数
最著名的流密码是一次性密码。许多作家将这个术语限制为仅指明文和密钥流逐字节进行异或的密码。这在历史上是不准确的。第一个一次性密码密码是由加利福尼亚州萨克拉门托的银行家弗兰克·米勒于 1882 年发表的,目的是通过缩短电报消息来节省费用。米勒的电报代码使用 5 位数字代码组来表示商业电报中常见的单词和短语。为了保密,米勒提出了一个密码,其中包括将 3 位数字添加到每个 5 位数字组中。他的代码值足够小,以至于总和永远不会超过 99999。也就是说,代码都小于 99000。因此,一次性密码最初是一个十进制系统,而不是一个二进制系统。
赋予一次性密码其名称的系统是由德国 Pers Z S(信号情报机构)的密码学家沃纳·昆策在 1922 年左右设计的。昆策的系统基于标准的 5 位数字组外交代码。与米勒的密码类似,昆策的密码将密钥组添加到代码组中。昆策使用了 5 位数字密钥组,逐位地将其添加到代码组中,而不进行进位。因此,33333+56789 将导致 89012,而不是 90122。昆策将密钥分发在 50 张纸的本子中,每张纸包含 8 行,每行包含 6 个密钥组。这些本子的页面一次用于加密一条消息,然后被丢弃。因此得名一次性密码。后来的发展包括使用水溶墨水和水溶纸进行快速处理。
另一个版本的一次性密码是由英国作家和编剧(Peeping Tom)利奥(利奥波德·塞缪尔)·马克斯于约 1940 年发明的。它被英国间谍广泛使用。马克斯的版本使用字母而不是数字。发送者将密钥字母加到明文字母模 26,以获得密文字母。换句话说,马克斯的一次性密码是一个带有随机密钥的贝拉索密码。麻省理工学院教授克劳德·香农在 1940 年至 1945 年之间发明了相同的密码,苏联信息理论家弗拉基米尔·科特尔尼科夫在 1941 年或之前发明了一个版本,但其细节仍属机密。香农和科特尔尼科夫都提出了一次性密码无法被破解的数学证明。它仍然是唯一被证明无法破解的密码方法。
自从米勒的 1882 年一次性密码和昆策的 1922 年一次性密码都使用十进制加法作为它们的组合函数,以及马克斯的 1940 年一次性密码使用模 26 加法,任何人都很难断言��次性密码仅限于使用异或来组合密钥和明文。一次性密码的定义特征是
-
关键是至少与消息一样长,
-
密钥与真随机不可区分,
-
每个密钥字符或块与一个明文字符或相同大小的明文块组合,并且
-
密钥仅使用一次。
任何满足这 4 个标准的密码都是一次性密码。然而,要证明一次性密码是无法被破解的,需要另一个更强的条件:
-
任何给定的明文字符转换为任何给定的密文字符的概率相等。
说了这么多,让我们看看一个基于异或的历史密码,与一次性密码系统密切相关。
14.1 佛南密码
到 1918 年,许多外交任务已经不再由人类电报操作员发送和接收消息,然后需要手动输入。相反,消息被打孔到由法国电报工程师埃米尔·鲍多特于 1870 年发明的 5 列鲍多码或由新西兰记者唐纳德·默里于 1901 年发明的鲍多特-默里码的纸带卷中。(我不会详细介绍这些代码的细节,因为它们在 1870 年至 1950 年代之间几次改变,当西联电报公司在 1963 年停止使用它们时,鲍多特风格的代码完全被废弃了。)重要的特征是一个人类打字员将消息键入到一个 5 列纸带中,从而可以直接在接收端传输和打印而无需任何进一步的人类参与。
与摩尔斯密码一样,无论是鲍多码还是鲍多特-默里码都没有提供任何保密性。任何人都可以直接从磁带上读取消息。直到 1918 年,如果需要保密性,消息必须由人工密码员手动加密,然后被输入到磁带上,并由接收端的另一名职员手动解密。需要一种方法来加快这个过程。于是佛南出现了。
佛南密码由 AT&T 贝尔实验室的吉尔伯特·桑福德·佛南在 1918 年应陆军信号部的约瑟夫·O·莫伯格纳之邀开发。这个想法非常简单而巧妙。一个人类打字员会像以前一样将消息键入到磁带上,但实际传输的是字符代码与密钥代码的异或。密钥代码来自一个单独的纸带,其上打有看似随机的字符序列。在接收端,传输字符将与该磁带的副本进行异或运算,从而解密它们。每个磁带有 1000 个类似随机的字符,以便长消息每 1000 个字符重复一次密钥。
该图显示了两个包含明文和密钥的磁带,用于读取磁带的拾取器,用于将密钥与明文进行异或运算的电路,以及接收端的打孔机,该打孔机可能位于远程位置。打孔机可以根据设置替换为打印机或发送器。

这是我自己的图表,因为我找不到 Vernam 机器本身的图片,可能是因为它被列为机密。
我将密钥带称为“近似随机”,因为它们是由一个人在类似打字机的键盘上敲击而产生的,这是 Friden Flexowriter 的前身。结果是键盘中心附近的字符比角落附近的字符更经常使用。人类很难产生随机数或字符。但对于 1918 年来说,这是一个非常强大的密码。
许多来源错误地将 Vernam 密码称为一次性密码本,可能是因为它是第一个使用二进制消息与二进制密钥进行异或运算的密码。然而,Vernam 密码并不是一次性密码本,因为它是重复的。它有一个固定的 1000 个字符的周期。此外,一次性密码本早在 36 年前就由米勒发明了,并且最初是一个基于十进制的系统。
对于一个繁忙的大使馆,可能每天会有 100 个或更多的密码消息。如果大使馆与其他几个大使馆通信,就需要多套带子。用于华盛顿到柏林的带子将与用于柏林到华盛顿的交通的带子分开。所有带子都标有 6 位数的序列号。在发送每个消息之前,带子编号将以明文形式传输,即未加密。办事员们需要区分哪些带子是为哪个大使馆准备的,哪些带子已经使用过需要销毁。新的带子必须不断地提供给每个大使馆。
Vernam 很快设计了第二个版本,使用了两个带子,两个带子都与明文进行了异或运算。一个带子有 1000 个字符,另一个带子有 999 个字符,使有效周期为 999,000 个字符。同一两个带子可以在整个一天内使用,只需在每个带子上的不同位置开始每个消息即可。如果一个大使馆有,比如,100 个带子,那么可以在不同的日子使用不同的带子组合,只要纸带能支持。
很容易看出 Vernam 的 2 带机器如何扩展到 3 或 4 带。就我所知,这从未发生过,因为这些基于带子的机器很快就被转子机取代了(参见第 5.10 节)。
14.2 密钥供应
一次性密码本的主要问题是提供足够的密钥。纸带方法可能足够用于每天发送 100 条消息的 10 个站点,但对于每天发送 1000 条消息的 100 个站点来说是行不通的。
许多关于密码学的书籍和论文描述了以下难题:桑德拉和里瓦决定使用一次性密码交换消息。他们每个人都有一份长随机密钥的副本。他们逐段使用这个密钥,直到用完为止。现在他们需要另一个随机密钥。桑德拉可以选择并发送给里瓦,但需要加密以防艾米莉获取。最安全的方法是使用一次性密码对其进行加密,因此他们需要另一个与之长度相同的密钥来加密新密钥。同样,桑德拉可以选择并发送给里瓦,但该密钥也需要加密。因此,他们需要另一个密钥,无穷尽。
这个困境的解决方案是双管齐下的。首先,可以使用第 13.15 节的技术(如滞后加法)刷新随机密钥流。例如,每天一次,或者当各方决定时,可以从基础密钥派生一个新密钥。其次,这些派生的每日密钥不需要直接用作消息密钥。相反,可以从每日密钥构建消息密钥。这样,即使艾米莉恢复了任何消息密钥,她距离恢复基础密钥还有两层。接下来的几节将描述一些生成消息密钥的方法。
每种方法都旨在实现两个目标:要么(1a)该方法必须能够每天生成足够的消息密钥材料,以便没有两个消息密钥重叠,要么(1b)艾米莉不可能检测到消息密钥的重叠部分,以及(2)艾米莉不可能重建派生密钥或基础密钥的部分。
14.2.1 循环密钥
每日密钥是使用第 13.14 节的技术派生的。每日密钥的连续部分用于生成消息密钥,例如通过轻度加密。一个带有密钥的简单替换就足够了。我建议在连续密钥之间留下随机宽度的间隙,例如 1 到 32 字节。当到达每日密钥的末尾时,它会使用滞后线性加法(第 13.14.1 节)的单次传递来延长以供在消息量较大的日子使用。您可以通过想象每次发送消息时,其密钥加上任何间隙都会从每日密钥的前端移动到每日密钥的末尾,并使用滞后线性加法进行刷新来可视化这一点。桑德拉和里瓦必须同步进行此操作。
这在消息量较低且桑德拉和里瓦很少同时发送消息的情况下效果很好。对于更高的消息量,最好使用两个基础密钥和两个每日密钥,一个用于桑德拉到里瓦的消息,另一个用于里瓦到桑德拉的消息。
14.2.2 组合密钥
对于长度为L的每条消息,从每日密钥中取出长度为L的三个段。将这些段称为 x、y 和 z,并将它们在每日密钥中的起始位置称为 p[x]、p[y]和 p[z]。如果这些位置中的任何一个接近每日密钥的末尾,则该段可能回到开头。消息密钥的每个字节都是通过取 x、y 和 z 中相应字节的线性组合形成的。也就是说,

其中系数 a、b 和 c 可以是 1 到 255 之间的任何奇整数。三个系数 a、b 和 c 的值以及三个起始位置 p[x]、p[y]和 p[z]对于每条消息必须是不同的。这些可以事先商定,或者加密并与每条消息一起发送。
14.2.3 选择密钥
对于长度为 L 的每条消息,从每日密钥中随机选择两个不重叠的段。第一个段是选择器,s,长度为 L。第二个段是库存,x,长度为 256。为了加密消息中的第 n 个字符 m[n],我们首先从选择器中取出相应的字节 p = s[n]。这个 p 选择了库存中取出密钥字节的位置,即 k[n] = x[p]。密钥字节 k[n]与消息字节 m[n]结合使用任何组合函数,如异或或加法。
在使用密钥字节 k[n]后,x[p]在库存中被替换为(ax[p]+b) mod 256。系数 a 和 b 必须满足 Hull-Dobell 条件(第 13.4 节),即 a≡1(mod 4)且 b≡1(mod 2)。实际上,库存 x 中的 256 个位置中的每一个都成为一个独立的线性同余伪随机数生成器(PRNG)。系数 a 和 b 可以对库存中的所有 256 个位置使用相同的值,也可以不同。一种选择是使用两对不同的 a 和 b 值,并根据某种固定模式选择第一对或第二对。无论使用多少对值,对于不同的消息,它们应该是不同的。
另一种更新库存的方案是将 x[p]替换为(ax[p]+bx[p-1]) mod 256,其中 a 和 b 是 1 到 255 之间的任何奇整数。您还可以选择将 x[p]替换为(ax[p]+bx[p-i]) mod 256,其中 i 是从 2 到 255 的任意整数。
由于 a 和 b 只有 8192 个可能的值,并且由于应避免值 a = 1,因此重复是不可避免的。然而,只要 Emily 无法确定每条消息使用了哪对值,这就不是问题。重要的是 Emily 无法累积多条她知道具有相同 a 和 b 值的消息。使用指示器的一个缺点是对手可能收集几条具有相同指示器的消息,因此他们知道这些消息具有相同的密钥。
14.3 指示器
在古典密码学中,通常会长时间使用同一把密钥,有时甚至长达几个月或几年。而在现代,密钥通常只用于单个消息。使用一次性密码本时,消息密钥必须只能使用一次。否则,艾米丽可能会将一条消息滑动到另一条消息上,并使用重合指数(第 5.7 节)来检测重叠。
对于适度的双向消息流量,桑德拉和里瓦可以使用一本小书,列出按照例如时间和星期几来使用的密钥。在计算机出现之前的一种常见做法是给每条消息编号。消息编号可以被加密并与消息一起发送。桑德拉和里瓦将使用消息编号在书中查找密钥。
当消息流量增加或有许多交换消息的参与方时,密钥本就变得不可行。即使将书本替换为计算机文件,情况也是如此。解决这个问题的一个方法是使用指示器。指示器是随消息一起发送的信息片段,接收方可以用来确定密钥。
在早期,指示器只是密钥本身,隐藏在消息中。例如,消息的第三组是密钥,或者前 8 组的第一个字符组成了密钥。稍微复杂一点的版本可能是,第二组的中间数字告诉您哪一组是密钥。这些类型的指示器的明显问题是,一旦艾米丽学会了系统,她就可以阅读所有的消息。即使艾米丽不知道这个系统,她也可以简单地尝试消息中的所有组,看看其中是否有一个是密钥。如果她找到了一些这样的密钥,那么她可能就能推断出模式。
更安全的方法是加密密钥并将其用作指示器。这就是二战期间德国人使用 Enigma 机器所做的。他们有一个特殊的设置,每天更换一次,用于加密消息密钥。他们首先将 Enigma 设置为每日设置,并使用该设置加密消息密钥两次。然后他们将机器重置为消息密钥,个别操作员会随机选择,并加密消息。波兰的Bomba利用了消息密钥的双重加密来推断这些密钥。(bomba kryptologiczna是由波兰首席密码学家玛丽安·雷耶夫斯基于 1938 年设计的一种用于破解德国 Enigma 消息的电机械设备。)当德国人意识到这一点时,他们停止了这种做法,波兰人被封锁了;他们不再能读懂 Enigma 消息。艾伦·图灵预见了这个问题,并设计了他的Bombe来处理密码词,或者是可能的明文。法国的 Enigma 破译机也被称为 bombe,据说是以冻雪糕(一种类似于圆顶形的冰淇淋,像阿拉斯加烤冰淇淋)命名的。
第 14.2 节描述了从每日密钥生成消息密钥的几种方法。每种方法都使用一小组参数来生成每个消息密钥,例如滞后线性加法的系数,或者每日密钥中的位置。这些参数集合非常适合用作指示器。
14.4 Diffie-Hellman 密钥交换
关于传统方法就说这么多。让我们谈谈一个更现代的方法。Diffie-Hellman 密钥交换是由斯坦福大学教授马丁·赫尔曼和他的研究助理贝利·惠特菲尔德·迪菲于 1976 年发明的,后者后来成为 Sun Microsystems 的员工。公钥密码学的基本概念是由加州大学伯克利分校本科生拉尔夫·默克尔于 1974 年发明的。
Diffie-Hellman 密钥交换的关键特点是,即使 Emily 拦截了他们交换的所有消息,Sandra 和 Riva 也可以建立一个安全的加密密钥。为了设置交换,Sandra 和 Riva 必须就一个大素数 P 和该素数的一个原根 w 达成一致。或者,Sandra 可以简单地选择 P 和 w 并将它们发送给 Riva。P 和 w 可以明文发送。回想一下第 13.3 节,找到原根是很容易的。对于大多数素数,2、3、5 或 7 中至少有一个是原根。
Sandra 选择一个秘密指数 s,并计算 x = w^s mod P。她将数值 x 发送给 Riva,但保留 s 的数值。Riva 选择一个秘密指数 r,并计算 y = w^r mod P。她将数值 y 发送给 Sandra,但保留 r 的数值。现在 Sandra 可以计算 y^s mod P,即 w^(rs) mod P,而 Riva 可以计算 x^r mod P,即 w^(sr) mod P。由于 w^(rs) = w^(sr),Sandra 和 Riva 计算出相同的数值,他们可以将其用作加密密钥,或者将其分割成几个加密密钥。在第 13.3 节中描述了执行指数运算的有效方法。
一些作者(以及维基百科)将 Diffie-Hellman 密钥交换描述为一种公钥方法。他们谈论结合 Sandra 和 Riva 的公钥及其私钥。这是不正确的。Diffie-Hellman 中没有涉及公钥。即使将指数 r 和 s 视为密钥,它们也都是秘密密钥。
假设 Emily 拦截了 Sandra 和 Riva 之间的所有消息。那么 Emily 知道 P、w、x 和 y,即 w^s mod P 和 w^r mod P,但她不知道 s、r 或 w^(rs) mod P。确定 w^(rs) mod P 被称为Diffie-Hellman 问题。目前尚不清楚这是否与确定 r 和 s 相同,但它们被认为是同样困难的问题。在给定 P、w 和 x 或 y 的情况下确定 s 和 r 被称为离散对数问题。这被认为是一个非常困难的问题。当 P、r 和 s 足够大时,这个问题被认为是计算上不可行的。专家们对 P 必须有多大存在分歧,但常见的建议是 300 和 600 位十进制数字。一些实现允许 P 达到 1234 位十进制数字,即 4096 位。指数 r 和 s 可以小得多。专家建议范围从 40 位十进制数字到 150 位十进制数字。
一个名为Silver-Pohlig-Hellman算法,以 Roland Silver、Stephen Pohlig 和 Martin Hellman 命名,使得在 P-1 只有小因子时解决离散对数问题变得容易。该算法让你可以分别解决每个小因子。因此,Sandra 必须确保 P 是一个安全素数,即 P-1 至少有一个大因子,比如 q > 10³⁵。理想情况下,Sandra 应选择 P 为形式为 2Q+1 的素数,其中 Q 也是素数。对应的素数 Q 被称为 Sophie Germain 素数,以法国数论家玛丽-索菲·杰尔曼(Marie-Sophie Germain)命名,她还研究过声学和弹性学。如果 Q-1 和 Q+1 都有大素因子,那就更强大了。在下一节中,我们将明确构造 Q,使得 Q-1 有一个大素因子。很可能 Q+1 也有一个大素因子,仅仅是因为 Q 太大了。只有小因子的数字被称为光滑数。随着数字变大,它们变得非常罕见。
*14.4.1 构造大素数,旧版
构建大素数的传统方法通常可以在许多网站上找到,它首先通过随机选择所需大小的奇数 N,然后测试 N 是否为素数。首先尝试几百个小素数。如果 N 可被其中任何一个整除,则 N 不是素数。重新选择。这种初步测试非常值得,因为它非常快速。接下来,通过应用概率素性测试来测试 N 是否为素数。最常见的测试是由加里·米勒和迈克尔·O·拉宾发明的Miller-Rabin测试。让 N-1 = 2^hd,其中 d 是奇数。也就是说,2^h 是能够整除 N-1 的最大 2 的幂。第一步是在范围 2 到 N-2 中选择一个基数 b,并测试 b^d≡1(mod N)是否成立。如果成立,则 N 通过测试。如果不成立,则查看 b^(2d)≡-1(mod N)是否成立,或者 b^(4d)≡-1(mod N),依此类推。只要指数 2^gd 仍然小于 2^hd,就一直继续。如果找到这样一个值 g,则 N 通过了测试,b 被称为 N 的见证者。如果找不到这样的 g,则可以确定 N 不是素数,因此必须重新选择 N 的值。
如果 N 通过了测试,仍然有 1/4 的概率 N 是合数。如果你想将 N 不是素数的概率降低到 2¹²⁸的倒数 1,你将需要 64 次 Miller-Rabin 测试,每次都使用不同的底数 b。不幸的是,这仍然不能保证。Miller-Rabin 测试错误地将卡迈克尔数认定为素数。这些数字不是素数,但每个底数 b 都是证明数的见证者。这些数字是由伊利诺伊大学的罗伯特·卡迈克尔于 1910 年发现的。前几个卡迈克尔数是 561、1105、1729、2465、2821、6601、8911、10585、15841、29341 和 41041。卡迈克尔数倾向于有小的素数因子,因此通过 64 次 Miller-Rabin 测试,并且还发现 N 不可被前几百个素数中的任何一个整除,使得 N 是素数的可能性非常大。
这是一种寻找特定大小素数的好方法,但不能保证 N 是一个安全素数,并且比本节方法要慢得多。如果 S 是您需要的素数的大小,那么您需要找到一个素数的尝试次数大约是 ln(S)。因此,对于一个 500 位数的素数,您需要大约 ln(10⁵⁰⁰)或者大约 1151 次尝试,每次尝试需要 64 次 Miller-Rabin 测试和数百次试除。使用我在本节中提出的方法可以节省您几个小时甚至几个星期的计算机时间,这取决于您使用的计算机类型以及所需的素数的大小。
14.4.2 构建大素数,新的
你可以尝试找到一个大质数的一种方式是从任何大整数 N 开始,然后尝试 2N+1, 2N+3, 2N+5, ... 测试每个直到找到一个质数为止。对此的一种小改进是测试 6N+1, 6N+5, 6N+7, 6N+11, 6N+13, ... 。这样可以从测试中消除所有 2 和 3 的倍数。你也可以尝试 30N+1, 30N+7, 30N+11, 30N+13, ... 来消除 2、3 和 5 的倍数,类似的方法还有 2×3×5×7 = 210,以此类推。
测试一个给定的整数 N 是否为质数有多种方法。最简单的方法是试除法。要测试 N 是否为质数,尝试将 N 每个小于等于 √N 的质数整除。如果其中任何一个质数能整除 N,则 N 是合数,否则 N 是质数。试除法适用于约 N = 10¹²,可能是 10¹⁴,但对于更大的 N,试除法耗时太长。大多数其他的质数测试只是概率测试,告诉你这个数可能是质数。
有一种测试可以确定一个数字是质数:如果一个大于 1 的整数 N 有一个原根,那么它就是质数。回顾第 13.3 节,如果 r^(N-1) mod N = 1,并且 r^((N-1)/p) mod N ≠ 1 对于任何能整除 N-1 的质数 p 都成立,那么 r 是 N 的原根。要测试 N 是否为质数,你只需要对于 N-1 的每个不同的质因数 p,分别计算 r^x mod N,其中 x = N-1 和 x = (N-1)/p。让我们称这种方法为原根质数测试,或者简称为根测试。这种方法是由法国数学家爱德华·卢卡斯在 1876 年发明的,同样是那个创造了斐波那契数(第 3.4 节)这个术语的爱德华·卢卡斯。卢卡斯于 1891 年因一场悲剧性的汤事故去世。
只需尝试 2、3、5、7、11 和 13 作为可能的原根即可。如果 N 有原根,那么至少这 6 个值中的一个很可能是原根。如果这些值中没有一个是原根,请不要浪费时间尝试其他值。更高效的方法是转到下一个质数的候选项。
Lucas 的根测试的问题在于你需要分解 N-1,如果 N 有 300 个或更多的数字,那么分解 N-1 实际上是不可能的,至少在没有量子计算机的情况下是不可能的。这就是为什么你在许多讨论质数测试的书籍或网站中不会看到这个测试被提及的原因。
有一种方法可以避开这个障碍。记住,你的目标不是找到一般的质数测试方法。你的目标是获得一个大质数来用作 Diffie-Hellman 密钥交换的模数。所以,与其找到那个质数,你可以构造出这个质数。
关键是选择具有已知因子的 N-1。例如,你可以选择 N-1 具有 2^n 的形式,因此 N 将具有 2^n+1 的形式。N-1 的唯一质因数将是 2。要找到形式为 2^n+1 的素数,你只需要找到一个数字 b,使得 b^(N-1) mod N = 1,且 b^((N-1)/2) mod N ≠ 1。我建议你尝试 b = 2、3、5、7、11 和 13。如果这些都不是原根,那么跳过 N = 2^n+1,看看 N = 2^(n+1)+1 是否为素数。这个搜索将获得你素数 3、5、17、257 和 65537。尽管人们花费了数千小时的计算机时间搜索,但目前尚不清楚是否还有其他素数。这 5 个素数被称为费马素数,以法国数学家皮埃尔·德·费马特命名,因为他著名的边注是关于方程 an+bn = c^n。
概述
在我详细介绍之前,让我概述一下构造一个大素数 P 的一般方法。该方法必须完成三件事:
-
P-1 必须具有一个大的素数因子,以便 P 是安全的,
-
每个候选的 P 应该具有较高的素数概率,以便你需要尽可能少的质数测试,
-
P-1 应该具有较少的不同质因数,以便每个质数测试尽可能快速。
对于寻找大素数的任何搜索都将涉及测试数百甚至数千个候选者。让我们称预期测试次数为 E。这里的方法是使 P-1 的每个候选者成为两个数的乘积 cK。系数 c 将通过一系列相对较小的数字进行步进,通常与 E 相当。核 K 将是一个大素数、两个大素数的乘积或者最多 2 个质数的乘积的幂,paqb,其中至少有一个是大素数。让我们先看看如何选择系数,然后再看如何选择核心。
系数
最简单的选择系数的方法是逐个遍历质数。由于系数必须是偶数,你需要使用每个质数的两倍,2×2、2×3、2×5、2×7,等等。让我们称这个方法为PickPrimes。PickPrimes 最小化了 cK 中不同质因数的数量。c 中最多有 2 个不同的质因数,在 K 中也最多有 2 个不同的质因数。然而,PickPrimes 对减少所需的测试次数几乎没有什么帮助。
第二种选择系数的方法是使它们具有 paqb 或 paqbr^c 的形式,或类似的形式。这里的 p、q 和 r 是小的质数,如 2、3 和 5,或者 2、5 和 7。(在本节的后面我们将看到必须省略 3 的情况。)这样,P 就永远不可能是 2、3 或 5 的倍数,这显著增加了 P 是素数的机会。如果你使用这种方法,你可能想要预先计算并排序系数的列表。
核心
内核 K 必须至少有一个大素数因子 R。我建议 R 至少为 2¹²⁸,约为 3.4×10³⁸。如果你的对手拥有量子计算机,请将 R 至少设为 2²⁵⁶ = 1.16×10⁷⁷。那么,你从哪里获得这些素数呢?如果你愿意接受 30 位数的素数,你可以从 bigprimes.org 网站在线获取一些。
如果你期望生成许多大素数,或者非常大的素数,你可以自己生成。提前准备,建立一个各种大小素数的表。将此表命名为 PrimeTab。一定要保存 PrimeTab,这样每当你需要更多素数时,就不必重复此过程。你可以从小于 100 的 25 个素数开始你的素数表。你可能能够背诵这些,所以只需将它们输入程序中。接下来,如果你愿意,你可以使用试除法生成一些 3 到 12 位数的素数,比如每个尺寸 2 或 3 个素数。我建议你随机进行,这样每次使用此方法时都不会构造相同的素数(以及每个使用此方法的读者都不会生成相同的素数)。在这个阶段,PrimeTab 可能有大约 50 个素数。
构建 R(小步骤方法)
现在让我们开始尝试构造 R,即 Q-1 的大素数因子。你可以通过找到每个比上一个素数稍大一点的素数来逐步构建 R,也可以一次跳跃到那里。如果你期望生成许多大素数,请分步构建,以便 PrimeTab 后面可以有很多条目供以后使用。为了说明这两种技术,让我们以小步骤构造 R,并以一次巨大的飞跃构造 Q。
假设 PrimeTab 包含 k 个素数,p[1] < p[2] < p[3] < ... < p[k]。要构造下一个素数,首先从表中选择任意两个素数,比如 p[i]和 p[j]。让 r 为乘积 p[i]p[j]。如果 r < p[k],你可能希望选择更大的 i 或 j,以免生成太多小素数。当然,你需要一些小素数,所以我建议当 p[i]p[j] < p[k]^(2/3)时选择更大的 i 或 j。首先,使用 Lucas 测试来确定 R = 2r+1 是否为素数。这很容易,因为你知道 R-1 的唯一素因子是 2、p[i]和 p[j]。如果 2r+1 不是素数,请尝试 4r+1、6r+1、10r+1 等,使用 PickPrimes 方法选择系数。当数字开始超过 20 位数时,找到一个素数可能需要每个素数 50 次或更多的尝试。
减少测试次数
当数字变得非常大时,你可以通过检查每个候选数 nr+1 是否可被许多小素数整除来节省时间,然后再寻找一个原根。例如,你可以验证 nr+1 是否不能被前 100 个素数中的任何一个整除。你可以通过提前计算 x[i] = r mod p[i]来使这个测试更快,其中 i 是前 100 个素数。然后,不是计算(nr+1) mod p[i],其中 r 可能有几百位数,而是计算(nx[i]+1) mod p[i],其中 x[i]只有 1 到 3 位数。也就是说,你只需进行一次试除(r mod p[i]),而不是对每个 n 值都进行一次。我们称这种方法为PrimeCheck。
PrimeCheck之所以有效是因为候选素数是按顺序选择的。你无法用传统方法找到大素数,因为候选素数是随机选择的。这使得对小素数的试除对这种方法更快,而且由于速度更快,你可以使用更多的小素数,比如 300 个而不是 100 个,从而减少所需的试验次数。
如前所述,如果 2、3、5、7、11 或 13 中没有一个是 nr+1 的原根,则跳过该候选数,并尝试下一个 n 值,直到找到下一个素数。由于这种方法每个候选数只使用 6 次测试,而传统方法使用 64 次测试,因此这种方法的速度是传统方法的 10 倍以上。将找到的每个素数添加到PrimeTab中。
构建 P 和 Q(巨大飞跃方法)
假设你的目标是找到一个 300 位的Sophie Germain素数。继续扩展PrimeTab,直到它至少有一个大素数,比如 R > 2¹²⁸。现在你已经准备好使用巨大的飞跃来生成你的 300 位素数。首先选择一个所需大小的目标 T,比如 T = 10³⁰⁰。可以使 P 任意接近目标值,但这对 Diffie-Hellman 密钥交换并不需要。T 只是一个所需的最小尺寸。
下一步是找到 Q。记住 Q 必须满足三个要求:Q 必须是素数,Q-1 必须是大素数 R 的倍数,且 P = 2Q+1 也必须是素数。找到 Q 的策略是从一些所有质因数都已知的种子数 t 开始,然后使用PickPrimes尝试 2t+1、4t+1、6t+1、10t+1 等。
警告:如果你让 t 成为 3 的倍数,那么 Q 将具有 3x+1 的形式。这意味着 P = 2Q+1 = 6x+3 将是 3 的倍数。让 t 成为 3 的倍数意味着 P 永远不可能是素数。
由于 T 是 P 的最小值,而 Q 约为 P/2,因此 t 应约为 T/2。要构造 t,从 PrimeTab 中最大的素数 R 开始。取小于 T/2 的最大 R 的幂,称为 R^r。例如,如果 T 为 10³⁰⁰,而 R 约为 10⁴⁰,那么 T/2 约为 5×10²⁹⁹,所以 r 为 7。这意味着 R^r 约为 10²⁸⁰。直接从 10⁴⁰跳到 10²⁸⁰是巨大的飞跃。这个 R^r 远远低于 5×10²⁹⁹,所以设定 t = R⁷S,其中 S 约为 5×10¹⁹。当 S < 10¹²时,您可以使用试除法找到大于 S 的下一个素数。如果这是 S',那么 t 就是 R⁷S'。当 S > 10¹²时,您可以将 S'设置为 PrimeTab 中的一个素数和您必须选择的小于 10¹²的素数的乘积,或者您可以将 S'设置为素数的平方或立方。假设后者。在这个例子中,S 约为 5×10¹⁹。它的平方根约为 7,071,067,812。下一个更高的素数是 U = 7,071,067,851。因此,t 将是 R⁷U²。
现在你已经构建了 t,并且知道了它的所有素数因子,你可以开始搜索 Q,通过使用根测试测试 2t+1、4t+1、6t+1、10t+1 等。随机选择的数字 N 成为素数的概率约为 1/ln(N)。当 N 的数量级为 10³⁰⁰时,ln(N)约为 690。这意味着大约需要 690 次尝试才能找到 nt+1 形式的素数。P 也必须是素数,这也有约为 1/690 的概率。这意味着大约需要 690² = 476100 次尝试才能找到 Q = nt+1 和 P = 2Q+1,它们都是素数。这是很多次测试。
这些测试非常耗时,因此任何减少测试次数的技术都是宝贵的。在这种情况下,我们可以使用 PrimeCheck 的自然扩展。对于每个素数 p[i],像之前一样计算 x[i] = t mod p[i]。对于每个 n 值,检查 nx[i]+1 是否能被 p[i]整除,以验证 Q 不是 p[i]的倍数,并且还要检查 2(nx[i]+1)+1,即 2nx[i]+3 是否能被 p[i]整除,以验证 P 不是 p[i]的倍数。这样你就可以从 x[i]列表中获得双倍价值。
秘密素数
对于一些密码,您可能需要使用一个只有您自己和您的合法通信者知道的秘密素数。您仍然可以使用本节的方法构造您的素数,但是,您需要确保任何对手都无法按照相同的步骤发现您的素数。我建议两项预防措施。(1)当您初始化 PrimeTab 时,不要选择 3 到 12 位数字大小的 2 或 3 个素数,而是随机选择 3 到 14 位数字大小的 5 到 10 个素数。目标是在 PrimeTab 中至少有 100 个初始素数。(2)使用构造 P、Q 和 R 的小步方法,最好在初始素数之外使用至少 100 个额外步骤。
精确大小
构建质数的巨大飞跃方法可以轻松修改为找到精确大小的质数。这是一个例子。假设您需要在 10³⁰⁰ 和 1.1×10³⁰⁰ 之间的质数。选择比 10³⁰⁰/2000000 稍大的 r,即 5×10²⁹⁴。使用 PickPrimes,但从 1000000 开始您的质数,即 1000003、1000033、1000037、1000039,依此类推。使用 PrimeCheck 来减少测试次数。
在 1,000,000 和 1,100,000 之间大约有 6700 个质数,在 10³⁰⁰ 和 1.1×10³⁰⁰ 之间的每 690 个数字中,大约有 1 个是质数,因此几乎可以肯定您会找到所需大小的质数。概率可以很容易地计算出来。在所需范围内的任何给定数字不是质数的几率是 689/690。所有 6700 个选择的数字都不是质数的几率是 (689/690)⁶⁷⁰⁰,或者是 0.00006。因此成功的机会是 99.994%。
第十五章:矩阵方法
本章涵盖
-
使用整数矩阵乘法或环元素矩阵的加密
-
使用大整数和小整数的加密
-
解线性同余方程
-
构造环和可逆矩阵
矩阵是一种非常适合用于密码学的工具,因为它们可以在一次操作中对任意大的文本块进行加密。通常,消息中的每个块都被视为字节向量,意味着模 256 的整数。

当桑德拉使用矩阵来加密消息时,瑞娃必须使用该矩阵的逆矩阵来解密消息。让我们从讨论矩阵方法的技术开始,这是一种求逆矩阵的技巧。
15.1 求逆矩阵
有几种解决矩阵方程(比如 C = AP)的方法,例如已知明文的情况下。由于艾米丽知道 P 和 C,但不知道 A,她可以通过右乘 P' 来解方程得到 CP' = APP' = A。因此,艾米丽需要求 P 的逆。瑞娃则相反。她知道 A,但不知道 P,因此她需要求 A 的逆。将方程左乘以 A',她得到 A'C = A'AP = P。
这里展示的方法有一个优点,即直接获得逆矩阵,而无需倒推的中间步骤,这是其他方法所必需的。该方法是将给定的矩阵与单位矩阵放在一个 n×2n 的双宽矩阵中。左侧通过初等行变换仅减少到单位矩阵。这些行操作应用于双矩阵的每一行,因此随着左半部分从原始矩阵变为单位矩阵,右半部分从单位矩阵变为原始矩阵的逆。
初等行变换包括(1)将一行乘以可逆常数,(2)交换两行,和(3)从另一行减去一个行的倍数。
该算法逐个将原始矩阵的元素转换为单位矩阵的元素,从左上角开始,然后向下处理左列。然后它对第二列执行相同的操作,依此类推。如果算法在任何时候被卡住,意味着活动列中的所有元素都是 2 的倍数,或者它们都是 13 的倍数,则该矩阵是不可逆的。如果这种情况发生在桑德拉身上,她需要尝试不同的矩阵 A。通常,只需在底部行的某个元素上加 1 即可。如果这种情况发生在艾米丽身上,她将需要更多的已知明文字符。这将给她一个(n+1)×n 矩阵。当她应用这个算法时,逆矩阵位于双宽矩阵的右上 n×n 部分。
这是一个 3×3 的例子。此矩阵适用于 26 个字母的英文字母表,因此矩阵元素是模 26 的整数。没有涉及到分数和负数。由于这是模 26 进行的,每个不是 2 的倍数且不是 13 的倍数的元素都有一个乘法逆元。这使得我们可以将每行的第一个非零元素变成 1,这样可以轻松地决定从任何其他行中减去哪个行的倍数。原始矩阵是

通过在右侧附加一个 3×3 的单位矩阵来将其扩展为双宽格式。

你立即陷入了困境,因为任何行的第一个元素都不是可逆的。我是故意这样做的,以展示一个非常有用的技巧。第一行的第一个元素是 13 的倍数,但不是 2 的倍数。第二行的第一个元素是 2 的倍数,但不是 13 的倍数。如果你简单地将第二行加到第一行,那么第一个元素就变成了 19,既不是 2 的倍数也不是 13 的倍数,因此它是可逆的。问题解决了。

19 的乘法逆元是 11 模 26,因为 19×11 = 209≡1 (mod 26)。你把第一行乘以 11,将矩阵的第一个元素变成 1。

现在,你可以通过从第二行减去顶部行的 6 倍,并从第三行减去顶部行的 10 倍来完成第一列。这将把第二行和第三行的第一个元素设为零。

是时候处理第二行了。第二行上第一个非零元素是 9。9 的乘法逆元是 3,因为 9×3 = 27≡1 (mod 26)。你把第二行乘以 3,将行的第一个元素变成 1。

这让你通过从第一行减去第二行,并从第三行减去 25 倍的第二行来完成第二列。注意,双宽矩阵的左侧逐渐变成单位矩阵。

差不多了。第三行上第一个非零元素是 21。21 的乘法逆元是 5,所以你把矩阵的底行乘以 5。

现在,你可以通过从第三行减去第一行的 9 倍,从第二行减去第一行的 19 倍,完成第三列。

完成了。双宽矩阵的左半部分现在保存着单位矩阵,右半部分是原始矩阵的逆矩阵。你可以通过将原始矩阵乘以逆矩阵来检查这一点。结果应该是单位矩阵——而确实如此。

15.2 转置矩阵
让我们从一个非常简单的矩阵方法开始,即转置矩阵,它在数学上等价于置换矩阵。这是一个方阵,每行和每列都恰好有一个 1。所有其他矩阵元素都是 0。如果你想要转置一个由 10 个字母组成的块,你可以将该块视为一个大小为 1×10 的行矩阵,并将其乘以一个大小为 10×10 的转置矩阵。结果将是一个 1×10 的矩阵,字母被转置了。
要将一个字母从块中的第 2 位置移到第 5 位置,你需要将第 2 行第 5 列的元素设置为 1。下面是一个 4×4 的转置矩阵的示例,它将消息块 ABCD 更改为 BADC。

单独使用转置矩阵并不特别实用,但是如果你有一个矩阵 M 对一个块进行替换,并且一个转置矩阵 T,你可以通过使用矩阵 MT 替换 M 来将它们合并为单个步骤。这样,你就可以在单个操作中获得替换和转置。
15.3 希尔密码
基于矩阵的最早的密码是希尔密码,由亨特学院的莱斯特·希尔于 1929 年发明,并发表在美国数学月刊上。类似的密码在 1924 年由当时还是十几岁的杰克·莱文发明,在 1926 年发表在弗林周刊上,一本通俗侦探杂志。弗林周刊的密码专栏由 M·E·奥哈弗负责,他发明了分数化的摩尔斯密码(第 4.4 节)。巧合的是,弗林周刊是肯德尔·福斯特·克劳森(也在第 4.4 节提到)发表许多故事的地方。莱文一生致力于推翻希尔的密码并推广自己的密码。
希尔密码操作的是 26 个字母的字母表,字母按某种乱序编号为 0 到 25。也就是说,在矩阵运算之前进行简单的替换。你将明文字母分成 3 个一组。这形成了一个列向量,即一个 3×1 矩阵,P。你将这个列向量在左边乘以一个 3×3 矩阵 A,然后加上一个列向量 B,得到密文向量 C。在矩阵表示中,这被写成 C = AP + B,使用模 26 的加法和乘法。最后,你将数字转换回字母,使用相同的字母到数字的对应关系。
不幸的是,许多作者将 Hill 密码 限制为该密码的一个弱化、削弱的版本。为了避免歧义,让我们对 Hill 密码的几个版本进行编号。Hill-0 是最弱的版本。您使用标准英语字母表,没有混合,并省略 B 向量,以便 C = AP。Hill-1 稍微强大一些。您仍然使用未混合的字母表,但 B 向量不为零。Hill-2 是 Hill 最初提出的版本。您使用混合字母表和非零的 B 向量。Hill3 是一个更强大的版本,您在其中使用一个混合字母表将字母转换为数字,但您使用另一个混合字母表将数字转换回字母。这类似于第 9.6.1 节中的共轭矩阵双重密码。
Hill 密码,即 Hill-2,如最初发布的那样,基本上是一种秘密方法密码。字母转换为数字以及矩阵 A 和 B 都是固定的。没有密钥。任何知道这种方法的人都可以像预期的接收者一样轻松阅读消息。大多数最近的书籍和网站讨论 Hill 密码时忽略了混合字母表,并集中于矩阵运算。如果使用了固定的字母到数字的转换,这是合法的,因为可以去掉已知的字母表混合。
让我们首先看一下 Hill-0 情况,其中 A 是一个未知的 n×n 矩阵,向量 B 是 0,所以 C = AP。这就是普通的矩阵乘法,我们在第 11.3 节中见过。Riva 可以通过将密文乘以矩阵 A 的逆矩阵 A' 来解密消息。逆矩阵具有这样的性质,即 A'A = AA' = I,其中 I 是单位矩阵。在矩阵 I 中,每个对角元素为 1,每个其他元素为 0。单位矩阵类似于普通乘法中的数字 1,即对于每个数字 N,1×N = N×1 = N。对于矩阵,这意味着 IA = AI = A 对于每个方阵 A。如果 Emily 能确定 A',她也可以解密消息。
这个 B = 0 版本的 Hill 密码容易受到已知明文攻击的影响。如果 Emily 有 n² 个已知明文字符,她可以将它们组成一个 n×n 矩阵。将此矩阵称为 P,并将相应的密文矩阵称为 C。那么 C = AP,其中 C、A 和 P 都是模 26 的 n×n 整数矩阵。有几种方法可以解决这个矩阵方程。一种方法如 15.1.1 节所示。
如果加法向量 B 不全为零,则艾米莉只需要更多已知明文的字符,她就可以从方程中消除 B。额外的已知明文字符可以形成一个列向量 P[2],相应的密文字符可以形成一个列向量 C[2]。这些向量可以像这样从方程中减去:(C-C[2]) = A(P-P[2])。这与 C = AP 具有相同的形式,并且通过相同的方式解决,即通过求逆矩阵 P-P[2]。通过从 n×1 列向量中减去 n×n 矩阵,可以将 n×1 列向量从矩阵中减去,方法是从向量的第一个元素中减去矩阵顶行的每个元素,从向量的第二个元素中减去矩阵第二行的每个元素,依此类推。

假设你没有已知的明文。仍然可以解决 Hill-0 变体。继续假设一个秘密的 3×3 乘法矩阵,C = AP。乘以 A',A 的逆矩阵,得到 P = A'C。在消息的每个块中,块的第一个明文字符仅取决于 A 的顶行。这只有 26³ = 17,576 种可能性,所以很容易尝试它们。每个顶行的组合将确定明文中位置 1、4、7 等位置的字母。对于每个这样的组合,统计字母频率。
你可以使用第 5.9.1 节中描述的高峰方法将这些字母频率与标准英语字母频率进行比较。选择那些匹配度最高的组合,比如前 1%,或者前 175 个组合。对于每个块的第二和第三个明文字母,使用逆矩阵 A'的第二和第三行。这为每个 3 行提供了 175 个可能的组合。现在你可以尝试这些组合的组合,以获得整个消息的可能重构。只需尝试 175³ = 5.36×10⁶种组合。第 1 行的组合给出每个块的第一个字母,第 2 行的组合给出每个块的第二个字母,第 3 行的组合给出每个块的第三个字母,因此你拥有每个字母。
现在你可以使用三字母组频率确定最有可能的明文。使用所有的三字母组,不仅仅是 3 个字母的块,还有跨块的三字母组。这与我们在第 5.10 节和第 8.2 节中使用的过程相同,所以我不会在这里重复所有细节。如果这无法产生令人满意的结果,请回到起点,并为每个字母选择前 2%或前 350 个组合。
Hill 密码 Hill-1 使用一个秘密的 3×3 乘法矩阵和一个秘密的 3×1 加法矩阵,但使用未混合的字母表,被评为三级。在矩阵操作之前和之后都进行密钥混合替换后,被评为五级。它可以被解密为一般的三字母替换密码。对于更大的矩阵,评级会增加。为了达到十级评级,矩阵必须至少为 8×8,并且 Hill-3 矩阵操作必须应用两次。以下是步骤。(1)使用一个键入的非线性替换将消息转换为数字形式。(2)将每个块乘以矩阵并添加列向量。(3)对数字进行第二次非线性替换。(4)将每个块乘以第二个矩阵并添加第二个列向量。(5)使用第三个键入的非线性替换将结果转换回字母。两个乘法矩阵可以固定,但用于混合字母表的 3 个密钥和 2 个加法列向量应该在每条消息中更改。将此密码称为DoubleHill。
15.4 Hill 密码,计算机版本
Hill 密码对密码员来说太复杂,无法手工完成。Hill 还创建了一个机械设备用于进行加密和解密。这是为了满足当时的专利法,允许对机器进行专利保护,但不允许对数学算法进行专利保护。然而,这种密码在实践中几乎没有被使用。
如今,在计算机时代,Hill 密码再次变得实用。对于计算机来说,矩阵乘法是小菜一碟。使用 10×10 矩阵比 3×3 矩阵更容易。对于已知明文攻击,艾米莉需要 100 个字符而不是 9 个字符。这几乎是不可能的,除非通过间谍活动或在战场上截获消息。使用标准字母表的秘密 10×10 矩阵的 Hill 密码评级为六级。使用秘密 10×10 矩阵的 Hill 密码,在矩阵乘法之前和之后进行密钥混合替换,被评为八级。
通过使用多个矩阵并选择每个块的矩阵,可以进一步加强 Hill 密码,可以周期性或随机选择矩阵。矩阵和明文块的大小可能不同。由于矩阵乘法不是可交换的,当你在左边或右边乘以一个矩阵时,你几乎总是得到不同的结果。当你在左边乘以一个矩阵时,每个明文块必须被视为一个列向量,但当你在右边乘以一个矩阵时,它必须被视为一个行向量。这表明通过交替使用不同的方向,可以获得更安全的密码,可以周期性或随机地交替。可变矩阵,可变块大小和可变方向。你可以自行选择或混合使用。
你也可以将置换与希尔密码结合起来,但并不是每种置换都能提高安全性。假设你正在使用希尔-0 或希尔-1 变种,并且在矩阵乘法之后转置每个区块中的字母。这与使用具有不同矩阵乘数的希尔密码是一样的。让 T 代表转置。在对 Hill-1 进行加密后应用 T 会得到 C = T(AP+B) = (TA)P+(TB)。你所做的一切就是使用 TA 代替 A,TB 代替 B。Emily 可以使用已知明文来解密密码,并且她永远不会知道有置换存在。如果你想在希尔-0 或希尔-1 中使用置换,你必须在不同的区块之间交换字母,或者在不同的区块中交换不同的字母。
令人惊讶的是,当你使用希尔-2 或希尔-3 时情况完全相同。这是因为简单的替换和置换是可交换的。如果 S 是任何简单的替换,T 是任何置换,M 是任何消息,那么 S(T(M)) = T(S(M)),因此 ST = TS。因此,无论你使用哪种希尔密码变种,如果你要添加一个置换步骤,你必须在不同的区块之间交换字母,或者在不同的区块中交换不同的字母,要么周期性地要么伪随机地。
另一个想法是在两侧都用矩阵乘以消息。正如前面提到的,当你将文本块左乘以矩阵时,它必须被视为列向量,但当你将其右乘以矩阵时,它必须被视为行向量。假设你正在使用 3×3 矩阵,加法矩阵 B = 0。通过单侧矩阵乘法,每个密文字符的表达式都有 3 项,每项都涉及一个明文字母和一个矩阵元素。通过双侧矩阵乘法,每个密文字符的表达式有 9 项,每项都涉及一个明文字母和 2 个矩阵元素的乘积。因此,明文字母的系数是二次的。在 81 个可能的二次系数中,有 27 个出现在这些表达式中。
对于希尔-0 和希尔-1 情况,Emily 仍然可以使用已知明文来解决这些方程。有一种简单的方法和一种困难的方法。困难的方法是使用 18 个已知明文字符来解决两个 3×3 矩阵中 18 个未知元素的 18 个二次方程。祝你好运!
用简单的方法,将 27 个二次系数视为单独的变量。这将把方程从 18 个变量的二次方程转变为 27 个变量的线性方程。忽略 27 个变量是如何从 18 个矩阵元素中形成的,只需将它们视为不可分割的单元。由于现在有 27 个未知数,艾米莉需要 27 个已知字母而不是 18 个。虽然不太可能,但有可能,尤其是如果她拦截了多条使用相同密钥的消息。例如,假设艾米莉知道每条从瑞典发出的消息都以单词 STOCKHOLM 结尾。由于 STOCKHOLM 的出现可能在 3 个字母块中的不同位置开始,3 条不同的消息可以给她 27 个已知字母的位置。她可以轻松解决这 27 个线性方程以获得 27 个系数。
从那里,解决 27 个一次项二次方程以找到 18 个矩阵元素很容易——但为什么要麻烦呢?明文字母和密文字母之间的关系都是以 27 个二次系数为基础的。对于艾米莉来说,知道这些系数是如何产生的并没有好处。
Hill-1 的情况与 Hill-0 基本相同。有 36 个未知数,所以艾米莉需要 36 个已知明文字符。否则,解决过程是相同的。Hill-2 和 Hill-3 没有可比的过程。最好将它们解决为三字母替换密码。
通过在每一侧使用不同大小的矩阵,并在每一侧以不同方式对齐矩阵,可以从双面矩阵乘法中获得更大的强度。以下是这些技术的两个示例。在第一个示例中,左侧乘法是由 3×3 矩阵进行的,而右侧乘法是由 4×4 矩阵进行的。由于 3×3 矩阵与 4×4 矩阵对头,如图所示,让我们称之为Butthead 配置。

这给出了一个有效的块大小为 12 个字符。由于每个右侧的 4×4 矩阵跨越两个左侧的 3×3 矩阵,每个密文字符依赖于 6 个明文字符,而不是 4 个。在这种配置下,生成每个密文字符只需 7 次乘法,因此这种方法非常快速。当混合字母表是秘密的,但矩阵是已知的时,Butthead 密码被评为六。如果混合字母表和矩阵都是秘密的,则被评为八。如果矩阵是 6×6 和 7×7 或更大,则评级提高到十。当然,桑德拉使用的矩阵大小应该是互质的。
砖墙是另一种推荐的双面矩阵乘法配置。在这里,所有矩阵都是相同大小,但它们的偏移量为宽度的一半,就像墙上的砖块一样。这张图解说明了这种方法。

注意到矩阵的边界从未对齐。这种配置没有块结构,或者等效地说,整个消息是一个单一的块。由于每个 4×4 右侧矩阵跨越两个左侧 4×4 矩阵,每个密文字母取决于 8 个明文字母。这对于高安全性工作是足够的。
如果您实际上使用 2×2 矩阵来处理第一个和最后一个块,那将使这些块变得薄弱和容易受攻击。这还要求您使用 1×1 和 3×3 矩阵来处理不均匀的消息长度。最好始终使用 4×4 矩阵。接下来的两个图示展示了如何对长度为 13 的消息执行此操作。第一个图示显示了左侧矩阵的放置,最后一个 4×4 矩阵与消息的右端齐平。

下一个图示显示了右侧矩阵的放置,偏移了 2 个字符。第一个和最后一个 4×4 右侧矩阵与消息的末端齐平。

将最后一个矩阵定位在最后一个左侧矩阵和最后一个右侧矩阵对齐。可以通过将其环绕到消息的开头来避免这种情况,就像这样。

当您在左侧矩阵乘法之前使用了混合密钥简单替换,并在右侧矩阵乘法之后使用了另一个,同时使用了大小为 6×6 或更大的秘密矩阵时,砖墙密码评级为十。
由于反转矩阵需要一些努力,因此最好使用固定矩阵进行左侧和右侧乘法。使用固定矩阵会削弱密码,但您可以通过在两个矩阵乘法步骤之间添加第三个简单替换来进行补偿。矩阵可以是任何偶数大小,如 6×6 或更大。与希尔密码相比,让我们称之为珠穆朗玛峰密码。珠穆朗玛峰密码评级为十。
15.5 大整数乘法
大整数乘法在一个重要方面类似于矩阵乘法:在矩阵乘法中,产品的每个元素是两个矩阵中的一个元素的乘积之和。在大整数乘法中,产品的每个数字是两个大整数中的一个数字的乘积之和。无论如何,这是我将这个主题放在矩阵章节中的理由。
一个 128 位块可以看作是 16 个字节,或者是 128 位整数的 16 个基于 256 的数字。如果您将两个这样的基于 256 的整数相乘,那就涉及 256 个乘积和 256 个加法(包括进位)。如果您使用的语言允许您将两个 32 位无符号整数相乘以获得 64 位无符号乘积,那么您只需要 16 次乘法和 16 次加法。如果语言允许 64 位整数与 128 位乘积相乘,那就更简单了。
有更快的方法可以乘以非常大的数字,比如 Karatsuba 和 Toom-Cook,但是对于乘以 128 位数字,甚至 256 位数字,这些方法的好处太小,不值得为了当前目的而使用,所以我不会介绍大整数乘法的机制。一些计算机语言会自动处理这些机制,因此用户永远不需要介入。
话虽如此,考虑一个密码,Mult128,其中消息以 128 位块为单位,每个块都乘以一个秘密的 128 位整数 M,对 2¹²⁸取模。换句话说,只使用 256 位乘积的低阶半部分,高阶半部分被丢弃。这意味着乘法中的一些中间产品不需要计算,因为它们只对乘积的高阶端有贡献。
利瓦可以通过将密文乘以 M 对 2¹²⁸取模的乘法逆元 M'来读取消息。当 M 为奇数时,这个逆元存在。让我们看看如何找到乘法逆元。
15.5.1 乘法和除法同余
我在本书的早期承诺过,我会根据需要逐步呈现所有必要的数学内容。这是其中之一。计算乘法逆元的方法涉及乘以线性同余式。在我展示如何做到这一点之前,让我们看一个示例来了解为什么这是一个问题。(我在第 3.6 节中使用了这个示例的部分内容。您可能希望在继续之前重新阅读该节。)
并不是所有的同余式都具有相同的强度。一些同余式很强,有唯一的解。一些同余式很弱,有许多解。同余式越强,提供的信息越多。考虑这些同余式,从最强到最弱排列:

这种不均衡的原因是,在除了这些同余式中的第一个以外的所有同余式中,ax≡b (mod n),参数 a、b 和 n 有一个公因数。在 10x≡8 (mod 12)中,参数 10、8 和 12 有公因数 2,同余式有 2 个解。在 9x≡3 (mod 12)中,参数 9、3 和 12 有公因数 3,同余式有 3 个解。等等。公因数越大,解越多,同余式越弱。
当 a、b 和 n 有一个公因数 d 时,你可以将同余式除以 d。例如,9x≡3 (mod 12)有一个公因数 3. 除以 3 得到 3x≡1 (mod 4)。你可以直观地解决这个问题。解是 x≡3 (mod 4)。检查一下,因为 3×3 = 9≡1 (mod 4)。将这个结果转换回(mod 12),第一个解是 3 (mod 12),然后通过添加 12/3 = 4 再次添加 4,得到另外两个解,即 7 (mod 12) 和 11 (mod 12)。
总结一下,如果 a、b 和 n 有一个公因数 d,那么就有 d 个不同的解。第一个解是满足 a/d≡b/d (mod n/d)的解,其他解相距 n/d。
让我们看看另外两种情况。再假设 ax≡b (mod n),并且 a 和 n 有一个不整除 b 的公约数,例如 3x≡7 (mod 30)。那么这个同余方程没有解。相反,假设 a 和 b 有一个不整除 n 的公约数 d。那么你可以将 a 和 b 除以 d。例如,如果 10x≡25 (mod 37),那么 2x≡5 (mod 37)。这可以通过在头脑中将 37 加到 5 上来解决,得到 2x≡42 (mod 37)。除以 2 得到 x≡21 (mod 37)。
就像你可以将 a 和 b 除以一个常数一样,你也可以将 a 和 b 乘以一个常数 m。这个 m 不能与 n 有公因数。换句话说,m 必须在模 n 下可逆。否则,你会使同余方程变弱并丢失信息。例如,假设给定 9x≡3 (mod 12)。这是一个有 3 个解的弱同余方程。如果你将 a 和 b 乘以 2,同余方程变为 18x≡6 (mod 12),等价于 6x≡6 (mod 12),有 6 个解。这个弱同余方程变得更弱。
你也可以相加和相减具有相同模数的同余方程。假设 ax≡b (mod n)和 cx≡d (mod n)。这些可以相加得到(a+c)x≡b+d (mod n),或相减得到(a-c)x≡b-d (mod n)。这可以用来加强一组弱同余方程。例如,假设你有 9x≡3 (mod 12)和 8x≡4 (mod 12)。第一个同余方程有 3 个解,第二个有 4 个解。如果你将它们相加,得到 17x≡7 (mod 12),化简为 5x≡7 (mod 12),有唯一解 x≡11 (mod 12)。更聪明的是,如果你将两个同余方程相减,得到(9-8)x≡(3-4) (mod 12),直接得到 x≡11 (mod 12)。
*15.6 解线性同余方程
现在你知道如何安全地操作同余方程而不失强度,我们可以解决如何解线性同余方程 ax≡b (mod m),其中 a、b 和 m 是给定常数,x 是我们试图找到的未知值。特殊情况下当 b = 1 时,x 是 a 对模 m 的乘法逆元。大多数教科书只提到一种叫做扩展欧几里德算法的技术。(欧几里德算法通常被归功于雅典的忒亚泰特,他比欧几里德早生活大约一个世纪。)那是一个非常好的方法。当模数较小或者模数有几个不同的小质因数时,可能是正确的方法。当因数分解未知且存在小因数的可能性时,这绝对是正确的方法。
然而,在密码学中,只有两种常见情况需要计算乘法逆元,当模数是质数时,以及当模数是 2 的幂时。本节将描述一种更简单、更直接的方法。
15.6.1 简化同余方程
解决同余式 ax≡b (mod m)的基本方法是反复减少 x 的系数。最简单的方法是ResM。它将同余式乘以一个整数 n,使得 x 的系数至少与模数一样大。即 a(n-1) < m ≤ an。你可以通过将 m/a 四舍五入确定 n 的值,所以 2.0000 保持为 2,但 2.0001 会变成 3。当系数对 m 取模时,结果是一个较小的系数。
让我们从一个简单的 ResM 示例开始,只是为了获得基本概念,并且在后面讨论变得复杂时更容易跟上。取同余式 38x≡55 (mod 101)。我们知道 101/38 = 2.658,所以我们将同余式乘以 3,然后对 101 取模,就像这样:

注意,x 的系数从 38 减少到 13。这可以再次减少。我们有 101/13 = 7.769,所以我们将同余式乘以 8,就像这样:

我们快到了。101/3 = 33.667,所以将最后的同余式乘以 34,x 的系数就减少到 1:

我们可以通过将 x = 36 代入原同余式 38x≡55 (mod 101)来检查这个结果。将 x 替换为 36 得到 38×36≡55 (mod 101),即 1368≡55 (mod 101),这是正确的。正确答案是 x≡36 (mod 101)。
15.6.2 一半一半法则
让我们看一个小的改进。我们可以称之为一半一半法则。大约一半时间,m/a 的小数部分小于 1/2,另一半时间大于 1/2。设 q = m/a。那么一半时间 qa 更接近 m,另一半时间(q+1)a 更接近 m。
一个数值示例可能有助于更清楚地理解这一点。让 m 为 101,让 a 为 40。那么 q = 101/40 = 2.525。分数.525 大于 1/2。如果你取 40×2,结果是 80,比 101 少 21。如果你取 40×3,结果是 120,比 101 多 19。所以 40×3 比 40×2 更接近 101。因此 n = 3 是最佳乘数。
假设,相反,a 是 41。那么 m/a = 101/41 = 2.463。这次分数.463 小于 1/2。如果你取 41×2,结果是 82,比 101 少 19。如果你取 41×3,结果是 123,比 101 多 22。所以 41×2 比 41×3 更接近 101。因此 n = 2 是最佳乘数。
总结一下,当 q = m/a 的小数部分小于 1/2 时,如果我们向下取整 q,na 更接近 m,但当 m/a 的小数部分大于 1/2 时,如果我们向上取整 q,na 更接近 m。使用 floor 和 ceil 符号(第 13.3 节),如果 frac(q) < 1/2,选择 n = ⌊q⌋,但如果 frac(q) > 1/2,选择 n = ⌈q⌉。听起来很容易,但有一个复杂之处。当 n = ⌈q⌉时,na 大于 m,所以你通过减去 m 的倍数来减少同余式,就像我们在本节开头所做的那样。当 n = ⌊q⌋时,na 小于 m,所以你通过从 m 的倍数中减去它来减少同余式。
从这里开始

由于 101/41 = 2.463,将同余式乘以 2,得到

从 101 的倍数中减去这个数,即

由于 101-82 = 19 并且 202-180 = 22,因此得到

为了说明这种改进有多大,让我们分别使用半分法和非半分法解一个同余式。

如果不使用半分法,则减少需要 8 步。使用半分法减少只需 4 步。对于不同的系数和模数,比例会有所不同,但 8:4 是相当典型的。使用半分法的 ResM 可以称为ResMH。
15.6.3 阶梯法
当整数非常大时,这仍然有点慢,因为我们要乘以和除以大数。可以使用阶梯技术来避免这种情况。它对每个步骤使用两个同余式。阶梯技术不是将 x 的系数乘以越来越大的数字使其接近模数的值,而是在每个同余式中将系数乘以一个小数使其接近前一个系数的值。这需要一个额外的同余式来启动该过程。为此,我们使用同余式 mx≡m(mod m),它等价于 0x≡0(mod m)。
让我们看一个使用更大数字的例子:

由于 28338689/6114257 约为 4.635,乘以 5 并减去得到

在这里,6114257/2232596 约为 2.739,所以乘以 3 并减去得到

继续这样做,依次得到

每个例子都使用了一个素数模数。当模数是复合数时,情况变得更加复杂。我不会在这里覆盖所有这些复杂性。对于密码学最重要的情况是模数为 2 的幂,例如 2³²或 2¹²⁸。在这种情况下,您在每个阶段选择的乘数必须是奇数。因此,不要将乘数四舍五入到最接近的整数,而是始终向奇整数四舍五入。例如,3.14 将四舍五入为 3,3.99 也将四舍五入为 3。使用阶梯技术的 ResMH 可以称为ResMHL。
15.6.4 连分数
一旦有两个或更多的线性同余式,您可以使用一种称为连分数的技术更快地减少 x 的系数。连分数是一种通过分数紧密逼近十进制数的方法。考虑十进制数 R = .13579。R 在 1/7 和 1/8 之间。更准确地说,R 约为 1/7.3643。这也可以写成 1/7+.3643。注意加号+在分数的分母中。这表示加法在分母中完成,而不是将两个分数 1/7+.3643 相加。
分数.3643 可以近似为 1/2.745,或者 1/2+.745,所以 R 现在是 1/7+1/2+.745。这里.745 非常接近 3/4,因此近似可以是 1/7+1/2+3/4。要将其转换回普通分数,只需向后工作:

分数 11/81 是.13580,与.13579 仅相差.00001。正如你所见,这种方法提供了出色的近似值。
让我们再试一次来自 15.4.3 节的例子,
6114257x ≡ 90926 (mod 28338689).
对于第二个同余式,我们使用了 0 = 0 的技巧,
28338689x ≡ 28338689 (mod 28338689).
这里 6114257/28338689 是

获得接近的近似值的一个好法则是在大分母之前停止,本例中为 24。在 24 之前截断连分数得到

这计算出为 241/1117。
将 6114257 同余式乘以 1117 和 28338689 同余式乘以 241 然后相减得到

这将 x 的系数从 6114257 降低到 1020,降低了 5994 倍。因此,继续分数法比其他方法使用的步骤要少得多。然而,使用起来很棘手,因为一步的系数可能比下一步的系数大得多,例如 6829625069 与 1020。你可以通过交替使用连分数步骤和一半步骤来平衡系数。******
15.7 大整数密码
可以使用大整数乘法构建许多密码。第 15.3 节描述了 Mult128 密码,其中消息以 128 位块进行。每个块被视为 128 位整数,并乘以秘密的 128 位整数 M 模 2¹²⁸。为了得到良好的混合,乘数的每个字节都应该是非零的。这仍然很脆弱,因为每个密文块的低阶 n 位仅取决于明文和密钥 M 的低阶 n 位。这使得低阶字节的加密变为简单的替换。在乘法之前和之后执行简单的替换不能修复这个弱点。类似地,低阶 2 字节经历双字母替换,低阶 3 字节经历三字母替换。Mult128 评级为 Three。
修复低阶字节问题的超快速方法是将高阶字节与低阶字节组合起来,例如使用xors或adds组合函数。这将提高评级至 Five。一个更好的解决方案是使用xors或adds将高阶 8 字节与低阶 8 字节组合起来。这将评级提高至 Seven。这里是一个例子。

加强密码的一种方法是对 16 个字节进行置换,然而,有了足够的密文,Emily 可以检测出哪个字节位置的变异最小,因此必须是置换后的低位字节。Permuted Mult128 被评为四级。
更强大的方法是进行乘法、置换,然后再进行乘法。置换需要将弱的低位字节移到块的高位半部分。适合的置换有 (1) 颠倒字节的顺序,(2) 交换块的低位和高位半部分,或 (3) 以相反顺序交错低位和高位字节。如果使用十六进制数字 0 到 F 对字节进行编号,那么这 3 种置换可以表示为

如果你的编程语言允许你将该块视为 32 位字和单个字节进行操作,那么将 4 个字的顺序颠倒可能会更快,从而得到这种排列:

这个密码,称为 MPM128,被评为七级。
当你在这个过程中添加替换步骤时,安全性会提升。让 S[1]、S[2]、S[3] 和 S[4] 成为 4 个独立的混合很好的键入替换,让 P 是固定的置换 5BF4AE39D28C1706,让 M[1]、M[2] 和 M[3] 是乘以 3 个秘密的 128 位整数。然后密码 S[1]M[1]PS[2]M[2]S[3]PM[3]S[4],称为 Tiger,被评为十级。
15.8 小整数乘法
使用普通的无符号 32 位乘法可以完成 Mult128 的迷你版本。128 位块被视为四个 32 位整数。这些整数中的每一个都与一个秘密的 32 位整数进行乘法,取模 2³²。这 4 个乘数必须是奇数,以便稍后进行解密。这产生了一个 32 位密码。要得到一个 128 位密码,这 4 个单独的 4 字节乘积可以被视为一个 16 字节块,并使用这个固定的 16 字节密钥转位混合(见第 7.6 节):

这个转位后跟着第二个乘法步骤,再次将 16 字节块视为四个 32 位整数。你可以使用相同的乘数或新的乘数。然后是第二个转位,和另一轮乘法,所以有 3 轮乘法和两轮转位。这个密码被称为 Mult32,并被评为七级。它比任何 Mult128 密码变体都要快得多。
让我们将 128 位块的 16 个字节视为一个 4×4 字节矩阵。该矩阵的任何一行的 4 个字节都可以视为 32 位整数。通常情况下,整数的 4 个字节从左到右取出,最左边的字节为高位字节。但是,它们也可以按相反的顺序取出,最左边的字节为低位字节。考虑十六进制数 01020304。如果我们按照正常方式将其乘以十六进制数 01010101 对 2³²取模,结果是十六进制 0A090704。如果我们按照相反的顺序将其乘以十六进制数 01010101 对 2³²取模,结果是十六进制 0A060301。
类似地,我们可以将任何列中的 4 个字节视为 32 位整数,既按照自上而下的顺序,也按照自下而上的顺序。将两个水平方向称为东和西,两个垂直方向称为北和南。如果我们按照东、北、西、南的顺序将行和列乘以奇数 32 位整数对 2³²取模,这将提供彻底的混合。这需要 16 个单独的 32 位乘法器。总密钥大小为 16×31 = 496 位,而不是 16×32 = 512 位,因为乘法器必须是奇数。这种密码,可以称为Compass,评为 Eight。
要将评级提升到 Ten,可以添加一个或多个替换轮,例如,东、北、替换、西、南。更好的方法是,添加多个替换,比如东、替换、北、西、替换、南。将其称为CompassS。即使使用固定替换,如果它们高度非线性,CompassS 也评为 Ten。
使用小整数乘法的另一种方法是进行循环乘法。让块中每个 32 位行中的字节从左到右依次编号为 1、2、3、4,即从高位字节到低位字节。将其乘以奇数模 2³²。将字节 1 移动到低位,使顺序变为 2、3、4、1。再次乘以奇数模 2³²。重复两次,使每个字节都占据每个位置一次。即,字节按顺序 1234,然后 2341,3412,最后 4123。对 4×4 字节矩阵的 4 行中的每一行都要执行此操作,共进行 16 次乘法和 12 次循环移位。
接着对列执行相同的操作。总共有 32 次乘法和 24 次循环移位。这种循环乘法密码评为 Eight。可以有多达 32 个不同的 32 位乘法器作为密钥。
这一节的方法可以与第 15.4 节的方法以多种方式结合使用。这里只是一个例子,我将其称为Mat36。将消息按 36 个字符一组,这些字符被视为九个 32 位整数。这些整数形成了模 2³²的 3×3 整数矩阵。这个矩阵将与一个秘密的 3×3 可逆整数矩阵相乘。如果你简单地将另一个 3×3 矩阵乘在右边,那么这 9 个整数的低位字节将被弱加密。相反,将整个 36 字节块左移 16 位,然后将块右边乘以第二个秘密的 3×3 可逆整数矩阵。Mat36 评级为 Eight。
15.9 模 P 乘法
当乘法取模 2^n 时,低位字节会被弱加密,我们需要费点周折来解决这个弱点。当乘法取模一个素数 P 时,这个问题不会发生。有了一个大的乘数,产品的每一位都取决于明文的每一位。有一个不同的问题。假设你选择了一个素数 P < 2^n,以及一个乘数 M,其中 1 < M < P。这样你就可以安全地将从 0 到 P-1 的值乘以 M 模 P,所以 Riva 可以通过乘以 M',M 的乘法逆元,来解密这些值。
然而,明文值 0 将保持不变,而 P 到 2^n-1 的明文值不能安全地相乘,因为结果会产生歧义。例如,当通过 M 模 P 相乘时,3 和 P+3 将产生相同的结果,因为 3M≡PM+3M(mod P),所以 Riva 无法确定消息是 3 还是 P+3。这意味着从 P 到 2^n-1 的值必须保持不变。为了做到这一点,定义函数 modp 如下:

这个问题的一个解决方案是让 Sandra 对明文进行异或。这建议了一族Modulo P 密码。让我们确定 n = 64,意味着块大小为 8 字节,素数模数 P = 2⁶⁴-59 = 18446744073709551557,乘数 M = 39958679596607489,也是素数。
Sandra 通过选择一个秘密的 64 位常数 C[1]作为密钥,计算 x = modp(C[1]⊕B)+C[1]来加密 64 位明文块 B。这是这个系列中的第一个密码。称为PMod1。评级为 Five。这个系列中的第二个密码PMod2是 PMod1 的两次迭代,使用第二个 64 位常数 C[2]:

PMod2 评级为 Seven。这个系列中的第三个密码PMod3有 3 次迭代,评级为 Nine:

第四个成员PMod4评级为 Ten。它的总密钥大小为 256 位,是块大小的 4 倍:

每个加法都是模 2^n 进行的,而不是模 P。
四个 PModX 密码都非常快,因为大多数编程语言都直接支持 64 位的加法、乘法和模除。在某些计算机上,它们是单一的机器指令。这使得 PModX 密码能够以 4 或 8 个字节作为一个单位运行,而不是像 DES 那样将每个 4 位块单独处理。这类密码非常适合软件加密。PMod2 比 DES 更安全,因为密钥长度更大,而 PMod4 比 3DES 更安全。
对于模 P 的乘法还有第二种方法,可以消除不变的值。思路是将从 0 到 2⁶⁴-1 的整数范围分成两个单独的范围,每个范围使用不同的质数模数和不同的乘数。选择两个质数 P 和 Q,使得 P+Q = 2⁶⁴+2。大约有 1016 对这样的数字,所以很容易找到,例如 P = 9228410438352162389 和 Q = 9218333635357389229,以及两个小于 P 和 Q 的大乘数 M 和 N。麻烦的部分在于你必须将每个范围进行移位,以便仅乘以范围 1 到 P-1 或 1 到 Q-1 中的数字。通过重新定义 modp 函数来实现这一点。

通过重新定义的 modp 函数,PMod1 到 PMod4 密码与以前的工作方式相同,并且具有相同的评级。这张图展示了范围从 0 到 2⁶⁴-1 是如何被划分的。

15.10 进制转换
更改数字进制与乘以一个大整数紧密相关。当数字非常大时,更改数字进制是一个缓慢的操作,因此最好的策略是将消息分成块,并分别转换每个块。更改进制会模糊消息字节之间的分隔。
有两种将数字从一种进制转换为另一种进制的方法。你可以从低位开始计算,也可以从高位开始计算。很多人在学校学过这些技巧,但随着时间的推移往往会忘记。为了提醒大家,这里展示了两种方法。我们将使用低位技术将数字 1A87 从十一进制转换为七进制,然后再使用高位方法将其转换回十一进制。
使用低位技术,你要反复将数字除以新的基数。每个余数都成为转换后数字的下一个数字。以下是将 1A87 转换的步骤:
1A87÷7 等于 312,余数为 4。
312÷7 等于 49,余数为 5。
49÷7 等于 7,余数为 4。
7÷7 等于 1,余数为 0。
因此,十一进制中的 1A87 变为七进制中的 10454。
使用高位技术,你要反复将高位数字乘以旧的基数,然后加上下一个数字。以下是将 10454 转换的步骤:
1×7+0 等于 7。
7×7+4 等于 49。
49×7+5 等于 312。
312×7+4 等于 1A87。
如果这些数字看起来不太对,记住数字 7、49、312 和 1A87 都是以十一进制表示的。
你可以根据改变进制制作很多漂亮的密码。例如,一个 16 字节的块也是一个以基数 256 表示的 16 位数字。将该数字转换为另一个进制,比如 263。现在你可以对基数 263 的数字进行置换,或者执行替换,或者两者兼而有之。然后,你可以将其转换为基数 277,并做同样的事情。最后,你将其转换回基数 256。这需要一个 17 字节的数字来保存结果。你可以使用从 256 到 362 的任何进制。请记住,如果任何结果有一个前导数字 0,那么这个数字是必需的,以便 Riva 能够解密密文。
如果每个连续的基数都比前一个稍大,那么在每个阶段都需要相同数量的数字。只有在将数字转换回基数 256 时,数字的位数才会增加。没有理由要求这些基数必须是素数。
这是一个基于进制变换的分组密码概念。首先,从一个秘密的、混合良好的、基于密钥的简单替换 S 开始。S 操作的是字节,即从 0 到 255 的整数。S 可以扩展到大于 256 的进制,方法是保持大于 255 的任何数字不变。这样就消除了为每种可能的进制准备单独的替换表的必要性。选择 3 个数字基数 B[1]、B[2]和 B[3],满足 256 < B[1] < B[2] < B[3] < 363。你还需要 3 个针对 16 个元素的带密钥的置换 T[1]、T[2]和 T[3]。这些元素是整数,可以大到 B[3]-1,因此它们每个都需要超过 1 个字节。
分组密码3Base包括以下步骤:(1)替换 S。(2)转换为基数 B[1]。(3)替换 S。(4)转置 T[1]。(5)转换为基数 B[2]。(6)替换 S。(7)转置 T[2]。(8)转换为基数 B[3]。(9)替换 S。(10)转置 T[3]。(11)转换为基数 256。 (12)替换 S。密码块由步骤 11 中的 16 个元素组成。第 12 步将块扩展为 17 字节。密码 3Base 评级为 Ten。
*15.11 环
环是整数的抽象版本。也就是说,环是一组可以像整数一样进行加法和乘法运算的元素集合。你已经熟悉了几个环:整数、有理数、实数、模某个固定数的整数,也许还有复数和代数数。一些不太熟悉的环是多项式,其系数是环的成员,矩阵,其元素是环的元素,形式为 a +b√13,形式为 a +b∛7+c∛49,以及形式为 a +b√2+c√3+d√6 的数,其中 a、b、c 和 d 可以是整数、有理数或模某个固定整数的整数。
在我们讨论如何在密码学中使用环之前,让我们先制定环的正式规则。环加法用加号+表示,a+b,环乘法用并置表示,ab。
-
对于所有的环元素 a 和 b,a +b 和 ab 都是环的元素。(封闭性)
-
对于所有环元素 a、b 和 c,a +(b+c) = (a +b)+c。(加法的结合规则)
-
对于所有环元素 a 和 b,a +b = b +a。(加法的交换律)
-
存在一个环元素 0,使得 0+a = a +0 = a 对于所有环元素 a。(加法恒等式)
-
对于每个环元素 a,存在一个元素 -a,使得 a +(-a) = (-a)+a = 0。(加法的逆元素)
-
对于所有环元素 a、b 和 c,a(bc) = (ab)c。(乘法的结合律)
-
对于所有环元素 a、b 和 c,a(b +c) = ab +ac,且 (a +b)c = ac +bc。(分配律)
-
存在一个环元素 1,使得 1a = a1 = a 对于每个元素 a。(乘法的恒等式)
当添加一个加法逆元素时,通常会省略括号,因此 (-a)+b 变成 -a +b,而 a +(-b) 变成 a-b。
请注意,环乘法不一定是可交换的。如果环乘法是可交换的,则称该环为 可交换环。所有前述的例子都是可交换环。暂时假设我们讨论的所有环都是可交换的。如果环元素 a 有一个乘法逆元素 a',使得 aa' = 1,则称 a 为 可逆的。在处理有限环时,建议尝试对所有可能的元素对进行乘法运算,以确定哪些元素是可逆的,并保留一个逆元素表以供快速参考。
一种利用环算术进行加密的简单方法是将第 11.8 节的涟漪密码与第 13.14.1 节的滞后线性加法结合起来。让我们选择环 R13,其元素采用 a + b√13 的形式,其中 a 和 b 是十六进制数字,即模 16 的整数。两个十六进制数 a 和 b 组成一个表示字符的字节。例如,字母 X 在 ASCII 码中表示为十六进制 58,对应于 R13 环元素 5+8√13。
两个 R13 环元素 a + b√13 和 c + d√13 的加法为 (a + c) + (b + d)√13,乘法为 (ac + 13bd) + (ad + bc)√13,其中所有的加法都是模 16 进行的。例如,如果 x = 2+3√13,y = 4+5√13,则 x+y 为 6+8√13,xy 为 11+6√13。
对于组合的涟漪 + 滞后线性加法密码,可以称为 Lag Ripple,将 x[n] 替换为 ax[n]+bx[n-i]+cx[n-j],其中系数 a、b 和 c 是环的元素,这种情况下为 R13,而滞后 i 和 j 是小整数,如 2 和 5。明文可以分成,比如,16 字节的块,但对于短消息,密码可以应用于整个消息。我们假设是后者。然后,加密将是
x[n] = ax[n] + bx[n-2] + cx[n-5] 对于 n = 1,2,3, ...,L。
这里 a 是 R13 的一个可逆元素,b 和 c 是 R13 的任意元素,L 是消息的长度。算术运算在环中进行。您可能会认出这是第 11.8 节中 madd 组合函数的变体。对于加密前几个字节,通常会使用环绕。
对于使用已知的固定滞后进行单次通过的情况,滞后纹波的评级为 Two,因为可能的系数组合只有 256³种。通过在滞后纹波阶段之前和之后使用简单替代,评级增加到 Five。使用 3 次通过,每次通过的系数和滞后不同,评级变为 Six。
三重纹波使用 3 次通过,每次纹波通过前后使用秘密钥匙化的简单替代。每次通过都有不同的秘密系数和滞后。可选择为每次通过的消息从不同位置开始并循环。三重纹波评级为 Ten。
15.12 环上的矩阵
在 15.1 节和 15.2 节中,我们研究了希尔密码,它由将消息的每个块视为整数向量,并将该向量乘以模 26 或 256 的整数矩阵组成。整数模 26 或 256 没有什么神奇的。你可以使用任何环的元素来表示消息的字符。如果字符比环元素多,你可以使用环元素的成对或三元组,就像将 1 到 5 的整数对用于表示 25 个字母的 Polybius 方阵(9.1 节)一样。
假设你使用的是R13上的矩阵,该环的元素形式为a+b√13。如果你将明文块视为包含 32 个十六进制数字而不是 16 字节的向量,并且为矩阵乘积的每个数字写出表达式,你会发现密文中的每个十六进制数字都是明文数字的线性组合。因此,在R13环上使用 16×16 的矩阵等效于在十六进制数字上使用 32×32 的矩阵,即模 16 的整数。因此,这样的密码仍然容易受到已知明文攻击。攻击需要至少 256 字节的明文。可能 16×17 = 272 字节就足够了。
你,发送者,可以轻松地通过在矩阵乘法之前和之后使用钥匙化的简单替代来击败这样的攻击。或者,你可以构建自己的环,一个除了你的合法通信者以外其他人都不知道的环。只要你能保密你的环,就没有人能对你的矩阵密码发起任何攻击。
15.13 构建环
一个包含 N 个元素的环,称为阶数为 N 的环,由两个 N×N 的表表示,即加法表和乘法表。构建环可以分阶段进行。让我们以构建一个包含 8 个元素的环为例进行演示。首先构建加法表。你从一开始就知道这个环必须有两个元素,0 是加法恒元,1 是乘法恒元。对于所有 a,和 0+a 和 a+0 都是已知的。这给了我们加法表的顶行和左列。

接下来,从第二行开始。策略是取第一个尚未分配值的和,为该和分配一个值,然后利用结合规则推断其他和的所有可能的值。假设你想要 1+1 = 2,2+1 = 3,3+1 = 4 和 4+1 = 0。利用结合规则,现在可以填写表的左上部分。例如,你可以确定 2+2 是多少,因为 2+2 = (1+1)+2 = 1+(1+2) = 1+3 = 4。

由于 4+1 = 0,因此 1 的加法逆元是 4,4 的加法逆元是 1。同样,2 是 3 的加法逆元,3 是 2 的加法逆元。那么我们应该给 5+1 赋什么值呢?它不能是 0,因为 4 和 5 不能同时是 1 的加法逆元。它也不能是 1,因为那样 5 就会是 0。它也不能是 2,因为 5+1 = 1+1 意味着 5 = 1。同样,5+1 也不能是 3 或 4。它也不能是 5,因为 5+5 = 5 意味着 5 = 0。那就只剩下 5+1 = 6 或 5+1 = 7。它们是等价的,所以假设 5+1 = 6。这强制使得 6+1 = 7 和 7+1 = 5。这意味着 5+1+1+1 = 5。这使得 1+1+1 = 0。由于我们已经知道 1+1+1 = 3,这意味着 3 = 0。不可能。这是一个死胡同。设置 4+1 = 0 不起作用。
出了什么问题?循环 1+1+1+1+1 = 0 有 5 个项。在一个阶数为 N 的环中,任何这样的循环的长度必须能够整除 N。由于 5 不能整除 8,因此无法完成加法表。这就留下了 3 个选择,将循环长度设为 2、4 或 8。如果选择循环长度为 8,则该环是模 8 的整数环。如果选择循环长度为 2,则加法与异或相同。由于目标是开发一个新环,所以只能选择循环长度为 4。加法表必须是

通过使用分配规则,现在可以推算出乘法表。例如,2×2 = 2×(1+1) = 2+2 = 0。

让我们称这个环为R8。它是一个可交换环,因为对于所有环元素 a 和 b,都有 ab = ba。注意环R8中只有 1 和 3 有乘法逆元,而且每个元素都是其自身的逆元。
有两个环值得特别提及,即高斯整数和四元数。
15.13.1 高斯整数
高斯整数是形式为 a+bi 的数字,其中 a 和 b 是整数,i 是虚数单位√-1。换句话说,高斯整数是实部和虚部都是整数的复数。对于密码学用途,a 和 b 可以是模 16 的整数。因此,高斯数 a+bi 可以用来表示十六进制数 ab。例如,字母 X,在十六进制 ASCII 码中是 58,将被表示为高斯整数 5+8i。
高斯整数的加法和乘法如下:

其中加法和乘法是用于密码学的模 16 运算。
15.13.2 四元数
四元数是爱尔兰数学家威廉·罗恩·哈密尔顿(William Rowan Hamilton)于 1843 年在都柏林三一学院(Trinity College Dublin)发明的,他是爱尔兰皇家天文学家,用于描述旋转体的运动。它们是形式为 a+bi+cj+dk 的数,其中 a、b、c 和 d 是普通数,i、j 和 k 是抽象单位。四元数的定义关系是 i² = j² = k² = ijk = -1。从这个关系中,您可以推导出这些乘法规则:

四元数乘法不是交换的。四元数经常被用作非交换环的典型例子。
四元数在物理学中被广泛用于表示球面上的点和固体的旋转等事物。通过让 a、b、c 和 d 成为模 16 或模 256 的整数,可以将其适应于加密用途。这将使每个四元数代表消息的 2 或 4 个字符。
使用四元数的另一种方法是让系数 a、b、c 和 d 成为模 2³² 的整数。您可以使用一组秘密的混合良好的 5 位、6 位或 8 位字符代码,以便每个系数可以分别表示 6、5 或 4 个字符。因此,整个四元数将代表消息的 24、20 或 16 个字符。您可以通过左乘或右乘一个秘密的四元数乘法器来加密消息四元数 M。由于四元数乘法不是交换的,左乘和右乘它更强大,比如 AMB。与普通乘法一样,每个分量中的低阶字节最弱,因此在第一次乘法后最好将整个 16 字节块循环左移 16 位位置。可以使用相同的字符代码集将乘积转换回标准 ASCII 字符,但最好使用不同的代码集,最好是不同大小的代码。
让我们称这种方法为Qmult。 Qmult 被评为十分。为了解密这条消息,Riva 必须左乘逆四元数 A',右乘逆四元数 B'。 四元数 a+bi+cj+dk 的逆由 (a-bi-cj-dk)/(a²+b²+c²+d²) 给出。由于我们是在模 2³² 下工作,当 a²+b²+c²+d² 为奇数时,即当其中一个或三个系数为奇数时,a²+b²+c²+d² 将具有乘法逆元。
15.14 寻找可逆矩阵
要将矩阵用于希尔式密码,该矩阵必须是可逆的。可逆矩阵通常难以找到。如果环中的可逆元素数为 i,总元素数为 r,则随机 n×n 矩阵是可逆的概率为(i/r)n。对于R8环,i/r 为 2/8 = 1/4。(这与有理数或实数上的矩阵形成鲜明对比,在这些域上除了 0 之外的每个元素都有乘法逆元,因此几乎每个矩阵都是可逆的。)如果矩阵很小,通常可以通过随机选择元素,然后尝试最后一个元素或最坏的情况下最后两个元素的所有可能值来找到一个可逆矩阵。通过使用最后 1 或 2 个元素,您可以将矩阵减少到底部两行,而不必为每次试验都进行完整的减少。
在本书中我选择不讨论行列式,因为我不知道在密码学中有任何对它们的用途,然而,对于熟悉行列式的读者,如果一个矩阵的行列式值是环中的可逆元素,则矩阵是可逆的。特别地,一个整数矩阵是可逆的,仅当其行列式是+1 或-1 时。
当所需矩阵较大时,可能不可行找到一个可逆矩阵。相反,您需要构造一个可逆矩阵。您首先通过以两种特定形式之一构造一组所需尺寸的矩阵来开始:三角形和块对角线。以下是四种类型的三角形矩阵的 4×4 示例。

上三角矩阵的非零元素只在主对角线上或其上方(从左上到右下)。
如果对角线上的所有元素是可逆的,则三角矩阵是可逆的。如果反对角线上的所有元素是可逆的,则反三角矩阵是可逆的。这些矩阵的逆可以使用第 15.1.1 节的技术轻松找到。对于上三角和下反三角矩阵,应从右向左执行第 15.1.1 节的约化过程。
通用的可逆矩阵可以通过这些三角形形式相乘来构造。这必须谨慎进行。两个上三角矩阵的乘积仍然是上三角的,两个下三角矩阵的乘积仍然是下三角的。反三角矩阵没有这个性质。一个明智的做法是构造四种三角形类型的矩阵的一个矩阵,然后形成它们的乘积。如果三角矩阵是 A、B、C 和 D,它们的逆矩阵是 A'、B'、C'和 D',那么乘积 ABCD 的逆矩阵是 D'C'B'A'。
除了三角矩阵外,分块对角矩阵还可以用来构造可逆矩阵。下面是一个 5×5 的分块对角矩阵示例。这个矩阵可以称为 2,3 型,因为它由一个 2×2 矩阵和一个 3×3 矩阵沿着 5×5 矩阵的对角线排列而成。

当两个相同类型的分块对角矩阵相乘时,结果是相同类型的分块对角矩阵。
使用分块对角矩阵的优点是您可以分别找到每个分块的逆矩阵。如果您将这些逆矩阵串联在对角线上,结果就是整个矩阵的逆矩阵。找到一个可逆的 16×16 矩阵可能不可行,但是找到四个 4×4 可逆矩阵并不是太具挑战性。您可以通过乘以其他类型的分块对角矩阵或一些可逆的三角矩阵来将您的可逆分块对角矩阵扩展到完整矩阵。
全力以赴。使用尽可能大的分块构造您的可逆分块对角矩阵,并使用 4 个三角矩阵,每种一个。您最终的可逆矩阵是这五个矩阵的乘积。******
第十六章:三次通行协议
本章内容包括
-
基于指数的三次通行协议
-
基于矩阵乘法的三次通行协议
-
基于双边矩阵乘法的三次通行协议
第 2.2 节和第 2.3 节描述了现代密码学分为 3 个分支,即秘密密钥、公钥和个人密钥。到目前为止,本书仅描述了秘密密钥密码学的方法。公钥密码学在许多书中有描述,因此这里不会涉及。本章将讨论个人密钥密码学,这是密码学的较不为人知的第三个分支。个人密钥密码学有时被称为无密钥密码学,因为各方不需要传输或共享任何密钥。
个人密钥密码学的基本概念是,两个通信者 Sandra 和 Riva 各自有自己的个人密钥。这个密钥永远不会被传输或与任何其他人共享,甚至不会与彼此共享,因此没有可能通过窃听、拦截广播或任何其他形式的窃听来了解任何个人密钥。个人密钥密码学的巨大优势是你不需要提前设置任何东西。不需要有任何秘密、安全的通道来交换密钥。消息可以在公共通道上交换。不需要密钥服务器或其他基础设施。
个人密钥密码学是通过三次通行协议实现的,该协议是由以色列魏茨曼学院的阿迪·沙米尔于大约 1975 年发明的。为了说明这种方法,我想出了一个小故事:
曾经有一位国王爱上了邻国的女王。为了追求女王,国王希望送她一颗珍贵的宝石。国王有一个坚固的保险箱和一个防拆锁。但是他怎么能送钥匙呢?如果信使既有钥匙又有保险箱,他就可以打开箱子并偷走宝石。国王可以用第二位信使送钥匙,但他担心两位信使会在途中相遇并一起偷走宝石。女王提出了一个巧妙的解决方案。
国王会在保险箱上放上他的锁,并将其发送给王后。然后她会添加自己的锁,并带着两把锁把保险箱送回来。国王然后用自己的钥匙取下他的锁,并只带着王后的锁把保险箱送回来。然后她可以用自己的钥匙打开箱子并拿到宝石。
这里的两把锁代表两个加密,两把钥匙代表相应的解密。消息将使用发送者的加密函数加密,发送给接收者,使用接收者的加密函数加密,发送回发送者,使用发送者的解密函数解密,发送回接收者并使用接收者的解密函数解密。这意味着消息发送了 3 次,因此称为三次通行协议。
*****让我们来分解一下。假设消息是 M,Sandra 的加密和解密函数分别是 S 和 S',Riva 的加密和解密函数分别是 R 和 R'。在第一次传递中,Sandra 用她的加密函数 S 加密消息 M 并将 SM 发送给 Riva。在第二次传递中,Riva 用她自己的加密函数 R 加密消息 SM 并将双重加密消息 RSM 发送回 Sandra。在第三次传递中,Sandra 将她的解密函数 S'应用于消息 RSM 以获得 S'RSM。这旨在去除 S 加密。只有当 R 和 S 可交换,或者 S'和 R 可交换时,才能实现这一点。这意味着 S'RSM = RS'SM = RM。这使得 Riva 可以去除她的加密并读取消息。
因此,为了使这个三次传递方案起作用,我们需要找到一个可交换的加密函数,或者两个彼此可交换的加密函数。我能立刻想到 3 个可交换的加密函数:加法、乘法和异或。很容易想象出一种加密方式,其中密钥与消息长度相同,加密包括逐字节将密钥加到消息中,或将消息字节乘以密钥字节,或将消息与密钥进行异或。这些都是一次性密码的简单形式。
这些都不安全。如果 Emily 设法获取所有三条加密消息,她可以轻松地去除加密。如果函数是加法,那么 3 条消息分别是 M+S、M+S+R 和 M+R。如果 Emily 将第一条和第三条消息相加,然后减去第二条消息,她会得到(M+S)+(M+R)-(M+S+R) = M。结果正是 M。当加密函数是乘法时,同样的方法也适用。3 条消息分别是(M×S)、(M×R)和(M×S×R)。再次进行(M×S)×(M×R)÷(M×S×R)运算得到 M。当加密函数是异或时,找到 M 甚至更简单,因为异或是其自身的逆运算。只需将 3 条加密消息进行异或运算,结果就是原始消息,(M⊕S)⊕(M⊕R)⊕(M⊕S⊕R) = M。
可交换的两个加密函数是替换和置换。这些也是不安全的。由于 Emily 会看到置换前后的消息,她可以轻易确定置换。
所需的是一对可交换的加密函数 S 和 R,使得即使 Emily 拥有 SM、RSM 和 RM,她也无法确定 M。
16.1 Shamir 的方法
Shamir 解决这个问题的方法是使用指数。设 p 是一个大素数,比如在 300 到 600 位十进制数字范围内。Sandra 将选择一个加密指数 s。相应的解密指数是 s',使得 ss'≡1 (mod p-1)。这是根据费马小定理得出的,如果 0<a<p,则 a^(p-1)≡1 (mod p)。第 14.4.2 节描述了如何选择素数 p,第 15.4 节描述了如何确定 s'。同样,Riva 选择她的加密和解密指数 r 和 r'。这两个加密是可交换的,因为(Ms)r = M^(sr) = M^(rs) = (Mr)s。
Sandra 计算(M^s mod p)并将其发送给 Riva。Riva 计算(M^(sr) mod p)并将其发送回 Sandra。Sandra 计算(M^(srs)' mod p) = (M^r mod p)并将其发送回 Riva,最终 Riva 计算(M^(rr)' mod p) = M,这就是原始消息。这种方法被认为是安全的,因为确定 s 或 r 需要解决离散对数问题。正如第 14.4 节所讨论的,这个问题被认为在计算上是困难的。目前没有已知的可计算的算法。
这种方法非常慢。所有这些大数的指数运算和模数减少需要大量计算。下一节描述了一种解决方案的尝试。
16.2 Massey-Omura
Massey-Omura方法是由 ETH Zurich 的 James Massey 和 UCLA 的 Jim K. Omura 于 1982 年发明的。(他的名字在专利上列为 Jimmy Omura。他是我在 MIT 的同学,尽管我不记得他。)Massey-Omura 系统与 Shamir 系统本质上相同,只是模数的形式为 2^k。这意味着模 2^k 的余数可以通过简单地取数字的低 k 位来计算。这比计算模 p 的余数要快得多,后者基本上是通过使用这些 300 到 600 位数字进行长除法来完成的。
哪种方法更快的问题在几年来一直在计算机协会(ACM)和电气电子工程师学会(IEEE)的出版物中激烈讨论。
16.3 离散对数
Diffie-Hellman 密钥交换、Shamir 三次协议和 Massey-Omura 方法的安全性都取决于解决离散对数问题的难度。解决这个问题的三种流行算法是穷举枚举,适用于 10¹²,Daniel Shanks 的 baby-step giant-step 算法,适用于 10¹⁸,以及 John Pollard 的 rho 算法,适用于 10²²。然而,我们需要一个适用于 10³⁰⁰的算法。为了让人们对离散对数问题的困难有所了解,让我们看看一个解决它的复合方法。这不是你可以在家用个人电脑完成的事情。这需要一个具有大量存储空间的大型计算机,或者一个由许多个人合作工作的网络。或者,你可以跳过这一部分,只是接受离散对数问题是困难的。
16.3.1 对数
首先考虑在计算机出现之前人们如何计算普通对数。一种方法是取一个数字 b = 1.000001,费力地计算它的连续幂。你会发现 b⁶⁹³¹⁴⁸是最接近 2 的幂,而 b²³⁰²⁵⁸⁶是最接近 10 的幂。然后你会知道 log10 几乎是 693148/2302586,即 0.3010302。正确值是 0.3010300,所以这种方法给出了一个很好的近似值。
您可以在一个环中进行相同的操作,比如取模某个素数 p。假设桑德拉发送消息 6 模 13,里瓦返回消息 7 模 13。艾米莉想知道里瓦使用了什么指数进行加密。与其使用 1.000001 的幂,不如使用模 13 的一个原根,比如 2。由于模数较小,艾米莉可以轻松列举出模 13 的所有 2 的幂。

现在艾米莉知道桑德拉发送了 2⁵,里瓦回复了 2¹¹。所以 (2⁵)r≡2(5r)≡2¹¹ (mod 13)。这意味着 5r≡11 (mod 12)。您可以在脑海中解决这个问题。只需想想 11+12 = 23,23+12 = 35。由于 35 是 5 的倍数,即 5×7,这意味着 r 必须是 7。您可以用手计算器检查,6⁷ = 279936≡7 (mod 13)。桑德拉发送了 6,里瓦回复了 7,所以这是正确的。
16.3.2 素数的幂
艾米莉通过穷举法可以找到一种搜索方法,但是当 p 很大时,这种方法行不通。让我们尝试约翰·波拉德的ρ 算法中的一个思想。第一步是生成模 p 的多个幂序列,并寻找重复项。艾米莉可以同时使用多个原根进行这样的操作,每个核心一个原根。现在我们来把它加倍。如果 b 是模 p 的一个原根,她可以在一个处理器上计算出 b²、b³、b⁴、b⁵... (mod p),在另一个处理器上计算出 b²、b⁴、b⁸、b¹⁶... (mod p)。这给了艾米莉每个使用的原根两个单独的幂序列。
除了原根,艾米莉还可以直接检查。桑德拉发送 SM,里瓦回复 RSM。艾米莉可以生成序列 (SM)²、(SM)³、(SM)⁴、(SM)⁵... 和 (SM)²、(SM)⁴、(SM)⁸、(SM)¹⁶...,以及 RSM 的类似序列。这给了艾米莉另外四个幂序列。
除了这些有序的幂序列之外,她还可以生成一些无序的序列。这些通常被称为随机游走或醉汉游走。一种方法是对生成的最后一个幂进行平方,然后将其乘以之前的某一个幂。艾米莉可以随机选择早期的幂,或者她可以使用列表的中间元素。例如,假设她已经有了幂 x、x²、x⁴、x⁸ 和 x¹⁶。对于下一个幂,她可以对 x¹⁶ 进行平方得到 x³²,然后乘以,比如说,x² 得到 x³⁴。对于下一个幂,她会对 x³⁴ 进行平方得到 x⁶⁸,然后再乘以另一个列表元素,比如说 x⁸,得到 x⁷⁶。依此类推。
艾米莉可以生成另一种随机游走,使用 2 或 3 个基本素数。每个基本素数应该是一个原根。从这些素数的乘积开始。要生成下一个乘积,她会随机选择其中一个素数并将其乘以。艾米莉拥有的序列越多,她就越快地开始得到结果。
16.3.3 崩溃
好了,现在艾米莉有了所有这些序列。然后呢?她在两个列表上寻找相同的数字。这被称为碰撞或崩溃。假设她发现 3¹⁷²⁹⁶⁴≡103⁴²⁹⁸⁷⁵⁵ (mod p)。通过解决同余式 172964r≡4298755 (mod p-1),这使得她能够将 103 表示为 3 的幂(模 p)。该方法在第 15.4 节中描述。一旦她积累了足够的崩溃,她就可以建立一个链,例如 RSM≡19^a, 19≡773^b, 773≡131^c, ... , 103y≡(SM)z。将所有指数模 p-1 相乘,她将得到 RSM≡(SM)^r (mod p)。这个指数 r 就是瑞娃的加密函数。艾米莉破解了密码!
这并不像听起来那么简单。当 p 是一个 300 位数素数时,她需要大约 10¹⁵⁰个这样的幂才能开始看到任何崩溃。如果艾米莉有 100 万个处理器,每秒产生 100 万个这样的幂,她可能每年就可以生成 3×10¹⁹个。这意味着她需要大约 10¹³⁰年才能开始看到任何结果,直到她能建立这样一个链为止。此外,它将需要 10¹⁵⁰个字节的存储的倍数。
16.3.4 因式分解
不是每次生成新的幂时都要搜索崩溃,艾米莉可以尝试对其在模 p 下的残留进行因式分解。假设她成功地对 97^a (mod p)的残余进行了因式分解,并找到了 97a≡11b29c83d (mod p)。她可以解这个同余式得到 97。设模 p-1 的 a 的乘法逆元为 a'。将同余式提升至 a'次幂。97(aa)'≡97≡(11b29c83d)^a' (mod p)。将所有指数相乘并将它们减去模 p-1,结果是 97≡11e29f83^g (mod p),其中 e、f 和 g 是一些值。(如果 p 有 300 位数字,实际值可能长达 300 位数字。)一旦她得到了一个质数基的表达式,比如说 97,在所有已经有和以后会找到的因式乘积中都可以替换这个值。
艾米莉将无法对每个幂的残留进行因式分解。对一个 300 位数进行因式分解非常困难,也就是说非常耗时。最好的策略是选择一个固定的质数基集 F(B),比如说所有小于 B = 10⁶的质数,或者也许是所有小于 B = 10⁷的质数。F(B)被称为因子基。尝试仅使用因子基中的质数对每个幂进行因式分解。可以用这种方式进行因式分解的数字称为B-平滑。随着数字变大,B-平滑数字的比例会变得越来越小。在 300 位数中,B-平滑数很少见。当艾米莉找到每个因子时,数字的未因式分解部分就会减少。如果她已经尝试了基础集中的所有质数,数字的一些未因式分解部分仍然存在,她就不应再尝试进一步因式分解它。放弃这个幂并继续下一个幂会更有效率。
这就是 Emily 必须做的事情:继续生成产品并对它们对 p 取余的结果进行因式分解。仅保留 B-smooth 数字并丢弃其余。检查 B-smooth 数字中的崩溃情况。每次发现崩溃时,解决乘积中最大质数的同余式,以便需要越来越少的基本质数来表示每个乘积。她可以保留一个或多个专用于此任务的处理器。
假设 q^n 是一个质数的幂,并且其模 p 的剩余为 x。尝试使用基本集 B 中的质数因式分解 x。如果 x 不是 B-smooth,则尝试因式分解数 x+p,x+2p,x+3p,...。因式分解一个 301 位数或 302 位数的数并不比因式分解一个 300 位数的数更难。设置一个固定数量的这样的尝试,比如说,对于每个剩余设置 10 次尝试。
当她生成这些幂时,她需要特别强调 SM 和 RSM。记住,这个练习的目标是找到指数 r,使得(SM)^r≡RSM (mod p)。她在将 SM 和 RSM 都表示为基本质数的幂之前是无法做到的。首先,她应该开发出多个 SM 和 RSM 幂的序列。一旦她成功找到这样的表达式,她就会寻找表达式中尚未用较小质数的幂表示的质数。接下来重点放在这些质数上。继续直到 SM 和 RSM 都表示为单一质数的幂。她现在可以使用第 15.3.2 节的方法找到 r。
16.3.5 估算
假设她使用了 10⁶ 个基本质数,也就是说,质数达到了 B = 15,485,863。要将所有这些表示为单一质数将需要 10⁶ 个同余式。存储这些需要一个 10⁶×10⁶ 的指数矩阵。矩阵最初是稀疏的,但随着解决方案的进展而变得稠密,因此稀疏矩阵技术将不会有益。每个指数是一个 300 位数。这需要大约 10¹⁵字节,或 1 个petabyte的存储空间。截至撰写本文时(2022 年 3 月),世界上最大的超级计算机是位于奥克里奇国家实验室的 Summit 计算机,拥有 2.76 petabytes 的可寻址存储空间。
显然,运行时间取决于找到 B-smooth 数字需要多长时间。B-smooth 数字的密度由 de Bruijn 函数Ψ(p,B)给出,它给出了小于 p 的 B-smooth 整数的数量。这由荷兰数学家尼古拉斯·戈弗特·德布鲁因研究过。Ψ(x,x^(1/u))的值由精算师卡尔·迪克曼发明的迪克曼函数ρ(u)近似,其中ρ(u)是迪克曼函数。迪克曼函数ρ(u)由 u^(-u)近似。在这种情况下,x = 10³⁰⁰和 x^(1/u) = 15,485,863,所以 u = 41.725。因此,大约需要大约 41.725^(41.725) = 4.08×10⁶⁷次尝试才能找到每个 B-smooth 数字。
总的来说,将需要超过 10⁷³ 次尝试来找到 10⁶ 个 B-平滑幂。对每个数字进行因数分解可能需要多达 10⁶ 次试除,因此总共需要 10⁷⁹ 次试除。由于数字有 300 位,每次试除将需要 300 倍的操作。总共是 10⁸² 次操作。这比崩溃法的 10¹⁵⁰ 有了巨大的改进,但对于当前的计算机仍然是不可及的。
这表明对于可预见的未来,300 位数字已经足够了,也许可以维持 20 到 30 年。随着量子计算机的发展,这可能会改变,但目前 300 位数字是安全的。
16.4 矩阵三次传输协议
用于三次传递算法的 Shamir 和 Massey-Omura 方法都使用了指数运算。三次传递算法的另一种方法是使用矩阵。我们之前已经见过这种情况,比如 Hill 密码,第 15.1 节。消息被分成块。每个块被视为模 256 的整数向量。这个向量被一个模 256 的可逆方阵左乘或右乘。对于三次传递版本,Sandra 将有一个用于加密的矩阵 S 和其逆矩阵 S',而 Riva 将有一个加密矩阵 R 和解密矩阵 R'。这些矩阵不是在模 256 整数上,而是在一个 256 个元素的环R上,消息的字符被视为该环的元素。假设消息块为 M,所以 Sandra 发送 SM 给 Riva,Riva 将 RSM 返回给 Sandra,Sandra 使用 S' 解密以获得 S'RSM = RM。现在 Riva 可以使用 R' 解密它,即 R'RM = M。
棘手的部分是使 S'RSM = RM。矩阵乘法不可交换,所以 Sandra 和 Riva 需要选择彼此可交换的特殊矩阵 S 和 R。明确地说,S 和 R 不是可交换矩阵。如果你随机选择一个矩阵 X,几乎可以肯定 SX ≠ XS 和 RX ≠ XR。这是一个重要的观点,所以让我重复一遍,S 和 R 不是可交换矩阵。它们不与大多数其他矩阵可交换。它们彼此可交换。
16.4.1 可交换矩阵族
Sandra 和 Riva 需要大量的这些矩阵,这样 Emily 就不能简单地尝试它们所有。这意味着他们需要一个大的可交换矩阵族Ғ,从中选择每个消息块的矩阵。
注意Ғ是一个可交换的矩阵族,而不是一组可交换的矩阵。重要的是要理解,可交换的是矩阵族,而不是矩阵本身。Ғ中几乎所有的矩阵都不可交换。它们彼此可交换,但与其他矩阵不可交换。
构造可交换矩阵族的最简单方法是从任意可逆矩阵 F 开始,并取其幂,F⁰、F¹、F²、F³、...,其中 F⁰ 是单位矩阵 I,而 F¹ = F。将 F 称为Ғ族的生成矩阵。
Sandra 和 Riva 每个消息块都需要使用不同的矩阵,否则 Emily 可能会在已知明文的足够消息块 M[i] 的情况下解出线性方程组 R(SM[i]) = RSM[i]。
16.4.2 乘法阶
要使Ғ族变得更大,你需要找到或构造一个具有很高乘法阶的生成矩阵 F。也就是说,需要找到一个最小的整数 n > 0,使得 F^n = I,至少要大于 10^(25),但最好更大。如果矩阵 F 是可逆的,这样的 n 总是存在的,并且 F 的乘法逆 F' 是 F^(n-1)。在第 15.8 节中给出了一种寻找可逆矩阵的方法。确定 F 的乘法阶有点艺术性。显然,一直计算 F 的连续幂直到 F^n = I 是不可行的,特别是当 n > 10^(25)时。但这是可以做到的。
要找到乘法阶,从 1×1 矩阵开始,即环元素。查看这些元素的乘法阶。这些可以通过枚举轻松找到,因为 n 的最大可能值是 255。可能的值是 2、3、7、15、31、63、127 和 255。更大矩阵的乘法阶往往是这些值的倍数。
假设环元素的乘法阶恰好是 2、7 和 31。当你尝试 2×2 矩阵时,首先将每个矩阵 A 提升到单元素阶的某个倍数,比如 2⁴7²31 = 24304。然后枚举 B = A²⁴³⁰⁴ 的幂。假设你发现 B⁵² = I。你现在可以确定 A 的乘法阶 m 能够整除 x = 24304×52 = 2⁶7²13×31,且是 2⁶13 的倍数。接下来应该尝试 A^(x/7) 和 A^(x/31) 看看它们是否为 I。如果 A^(x/7) 是 I,那么你就尝试 A^(x/49)。在这种情况下,最高的乘法阶可能是 2⁶7×13×31。
接下来你要处理 3×3 矩阵。如果除了 2、3、7、13 和 31 之外,2×2 矩阵的乘法阶中没有其他质因数出现,那么一个好的起始指数可能是 x = 2⁸7²13²31²。枚举 B = A^x 的连续幂,并重复缩小指数的过程。随着矩阵变大,乘法阶可能会增加一个无法通过枚举找到的因子。在这种情况下,你将需要猜测新的可能出现的质因数。
注意乘法阶序列中出现的模式。这需要一些侦探工作。例如,假设出现了 2³-1、2⁶-1、2⁹-1 和 2¹²-1。你不会直接看到这些,因为它们不全是质数。2⁶-1 = 63 = 3²7,2⁹-1 = 511 = 7×73 和 2¹²-1 = 4095 = 3²5×7×13。所以在质因数中找到 13 是指向“真正”因数可能是 2¹²-1 的线索,而找到 73 则强烈表明 2⁹-1 是一个因数。如果出现了 2³-1、2⁶-1、2⁹-1 和 2¹²-1,你应该期待很快出现 2¹⁵-1。如果这些全部出现,它们都可以被 7 整除,所以乘法阶将被 7⁴ 整除。
16.4.3 最大阶
艾米莉在这一切中的目标是尽可能地扩大家族Ғ,这样她和里娃就有很多选择来选择他们的矩阵 S 和 R。一个有用的技巧是观察因子集合之间的乘法阶数差异。例如,如果 A 的乘法阶数为 19m,B 的乘法阶数为 23m,那么 AB 的乘法阶数很可能是 19×23m=437m。如果这不起作用,那么 A'B 或 AB'可能具有乘法阶数 437m。
如果可能的话,桑德拉应该选择一个生成矩阵 F,其乘法阶数具有一个大素数因子,比如\(m > 10^{35}\),以防止 Silver-Pohlig-Hellman 攻击(第 14.4 节)。桑德拉需要对各种\(n\)进行因式分解\(2^n-1\),找到具有大素数因子的那些,并尝试用逐渐增大的矩阵找到一个乘法阶数可被其中一个\(2^n-1\)整除的生成矩阵。
16.4.4 艾米莉的攻击
假设桑德拉已经选择了 F 和Ғ,并且她已经向里娃发送了一条消息。由于桑德拉和里娃正在通过公共信道进行通信,比如互联网,假设艾米莉知道 F、Ғ、SM、RSM 和 RM。她的目标是找到 R 或 S,所以她有两次机会。让我们集中讨论艾米莉如何找到 R。艾米莉知道关于 R 的两件事。首先,她知道 SM 和 RSM 的值,这给了她 n 个线性方程,这些方程是关于 R 的\(n²\)个未知元素的。其次,她知道 R 在家族Ғ中,所以它必须与 F 交换,即 RF = FR。如果环R是可交换的,那么这给了她 n(n-1)个关于 R 的\(n²\)个元素的附加线性方程。
这有效的原因是矩阵方程 RF = FR 的左侧产生了形式为\(r f\)的项,其中\(r\)是 R 的未知元素,\(f\)是 F 的已知元素。右侧产生了形式为\(f r\)的项。由于环是可交换的,左侧项\(r f\)可以转换为形式\(f r\),并与右侧项组合形成线性方程。
在\(n²\)个未知数的\(n²\)个线性方程中解决这些线性方程并找到\(R\)似乎很容易。但事实并非如此。回顾第 15.3.1 节,我们知道有强同余和弱同余。对于任何不是素数的有限环上的线性方程,情况也是如此。环大小有多少素因子,就有多少潜在的弱方程。在当前情况下,环大小为\(2⁸\),有 8 个素因子,所以许多线性方程很可能是弱方程。如果环R选择得当,矩阵的典型大小可能是 30×30,或者 128×128,甚至 256×256,如果环的选择不佳。即使选择了合适的环,即使一半的方程是强的,你也会期望至少有\(2^{450}\)个解集合的 30×30=900 个方程。实际上,解的数量要多得多,因为可能有 4、8 或甚至 16 个解的方程。
Emily 有个好消息。Emily 可以解决 R' 而不是 R,而她得到的那 2⁴⁵⁰ 或更多的解中的任何一个都将是 R 的有效逆,让她通过 R'RM = M 获得消息。
16.4.5 非交换环
Sandra 和 Riva 看起来是失败的。Emily 赢得了这场战斗。
解决这种攻击的一个可能方法是让 Sandra 和 Riva 使用一个非交换环。非交换环的两个例子是矩阵和四元数(第 15.7.2 节)。你可以形成元素本身是矩阵或四元数的矩阵,或者反过来,系数是矩阵或四元数的四元数。但这些都不是好选择。你需要让它们变得非常大才能产生高乘法阶的矩阵。
更好的方法是使用第 15.7 节的技术构造你自己的环N。你应该选择一个具有许多具备以下特征的元素的环:(1) 可逆,(2) 具有高乘法阶,以及 (3) 非交换。要找到一个同时具有所有这些特征的环是一个棘手的平衡行为。例如,一个具有最大乘法阶元素(256 元素环的 255)的环不能有任何非交换元素。如果你能找到一个环,其中一半元素是可逆的,一半具有乘法阶约为环大小一半的元素,一半是非交换的,dayenu(这就足够了)。你不能同时达到这 3 个目标,但你可以在某些目标上超过其他目标,同时接近其他目标。
使用非交换环,矩阵方程 RF = FR 不再能线性化,因为不再确定 rf = fr。相反,矩阵方程导致一组bilinear方程。双线性方程中的一般项的形式为 axb,其中 a 和 b 是环的元素,x 是您希望确定的变量。虽然线性方程可以使用简单的系统方法解决,即高斯消元法,但对于双线性方程却没有这样的方法。甚至对于一个变量 x 的简单方程 ax+xb = c 也没有一个一般的解法。因此,在环上解双线性方程是“不可能的”。
16.4.6 解双线性方程
话虽如此,我现在将向你展示如何解决双线性方程。诀窍在于改变环N中元素的表示。我们已经看到了几个这样做的示例。在环R13中,元素表示为a + b√13。高斯整数表示为 a+bi。四元数表示为 a+bi+cj+dk。这里,i、j 和 k 是决定环行为的抽象单位的乘积,而 a、b、c 和 d 是环的可交换元素。四元数可以是非交换的,因为单位的乘法不是交换的,即,ij ≠ ji,ik ≠ ki,jk ≠ kj。只有一个单位时,高斯整数必然是可交换的。
线性化双线性方程的技巧是通过找到非交换环 N 的表示来完成的。这很容易做到。首先将 N 的元素划分为两组,A 和 B,其中 A 包含具有表示的元素,而 B 包含其余的元素。最初,A 是空的,B 包含环的所有元素。从取可交换的元素并将它们移到集合 A 开始。这些环元素将表示它们自己。它们是表示中的“a”项。选择任意剩余可逆元素作为单位 i。取所有可以表示为 a+bi 的环元素,其中 a 和 b 是环的可交换元素,并将它们从集合 B 移动到集合 A。到目前为止,A 的所有元素仍然是可交换的。
集合 B 不能为空,因为 N 不是交换的。我们已经注意到只有一个单位的环,如高斯整数,必须是可交换的。因此,从集合 B 中取出第二个可逆元素,并称其为第二个单位 j。这次,您将所有可以表示为 a+bi+cj 的元素从集合 B 移动到集合 A。可能仍然存在于集合 B 中的环元素。在这种情况下,您将重复这些步骤,但为简单起见,假设(1)只需要两个单位;(2)环中的所有元素都可以表示为 a+bi+cj,其中 i 和 j 是抽象单位;和(3)a、b 和 c 是环 N 的可交换元素。在实践中,您获得的单位数量可能取决于您选择的 i 和 j,因此您应该进行多次尝试以获得最少的单位。这很重要,因为更多的单位意味着在线性化时会有更多的方程。由于解一组线性方程所需的时间与方程数量的立方成正比,这对计算有很大影响。
回到矩阵方程 RF = FR,并将环元素表示为 a+bi+cj 的形式。 R 的未知元素将具有 x+yi+zj 的形式,其中 x、y 和 z 是未知的可交换环元素。 现在矩阵乘积 RF 的一个项将具有以下形式:

其中 i²、j²、ij 和 ji 将进一步扩展为 1、i 和 j 的线性组合,如 d+ei+fj。当然,实际的展开取决于环的选择以及哪些元素被选择为 i 和 j。
矩阵乘积 FR 中的项也必须进行相同的处理。最终,您将得到 2700 个未知数的 2700 个方程,而不是 900 个未知数的 900 个方程。这将将错误解的数量从 2⁴⁵⁰增加到 2¹³⁵⁰。这对 Emily 来说是个坏消息。错误的解决方案不允许她恢复消息。
16.4.7 弱点
Ғ家族将包括一些弱点,如对角矩阵和三角矩阵,艾米莉可以轻松求逆。这些弱点不应作为密钥使用。在从Ғ中选择矩阵时,请验证主对角线上下至少有一个非零元素。为了快速进行这个测试,只需验证 X[12]、X[13]和 X[23]中至少有一个非零,以及 X[21]、X[31]和 X[32]中至少有一个非零。否则拒绝 X 并重新选择。被拒绝的矩阵的百分比是可以忽略不计的。
16.4.8 加速方法
使用矩阵而不是指数的优势可能还不太明显。从Ғ家族中选择矩阵 S 或 R 需要对生成矩阵 F 进行大幂次运算。这与将大整数求大幂次有何区别或更快?区别在于准备工作。在 Shamir 和 Massey-Omura 方法中,桑德拉和瑞娃必须对对方收到的数字进行大幂次运算。由于他们事先不知道这个数字,所以他们无法做任何准备来加快指数运算。
然而,使用矩阵方法,生成矩阵 F 事先是已知的。桑德拉和瑞娃都可以提前生成一些 F 的幂次,然后保留这个基础矩阵幂集,这样他们就可以通过仅进行 1 或 2 次矩阵乘法来生成新的 F 的幂次。首先,他们可以仅使用 15 次矩阵乘法生成 16 个矩阵 F,F²,F⁴,F⁸,...,F³²⁷⁶⁸的集合。
如果他们只是做到了这一点,那么艾米莉也可以做到同样的事情。她会拥有与桑德拉和瑞娃相同的基础矩阵集,因此她可以轻松确定它们的加密矩阵 S 和 R。为了防止这种情况发生,桑德拉和瑞娃需要随机化他们的矩阵集。他们通过随机选择两个矩阵并将它们相乘来实现这一点。这个乘积将替换基础集中的其中一个矩阵。桑德拉和瑞娃独立地执行这个操作。彼此都不知道对方选择了哪些 F 的幂次。
在设置过程中,应该重复执行这个替换操作很多次,比如 1000 次,这样每个参与方的矩阵集就会彻底随机化。如果 1000 次看起来过多,记住,在 Shamir 方法中使用一个 300 位的素数,每次指数运算将需要约 1000 次乘法和 1000 次模重。桑德拉和瑞娃还需要保留他们矩阵的逆。每次他们将两个 F 的幂次相乘时,他们需要相应地将 F'的幂次相乘,这样他们就永远不需要求逆任何幂次。
此设置步骤,在发送第一条消息之前,只需执行一次。当您拥有这个扩展的生成矩阵集时,您可以通过仅进行一次矩阵乘法和一次其逆矩阵的乘法来生成用于发送消息的矩阵。您随机选择来自基本集的两个不同的矩阵 F^a 和 F^b,相乘得到 F^(a+b),然后将 F^a 替换为 F^(a+b),以便每次生成不同的矩阵。
使用这种技术,我发现矩阵方法对于 30×30 矩阵与 1024 位模数相比,约快 2100 倍,而不论是 Shamir 还是 Massey-Omura 指数方法。
16.5 双侧三步协议
前述矩阵方法中的矩阵乘法可以在左侧或右侧执行,这意味着消息可以被加密为 SM 或 MS。也可以在两侧同时进行乘法。在这种情况下,消息被分成 n²个字符的块,并且有两个独立的 n×n 矩阵的可交换的族,Ғ 和 Ɠ,其生成矩阵为 F 和 G。桑德拉将用来自 Ғ 的矩阵 S 和来自 Ɠ 的矩阵 T 加密消息,而丽娃将用来自 Ғ 的矩阵 R 和来自 Ɠ 的矩阵 Q 进行超加密。
桑德拉向丽娃发送加密的消息 SMT。丽娃进行超加密并发送回 RSMTQ。桑德拉通过使用逆矩阵 S'和 T'去除她的加密,发送 S'RSMTQT' = RMQ 回给丽娃,丽娃使用她的逆矩阵 R'和 Q'来解密,如 R'RMQQ' = M。对于短消息来说,双侧方法不实用,因为其块大小较大,但对于长消息来说,它比单侧方法快得多,因为每个块中有 n²个字符而不是 n 个字符。对于 30×30 矩阵,它可以比单侧方法快 15 倍,因此约比 Shamir 或 Massey-Omura 方法快约 30,000 倍。
艾米莉必须同时解出两个矩阵。让艾米莉拦截的三个矩阵分别称为 X、Y 和 Z,即 X = SMT,Y = RSMTQ 和 Z = RMQ。艾米莉知道 Y = RXQ 和 Z = S'YT'。看起来艾米莉需要解一个大型的二次方程组,而不是解线性或双线性方程。然而,如果这些方程分别乘以 R'、Q'、S 和 T,它们就会变成 R'Y = XQ、YQ' = RX、SZ = YT'和 ZT = S'Y。这些矩阵方程展开后会得到双线性方程。我们在第 16.4.6 节中看到了如何解决双线性方程。
艾米丽可以通过找到 R' 和 Q',或者找到 S' 和 T' 来恢复 M。她可以选择解决这四个方程中的前两个或后两个中的任意一个。让我们继续以 30×30 矩阵的例子,并集中于解决 R'Y = XQ。R' 中有 900 个未知数,Q 中还有 900 个。这个矩阵方程在这 1800 个未知数中提供了 900 个双线性方程。艾米丽还知道 R' 在 Ғ 中,Q 在 Ɠ 中,所以 R'F = FR',QG = GQ。每个方程都产生了额外的 30×29 = 870 个双线性方程。这给了艾米丽总共 2640 个双线性方程,1800 个未知数。通过改变环元素的表示,这些方程可以线性化。
这导致了 7920 个线性方程,5400 个未知数。当方程比未知数多时,系统被称为 过度确定。随着艾米丽减少方程组,多余的方程将被简单地舍弃。也就是说,7920×5400 矩阵的许多行变成了全零。它们可以移到矩阵底部并被忽略。最后,与单边情况一样出现了相同的困难,即存在大量的解决方案。由于双边方程组是过度确定的,它们比单边方程组更强大。另一方面,未知数是两倍多。不清楚哪种方法最终更强大。您可能会选择双边方法,因为它快得多。******
第十七章:密码
本章涵盖
构建密码的思路
尽管在密码、密码机和现在的数字加密方面取得了进步,但军队始终依赖于密码。即使在今天,我们也可以假设军队仍然将密码作为备用,以防电子设备出现故障或电力不可用。
大多数密码将字母、音节、单词或短语替换为固定大小的组,通常是 3、4 或 5 位十进制数字,或者是 3 或 4 个字母的组。可变长度的密码很少见。密码通常分为两种类型,单一密码和双重密码。在单一密码中,单词和短语按字母顺序列出,并且代码组按数字顺序分配,尽管不是连续的,因此可以使用相同的列表查找单词和代码组。这种方法的弱点是显而易见的。如果你的对手已经弄清楚了代码 08452 的含义是 CANNON,那么他们就知道与 08452 接近的任何代码必须有类似 CAMOUFLAGE、CAMPAIGN、CANCEL、CANINE、CANVAS、CAPITAL、CAPITULATE、CAPSIZE、CAPTAIN 等含义。
在双重密码中,代码组是以随机顺序分配的。密码书将包含两个单独的列表,一个按字母顺序列出单词和短语,另一个按数字顺序列出代码组。过去,双重密码需要数月的时间才能编制,并且成本很高。因此,一个政府可能会多年使用相同的代码,从而大大削弱其有效性。自 1960 年代以来,编制双重密码的工作可以在几秒钟内由计算机完成。
密码编制者有很多技巧来使他们的密码更加安全。对于常见的单词和短语,他们会提供许多等效的代码组,或者同义词。因此,海军密码可能有 10 到 20 个代码组代表“ship”,而陆军密码可能有相同数量的代码组代表“artillery”,外交密码可能有同样多的代码组代表“treaty”。密码往往有很多空组。消息的整个部分可能完全为空。某些代码组可能具有多重含义,取决于某个指示器,例如前一组的最后一个数字。
有些密码书是以两列印刷的。根据某个指示器,密码来自左列或右列。例如,如果当前的代码组以偶数数字开头,则从左列取下一个代码组,否则从右列取下一个代码组。
17.1 小丑
小丑 是我自己发明的一种密码风格。如果有读者想要设计自己的密码,小丑可能会给他们一些有用的思路。基本概念是,在每个代码组中,一个字母或数字与其他字母或数字不同。例如,在一个 5 字符组中,4 个字符将携带意义,而另一个字符,称为小丑,存在于此以制造混乱。仅仅有一个空字符就会让对手的工作变得更加困难,但是你还可以用这个特殊的字母或数字做更多的事情。
假设一个 5 位数字组的代码。其中 4 位是代码本身,另一位是小丑。为了开始,假设小丑总是在每条消息中第一个代码组的中间位置。还假设这是一个 2 列代码书,左列的代码与右列的代码完全不同。例如,左列的 0022 可能表示“救援”,而右列的 0022 可能表示“引擎”。
同样,小丑可能有两列含义,因此小丑可以移动到不同的数字位置,也可以移动到不同的列。
这里是您可以为小丑分配的可能含义列表。不止 10 个。您可以选择您想要的 10 个。或者,使用 2 列并为小丑选择 20 个含义。或者,使用字母而不是数字,并为小丑选择 26 个含义。
-
从下一组开始,小丑向左移动 1 个位置。
-
从下一组开始,小丑向右移动 1 个位置。
-
从下一组开始,小丑移动到位置 1。
-
从下一组开始,小丑移动到位置 2,依此类推。
-
仅对于下一组,小丑在位置 1。
-
仅对于下一组,小丑在位置 2,依此类推。
-
切换到代码的左列。
-
切换到代码的右列。
-
切换到代码的相反列。
-
仅对于下一个代码,使用相反的代码列。
-
对于接下来的 2 个代码,使用相反的代码列,依此类推。
-
接下来的组为空。
-
下一组之后为空。
-
接下来的 2 组为空,依此类推。
-
在下一组中,代码为空,但小丑是真实的。
-
在下一组中,代码是真实的,但小丑是空的。
-
交换接下来的 2 组的顺序。
-
在下一组的代码中加上 1111(不进位相加)。
-
在下一组的代码中加上 3030(不进位相加),依此类推。
-
如果下一个代码是偶数,则加上 2222,否则减去 2222(不进位)。
-
在下一组中,将小丑加 1(不进位)。
-
在下一组的小丑中加 2(不进位),依此类推。
-
将这个 4 位代码加到下一个 4 位代码中。小丑除外。
-
反向阅读下一个代码的数字,例如 1075 实际上表示 5701。
-
忽略接下来的代码,直到有一个以 0 开头的代码。
-
下一组是一个特殊指示器。
有关不进位相加的示例,请参见第 4.6 节。
特殊指示器需要更详细的解释。在特殊指示器中,代码组的所有 5 位数字都有特殊用途,比如告诉小丑将在哪里,或者使用哪一列。例如,特殊指示器 13152 可能意味着在接下来的 5 组中,小丑将按顺序出现在位置 1、3、1、5 和 2。特殊指示器还可以告诉接下来的 5 个代码从哪一列取出,奇数表示代码来自左列,偶数表示代码来自右列。特殊指示器 10384 可能意味着在接下来的 5 组中,代码将依次从左、右、左、右和右列中取出。
另一个特殊指示器的用途可能是指定要添加到接下来的 5 组代码中的数字。例如,特殊指示器可能意味着将以下值添加到 4 位代码中:

这些值将使用非进位加法,模 10 加法进行相加。
小丑总是指示接下来的组或组中要采取的行动,而不是当前组或前一组。例如,不应使用意思为“取消前一个小丑”的小丑。当一个小丑指示涵盖几个后续组的行动时,请确保两个不同小丑的行动不冲突。例如,不应该在第 20 组中有一个小丑说,“接下来的 3 个代码取自左列”,然后在第 21 组中有一个小丑说,“接下来的 3 个代码取自右列”。
可以与小丑代码一起使用的另一个技巧是使用字母 A 到 E 代替小丑。这个字母可以出现在任何位置,并取代小丑的预期位置。字母 A 表示下一个小丑将在位置 1,B 表示位置 2,依此类推。您还可以为字母 F、G 和 H 分配含义。例如,F 可以表示代码应从相反的列中取出,下一个小丑将在位置 1。
如果有可能将字母 I 误认为是数字 1,请不要使用字母 I。我喜欢使用字母 J 作为超级小丑。它表示接下来的一切都是空的。您可以继续输入另外 10、20 或 100 组代码的胡言乱语,真的让艾米莉陷入狂喜。或者,您可以使用这些空白来发送一个误导性的虚假消息,比如“诺曼底登陆推迟到 6 月 10 日在犹他海滩进行”。
第十八章:量子计算机
本章内容包括
-
量子计算机的特性
-
使用量子计算机进行通信
-
使用量子计算机进行密钥交换
-
使用量子计算机解决优化问题
-
使用量子计算机解密分组密码
-
超级计算机,超越量子计算机
当我写这本书时,量子计算机还处于萌芽阶段。全世界没有超过 20 台量子计算机,其中没有一台包含超过大约 50 个 qubit 或量子比特。我写这一章时知道其中很多内容可能已经过时,甚至在书发布之前就被证明是错误的。量子力学和量子计算中使用的许多数学远远超出了本书的范围,因此本章的部分内容将简单提及量子方法和算法,而不解释它们的工作原理。
量子计算的基础是量子比特,或qubit。一个 qubit 有两个基态,分别表示为|0〉和|1〉,对应于传统计算机中普通比特的 0 和 1 状态。符号|1〉被称为bra-ket符号。当尖括号在左边时,如〈0|,称为bra,因此〈0|读作“bra-0”。当尖括号在右边时,称为ket,因此|1〉读作“ket-1”。这种符号是由诺贝尔物理奖获得者英国物理学家保罗·阿德里安·莫里斯·狄拉克发明的。
在传统计算机中,普通比特具有明确的值,可能是 0 或 1。该值只能是 0 或 1,不能是某个中间值,也不能同时是多个值,有时是 0 有时是 1。物理设备,如表面上的磁点,可以通过施加电流或磁场从一个值切换到另一个值。可能会有一个短暂的过渡,但设备不能停留在任何类型的中间或混合状态。
18.1 叠加
相比之下,qubit 在进行测量或观察之前没有值。在那时,它的值将是 0 或 1。基态|0〉表示其值为 0 的概率为 1.0,基态|1〉表示其值为 1 的概率为 1.0。一般来说,qubit 将处于两个基态α|0〉+β|1〉的叠加状态,其中α和β是复数,使得|α|²+|β|² = 1。当测量时,这个 qubit 产生 0 的概率是|α|²,产生 1 的概率是|β|²。符号|α|表示α的幅度。复数 a+bi 的幅度是√(a² + b²)。由于测量结果是概率性的,两个处于相同状态的 qubit 的测量结果可能不同。可以叠加任意数量的状态。
当一个量子态 x 由几个量子比特组成,比如 x[1]、x[2]、x[3]时,态〈x|被表示为一个行向量(x̅[1],x̅[2],x̅[3]),其中每个分量上方的横线表示复共轭。如果复数α为 a+bi,则其复共轭α̅为 a-bi。复共轭具有性质,即乘积α**α̅ = a²+b² = |α|²。反之,态|y〉被表示为一个列向量。

由于这个示例中的行向量是一个 1×3 矩阵,列向量是一个 3×1 矩阵,它们可以相乘。矩阵乘积,表示为〈x|y〉,是一个 1×1 矩阵,其单个元素是内积x̅•y。也就是说,〈x|y〉是一个标量。(如果这很陌生,你可以复习第 11.3 节。)
由于任意两个状态可以叠加,并且这些状态反过来又可以叠加,任意量子比特可能处于任意多个状态的叠加中。
叠加态是脆弱的。小的扰动,比如温度波动或机械振动,可以导致量子比特退出叠加态,并回到基态之一。这称为退相干。这种脆弱性是实现大型可靠量子计算机的主要障碍。特别是,当进行测量时,量子比特将退相干并掉入观察到的任一基态。同样,量子比特不能被复制,因为那将需要一个观测。
如果难以理解复数系数的概念,也许这会有所帮助。在笛卡尔坐标中想象点(a,b)。从原点(0,0)到点(a,b)的线段是一个向量。它既有大小又有方向。当两个状态叠加时,根据坐标几何的规则将这些向量相加,这恰好是复数相加的方式。这就是为什么概率被表示为复数的原因。在向量相加后,必须重新调整系数,使|α|²+|β|² = 1。如果α和β用角度描述,则可以消除重新调整,使用角度的三角函数公式描述角度的和与差。
量子比特可以使用一些基本逻辑函数进行操作,以形成量子电路。一个例子是条件非门函数 CNOT,它对 2 比特量子比特|xy〉进行操作。CNOT 定义为|xy〉如果 x = 0,和|xy'〉如果 x = 1。换句话说,第一个比特保持不变,第二个比特是两个比特的异或。
18.2 纠缠
除了叠加之外,粒子还可以显示第二个量子力学属性,称为纠缠。如果一个粒子的某个属性与其他粒子的同一属性之间存在相关性,则称该粒子组为纠缠。例如,电子具有称为自旋的属性。关于特定轴(如 x 轴)的自旋可能在粒子组中是相关的。或者,一组光子的极化可能是纠缠的。即使粒子相距很远,这种纠缠也可能存在。这使得纠缠可以用于通信。
该过程始于创建一对纠缠粒子。一种方法是将激光束通过一种特殊类型的晶体。这导致一些高能光子分裂成两个低能光子。其中一些光子对将是纠缠的,尽管产率非常低,例如十亿分之一。下一步是将这些纠缠光子传输到桑德拉和莉娃将要传输和接收的地方。对于长距离传输,通常的方法是通过光纤传输它们,尽管它们也可以通过晶格中的空腔物理携带。
当桑德拉准备发送她的消息时,她将她的光子与一些特别准备好的称为辅助光子的光子相互作用。这种相互作用导致她的光子采取她希望传输的所需状态。这导致了莉娃的纠缠光子,它可能在数英里之外,采取互补状态。过去人们认为这是瞬时发生的,但是变化是以光速传播的。信息不能瞬间传输,尽管几代科幻作家都幻想过这一点。
最后,莉娃测量她的纠缠光子并确定 1 比特的消息——或者不确定,因为这是一个概率过程。这有时被科学家们称为量子传送,他们读了太多科幻小说。据说这是安全的,因为如果艾米丽测量了光子,它会解缠,桑德拉和莉娃应该可以检测到。
这里存在两个缺陷。(1) 艾米丽可能不在乎她的窃听是否被发现。只要她知道这些信息,桑德拉和莉娃知道她知道可能并不重要。(2) 艾米丽的目标可能不是收集信息;她的目标可能是扰乱通讯。艾米丽可能不会得知秘密作战计划,但莉娃也不会。实际上,如果桑德拉和莉娃发现艾米丽在窃听,他们可能会更少地使用量子链接,这对艾米丽也是有利的。
18.3 错误校正
由于量子事件是概率性的,量子计算机的错误率比传统计算机高得多。必须有一些手段来检测和纠正错误。在经典计算机中,有错误检测和纠正码。这些码使用额外的位来检测差异,例如通过为每个字节添加奇偶校验位来检测错误。奇偶校验位通常是 8 个数据位的异或。这意味着带有错误位的 9 位字节将始终具有偶校验。如果奇偶校验是奇数,那表明发生了错误,但它并不告诉错误是什么。
传统计算机最简单的纠错码形式是 2-3 码。每个位有 3 个副本。如果发生单位错误,两个副本仍将具有正确值。如果单位错误的几率是,比如,10⁷中的 1,那么使用这种常见值将将错误几率降低到 10¹⁴中的 3,这是一个巨大的改进。使用 3 位来表示每个数据位是昂贵的,但有几种类型的码,如海明码和卷积码,使用更少的额外位,其中一些可以检测和纠正多位错误。在当前的加密中,无错误的通信是绝对必要的,即使改变一个位也可能使消息无法阅读。
这种类型的错误检测和纠正在量子计算机中是不可能的。这些码依赖于复制位的值并检查码的奇偶性。这些在量子比特中无法完成,因为测量量子比特的值会导致其退相干。提供量子纠错通常依赖于使用额外的量子比特。错误检测和纠正量子比特可以与数据量子比特交错排列在一个被称为表面码的平面晶格结构中。
到目前为止,量子纠错仅仅是理论上的。还没有人建造出实用的设备。额外的纠错位需求增加了实用量子计算机所需的量子比特数量。由于量子错误率很高,实用量子计算机可能仍然遥不可及。在阅读以下各节中各种量子算法的描述时,请记住这一点。
18.4 测量
测量光子的极化是一件棘手的事情。想一想你如何测量一束光的极化。你通过一个极性滤波器传递光束并观察亮度。然后慢慢旋转滤波器,直到经过滤的光达到最大亮度。在那一点上,滤波器与光束的极化对齐,你可以测量角度。
然而,里瓦没有这样的奢侈。她正在处理一个单光子。它穿过她的滤光片或晶体,要么她检测到闪光,要么没有。如果她的滤光片与桑德拉的发射器不对齐,那么她获得与桑德拉相同状态的几率取决于相对角度。例如,如果她的探测器与桑德拉的发射器呈 90º角度,那么她获得量子位相同值的几率正好是 50%。
解决这个问题的方法是桑德拉发送一串光子。里瓦可以对这些光子进行采样,通过各种滤光片进行传输。她可以通过使用光传感器和电压表测量每个样本的亮度,并计算准确的极化角度。然后她以那个角度进行测量,并以非常高的概率获得与桑德拉相同的基态。利用量子计算机进行密码学可能最终取决于区分极化中微小渐变的能力。
18.5 量子三阶段协议
这为 2006 年由俄克拉荷马州立大学的 Subhash Kak 发明的三阶段量子协议奠定了基础。Kak 的 3 阶段协议使用与第 16.1、16.2 和 16.4 节讨论的其他三次传递算法相同的 3 消息框架。在量子版本中,加密操作是围绕选择的空间轴随机旋转极化。桑德拉和里瓦必须就轴达成一致意见,否则旋转将不会交换。 (1) 桑德拉发送经过她随机角度φ旋转的光子, (2) 里瓦将光子旋转她的秘密角度ψ并发送经过φ+ψ旋转的光子, (3) 桑德拉应用逆旋转-φ并发送经过里瓦角度ψ旋转的光子,里瓦移除以读取量子位。如果艾米丽尝试测量任何旋转的量子位,她无法知道她的探测器是否具有正确的角度,因此也无法知道获得正确值的概率。
使用这种方法,桑德拉和里瓦必须经常改变它们的角度,最好是每个比特都要改变。否则,艾米丽可以随意选择一个随机角度并尝试读取每条消息。如果艾米丽的角度接近正确角度,那么她将在 80%甚至 90%的比特上得到正确值。这足以让她能够读取消息。幸运的话,她将能够读取大约 25%的消息。请注意,艾米丽的角度接近 180º也同样有用,因为这将给她 80%到 90%的比特的逆。
18.6 量子密钥交换
有几种类似于 Diffie-Hellman 密钥交换的量子密钥交换算法。其中最著名的算法是BB84,以其发明者 IBM 研究院的查尔斯·H·贝内特和蒙特利尔大学的吉尔·布拉萨德命名。该算法使用 4 个量子位允许在通信信道中检测和纠正噪声。由 Emily 引起的任何扰动都简单地视为通道中的额外噪声,因此不需要进一步检测或纠正。
这项工作的一个推论是,几个松散纠缠的粒子可以结合成更少数量的紧密纠缠粒子。
18.7 格罗弗算法
格罗弗的 密码算法 是一种使用量子计算机破解诸如 DES 和 AES 这样的秘密密钥分块密码的算法。它由贝尔实验室的洛夫·库马尔·格罗弗在 1996 年开发,基于他的量子文件搜索算法。该算法将加密函数的每次评估都视为对未排序数据库的一次读取访问。该算法将期望的评估次数从 K 减少到 √K,其中 K 是可能的密钥数量。实际上,这将密钥大小从 n 位减小到 n/2 位。
格罗弗算法以很高的概率找到密钥 k,使得 E(k,p) = c,其中 E 是加密函数,p 是明文,c 是密文。该算法需要每个这样的密钥一个已知明文块。一个量子物理学家,可能对密码学知之甚少,可能会得出这样的结论,即对抗格罗弗算法需要将所有加密密钥的大小加倍。这是低效的,因为它会需要额外的块密码轮次。例如,使用 128 位密钥的 AES 使用 10 轮,而使用 256 位密钥的 AES 使用 14 轮。
一个更便宜的替代方法是通过在主加密前后添加一个简单快速的密码步骤,如简单替代,来增加密钥大小。用于混合两个简单替代字母表的密钥可以达到每个 1684 位(5.2 节),因为每个字母表可以有 256! 种可能的排列,接近于 2¹⁶⁸⁴。简单的转位也可以帮助扩展密钥大小,但方式更受限,因为 16! 大约是 2⁴⁴。如果选择使用转位,您可以一次转位两个块,因为 32! 大约是 2¹¹⁸,总密钥大小显著增加。
读者们会意识到,格罗弗算法也可以通过使用空值、为每个块使用不同的密钥、链接块或压缩消息等基本手段来进行打败。这意味着在块加密之前通过混合哈夫曼(4.2.1 节)之类的压缩密码实现两个目标,即更大的密钥和压缩,一举两得。混合哈夫曼的缺点是它改变了块大小。在块密码之前和之后使用哈夫曼替换(10.4 节)或者邮件替换(10.5 节)可能更明智。
18.8 方程式
在我们讨论下一个话题——量子模拟退火之前,我们需要讨论方程式。 许多密码可以表示为方程组。 比拉索密码可以表示为 C = P+K,其中 C 是密文,P 是明文,K 是密钥,都是在模 26 的整数中表示的。 希尔密码是一组线性方程。 像普莱费尔和双平方这样的密码会被表示为基于 5 的方程式。
18.8.1 交换
交换可以很容易地表示为相等集合。 例如,列转置

可以表示为 c[1] = m[1], c[2] = m[4], c[3] = m[7], c[4] = m[2], c[5] = m[5], c[6] = m[3], c[7] = m[6],其中 m[i] 为明文消息字符,c[j] 为密文字符。
逻辑函数可以转换为如下的数值方程:
not x → 1-x
x or y → x+y-xy
x and y → xy
x xor y → x+y-2xy
18.8.2 替换
替换可以通过一个三步过程转换为方程形式。 首先,使用密钥和明文的比特将每个密文比特表示为布尔表达式。 例如,考虑这个替换,它接受一个 1 位密钥 K 和一个 2 位明文 AB,生成一个 2 位密文 XY。
| K | AB | XY | 布尔输入 |
|---|---|---|---|
| 0 | 00 | 01 | K̅A̅B̅ |
| 0 | 01 | 11 | K̅A̅B |
| 0 | 10 | 00 | K̅AB̅ |
| 0 | 11 | 01 | K̅AB |
| 1 | 00 | 10 | KA̅B̅ |
| 1 | 01 | 00 | KA̅B |
| 1 | 10 | 10 | KAB̅ |
| 1 | 11 | 11 | KAB |
这里 K̅A̅B̅ 意味着 K = 0,A = 0 和 B = 0, K̅A̅B 意味着 K = 0,A = 0 和 B = 1,依此类推。 现在可以将密文位 X 写为 X = K̅A̅B+KA̅B̅+KAB̅+KAB。 Y 也有类似的表达式。
18.8.3 卡诺图
卡诺图用于简化或简化这些表达式。 这是第二步。 这个概念是贝尔实验室的莫里斯·卡诺纳于 1953 年发明的。 这个想法是把所有可能的 n 位输入集合看作 n 维空间,2×2×2×...×2。 填充每个输出比特为 1 的单元格。 这是输出比特 X 的空间。 Y 也会有一个类似的图。

注意此地图中的列是如何标记的。 当您从一个单元格移到下一个单元格时,从左到右只有一个位改变,包括从第 4 列到第 1 列的环绕步骤。 这种排列被称为格雷码。 格雷码由贝尔实验室的弗兰克·格雷于 1947 年发明。 通过一次附加一个位轻松构造格雷码。 例如,要将这个 2 位格雷码扩展为 3 位格雷码,首先以顺序列出 4 个 A,B 对 A̅B̅,AB̅,AB,A̅B,每个对应的 C̅,然后以相反的顺序列出每个对应的 C。 C 位只更改两次,第四个代码组后和第八个代码组后环绕到开始。
卡诺图让您通过眼睛优化逻辑达到大约 6 位的水平,3 水平和 3 垂直,使用一个 8 单元格乘以 8 单元格的地图。 超过 6 位最好用程序来做。 每个步骤都要添加最大的矩形块,该矩形块适合填充区域内,并覆盖至少一个尚未被覆盖的新单元格。 块的每个维度都必须是 2 的幂,因此其体积也将是 2 的幂。 如果有几个最大尺寸的块,请选择覆盖尚未覆盖的大多数单元格的块之一。 继续,直到所有填充单元都被覆盖。
在 K,A,B 示例中,填充区域中有两个 1×2 块,即 KA 和 KB̅。 每个都覆盖 2 个单元格。 由于它们一起覆盖 3 个单元格,因此两者都是必需的。 这只留下了单元格 KAB̅ 需要被覆盖。 因此,X 的简化表达式为 KA+KB̅+KAB̅。
将替换这些表达式中的and,or和not函数为算术表达式,遵循先前的规则,作为将替换的第三步。
18.8.4 中间变量
如果您尝试将诸如 AES 这样的复杂分组密码中的每个密文位表示为单个表达式,则该表达式的大小将随每轮呈指数增长。 这个问题有时被引用为你不能使用方程式来破解分组密码的原因。 胡扯。 这个问题可以通过使用中间变量来消除。 让每一轮的输出成为一个单独的变量集。
第一轮的输入,密钥,明文和链向量(s)是独立变量。 这些位中的任何一个都可以独立于其他位变化。 每一轮或每一轮内的每个阶段的输出是相关变量。 这包括下一个块的链向量。 它们的值完全由独立变量的值确定。 不能改变其中一个位而不改变其他变量的一些位。
18.8.5 已知明文
假设 Emily 有一定量的已知明文。为简单起见,假设这是一个 n 位的消息块。她的目标是利用已知的明文和拦截的密文确定密钥。假设 Emily 已经找到了每个密文位的表达式,这些表达式是关于明文、密钥和可能的链向量的。设第 i 位的表达式为 E[i],设 c[i] 为密文的第 i 位。对于任何给定的密钥 K,Emily 可以通过计算对应于使用密钥 K 对已知明文进行加密得到的密文与拦截的密文之间的差异来衡量:

当找到正确的密钥时,D(K) 将为 0。在这里,D(K) 称为目标函数,或简称分数。
18.9 最小化
引入目标函数将找到正确密钥的问题转换为一个最小化问题。目的是最小化函数 D(K) 的值。量子计算机的工作原理是因为系统的量子态总是趋向于最低能量态。如果可以配置量子计算机,使得量子比特或量子比特组表示变量的值,而系统的能量对应于目标函数的值,那么最低能量态将对应于目标函数的最小值。如果可以实现这种配置,那么量子计算机将能够解决各种现实世界的问题,包括破译密码。
起初,用实数替换密钥中的位。最终这些数字必须是 0 或 1,但允许变量在搜索过程中超出 0-1 范围是有利的。从某些初始值开始,例如将所有位设置为 .5,或将它们设置为 0-1 范围内的随机值,然后调整它们的值以减少 D(K) 的值,尝试将其减少到 0。
现在有许多与传统计算机一起使用的优化技术,但让我们只看三种。使用这些算法找到加密密钥将需要大量已知明文。至少已知明文应该是密钥大小的 3 倍。
18.9.1 爬山法
爬山法,也称为最陡下降法或梯度法,是最古老的优化方法之一。其思想是从某一点 P[1] 开始,看看随机方向上的几个等距点。在这些点中,选择改进最大的点 P[2],也就是具有最小 D(K) 值的点。然后通过查看接近 P[2] 的随机点来细化方向。从 P[2] 到任何这些点的距离将远小于从 P[1] 到 P[2] 的距离。将这个点称为 P[3]。从 P[1] 到 P[3] 的线定义了搜索方向。最后,找到这条线上使 D(K) 最小的点 P[4]。搜索重复使用 P[4] 作为起点。随着搜索的进行,从 P[i] 到 P[i+1] 的步长在找到改进时逐渐增加,如果没有改进则减小。
这种搜索形式在搜索空间形状像 n 维空间中的单个山或被许多较小的山丘包围的大中央山时效果很好。在具有许多局部最优解的更复杂地形中,它可能失败得很严重。在这个图中,颜色越深,分数越好。

18.9.2 千峰
千峰,或千峰,是我在 20 世纪 70 年代参加各种谜题比赛中取得胜利的方法。后来,我开始为一些计算机期刊撰写这种搜索方法,但我陷入了试图表征这种搜索方法比其他搜索方法更好的目标函数类型的困境中。这种方法在 20 世纪 90 年代以粒子群优化的名字重新被发现。
想象搜索空间就像是一个有许多峰、谷和山脊的山脉。现在想象一队飞机飞越这片地形,通过降落伞投放数百名登山者。换句话说,有许多同时的起点。这些登山者会查看附近的点,看看这些地点是更高还是更低。有两种变体。(1)你可以选择这些点中最好的一个,并将登山者移动到那里。在这种情况下,如果没有一个点更好,你会减小步长并重试。如果这次失败,比如连续失败 3 次,那么你会引入一个新的登山者,他会从一个随机位置开始。(2)你保留显示改进的几个点。你可以将这看作是登山队分成几个小组尝试不同的路径。最好不要选择所有改进的解决方案,因为这会迅速将所有登山者集中在几个区域。

我最初的想法是将所有解保留在一个堆结构中,以便顶部条目始终是最差的解。你拿到那个最差的条目并尝试改进它。但这被证明是低效的,因为你花了大量的精力去改进最终被丢弃的差解。相反,总是选择最好的解会把所有爬山者都集中在一个单一的高峰上。最佳策略是随机选择下一个爬山者。同样,在一个解产生多个改进解时,不总是选择其中最好的有利。有时,随机选择几个改进解更好。
18.9.3 模拟退火
模拟退火是一种流行的优化技术,主要是因为它很容易实现。你从搜索空间中的一个随机点开始,并查看附近的一个点。如果那个解更好,那么以概率 B 移动到该点。如果那个解更差,那么以概率 W 移动到该点。
模拟退火的定义特征是在搜索过程中改变概率。最初,你设定拒绝好解的机会或接受坏解的机会相当高。比如,你拒绝 40%的更好解,接受 30%的更差解,即 B = .6 和 W = .3。然后在一段时间后,比如 1000 步之后,你会降低拒绝好解的概率。也许在第二阶段,你拒绝更好解的 20%,接受更差解的 15%。再过一段时间,比如再 2000 步之后,你可能只开始拒绝更好解的 10%,接受更差解的 7%。
这个过程被称为模拟退火,因为它类似于金属热处理中的热退火过程,在这个过程中,金属首先被加热直到发光,然后非常缓慢地冷却。这改变了金属的结晶结构,减少了其硬度,增加了其韧性和延展性,使其更容易加工。在模拟退火中,拒绝更好解和接受更差解的高初始概率类似于金属的高温状态,而这些概率的逐渐降低则类似于金属的缓慢冷却。对模拟退火的描述通常提到概率逐步降低的几个阶段称为降温。
让我传授一些我在模拟退火中的经验:
-
过于缓慢是不值得的。每个阶段的接受/拒绝率应该在前一率的 1/2 到 2/3 之间。例如,第一阶段是 40%,然后 20%,10%,5%,3%。或者,从 40%开始,然后 25%,15%,10%,6%,4%,最后 2.5%。
-
通常五个阶段就足够了。
-
以 50%的接受率开始是浪费时间的。从 60%到 75%之间开始。
-
将接受率降到 0% 是得不偿失的。如果最后一个阶段接受了 2% 到 3% 的更差的解决方案,你将获得更大的改进。
-
当什么都不发生时停止。你可能计划在每个阶段进行 1000 次试验,但如果你已经进行了 100 次尝试而没有改变,就停止吧。
-
让百分比取决于改进的大小。例如,在第一阶段,你可以接受改进分数为 1% 的变化的 60%,改进分数为 2% 的变化的 75%,改进分数为 3% 或更多的变化的 90%。
-
实验。每个优化问题都是不同的。尝试改变阶段的数量、每个阶段的试验次数、改变概率的速率、步长和改进程度与接受率之间的关系。
爬山、千山万峰和模拟退火技术可以自由组合,产生各种混合方法。
18.10 量子模拟退火
有几种提议的方法可以利用量子计算机进行模拟退火。这些方法利用量子现象如叠加来并行执行许多搜索。然而,每次试验都需要在选择的点上评估目标函数。量子计算机不适用于评估表达式。到目前为止,尚无方法可以通过量子手段并行评估这些函数。量子计算机可以利用传统计算机来评估表达式,但这将失去并行性。到目前为止,量子搜索还没有显示出比传统计算机搜索更快的改进。
18.11 量子因式分解
RSA 公钥密码系统的强度取决于大整数因式分解的难度。给定两个大整数 A 和 B,将它们相乘得到乘积 AB 是很容易的,但要反向执行这个过程并确定大整数的因子则非常困难。对一个大数进行因式分解的难度与计算离散对数(第 16.3 节)的难度相同,并且使用许多相同的技术。
这种安全性可能会被用于因式分解大数的 Shor 算法突破。这是第一个量子算法,由 MIT 的 Peter Shor 在 1994 年发明。如果该算法能够成功地用于大整数,那么 RSA 必须被放弃,或者模数必须变得更大,也许是数百万位。到目前为止,使用 Shor 算法,2001 年将数字 15 因式分解为 3×5,2012 年将数字 21 因式分解为 3×7。按照这个速度,我们可以期待到 2023 年左右将数字 35 因式分解为 5×7。
开个玩笑,Shor 算法对 RSA 安全性的真正威胁可能要几十年后才会出现。
18.12 超级计算机
量子计算机并不是为了评估表达式而制造的——至少目前不是。但让我们假设这只是一个技术问题。假设将来会有混合计算机,结合了超级计算机的计算能力和量子计算机的并行性。让我们称这些为超级计算机。
桑德拉今天可以做些什么来为艾米莉拥有超级计算机的时代做准备?我们可以从我们击败格罗弗算法的方式中获得启示(第 18.6 节)。我们扩大了密钥的大小,超过了算法的能力。这在超级计算机上也是可行的。我们可以增加计算机需要处理的未知数的数量,超出您估计超级计算机可能具有的任何能力。让我们看看这两个方面,替换和随机数生成。
这些算法将需要极其庞大的加密密钥。让我们简单地接受,在未来存在超级计算机的世界中,这样巨大的密钥将是可管理的。
18.12.1 替换
如果一个替换没有通过某种数学规则定义,那么它可以通过一个替换表来定义。表中的每个条目是桑德拉知道但艾米莉不知道的值。每个表条目可以被视为数学意义上的一个变量。最初,每个变量可以取任何值。如果艾米莉学到了其中一些值,那么对其他变量的选择就会变得更加狭窄,但最初任何字符都可以替换为任何其他字符。
桑德拉的目标是压倒超级计算机的能力。一个通用的多表密码手动使用 26×26 的表格,但计算机使用 256×256 的表格。这提供了 2¹⁶,或者 65,536 个未知值。然而,并没有理由限制表格中的行数为 256。如果艾米莉有一个超级计算机,那么桑德拉也有一个速度快、内存大的计算机是合理的。桑德拉可以使用 1024 行带有 10 位密钥的表格,或者使用 4096 行带有 12 位密钥的表格,甚至使用 65536 行带有 16 位密钥的表格。这需要 2²⁴ = 16,777,216 字节的内部存储空间用于替换表,远远在当前个人计算机的容量范围内。此外,对于 8 位替换使用 16 位密钥提供了非常理想的冗余性。让我们称这个 2²⁴元素的表格为Tab24。Tab24 的每一行都有自己的混合密钥。如果这个混合密钥有 256 位,那么整个表格就有 256×65536 = 16,777,216 位密钥。
对于桑德拉来说,使用完整的双字母频率表也是可行的。一个 256×256 的双字母频率表,使用 8 位密钥选择一行(实际上是一层),需要 2²⁵ = 33,554,432 字节的内部存储空间。同样,这在今天是可行的。如果表格有 65536 层和 16 位密钥,那么将需要一个更大的计算机。
但请记住,这些替换表必须保密,并且必须是完全随机的。即使它们是由某种算法生成的,也必须绝对超出艾米莉的超级计算机确定生成器的初始状态和参数的能力。请参阅第 13.13 节了解一些相关方法。
18.12.2 随机数
第 13.13 节的方法是一个很好的起点,但要制作一个能经得起超级计算机考验的伪随机数生成器,我们将第 13.11 节的选择生成器概念与第 13.15 节的刷新生成器技术相结合。
超级生成器 UG(发音为 HUGE-ee)使用三个数组,A、B 和 C。数组 A 和 B 各包含 65,536 个条目,每个条目都是 24 位整数。数组 C 包含 2²⁴,即 16,777,216 个条目,每个条目都是 8 位整数。这 3 个数组可以从自然照片中初始化,如第 13.14.2 节所述。桑德拉和里瓦必须有相同的数组。生成器在每个周期中产生一个 8 位输出。第 n 个周期包括以下步骤:
-
计算 x = (A[n]+A[n-103]+A[n-1071]) mod 16777216,并将 A[n]替换为 x。
-
减少 x = x mod 65536,并设置 y = B[x]。
该周期内 UG 生成器的输出是 C[y]。
-
将 B[x]替换为(B[x]+B[x-573]+B[x-2604]) mod 16777216。
-
将 C[y]替换为(C[y]+C[y-249]+C[y-16774]) mod 256。
下标根据需要在模 65536 或模 16777216 下循环。103、1071、...、16774 这些滞后值并没有什么特别之处。我没有测试这些值是否产生特别长的周期。有了如此巨大的种子数组,即使是退化周期也会非常长。你可以使用第 13.1 节的任何组合函数,比如madd,或者第 13.14.1 节的滞后线性加法。
当你刷新这些随机数时,第 13.14 节的两种方法在你的对手拥有超级计算机时不足以使用,但它们可以结合起来制作一个强大的刷新函数。每次刷新时,你将需要一个包含 65,536 个或更多 24 位整数的新随机数组 R。让 A、B、C 和 R 的长度分别为 L[A]、L[B]、L[C]和 L[R]。

这里 a = ⌊L[C]/L[R]⌋-1。符号⌊L[C]/L[R]⌋,读作“L[C]/L[R]的底”,表示不超过 L[C]/L[R]的最大整数。例如,⌊8/3⌋是 2,⌊9/3⌋是 3。使用 C[an]而不是 C[n]的效果是将 R 的字节均匀分布在 C 数组中。

这两个步骤应该重复 3 次或更多次。如常,下标循环。
顺便说一句,C 数组的大小不一定必须是 2 的幂。L[C]可以是,例如,77,777,777,这种情况下 A、B 和 R 数组需要包含模 77777777 的整数,而模 16777216 将在上述计算中被 77777777 替换。对于 L[C]的大小的唯一限制是您希望使用的存储量以及分发如此大密钥的实际情况。
这两种技术,替换和随机数生成,可以结合起来制作任意数量的块和流密码,可以抵御超级计算机。接下来的两节介绍了每种类型的一种密码。
18.12.3 超替代密码 US-A
写这一节时的一个巨大诱惑是指定一个巨大的块大小,比如 65,536 甚至 16,777,216 字节。然而,仅仅因为在超级计算机时代加密必须改变,并不意味着消息的类型会改变。少于 100 个字符的消息仍然很常见,将这样的消息填充到 65,536 字节或更大的块大小将是极其低效的。
让我们将样本超替代密码称为US-A。US-A 密码以 32 字节或 256 位的块为单位运行。每个块中的 32 字节交替地被视为 32 个单独的字节和一个 16×16 位的位数组。US-A 密码有 15 轮,每轮包括 3 个步骤:替换、行置换和翻转数组。15 轮后跟着最后的替换步骤。
16 个替换步骤使用 Tab24 替换表,每个字符需要 16 个密钥位,每轮总共需要 16×32 = 512 位,或者 15 轮加上最后的替换需要 8192 位。每个 15 轮中的第二阶段是对每一行进行置换。这可能只是行的循环移位,每行只需要 4 位,因此每轮需要 64 位,总共 960 位。
对于位置换的更强选项是拥有一个置换表,比如 256 个不同的置换,比如密钥置换(第 7.6 节)。16×16 位矩阵的每一行将被单独置换。每行置换将由 16 个十六进制数字指定,比如5A3F1E940B2D68C7,意味着第一个位将移到位置 5,第二个位移到位置 A,即 10,依此类推。每行的置换将由一个 8 位密钥从表中选择,每轮需要 8×16 = 128 位,或者 15 轮总共需要 1920 位。
每轮的第三阶段是翻转位数组,即交换(i,j)处的位和(j,i)处的位。这在第 11.7 节中有描述,并且在第 11.2.3 节中给出了翻转数组的快速方法。这个阶段没有密钥。
让我们将所有 3 个阶段结合起来。US-A 密码需要 8192 位用于替换密钥,以及,比如说,1920 位用于密钥转置,总共是 10,112 位密钥。这远远不足以抵御超级计算机所需的 65,536 位。不用担心。别忘了,替换使用了 Tab24 表格,为了混合其 65,536 行,使用了 16,777,216 位密钥,更不用提用于混合置换表的比特数了。
为了额外的强度,我建议使用明文到明文(模式 PP)分块链接(第 11.10 节)与 US-A 密码。
18.12.4 超流密码 US-B
第 18.11.1 节的 Tab24 替换和第 18.11.2 节的伪随机数生成器可以结合起来制作一个强度极高的流密码。称其为US-B密码。US-B 在加密之前使用一个预处理步骤使明文具有随机外观。假设消息为 M,其长度为 L[M]。预加密步骤为

额外的 16 次循环迭代用于对消息的前 16 个字符进行双重哈希处理。这一步骤并不增加密码强度,但却使 Emily 很难辨认出她找到了正确的密钥。
每个 16 位字符密钥 K[n] 由随机数发生器生成的两个连续输出字节 x 和 y 组合而成,即 256x+y。(或者,你可以将 C 数组设为 16 位整数,但这会使所需存储空间翻倍。)密钥 K[n] 被用来在 Tab24 替换表中对消息字符 M[n] 进行加密,形式为 Tab24(K[n],M[n])。也就是说,M[n] 的替代字符取自表格的第 K[n] 行。
你可能会认出这是使用大型表格和随机密钥的通用多字母密码。请记住,法国人称多字母密码为不可破译的密码。使用 UG 超生成器,US-B 多字母密码最终在超级计算机时代也是不可破译的。我们已经实现了不可破解的加密。
附录 A:娱乐页面
这个图表中有四个独立的密码,从 S1 到 S4。每个密码都是一个简单的单表替换。你的任务是识别类型,比如摩斯码,然后解决它。每个密码都以标准英文书写,使用大写字母,不带空格或标点符号。每个密码长度介于 75 到 90 个字母之间。所有密码都从左上角单元格开始。前 3 个密码从左到右跨越行读取。最后一个密码按照顺时针方向沿着边界读取。

所有方法都在这本书中描述了。唯一的区别是视觉呈现方式。你需要确定每个密码中哪些特征是相关的,比如高度、宽度、位置或颜色。你可以按照本书其他地方隐藏的说明提交你的答案以获取学分。
这里有一些额外的有趣密码,使用了一些最流行的业余爱好者密码。这些密码是标准英文,带有一些专有名词。按照惯例,字母被分组为五个,不论周期。如果你想要更多类似的密码,可以考虑加入美国密码协会,网址为cryptogram.org。你可以按照本书其他地方隐藏的说明提交你的答案以获取学分。你可以在www.contestcen.com/crypt.htm找到更多要解决的密码。
F1:Belaso 密码(第 5.8.1 节)

F2:维吉尼亚密码(第 5.8.2 节)

F3:栏式置换(第 7.2 节)

F4:Playfair 密码(第 9.2 节)

F5:Bifid 密码(第 9.6 节)
区块大小为 7,主题是园艺。

F6:一次性密码本(第十四章)
对于消息中的每个字母,都生成一个随机数。如果这个数字是偶数,就对字母加上 X 对 26 取模,否则对 Y 对 26 取模。

当然,一次性密码本不是一种业余爱好者密码。我把它包括在内是为了说明一些一次性密码本密码在实践中是可以被破解的。你能看出如何找到 X 和 Y 的值而不尝试所有 676 种组合吗?
F7:通用多表密码(第 5.9.3 节)
为了增加乐趣,还有来自几种语言的字符,并且使用了超过 26 个字符。然而,每个字母表只包含了 26 个不同的字符,并且消息是标准英文。

附录 B:挑战
这些密码图被呈现给读者作为挑战。 方法未给出。 您的任务是确定方法并解决密码图。 提供了足够的材料,以便已确定方法的有经验的业余爱好者可以解决它。 在所有情况下,语言都是英语。 文本读起来正常且符合语法。 没有特别努力来扭曲标准英语字母频率或联系频率。
这些都是单步密码。 没有混合方法,比如将替换与置换相结合。 这些挑战密码被评为三级。
C1: 挑战 #1
这是一种纸笔密码。 明文由 250 个大写字母组成,没有单词间隔或标点符号。

C2: 挑战 #2
这个密码可以手工解密,但使用一些计算机辅助来管理十六进制表示会更容易。 明文由混合大小写的 200 个字符组成,带有单词间隔和标点符号。

C3: 挑战 #3
这个密码可以手工加密和解密。 明文由 180 个大写字母组成,没有单词间隔或标点符号。

第十九章:总结
这本书介绍了大约 140 种不同的密码,以及无数的变体。这可能会使一些读者困惑。他们可能只想知道一件事:“对我来说什么是最好的密码?”这个问题很复杂,因为这本书是为如此广泛的读者群体而设计的。在这个结语中,我希望提供一些有用的答案。
儿童:这里有几种儿童可以理解和使用的密码。他们可以使用简单的替换密码,尤其是凯撒密码。儿童特别喜欢字母被图片或符号替换的密码,比如🙂☽♡⚇⚓🎾🧙☼◈☆。儿童也喜欢路径置换。青少年可能会喜欢列置换和贝拉索密码。
爱好者:爱好者可能会喜欢与朋友交换密码,挑战彼此解密。最适合这样做的密码是简单替换、多表替换、自动密钥、流动密钥、Playfair、双密码、对角双密码、三密码、双方密码、路径置换、列置换、巴泽里斯和分数莫尔斯。
我鼓励爱好者加入美国密码协会,www.cryptogram.org,在那里他们可以提交他们的密码供其他会员解决,并解决其他会员提交的密码。他们的网页www.cryptogram.org/resource-area/cipher-types/列出了他们接受的密码类型。
开发者:想要开发或发明自己的密码的人会在这里找到许多方法,这些方法可以以无数种方式组合。字母可以被其他字母替换,或者被固定长度或可变长度的比特组、莫尔斯符号、任何数制的数字或数学环的元素替换。所有这些都可以进行置换和重新分组。组可以再次被替换、压缩、乘以大整数或矩阵,转换为其他数制,或者链接在一起。一些组的部分可以用来加密其他组的部分。
加密服务提供商:提供加密通信服务的公司通常使用自己的专有算法。他们可以使用开发者刚列出的任何技术,但他们必须确保他们的密码符合第十二章的所有标准。密码应该有大块和长密钥。它应该是高度非线性的,具有良好的扩散和饱和度。
如果服务提供商使用标准算法如 3DES 或 AES,那么标准密码应该在前后都加上一个有密钥的秘密替换或秘密置换。
银行业务:银行和金融公司被要求在所有通信中使用 AES,以便它们可以相互之间以及与美联储、证券交易委员会、国税局和其他政府机构进行信息交换。银行还广泛使用公钥密码学来建立加密密钥以及进行身份验证和验证。
军事和外交:美国军方和国务院根据 NSA 规定被强制使用 256 位 AES。这具有法律效力。这在个人电脑、笔记本电脑甚至带有 AES 芯片或 AES 软件的智能手机上完成。然而,军方和情报机构在可能计算机和手机无法工作的地方和条件下操作,或者一个配备 AES 的手机可能会引起怀疑或违法。在许多国家,拥有任何形式的密码设备、文献或工作成果都是非法的。此外,外国军队和外交团体可能会对来自 NSA 或受 NSA 监管的供应商的任何 AES 硬件或软件表示不信任。
由于这些原因,军队和情报机构都备有代码和密码来支持他们的电子加密设备。适用于战斗条件的手写密码包括对角线双字母密码、TwoSquare+1、Two Square ripple 和 Playfair TwoSquare。另一个想法是使用双字母密码或 Two Square,然后是逐块置换。
大文件:对于非常大的文件,使用流密码比块密码要快得多。您可以生成一系列伪随机数,并将其与数据文件组合以模拟一次性密码本。您可以使用 Xorshift、FRand 或 Gen5 进行 PRNG,并且可以使用xors、adds或poly进行组合功能。或者,您可以同时使用 GenX 进行生成和组合。


浙公网安备 33010602011771号