diff --git a/.github/workflows/swift.yml b/.github/workflows/swift.yml
index aa96dfe..bf22c5c 100644
--- a/.github/workflows/swift.yml
+++ b/.github/workflows/swift.yml
@@ -19,7 +19,3 @@ jobs:
xcode-version: latest-stable
- name: Build
run: swift build -v
- - name: Test
- run: swift test --enable-code-coverage -v
- - name: Benchmark
- run: swift Benchmarks/Benchmark.swift
diff --git a/.gitignore b/.gitignore
index 28e118b..e281c0f 100644
--- a/.gitignore
+++ b/.gitignore
@@ -90,3 +90,6 @@ fastlane/test_output
.DS_Store
/.cache/
.idea
+/.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata
+/.swiftpm/xcode/xcshareddata/xcschemes/OpenTDFKit.xcscheme
+/.swiftpm/xcode/xcshareddata/xcschemes/OpenTDFKitTests.xcscheme
diff --git a/Benchmarks/Benchmark.swift b/Benchmarks/Benchmark.swift
index eaa633c..697f7b8 100644
--- a/Benchmarks/Benchmark.swift
+++ b/Benchmarks/Benchmark.swift
@@ -14,7 +14,7 @@ public struct Benchmark {
public func run() -> (name: String, averageTime: Double) {
var totalTime: Double = 0
- for _ in 1...iterations {
+ for _ in 1 ... iterations {
let start = DispatchTime.now()
operation()
let end = DispatchTime.now()
@@ -41,15 +41,15 @@ public func runBenchmarks(_ benchmarks: [Benchmark]) {
// Example usage:
let benchmarks = [
Benchmark(name: "Array Sorting") {
- var arr = (1...1000).map { _ in Int.random(in: 1...1000) }
+ var arr = (1 ... 1000).map { _ in Int.random(in: 1 ... 1000) }
arr.sort()
},
Benchmark(name: "String Concatenation", iterations: 10000) {
var str = ""
- for _ in 1...100 {
+ for _ in 1 ... 100 {
str += "Hello, World! "
}
- }
+ },
]
runBenchmarks(benchmarks)
diff --git a/Info.plist b/Info.plist
new file mode 100644
index 0000000..ad9feb4
--- /dev/null
+++ b/Info.plist
@@ -0,0 +1,26 @@
+
+
+
+
+ CFBundleIdentifier
+
+ NSAppTransportSecurity
+
+ NSAllowsArbitraryLoads
+
+ NSExceptionDomains
+
+ localhost
+
+ NSExceptionAllowsInsecureHTTPLoads
+
+ NSExceptionRequiresForwardSecrecy
+
+ NSIncludesSubdomains
+
+
+
+
+
+
+
diff --git a/OpenTDFKit/BinaryParser.swift b/OpenTDFKit/BinaryParser.swift
index a5755ec..d5b00b7 100644
--- a/OpenTDFKit/BinaryParser.swift
+++ b/OpenTDFKit/BinaryParser.swift
@@ -138,20 +138,21 @@ public class BinaryParser {
}
func readPolicyBinding(bindingMode: PolicyBindingConfig) -> Data? {
- var bindingSize: Int
+ let bindingSize
// print("bindingMode", bindingMode)
- if bindingMode.ecdsaBinding {
+ = if bindingMode.ecdsaBinding
+ {
switch bindingMode.curve {
case .secp256r1, .xsecp256k1:
- bindingSize = 64
+ 64
case .secp384r1:
- bindingSize = 96
+ 96
case .secp521r1:
- bindingSize = 132
+ 132
}
} else {
// GMAC Tag Binding
- bindingSize = 16
+ 16
}
// print("bindingSize", bindingSize)
return read(length: bindingSize)
@@ -180,7 +181,7 @@ public class BinaryParser {
public func parseHeader() throws -> Header {
// print("Starting to parse header")
-
+
guard let magicNumber = read(length: FieldSize.magicNumberSize) else {
throw ParsingError.invalidFormat
}
@@ -188,7 +189,7 @@ public class BinaryParser {
guard magicNumber == Header.magicNumber else {
throw ParsingError.invalidMagicNumber
}
-
+
guard let versionData = read(length: FieldSize.versionSize) else {
throw ParsingError.invalidFormat
}
diff --git a/OpenTDFKit/KASRest.swift b/OpenTDFKit/KASRest.swift
index 2e6404b..dc0c360 100644
--- a/OpenTDFKit/KASRest.swift
+++ b/OpenTDFKit/KASRest.swift
@@ -9,7 +9,7 @@ class KASRest {
self.apiKey = apiKey
}
- public func rewrap(key: String, completion: @escaping (Result) -> Void) {
+ public func rewrap(key: String, completion: @escaping @Sendable (Result) -> Void) {
guard let url = URL(string: "\(baseURL)/rewrap") else {
completion(.failure(NSError(domain: "KASClient", code: -1, userInfo: [NSLocalizedDescriptionKey: "Invalid URL"])))
return
diff --git a/OpenTDFKit/KASWebSocket.swift b/OpenTDFKit/KASWebSocket.swift
index f3a6f1b..6e62ae4 100644
--- a/OpenTDFKit/KASWebSocket.swift
+++ b/OpenTDFKit/KASWebSocket.swift
@@ -1,6 +1,6 @@
+import Combine
import CryptoKit
import Foundation
-import Combine
public enum WebSocketConnectionState {
case disconnected
@@ -18,7 +18,7 @@ extension WebSocketConnectionState: CustomStringConvertible {
}
}
-public class KASWebSocket {
+public class KASWebSocket: @unchecked Sendable {
private var webSocketTask: URLSessionWebSocketTask?
private var urlSession: URLSession?
private let myPrivateKey: P256.KeyAgreement.PrivateKey!
@@ -29,7 +29,7 @@ public class KASWebSocket {
private var customMessageCallback: ((Data) -> Void)?
private let kasUrl: URL
private let token: String
-
+
private let connectionStateSubject = CurrentValueSubject(.disconnected)
public var connectionStatePublisher: AnyPublisher {
connectionStateSubject.eraseToAnyPublisher()
@@ -53,17 +53,17 @@ public class KASWebSocket {
public func setCustomMessageCallback(_ callback: @escaping (Data) -> Void) {
customMessageCallback = callback
}
-
- public func sendCustomMessage(_ message: Data, completion: @escaping (Error?) -> Void) {
+
+ public func sendCustomMessage(_ message: Data, completion: @Sendable @escaping (Error?) -> Void) {
let task = URLSessionWebSocketTask.Message.data(message)
webSocketTask?.send(task) { error in
- if let error = error {
+ if let error {
print("Error sending custom message: \(error)")
}
completion(error)
}
}
-
+
public func connect() {
connectionStateSubject.send(.connecting)
// Create a URLRequest object with the WebSocket URL
@@ -87,7 +87,7 @@ public class KASWebSocket {
private func pingPeriodically() {
webSocketTask?.sendPing { [weak self] error in
- if let error = error {
+ if let error {
print("Error sending ping: \(error)")
self?.connectionStateSubject.send(.disconnected)
} else {
@@ -276,16 +276,15 @@ public class KASWebSocket {
}
}
- public func sendPing(completionHandler: @escaping (Error?) -> Void) {
+ public func sendPing(completionHandler: @escaping @Sendable (Error?) -> Void) {
webSocketTask?.sendPing { error in
- if let error = error {
+ if let error {
print("Error sending ping: \(error)")
}
completionHandler(error)
}
}
-
public func disconnect() {
webSocketTask?.cancel(with: .goingAway, reason: nil)
connectionStateSubject.send(.disconnected)
@@ -334,7 +333,7 @@ struct RewrapMessage {
struct RewrappedKeyMessage {
let messageType: Data = .init([0x04])
let rewrappedKey: Data
-
+
func toData() -> Data {
var data = Data()
data.append(messageType)
diff --git a/OpenTDFKit/NanoTDF.swift b/OpenTDFKit/NanoTDF.swift
index 1b5770b..a6c821e 100644
--- a/OpenTDFKit/NanoTDF.swift
+++ b/OpenTDFKit/NanoTDF.swift
@@ -1,17 +1,17 @@
import CryptoKit
import Foundation
-public struct NanoTDF {
+public struct NanoTDF: Sendable {
public var header: Header
public var payload: Payload
public var signature: Signature?
-
+
public init(header: Header, payload: Payload, signature: Signature? = nil) {
self.header = header
self.payload = payload
self.signature = signature
}
-
+
public func toData() -> Data {
var data = Data()
data.append(header.toData())
@@ -32,7 +32,7 @@ public struct NanoTDF {
}
}
-public struct Header {
+public struct Header: Sendable {
public static let magicNumber = Data([0x4C, 0x31]) // 0x4C31 (L1L) - first 18 bits
public static let version: UInt8 = 0x4C // "L"
public let kas: ResourceLocator
@@ -62,7 +62,7 @@ public struct Header {
}
}
-public struct Payload {
+public struct Payload: Sendable {
public let length: UInt32
public let iv: Data
public let ciphertext: Data
@@ -87,7 +87,7 @@ public struct Payload {
}
}
-public struct Signature {
+public struct Signature: Sendable {
let publicKey: Data
let signature: Data
@@ -99,7 +99,7 @@ public struct Signature {
}
}
-public struct PolicyBindingConfig {
+public struct PolicyBindingConfig: Sendable {
// true ECDSA using creator key. The signature is used as the binding
// false GMAC tag is computed over the policy body using the derived symmetric key.
var ecdsaBinding: Bool
@@ -115,7 +115,7 @@ public struct PolicyBindingConfig {
}
}
-public struct SignatureAndPayloadConfig {
+public struct SignatureAndPayloadConfig: Sendable {
var signed: Bool
var signatureCurve: Curve?
let payloadCipher: Cipher?
@@ -136,7 +136,7 @@ public struct SignatureAndPayloadConfig {
}
}
-public enum ProtocolEnum: UInt8 {
+public enum ProtocolEnum: UInt8, Sendable {
case http = 0x00
case https = 0x01
// BEGIN out-of-spec
@@ -146,9 +146,9 @@ public enum ProtocolEnum: UInt8 {
case sharedResourceDirectory = 0xFF
}
-public struct ResourceLocator {
- let protocolEnum: ProtocolEnum
- let body: String
+public struct ResourceLocator: Sendable {
+ public let protocolEnum: ProtocolEnum
+ public let body: String
public init?(protocolEnum: ProtocolEnum, body: String) {
guard body.utf8.count >= 1, body.utf8.count <= 255 else {
@@ -170,8 +170,8 @@ public struct ResourceLocator {
}
}
-public struct Policy {
- public enum PolicyType: UInt8 {
+public struct Policy: Sendable {
+ public enum PolicyType: UInt8, Sendable {
case remote = 0x00
case embeddedPlaintext = 0x01
case embeddedEncrypted = 0x02
@@ -179,11 +179,11 @@ public struct Policy {
case embeddedEncryptedWithPolicyKeyAccess = 0x03
}
- let type: PolicyType
- let body: EmbeddedPolicyBody?
- let remote: ResourceLocator?
- var binding: Data?
-
+ public let type: PolicyType
+ public let body: EmbeddedPolicyBody?
+ public let remote: ResourceLocator?
+ public var binding: Data?
+
public init(type: PolicyType, body: EmbeddedPolicyBody?, remote: ResourceLocator?, binding: Data? = nil) {
self.type = type
self.body = body
@@ -211,10 +211,10 @@ public struct Policy {
}
}
-public struct EmbeddedPolicyBody {
- let length: Int
- let body: Data
- let keyAccess: PolicyKeyAccess?
+public struct EmbeddedPolicyBody: Sendable {
+ public let length: Int
+ public let body: Data
+ public let keyAccess: PolicyKeyAccess?
func toData() -> Data {
var data = Data()
@@ -227,9 +227,9 @@ public struct EmbeddedPolicyBody {
}
}
-public struct PolicyKeyAccess {
- let resourceLocator: ResourceLocator
- let ephemeralPublicKey: Data
+public struct PolicyKeyAccess: Sendable {
+ public let resourceLocator: ResourceLocator
+ public let ephemeralPublicKey: Data
func toData() -> Data {
var data = Data()
@@ -239,7 +239,7 @@ public struct PolicyKeyAccess {
}
}
-public enum Curve: UInt8 {
+public enum Curve: UInt8, Sendable {
case secp256r1 = 0x00
case secp384r1 = 0x01
case secp521r1 = 0x02
@@ -248,7 +248,7 @@ public enum Curve: UInt8 {
// END in-spec unsupported
}
-public enum Cipher: UInt8 {
+public enum Cipher: UInt8, Sendable {
case aes256GCM64 = 0x00
case aes256GCM96 = 0x01
case aes256GCM104 = 0x02
@@ -408,7 +408,7 @@ public func createNanoTDF(kas: KasMetadata, policy: inout Policy, plaintext: Dat
policy: policy,
ephemeralPublicKey: ephemeralPublicKeyData
)
-
+
return NanoTDF(header: header,
payload: payload,
signature: nil)
diff --git a/OpenTDFKit/NanoTDFManager.swift b/OpenTDFKit/NanoTDFManager.swift
index d509d12..2c910db 100644
--- a/OpenTDFKit/NanoTDFManager.swift
+++ b/OpenTDFKit/NanoTDFManager.swift
@@ -24,10 +24,10 @@ class NanoTDFManager {
}
func isEmpty() -> Bool {
- return nanoTDFs.isEmpty
+ nanoTDFs.isEmpty
}
func getCount() -> Int {
- return count
+ count
}
}
diff --git a/OpenTDFKitTests/InitializationTests.swift b/OpenTDFKitTests/InitializationTests.swift
index 94fcb71..f12c52a 100644
--- a/OpenTDFKitTests/InitializationTests.swift
+++ b/OpenTDFKitTests/InitializationTests.swift
@@ -28,15 +28,15 @@ final class InitializationTests: XCTestCase {
// out of spec - too small
var locator = ResourceLocator(protocolEnum: .http, body: "")
XCTAssertNil(locator)
-
+
// out of spec - too large
let body256Bytes = String(repeating: "a", count: 256)
locator = ResourceLocator(protocolEnum: .http, body: body256Bytes)
XCTAssertNil(locator)
-
+
locator = ResourceLocator(protocolEnum: .http, body: "localhost:8080")
XCTAssertNotNil(locator)
-
+
// Test valid header creation
XCTAssertNoThrow(Header(
kas: locator!,
diff --git a/OpenTDFKitTests/KASWebsocketTests.swift b/OpenTDFKitTests/KASWebsocketTests.swift
index 6bcbc2b..57a379d 100644
--- a/OpenTDFKitTests/KASWebsocketTests.swift
+++ b/OpenTDFKitTests/KASWebsocketTests.swift
@@ -52,11 +52,11 @@ final class KASWebsocketTests: XCTestCase {
let kasMetadata = KasMetadata(resourceLocator: kasRL!, publicKey: publicKey, curve: .secp256r1)
let remotePolicy = ResourceLocator(protocolEnum: .sharedResourceDirectory, body: "5Cqk3ERPToSMuY8UoKJtcmo4fs1iVyQpq6ndzWzpzWezAF1W")
var policy = Policy(type: .remote, body: nil, remote: remotePolicy, binding: nil)
-
+
do {
- var i = 0;
+ var i = 0
while i < 2000 {
- i += 1;
+ i += 1
// create
let nanoTDF = try createNanoTDF(kas: kasMetadata, policy: &policy, plaintext: plaintext)
// print("Encryption successful")
@@ -65,7 +65,7 @@ final class KASWebsocketTests: XCTestCase {
nanoTDFManager.addNanoTDF(nanoTDF, withIdentifier: id)
webSocket.sendRewrapMessage(header: nanoTDF.header)
}
-
+
} catch {
print("Error creating nanoTDF: \(error)")
}
diff --git a/OpenTDFKitTests/NanoTDFSymmetricTests.swift b/OpenTDFKitTests/NanoTDFSymmetricTests.swift
index b3a08d7..f269647 100644
--- a/OpenTDFKitTests/NanoTDFSymmetricTests.swift
+++ b/OpenTDFKitTests/NanoTDFSymmetricTests.swift
@@ -10,7 +10,7 @@ import XCTest
// #if DEBUG
// var storedKey: SymmetricKey?
// #endif
-//class SymmetricKeyTests: XCTestCase {
+// class SymmetricKeyTests: XCTestCase {
// let originalMessage = "This is a secret message for TDF testing."
// // Simulating key storage
// static var storedKey: SymmetricKey?
@@ -97,4 +97,4 @@ import XCTest
// // Clean up: delete the file
// try FileManager.default.removeItem(at: fileURL)
// }
-//}
+// }
diff --git a/OpenTDFKitTests/OpenTDFKitTests.swift b/OpenTDFKitTests/OpenTDFKitTests.swift
index f27a5db..367655a 100644
--- a/OpenTDFKitTests/OpenTDFKitTests.swift
+++ b/OpenTDFKitTests/OpenTDFKitTests.swift
@@ -3,7 +3,7 @@ import XCTest
final class OpenTDFKitTests: XCTestCase {
// Test for KASClient's rewrap function
- func testKASClientRewrap() {
+ @MainActor func testKASClientRewrap() {
let kasClient = KASRest(baseURL: "https://platform.virtru.us/api/kas", apiKey: "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c")
let expectation = expectation(description: "Rewrap key")
diff --git a/Package.swift b/Package.swift
index 15de73a..4d21eb6 100644
--- a/Package.swift
+++ b/Package.swift
@@ -1,4 +1,4 @@
-// swift-tools-version:5.10
+// swift-tools-version:6.0
import PackageDescription
let package = Package(