Skip to content

Instantly share code, notes, and snippets.

@jmcd
Last active April 8, 2022 17:37
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save jmcd/b9a212df5dfa88b6d8dcb52c51b6be6b to your computer and use it in GitHub Desktop.
Save jmcd/b9a212df5dfa88b6d8dcb52c51b6be6b to your computer and use it in GitHub Desktop.
Diffie–Hellman key exchange simple implementation
import Foundation
protocol Cipher {
func encrypt(message: String, secret: Int) -> String
func decrypt(message: String, secret: Int) -> String
}
struct XOR: Cipher {
private func impl(message: String, secret: Int) -> String? {
return message.unicodeScalars.map { UnicodeScalar(Int($0.value) ^ secret) }.flatMap{ $0 }.reduce("") { $0 + String($1) }
}
func encrypt(message: String, secret: Int) -> String { return impl(message: message, secret: secret)! }
func decrypt(message: String, secret: Int) -> String { return impl(message: message, secret: secret)! }
}
protocol Exchange {
func sharedBaseForInsecureTransmission(secret: Int) -> Int
func sharedSecretByMixing(receivedSharedBase: Int, with secret: Int) -> Int
}
struct MultiplicativeGroupOfIntegersModulo: Exchange {
private let modulus: Int
private let base: Int
init(modulus: Int, base: Int) {
self.modulus = modulus
self.base = base
}
func sharedBaseForInsecureTransmission(secret: Int) -> Int {
return powMod(radix: base, power: secret)
}
func sharedSecretByMixing(receivedSharedBase: Int, with secret: Int) -> Int {
return powMod(radix: receivedSharedBase, power: secret)
}
private func powMod(radix: Int, power: Int) -> Int {
return Int(pow(Double(radix), Double(power))) % modulus
}
}
let exchange: Exchange = MultiplicativeGroupOfIntegersModulo(modulus: 23, base: 5)
let cipher: Cipher = XOR()
class Person {
let name: String
private let secret: Int
private var contacts = [(Person, sharedSecret: Int)]()
init(name: String, secret: Int) {
self.name = name
self.secret = secret
}
private func establishSharedSecret(with other: Person) {
let sharedBase = exchange.sharedBaseForInsecureTransmission(secret: secret)
other.accept(sharedBase: sharedBase, from: self)
}
private func accept(sharedBase: Int, from other: Person) {
let sharedSecret = exchange.sharedSecretByMixing(receivedSharedBase: sharedBase, with: secret)
contacts.append((other, sharedSecret))
}
static func establishSharedSecret(_ p0: Person, _ p1: Person) {
p0.establishSharedSecret(with: p1)
p1.establishSharedSecret(with: p0)
}
private func sharedSecret(for contact: Person) -> Int? {
guard let sharedSecret = (contacts.first { $0.0 === contact })?.sharedSecret else { return nil }
return sharedSecret
}
func send(message plaintext: String, to contact: Person) {
guard let sharedSecret = sharedSecret(for: contact) else { return }
let ciphertext = cipher.encrypt(message: plaintext, secret: sharedSecret)
print("\(name) encrypted '\(plaintext)' to '\(ciphertext)'")
contact.recieve(ciphertext: ciphertext, from: self)
}
private func recieve(ciphertext: String, from contact: Person) {
guard let sharedSecret = sharedSecret(for: contact) else { return }
let plaintext = cipher.encrypt(message: ciphertext, secret: sharedSecret)
print("\(name) decrypted '\(ciphertext)' to '\(plaintext)'")
}
}
let alice = Person(name: "Alice", secret: 6)
let bob = Person(name: "Bob", secret: 15)
Person.establishSharedSecret(alice, bob)
alice.send(message: "Hello!", to: bob)
bob.send(message: "Hi Alice", to: alice)
Alice encrypted 'Hello!' to 'Jgnnm#'
Bob decrypted 'Jgnnm#' to 'Hello!'
Bob encrypted 'Hi Alice' to 'Jk"Cnkag'
Alice decrypted 'Jk"Cnkag' to 'Hi Alice'
@raoarafat
Copy link

https://github.com/raoarafat/DeffieHelmanKeyExchange-Swift
Please check this out complete example.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment