Skip to content

Commit

Permalink
fix: Update PBKDF2 count to OWASP recomended 310,000
Browse files Browse the repository at this point in the history
fix: Swift 5.9 build issue
  • Loading branch information
amosavian committed Jan 16, 2025
1 parent dcd0953 commit 4cd3215
Show file tree
Hide file tree
Showing 10 changed files with 189 additions and 17 deletions.
2 changes: 1 addition & 1 deletion Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ let package = Package(
// Linux support
.product(name: "_CryptoExtras", package: "swift-crypto", condition: .when(platforms: .nonDarwin)),
.product(name: "CryptoSwift", package: "CryptoSwift", condition: .when(platforms: .nonDarwin)),
.target(name: "Czlib", condition: .when(platforms: .nonDarwin)),
.byName(name: "Czlib"),
],
resources: [
.process("PrivacyInfo.xcprivacy"),
Expand Down
7 changes: 3 additions & 4 deletions Sources/JWSETKit/Cryptography/Compression/Zlib.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
// Created by Amir Abbas Mousavian on 5/1/24.
//

#if canImport(Czlib)
#if canImport(Czlib) || canImport(zlib)
#if canImport(FoundationEssentials)
import FoundationEssentials
#else
Expand All @@ -23,8 +23,8 @@ extension POSIXError {
case Z_ERRNO:
POSIXError(.EIO, userInfo: [:])
case Z_STREAM_ERROR,
Z_DATA_ERROR,
Z_VERSION_ERROR:
Z_DATA_ERROR,
Z_VERSION_ERROR:
POSIXError(.EINVAL, userInfo: [:])
case Z_MEM_ERROR:
POSIXError(.ENOMEM, userInfo: [:])
Expand All @@ -45,7 +45,6 @@ private func zlibCall(_ handler: () -> Int32) throws -> Int32 {
return status
}


/// Compressor contain compress and decompress implementation using `Compression` framework.
struct ZlibCompressor<Codec>: JSONWebCompressor, Sendable where Codec: CompressionCodec {
static func compress<D>(_ data: D) throws -> Data where D: DataProtocol {
Expand Down
4 changes: 2 additions & 2 deletions Sources/JWSETKit/Cryptography/KeyAccessors.swift
Original file line number Diff line number Diff line change
Expand Up @@ -58,8 +58,8 @@ public struct JSONWebKeyRevocation: Codable, Hashable, Sendable {

public func encode(to encoder: any Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encodeIfPresent((self.time?.timeIntervalSince1970).map(Int.init), forKey: .revokedAt)
try container.encodeIfPresent(self.reason, forKey: .reason)
try container.encodeIfPresent((time?.timeIntervalSince1970).map(Int.init), forKey: .revokedAt)
try container.encodeIfPresent(reason, forKey: .reason)
}
}

Expand Down
2 changes: 1 addition & 1 deletion Sources/JWSETKit/Cryptography/Symmetric/PBKDF2.swift
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ extension SymmetricKey {
static let defaultPBES2IterationCount: [Int: Int] = [
128: 600_000,
192: 450_000,
256: 210_000,
256: 310_000,
]

/// Generates a symmetric key using `PBKDF2` algorithm.
Expand Down
8 changes: 4 additions & 4 deletions Sources/JWSETKit/Entities/JWT/JWTPopClaims.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@
// Created by Amir Abbas Mousavian on 1/15/25.
//

import Foundation
import Crypto
import Foundation

/// Presenter possesses a particular key and that the recipient can cryptographically
/// confirm that the presenter has possession of that key as described in
Expand Down Expand Up @@ -124,7 +124,7 @@ public enum JSONWebTokenConfirmation: Codable, Hashable, Sendable {
self = .certificateThumbprint(jktData)
}

self = .keyId(try container.decode(String.self, forKey: .kid))
self = try .keyId(container.decode(String.self, forKey: .kid))
}

public func encode(to encoder: any Encoder) throws {
Expand All @@ -134,9 +134,9 @@ public enum JSONWebTokenConfirmation: Codable, Hashable, Sendable {
try container.encode(jwk, forKey: .jwk)
case .encryptedKey(let jwe):
try container.encode(jwe, forKey: .jwe)
case let .keyId(kid):
case .keyId(let kid):
try container.encode(kid, forKey: .kid)
case let .url(setURL, kid):
case .url(let setURL, let kid):
try container.encode(setURL, forKey: .jku)
try container.encodeIfPresent(kid, forKey: .kid)
case .certificateThumbprint(let x5t):
Expand Down
2 changes: 1 addition & 1 deletion Tests/JWSETKitTests/Cryptography/CompressionTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ struct CompressionTests {
for deflateCompressor in compressors {
let testDecompressed = try deflateCompressor.decompress(deflateCompressed)
#expect(testDecompressed == decompressed)
}
}
}

@Test
Expand Down
4 changes: 2 additions & 2 deletions Tests/JWSETKitTests/Cryptography/JWKSetTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -97,8 +97,8 @@ struct JWKSetTests {
#expect(jwks[3] is (any JSONWebSigningKey))
#expect(jwks[3] is JSONWebRSAPrivateKey)
#expect(!(jwks[3] is JSONWebRSAPublicKey))
#expect(jwks[3].issuedAt == .init(timeIntervalSince1970: 123972394872))
#expect(jwks[3].revoked == JSONWebKeyRevocation(at: .init(timeIntervalSince1970: 123972495172), for: .compromised))
#expect(jwks[3].issuedAt == .init(timeIntervalSince1970: 123_972_394_872))
#expect(jwks[3].revoked == JSONWebKeyRevocation(at: .init(timeIntervalSince1970: 123_972_495_172), for: .compromised))
}

@Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -363,7 +363,7 @@ struct RFC7520DecryptionTests {
#expect(decodedText == plainText.data)
}

@Test//(.disabled(if: JSONWebCompressionAlgorithm.registeredAlgorithms.isEmpty))
@Test // (.disabled(if: JSONWebCompressionAlgorithm.registeredAlgorithms.isEmpty))
func testDecryptCompact_AESKW_Deflate() throws {
let jweString = """
eyJhbGciOiJBMTI4S1ciLCJraWQiOiI4MWIyMDk2NS04MzMyLTQzZDktYTQ2OC\
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -313,7 +313,7 @@ struct RFC7520EncryptionTests {
#expect(try jwe.decrypt(using: RFC7520ExampleKeys.keyWrapSymmetricKey.key) == plainText.data)
}

@Test//(.disabled(if: JSONWebCompressionAlgorithm.registeredAlgorithms.isEmpty))
@Test // (.disabled(if: JSONWebCompressionAlgorithm.registeredAlgorithms.isEmpty))
func testEncrypt_AESKW_Deflate() throws {
let header = """
eyJhbGciOiJBMTI4S1ciLCJraWQiOiI4MWIyMDk2NS04MzMyLTQzZDktYTQ2OC\
Expand Down
173 changes: 173 additions & 0 deletions Tests/JWSETKitTests/Cryptography/RSACryptoTests.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,173 @@
//
// RSACryptoTests.swift
// JWSETKit
//
// Created by Amir Abbas Mousavian on 1/16/25.
//

import Foundation
import Testing
@testable import JWSETKit
#if canImport(_CryptoExtras)
import _CryptoExtras

@Suite
struct RSACryptoTests {
let privateKeyDER = """
MIIEogIBAAKCAQBc8heBuESxpRARckQCuVNuiLsH5AX73F1lqNxpFsS+GPWl6rrT\
Q0j9Ox/ag2ZwyPby3FtJ11gWT/kDYkjTbqYBCzmzUeGjm3MbuCzErQLPjzGvdUDn\
vCxx8G+uE2uqTdryfEaregUyo69JmucLq3HQ91cHVeLMN/xMvaAu+xEUbZFiDBcV\
wOOWUft7HmrS+QLngCPlTMyU8Q9ISDtEfE/7rbIRyO49u56Y9SulTm/aOcQn/1Qg\
pc5NvHfRnHJ4Y7zclERWhtOLiDlVPIR7JjOMg3wVUEK18XPgoKdTxHBLJymLF2dQ\
SQhfhLruUcndV0R9vOdt3kMB0cSo7NzF4FcbAgMBAAECggEAM9pTxujYWgruRe1r\
h+GAbEAXp7VMqVAtQtPL80zigfNGyEOF6uq0w6HCiZOZCP701lSdETr0R65iC8M/\
QcWPEzICBMp/iVjmBObhAvBKiyUl4O8XQLE4UnCCvajT/fTlWzZ97phqYe/zkKq8\
j0QcgSocAVmm56usM9vui4dB5hT1TSpBj6UOXD4qSRmlHm+Ynp+5R19ktI0ay7fo\
P6QxZ/18QlS2VmVWu2tmfbbXU1EFjfQbdmIkEJI78rhEYXU/r3MDW3UnXCNDJTqq\
Q5/uD688BrRyTMZD1kZYCr7mlzx05keDQubSEXbVHG1bS4xAFzvmFB0A+lZn+Inl\
NqjggQKBgQCsCQtSTGmIqyPdF3siIK4HvfRbcn0WUJGMp/N8/Lu8CFHiT3hOkwN9\
6rBLLTl1qn8HjpHc226bHCPIbuHhZea3WlW2AIfbOJle/0m+BN8jEE8woZWOcgd/\
a7UV6mzxIxw8wq+4tWVoTYGadrePGZzOKkqD+W44uVn/vWCB2yhrOwKBgQCKTzCH\
qVMcrXLUqlQbJGOpfd+UzzsB0SOCZX83aifx+8vsNzXUgjyxIvz7oNZNyXHT7CnN\
9poldxgg2ajxQ9Nfr+e98eUD/nHjwbixGr+m1KRaiM0q+raLGpFQAcrgiVxFXVEH\
BVuoTW/uTCVfEdDQg0iCLb1nCJoIrU2bUMpFoQKBgEpZzk7PP30VmfZfw5PIU+58\
pjMvk+glAgKsQ4ttHyXw4pLQjcpHt2agG3kiHodAHI6Di37MR006KCzj3zOu+rub\
ixeRuyV/nKl148UADf/1eIQoEZ7yoVLsleLW4iaFahrIeXF21FDzzmOXk1WBWEex\
92p6TqytTrw8eI0mzp0pAoGAbZqJq8gcS+qLyEnecs/ohqVwa725VhxFFo2WPfTL\
CPFwTZYG+4vlyr4eWs2/Zk9P/A/3pPdaenwhS88RGXiVZgvBCv5JbVvTJxkaYob+\
/5cdU317kSazSBLauttgyYUw8OsdTgIJ+5q6K85+AxPcNZEEAd17bc4cOuoTSRTB\
5mECgYEAiZXJe66KpFZlzomsvoghwjTCdMb0CSzH8DvstGRC7X2QR1s9BhS8pvSS\
1cPwodOyPbUm6t16iYgZN1ibqxWG+TtiftzNzBjrPWGAIWVW+v0uvYBRgdOKbN/c\
nFi6gyV13lGIMMK61gCaEgcgBtJ9hbuIEH6B3a3n8TACIzewfx0=
""".decoded

let publicKeyDER = """
MIIBITANBgkqhkiG9w0BAQEFAAOCAQ4AMIIBCQKCAQBc8heBuESxpRARckQCuVNu\
iLsH5AX73F1lqNxpFsS+GPWl6rrTQ0j9Ox/ag2ZwyPby3FtJ11gWT/kDYkjTbqYB\
CzmzUeGjm3MbuCzErQLPjzGvdUDnvCxx8G+uE2uqTdryfEaregUyo69JmucLq3HQ\
91cHVeLMN/xMvaAu+xEUbZFiDBcVwOOWUft7HmrS+QLngCPlTMyU8Q9ISDtEfE/7\
rbIRyO49u56Y9SulTm/aOcQn/1Qgpc5NvHfRnHJ4Y7zclERWhtOLiDlVPIR7JjOM\
g3wVUEK18XPgoKdTxHBLJymLF2dQSQhfhLruUcndV0R9vOdt3kMB0cSo7NzF4Fcb\
AgMBAAE=
""".decoded

let plaintext = Data("The quick brown fox jumps over the lazy dog.".utf8)

func testPKCS8Init() throws {
#expect(throws: Never.self) { try _RSA.Signing.PrivateKey(derRepresentation: privateKeyDER) }
#expect(throws: Never.self) { try _RSA.Signing.PublicKey(derRepresentation: publicKeyDER) }
}

func testEncrypt_RSA2048_OAEP_SHA1() throws {
let publicKey = try _RSA.Encryption.PublicKey(derRepresentation: publicKeyDER)
let privateKey = try _RSA.Encryption.PrivateKey(derRepresentation: privateKeyDER)

let ciphertext = try publicKey.encrypt(plaintext, using: .rsaEncryptionOAEP)
let decrypted = try privateKey.decrypt(ciphertext, using: .rsaEncryptionOAEP)

#expect(plaintext == decrypted)
#expect(plaintext != ciphertext)
#expect(ciphertext.count == 2048 / 8)
}

func testEncrypt_RSA2048_OAEP_SHA256() throws {
let publicKey = try _RSA.Encryption.PublicKey(derRepresentation: publicKeyDER)
let privateKey = try _RSA.Encryption.PrivateKey(derRepresentation: privateKeyDER)

let ciphertext = try publicKey.encrypt(plaintext, using: .rsaEncryptionOAEPSHA256)
let decrypted = try privateKey.decrypt(ciphertext, using: .rsaEncryptionOAEPSHA256)

#expect(plaintext == decrypted)
#expect(plaintext != ciphertext)
#expect(ciphertext.count == 2048 / 8)
}

func testSigning_RSA2048_PKCS1_SHA256() throws {
let publicKey = try _RSA.Signing.PublicKey(derRepresentation: publicKeyDER)
let privateKey = try _RSA.Signing.PrivateKey(derRepresentation: privateKeyDER)

let signature = try privateKey.signature(plaintext, using: .rsaSignaturePKCS1v15SHA256)
#expect(throws: Never.self) { try publicKey.verifySignature(signature, for: plaintext, using: .rsaSignaturePKCS1v15SHA256) }

#expect(plaintext != signature)
#expect(signature.count == 2048 / 8)
}

func testSigning_RSA2048_PKCS1_SHA384() throws {
let publicKey = try _RSA.Signing.PublicKey(derRepresentation: publicKeyDER)
let privateKey = try _RSA.Signing.PrivateKey(derRepresentation: privateKeyDER)

let signature = try privateKey.signature(plaintext, using: .rsaSignaturePKCS1v15SHA384)
#expect(throws: Never.self) { try publicKey.verifySignature(signature, for: plaintext, using: .rsaSignaturePKCS1v15SHA384) }

#expect(plaintext != signature)
#expect(signature.count == 2048 / 8)
}

func testSigning_RSA2048_PKCS1_SHA512() throws {
let publicKey = try _RSA.Signing.PublicKey(derRepresentation: publicKeyDER)
let privateKey = try _RSA.Signing.PrivateKey(derRepresentation: privateKeyDER)

let signature = try privateKey.signature(plaintext, using: .rsaSignaturePKCS1v15SHA512)
#expect(throws: Never.self) { try publicKey.verifySignature(signature, for: plaintext, using: .rsaSignaturePKCS1v15SHA512) }

#expect(plaintext != signature)
#expect(signature.count == 2048 / 8)
}

func testSigning_RSA2048_PSS_SHA256() throws {
let publicKey = try _RSA.Signing.PublicKey(derRepresentation: publicKeyDER)
let privateKey = try _RSA.Signing.PrivateKey(derRepresentation: privateKeyDER)

let signature = try privateKey.signature(plaintext, using: .rsaSignaturePSSSHA256)
#expect(throws: Never.self) { try publicKey.verifySignature(signature, for: plaintext, using: .rsaSignaturePSSSHA256) }

#expect(plaintext != signature)
#expect(signature.count == 2048 / 8)
}

func testSigning_RSA2048_PSS_SHA384() throws {
let publicKey = try _RSA.Signing.PublicKey(derRepresentation: publicKeyDER)
let privateKey = try _RSA.Signing.PrivateKey(derRepresentation: privateKeyDER)

let signature = try privateKey.signature(plaintext, using: .rsaSignaturePSSSHA384)
#expect(throws: Never.self) { try publicKey.verifySignature(signature, for: plaintext, using: .rsaSignaturePSSSHA384) }

#expect(plaintext != signature)
#expect(signature.count == 2048 / 8)
}

func testSigning_RSA2048_PSS_SHA512() throws {
let publicKey = try _RSA.Signing.PublicKey(derRepresentation: publicKeyDER)
let privateKey = try _RSA.Signing.PrivateKey(derRepresentation: privateKeyDER)

let signature = try privateKey.signature(plaintext, using: .rsaSignaturePSSSHA512)
#expect(throws: Never.self) { try publicKey.verifySignature(signature, for: plaintext, using: .rsaSignaturePSSSHA512) }

#expect(plaintext != signature)
#expect(signature.count == 2048 / 8)
}

func testSigning_RSA3072_PSS_SHA256() throws {
let publicKey = try _RSA.Signing.PublicKey(derRepresentation: publicKeyDER)
let privateKey = try _RSA.Signing.PrivateKey(derRepresentation: privateKeyDER)

let signature = try privateKey.signature(plaintext, using: .rsaSignaturePSSSHA256)
#expect(throws: Never.self) { try publicKey.verifySignature(signature, for: plaintext, using: .rsaSignaturePSSSHA256) }

#expect(plaintext != signature)
#expect(signature.count == 3072 / 8)
}

func testSigning_RSA4096_PSS_SHA256() throws {
let publicKey = try _RSA.Signing.PublicKey(derRepresentation: publicKeyDER)
let privateKey = try _RSA.Signing.PrivateKey(derRepresentation: privateKeyDER)

let signature = try privateKey.signature(plaintext, using: .rsaSignaturePSSSHA256)
#expect(throws: Never.self) { try publicKey.verifySignature(signature, for: plaintext, using: .rsaSignaturePSSSHA256) }

#expect(plaintext != signature)
#expect(signature.count == 4096 / 8)
}
}
#endif

0 comments on commit 4cd3215

Please sign in to comment.