'Compute Diffie-Hellman key pair and shared secret in iOS with Swift

I need on iOS with Swift to:

  • Generate a Diffie–Hellman key pair with a pre-agreed modulus P and a base G
  • Compute a shared secret with a local private key, a remote public key and pre-agreed modulus P

And this without Elliptic-curve Diffie–Hellman (ECDH).

I wrote this code using BigInt repository.

/// Diffie–Hellman key pair
struct DHKeyPair {
    var privateKey: Data
    var publicKey: Data

    init(privateKey: Data, publicKey: Data) {
        self.privateKey = privateKey
        self.publicKey = publicKey
    }
}

/// Generate a Diffie–Hellman key pair
///
/// - Parameter modulus: Diffie-Hellman modulus P
/// - Parameter base: Diffie-Hellman base G
/// - Returns: DH key pair, or nil on error
static func generateDhKeyPair(modulus: Data, base: Data) -> DHKeyPair? {
    // Modulus
    let modulusBigUInt = BigUInt(modulus)

    // Base
    let baseBigUInt = BigUInt(base)

    // Generate random private key
    guard let privateKey = Crypto.randomBytes(length: 512) else {
        return nil
    }
    let privateKeyBigUInt = BigUInt(privateKey)

    // Compute public key
    let publicKeyBigUInt = baseBigUInt.power(privateKeyBigUInt, modulus: modulusBigUInt)
    var publicKey = publicKeyBigUInt.serialize()

    // Set Diffie-Hellman key pair
    let dhKeypair = DHKeyPair(privateKey: privateKey, publicKey: publicKey)

    return dhKeypair
}

/// Compute a shared secret based on local pair key (public/private) and remote public key
///
/// - Parameter privateKey: Private key
/// - Parameter remotePublicKey: Remote public key
/// - Parameter modulus: Diffie-Hellman modulus P
/// - Returns: the computed shared secret
static func computeSharedSecret(privateKey: Data, remotePublicKey: Data, modulus: Data) -> Data {
    // Private key
    let privateKeyBigUInt = BigUInt(privateKey)

    // Remote public key
    let remotePublicKeyBigUInt = BigUInt(remotePublicKey)

    // Modulus
    let modulusBigUInt = BigUInt(modulus)

    // Compute shared secret
    let sharedSecretBigUInt = remotePublicKeyBigUInt.power(privateKeyBigUInt, modulus: modulusBigUInt)
    var sharedSecret = sharedSecretBigUInt.serialize()

    return sharedSecret
}

It's well working but it takes too long, about 50 seconds to generate the key pair, and the same to compute the shared secret. This is because of the BigUInt modular exponentiation function (see doc).

I couldn't find anything for these operations in the Keys documentation of the API for Swift.

So how can I do these Diffie-Hellman operations faster? Can it be done also with Swift API?

PS: we've the same function on the JDK which takes just a few seconds.

EDIT 1:

These 2 operations take about 4 seconds with a build in release, which is acceptable. But the execution time is still too long in debug (on a real device or a simulator), and also the unit tests are commented because the execution time is too long when running the unit tests.



Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source