Virgil Security Ratchet Objective-C/Swift SDK
介绍 | SDK 特性 | 安装 | 注册用户 | 点对点聊天示例 | 群组聊天示例 | 支持
介绍
Virgil Security 提供一系列服务和开源库,以便为任何应用程序添加安全性。如果您正在开发聊天应用程序,您会了解到确保机密性和数据完整性的高水平数据保护的需求。
您可能已经听说过我们的 e3kit,它提供端到端加密的高级保护,但是如果您需要为应用程序提供最大保护,Virgil Security 推出 Double Ratchet SDK – 双重 ratchet 算法的实现。通过本 SDK 中的强大工具,您甚至可以保护被窃取的用户消息或私钥的加密数据。Double Ratchet SDK 不仅为每个聊天会话分配一个私钥加密密钥,而且还允许开发人员限制这些密钥的生命周期。如果在应用程序中激活的密钥被盗,它将根据您预先设置的应用程序中设定的生命周期自动过期。
跳扣 SDK 与 PFS 服务 交互,以发布和管理一次性密钥(OTK)、长期密钥(LTK),并与 Virgil Cards 服务交互以检索基于 OTK 和 LTK 的用户身份卡。跳扣 SDK 为每次会话向聊天参与者颁发新的密钥。因此,新会话密钥无法泄露过去会话的密钥。
SDK 功能
- 与 Virgil PFS 服务通信
- 管理用户的一次性密钥(OTK)和长期密钥(LTK)
- 启用群组或点对点聊天加密
- 使用 Virgil 加密库 和 Virgil Core SDK
安装
Virgil Ratchet SDK 以一组通过 Carthage 和 CocoaPods 分发的框架的形式提供。
所有框架都可用于以下平台:
- iOS 9.0+
- macOS 10.11+
- tvOS 9.0+
- watchOS 2.0+
COCOAPODS
CocoaPods 是 Cocoa 项目的依赖管理器。您可以使用以下命令安装它:
$ gem install cocoapods
要使用 CocoaPods 将 Virgil Ratchet SDK 集成到您的 Xcode 项目中,请在您的 Podfile 中指定它
target '<Your Target Name>' do
use_frameworks!
pod 'VirgilSDKRatchet', '~> 0.8.0'
end
然后,运行以下命令
$ pod install
Carthage
Carthage 是一个分布式的依赖管理器,它构建您的依赖并提供了二进制框架。
您可以使用 Homebrew 使用以下命令安装 Carthage
$ brew update
$ brew install carthage
要使用 Carthage 将 Virgil Ratchet SDK 集成到您的 Xcode 项目中,在您的项目根目录下创建一个名为 Cartfile 的空文件,并将以下行添加到您的 Cartfile
github "VirgilSecurity/virgil-ratchet-x" ~> 0.7.0
针对预构建的二进制文件进行链接
要将预构建的框架链接到您的应用程序,请运行以下命令
$ carthage update --use-xcframeworks
这将构建每个依赖项或从github发行版下载预编译的框架。
为iOS/tvOS/watchOS构建
在您的应用程序的目标的“常规”设置选项卡中,“链接框架和库”部分,从您项目文件夹内的《Carthage/Build》文件夹中添加以下框架
- VirgilSDKRatchet
- VirgilSDK
- VirgilCrypto
- VirgilCryptoFoundation
- VirgilCryptoRatchet
- VSCCommon
- VSCFoundation
- VSCRatchet
每个框架都要检查“嵌入并签名”。
为macOS构建
在您的应用程序目标“常规”设置选项卡中,“嵌入二进制文件”部分,从Carthage/Build文件夹中将以下框架拖放到相应位置
- VirgilSDKRatchet
- VirgilSDK
- VirgilCrypto
- VirgilCryptoFoundation
- VirgilCryptoRatchet
- VSCCommon
- VSCFoundation
- VSCRatchet
另外,您还需要复制macOS的调试符号以进行调试和崩溃报告。
在您的应用程序目标“构建阶段”设置选项卡中,点击“+”图标,选择“新复制文件阶段”。点击“目标位置”下拉菜单并选择“产品目录”。对于每个框架,拖放相应的dSYM文件。
Swift包管理器
Swift包管理器是苹果官方用于管理Swift代码分发的工具。
苹果的文档可以用于向Xcode项目添加框架。
注册用户
请确保您已注册到Virgil仪表板并且已创建E2EE V5应用程序。
除了在您的服务器上注册外,用户还必须在Virgil云上注册。如果他们已经注册,您可以跳过此步骤,进入下一个步骤。
每个Virgil用户在其设备上都有一张Virgil卡
,寿命无限。这张卡包含私钥
、公钥
和用户的身份
。
要在Virgil云上注册用户(即创建和发布他们的身份卡
),请按照以下步骤操作
- 设置您的后端以生成JWT,为您的服务和用户提供访问Virgil云的权限。
- 设置客户端用于在Virgil云上验证用户。
- 在您的客户端上设置Cards Manager,使用Virgil Cards服务生成和发布
Virgil卡
。
如果您已经安装了Virgil Ratchet SDK或不需要安装Virgil SDK或Virgil Crypto,您可以使用此指南进行上述步骤。
初始化SDK
为了开始与PFS服务通信并建立一个安全会话,每个用户都必须运行初始化。为此,您需要从Virgil云中获取接收者的公钥(身份卡)和来自本地存储的发送者的私钥。
import VirgilSDKRatchet
let context = SecureChatContext(identityCard: card,
identityKeyPair: keyPair,
accessTokenProvider: provider)
let secureChat = try! SecureChat(context: context)
secureChat.rotateKeys().start { result in
switch result {
// Keys were rotated
case .success(let rotationLog): break
// Error occured
case .failure(let error): break
}
}
在初始化过程中,使用身份卡和rotateKeys
方法,我们生成具有自己寿命的特殊密钥。
- 一次性密钥(OTK) - 每次聊天参与者想要创建会话时,都会从服务器获得并丢弃单个一次性密钥。
- 长期密钥(LTK) - 根据开发者的安全考虑定期更换,并使用身份私钥进行签名。
点对点聊天示例
在本节中,您将了解如何使用Virgil Ratchet SDK构建点对点聊天。
发送初始加密消息
假设爱丽丝想开始与鲍勃通信,并希望发送第一条消息
- 首先,爱丽丝需要通过运行
startNewSessionAsSender
函数创建一个新的会话,并指定鲍勃的身份卡 - 然后,爱丽丝使用
encrypt
SDK函数对初始消息进行加密 - 最后,Ratchet SDK不会自动存储和更新会话。爱丽丝必须使用
storeSession
SDK函数将生成的会话本地存储。
import VirgilSDKRatchet
// prepare a message
let messageToEncrypt = "Hello, Bob!"
// start new secure session with Bob
let session = try! secureChat.startNewSessionAsSender(receiverCard: bobCard).startSync().get()
let ratchetMessage = try! session.encrypt(string: messageToEncrypt)
try! secureChat.storeSession(session)
let encryptedMessage = ratchetMessage.serialize()
重要:您需要在改变会话状态的操作(加密、解密)之后存储会话,因此如果会话已存在于存储中,它将被覆盖
解密初始消息
爱丽丝生成并存储会话后,鲍勃也必须
- 通过运行
startNewSessionAsReceiver
函数开始会话 - 使用
decrypt
SDK函数解密加密的消息
import VirgilCryptoRatchet
import VirgilSDKRatchet
let ratchetMessage = try! RatchetMessage.deserialize(input: encryptedMessage)
let session = try! secureChat.startNewSessionAsReceiver(senderCard: aliceCard, ratchetMessage: ratchetMessage)
let decryptedMessage = try! session.decryptString(from: ratchetMessage)
try! secureChat.storeSession(session)
重要:您需要在改变会话状态的操作(加密、解密)之后存储会话。如果会话已存在于存储中,它将被覆盖
加密和解密消息
加密消息
要加密未来的消息,请使用encrypt
函数。此函数允许您加密数据和字符串。
还需要使用消息序列化来在不同用户之间传输加密消息。并且不要忘记在每个加密操作更改会话状态时更新存储中的会话!
- 请使用以下代码片段来加密字符串
let session = secureChat.existingSession(withParticipantIdentity: bobCard.identity)!
let message = try! session.encrypt(string: "Hello, Bob!")
try! secureChat.storeSession(session)
let messageData = message.serialize()
// Send messageData to Bob
- 请使用以下代码片段来加密数据
let session = secureChat.existingSession(withParticipantIdentity: bobCard.identity)!
let message = try! session.encrypt(data: data)
try! secureChat.storeSession(session)
let messageData = message.serialize()
// Send messageData to Bob
解密消息
要解密消息,请使用 decrypt
函数。此函数允许您解密数据和字符串。
您还需要使用消息序列化来在用户之间传输加密消息。并且,不要忘记每次解密操作后更新存储中的会话,因为它们的状态会随之改变!
- 以下代码示例用于解密字符串
let session = secureChat.existingSession(withParticipantIdentity: aliceCard.identity)!
let message = try! RatchetMessage.deserialize(input: messageData)
let decryptedMessage = try! session.decryptString(from: message)
try! secureChat.storeSession(session)
- 以下代码示例用于解密数据
let session = secureChat.existingSession(withParticipantIdentity: aliceCard.identity)
let message = try! RatchetMessage.deserialize(input: messageData)
let decryptedMessage = try! session.decryptData(from: message)
try! secureChat.storeSession(session)
群组聊天示例
在本节中,您将学习如何使用 Virgil Ratchet SDK 构建 group chat。
创建群组聊天票证
假设 Alice 想与 Bob 和 Carol 开始群组聊天。首先,通过运行 startNewGroupSession
方法创建一个新的群组会话票证。这个票证包含未来群组加密的共享根密钥。因此,它应该被加密,然后传输给其他群组参与者。每个群组聊天都应该有一个唯一的 32 字节会话标识符。我们建议将此标识符与您的唯一传输通道 ID 关联。如果您的通道 ID 不是 32 字节,您可以使用 SHA-256 从它导出会话 ID。
// Create transport channel according to your app logic and get session id from it
let sessionId = Data(hexEncodedString: "7f4f96cedbbd192ddeb08fbf3a0f5db0da14310c287f630a551364c54864c7fb")!
let ticket = try! secureChat.startNewGroupSession(sessionId: sessionId)
启动群组聊天会话
现在,通过运行 startGroupSession
函数启动群组会话。此函数需要指定群组聊天会话 ID、接收者的 Virgil 卡和票证。
let receiverCards = try! cardManager.searchCards(["Bob", "Carol"]).startSync().get()
let groupSession = try! secureChat.startGroupSession(with: receiverCards,
sessionId: sessionId,
using: ticket)
存储群组会话
Ratchet SDK 不存储和更新群聊会话本身。请使用 storeGroupSession
SDK 函数存储聊天会话。
此外,在更改会话状态的操作(加密、解密、设置参与者、更新参与者)后存储现有会话。如果会话已存在于存储中,它将被覆盖
try! secureChat.storeGroupSession(groupSession)
发送群组券
然后,将群组聊天券提供给其他成员。
- 首先,序列化券
let ticketData = ticket.serialize()
- 出于安全原因,我们无法发送未受保护的券,因为它包含未加密的对称密钥。因此,我们必须对接收者加密序列化的券。唯一安全的方法是使用每个参与者之间的点对点双摇钉会话来发送券。
for card in receiverCards {
guard let session = secureChat.existingSession(withParticipantIdentity: card.identity) else {
// If you don't have session, see Peer-to-peer Chat Example on how to create it as Sender.
return
}
let encryptedTicket = try! session.encrypt(data: ticketData).serialize()
try! secureChat.storeGroupSession(groupSession)
// Send ticket to receiver
}
- 然后,使用您的应用程序的业务逻辑将加密的券与其他群聊参与者共享。
加入群聊
现在,当我们创建了群聊,其他参与者可以使用群组聊天券加入聊天。
- 首先,我们必须解密加密的券
guard let session = secureChat.existingSession(withParticipantIdentity: "Alice") else {
// If you don't have a session, see the peer-to-peer chat example on how to create it as a receiver.
return
}
let encryptedTicketMessage = try! RatchetMessage.deserialize(input: encryptedTicket)
let ticketData = session.decryptData(from: encryptedTicketMessage)
- 然后,使用
deserialize
函数反序列化会话券。
let ticket = try! RatchetGroupMessage.deserialize(input: ticketData)
- 通过运行
startGroupSession
函数并存储会话来加入群聊。
let receiverCards = try! cardManager.searchCards(["Alice", "Bob"]).startSync().get()
let groupSession = try! secureChat.startGroupSession(with: receiverCards,
sessionId: sessionId,
using: ticket)
try! secureChat.storeGroupSession(groupSession)
加密和解密消息
加密消息
为了对群聊中的消息进行加密,请使用 encrypt
函数。此函数允许您加密数据和字符串。您仍然需要使用消息序列化在用户之间传递加密消息。并且别忘了更新存储中的会话,因为它们的状态在每次加密操作都会改变!
- 请使用以下代码片段来加密字符串
let message = try! groupSession.encrypt(string: "Hello, Alice and Bob!")
try! secureChat.storeGroupSession(groupSession)
let messageData = message.serialize()
// Send messageData to receivers
- 请使用以下代码片段来加密数据
let message = try! groupSession.encrypt(data: data)
try! secureChat.storeGroupSession(groupSession)
let messageData = message.serialize()
// Send messageData to receivers
解密消息
要解密消息,请使用 decrypt
函数。此函数允许您解密数据和字符串。别忘了更新存储中的会话,因为它们的状 态在每次加密操作中都随之改变!
- 以下代码示例用于解密字符串
let message = RatchetGroupMessage.deserialize(input: messageData)
let carolCard = receiversCard.first { $0.identity == "Carol" }!
let decryptedMessage = try! groupSession.decryptString(from: message, senderCardId: carolCard.identifier)
try! secureChat.storeGroupSession(groupSession)
- 以下代码示例用于解密数据
let message = RatchetGroupMessage.deserialize(input: messageData)
let carolCard = receiversCard.first { $0.identity == "Carol" }!
let data = try! groupSession.decryptData(from: message, senderCardId: carolCard.identifier)
try! secureChat.storeGroupSession(groupSession)
许可协议
此库已在 3-clause BSD License 下发布。
支持
我们的开发者支持团队在此为您提供帮助。更多信息均可在我们的 帮助中心 查询。
您可以在 Twitter 上找到我们,或发送电子邮件至 [email protected]。
此外,您还可以在我们的 Slack 社区获得支持团队的帮助。