I'm converting a method that I have working in both NodeJS/Java to Swift but I'm having trouble getting it to work.
Hoping someone can help me covert this to Swift
NodeJS Code:
//the public_key param here is from a different device.
sign: function(public_key)
{
//dummy values
var PRE_SALT_VALUE = 'f0f0f0f0f0';
var POST_SALT_VALUE = '0101010101';
const crypto = require('crypto');
var sha512 = crypto.createHash("sha512");
var EC = require('elliptic').ec;
var ec = new EC('p256');
// Generate keys
var key1 = ec.genKeyPair(); //key1 is gen before pub key
var key2 = ec.keyFromPublic(public_key, 'hex') //pub key gen from saved cert
var derived_secret = key1.derive(key2.getPublic());
var derived_secret = Buffer.from(derived_secret.toString(16), 'hex')
var public_key_client = key1.getPublic('hex')
var pre_salt = Buffer.from(PRE_SALT_VALUE, 'hex')
var post_salt = Buffer.from(POST_SALT_VALUE, 'hex')
derived_secret = Buffer.from(pre_salt.toString('hex')+derived_secret.toString('hex')+post_salt.toString('hex'), 'hex') // finalyze shared secret
// Hash shared secret
var sha = sha512.update(derived_secret);
derived_secret = sha.digest();
return {
public_key: public_key_client.toString('hex').slice(2), //dropping first byte of compression bits
secret: derived_secret.toString('hex')
}
}
The same code is also working in Java: See the answer to a similar question I asked a few years ago here if you would like to see the java implementation. This was what originally helped me port it to java.
How do I add the same logic in Swift (I am a Swift beginner). So far I have tried
Step 1
// certData will be the external cert byte array in der format
let certData = Data(bytes: self.cert!, count: self.cert_length!)
// load the cert so I can read the data
guard let certificate = SecCertificateCreateWithData(nil, certData as CFData) else {
// todo handle error
print("explode")
return
}
// log public key from cert
let publicKey = SecCertificateCopyKey(certificate)!
let pubKeyExternRep = SecKeyCopyExternalRepresentation(publicKey, nil)
let pubKeyExternRepData:Data = pubKeyExternRep! as Data
print(pubKeyExternRepData.bytes) // printed pub key looks reasonable
Step 2 Next I have to generate a new random public/private keypair, so I tried this
// Attempt 1 - generate our own random public/private keypair
let attributes: [String: Any] = [
kSecAttrType as String: kSecAttrKeyTypeECSECPrimeRandom,
kSecAttrKeySizeInBits as String: 256,
kSecPrivateKeyAttrs as String: [
kSecAttrIsPermanent as String: true
]
]
var error: Unmanaged<CFError>?
let ouPrivateKeyAttempt1 = SecKeyCreateRandomKey(attributes as CFDictionary, &error)!
let ourPubKeyAttempt1 = SecKeyCopyPublicKey(ouPrivateKeyAttempt1)
let ourPubKeyExternRep = SecKeyCopyExternalRepresentation(ourPubKeyAttempt1!, &error)
print("our generated EC public key (65 bytes)")
print("\(pubKeyExternRep!)")
// =-=-=--=-=-=-=-==--==-=-=-=- End attempt1
Step 3 Next I have to derive the shared secret given the random keypair above the the public external cert. I am pretty lost at this point. I tried something like
// our private key agreement (does this generate a new private key, guess we dont need 'Attempt1' above?)
let ourPrivateKey = P256.KeyAgreement.PrivateKey()
let ourPubKey = ourPrivateKey.publicKey
// external device public key agreement given our generated private agreement
let externalPubKeyAg = try! P256.KeyAgreement.PublicKey(
rawRepresentation: pubKeyExternRepData.bytes) // <-- var from step 1, crashes here
// get shared secret
let sharedSecret = try! ourPrivateKey.sharedSecretFromKeyAgreement(
with: externalPubKeyAg)
print(sharedSecret)
The above will crash with CryptoKit.CryptoKitError.incorrectParameterSize
.
Anyway, hoping someone can help me convert the function that's in NodeJS/Java above into Swift. Thanks! :)