Can I create a seckey from a private key?

I've looked online for information on SecKeys and even more on what I'm trying to do, with little result. All I'm wanting to do is access the Google API for a Google calendar from my iOS app. I've read through Google's documentation on how to authenticate using OAuth2. I've obtained a private key for my service account, and I have an API key already, an app identity, etc. I know I've got to submit a JWT to Google's token server in exchange for a token. I've got the header and payload encoded to base64. The only part I'm stuck on is the last part, creating the signature. I know I need to generate a JWS, but documentation on doing this is sparse. To help, I've employed the use of JOSESwift from GitHub (https://github.com/airsidemobile/JOSESwift. The first thing it wants is to define a variable as a SecKey.


let privateKey: SecKey = /* ... */

But the documentation doesn't tell me what /* ... */ is supposed to be. I was assuming it was my private key, so I tried to feed it as a string value, but that failed. Then I tried encoding the private key as base64 and setting that as the secKey but that also failed. I tried casting my private key as Data and passing that, but it also failed. Online documentation and prior answers to this problem are so sparse and I've not been able to find a solution, so I'm turning here for help. What do I need in order to create a SecKey in Swift?

A

SecKey
is an opaque object that represents a key. You can’t create one from, say, a string literal. Rather, you have to call a routine to create the key from some external representation. The easiest way to do that is with
SecKeyCreateWithData
. For example:
let keyBase64 = "MIIEpAIBAAKCAQEA5B7lqLrwVCFNUiCmwMr5Q48iuArOolxb7DAuclGnoZVX0SaJ8mrvCOtd6qY/VeBw227txWEPH7840qX/yGxxqTngdNCuDATqYrrbxFOGV30GZmg6NpZYKShTlsftkhiCsoXW0A7m5MCZUkH2/sNBC8oRHCNDXRlsU5bq/yPaAMt6xlBsUgLt/++INcuw+rx1Rm7LJv0FeukQmlekUOL/DMJXcLXCa05StTbvHPiAHOLej07pThCZoX3XHFpOTQ6379EsjvSZHtNhr67qrtRb8or2rX7wt5NWzXHbhUDlyzEcIBB/7G8ygqWhyZTEIMFiRMWSa3KGYZE3nZe5weC7SQIDAQABAoIBAQCjjxehA+++kmYK5YhKIP3Zl64QAQeo18m8rcsPgkZLj3V4a0Zq/orGfWNIE8zDePnSC1YFuBKM86D9P7IGdOKFsA6kEt9HlNqs0UczG6Pt5KGLGV3rt54cXGKacFyA7HwBHf8oDBc2mnUTymIaxcpEdqwP3aS2Ar1trX5uUrlC6UcZyspBZVYvMlU+uAKL1ZtFxjsv0EzuQQW1HX7b2WPUAoxp/yBC/EBRM9K8WbG9i7NB4FTFHAdTMt/EZLGUESizFgrai6lp3s96Apz5GvncRUI+UVP/7zbUaFYdRMW5lrcR8+PL9NACkL2rnQuLoyLKWZWPPlD3WEE9EzY4bH6FAoGBAPu8hL8goEbWMFDZuox04Ouy6EpXR8BDTq8ut6hmad6wpFgZD15Xu7pYEbbsPntdYODKDDAIJCBsiBgf2emL50BpiQkzMPhxyMsN5Pzry9Ys+AzPkJcQ7g+/Wbto9lCC+JmgxtGQ7JIibo1QH7BTsuK9+k72HnZne6oIfaYKbBZfAoGBAOf7/D2Q7NiNcEgxpZRn06+mnkHMb8PfCKfJf/BFf5WKXSkDBZ3XhWSPnZyQnE3gW3lzJjzUwHS+YDk8A0Xl2piAHa/d5O/8eoijB8wa6UGVDBIXqUnfM3Udfry78rM71FOpbzV3H48G7u4CUJMGwOpEqF0TfgtQr4uf8OurdH9XAoGAbdNhVsE1K7Jmgd97s6uKNUpobYaGlyrGOUd4eM+1gKIwEP9d5RsBm9qwX83RtKCYk3mSt6HVoQ+4kE3VFD8lNMTWNF1REBMUNwJo1K9KzrXvwicMPdv1AInK7ChuzdFWBDBQjT1c+KRs9tnt+U+Ky8F2Ytydjaq4GQZ7SuVhIqECgYBMsS+IovrJ9KhkFZWp5FFFRo4XLqDcXkWcQq87HZ66L03xGwCmV/PPdPMkKWKjFELpebnwbl1Zuv5QrZhfaUfFFsW5uF/RPuS7ezo+rb7jYYTmDlB3DYUTeLbHalMoEeV16xPK1yDlxeMDaFx+3sK0MBKBAsqurvP58txQ7RPMbQKBgQCzRcURopG0DF4VF4+xQJS8FpTcnQsQnO/2MJR35npA2iUb+ffs+0lgEdeWs4W46kvaF1iVEPbr6She+aKROzE9Bs25ZCgGLv97oUxDQo0IPvURX7ucN+xOUU1hw9oQDVdGKl1JZh93fn+bjtMTe+26asGLmM0r9YQX1P8qaw3KOg=="
let keyData = Data(base64Encoded: keyBase64)!
let key = SecKeyCreateWithData(keyData as NSData, [
    kSecAttrKeyType: kSecAttrKeyTypeRSA,
    kSecAttrKeyClass: kSecAttrKeyClassPrivate,
] as NSDictionary, nil)!
print(key)  // prints "<SecKeyRef algorithm id: 1, key type: RSAPrivateKey, version: 4, block size: 2048 bits, addr: 0x101a25d10>"

The biggest gotcha with this code it that it requires the key to be in a specific format, namely, a DER-encode

RSAPrivateKey
structure (see Section 7.2 of RFC 2313). If you’re starting out with a PEM key it’s likely that your key isn’t a vanilla
RSAPrivateKey
but rather a
PrivateKeyInfo
(see Section 5 of RFC 5208). You can convert from the former to the latter using:
$ openssl rsa -in key.pem -outform der -out key.der

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"

Having said that, I’m concerned about you embedding a private key into your app. Such a key could be extracted and then used maliciously (you can make this easier or harder depending on how you try to obfuscate the key, but there’s no way to get guaranteed protection). If you can move this work to a server, so that the private key only resides on a server you control, that’d be much better.

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"

If you are given a private key in String format (base64 encoded, Algorithm : EC with secp256r1 (curve)), then how can the same be converted to SecKey ? Please help!!

how can the same be converted to SecKey?

It’s hard to say without more details. However, I’ve recently created two posts that’ll help you determine those details and import the key from there:

Share and Enjoy

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

Thanks eskimo!

I want to ask :

  1. Is there any way to convert private key string (base64 encoded) directly to SecKey without using openssl i.e. via swift code?

  2. Further I want to sign a data using the generated SecKey with SHA256withECDSA algorithm.

Can you please help!!

Is there any way to convert private key string (Base64 encoded) directly to SecKey without using openssl i.e. via swift code?

That depends on the specific details. I recommend that you use the techniques shown in the posts I referenced previously to unpack an example key and thus uncover those details.

Further I want to sign a data using the generated SecKey with SHA256withECDSA algorithm.

If you have a SecKey you can sign data using SecKeyCreateSignature. From there it’s just a matter of deciding what SecKeyAlgorithm to request. I suspect that you want .ecdsaSignatureDigestX962SHA256 but, again, it’s hard to say for sure based on the details you’ve provided.

Share and Enjoy

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

Hi eskimo, 

I am mentioning my query in details. 

Suppose, 

Algorithm used for Key Generation: EC with secp256r1 (curve) 

Private Key (Base64 Encoded): MEECAQAwEwYHKoZIzj0CAQYIKoZIzj0DAQcEJzAlAgEBBCChpu/0UpxLGB9S7J/vbNaThjp4jCYtAToRNq87Im4+rA== 

and Public key (Base64 Encoded): MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEuV2qegvFLPlyI4JIZdfdMx3MIenSKfTr1X53vOoou1ZE3KZPCgveHDS5zJBq9ofaMl+5Bz3uJhgA7bIZpKqQxg==  

Data for signing: "{"my-name":"example-name","email-id":"sample-@email-id","mobile-number":1111111110,"my-designation-type":"emp","my-company-name":"ABC"}" 

Algorithm to use for Signing: SHA256withECDSA  


Can you please provide complete code in swift to sign the above data (as mentioned in Data for Signing) using above mentioned algorithm?  

I searched a lot, but nothing helped. Thanks again...

So, again, I’m going to recommend that you use the techniques from the above-mentioned post to:

  1. Decode your private key to confirm the exact format they’re in.

  2. If the format is one supported by iOS, import the key.

Once you have the key imported, we can talk about signing data.

Share and Enjoy

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

Hi eskimo !

Thanks a lot for your precious help !

I read the 2 links you mentioned in your earlier posts and followed the procedure as below -

  1. From given pem file, I created a .der file.

openssl ec -in privateKey_encoded.pem -outform DER -out privateKey_encoded.der

which gave me privateKey_encoded.der file.

  1. Then I did following :

xxd -p privateKey_encoded.der

which gave following -

307702010104202be46bb8e45619c112c025bf1ee1e82a0e29c74badd0a6
98aa75cb35b04e1852a00a06082a8648ce3d030107a14403420004b33ee9
0c5e9c3fea406ebfcf94b9a9f012d46aa8f2b42f7a9b92de01fec3b84397
9398a243dbf0a0c9172db33ea49ab96c295e11c52fed2bbfb183987943be
d9

(The presence of the leading 0x30 is a common indicator that you’re looking at DER-encoded ASN.1)

  1. I tried to decode the private key to confirm the exact format its in. (using dumpans1.c tool as you recommended)

./dumpasn1 -p -a privateKey_encoded.der

which gave following output:

SEQUENCE {
  INTEGER 1
  OCTET STRING
    2B E4 6B B8 E4 56 19 C1 12 C0 25 BF 1E E1 E8 2A
    0E 29 C7 4B AD D0 A6 98 AA 75 CB 35 B0 4E 18 52
  [0] {
    OBJECT IDENTIFIER '1 2 840 10045 3 1 7'
    }
  [1] {
    BIT STRING
      04 B3 3E E9 0C 5E 9C 3F EA 40 6E BF CF 94 B9 A9
      F0 12 D4 6A A8 F2 B4 2F 7A 9B 92 DE 01 FE C3 B8
      43 97 93 98 A2 43 DB F0 A0 C9 17 2D B3 3E A4 9A
      B9 6C 29 5E 11 C5 2F ED 2B BF B1 83 98 79 43 BE
      D9
    }
  }

(This is an ASN.1 ECPrivateKey structure) It is prime256v1 (1 2 840 10045 3 1 7)


Now comes importing the key.

I read the link you provided, but I did not understand how should I proceed importing the key.

My questions are -

  1. From the above got BIT STRING, how can I create privateKey_encoded.dat file ? Is that the way to proceed further? I mean is that what I need to do in order to import the private key ?

  2. From the link you gave (https://developer.apple.com/forums/thread/680572) which section do I need to refer to proceed for importing the private key?

Do you have to end up with SecKey here? Or can you use Apple CryptoKit?

The main tradeoff here is that CryptoKit has better import options but it also has strict deployment target.

Share and Enjoy

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

Why complicate things so much? I don't want a degree in Security? I just want a step by step guide on how to send a Push Notification with any of the 20 keys I have in any format you want. I have spent 80 hours on LOADING a Security Key. It should take 20 minutes. WHY!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

Can I create a seckey from a private key?
 
 
Q