Skip to content

Commit

Permalink
fix: encryption bug
Browse files Browse the repository at this point in the history
  • Loading branch information
metalurgical committed May 21, 2024
1 parent 4ea7912 commit c20aec6
Show file tree
Hide file tree
Showing 6 changed files with 122 additions and 148 deletions.
2 changes: 1 addition & 1 deletion Sources/TorusUtils/Constants.swift
Original file line number Diff line number Diff line change
@@ -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"
Expand Down
4 changes: 2 additions & 2 deletions Sources/TorusUtils/Helpers/KeyUtils.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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())
Expand Down
15 changes: 2 additions & 13 deletions Sources/TorusUtils/Helpers/MetadataUtils.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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())
}
Expand Down
231 changes: 117 additions & 114 deletions Sources/TorusUtils/Helpers/NodeUtils.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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<ShareRequestResult>?] = try await withThrowingTaskGroup(of: JRPCResponse?.self, returning: [JRPCResponse<ShareRequestResult>?].self) {
group -> [JRPCResponse<ShareRequestResult>?] 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<ShareRequestResult>?] = try await withThrowingTaskGroup(of: JRPCResponse?.self, returning: [JRPCResponse<ShareRequestResult>?].self) {
group -> [JRPCResponse<ShareRequestResult>?] 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<ShareRequestResult>.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<ShareRequestResult>.self, from: val.0)
return decoded
} catch {
return nil
}
}
}
}

var collected = [JRPCResponse<ShareRequestResult>?]()
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<ShareRequestResult>?]()
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 }

Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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)
Expand Down
1 change: 0 additions & 1 deletion Sources/TorusUtils/TorusUtils.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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")
}
Expand Down
17 changes: 0 additions & 17 deletions Tests/TorusUtilsTests/SapphireMainnetTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down

0 comments on commit c20aec6

Please sign in to comment.