From c20aec633ee3320d32ef0775f8cfb9b01fdaff5a Mon Sep 17 00:00:00 2001 From: metalurgical <97008724+metalurgical@users.noreply.github.com> Date: Tue, 21 May 2024 06:01:15 +0200 Subject: [PATCH] fix: encryption bug --- Sources/TorusUtils/Constants.swift | 2 +- Sources/TorusUtils/Helpers/KeyUtils.swift | 4 +- .../TorusUtils/Helpers/MetadataUtils.swift | 15 +- Sources/TorusUtils/Helpers/NodeUtils.swift | 231 +++++++++--------- Sources/TorusUtils/TorusUtils.swift | 1 - .../SapphireMainnetTests.swift | 17 -- 6 files changed, 122 insertions(+), 148 deletions(-) diff --git a/Sources/TorusUtils/Constants.swift b/Sources/TorusUtils/Constants.swift index 09c51953..f0956a63 100644 --- a/Sources/TorusUtils/Constants.swift +++ b/Sources/TorusUtils/Constants.swift @@ -1,7 +1,7 @@ enum JRPC_METHODS { static let GET_OR_SET_KEY = "GetPubKeyOrKeyAssign" static let COMMITMENT_REQUEST = "CommitmentRequest" - static let IMPORT_SHARE = "ImportShares" + static let IMPORT_SHARES = "ImportShares" static let GET_SHARE_OR_KEY_ASSIGN = "GetShareOrKeyAssign" static let VERIFIER_LOOKUP_REQUEST = "VerifierLookupRequest" static let KEY_ASSIGN = "KeyAssign" diff --git a/Sources/TorusUtils/Helpers/KeyUtils.swift b/Sources/TorusUtils/Helpers/KeyUtils.swift index 89b5aa8a..a2eaf859 100644 --- a/Sources/TorusUtils/Helpers/KeyUtils.swift +++ b/Sources/TorusUtils/Helpers/KeyUtils.swift @@ -160,9 +160,9 @@ public class KeyUtils { let nonceParams = try KeyUtils.generateNonceMetadataParams(operation: "getOrSetNonce", privateKey: BigInt(keyData.signingKey, radix: 16)!, nonce: BigInt(keyData.nonce, radix: 16), serverTimeOffset: serverTimeOffset) var encShares: [Ecies] = [] - for i in 0 ..< nodePubKeys.count { - let shareInfo: Share = shares[nodeIndexes[i].magnitude.serialize().hexString.addLeading0sForLength64()]! + let shareInfo: Share = shares[nodeIndexes[i].magnitude.serialize().hexString.addLeading0sForLength64()]! + let nodePub = KeyUtils.getPublicKeyFromCoords(pubKeyX: nodePubKeys[i].X, pubKeyY: nodePubKeys[i].Y) let nodePubKey = try PublicKey(hex: nodePub).serialize(compressed: true) let encrypted = try MetadataUtils.encrypt(publicKey: nodePubKey, msg: shareInfo.share.magnitude.serialize().hexString.addLeading0sForLength64()) diff --git a/Sources/TorusUtils/Helpers/MetadataUtils.swift b/Sources/TorusUtils/Helpers/MetadataUtils.swift index f0963f4a..b6ce8859 100644 --- a/Sources/TorusUtils/Helpers/MetadataUtils.swift +++ b/Sources/TorusUtils/Helpers/MetadataUtils.swift @@ -33,19 +33,8 @@ internal class MetadataUtils { return result } - public static func encryptData(privkeyHex: String, _ dataToEncrypt: String) throws -> String { - let privKey = try SecretKey(hex: privkeyHex) - let pubKey = try privKey.toPublic().serialize(compressed: false) - let encParams = try encrypt(publicKey: pubKey, msg: dataToEncrypt, opts: nil) - let data = try JSONEncoder().encode(encParams) - guard let string = String(data: data, encoding: .utf8) else { throw TorusUtilError.runtime("Invalid String from enc Params") } - return string - } - - public static func encrypt(publicKey: String, msg: String, opts: Ecies? = nil) throws -> Ecies { - guard let data = msg.data(using: .utf8) else { - throw TorusUtilError.runtime("Encryption: Invalid utf8 string") - } + public static func encrypt(publicKey: String, msg: String) throws -> Ecies { + let data = Data(hex: msg) let curveMsg = try Encryption.encrypt(pk: PublicKey(hex: publicKey), plainText: data) return try .init(iv: curveMsg.iv(), ephemPublicKey: curveMsg.ephemeralPublicKey().serialize(compressed: false), ciphertext: curveMsg.chipherText(), mac: curveMsg.mac()) } diff --git a/Sources/TorusUtils/Helpers/NodeUtils.swift b/Sources/TorusUtils/Helpers/NodeUtils.swift index bc0e7199..5ec369d8 100644 --- a/Sources/TorusUtils/Helpers/NodeUtils.swift +++ b/Sources/TorusUtils/Helpers/NodeUtils.swift @@ -228,126 +228,131 @@ internal class NodeUtils { var shareImportSuccess = false - if isImportShareReq { - var importedItems: [ShareRequestParams.ShareRequestItem] = [] - for j in 0 ..< endpoints.count { - let importShare = importedShares![j] - - let shareRequestItem = ShareRequestParams.ShareRequestItem( - verifieridentifier: verifier, - verifier_id: verifierParams.verifier_id, - extended_verifier_id: verifierParams.extended_verifier_id, - idtoken: idToken, - nodesignatures: nodeSigs, - pub_key_x: importShare.oauth_pub_key_x, - pub_key_y: importShare.oauth_pub_key_y, - signing_pub_key_x: importShare.signing_pub_key_x, - signing_pub_key_y: importShare.signing_pub_key_y, - encrypted_share: importShare.encryptedShare, - encrypted_share_metadata: importShare.encryptedShareMetadata, - node_index: importShare.node_index, - key_type: importShare.key_type, - nonce_data: importShare.nonce_data, - nonce_signature: importShare.nonce_signature, - // extra_params: extraData - sub_verifier_ids: verifierParams.sub_verifier_ids, - session_token_exp_second: sessionExpiry, - verify_params: verifierParams.verify_params, - sss_endpoint: endpoints[j] - ) - - importedItems.append(shareRequestItem) - } - - let params = ShareRequestParams(encrypted: "yes", item: importedItems, client_time: String(Int(trunc(Double((serverTimeOffset ?? 0) + Int(Date().timeIntervalSince1970)))))) - - let jsonRPCRequest = JRPCRequest( - method: JRPC_METHODS.IMPORT_SHARE, - params: params - ) - - let encoder = JSONEncoder() - encoder.outputFormatting = .sortedKeys - let rpcdata = try encoder.encode(jsonRPCRequest) - var request = try MetadataUtils.makeUrlRequest(url: endpoints[Int(try getProxyCoordinatorEndpointIndex(endpoints: endpoints, verifier: verifier, verifierId: verifierParams.verifier_id))]) - request.httpBody = rpcdata - debugPrint(String(data: rpcdata, encoding: .utf8)!) - let val = try await URLSession(configuration: .default).data(for: request) - let decoded = try JSONDecoder().decode(JRPCResponse<[ShareRequestResult]>.self, from: val.0) - if decoded.error == nil { - shareImportSuccess = true - } - } + var shareRequestResults: [ShareRequestResult?] = [] - if isImportShareReq && !shareImportSuccess { - throw TorusUtilError.importShareFailed - } - - let shareRequestResults: [JRPCResponse?] = try await withThrowingTaskGroup(of: JRPCResponse?.self, returning: [JRPCResponse?].self) { - group -> [JRPCResponse?] in - var received = 0 - - for i in 0 ..< endpoints.count { - if !nodeSigs.indices.contains(i) { - if isImportShareReq { - throw TorusUtilError.importShareFailed + if isImportShareReq { + var importedItems: [ShareRequestParams.ShareRequestItem] = [] + for j in 0 ..< endpoints.count { + let importShare = importedShares![j] + + let shareRequestItem = ShareRequestParams.ShareRequestItem( + verifieridentifier: verifier, + verifier_id: verifierParams.verifier_id, + extended_verifier_id: verifierParams.extended_verifier_id, + idtoken: idToken, + nodesignatures: nodeSigs, + pub_key_x: importShare.oauth_pub_key_x, + pub_key_y: importShare.oauth_pub_key_y, + signing_pub_key_x: importShare.signing_pub_key_x, + signing_pub_key_y: importShare.signing_pub_key_y, + encrypted_share: importShare.encryptedShare, + encrypted_share_metadata: importShare.encryptedShareMetadata, + node_index: importShare.node_index, + key_type: importShare.key_type, + nonce_data: importShare.nonce_data, + nonce_signature: importShare.nonce_signature, + // extra_params: extraData + sub_verifier_ids: verifierParams.sub_verifier_ids, + session_token_exp_second: sessionExpiry, + verify_params: verifierParams.verify_params, + sss_endpoint: endpoints[j] + ) + + importedItems.append(shareRequestItem) + } + + let params = ShareRequestParams(encrypted: "yes", item: importedItems, client_time: String(Int(trunc(Double((serverTimeOffset ?? 0) + Int(Date().timeIntervalSince1970)))))) + + let jsonRPCRequest = JRPCRequest( + method: JRPC_METHODS.IMPORT_SHARES, + params: params + ) + + let encoder = JSONEncoder() + encoder.outputFormatting = .sortedKeys + let rpcdata = try encoder.encode(jsonRPCRequest) + var request = try MetadataUtils.makeUrlRequest(url: endpoints[Int(try getProxyCoordinatorEndpointIndex(endpoints: endpoints, verifier: verifier, verifierId: verifierParams.verifier_id))]) + request.httpBody = rpcdata + let val = try await URLSession(configuration: .default).data(for: request) + let decoded = try JSONDecoder().decode(JRPCResponse<[ShareRequestResult]>.self, from: val.0) + if decoded.error == nil { + shareImportSuccess = true + } + + if isImportShareReq && !shareImportSuccess { + throw TorusUtilError.importShareFailed + } + + shareRequestResults = decoded.result! + + } else { + let shareResults: [JRPCResponse?] = try await withThrowingTaskGroup(of: JRPCResponse?.self, returning: [JRPCResponse?].self) { + group -> [JRPCResponse?] in + var received = 0 + + for i in 0 ..< endpoints.count { + if !nodeSigs.indices.contains(i) { + if isImportShareReq { + throw TorusUtilError.importShareFailed + } + continue } - continue - } - - group.addTask { - do { - let shareRequestItem = ShareRequestParams.ShareRequestItem( - verifieridentifier: verifier, - verifier_id: verifierParams.verifier_id, - extended_verifier_id: verifierParams.extended_verifier_id, - idtoken: idToken, - nodesignatures: nodeSigs, - // extra_params: extraData - sub_verifier_ids: verifierParams.sub_verifier_ids, - session_token_exp_second: sessionExpiry, - verify_params: verifierParams.verify_params - ) - - let params = ShareRequestParams(encrypted: "yes", item: [shareRequestItem], client_time: String(Int(trunc(Double((serverTimeOffset ?? 0) + Int(Date().timeIntervalSince1970)))))) - - let jsonRPCRequest = JRPCRequest( - method: JRPC_METHODS.GET_SHARE_OR_KEY_ASSIGN, - params: params - ) - - let encoder = JSONEncoder() - encoder.outputFormatting = .sortedKeys - let rpcdata = try encoder.encode(jsonRPCRequest) - var request = try MetadataUtils.makeUrlRequest(url: endpoints[i]) - request.httpBody = rpcdata - let val = try await URLSession(configuration: .default).data(for: request) - - let decoded = try JSONDecoder().decode(JRPCResponse.self, from: val.0) - return decoded - } catch { - return nil + + group.addTask { + do { + let shareRequestItem = ShareRequestParams.ShareRequestItem( + verifieridentifier: verifier, + verifier_id: verifierParams.verifier_id, + extended_verifier_id: verifierParams.extended_verifier_id, + idtoken: idToken, + nodesignatures: nodeSigs, + // extra_params: extraData + sub_verifier_ids: verifierParams.sub_verifier_ids, + session_token_exp_second: sessionExpiry, + verify_params: verifierParams.verify_params + ) + + let params = ShareRequestParams(encrypted: "yes", item: [shareRequestItem], client_time: String(Int(trunc(Double((serverTimeOffset ?? 0) + Int(Date().timeIntervalSince1970)))))) + + let jsonRPCRequest = JRPCRequest( + method: JRPC_METHODS.GET_SHARE_OR_KEY_ASSIGN, + params: params + ) + + let encoder = JSONEncoder() + encoder.outputFormatting = .sortedKeys + let rpcdata = try encoder.encode(jsonRPCRequest) + var request = try MetadataUtils.makeUrlRequest(url: endpoints[i]) + request.httpBody = rpcdata + let val = try await URLSession(configuration: .default).data(for: request) + + let decoded = try JSONDecoder().decode(JRPCResponse.self, from: val.0) + return decoded + } catch { + return nil + } } } - } - - var collected = [JRPCResponse?]() - for try await value in group { - collected.append(value) - if !isImportShareReq { - if value != nil && value?.error == nil { - received += 1 - if received >= minRequired { - group.cancelAll() + + var collected = [JRPCResponse?]() + for try await value in group { + collected.append(value) + if !isImportShareReq { + if value != nil && value?.error == nil { + received += 1 + if received >= minRequired { + group.cancelAll() + } } } } + + return collected } - - return collected + shareRequestResults = shareResults.map({ $0?.result }) } - - let shareResponses: [ShareRequestResult] = shareRequestResults.filter({ $0?.result != nil }).map({ $0!.result! }) + + let shareResponses: [ShareRequestResult] = shareRequestResults.filter({ $0 != nil }).map({ $0! }) let pubkeys = shareResponses.filter({ $0.keys.count > 0 }).map { $0.keys[0].publicKey } @@ -436,9 +441,8 @@ internal class NodeUtils { guard let cipherTextHex = String(data: cipherData, encoding: .utf8) else { throw TorusUtilError.decodingFailed("cipherData is not utf8") } - let decrypted = try MetadataUtils.decryptNodeData(eciesData: latestKey.shareMetadata, ciphertextHex: cipherTextHex, privKey: sessionAuthKeySerialized) - + let share1 = BigInt(decrypted, radix: 16)?.magnitude.serialize().addLeading0sForLength64() shares.append(decrypted) } else { nodeIndexes.append(nil) @@ -472,7 +476,6 @@ internal class NodeUtils { decryptedShares.updateValue(item!, forKey: nodeIndexes[i]!) } } - let elements = Array(0...decryptedShares.keys.max()!) // Note: torus.js has a bug that this line resolves let allCombis = kCombinations(elements: elements.slice, k: threshold) diff --git a/Sources/TorusUtils/TorusUtils.swift b/Sources/TorusUtils/TorusUtils.swift index c566680f..68bc2a55 100644 --- a/Sources/TorusUtils/TorusUtils.swift +++ b/Sources/TorusUtils/TorusUtils.swift @@ -181,7 +181,6 @@ public class TorusUtils { newPrivateKey: String ) async throws -> TorusKey { let nodePubs = TorusNodePubModelToINodePub(nodes: nodePubKeys) - debugPrint(nodePubs.map({ $0.X })) if endpoints.count != nodeIndexes.count { throw TorusUtilError.runtime("Length of endpoints must be the same as length of nodeIndexes") } diff --git a/Tests/TorusUtilsTests/SapphireMainnetTests.swift b/Tests/TorusUtilsTests/SapphireMainnetTests.swift index 456303c2..bebc92b4 100644 --- a/Tests/TorusUtilsTests/SapphireMainnetTests.swift +++ b/Tests/TorusUtilsTests/SapphireMainnetTests.swift @@ -49,23 +49,6 @@ class SapphireMainnetTests: XCTestCase { XCTAssertNotNil(val.nodesData) } - func test_should_be_able_to_import_key_for_a_new_user() async throws { - let fakeEmail = generateRandomEmail(of: 6) - let jwt = try generateIdToken(email: fakeEmail) - let privateKey = try KeyUtils.generateSecret() - - let verifier = TORUS_TEST_VERIFIER - let verifierID = fakeEmail - - let nodeDetails = try await fnd.getNodeDetails(verifier: verifier, verifierID: verifierID) - - let verifierParams = VerifierParams(verifier_id: verifierID) - - let val = try await torus.importPrivateKey(endpoints: nodeDetails.getTorusNodeSSSEndpoints(), nodeIndexes: nodeDetails.getTorusIndexes(), nodePubKeys: nodeDetails.getTorusNodePub(), verifier: verifier, verifierParams: verifierParams, idToken: jwt, newPrivateKey: privateKey) - - XCTAssertEqual(val.finalKeyData.privKey, privateKey) - } - func test_should_be_able_to_key_assign() async throws { let fakeEmail = generateRandomEmail(of: 6) let verifier = "tkey-google-sapphire-mainnet"