JOSESwift


JOSESwift 是一个模块化和可扩展的框架,用于 Swift 中编写的 JOSE 标准 JWSJWEJWK

CircleCI

💡 请注意,此 JOSE 标准的实现尚未完全完成。 例如,目前仅提供有限的支持算法集。 此外,我们目前仅支持 JOSE 类型的紧凑序列化。 如果您缺少特定的功能、算法或序列化,请随时提交 pull request

目录

特性

如果您缺少特定的功能、算法或序列化,请随时提交 pull request

加密算法

🔏 JWS 🔐 JWE 🔑 JWK
数字签名和 MAC 密钥管理 内容加密 密钥
HS256 RSA1_5 A128CBC-HS256 RSA
HS384 RSA-OAEP A192CBC-HS384 EC
HS512 RSA-OAEP-256 A256CBC-HS512 oct
RS256 A128KW A128GCM
RS384 A192KW A192GCM
RS512 A256KW A256GCM
ES256 dir
ES384 ECDH-ES
ES512 ECDH-ES+A128KW
PS256 ECDH-ES+A192KW
PS384 ECDH-ES+A256KW
PS512 A128GCMKW
A192GCMKW
A256GCMKW
PBES2-HS256+A128KW
PBES2-HS384+A192KW
PBES2-HS512+A256KW

序列化

为了实现互换性,JOSESwift 目前支持 JWSJWE 的紧凑序列化。

紧凑序列化 JSON 序列化

压缩算法

JOSESwift 支持 DEFLATE 压缩算法 用于 JWE

安装

JOSESwift 可以很好地集成到您的 iOS 和 macOS 项目中。 我们支持以下包管理器

CocoaPods

要将 JOSESwift 集成到您的 Xcode 项目中,请将其包含在您的 Podfile

source 'https://cdn.cocoapods.org/'
platform :ios, '13.0'
use_frameworks!

target '<Your Target Name>' do
    pod 'JOSESwift', '~> 3.0'
end

然后通过运行 pod install 安装它。 有关使用 CocoaPods 的更多文档可以在这里找到。

Carthage

要将 JOSESwift 集成到您的 Xcode 项目中,请将其包含在您的 Cartfile

github "airsidemobile/JOSESwift" ~> 3.0

然后通过运行 carthage update 构建它,并将构建的框架拖到您的 Xcode 项目中。 有关使用 Carthage 的更多文档可以在这里找到。

Swift Package Manager

要将 JOSESwift 作为 Swift 包集成到您的 Xcode 项目中,请按照 Apple 关于如何将包依赖项添加到您的应用程序的文章进行操作。

或者,当手动使用 Swift Package Manager 时,请在您的 Package.swift 文件中包含以下依赖项。 有关指定依赖项版本要求的更多详细信息,请参阅Apple 的文档

.package(url: "https://github.com/airsidemobile/JOSESwift.git", from: "3.0.0")

用法

JOSESwift 涵盖三个功能方面

  1. JWS:数字签名
  2. JWE:加密和解密
  3. JWK:表示密钥

JWS:数字签名

JWS 使用数字签名封装并保护数据,接收 JWS 的人可以验证该签名。

签名数据

为了构造 JWS,我们需要提供以下部分

  1. 标头
  2. 有效负载
  3. 签名者
标头
var header = JWSHeader(algorithm: .RS512)

您可以通过方便的访问器设置注册的标头参数

header.kid = "2018-10-08"

header.typ = "JWS"

可以像这样设置和读取公共私有标头参数

try header.set("rice", forParameter: "meal")
let meal = header.get(parameter: "meal") // "rice"
header.remove(parameter: "meal")
有效负载
let message = "Summer ⛱, Sun ☀️, Cactus 🌵".data(using: .utf8)!

let payload = Payload(message)
签名者

签名者算法必须与标头算法匹配。

let privateKey: SecKey = /* ... */

let signer = Signer(signatureAlgorithm: .RS512, key: privateKey)!
序列化

JWS 紧凑序列化是一个 URL 安全的字符串,可以使用您选择的方法轻松地传输给第三方。

guard let jws = try? JWS(header: header, payload: payload, signer: signer) else { ... }

print(jws.compactSerializedString) // ey (...) J9.U3 (...) LU.na (...) 1A

有关构建 JWS 的更多详细信息,请参见wiki

验证数据

let publicKey: SecKey = /* ... */

let serialization = "ey (..) n0.HK (..) pQ.yS (..) PA.AK (..) Jx.hB (..) 7w"
do {
    let jws = try JWS(compactSerialization: serialization)
    let verifier = Verifier(verifyingAlgorithm: .RS512, publicKey: publicKey)!
    let payload = try jws.validate(using: verifier).payload
    let message = String(data: payload.data(), encoding: .utf8)!

    print(message) // Summer ⛱, Sun ☀️, Cactus 🌵
}

有关验证现有序列化的 JWS 的更多详细信息,请参见wiki


JWE:加密和解密

JWE 通过加密封装和保护数据。 它可以通过 JWE 的接收者解密。

加密数据

为了构造 JWE,我们需要提供以下部分

  1. 标头
  2. 有效负载
  3. 加密器
标头
var header = JWEHeader(keyManagementAlgorithm: .RSA1_5, contentEncryptionAlgorithm: .A256CBCHS512)

您可以设置注册的标头参数

header.kid = "2018-10-08"

header.typ = "JWE"

可以像这样设置和读取公共私有标头参数

try header.set("rice", forParameter: "meal")
let meal = header.get(parameter: "meal") // "rice"
header.remove(parameter: "meal")
有效负载
let message = "Summer ⛱, Sun ☀️, Cactus 🌵".data(using: .utf8)!

let payload = Payload(message)
加密器

加密器算法必须与标头算法匹配。

let publicKey: SecKey = /* ... */

let encrypter = Encrypter(keyManagementAlgorithm: .RSA1_5, contentEncryptionAlgorithm: .A256CBCHS512, encryptionKey: publicKey)!

请注意,提供的加密密钥的类型必须与指定的密钥管理算法匹配,如下表所示。

密钥管理算法 加密密钥类型
RSA1_5 SecKey
RSAOAEP SecKey
RSAOAEP256 SecKey
A128KW 数据
A192KW 数据
A256KW 数据
direct 数据
序列化

JWE 紧凑序列化是一个 URL 安全的字符串,可以使用您选择的方法轻松地传输给第三方。

guard let jwe = try? JWE(header: header, payload: payload, encrypter: encrypter) else { ... }

print(jwe.compactSerializedString) // ey (..) n0.HK (..) pQ.yS (..) PA.AK (..) Jx.hB (..) 7w

有关构建 JWE 的更多详细信息,请参见wiki

解密数据

let privateKey: SecKey = /* ... */

let serialization = "ey (..) n0.HK (..) pQ.yS (..) PA.AK (..) Jx.hB (..) 7w"
do {
    let jwe = try JWE(compactSerialization: serialization)
    let decrypter = Decrypter(keyManagementAlgorithm: .RSA1_5, contentEncryptionAlgorithm: .A256CBCHS512, decryptionKey: privateKey)!
    let payload = try jwe.decrypt(using: decrypter)
    let message = String(data: payload.data(), encoding: .utf8)!

    print(message) // Summer ⛱, Sun ☀️, Cactus 🌵
}

有关解密现有序列化的 JWE 的更多详细信息,请参见wiki

请注意,提供的解密密钥的类型必须与指定的密钥管理算法匹配,如下表所示。

密钥管理算法 解密密钥类型
RSA1_5 SecKey
RSAOAEP SecKey
RSAOAEP256 SecKey
A128KW 数据
A192KW 数据
A256KW 数据
direct 数据

JWK:表示密钥

JWK 是一种 JSON 数据结构,表示加密密钥。 例如,您可以将其用作 JWS 或 JWE 的有效负载,以将您的公钥传输到服务器。

编码 RSA 公钥

let publicKey: SecKey = /* ... */

let jwk = try! RSAPublicKey(publicKey: publicKey)

let json = jwk.jsonString()! // {"kty":"RSA","n":"MHZ4L...uS2d3","e":"QVFBQg"}

有关编码 RSA 公钥的更多详细信息,请参见wiki

解码 RSA 公钥

let json: Data = /* ... */

let jwk = try! RSAPublicKey(data: json)

let publicKey: SecKey = try! jwk.converted(to: SecKey.self)

有关解码 RSA 公钥的更多详细信息,请参见wiki

⚠️目前,解码时我们会忽略密钥参数 "key_ops""x5c"。 这是由于我们的解码实现中的一个错误。 有关详细信息,请参见#117

安全

JOSESwift 使用 Apple 的 Security frameworkApple 的 CommonCryptoApple 的 CryptoKit 进行加密。

对于安全披露或相关事宜,请联系joseswift@airsidemobile.com

有关更多信息,请参见我们的安全策略

贡献

鼓励并非常欢迎为该项目做出贡献。 🤓

如果您想做出贡献,请提交 pull request。 对于功能请求、讨论或错误报告,只需打开一个 issue。

有关更多信息,请参见我们的贡献指南

资源

您可以在相应的 RFC 中找到有关相关 JOSE 标准的详细信息

不要忘记查看我们的 wiki 以获取更详细的文档。

联系

请随时通过joseswift@airsidemobile.com与项目维护者联系。

致谢

JOSESwift 由 Airside Mobile 维护。

项目维护者

@daniel-moh, @haeser

Logo

该徽标由 Ivan Leuzzi 设计。

感谢

感谢以下项目,它们在开发过程中为我们提供了参考和灵感

许可证

JOSESwift 在 Apache License 2.0 下获得许可。 有关详细信息,请参见LICENSE