Issue creating SecKey type secp256r1 from base64 encoded string

Hi!

With CryptoKit functions i can instantiate certificate keys, but with usage of Security module the code fails. I cannot figure out what is the issue.

Anyone have any idea what needs to be changed?

Thanks!!!, Garfield

This is the code that causes issue:

import Security
import CryptoKit

// base64 encoded
let privateKeyString = "deXnwQoRHddejAMvHsucXdPkE0B5hAIap1VE69ASplo="

let publicKeyString = "p4Rqbh+nmv/FslbJFGOe7JzSP6/ySaTkgW6h5t/+fqC/E8M9SVmamBKdTusddEecWY5KBGZo4x2oeNYyM7EtPA=="

let attributesPrivate: [NSObject : NSObject] = [
        kSecAttrKeyType: kSecAttrKeyTypeECSECPrimeRandom,
        kSecAttrKeyClass: kSecAttrKeyClassPrivate
 ]
     
    let attributesPublic: [NSObject : NSObject] = [
        kSecAttrKeyType: kSecAttrKeyTypeECSECPrimeRandom,
        kSecAttrKeyClass: kSecAttrKeyClassPublic
 ]
     
 var errorPrivate: Unmanaged<CFError>?
 var errorPublic: Unmanaged<CFError>?
 var error: Unmanaged<CFError>?

  if #available(iOS 13.0, *) {
      let publicKeyX = try! P256.Signing.PublicKey(rawRepresentation: Data(base64Encoded: publicKeyString)!.suffix(65))
      //https://developer.apple.com/forums/thread/680554
      print(publicKeyX, "P256 PUBLIC")
      let privateKeyX = try! P256.Signing.PrivateKey(rawRepresentation: Data(base64Encoded: privateKeyString)!.suffix(65))
      print(privateKeyX, "P256 PRIVATE")
       
    } else {
      // Fallback on earlier versions
    }
     
     
    let publicKey = SecKeyCreateWithData(Data(base64Encoded: publicKeyString)! as NSData, attributesPublic as NSDictionary, &errorPublic)!
     
    let privateKey = SecKeyCreateWithData(Data(base64Encoded: privateKeyString)! as NSData, attributesPrivate as NSDictionary, &errorPrivate)!

Replies

The publicKeyString value you posted isn’t in any format I recognise. When I decode the Base64 I get this:

% xxd public.dat 
00000000: a784 6a6e 1fa7 9aff c5b2 56c9 1463 9eec  ..jn......V..c..
00000010: 9cd2 3faf f249 a4e4 816e a1e6 dffe 7ea0  ..?..I...n....~.
00000020: bf13 c33d 4959 9a98 129d 4eeb 1d74 479c  ...=IY....N..tG.
00000030: 598e 4a04 6668 e31d a878 d632 33b1 2d3c  Y.J.fh...x.23.-<

That’s not P-256 key (there’s no leading 04). It’s not valid ASN.1, which rules out a bunch of other possibilities. And it’s the wrong size for Curve 25519.

Likewise for privateKeyString:

% xxd private.dat 
00000000: 75e5 e7c1 0a11 1dd7 5e8c 032f 1ecb 9c5d  u.......^../...]
00000010: d3e4 1340 7984 021a a755 44eb d012 a65a  ...@y....UD....Z

Where did you get this key from? I recommend that you ask those folks what format they’re using. For reference, see On Cryptographic Key Formats.


Oh, wait, perhaps this is a P-256 key but you’re split apart the components. In that case publicKeyString represents X and Y and privateKeyString represents K. If so, you can get an importable public key by concatenating 04 + X + Y and an importable private key by concatenating 04 + X + Y + K.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

Hi Quinn!

Thanks for you response!

I updated my code as:

   let scPrivKey = "rDwi4NmRl72ddh8pfokibvvU1HWehdr6EWBC/ylJed8="
   let scPubKey = "p4Rqbh+nmv/FslbJFGOe7JzSP6/ySaTkgW6h5t/+fqC/E8M9SVmamBKdTusddEecWY5KBGZo4x2oeNYyM7EtPA=="
     
   var scPrivKeyData = Data(base64Encoded: scPrivKey)
   var scPubKeyData = Data(base64Encoded: scPubKey)
     
   var scPubKeyDataBytes = [UInt8](scPubKeyData!)
   scPubKeyDataBytes.insert(04, at: 0)
 
     
  var errorXPub: Unmanaged<CFError>? = nil
  var errorXPriv: Unmanaged<CFError>? = nil

     
  var xy = Data(scPubKeyDataBytes)
  xy.append(scPrivKeyData!)
     
  let keyW = SecKeyCreateWithData(Data(scPubKeyDataBytes) as NSData, [
    kSecAttrKeyType: kSecAttrKeyTypeECSECPrimeRandom,
    kSecAttrKeyClass: kSecAttrKeyClassPublic
  ] as NSDictionary, &errorXPub)
     
     
  let keyWP = SecKeyCreateWithData(xy as NSData, [
    kSecAttrKeyType: kSecAttrKeyTypeECSECPrimeRandom,
    kSecAttrKeyClass: kSecAttrKeyClassPrivate
  ] as NSDictionary, &errorXPriv)
     
  print(keyW, "DEMO PUBLIC KEY", errorXPub, "PRIVATE KEY", keyWP, errorXPriv)

Now the keys are instantiated using your advice and link to documentation.

But no such luck with generation of SecKeyCopyKeyExchangeResult

Bellow is the code I use

var errorPA: Unmanaged<CFError>? = nil
     
var dict: [String: Any] = [
  SecKeyKeyExchangeParameter.requestedSize.rawValue as String: 16,
  kSecAttrKeyType as String: kSecAttrKeyTypeECSECPrimeRandom,
 ]
     
 let ff = SecKeyCopyKeyExchangeResult(
  keyWP!,
  SecKeyAlgorithm.ecdhKeyExchangeStandardX963SHA256,
  keyW!,
  dict as CFDictionary, &errorPA
 )
print("DF shared", ff, errorPA)

The result of shared secret generation is

Optional(Swift.Unmanaged<__C.CFErrorRef>(_value: Error Domain=NSOSStatusErrorDomain Code=-26275 "ECpriv failed to compute shared secret (err -1)" UserInfo={numberOfErrorsDeep=0, NSDescription=ECpriv failed to compute shared secret (err -1)}))

Uf, any idea what to adjust!

Thanks!

I can’t spot the problem in your code but in this post you’ll find code that I know works.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

Ok. Thanks for your effort Quinn!

Have a nice day!