diff --git a/Sources/JWSETKit/Cryptography/Algorithms/Algorithms.swift b/Sources/JWSETKit/Cryptography/Algorithms/Algorithms.swift index c2fc744..48d542f 100644 --- a/Sources/JWSETKit/Cryptography/Algorithms/Algorithms.swift +++ b/Sources/JWSETKit/Cryptography/Algorithms/Algorithms.swift @@ -12,9 +12,17 @@ import CryptoKit import Crypto #endif +/// JSON Web Signature Algorithms. public protocol JSONWebAlgorithm: RawRepresentable, Hashable, Codable, ExpressibleByStringLiteral, Sendable { + /// Key type, which is either `RSA`, `EC` for elliptic curve or `oct` for symmetric keys. var keyType: JSONWebKeyType? { get } + + /// Elliptic key curve, if key type is `EC`. var curve: JSONWebKeyCurve? { get } + + /// Initialize algorithm from name. + /// + /// - Parameter rawValue: JWA registered name. init(_ rawValue: S) } @@ -88,7 +96,7 @@ extension JSONWebAlgorithm { } } -/// JSON Web Signature Algorithms +/// JSON Web Signature Algorithms. public struct AnyJSONWebAlgorithm: JSONWebAlgorithm { public let rawValue: String diff --git a/Sources/JWSETKit/Documentation.docc/Extensions/JWE.md b/Sources/JWSETKit/Documentation.docc/Extensions/JWE.md index 5772bdc..882aa31 100644 --- a/Sources/JWSETKit/Documentation.docc/Extensions/JWE.md +++ b/Sources/JWSETKit/Documentation.docc/Extensions/JWE.md @@ -4,9 +4,70 @@ Use JWE to encrypt a payload. ## Overview +JSON Web Encryption (JWE) represents encrypted content using JSON-based +data structures RFC7159. The JWE cryptographic mechanismsencrypt +and provide integrity protection for an arbitrary sequence of octets. + +## Decoding And Decrypting + +To create a new instance from compact or complete serialization, + +``` swift +let jwe = try JSONWebEncryption(from: jweString) +``` + +Now it is possible to decrypt data using private key, + +```swift +let data = try jwe.decrypt(using: keyEncryptionKey) +``` + +Decrypted content now can be deserialzed. For example if content is JWT claims, + +```swift +let claims = JSONDecoder().decode(JSONWebTokenClaims.self, from: data) +``` + +## Encrypting & Encoding + +To create a new container from plain-text data and a key, first +create a new random *Key Encryption Key* or use an existing one. + +Either provide no `contentEncryptionKey` to generate new random one, +or provide an existing one. + +Finally, serialize the result into string representation. + +```swift +// Generate a new AES-KeyWrap key with `A256KW` algorithm. +let kek = JSONWebKeyAESKW(.bits256) + +// Alternatively, simply generate a 256-bit `SymmetricKey`. +// +// This works well as `keyEncryptingAlgorithm` is provided +// in next step. +let kek = SymmetricKey(size: .bits256) + +// Create JWE container with random content enc. key. +let jwe = try! JSONWebEncryption( + content: Data("Live long and prosper.".utf8), + keyEncryptingAlgorithm: .aesKeyWrap256, + keyEncryptionKey: kek, + contentEncryptionAlgorithm: .aesEncryptionGCM128 +) + +// Encode JWE in compact string. +let jweString = try! String(jwe: jwe) +``` + +In case multiple recipient support is neccessary or a unknown newly registered key type +is used for encryption, you may first create encrypted key and sealed box and use +``JSONWebEncryption/init(header:recipients:sealed:additionalAuthenticatedData:)`` +to create JWE instance from parts. + ## Topics -### Cotents +### Contents - ``JSONWebEncryptionHeader`` - ``JSONWebEncryptionRecipient`` @@ -22,3 +83,8 @@ Use JWE to encrypt a payload. - ``JSONWebKeyAESGCM`` - ``JSONWebKeyAESCBCHMAC`` + +### Encoding + +- ``JSONWebEncryptionRepresentation`` +- ``JSONWebEncryptionCodableConfiguration`` diff --git a/Sources/JWSETKit/Documentation.docc/Extensions/JWS.md b/Sources/JWSETKit/Documentation.docc/Extensions/JWS.md index ebf5854..0e5c70e 100644 --- a/Sources/JWSETKit/Documentation.docc/Extensions/JWS.md +++ b/Sources/JWSETKit/Documentation.docc/Extensions/JWS.md @@ -141,3 +141,8 @@ try jws.updateSignature(using: hmacKey) - ``JOSEHeader`` - ``JoseHeaderJWSRegisteredParameters`` - ``JoseHeaderJWERegisteredParameters`` + +### Encoding + +- ``JSONWebSignatureRepresentation`` +- ``JSONWebSignatureCodableConfiguration`` diff --git a/Sources/JWSETKit/Documentation.docc/Extensions/JWSETKit.md b/Sources/JWSETKit/Documentation.docc/Extensions/JWSETKit.md index 90da29d..8cf191a 100644 --- a/Sources/JWSETKit/Documentation.docc/Extensions/JWSETKit.md +++ b/Sources/JWSETKit/Documentation.docc/Extensions/JWSETKit.md @@ -53,3 +53,24 @@ of JWS. Check ``JSONWebEncryption`` documentation for usage, encrypting and decrypting payload. + +## Topics + +### Essentials + +- ``JSONWebToken`` +- ``JSONWebSignature`` +- ``JSONWebEncryption`` + +### Cryptography + +- + +### Extending + +- +- ``JSONWebContainer`` +- ``ProtectedWebContainer`` +- ``TypedProtectedWebContainer`` +- ``ProtectedJSONWebContainer`` +- ``ProtectedDataWebContainer`` diff --git a/Sources/JWSETKit/Documentation.docc/Extensions/JWT.md b/Sources/JWSETKit/Documentation.docc/Extensions/JWT.md index 4a279f6..e36ed6f 100644 --- a/Sources/JWSETKit/Documentation.docc/Extensions/JWT.md +++ b/Sources/JWSETKit/Documentation.docc/Extensions/JWT.md @@ -100,17 +100,18 @@ extension JSONWebTokenClaims { ``` Intrinsic supported types to be parsed by generic accessor are: + - `UnsignedInteger` conforming types, e.g. `UInt`, `UInt32`, etc. - `SignedInteger` conforming types, e.g. `Int`, `Int32`, etc. - `BinaryFloatingPoint` conforming types, e.g. `Double`, `Float`, etc. -- `Foundation. Decimal` +- `Foundation.Decimal` - `Foundation.Date`, serialized as unix timestamp. - `Array`, `Foundation.Data`, `Foundation.NSData`, seriailzed as `Base64URL`. - `Foundation.URL` - `Foundation.Locale`, `Foundation.NSLocale` - `Foundation.TimeZone`, `Foundation.NSTimeZone` - Types conformed to ``JSONWebKey``. -- Types conformed to``JSONWebAlgorithm``. +- Types conformed to ``JSONWebAlgorithm``. - Types conformed to `Foundation.Decodable`. diff --git a/Sources/JWSETKit/Documentation.docc/Manuals/4-Keys.md b/Sources/JWSETKit/Documentation.docc/Manuals/3-Cryptography.md similarity index 61% rename from Sources/JWSETKit/Documentation.docc/Manuals/4-Keys.md rename to Sources/JWSETKit/Documentation.docc/Manuals/3-Cryptography.md index c26cea9..d396439 100644 --- a/Sources/JWSETKit/Documentation.docc/Manuals/4-Keys.md +++ b/Sources/JWSETKit/Documentation.docc/Manuals/3-Cryptography.md @@ -1,54 +1,62 @@ -# Keys and Certificates +# Cryptography -Using cryptographic keys to sign, verify, encrypt and decrypt contents. - -## Overview - -This article give details about keys and their usage. +Cryptography keys and algorithms ## Protocols -### JSONWebKey +### Key Protocol An object that can represented in A JSON Web Key (JWK). data structure represents a cryptographic key. -The key object can be fetched using [`storage`](jsonwebcontainer/storage) property. +The key object can be fetched using ``JSONWebContainer/storage`` property. + +See ``JSONWebKey``. -### JSONWebValidatingKey +### Signature Validation This protocol defines method to verify signatures, which is usually a public or symmetric key. -### JSONWebEncryptingKey +See ``JSONWebValidatingKey``. + +### Encryption This method defines method to encrypt a plain-text, which is usually a public or symmetric key. -### JSONWebSigningKey +See ``JSONWebEncryptingKey``. + +### Signing This protocol defines method to generate a new signature out of data, which is usually a private or symmetric key. -### JSONWebDecryptingKey +See ``JSONWebSigningKey`` and ``JSONWebSymmetricSigningKey``. + +### Decryption This protocol defines method to decrypt a cipher-text, which is usually a private or symmetric key. -### JSONWebSealingKey +See ``JSONWebDecryptingKey`` and ``JSONWebSymmetricDecryptingKey``. + +### Sealing This method defines method to encrypt/decrypt a plain-text with initial vector and resulting an authentication tag, which is asymmetric key. -## Implementations +See ``JSONWebSealingKey``. + +## Keys and Certificates ### Symmetric -#### JSONWebKeyHMAC +#### HMAC Supports `HS256`, `HS384` and `HS512` algorithms for signature. -Usable for validating and signing. See [JSONWebKeyHMAC](jsonwebkeyhmac). +Usable for validating and signing. See ``JSONWebKeyHMAC``. #### SymmetricKey @@ -59,89 +67,88 @@ Supports `HS256`, `HS384` and `HS512` algorithms for signature, encryption/decryption. Usable for validating, signing, decryption and encrypting. -See [SymmetricKey](cryptokit/symmetrickey). +See ``CryptoKit/SymmetricKey``. ##### Generating SymmetricKey using PBKDF2 -To generate a symmetric key using PBKDF2 use -[SymmetricKey.pbkdf2(pbkdf2password:salt:hashfunction:iterations:)](cryptokit/symmetrickey/pbkdf2(pbkdf2password:salt:hashfunction:iterations:)) method. +To generate a symmetric key using PBKDF2 use ``CryptoKit/SymmetricKey/pbkdf2(pbkdf2Password:salt:hashFunction:iterations:)`` method. -#### JSONWebKeyAESGCM +#### AES GCM Supports `A128GCM`, `A192GCM` and `A256GCM` algorithms for encryption. -Usable for decryption and encrypting. See [JSONWebKeyAESGCM](jsonwebkeyaesgcm). +Usable for decryption and encrypting. See ``JSONWebKeyAESGCM``. -#### JSONWebKeyAESCBCHMAC +#### AES CBC-HMAC Supports `A128CBC-HS256`, `A192CBC-HS384` and `A256CBC-HS512` algorithms for encryption. -Usable for decryption and encrypting. See [JSONWebKeyAESCBCHMAC](jsonwebkeyaescbchmac). +Usable for decryption and encrypting. See ``JSONWebKeyAESCBCHMAC``. ### Eliptic-Curve -#### JSONWebECPublicKey +#### Public Key Supports `ES256`, `ES384`, `ES512` and `EdDSA` algorithms for signature. -Usable for validating. See [JSONWebECPublicKey](jsonwebecpublickey). +Usable for validating. See ``JSONWebECPublicKey``. -#### JSONWebECPrivateKey +##### P256.Signing.PublicKey -Supports `ES256`, `ES384`, `ES512` and `EdDSA` algorithms for signature. +Supports `ES256` algorithm for signature. -Usable for validating and signing. See [JSONWebECPrivateKey](jsonwebecprivatekey). +Usable for validating. +See [P256.Signing.PublicKey](cryptokit/p256/signing/publickey). -#### P256.Signing.PublicKey +###### P384.Signing.PublicKey -Supports `ES256` algorithm for signature. +Supports `ES384` algorithm for signature. Usable for validating. -See [P256.Signing.PublicKey](cryptokit/p256/signing/publickey). +See [P384.Signing.PublicKey](cryptokit/p384/signing/publickey). -#### P256.Signing.PrivateKey +##### P521.Signing.PublicKey -Supports `ES256` algorithm for signature. +Supports `ES512` algorithm for signature. -Usable for validating and signing. -See [P256.Signing.PrivateKey](cryptokit/p256/signing/privatekey). +Usable for validating. +See [P521.Signing.PublicKey](cryptokit/p521/signing/publickey). -##### P384.Signing.PublicKey +##### Ed25519.Signing.PublicKey -Supports `ES384` algorithm for signature. +Supports `EdDSA` algorithm for signature. Usable for validating. -See [P384.Signing.PublicKey](cryptokit/p384/signing/publickey). +See [Curve25519.Signing.PublicKey](cryptokit/curve25519/signing/publickey). -#### P384.Signing.PrivateKey +#### Private Key -Supports `ES384` algorithm for signature. +Supports `ES256`, `ES384`, `ES512` and `EdDSA` algorithms for signature. -Usable for validating and signing. -See [P384.Signing.PrivateKey](cryptokit/p384/signing/privatekey). +Usable for validating and signing. See ``JSONWebECPrivateKey``. -##### P521.Signing.PublicKey +##### P256.Signing.PrivateKey -Supports `ES512` algorithm for signature. +Supports `ES256` algorithm for signature. -Usable for validating. -See [P521.Signing.PublicKey](cryptokit/p521/signing/publickey). +Usable for validating and signing. +See [P256.Signing.PrivateKey](cryptokit/p256/signing/privatekey). -#### P384.Signing.PrivateKey +##### P384.Signing.PrivateKey -Supports `ES512` algorithm for signature. +Supports `ES384` algorithm for signature. Usable for validating and signing. -See [P521.Signing.PrivateKey](cryptokit/p521/signing/privatekey). +See [P384.Signing.PrivateKey](cryptokit/p384/signing/privatekey). -##### Ed25519.Signing.PublicKey +##### P384.Signing.PrivateKey -Supports `EdDSA` algorithm for signature. +Supports `ES512` algorithm for signature. -Usable for validating. -See [Curve25519.Signing.PublicKey](cryptokit/curve25519/signing/publickey). +Usable for validating and signing. +See [P521.Signing.PrivateKey](cryptokit/p521/signing/privatekey). -#### Ed25519.Signing.PrivateKey +##### Ed25519.Signing.PrivateKey Supports `EdDSA` algorithm for signature. @@ -150,26 +157,26 @@ See [Curve25519.Signing.PrivateKey](cryptokit/curve25519/signing/privatekey). ### RSA -#### JSONWebRSAPublicKey +#### Public Key Supports `RS256`, `RS384`, `RS512`, `PS256`, `PS384` and `PS512` algorithms for signature and `RSA1_5`, `RSA-OAEP`, `RSA-OAEP-256`, `RSA-OAEP-384` and `RSA-OAEP-512` for encryption. -Usable for validating and decryption. See [JSONWebRSAPublicKey](jsonwebrsapublickey). +Usable for validating and decryption. See ``JSONWebRSAPublicKey``. -#### JSONWebRSAPrivateKey +#### Private Key Supports `RS256`, `RS384`, `RS512`, `PS256`, `PS384` and `PS512` algorithms for signature and `RSA1_5`, `RSA-OAEP`, `RSA-OAEP-256`, `RSA-OAEP-384` and `RSA-OAEP-512` for encryption. -Usable for validating, signing, decryption and encryption. See [JSONWebRSAPrivateKey](jsonwebrsaprivatekey). +Usable for validating, signing, decryption and encryption. See ``JSONWebRSAPrivateKey``. #### SecKey Supports `RS256`, `RS384`, `RS512`, `PS256`, `PS384`, `PS512`, `ES256`, `ES384`and `ES512` algorithms for signature. -Usable for validating and signing. See [SecKey](security/seckey). +Usable for validating and signing. See ``Security/SecKey``. #### \_RSA.Signing.PublicKey @@ -196,11 +203,62 @@ See [_CryptoExtras._RSA.Signing.PrivateKey](_cryptoextras/_rsa/signing/privateke Supports `RS256`, `RS384`, `RS512`, `PS256`, `PS384`, `PS512`, `ES256`, `ES384`and `ES512` algorithms for signature. -Usable for validating. See [X509.Certificate](x509/certificate). +Usable for validating. See ``X509/Certificate``. #### SecCertificate Supports `RS256`, `RS384`, `RS512`, `PS256`, `PS384`, `PS512`, `ES256`, `ES384`and `ES512` algorithms for signature. -Usable for validating. See [SecCertificate](security/seccertificate) +Usable for validating. See ``Security/SecCertificate``. + +## Topics + +- ``JSONWebKeyError`` + +### Protocols + +- ``JSONWebKey`` +- ``JSONWebValidatingKey`` +- ``JSONWebSigningKey`` +- ``JSONWebSymmetricSigningKey`` +- ``JSONWebEncryptingKey`` +- ``JSONWebDecryptingKey`` +- ``JSONWebSymmetricDecryptingKey`` +- ``JSONWebSealingKey`` + +### Containers + +- ``AnyJSONWebKey`` +- ``JSONWebKeySet`` + +### Symmetric + +- ``CryptoKit/SymmetricKey`` +- ``JSONWebKeyHMAC`` +- ``JSONWebKeyAESGCM`` +- ``JSONWebKeyAESCBCHMAC`` +- ``JSONWebKeyAESKW`` +- ``CryptoKit/SymmetricKey/pbkdf2(pbkdf2Password:salt:hashFunction:iterations:)`` + +### RSA + +- ``JSONWebRSAPublicKey`` +- ``JSONWebRSAPrivateKey`` +- ``Security/SecKey`` +- ``Security/SecCertificate`` +- ``Security/SecTrust`` + +### Elliptic Curve + +- ``JSONWebECPublicKey`` +- ``JSONWebECPrivateKey`` + +### Algorithms + +- ``JSONWebAlgorithm`` +- ``AnyJSONWebAlgorithm`` +- ``JSONWebSignatureAlgorithm`` +- ``JSONWebKeyEncryptionAlgorithm`` +- ``JSONWebContentEncryptionAlgorithm`` +- ``JSONWebCompressionAlgorithm`` diff --git a/Sources/JWSETKit/Documentation.docc/Manuals/9-Extending.md b/Sources/JWSETKit/Documentation.docc/Manuals/7-Extending-Container.md similarity index 100% rename from Sources/JWSETKit/Documentation.docc/Manuals/9-Extending.md rename to Sources/JWSETKit/Documentation.docc/Manuals/7-Extending-Container.md diff --git a/Sources/JWSETKit/Entities/JWT/JWTPayload.swift b/Sources/JWSETKit/Entities/JWT/JWTPayload.swift index 27929b8..3e7a0e2 100644 --- a/Sources/JWSETKit/Entities/JWT/JWTPayload.swift +++ b/Sources/JWSETKit/Entities/JWT/JWTPayload.swift @@ -50,33 +50,56 @@ extension JSONWebToken { self.payload = try .init(value: payload) try updateSignature(using: signingKey) } - +} + +extension JSONWebTokenClaims { /// Verify that the given audience is included as one of the claim's intended audiences. /// /// - Parameter audience: The exact intended audience. public func verifyAudience(includes audience: String) throws { - guard payload.value.audience.contains(audience) else { - throw JSONWebValidationError.tokenExpired(expiry: .init()) + // swiftformat:disable:next redundantSelf + guard self.audience.contains(audience) else { + throw JSONWebValidationError.audienceNotIntended(audience) } } } -extension JSONWebToken: Expirable { +extension JSONWebToken { + /// Verify that the given audience is included as one of the claim's intended audiences. + /// + /// - Parameter audience: The exact intended audience. + public func verifyAudience(includes audience: String) throws { + try payload.value.verifyAudience(includes: audience) + } +} + +extension JSONWebTokenClaims: Expirable { /// Verifies the `exp` and `nbf` headers using current date. /// /// - Parameters: /// - currentDate: The date that headers will be check against. Default is current system date. public func verifyDate(_ currentDate: Date) throws { - let claims = payload.value - if let expiry = claims.expiry, currentDate > expiry { + // swiftformat:disable:next redundantSelf + if let expiry = self.expiry, currentDate > expiry { throw JSONWebValidationError.tokenExpired(expiry: expiry) } - if let notBefore = claims.notBefore, currentDate < notBefore { + // swiftformat:disable:next redundantSelf + if let notBefore = self.notBefore, currentDate < notBefore { throw JSONWebValidationError.tokenInvalidBefore(notBefore: notBefore) } } } +extension JSONWebToken: Expirable { + /// Verifies the `exp` and `nbf` headers using current date. + /// + /// - Parameters: + /// - currentDate: The date that headers will be check against. Default is current system date. + public func verifyDate(_ currentDate: Date) throws { + try payload.value.verifyDate(currentDate) + } +} + #if canImport(Foundation.NSURLSession) extension URLRequest { /// The `Authorization` http header in `Bearer` with given JSON Web Token (JWT). diff --git a/Sources/JWSETKit/Extensions/Base64.swift b/Sources/JWSETKit/Extensions/Base64.swift index cc70271..59de686 100644 --- a/Sources/JWSETKit/Extensions/Base64.swift +++ b/Sources/JWSETKit/Extensions/Base64.swift @@ -74,3 +74,16 @@ extension Data { self = value } } + +extension Data { + init(bigEndian value: T) { + let count = T.bitWidth / 8 + var value = value.bigEndian + let bytePtr = withUnsafePointer(to: &value) { + $0.withMemoryRebound(to: UInt8.self, capacity: count) { + UnsafeBufferPointer(start: $0, count: count) + } + } + self = Data(bytePtr) + } +}