Fix missing IV & improve error handling

pull/148/head
gmbnt 6 years ago
parent 41701ecde3
commit b323637f7a

@ -20,14 +20,14 @@ extension OnionRequestAPI {
/// - Note: Sync. Don't call from the main thread. /// - Note: Sync. Don't call from the main thread.
private static func encrypt(_ plaintext: Data, usingAESGCMWithSymmetricKey symmetricKey: Data) throws -> Data { private static func encrypt(_ plaintext: Data, usingAESGCMWithSymmetricKey symmetricKey: Data) throws -> Data {
guard !Thread.isMainThread else { preconditionFailure("It's illegal to call encryptUsingAESGCM(symmetricKey:plainText:) from the main thread.") } guard !Thread.isMainThread else { preconditionFailure("It's illegal to call encrypt(_:usingAESGCMWithSymmetricKey:) from the main thread.") }
let ivSize: UInt = 12 let ivSize: UInt = 12
let iv = try getRandomData(ofSize: ivSize) let iv = try getRandomData(ofSize: ivSize)
let gcmTagLength: UInt = 128 let gcmTagLength: UInt = 128
let gcm = GCM(iv: iv.bytes, tagLength: Int(gcmTagLength), mode: .combined) let gcm = GCM(iv: iv.bytes, tagLength: Int(gcmTagLength), mode: .combined)
let aes = try AES(key: symmetricKey.bytes, blockMode: gcm, padding: .noPadding) let aes = try AES(key: symmetricKey.bytes, blockMode: gcm, padding: .noPadding)
let ciphertext = try aes.encrypt(plaintext.bytes) let ciphertext = try aes.encrypt(plaintext.bytes)
return Data(bytes: ciphertext) return iv + Data(bytes: ciphertext)
} }
/// - Note: Sync. Don't call from the main thread. /// - Note: Sync. Don't call from the main thread.

@ -18,7 +18,7 @@ internal enum OnionRequestAPI {
private static let pathSize: UInt = 3 private static let pathSize: UInt = 3
private static let timeout: TimeInterval = 20 private static let timeout: TimeInterval = 20
private static var guardSnodeCount: UInt { return pathCount } private static var guardSnodeCount: UInt { return pathCount } // One per path
// MARK: HTTP Verb // MARK: HTTP Verb
private enum HTTPVerb : String { private enum HTTPVerb : String {
@ -94,8 +94,14 @@ internal enum OnionRequestAPI {
} }
let statusCode = UInt(response.statusCode) let statusCode = UInt(response.statusCode)
guard 200...299 ~= statusCode else { guard 200...299 ~= statusCode else {
print("[Loki] [Onion Request API] \(verb.rawValue) request to \(url) failed with status code: \(statusCode).") var json: JSON? = nil
let json = try? JSONSerialization.jsonObject(with: data, options: []) as? JSON if let j = try? JSONSerialization.jsonObject(with: data, options: []) as? JSON {
json = j
} else if let message = String(data: data, encoding: .utf8) {
json = [ "message" : message ]
}
let jsonDescription = json?.prettifiedDescription ?? "no debugging info provided"
print("[Loki] [Onion Request API] \(verb.rawValue) request to \(url) failed with status code: \(statusCode) (\(jsonDescription).")
return seal.reject(Error.httpRequestFailed(statusCode: statusCode, json: json)) return seal.reject(Error.httpRequestFailed(statusCode: statusCode, json: json))
} }
do { do {
@ -121,7 +127,7 @@ internal enum OnionRequestAPI {
execute(.get, url, timeout: timeout).done(on: queue) { rawResponse in execute(.get, url, timeout: timeout).done(on: queue) { rawResponse in
guard let json = rawResponse as? JSON, let version = json["version"] as? String else { return seal.reject(Error.missingSnodeVersion) } guard let json = rawResponse as? JSON, let version = json["version"] as? String else { return seal.reject(Error.missingSnodeVersion) }
// TODO: Caching // TODO: Caching
if version >= "2.0.3" { if version >= "2.0.0" {
seal.fulfill(()) seal.fulfill(())
} else { } else {
print("[Loki] [Onion Request API] Unsupported snode version: \(version).") print("[Loki] [Onion Request API] Unsupported snode version: \(version).")
@ -210,11 +216,12 @@ internal enum OnionRequestAPI {
/// Builds an onion around `payload` and returns the result. /// Builds an onion around `payload` and returns the result.
private static func buildOnion(around payload: Data, targetedAt snode: LokiAPITarget) -> Promise<OnionBuildingResult> { private static func buildOnion(around payload: Data, targetedAt snode: LokiAPITarget) -> Promise<OnionBuildingResult> {
var guardSnode: LokiAPITarget! var guardSnode: LokiAPITarget!
var encryptionResult: EncryptionResult!
return getPath().then(on: workQueue) { path -> Promise<EncryptionResult> in return getPath().then(on: workQueue) { path -> Promise<EncryptionResult> in
guardSnode = path.first! guardSnode = path.first!
return encrypt(payload, forTargetSnode: snode).then(on: workQueue) { r -> Promise<EncryptionResult> in return encrypt(payload, forTargetSnode: snode).then(on: workQueue) { r -> Promise<EncryptionResult> in
encryptionResult = r
var path = path var path = path
var encryptionResult = r
var rhs = snode var rhs = snode
func addLayer() -> Promise<EncryptionResult> { func addLayer() -> Promise<EncryptionResult> {
if path.isEmpty { if path.isEmpty {
@ -230,7 +237,7 @@ internal enum OnionRequestAPI {
} }
return addLayer() return addLayer()
} }
}.map(on: workQueue) { (guardSnode: guardSnode, encryptionResult: $0) } }.map(on: workQueue) { _ in (guardSnode: guardSnode, encryptionResult: encryptionResult) }
} }
// MARK: Internal API // MARK: Internal API

Loading…
Cancel
Save