操作系统 / Swift | 构建状态 |
---|---|
Linux 5.0 | |
MacOS 5.0 |
一个库,用于促进基于哈希的 KDF 签名认证,以及与兼容 API 进行端到端加密通信。
可以通过 Swift Package Manager 安装此库,方法是添加以下依赖项
dependencies: [
.package(url: "https://github.com/ncryptf/ncryptf-swift.git", , .upToNextMinor(from: "0.2.0")),
],
MacOS 测试通过 swift test 命令运行
swift test
Linux 测试可以在本地运行,也可以通过提供的 docker 容器运行
apt install libsodium-dev
swift test
如果您正在使用的平台不支持 swift 或 XCTestCase,您可以通过 Docker 运行测试套件
首先,构建 docker 镜像
docker build --tag ncryptf --compress --squash .
然后可以按如下方式运行测试
docker run -it -v${PWD-.}:/package ncryptf swift test
HMAC+HKDF 身份验证是一种身份验证方法,可确保请求在传输过程中未被篡改。这不仅可以防止网络层操纵,还可以防止中间人攻击。
在高层面上,HMAC 签名是基于原始请求正文、HTTP 方法、URI(如果存在查询参数)和当前日期创建的。除了确保请求在传输过程中不会被操纵外,它还确保请求是限时的,有效防止重放攻击。
该库本身可以通过导入以下结构体来使用
支持的 API 将返回以下有效负载,其中至少包含以下信息。
{
"access_token": "7XF56VIP7ZQQOLGHM6MRIK56S2QS363ULNB5UKNFMJRQVYHQH7IA",
"refresh_token": "7XF56VIP7ZQQOLGHM6MRIK56S2QS363ULNB5UKNFMJRQVYHQH7IA",
"ikm": "bDEyECRvKKE8w81fX4hz/52cvHsFPMGeJ+a9fGaVvWM=",
"signing": "7v/CdiGoEI7bcj7R2EyDPH5nrCd2+7rHYNACB+Kf2FMx405und2KenGjNpCBPv0jOiptfHJHiY3lldAQTGCdqw==",
"expires_at": 1472678411
}
提取元素后,我们可以通过执行以下操作来创建签名请求
let auth = try? Authorization(
httpMethod: httpMethod,
uri: uri,
token: token,
date: Date(),
payload: payload
)
if auth = auth {
let header = auth.getHeader()!
}
一个简单的完整示例如下所示
let token = Token(
accessToken: "7XF56VIP7ZQQOLGHM6MRIK56S2QS363ULNB5UKNFMJRQVYHQH7IA",
refreshToken: "7XF56VIP7ZQQOLGHM6MRIK56S2QS363ULNB5UKNFMJRQVYHQH7IA",
ikm: Data(base64Encoded: "bDEyECRvKKE8w81fX4hz/52cvHsFPMGeJ+a9fGaVvWM=")!,
signature: Data(base64Encoded: "7v/CdiGoEI7bcj7R2EyDPH5nrCd2+7rHYNACB+Kf2FMx405und2KenGjNpCBPv0jOiptfHJHiY3lldAQTGCdqw==")!,
expiresAt: Date(timeIntervalSinceReferenceDate: 1472678411)
)
let date = Date()
let auth = try? Authorization(
httpMethod: "POST",
uri: "/api/v1/test",
token: token,
date: date,
payload: "{\"foo\":\"bar\"}".data(using: .utf8, allowLossyConversion: false)
)
if auth = auth {
let header = auth.getHeader()!
}
请注意,调用
Authorization
时,date
属性应为预偏移,以防止时间偏差。
Authorization:init
中的 payload
参数应为 JSON 可序列化字符串。
对于支持版本 2 HMAC 标头的 API,可以通过调用以下方法检索
if auth = auth {
let header = auth.getHeader()!
}
对于使用版本 1 HMAC 标头的 API,请调用 Authorization
并将可选的 version
参数设置为 1
作为第 6 个参数。
let auth = try? Authorization(
httpMethod: httpMethod,
uri: uri,
token: token,
date: Date(),
payload: payload,
version: 1
)
if auth = auth {
let header = auth.getHeader()!
}
此字符串可用于 Authorization
标头
版本 1 HMAC 标头需要额外的 X-Date
标头。X-Date
标头可以通过调用 authorization.getDateString()
来检索
此库使客户端能够在 TLS 层之上建立受信任的加密会话,同时(且独立地)提供通过 HMAC+HKDF 样式身份验证来验证和识别客户端的能力。
此功能的原理包括但不限于
您可能想要与 API 本身建立加密会话的主要原因是确保 IKM 的机密性,以防止在不受信任的网络上发生数据泄漏,从而避免在类似 Cloudflare 的事件(或任何中间人攻击)中暴露信息。加密会话使您能够使用像 Cloudflare 这样的服务,即使再次发生内存泄漏,您也有信心 IKM 和其他安全数据不会被泄露。
要加密、解密、签名和验证消息,您需要能够生成适当的密钥。在内部,此库使用 libsodium-swift 来执行所有必要的密码学功能。
加密使用 sodium crypto box。密钥对可以按如下方式生成
let kp = Utils.generateKeypair()
加密使用 sodium 签名。密钥对可以按如下方式生成
let kp = Utils.generateSigningKeypair()
有效负载可以按如下方式加密
import CryptoSwift // For .bytes alias
let payload = """
{
"foo": "bar"
}
"""
guard var Request = try? Request(
secretKey: kp.secretKey
) else {
// Handle init errors
}
guard let cipher = try? request!.encrypt(
request: payload.data(using: .utf8, allowLossyConversion: false)!,
publicKey: publicKey // 32 byte public key from server
) else {
// Handle errors
}
// Do your HTTP request here
请注意,您需要拥有预先引导的公钥才能加密数据。对于 v1 API,这通常由
/api/v1/server/otk
返回。
来自服务器的响应可以按如下方式解密
import CryptoSwift // For .bytes alias
guard let response = try? Response(
secretKey: kp.secretKey
) else {
// Handle initialization errors
}
guard let decrypted = try? response!.decrypt(
response: Data(base64Encoded: "")!.bytes, // The raw body provided in the servers http response
) else {
// Handle errors
}
版本 2 的工作方式与版本 1 有效负载相同,唯一的例外是解密消息所需的所有组件都捆绑在有效负载本身中,而不是分解为单独的标头。这减轻了开发人员管理多个标头的担忧。
版本 2 有效负载描述如下。每个组件连接在一起。
段 | 长度 |
---|---|
4 字节标头 DE259002 ,二进制格式 |
4 字节 |
随机数 | 24 字节 |
与私钥关联的公钥 | 32 字节 |
加密正文 | X 字节 |
签名公钥 | 32 字节 |
签名或原始请求正文 | 64 字节 |
先前连接在一起的元素的校验和 | 64 字节 |