Skip to content

Instantly share code, notes, and snippets.

@below
Last active August 16, 2023 15:57
Show Gist options
  • Save below/4ac77dbf03a61fbc69bbcb3e7bebe011 to your computer and use it in GitHub Desktop.
Save below/4ac77dbf03a61fbc69bbcb3e7bebe011 to your computer and use it in GitHub Desktop.
Diffie-Hellman-Keyexchange
import CryptoKit
import Foundation
/** # Diffie-Heelman Keyexchange
This playground is meant to test a Diffie-Hellman Key Exchange between .Net´s `System.Security.Cryptography` and `CryptoKit`. Currently, my test is failing and any help is appreciated. More comments are in the code
*/
/// For testing, this is a constant private key. Yes, all of these keys have been generated for testing and are not used in production
let clientPrivateKey = try P521.KeyAgreement.PrivateKey(rawRepresentation: Data(base64Encoded: "AQmPwAfFwDDN298ek1vH3YIslW4hT2qPps7X4A2TMtnEBdJ6owPwB8cidtr9bl6vRiqIFJAc87S7lHwEbHoZCdRK")!)
let clientPublicKey = clientPrivateKey.publicKey
/// This is the public key we received from the server. **NOTE:** it is in the `eccBlob` Format, which means it starts with `ECK5`, and four bytes designating the length, followed by the actual key. For CryptoKit, the first 8 bytes must be discarded
let serverPublicKeyRaw = Data(base64Encoded: "RUNLNUIAAAABKtzFNMpPFNikLBlbkAkqo8c9Y8uXES3nNfDA50iq6TqpNgNvv6Ly/UC9/kH5ttP22qwN4A/axG4oqqfLhPP5vm0BDTTJh5FkfzaC0aHkqrBB5SznodNaD02UIqwCFjVsQiMtvl4q8OYCi41i3pRfD8MzpbUB1eQKow9EmQrTVmGm59k=")![8...]
var serverPublicKey: P521.KeyAgreement.PublicKey!
do {
serverPublicKey = try P521.KeyAgreement.PublicKey(rawRepresentation: serverPublicKeyRaw)
} catch {
print ("Server Public Key does not work: \(error)")
}
/// Now lets create a shared Secret
let sharedSecret = try clientPrivateKey.sharedSecretFromKeyAgreement(
with: serverPublicKey)
/// and derive a `SymetricKey`
let sharedHash = SHA256.self
let sharedInfo = serverPublicKey.rawRepresentation
let sharedLength = 32
let symetricKey = sharedSecret.x963DerivedSymmetricKey(
using: sharedHash,
sharedInfo: Data(),
outputByteCount: sharedLength)
/// (I have also tried `hkdfDerivedSymmetricKey`, no change)
/// Let's encrypt some stuff with it:
let data = "Hello, World!".data(using: .utf8)!
let sealedBox = try AES.GCM.seal(data, using: symetricKey)
/** Now, for testing, this is the raw sharedSecret I received from the server after sending the above PublicKey. It has been created using:
`ECDiffieHellmanCng.DeriveKeyMaterial(clientCngKey)`, a more detailed description is here: https://learn.microsoft.com/en-us/dotnet/api/system.security.cryptography.ecdiffiehellmancng?view=net-7.0
*/
let sharedServerSecret = Data(base64Encoded: "l0w86tNivCCin6dPxr/T6rIJsx1EZvrQZlFSGL2PIDQ=".data(using: .utf8)!)!
/// We can successfully create a `SymetricKey` with this data
let serverSymetricKey = SymmetricKey(data: sharedServerSecret)
/// Finally, let's try to open the box with the serverSymetricKey, as the assumption is that this is precisely what the server will attempt to do. After all, the keys *should* be identical:
do {
let openBox = try AES.GCM.open(sealedBox, using: serverSymetricKey)
String(data: openBox, encoding: .utf8)
} catch {
/// And we land here :( "Error opening box: authenticationFailure\n"
print ("Error opening box: \(error)")
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment