TextbookRSA 1.0.1

TextbookRSA 1.0.1

Tomás Silveira Salles 维护。



TextbookRSA

RS 加密的一个教科书级实现,用于教学目的。

不要使用此框架进行实际的加密!

Platforms License CocoaPods compatible Swift Package Manager compatible

TextbookRSA 是一个用 swift 编写的框架,旨在为初学者提供一个(非常)简化和易于理解的 RSA 加密实现。除此之外,它还包含了一个“通过周期查找器解密”的实现,这展示了如果有一个快速的周期查找器(例如有 Shor 算法实现的量子计算机),RSA 加密可能会被破解。

RSA 加密最重要的方面之一是公钥的 长度。现代标准要求 2048 位或更多,而使用 1024 位加密仍然在使用中,但略有缺点,使用 512 位已被认为相当危险。在这个框架中,密钥长度从不超过 32 位,所以我要再次强调:不要使用这个框架进行实际世界的加密!密钥之所以这么短,是因为我们不希望实现“大整数”类型(我们只是使用现有的类型 UIntUInt32)。大整数算术可能非常有趣,但它不是 RSA 加密的概念性部分,而我们在这里的目标是关注基础。

ECB

RSA 加密被称为 非对称公钥 加密。它独立加密 (简单地说就是整数),这些块必须小于公钥。特别地,块的大小有限意味着我们只能通过 RSA 发送非常短的消息。

遗憾的是,如果这个框架只能加密一些单个、微小的数字,那么它可能会相当无聊。为了让用户能够加密任意消息,我们添加了一个更高级的协议,称为电子密码簿(ECB)。这是一个分组密码方案的形式,其中原始消息被简单地切割成更小的块(块),然后单独加密这些块。

同样,这只是为了使框架的使用更加有趣和触手可及,但对于实际应用来说却被强烈反对。在分组密码方案中使用RSA通常是一个糟糕的主意,它既低效又过时,甚至在其他加密协议中,ECB也被认为是一个糟糕且过时的选择。然而,它却是理解起来最简单且实现起来最简单的一种。

Alice想要向Bob发送一条秘密消息

让我们通过一个典型的RSA交换过程来演示,并使用我们的框架来阐述每个步骤。

步骤0:选择我们想要使用的实现

目前《RSAProtocol》的唯一实现是《UIntRSA》,因此我们可以从一些代码糖开始

typealias RSA = UIntRSA

步骤1:Bob生成并保存他的密钥

let keys = RSA.Keys()

keys对象包含私钥,即公钥的两个素数因子。它是CustomStringConvertible,因此您可以打印出来,并且它是Codable,所以Bob可以轻松地生成一个JSON文件来将密钥存储在他的计算机上的某个位置

let keysJSON = try JSONEncoder().encode(keys)

// ... store `keysJSON` (type `Data`) somewhere (safe) on the computer.

步骤2:Bob生成加密参数并将其发送给Alice

let encryptionParms = keys.generateEncryptionParameters()

这些参数包含公钥(作为成员modulo)和一个加密指数。同样,它们也是CustomStringConvertibleCodable,所以鲍勃可以生成一个JSON文件并将其发送给爱丽丝(因为这些参数是公开的,所以可以使用任何安全的通信渠道)

let encryptionParmsJSON = try JSONEncoder().encode(encryptionParms)

// ... send `encryptionParmsJSON` to Alice via e-mail/SMS/smoke signals...

步骤 3:爱丽丝加密她的消息并发送给鲍勃

爱丽丝收到鲍勃的(公开)消息,该消息作为JSON文件包含加密参数,并将其再次转换为RSA.TransformationParameters对象

let encryptionParmsJSON = Data(/* ... get the JSON data sent by Bob ... */)
let encryptionParms = try JSONDecoder().decode(
    RSA.TransformationParameters.self, from: encryptionParmsJSON)

现在,爱丽丝可以使用加密参数来加密她的秘密消息。如果她的消息是一个任意文件,即一系列字节,她可以加密一个类型为Data的对象

let message = Data(/* ... get data from a file ... */)
let encryptedMessage = Encrypter.encrypt(message, parameters: encryptionParms)

另一方面,如果爱丽丝只是想加密一个文本字符串,她可以使用接受一个String参数的便利重载

let message = "Hi, Bob. The code for my safe is 1234."
let encryptedMessage = Encrypter.encrypt(message, parameters: encryptionParms)

对象encryptedMessage的类型为Encrypter.EncryptedData。它不仅包含加密结果,还包含加密参数的一部分(即指数)。这一点很重要,因为鲍勃可能会使用相同的密钥进行许多对话,与许多不同的人,但是为了每条信息,他应该生成新的加密参数,并且他需要知道哪些参数对应于哪些信息,以便最终解密它们。

同样,此类型是CustomStringConvertibleCodable,因此爱丽丝可以轻松地将她的加密消息(这是公开的)发送给鲍勃

let encryptedMessageJSON = try JSONEncoder().encode(encryptedMessage)

// ... send `encryptedMessageJSON` to Bob via e-mail/SMS/smoke signals...

步骤 4:鲍勃解密爱丽丝的消息

首先,鲍勃需要将收到的JSON数据再次转换为Encrypter.EncryptedData对象

let encryptedMessageJSON = Data(/* ... get the JSON data sent by Alice ... */)
let encryptedMessage = try JSONDecoder().decode(
    Encrypter.EncryptedData.self, from: encryptedMessageJSON)

他还需要他的密钥,这些密钥存储在某处的一个文件中

let keysJSON = Data(/* ... get the JSON data for the keys from a file */)
let keys = try JSONDecoder().decode(RSA.Keys.self, from: keysJSON)

使用这些密钥,鲍勃可以初始化一个Decrypter

let decrypter = Decrypter(keys: keys)

最后,鲍勃可以解密爱丽丝的消息。基本方法将消息解密为Data对象

let message = decrypter.decrypt(encryptedMessage) // `message` is of type `Data`

如果他们(公开地)同意爱丽丝会发送一个文本消息,鲍勃可以使用便利方法decryptText,该方法返回一个String

let message = decrypter.decryptText(encryptedMessage) // `message` is of type `String`

艾芙试图解密爱丽丝的消息

与大多数RSA教科书介绍一样,我们假设一个名为Eve的监听者一直在监听对话,并希望仅使用公开信息(即不知道公钥的素数因子)来解密Alice的消息。一种理论上可以做到的方法是,如果Eve有一个快速的模指数化的周期预言机。

为了更精确,给定正数m(加法群的阶)和b(指数运算的底数),考虑函数f(x) = b^x (mod m)。如果bm互质(没有公共的非平凡因子),那么这个函数有一个周期。也就是说,存在一个正数r,使得对所有x,有f(x) = f(x + r)。这个周期是非常难以找到的,如果有人找到了快速计算它的方法,RSA就处于严重危险之中(以下将会显示)。

在我们的框架中,我们实现了类PeriodOracle(实际上是一个具有静态方法的enum),它使用“暴力”方法(即仅计算f(1)f(2)f(3)...直到值开始重复)计算模指数化的这样的周期。这非常慢,在实际操作中只能用于处理小数字。有更多的先进算法用于计算周期,但即使最快的算法在面对有数千位数的公钥时也是无用的。

PeriodDecrypter是对DecrypterProtocol的第二个实现(第一个是类Decrypter),它使用PeriodOracle来解密消息,而不必知道私钥。如何实现以及为什么它工作的理论超出了本文档的范围。我们只想显示如何使用此框架。以下是Eve使用PeriodDecrypter的方法:

// Listen to public information being sent between Alice and Bob:
let encryptionParmsJSON = Data(/* ... get the JSON data for the encryption parameters ... */)
let encryptedMessageJSON = Data(/* ... get the JSON data for the encrypted message ... */)

// Convert JSON data into objects from the framework:
let encryptionParms = try JSONDecoder().decode(
    RSA.TransformationParameters.self, from: encryptionParmsJSON)
let encryptedMessage = try JSONDecoder().decode(
    Encrypter.EncryptedData.self, from: encryptedMessageJSON)

// Initialize a decrypter:
let decrypter = PeriodDecrypter(publicKey: encryptionParms.modulo)

在此之后,解密工作与Decrypter类型完全一样,即基本方法解密为Data

let message = decrypter.decrypt(encryptedMessage) // `message` is of type `Data`

便利方法decryptText更进一步,将数据转换为String

let message = decrypter.decryptText(encryptedMessage) // `message` is of type `String`

重要:记得我们说寻找周期是非常难的吗?如果你尝试使用具有大公钥的PeriodDecrypter,计算可能需要一天、一年或数千年。即使使用我们高达32位的微小公钥,也需要花费很长时间。为了使你能够测试基于周期的解密,我们在类UIntRSAKeys中添加了一个静态方法small(maxPrime: UInt32)。使用此方法,你可以指定公钥素数因子的上限。100的上限似乎可以得到相当快的测试。你可以决定多高,所以当你想使用基于周期的解密运行测试时,请确保替换Bob初始化键的行,如下所示:

let keys = RSA.Keys.small(maxPrime: 100)

安装

除了手动克隆存储库并按需使用/修改源文件外,我们还支持通过CocoaPods和Swift包管理器进行安装。

CocoaPods

要将 TextbookRSA 安装为 pod,请将以下行添加到您的 Podfile 中并运行

pod 'TextbookRSA', '~> 1.0.1'

$ pod install

如果您不熟悉 CocoaPods,您可以在 这里 了解有关 CocoaPods 的所有信息。

Swift Package Manager

要通过 SPM 安装 TextbookRSA,请打开 Package.swift,将依赖项

.package(url: "https://github.com/imagineon/TextbookRSA.git", from: "1.0.1")

添加到您的 package 常量中,并将依赖项

"TextbookRSA"

添加到应该使用此框架的每个目标中。然后运行

$ swift build

如果您不熟悉 SPM,您可以在 这里 了解有关 SPM 的所有信息。

许可证