I’ve set up a relatively simple license server for my app. All works fine, but the app needs internet to check the Stripe purchase confirmation and my client-base tends to sandbox their computers so when the app phones home, it often gets blocked.
Instead I thought I’d do a public/private key pair and have Swift verify the signature obtained from the website. I realise this will cause issues with getting the signature to the end-user’s computer but I’m going to have to provide something that will mean cutting and pasting in some way.
To this end, I’ve prototyped signature generation in PHP and attempting verification in Swift using Apple’s Security framework.
The PHP code is:
<?php
$privateKey = openssl_pkey_get_private(file_get_contents(“my_private_key.pem"));
$data = "TRANS_ID";
openssl_sign($data, $signature, $privateKey);
echo (base64_encode($signature));
?>
In Swift, locally, I attempt to verify this data with:
let publickey = """
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA8DOlH14DBTIca4z0+9qk
…
-----END PUBLIC KEY-----
"""
if let cU = URL(string: "https://swphp.brightscreentv.net/license_check_rsa.php") {
var r = URLRequest(url: cU, cachePolicy: URLRequest.CachePolicy.reloadIgnoringLocalAndRemoteCacheData, timeoutInterval: 5.0)
r.httpMethod = "POST"
let s = URLSession.shared
s.dataTask(with: r, completionHandler: { (someData, r, e) in
if let returnedError = e {
print( returnedError.localizedDescription)
} else if let retData = someData, let st = String(data: retData, encoding: .utf8) {
print (st)
var error: UnsafeMutablePointer<Unmanaged<CFError>?>?
if let pubKeyData = publickey.data(using: .utf8) {
if let secKey = SecKeyCreateWithData(pubKeyData as CFData,
[
kSecAttrKeyType: kSecAttrKeyTypeRSA,
] as NSDictionary,
error) {
let success = SecKeyVerifySignature(secKey, .rsaSignatureMessagePSSSHA1, ("Hi".data(using: .utf8)! as CFData ) as CFData, someData! as CFData, error)
print("(success)")
} else {
print ("secKey init failure: (error.debugDescription)")
}
} else {
print("pubKeyData init failed: (error.debugDescription)")
}
} else {
dump(someData)
}
}).resume()
}
I appreciate that the Swift code probably has more than one problem, it’s a third or fourth iteration and has various elements from SO answers and Apple Forum answers. But it’s the first attempt that I’ve managed to get to compile. I’ve tried various encoding options for the Swift String
methods but all have the same outcome.
How should I go about generating a SecKeyCreateWithData
from the PHP response so that I can then verify it?