I’m making an attempt to get Diffie Hellman Key Alternate working between my iOS (swift) app and my ASP.NET 8 Core Net Server however with every part I’ve tried thus far, the shared secrets and techniques derived on every platform are nonetheless completely different.
Issues I’ve tried:
- Made positive that public key despatched from iOS app to webserver match when acquired and processed.
- Additionally made positive that public key despatched from webserver to iOS app match when acquired and processed.
- (May very well be improper) however I’ve made positive that the important thing codecs are constant in each environments.
My workflow is under:
- iOS app generates a brand new key pair and sends its public key to the webserver
- The webserver, derives the shared secret and sends again its public key to the app
- iOS app then derives the shared secret utilizing server’s pk
And these derived shared secrets and techniques don’t match
Swift Code (Makes use of CryptoKit and at present examined on iOS 17.6+):
class HandshakeHelper
{
// CreateKeyPairs: Generates a private-public key pair
static func createKeyPairs() -> [String]
{
let privateKey = P256.KeyAgreement.PrivateKey()
let privateKeyBase64 = privateKey.derRepresentation.base64EncodedString()
let publicKeyBase64 = privateKey.publicKey.derRepresentation.base64EncodedString() // DER-encoded (X.509 format)
return [privateKeyBase64, publicKeyBase64]
}
// DeriveSharedSecret: Derives a shared secret utilizing our personal key and the opposite get together's public key
static func deriveSharedSecret(ourPrivateKeyBase64: String, receivedPublicKeyBase64: String) -> String?
{
guard let privateKeyData = Information(base64Encoded: ourPrivateKeyBase64),
let receivedPublicKeyData = Information(base64Encoded: receivedPublicKeyBase64) else
{
print("Invalid key information")
return nil
}
do
{
// Reconstruct our personal key and the acquired public key
let privateKey = attempt P256.KeyAgreement.PrivateKey(derRepresentation: privateKeyData)
let receivedPublicKey = attempt P256.KeyAgreement.PublicKey(derRepresentation: receivedPublicKeyData) // DER-encoded
// Derive the shared secret
let sharedSecret = attempt privateKey.sharedSecretFromKeyAgreement(with: receivedPublicKey)
// Return the shared secret as a base64 string
return sharedSecret.withUnsafeBytes { Information($0).base64EncodedString() }
} catch
{
print("Error deriving shared secret: (error)")
return nil
}
}
}
.NET 8 Code (Makes use of System.Safety.Cryptography):
public class HandshakeHelper
{
// CreateKeyPairs: Generates a private-public key pair
public static Listing CreateKeyPairs()
{
utilizing var ecdh = ECDiffieHellman.Create(ECCurve.NamedCurves.nistP256);
var privateKey = Convert.ToBase64String(ecdh.ExportECPrivateKey()); // PKCS#8 format
var publicKey = Convert.ToBase64String(ecdh.ExportSubjectPublicKeyInfo()); // X.509 format
File.WriteAllText("ecdh_priv.key", privateKey);
File.WriteAllText("ecdh_pub.key", publicKey);
return new Listing { privateKey, publicKey };
}
// DeriveSharedSecret: Derives a shared secret utilizing our personal key and the opposite get together's public key
public static string DeriveSharedSecret(string ourPrivateKeyBase64, string receivedPublicKeyBase64)
{
var privateKeyBytes = Convert.FromBase64String(ourPrivateKeyBase64);
var receivedPublicKeyBytes = Convert.FromBase64String(receivedPublicKeyBase64);
utilizing var ecdh = ECDiffieHellman.Create(ECCurve.NamedCurves.nistP256);
ecdh.ImportECPrivateKey(privateKeyBytes, out _); // Import our personal key
utilizing var receivedPublicKey = ECDiffieHellman.Create();
receivedPublicKey.ImportSubjectPublicKeyInfo(receivedPublicKeyBytes, out _); // Import the acquired public key
// Derive the shared secret
var sharedSecret = ecdh.DeriveKeyMaterial(receivedPublicKey.PublicKey);
return Convert.ToBase64String(sharedSecret); // Return shared secret in Base64 format
}
}