Skip to content

Commit e3928a9

Browse files
committed
added rsa 256
1 parent 41b20db commit e3928a9

File tree

4 files changed

+66
-44
lines changed

4 files changed

+66
-44
lines changed

.DS_Store

0 Bytes
Binary file not shown.

Sources/Decode.swift

Lines changed: 20 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -5,25 +5,25 @@ import Foundation
55
public enum InvalidToken: CustomStringConvertible, Error {
66
/// Decoding the JWT itself failed
77
case decodeError(String)
8-
8+
99
/// The JWT uses an unsupported algorithm
1010
case invalidAlgorithm
11-
11+
1212
/// The issued claim has expired
1313
case expiredSignature
14-
14+
1515
/// The issued claim is for the future
1616
case immatureSignature
17-
17+
1818
/// The claim is for the future
1919
case invalidIssuedAt
20-
20+
2121
/// The audience of the claim doesn't match
2222
case invalidAudience
23-
23+
2424
/// The issuer claim failed to verify
2525
case invalidIssuer
26-
26+
2727
/// Returns a readable description of the error
2828
public var description: String {
2929
switch self {
@@ -49,12 +49,12 @@ public enum InvalidToken: CustomStringConvertible, Error {
4949
/// Decode a JWT
5050
public func decode(_ jwt: String, algorithms: [Algorithm], verify: Bool = true, audience: String? = nil, issuer: String? = nil) throws -> ClaimSet {
5151
let (header, claims, signature, signatureInput) = try load(jwt)
52-
52+
5353
if verify {
5454
try claims.validate(audience: audience, issuer: issuer)
5555
try verifySignature(algorithms, header: header, signingInput: signatureInput, signature: signature)
5656
}
57-
57+
5858
return claims
5959
}
6060

@@ -82,35 +82,35 @@ func load(_ jwt: String) throws -> (header: JOSEHeader, payload: ClaimSet, signa
8282
if segments.count != 3 {
8383
throw InvalidToken.decodeError("Not enough segments")
8484
}
85-
85+
8686
let headerSegment = segments[0]
8787
let payloadSegment = segments[1]
8888
let signatureSegment = segments[2]
8989
let signatureInput = "\(headerSegment).\(payloadSegment)"
90-
90+
9191
guard let headerData = base64decode(headerSegment) else {
9292
throw InvalidToken.decodeError("Header is not correctly encoded as base64")
9393
}
94-
94+
9595
let header = (try? JSONSerialization.jsonObject(with: headerData, options: JSONSerialization.ReadingOptions(rawValue: 0))) as? Payload
9696
if header == nil {
9797
throw InvalidToken.decodeError("Invalid header")
9898
}
99-
99+
100100
let payloadData = base64decode(payloadSegment)
101101
if payloadData == nil {
102102
throw InvalidToken.decodeError("Payload is not correctly encoded as base64")
103103
}
104-
104+
105105
let payload = (try? JSONSerialization.jsonObject(with: payloadData!, options: JSONSerialization.ReadingOptions(rawValue: 0))) as? Payload
106106
if payload == nil {
107107
throw InvalidToken.decodeError("Invalid payload")
108108
}
109-
109+
110110
guard let signature = base64decode(signatureSegment) else {
111111
throw InvalidToken.decodeError("Signature is not correctly encoded as base64")
112112
}
113-
113+
114114
return (header: JOSEHeader(parameters: header!), payload: ClaimSet(claims: payload!), signature: signature, signatureInput: signatureInput)
115115
}
116116

@@ -120,11 +120,11 @@ func verifySignature(_ algorithms: [Algorithm], header: JOSEHeader, signingInput
120120
guard let alg = header.algorithm else {
121121
throw InvalidToken.decodeError("Missing Algorithm")
122122
}
123-
124-
let verifiedAlgorithms = algorithms
123+
124+
let verifiedAlgorithms = try algorithms
125125
.filter { algorithm in algorithm.description == alg }
126-
.filter { algorithm in algorithm.verify(signingInput, signature: signature) }
127-
126+
.filter { algorithm in try algorithm.verify(signingInput, signature: signature) }
127+
128128
if verifiedAlgorithms.isEmpty {
129129
throw InvalidToken.invalidAlgorithm
130130
}

Sources/Encode.swift

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -5,25 +5,25 @@ import Foundation
55
- parameter algorithm: The algorithm to sign the payload with
66
- returns: The JSON web token as a String
77
*/
8-
public func encode(claims: ClaimSet, algorithm: Algorithm, headers: [String: String]? = nil) -> String {
8+
public func encode(claims: ClaimSet, algorithm: Algorithm, headers: [String: String]? = nil) throws -> String {
99
func encodeJSON(_ payload: [String: Any]) -> String? {
1010
if let data = try? JSONSerialization.data(withJSONObject: payload) {
1111
return base64encode(data)
1212
}
13-
13+
1414
return nil
1515
}
16-
16+
1717
var headers = headers ?? [:]
1818
if !headers.keys.contains("typ") {
1919
headers["typ"] = "JWT"
2020
}
2121
headers["alg"] = algorithm.description
22-
22+
2323
let header = encodeJSON(headers)!
2424
let payload = encodeJSON(claims.claims)!
2525
let signingInput = "\(header).\(payload)"
26-
let signature = algorithm.sign(signingInput)
26+
let signature = try algorithm.sign(signingInput)
2727
return "\(signingInput).\(signature)"
2828
}
2929

@@ -32,16 +32,16 @@ public func encode(claims: ClaimSet, algorithm: Algorithm, headers: [String: Str
3232
- parameter algorithm: The algorithm to sign the payload with
3333
- returns: The JSON web token as a String
3434
*/
35-
public func encode(claims: [String: Any], algorithm: Algorithm, headers: [String: String]? = nil) -> String {
36-
return encode(claims: ClaimSet(claims: claims), algorithm: algorithm, headers: headers)
35+
public func encode(claims: [String: Any], algorithm: Algorithm, headers: [String: String]? = nil) throws -> String {
36+
return try encode(claims: ClaimSet(claims: claims), algorithm: algorithm, headers: headers)
3737
}
3838

3939

4040
/// Encode a set of claims using the builder pattern
41-
public func encode(_ algorithm: Algorithm, closure: ((ClaimSetBuilder) -> Void)) -> String {
41+
public func encode(_ algorithm: Algorithm, closure: ((ClaimSetBuilder) -> Void)) throws -> String {
4242
let builder = ClaimSetBuilder()
4343
closure(builder)
44-
return encode(claims: builder.claims, algorithm: algorithm)
44+
return try encode(claims: builder.claims, algorithm: algorithm)
4545
}
4646

4747

@@ -51,6 +51,6 @@ public func encode(_ algorithm: Algorithm, closure: ((ClaimSetBuilder) -> Void))
5151
- returns: The JSON web token as a String
5252
*/
5353
@available(*, deprecated, message: "use encode(claims: algorithm:) instead")
54-
public func encode(_ payload: Payload, algorithm: Algorithm) -> String {
55-
return encode(claims: ClaimSet(claims: payload), algorithm: algorithm)
54+
public func encode(_ payload: Payload, algorithm: Algorithm) throws -> String {
55+
return try encode(claims: ClaimSet(claims: payload), algorithm: algorithm)
5656
}

Sources/JWT.swift

Lines changed: 35 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,26 @@
11
import Foundation
22
import CryptoSwift
3+
import SwiftyRSA
34

45
public typealias Payload = [String: Any]
56

67
/// The supported Algorithms
78
public enum Algorithm: CustomStringConvertible {
89
/// No Algorithm, i-e, insecure
910
case none
10-
11+
1112
/// HMAC using SHA-256 hash algorithm
1213
case hs256(Data)
13-
14+
1415
/// HMAC using SHA-384 hash algorithm
1516
case hs384(Data)
16-
17+
1718
/// HMAC using SHA-512 hash algorithm
1819
case hs512(Data)
19-
20+
21+
/// RSA using SHA-256 hash algorithm
22+
case rsa256(PrivateKey)
23+
2024
public var description: String {
2125
switch self {
2226
case .none:
@@ -27,11 +31,14 @@ public enum Algorithm: CustomStringConvertible {
2731
return "HS384"
2832
case .hs512:
2933
return "HS512"
34+
case .rsa256:
35+
return "RSA256"
3036
}
3137
}
32-
38+
3339
/// Sign a message using the algorithm
34-
func sign(_ message: String) -> String {
40+
func sign(_ message: String) throws -> String {
41+
3542
func signHS(_ key: Data, variant: CryptoSwift.HMAC.Variant) -> String {
3643
let messageData = message.data(using: String.Encoding.utf8, allowLossyConversion: false)!
3744
let mac = HMAC(key: key.bytes, variant: variant)
@@ -43,24 +50,39 @@ public enum Algorithm: CustomStringConvertible {
4350
}
4451
return base64encode(Data(bytes: result))
4552
}
46-
53+
54+
func signRSA(_ privateKey: PrivateKey, digestType: Signature.DigestType) throws -> String {
55+
56+
let clear = try ClearMessage(string: message, using: .utf8)
57+
58+
let signature = try clear.signed(with: privateKey, digestType: digestType)
59+
let base64Signature = signature.base64String
60+
61+
return base64Signature
62+
63+
}
64+
4765
switch self {
4866
case .none:
4967
return ""
50-
68+
5169
case .hs256(let key):
5270
return signHS(key, variant: .sha256)
53-
71+
5472
case .hs384(let key):
5573
return signHS(key, variant: .sha384)
56-
74+
5775
case .hs512(let key):
5876
return signHS(key, variant: .sha512)
77+
78+
case .rsa256(let privateKey):
79+
return try signRSA(privateKey, digestType: .sha256)
80+
5981
}
6082
}
61-
83+
6284
/// Verify a signature for a message using the algorithm
63-
func verify(_ message: String, signature: Data) -> Bool {
64-
return sign(message) == base64encode(signature)
85+
func verify(_ message: String, signature: Data) throws -> Bool {
86+
return try sign(message) == base64encode(signature)
6587
}
6688
}

0 commit comments

Comments
 (0)