Skip to content

Commit 56c8687

Browse files
authored
CryptorModule (#144)
fix(crypto): Improved security of crypto implementation by adding AES-CBC cryptor feat(crypto): Add CryptorModule that allows configuring SDK to encrypt and decrypt messages PubNub SDK 6.2.0 release
1 parent cb04c77 commit 56c8687

38 files changed

+2139
-703
lines changed

.pubnub.yml

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,16 @@
11
---
22
name: swift
33
scm: github.com/pubnub/swift
4-
version: "6.1.0"
4+
version: "6.2.0"
55
schema: 1
66
changelog:
7+
- date: 2023-10-16
8+
version: v6.2.0
9+
changes:
10+
- type: feature
11+
text: "Add CryptorModule that allows configuring SDK to encrypt and decrypt messages."
12+
- type: bug
13+
text: "Improved security of crypto implementation by adding AES-CBC cryptor."
714
- date: 2023-08-30
815
version: 6.1.0
916
changes:
@@ -490,7 +497,7 @@ sdks:
490497
- distribution-type: source
491498
distribution-repository: GitHub release
492499
package-name: PubNub
493-
location: https://github.com/pubnub/swift/archive/refs/tags/6.1.0.zip
500+
location: https://github.com/pubnub/swift/archive/refs/tags/6.2.0.zip
494501
supported-platforms:
495502
supported-operating-systems:
496503
macOS:

Examples/Sources/ConfigDetailTableViewController.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ class ConfigDetailTableViewController: UITableViewController {
9090
case .subscribeKey:
9191
return config.subscribeKey
9292
case .cipherKey:
93-
return config.cipherKey?.key.description ?? "Key Not Found"
93+
return config.cryptorModule?.description ?? "CryptorModule Not Found"
9494
case .authKey:
9595
return config.authKey
9696
case .uuid:

LICENSE

Lines changed: 23 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,29 @@
1-
PubNub Real-time Cloud-Hosted Push API and Push Notification Client Frameworks
2-
Copyright (c) 2020 PubNub Inc.
3-
https://www.pubnub.com/
4-
https://www.pubnub.com/terms
1+
PubNub Software Development Kit License Agreement
2+
Copyright © 2023 PubNub Inc. All rights reserved.
3+
4+
Subject to the terms and conditions of the license, you are hereby granted
5+
a non-exclusive, worldwide, royalty-free license to (a) copy and modify
6+
the software in source code or binary form for use with the software services
7+
and interfaces provided by PubNub, and (b) redistribute unmodified copies
8+
of the software to third parties. The software may not be incorporated in
9+
or used to provide any product or service competitive with the products
10+
and services of PubNub.
511

6-
Permission is hereby granted, free of charge, to any person obtaining a copy
7-
of this software and associated documentation files (the "Software"), to deal
8-
in the Software without restriction, including without limitation the rights
9-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10-
copies of the Software, and to permit persons to whom the Software is
11-
furnished to do so, subject to the following conditions:
12+
The above copyright notice and this license shall be included
13+
in or with all copies or substantial portions of the software.
1214

13-
The above copyright notice and this permission notice shall be included in
14-
all copies or substantial portions of the Software.
15+
This license does not grant you permission to use the trade names, trademarks,
16+
service marks, or product names of PubNub, except as required for reasonable
17+
and customary use in describing the origin of the software and reproducing
18+
the content of this license.
1519

16-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22-
THE SOFTWARE.
20+
THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF
21+
ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO
23+
EVENT SHALL PUBNUB OR THE AUTHORS OR COPYRIGHT HOLDERS OF THE SOFTWARE BE
24+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
25+
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
26+
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
2327

24-
PubNub Real-time Cloud-Hosted Push API and Push Notification Client Frameworks
25-
Copyright (c) 2013 PubNub Inc.
2628
https://www.pubnub.com/
2729
https://www.pubnub.com/terms

Podfile.lock

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,4 +19,4 @@ SPEC CHECKSUMS:
1919

2020
PODFILE CHECKSUM: 61a40240486621bb01f596fdd5bc632504940fab
2121

22-
COCOAPODS: 1.11.3
22+
COCOAPODS: 1.12.1

PubNub.xcodeproj/project.pbxproj

Lines changed: 204 additions & 20 deletions
Large diffs are not rendered by default.

PubNubSwift.podspec

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
Pod::Spec.new do |s|
22
s.name = 'PubNubSwift'
3-
s.version = '6.1.0'
3+
s.version = '6.2.0'
44
s.homepage = 'https://github.com/pubnub/swift'
55
s.documentation_url = 'https://www.pubnub.com/docs/swift-native/pubnub-swift-sdk'
66
s.authors = { 'PubNub, Inc.' => '[email protected]' }

Sources/PubNub/APIs/File+PubNub.swift

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -160,9 +160,9 @@ public extension PubNub {
160160
switch result {
161161
case let .success(response):
162162
do {
163-
let autoCrypto = requestConfig.customConfiguration?.cipherKey ?? configuration.cipherKey
163+
let cryptorModule = requestConfig.customConfiguration?.cryptorModule ?? configuration.cryptorModule
164164
completion?(.success((
165-
try URLRequest(from: response.payload, uploading: content, crypto: autoCrypto),
165+
try URLRequest(from: response.payload, uploading: content, cryptorModule: cryptorModule),
166166
response.payload.fileId,
167167
response.payload.filename
168168
)))
@@ -450,7 +450,7 @@ public extension PubNub {
450450
/// - downloadTo: The async `Result` of the method call
451451
/// - Returns: The new file download task. The `urlSessionTask` property can be used to access the underlying `URLSessionDownloadTask`
452452
func createFileURLSessionDownloadTask(
453-
_ taskType: FileDownloadTaskType, session: URLSessionReplaceable, downloadTo url: URL, decrypt: Crypto? = nil
453+
_ taskType: FileDownloadTaskType, session: URLSessionReplaceable, downloadTo url: URL, decrypt: CryptorModule? = nil
454454
) -> HTTPFileDownloadTask {
455455
let downloadTask: URLSessionDownloadTask
456456
switch taskType {
@@ -464,7 +464,7 @@ public extension PubNub {
464464
task: downloadTask,
465465
session: session.configuration.identifier,
466466
downloadTo: url,
467-
crypto: decrypt ?? configuration.cipherKey
467+
cryptorModule: decrypt ?? configuration.cryptorModule
468468
)
469469

470470
// Create task map inside Delegate

Sources/PubNub/Errors/ErrorDescription.swift

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -294,6 +294,12 @@ extension PubNubError.Reason: CustomStringConvertible, LocalizedError {
294294
return "The Content-Length was incorrect for the content being uploaded"
295295
case .serviceNotEnabled:
296296
return "The PubNub Service that you're attempting to use has not be enabled for your keyset."
297+
case .encryptionFailure:
298+
return "Failure to perform encryption"
299+
case .decryptionFailure:
300+
return "Failure to perform decryption"
301+
case .unknownCryptorFailure:
302+
return "Unknown Cryptor error"
297303
}
298304
}
299305

Sources/PubNub/Errors/PubNubError.swift

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,9 @@ public struct PubNubError: Error {
105105

106106
// Crypto
107107
case missingCryptoKey
108+
case encryptionFailure
109+
case decryptionFailure
110+
case unknownCryptorFailure
108111

109112
// Request Processing
110113
case requestMutatorFailure
@@ -232,6 +235,8 @@ public struct PubNubError: Error {
232235
return .streamFailure
233236
case .fileTooLarge, .fileMissingAtPath, .fileAccessDenied, .fileContentLength:
234237
return .fileManagement
238+
case .encryptionFailure, .decryptionFailure, .unknownCryptorFailure:
239+
return .crypto
235240
}
236241
}
237242
}

Sources/PubNub/Extensions/URLRequest+PubNub.swift

Lines changed: 22 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ public extension URLRequest {
4646
internal init(
4747
from response: GenerateUploadURLResponse,
4848
uploading content: PubNub.FileUploadContent,
49-
crypto: Crypto? = nil
49+
cryptorModule: CryptorModule? = nil
5050
) throws {
5151
self.init(url: response.uploadRequestURL)
5252
method = response.uploadMethod
@@ -65,30 +65,32 @@ public extension URLRequest {
6565
postfixData.append("\r\n--\(response.fileId)--")
6666

6767
// Get Content InputStream
68-
guard var contentStream = content.inputStream else {
68+
guard let contentStream = content.inputStream else {
6969
throw PubNubError(.streamCouldNotBeInitialized, additional: [content.debugDescription])
7070
}
71-
72-
// If we were given a Crypto payload we should convert the stream to a secure stream
73-
if let crypto = crypto {
74-
let cryptoStream = CryptoInputStream(
75-
.encrypt, input: contentStream, contentLength: content.contentLength, with: crypto
76-
)
77-
setValue(
78-
"\(prefixData.count + cryptoStream.estimatedCryptoCount + postfixData.count)",
79-
forHTTPHeaderField: "Content-Length"
80-
)
81-
contentStream = cryptoStream
71+
72+
let finalStream: InputStream
73+
let contentLength: Int
74+
75+
// If we were given a Crypto module we should convert the stream to a secure stream
76+
if let cryptorModule = cryptorModule {
77+
switch cryptorModule.encrypt(stream: contentStream, contentLength: content.contentLength) {
78+
case .success(let encryptingResult):
79+
finalStream = encryptingResult
80+
contentLength = prefixData.count + ((encryptingResult as? MultipartInputStream)?.length ?? 0) + postfixData.count
81+
case .failure(let encryptionError):
82+
throw encryptionError
83+
}
8284
} else {
83-
setValue("\(prefixData.count + content.contentLength + postfixData.count)", forHTTPHeaderField: "Content-Length")
85+
finalStream = contentStream
86+
contentLength = prefixData.count + content.contentLength + postfixData.count
8487
}
8588

86-
let inputStream = MultipartInputStream(
87-
inputStreams: [InputStream(data: prefixData), contentStream, InputStream(data: postfixData)]
88-
)
89-
90-
httpBodyStream = inputStream
91-
89+
setValue("\(contentLength)", forHTTPHeaderField: "Content-Length")
9290
setValue("multipart/form-data; boundary=\(response.fileId)", forHTTPHeaderField: "Content-Type")
91+
92+
httpBodyStream = MultipartInputStream(
93+
inputStreams: [InputStream(data: prefixData), finalStream, InputStream(data: postfixData)]
94+
)
9395
}
9496
}

0 commit comments

Comments
 (0)