-
Notifications
You must be signed in to change notification settings - Fork 113
A JSON Web Key (JWK) is a JSON data structure that represents a cryptographic key.
The following JSON object represents an RSA public key.
{
"kty":"RSA",
"n": "0vx7a...qDKgw",
"e":"AQAB",
"alg":"RS256",
"kid":"2011-04-29"
}
A JWK Set is a JSON object that represents a set of JWKs. It has a ”keys”
member. The value of this member is an array of JWKs.
{
"keys": [
{
"kty":"RSA",
"n": "0vx7a...qDKgw",
"e":"AQAB",
"alg":"RS256",
"kid":"2011-04-29"
},
{
"kty":"RSA",
"n": "agoeb...pJzKn",
"e":"AQAB"
}
]
}
This section describes how the above concepts are implemented and used in JOSESwift.
JOSESwift implements JWK representation for RSA public keys and for RSA private keys without optional parameters as they are defined in PKCS#1.
JWS
is a protocol
with the following requirements:
protocol JWK: Codable {
var keyType: JWKKeyType { get }
var parameters: [String: JWKParameterType] { get }
subscript(parameter: String) -> Any? { get }
init(data: Data) throws
func jsonString() -> String?
func jsonData() -> Data?
}
Via the JWK
subscript can directly access the parameters dictionary. Additionally, the JWK
protocol also provides typed getters for the parameters defined in RFC-7517:
let publicKey: RSAPublicKey = /* ... */
publicKey["use"] // "sig"
publicKey.use // "sig"
type(of: publicKey["use"]) // Optional<Any>.Type
type(of: publicKey.use) // Optional<String>.Type
Key specific parameters defined in RFC-7518 are provided as parameters in the respective key types (e.g. RSAPublicKey
).
RSA keys are represented as struct
s that conform to the JWS
protocol.
struct RSAPublicKey: JWK {
let keyType: JWKKeyType
let parameters: [String: JWKParameterType]
let modulus: String
let exponent: String
struct RSAPrivateKey: JWK {
let keyType: JWKKeyType
let parameters: [String: JWKParameterType]
let modulus: String
let exponent: String
let privateExponent: String
The following examples use RSA public keys. If not noted otherwise, the functionality is similar for RSA private keys.
RSAPublicKey
provides an initializer expecting an existing public key as a parameter. This key has to conform to ExpressibleAsRSAPublicKeyComponents
. Optionally additional JWK parameters can be supplied.
init(publicKey: ExpressibleAsRSAPublicKeyComponents, additionalParameters parameters: [String: String] = [:]) throws
By default, Data
containing an RSA public key in PKCS#1 format and iOS’s SecKey
conform to ExpressibleAsRSAPublicKeyComponents
. Of course, you can extend your own custom key types to conform to this protocol. It has the following requirements:
public protocol ExpressibleAsRSAPublicKeyComponents {
// Constucts an instance of it's type from the given components.
static func representing(rsaPublicKeyComponents components: RSAPublicKeyComponents) throws -> Self
// Converts the key to modulus and exponent.
func rsaPublicKeyComponents() throws -> RSAPublicKeyComponents
}
SecKey
already conforms to ExpressibleAsRSAPublicKeyComponents
. Instantiating an RSAPublicKey
is done using:
let publicKey: SecKey = /* ... */
let jwk = try! RSAPublicKey(publicKey: publicKey)
You can then get the JWK JSON object from this RSAPublicKey
like this:
let json = jwk.jsonString()! // "{"kty": "RSA", "n": "MHZ4L...uS2d3", "e": "QVFBQg"}"
Or like this:
let json = jwk.jsonData()!
JWK
requires conformance to Codable
. This is possible as well:
let json = try! JSONEncoder().encode(jwk)
💡 Note that SecKey
and Data
do not already conform to ExpressibleAsRSAPrivateKeyComponents
.
The following examples use RSA public keys. If not noted otherwise, the functionality is similar for RSA private keys.
RSAPublicKey
provides an initializer expecting JSON data representing a JWK as a parameter.
init(data: Data) throws
You can get a RSAPublicKey
instance from JWK data like this:
let json: Data = /* ... */
let jwk = try! RSAPublicKey(data: json)
JWK
requires conformance to Codable
. This is possible as well:
let jwk = try JSONDecoder().decode(RSAPublicKey.self, from: json)
You can then convert this RSAPublicKey
to any type that conforms to ExpressibleAsRSAPublicKeyComponents
. For more details regarding this protocol, see Initializing a JWK from an Existing RSA Key.
let publicKey: SecKey = try! jwk.converted(to: SecKey.self)
Or:
// Data will be in PKCS#1 format.
let publicKey: Data = try! jwk.converted(to: Data.self)
💡 Note that SecKey
and Data
do not already conform to ExpressibleAsRSAPrivateKeyComponents
.