CryptoKit框架详细解析(二) —— CryptoKit使用入门简单示例(一)

版本记录

版本号 时间
V1.0 2020.08.01 星期六

前言

CryptoKitiOS13的新的SDK,接下来几篇我们就一起看一下这个专题。感兴趣的可以看下面几篇文章。
1. CryptoKit框架详细解析(一) —— 基本概览(一)

开始

首先看下主要内容:

密码学(Cryptography)是保护用户数据的关键。 本教程向您展示如何使用Apple的新CryptoKit API来验证或加密应用程序的数据,内容来自翻译

接着就是下面的写作环境:

Swift 5, iOS 13, Xcode 11

下面就是正文了

如果您的应用程序需要的内容超过Apple的默认硬件和软件保护,则Apple的新CryptoKit API使您能够对应用程序发送和接收的数据进行身份验证和加密。

在本文中,您将使用对称密钥(symmetric key)和公用密钥加密技术(public key cryptography)对数据进行身份验证和加密。 您将了解何时以及如何使用:

  • Cryptographic hashing
  • Hash-based Message Authentication Code (HMAC)
  • Authenticated Encryption with Associated Data (AEAD) ciphers
  • Public key cryptography with elliptic curves (ECC)
  • Digital signatures
  • Key agreement

继续阅读以解锁所有秘密!

本教程假定您熟悉J.K撰写的《哈利波特》系列。 罗琳还是没有兴趣阅读它。 它讨论了最近几本书中揭示的秘密。

在启动starter文件夹中打开,构建和运行SecretKeeper项目。

这个应用程式列出了伏地魔的魂器 Voldemort’s horcruxes。只要他的灵魂的一部分在这些物品之一中是安全的,伏地魔(Voldemort)就不会被杀死。因此,他必须对所有人,尤其是阿不思·邓布利多和哈利·波特,保持自己身份和位置的秘密。


Protecting Users’ Data

就像Voldemort的秘密一样,您的用户数据也需要保护,以防止意外或恶意破坏以及未经授权的使用。 iOS在Foundation / NSData,Security / KeychainCloudKit中已经具有很多内置或易于使用的安全性。如果您的应用访问HTTPS服务器,则可以免费获得TLS加密和数字签名。如果您的应用需要验证数据或验证发件人,那么现在有了CryptoKit

您需要在以下三种状态的每一种中保护数据:

  • Data in motion - 动态数据:传输中,通常通过网络
  • Data in use - 正在使用的数据:在内存中
  • Data at rest - 静态数据:存储在磁盘上,未使用

传输数据(Data in motion)是进行加密的最初原因,可以追溯到凯撒密码 Caesar cipher向凯撒将军发送书面命令之前。如今,如果您的应用程序使用TLS 1.3与服务器通信,则加密由传输层安全性Transport Layer Security(TLS)处理。但是您可能仍然需要使用加密哈希和键签名对数据和发送方进行身份验证。本教程的大部分内容与这些主题有关。

使用中的数据(Data in use)必须受到用户身份验证的保护。要限制何时可以执行操作,请使用本地身份验证(Local Authentication )来检查用户何时以及如何进行身份验证。例如,您可能要求用户使用生物识别技术(Face ID or Touch ID)进行身份验证,以确保用户在场。

静态数据(Data at rest )通过Data Protection API在设备上受到保护。设置设备密码后,用户即可获得自动软件数据保护。每个新文件都会获得一个新的256位加密密钥,该密钥特定于文件的保护类型。共有三种文件保护类型:

  • Protected Until First User Authentication - 在首次用户身份验证之前受保护:默认文件保护类型。设备启动时无法访问该文件,但是直到设备重新启动后,即使设备已锁定,也可以访问该文件。
  • Complete - 已完成:仅当设备解锁后才能访问该文件。
  • Complete Unless Open - 除非打开,否则完成:如果设备锁定时文件已打开,则仍然可以访问。如果设备锁定时文件未打开,则只有在设备解锁后才能访问该文件。

当设备锁定以允许网络传输继续时,您可能需要允许访问文件。

您的应用程序还可以将加密数据存储在私有CloudKit数据库中,该数据库可在所有用户设备上使用。

1. Increasing Protection for Voldemort’s Secrets

SecretKeeper从文件读取以创建魂器(horcruxes)列表。 该应用程序写入此文件时没有文件保护选项:

try data.write(to: secretsURL)

这意味着秘密文件仅具有默认的文件保护,因此在应用程序处于后台甚至锁定状态下都可以访问该文件。

Voldemort的机密需要更高级别的文件保护。 在ContentView.swiftwriteFile(items :)中,用以下这一行替换data.write(to :)语句:

try data.write(to: secretsURL, options: .completeFileProtection)

使用此级别的保护,仅当设备解锁后才能访问该文件。

2. Keychain and Secure Enclave

您的应用程序应在本地或iCloud钥匙串中存储加密密钥,身份验证令牌和密码(encryption keys, authentication tokens and passwords)。苹果公司的示例应用程序在钥匙串中存储CryptoKit密钥Storing CryptoKit Keys in the Keychain显示了如何将CryptoKit密钥类型P256P384P521转换为SecKey,并将其他密钥类型转换为通用密码。

2013年底以来发布的iOS设备(iPhone 5S,iPad Air和更高型号)均采用Secure Enclave芯片。 Secure Enclave是一个专用的加密引擎,与处理器分开,并在工厂融合了设备的Unique IDentifier (UID) 256位加密密钥。 Secure Enclave还存储TouchIDFaceID的生物特征数据。

Secure Enclave中的密钥和数据永不离开。它们永远不会加载到内存或写入磁盘,因此受到了完全保护。您的应用程序通过邮箱与Secure Enclave通信,您可以在其中存储要加密或解密的数据,然后检索结果。

CryptoKit使您的应用程序可以直接在Secure Enclave中创建用于公共密钥加密的密钥。本教程结尾处有示例代码。


Using CryptoKit

所有这些内置的数据保护可能会满足您的应用需求。或者,如果您的应用程序使用第三方加密的数据或验证文件传输或财务交易,则可能需要使用CryptoKit

1. Rolling Your Own Crypto: Don’t

数据安全是密码学家和攻击者之间的战场。除非您是密码学家,否则编写自己的密码算法会对用户数据造成巨大风险。有许多针对不同平台的加密框架。现在,您有了Apple的CryptoKit,可以非常轻松地在应用程序中使用加密。

2. Performance: Don’t Worry

性能如何? CryptoKit建立在Apple本地加密库corecrypto的基础上。 Corecrypto的手动调整汇编代码可以高效利用硬件。

3. Cryptographic Hashing

现在介绍密码学(cryptography)的最基本形式。您可能熟悉对字典项或数据库记录进行哈希处理以提高检索效率的想法。许多标准类型都符合Hashable协议conform to the Hashable protocol。将这些类型的对象哈希到哈希器Hasher中会产生具有合理唯一性的整数哈希值。输入的较小更改会导致哈希值发生较大更改。

Hasher使用随机生成的种子值,因此每次您的应用运行时,它都会产生不同的哈希值。亲自看看这个。

在起始文件夹中打开CryptoKitTutorial.playground。第一部分,Hashable Protocol,具有以下hashItem(item :)函数:

func hashItem(item: String) -> Int {
  var hasher = Hasher()
  item.hash(into: &hasher)
  return hasher.finalize()
}

通过在下面添加以下行来进行尝试:

let hashValue = hashItem(item: "the quick brown fox")

运行playground。 哈希值显示在结果侧栏中,或单击Show Result按钮以在playground上查看它:

Hasher hash value

您的值与我的不同。再次运行playground,您将获得不同的值。

Hasher不同,加密哈希(cryptographic hashing)每次都会产生相同的哈希值。像Hasher算法一样,密码哈希算法(cryptographic hashing algorithm)会产生几乎唯一的哈希值,而对输入的较小更改会导致哈希值发生较大变化。差异是,即产生可以可靠地验证数据完整性的哈希值(称为摘要或校验和)所需的计算量不同。

密码哈希算法(Cryptographic hashing algorithms)为输入数据创建一个小的,固定长度的,几乎唯一的数据值(摘要)。最常见的摘要大小是256位和512位。 512位摘要可以截断为384位。找到两个产生相同摘要的输入是不太可能但并非不可能,因为256位或512位摘要分别只有2^2562^512个可能的值。

散列算法(Hashing algorithms)是单向的,并且包含非线性运算,因此攻击者无法反转运算来从摘要中计算原始数据。输出的每一位都取决于输入的每一位,因此攻击者无法尝试根据摘要的一部分来计算部分输入。即使更改输入中的单个位也会产生完全不同的摘要,因此攻击者无法找到输入和输出之间的关系。

Cryptographic digest is almost unique and very hard to reverse

这些特征使您可以通过计算摘要来查看两个数据集是否不同。 例如,Git计算摘要以标识每个提交。 您可以传输或存储数据及其摘要,以检测随后的更改,例如数据损坏。 软件下载通常提供摘要,称为校验和(checksum)。 下载器使用相同的哈希算法(hashing algorithm)为下载的数据计算摘要。 如果此摘要与文件的校验和不匹配,则表明文件已损坏或不完整。

Receiver computes digest to check data is complete, not corrupted

CryptoKit提供了Secure Hash Algorithm 2 (SHA-2)算法SHA-256SHA-384SHA-512。 数字表示摘要大小。 其不安全(Insecure)的容器提供SHA-1160位)和MD5128位),以便与较早的服务向后兼容。 SHA-2由美国国家标准技术研究院(U.S. National Institute of Standards and Technology)(NIST)发布,法律要求在某些美国政府应用中使用。

playground上,向下滚动至以下语句:

UIImage(data: data)

在结果侧边栏中,单击w 714 h 900旁边的Show Result,以查看数据是一岁的Harry Potter的图像:

Data is baby Harry Potter image

当伏地魔没能杀死哈利时,他不小心把他变成了魂器。 但是伏地魔不知道这一点。 Albus Dumbledore知道,他想与哈利分享这个秘密。

首先,您作为Dumbledore创建此数据的摘要。 添加此行:

let digest = SHA256.hash(data: data)

这就是您要做的! SHA256产生256位摘要。 使用其他两种哈希算法之一 SHA384SHA512一样容易。 而且,如果Apple将它们更新为使用SHA-3而不是SHA-2,则您无需更改代码。

然后Dumbledore通过网络连接将数据和摘要发送给Harry。 因此,现在,作为Harry,添加以下代码来检查摘要匹配情况:

let receivedDataDigest = SHA256.hash(data: data)
if digest == receivedDataDigest { 
  print("Data received == data sent.") 
}

您对数据使用相同的哈希算法,然后检查两个摘要值是否相等。

运行playground。 消息打印。 不足为奇,因为data没有机会被破坏。

现在,单击receivedDataDigest旁边的Show Result按钮以很好地了解摘要:

CryptoKit SHA256 digest of data

这是一个元组。 不太可读。

键入以下行以显示其description

String(describing: digest)

注意:Apple的文档不建议直接调用.description

运行playground。 点击显示结果:

String description of CryptoKit digest

摘要description包含一个字符串String。 这更易于理解,看起来像一个Git哈希值,但长度是它的两倍。 它也比Hasher哈希值长得多。

最后,要查看数据的微小变化如何产生完全不同的摘要,请对两条相同的代码行之一进行很小的更改。 例如:

String(describing: SHA256.hash(data: "Harry is a horcrux".data(using: .utf8)!))
String(describing: SHA256.hash(data: "Harry's a horcrux".data(using: .utf8)!))

运行playground。 单击两行的显示结果:

CryptoKit digests of almost-identical data are very differen

请注意,您得到的哈希值与我完全一样。

4. Signing the Digest

散列数据(Hashing data)并不能保护您免受恶意更改的侵害,因为恶意攻击者只会为他们更改后的数据发送正确的摘要。

基于哈希的消息身份验证代码(Hash-based Message Authentication Code - HMAC)通过使用对称加密密钥(symmetric cryptographic key)对摘要进行签名来防止恶意更改。 一个常见的用例是对文件的摘要签名,以便应用程序的服务器可以检查您是否有权上传文件。

“Symmetric key”是指发送者和接收者都知道秘密密钥。 HMAC使用秘密密钥派生内部和外部密钥。 然后,它根据数据和内部键创建内部哈希。 最后,它根据内部哈希和外部密钥创建签名。

Diagram of Hashed Message Authentication Code

这就是算法的作用。 但是,要使用CryptoKit创建对称密钥(symmetric key),只需键入以下行:

let key256 = SymmetricKey(size: .bits256)

Apple的旧C加密API相比,它的工作量要少得多,后者必须转换位和字节,并记得在完成操作后从内存中删除密钥!

HMAC的最常见攻击是蛮力发现密钥,因此HMAC的安全性取决于密钥的大小。 CryptoKit允许三种密钥大小:.bits128.bits192.bits256

接下来,添加以下两个代码语句:

let sha512MAC = HMAC<SHA512>.authenticationCode(
  for: data, using: key256)
String(describing: sha512MAC)

您正在使用对称密钥(symmetric key)为数据data创建摘要,因此现在将摘要称为身份验证代码或签名(authentication code or signature)

运行playground。 点击显示结果以查看签名的描述:

Description of CryptoKit HMAC 512-bit signature

您已经为婴儿图片生成了512位(64字节)签名。

要通过网络发送此签名,请将其转换为Data

let authenticationCodeData = Data(sha512MAC)

现在,Dumbledore将签名的数据发送给您,即哈里。 您作为哈利已经拥有相同的密钥key256。 输入以下代码以验证您收到的信息:

if HMAC<SHA512>.isValidAuthenticationCode(authenticationCodeData,
   authenticating: data, using: key256) {
    print("The message authentication code is validating the data: \(data))")
  UIImage(data: data)
}
else { print("not valid") }

如果签名有效,您即哈利查看数据,就知道这确实是Dumbledore发送的。

运行playground。 单击print语句旁边和UIImage旁边的显示结果:

CryptoKit authenticating HMAC signature and data

HMAC可让您验证发件人的身份和数据的完整性,但不对数据进行加密。如果您忘记使用TLS,而Voldemort截取了传输信息,他会怀疑Harry是他的灵魂之一。

或者,Voldemort可能决定手动加密他的魂器清单,以确保DumbledoreHarry找不到并销毁它们。

数据加密就是密码学的全部内容,因此来了。

5. Encrypting and Authenticating Data

即使使用TLS加密网络数据,您也可能希望将加密的文件发送给用户。例如,如果他们进行了应用内购买,则可以向他们发送加密文件和(单独)解密文件的密钥。

当前的技术水平是具有关联数据的认证加密(Authenticated Encryption with Associated Data - AEAD)密码。 AEAD密码使用不同的密钥进行加密和MAC,并且MAC会对密码文本而不是纯文本进行哈希处理。一切都结合到一个密封的盒子里。

有两种常用的AEADAdvanced Encryption Standard Galois/Counter Mode (AES-GCM)ChaCha20-Poly1305。两者都是Apple加密API的新功能。 AES-GCMNIST建立的标准。 Daniel J. Bernstein开发了ChaCha20-Poly1305,以防攻击者设法破坏AES-GCM

在2019年,几乎所有TLS流量都使用AES,但是ChaCha20-Poly1305越来越受欢迎,因为在不支持AES-GCM的移动设备上,它比AES-GCM快得多。但是请放心在您的应用程序中使用AES-GCM,因为iOS设备具有AES硬件。

AESChaCha20是密码算法。 GCMPoly1305MAC算法。伯恩斯坦(Bernstein)从他较早的莎莎(Salsa)密码开发了ChaCha20

要创建密封盒,AEAD密码采用以下输入:

  • 1) 要加密的明文
  • 2) 秘密钥匙
  • 3) 唯一的初始化值 - IV或随机数:这可以防止重播攻击,例如某人(确实需要生命)重新发送同一购物车订单多次。
  • 4) 可选:已认证但未加密的其他非秘密数据。这是AEAD中的AD

然后进行密封操作:

  • 1) 使用密钥和随机数生成辅助密钥。
  • 2) 使用密钥和随机数将数据加密为长度相等的加密数据(密文ciphertext)。
  • 3) 使用辅助密钥来生成任何其他数据,加密数据及其长度的带密钥摘要。
  • 4) 使用密钥和随机数加密密钥摘要,然后将加密的密钥摘要附加到加密的数据。

在此图中,我省略了相关数据:

Diagram of CryptoKit Sealed Box seal operation

这看起来需要很多工作,不是吗? 好吧,这里是您要键入的所有内容,以创建一个密封的盒子:

let sealedBoxData = try! ChaChaPoly.seal(data, using: key256).combined

您提供数据和密钥以得到一个密封的盒子。 它的combined属性是Data类型,您可以通过网络发送它。

要改用AES-GCM,您可以将ChaChaPoly替换为AES.GCM

现在,Dumbledore将密封的盒子数据发送给哈利。 您是哈利,请键入以下代码以将其转回密封盒中:

let sealedBox = try! ChaChaPoly.SealedBox(combined: sealedBoxData)

作为哈利的用户已经具有与邓布利多相同的密钥,因此您可以打开密封盒并解密其密文(ciphertext)

let decryptedData = try! ChaChaPoly.open(sealedBox, using: key256)

运行playground

CryptoKit code for ChaChaPoly seal and open operations

注意SealedBoxData的大小比图像数据大28个字节。 添加这些行以查看密封框盒还有什么:

sealedBox.nonce  // 12 bytes
sealedBox.tag  // 16 bytes
Sizes and contents of CryptoKit sealed box nonce and tag

两种算法都会为您选择一个随机数,然后将其打包到密封的盒子中以供使用。 太简单! 16字节tag是加密的密钥摘要 - 验证数据的签名。 每次创建密封盒时,随机数都会更改,这也会更改加密的密钥摘要。 因此,您的实际noncetag值与我的屏幕截图不匹配。

最后,为了证明无法查看加密数据,请添加以下行:

let encryptedData = sealedBox.ciphertext
UIImage(data: encryptedData)
UIImage(data: decryptedData)

运行playground,查看以下行:

Encrypted data cannot be viewed as UIImage

这样就很容易发送加密的数据,但是发送者和接收者都需要知道密钥。如果不可能的话怎么办?


Public-Key Cryptography

注意:这仍然是CryptoKit的一部分,但这是一个很大的话题,因此请获取其自己的部分。

HMAC和密封箱(Sealed Box)加密使用对称密钥,其中发送者和接收者都知道密钥。对称密钥必须“带外”传输。如果您不能安全地执行此操作,请使用公共密钥加密。实际上,互联网上的大多数常规加密都使用公钥加密,包括每当Xcode对您的应用进行签名时。

公钥加密(Public-key cryptography)创建两个数学链接的密钥。您将私钥保密,并发布相应的公钥数据。您使用私钥对数据或其摘要签名,然后将其发送。接收者根据您的公共密钥数据创建一个公共密钥,然后使用它来检查已签名的数据或摘要。

例如,您的应用可能需要通过后端服务器对操作进行身份验证。它在用户的设备上创建一个私钥,并将其存储在KeychainSecureEnclave中,然后在服务器上注册相应的公钥。用户设置操作时,您的应用会使用用户的私钥对操作的详细信息进行签名,然后将签名的详细信息发送到服务器,服务器将使用用户的公钥对其进行验证。

要发送加密的数据,您和您的收件人分别创建一对密钥并发布公共密钥。然后,你们两个都将您的私钥与另一个人的公钥结合在一起,以创建共享密钥。你们两个都使用该共享机密来导出相同的对称密钥,然后可以按照上一节中的说明将其用于AEAD

1. Creating Private and Public Keys

公钥密码术的关键特征是它使用活板门算法(trapdoor algorithms):从公钥中计算私钥非常困难。

1978年发布后,RSA(Rivest-Shamir-Adleman)成为最受欢迎的公钥算法。它依赖于确定一个非常非常大的数字的两个素数因子的难度。其他数学家则面临挑战,开发了只能通过增加键的大小来阻止因素分解的算法。生成RSA密钥的速度很慢,并且时间随着密钥的大小而增加。最终,保理算法的改进速度快于移动设备进行大量计算的能力。注意力转移到另一种技术上,事实证明,这种技术很难被攻击。

ECC (Elliptic Curve Cryptography), 于1985年首次提出,自2004年以来已广泛使用,并在2015年底成为服务器上的首选技术。ECC密钥比具有类似安全性的RSA密钥小得多:例如, 256ECC公钥与3072RSA公钥相当。

CryptoKit仅使用ECC算法。您可以在此处选择NISTP256 / P384 / P521Daniel J. BernsteinCurve25519P256是迄今为止使用最广泛的曲线。这是OpenSSL的默认曲线,称为prime256v1P384的计算量是P2562-3倍。美国国家安全局(NSA)要求使用P384保护绝密信息。 P256P384位于NSASuite B Cryptography中,但P521没有,而且我找不到有关谁使用它的任何信息。超级惊吓吧?

注意:在2018年,NSACommercial National Security Algorithm Suite (CNSA)取代了 Suite B,这是其向抗量子密码技术(quantum-resistant cryptography)过渡的一步,因为量子计算quantum computing可以轻松打破ECC算法。

伯恩斯坦(Bernstein)NSA Suite B的同一年发布了Curve25519,但在爱德华·斯诺登(Edward Snowden)于2013年发布内部备忘录后暗示,NSA已在基于椭圆曲线的伪随机生成器Dual_EC_DRBG中插入了密码后门,从而使其流行度提高。 Dual_EC_DRBGP256都依赖于 Nothing Up My Sleeve (NUMS)幻数。密码学界怀疑,NSA使用特殊值来导出这些幻数,从而使它们能够解密使用P256加密的任何内容。 Curve25519不依赖于幻数。它的计算复杂度比P25640%。并且2018年TLS 1.3标准需要对此提供支持。

2. ECC: How Does It Work?

像这样this one的许多文章都使用小质数算法以易于理解的方式解释RSA。该算法非常聪明。

椭圆曲线密码学(Elliptic curve cryptography)甚至更好!但是解释起来有点复杂。

椭圆曲线由满足以下形式的等式的(x,y)点组成:

y^2 = x^3 + ax + b

例如,y^2 = x^3 - x + 1看起来如下所示:

Graph of an elliptic curve

您可以在Desmos Graphing Calculator.中绘制更多的椭圆曲线。

ECC使用椭圆曲线的两个属性:

  • 1) 任何非垂直线与图形的相交点不得超过三个点。
  • 2) 该图围绕x轴对称。

这些属性使您可以定义图形上任意两个点之间的点运算:

  • 1) 在点A和点B之间画一条线。
  • 2) 如果该线在第三个点交到图形,则在x轴上反射以得到点C = A·B
elliptic curve A dot B operation

您还可以定义点乘法运算k * A,其中k是一个正整数。

  • 1) 从A·A开始获得点B:在点A处的曲线上绘制切线,并在x轴击中图形的地方横切x线。这是第一个点操作。
  • 2) 现在执行A·B以获得点C,然后A·C = D,依此类推。总共进行k个点运算,以点P结尾。如果您告诉某人点AP在哪里,那么他们很难计算k

实际算法仅使用xy的整数值,以质数n为模。起点称为生成器,因此通常称为G。它的属性为n * G =G

要设置ECC密码系统,请选择一个曲线方程式(x的系数和常数b),该曲线上的生成器点G及其对应的素数n。私钥是随机选择的数字k,公钥是k * G - 对G进行k点操作后曲线上的端点。

当然,您不需要执行任何操作。已经有标准曲线,如Curve25519NIST ECC所使用的曲线,并通过CryptoKit的公钥方法实现。

3. Digital Signatures

数字签名就像HMAC,但带有公共密钥密码学。发送者不是使用相同的密钥来签名和验证,而是使用私钥进行签名,接收者使用发送者的公钥进行验证。

Public key cryptography: sign with private key, verify with public key

数字签名的缩写是使用NISTP256 / P384 / P512曲线的椭圆曲线数字签名算法(Elliptic Curve Digital Signature Algorithm - ECDSA),以及使用BernsteinEd25519曲线的Edwards曲线数字签名算法(EdDSA)

假设您像Dumbledore一样想要将魂器图像发送给哈利。 您将对其进行签名,以便Harry可以从您作为Dumbledore处进行验证。 首先,创建用于数字签名的私钥和公钥:

let albusSigningPrivateKey = Curve25519.Signing.PrivateKey()
let albusSigningPublicKeyData = 
  albusSigningPrivateKey.publicKey.rawRepresentation

公钥的rawRepresentation类型为Data,因此您可以通过网络发送它。

接下来,您作为Dumbledore使用私钥对数据进行签名:

let signatureForData = try! albusSigningPrivateKey.signature(for: data)

或者,您可以签署数据摘要,这样更快:

let digest512 = SHA512.hash(data: data)
let signatureForDigest = try! albusSigningPrivateKey.signature(
  for: Data(digest512))

您是邓布利多,这次使用SHA-512

当使用Curve25519私钥时,signature(for :)使用SHA-512作为哈希函数,生成数据的椭圆曲线数字签名算法(EdDSA)签名或Ed25519椭圆曲线上的摘要。 该算法会生成随机随机数,以在每次调用时产生不同的签名,即使对于相同的数据和密钥也是如此,以防止定时攻击。

如果使用P256而不是Curve25519,它将使用SHA-256作为哈希函数,生成P-256椭圆曲线上数据的椭圆曲线数字签名算法(ECDSA)签名。

现在,您作为邓布利多将datadigest512signatureForDatasignatureForDigest发送给Harry。

切换到你是Harry,您添加此代码以使用从albusSigningPublicKeyData创建的密钥来验证签名。

let publicKey = try! Curve25519.Signing.PublicKey(
  rawRepresentation: albusSigningPublicKeyData)
if publicKey.isValidSignature(signatureForData, for: data) {
  print("Dumbledore sent this data.")
}
if publicKey.isValidSignature(signatureForDigest,
  for: Data(digest512)) {
  print("Data received == data sent.")
  UIImage(data: data)
}

注意:P256及其NIST兄弟姐妹有一种方法来签名摘要,而无需将其转换为Data

运行playground以查看经过身份验证的数据:

CryptoKit code using public key to verify private key signature

这就是进行数字签名的容易程度。 但是同样,数据没有加密。 因此,请继续阅读!

4. Creating a Symmetric Key for Encryption

在本教程的早期,DumbledoreHarry有一个他们都知道的秘密密钥,这使他们可以使用AEAD密封盒来加密和解密数据。 但是伏地魔以某种方式发现了这个秘密钥匙,并且不可能安全地设置一个新的对称钥匙-哈里在奔跑,邓布利多只是一种精神-所以现在他们需要寻找另一种方式。

密钥协商算法(Key agreement algorithm)使他们能够从其公共密钥和私有密钥创建共享机密,然后添加约定的盐值(salt value)以生成对称密钥(symmetric key)

Diagram of public-private key agreement algorithm

计算共享秘密非常简单。 如果G是椭圆曲线的生成点,而a是邓布利多的秘密密钥,那么a * G是他的公钥。 同样,Harry的秘密密钥是h,而他的公共密钥是h *G。事实证明这是事实:

(a * G) * h = (h * G) * a

是的,HarryDumbledore的公钥乘以他的私钥,这与Dumbledore通过将Harry的公钥乘以他自己的私钥所获得的相同。 魔法!

在这里,acronymDiffie Hellman(ECDH)秘钥协议,使用NISTP256 / P384 / P512曲线或BernsteinX25519曲线。

首先,邓布利多和哈里创建密钥协议的私钥和公钥,并将其公钥发布为Data

let albusPrivateKey = Curve25519.KeyAgreement.PrivateKey()
let albusPublicKeyData = albusPrivateKey.publicKey.rawRepresentation
let harryPrivateKey = Curve25519.KeyAgreement.PrivateKey()
let harryPublicKeyData = harryPrivateKey.publicKey.rawRepresentation

DumbledoreHarry必须就创建对称密钥的盐值达成共识:

let protocolSalt = "Voldemort's Horcruxes".data(using: .utf8)!

通过网络发送此邮件是安全的。 除非攻击者也知道其中一个私钥,否则它不会有所帮助。

Dumbledore从原始表示中创建Harry的公钥,然后将其与他的私钥结合起来,首先计算sharedSecret,然后计算对称密钥symmetricKey

let harryPublicKey = try! Curve25519.KeyAgreement.PublicKey(
  rawRepresentation: harryPublicKeyData)
let ADsharedSecret = try! albusPrivateKey.sharedSecretFromKeyAgreement(
  with: harryPublicKey)
let ADsymmetricKey = ADsharedSecret.hkdfDerivedSymmetricKey(
  using: SHA256.self, salt: protocolSalt,
  sharedInfo: Data(), outputByteCount: 32)

哈里(Harry)从原始表示中创建了邓布利多(Dumbledore)的公钥,然后将其与他的私钥结合起来,首先计算sharedSecret,然后计算symmetricKey

let albusPublicKey = try! Curve25519.KeyAgreement.PublicKey(
rawRepresentation: albusPublicKeyData)
let HPsharedSecret = try! harryPrivateKey.sharedSecretFromKeyAgreement(
  with: albusPublicKey)
let HPsymmetricKey = HPsharedSecret.hkdfDerivedSymmetricKey(
  using: SHA256.self, salt: protocolSalt,
  sharedInfo: Data(), outputByteCount: 32)

现在来看它们是否匹配:

if ADsymmetricKey == HPsymmetricKey {
  print("Dumbledore and Harry have the same symmetric key.")
}

运行playground

CryptoKit derived symmetric keys match

就像是魔术一样,邓布利多和哈利产生了相同的对称密钥! 现在,他们可以使用此对称密钥进行AEAD身份验证的加密。

5. P256 Key in Secure Enclave

注意:SecureEnclave代码仅在具有Secure Enclave芯片的设备上起作用:iPhone 5S,iPad Air和更高型号。

为了提供额外的保护,您可以直接在设备的Secure Enclave中创建P256私钥。 对代码的改动很小:

// Check that the device has a Secure Enclave
if SecureEnclave.isAvailable {
  // Generate private key in Secure Enclave
  let privateKey = try SecureEnclave.P256.Signing.PrivateKey() 
} else {
  let privateKey = P256.Signing.PrivateKey()
}

使用Secure Enclave中的私钥,创建公钥数据和签名数据或摘要的工作原理完全相同:

// Create public key data
let publicKeyData = privateKey.publicKey.compactRepresentation!
// Produce a signature
let dataSignature = try privateKey.signature(for: data)
let digestSignature = try privateKey.signature(for: digest)

注意:您只能在Secure Enclave中创建P256密钥。 这可能是因为该芯片包含P256使用的AES引擎,而不是因为美国政府要求苹果提供后门。

Secure Enclave具有以下很酷的功能:您可以通过访问控制来限制密钥的使用。 例如:

let accessControl = SecAccessControlCreateWithFlags(
  nil,
  kSecAttrAccessibleWhenUnlockedThisDeviceOnly,
  [.privateKeyUsage, .userPresence], 
  nil)!
let privateKey = try SecureEnclave.P256.Signing.PrivateKey(
  accessControl: accessControl)

您正在设置访问控制,因此只有在设备解锁后才能访问在Secure Enclave中创建的密钥,并且仅在此设备上可用。另外,您的应用在执行私钥操作时要求用户在场。需要用户在场意味着用户必须通过TouchIDFaceID或设备密码进行身份验证。


Complying With Encryption Export Regulations

最后一件事。在许多国家,加密是一个敏感的政治问题。该地图This map显示了哪些国家/地区具有许可或注册要求,进出口控制,提供者协助当局的义务和其他限制。

美国是实行出口管制的国家之一。这是合法的内容,因此我将直接引用Apple的文章 Complying with Encryption Export Regulations

当您将应用程序提交到TestFlightApp Store时,会将您的应用程序上传到美国的服务器。如果您在美国或加拿大境外分发应用程序,则无论您的法人实体位于何处,您的应用程序都必须遵守美国出口法律。如果您的应用使用,访问,包含,实施或合并加密,则这被视为加密软件的出口,这意味着您的应用要遵守美国出口合规性要求以及您分发产品所在国家/地区的进口合规性要求。应用程式。

AppleApp Store Connect Help Export compliance overview

加密的使用包括但不限于:

  • 通过安全通道(即HTTPS,SSL等)进行调用。
  • 使用标准的加密算法。
  • 使用其他来源的加密功能,例如iOSmacOS
  • 使用专有或非标准加密算法。美国政府将“非标准加密”(non-standard cryptography)定义为涉及并入或使用专有或未发布的加密功能的任何“加密”实施方式,包括尚未得到公认的国际标准机构(例如,未采用或批准)的加密算法或协议。IEEE,IETF,ISO,ITU,ETSI,3GPP,TIAGSMA),除非另行发布。

App Store Connect提供了一系列问题App Store Connect provides a set of questions,可帮助您确定是否需要您提供出口合规性文件以及需要哪些表格。

与往常一样,您可以在源代码中找到更多信息:

除了本教程中的(大部分为Wikipedia)链接之外,这是对椭圆曲线密码学的解释,它确实帮助我了解了所发生的情况:

A (Relatively Easy To Understand) Primer on Elliptic Curve Cryptography入门确实很容易理解,并且具有一些非常有用的GIF动画。 但是,请务必扫描注释,以查找某些缺少的信息。 Cloudflare还有许多其他有关密码学主题的精彩文章。

后记

本篇主要讲述了CryptoKit使用入门简单示例,感兴趣的给个赞或者关注~~~

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,293评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,604评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,958评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,729评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,719评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,630评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,000评论 3 397
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,665评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,909评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,646评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,726评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,400评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,986评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,959评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,197评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,996评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,481评论 2 342