12 Replies
      Latest reply on Jun 9, 2019 4:27 PM by Craz1k0ek
      nighthound Level 1 Level 1 (0 points)
        let pubString = "MFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAECDDYmcIpUxC2EVJu8o/qPHPoZMId11A/2nVAXJByFOYSigUnZ6njK4qZQMGxLr3xNND17yYoXZ21QKus4bUHfg=="
        let pubData = NSData(base64Encoded: pubString)
        
        let pubRaw = pubData?.bytes.assumingMemoryBound(to: UInt8.self)
        
        let CFPubData = CFDataCreate(nil, pubRaw!, pubData!.length)
        
        let options: [String: Any] = [kSecAttrKeyType as String: kSecAttrKeyTypeEC,
                                      kSecAttrKeyClass as String: kSecAttrKeyClassPublic,
                                      kSecAttrKeySizeInBits as String: 256]
        
        var error: Unmanaged<CFError>?
        
        guard let privKey = SecKeyCreateWithData(CFPubData!, options as CFDictionary, &error) else {
            throw error!.takeRetainedValue() as Error
        }
        
        
        

         

        I'm getting Code=-50 "EC public key creation from data failed" (paramErr: error in user parameter list)

         

        The key is a public EC key generated (PEM Format, Headers stripped) with the following command:

         

        openssl ecparam -genkey -name secp256k1 -noout -out ngthnd_priv.pem

        • Re: MacOS: EC public key creation from data failed
          iTen Level 2 Level 2 (80 points)

          First off you already have base64 pubString, which you're encoding to base64 again, you will want to decode the base 64 to get the original value then create a data object to represent that string before passing it to the SecKeyCreateWithData ...

           

           

          https://forums.developer.apple.com/thread/72445

          • Re: MacOS: EC public key creation from data failed
            eskimo Apple Staff Apple Staff (11,805 points)

            The problem here is that the data you’re passing in isn’t sufficiently ‘raw’.  I decoded your Base64 and put the bytes into a file (tmp.asn1).  Dumping that file with dumpasn1 it’s clearly ASN.1 DER data:

            $ dumpasn1 -p tmp.asn1 
            SEQUENCE {
              SEQUENCE {
                OBJECT IDENTIFIER '1 2 840 10045 2 1'
                OBJECT IDENTIFIER secp256k1 (1 3 132 0 10)
                }
              BIT STRING
                04 08 30 D8 99 C2 29 53 10 B6 11 52 6E F2 8F EA
                3C 73 E8 64 C2 1D D7 50 3F DA 75 40 5C 90 72 14
                E6 12 8A 05 27 67 A9 E3 2B 8A 99 40 C1 B1 2E BD
                F1 34 D0 F5 EF 26 28 5D 9D B5 40 AB AC E1 B5 07
                7E
              }

            What you need to pass to SecKeyCreateWithData is the contents of the BIT STRING element.  I extracted that:

            $ hexdump -Cv tmp.dat
            00000000  04 08 30 d8 99 c2 29 53  10 b6 11 52 6e f2 8f ea  |..0...)S...Rn...|
            00000010  3c 73 e8 64 c2 1d d7 50  3f da 75 40 5c 90 72 14  |<s.d...P?.u@\.r.|
            00000020  e6 12 8a 05 27 67 a9 e3  2b 8a 99 40 c1 b1 2e bd  |....'g..+..@....|
            00000030  f1 34 d0 f5 ef 26 28 5d  9d b5 40 ab ac e1 b5 07  |.4...&(]..@.....|
            00000040  7e                                                |~|

            converted it to Base64:

            $ base64 -b 76 tmp.dat
            BAgw2JnCKVMQthFSbvKP6jxz6GTCHddQP9p1QFyQchTmEooFJ2ep4yuKmUDBsS698TTQ9e8mKF2d
            tUCrrOG1B34=
            $

            and then rolled it into a simple test project:

            let key = """
                BAgw2JnCKVMQthFSbvKP6jxz6GTCHddQP9p1QFyQchTmEooFJ2ep4yuKmUDBsS698TTQ9e8mKF2d\
                tUCrrOG1B34=
                """
            
            func test() {
                let keyData = Data(base64Encoded: self.key)!
                var error: Unmanaged<CFError>? = nil
                let key = SecKeyCreateWithData(keyData as NSData, [
                    kSecAttrKeyType: kSecAttrKeyTypeEC,
                    kSecAttrKeyClass: kSecAttrKeyClassPublic
                ] as NSDictionary, &error)
                NSLog("%@", "\(key)")
            }

            This successfully creates a SecKey.


            Finally, the code you posted is working way harder than it needs to.  In Swift you typically don’t use the NSData class but the Swift Data value.  You can convert that to NSData using as NSData, and NSData is then compatible with the CFData required by SecKeyCreateWithData.

            Share and Enjoy

            Quinn “The Eskimo!”
            Apple Developer Relations, Developer Technical Support, Core OS/Hardware
            let myEmail = "eskimo" + "1" + "@apple.com"

              • Re: MacOS: EC public key creation from data failed
                nighthound Level 1 Level 1 (0 points)
                let pubString = """
                BAlrIluxyea/xayqVZtMzsNZtbBxdw0GEsUujfneVp85xDbcfmUZK2seopYOFbvImrej+dHK0ZUbdgyVlADrhsE=
                """
                
                let keyData = Data(base64Encoded: pubString)
                
                var error: Unmanaged<CFError>? = nil
                
                let key = SecKeyCreateWithData(keyData! as NSData, [
                    kSecAttrKeyType: kSecAttrKeyTypeEC,
                    kSecAttrKeyClass: kSecAttrKeyClassPublic
                    ] as NSDictionary, &error)
                
                NSLog("%@", "\(key)")
                
                var test: String = "Testing String"
                
                let tdat = test.data(using: .utf8)
                
                var tsig: String = "MEUCIFxeafOypiP34gPldM0owqBZXVIDx/qZJm2l5DclV4aNAiEA+ntwG9kOqs3p5cU4RITlSVR5VvrVM76VE1BvnJb+rps="
                let sDat = NSData(base64Encoded: tsig)
                
                guard SecKeyVerifySignature(key!, SecKeyAlgorithm.ecdsaSignatureMessageX962SHA256, tdat! as NSData, sDat! as NSData, &error) else {
                    throw error!.takeRetainedValue() as Error
                }
                
                
                
                

                 

                This helped. but I have another question. If I use the following PHP code:

                $kString = "-----BEGIN EC PRIVATE KEY-----
                
                MHQCAQEEIB/i6S16PGkX6D6rVm5BlQ7TCxrKXy8Do3ve6mVxtUrtoAcGBSuBBAAK
                oUQDQgAECWsiW7HJ5r/FrKpVm0zOw1m1sHF3DQYSxS6N+d5WnznENtx+ZRkrax6i
                lg4Vu8iat6P50crRlRt2DJWUAOuGwQ==
                -----END EC PRIVATE KEY-----";
                
                
                
                
                $key = openssl_pkey_get_private($kString);
                
                
                
                
                $stringToSign = "Testing String";
                openssl_sign($stringToSign, $sig, $key, "sha256");
                
                
                
                

                which SecKeyAlgorithm could I then use to verify the signature? because I'm getting "EC signature verification failed (ccerr -1)" with algorithm ecdsaSignatureMessageX962SHA256

                 

                With the PHP code, I was able to base64 encode the resulting signature ($sig) and it came out like this:

                MEUCIFxeafOypiP34gPldM0owqBZXVIDx/qZJm2l5DclV4aNAiEA+ntwG9kOqs3p5cU4RITlSVR5VvrVM76VE1BvnJb+rps=

                  • Re: MacOS: EC public key creation from data failed
                    eskimo Apple Staff Apple Staff (11,805 points)

                    I don’t have a ready answer for you here.  My general approach for dealing with problems like this is to import the private key on iOS, creating a test signature there, then try verifying that on the other platform.  Some other hints:

                    • I recommend that you pull PHP out of the equation (PHP crypto is super weird in my experience) and instead do the signing and verification using the openssl command line tool.

                    • You should take a look at RFC 6979, which has test vectors for this stuff.

                    Share and Enjoy

                    Quinn “The Eskimo!”
                    Apple Developer Relations, Developer Technical Support, Core OS/Hardware
                    let myEmail = "eskimo" + "1" + "@apple.com"

                      • Re: MacOS: EC public key creation from data failed
                        nighthound Level 1 Level 1 (0 points)

                        So if I try to pass the private key into SecKeyCreateWithData, do I need to pass the OCTET STRING from dumpasn1 or both it and the BIT STRING or is there some special way I need to go about this?

                          • Re: MacOS: EC public key creation from data failed
                            eskimo Apple Staff Apple Staff (11,805 points)

                            So if I try to pass the private key into SecKeyCreateWithData, do I need to pass the OCTET STRING from dumpasn1 or both it and the BIT STRING

                            I’m missing some context.  The only dumpasn1 example on this thread is mine, from 22 Sep, and it only includes a BIT STRING.  Which dumpasn1 output are you referring to?

                            Share and Enjoy

                            Quinn “The Eskimo!”
                            Apple Developer Relations, Developer Technical Support, Core OS/Hardware
                            let myEmail = "eskimo" + "1" + "@apple.com"

                              • Re: MacOS: EC public key creation from data failed
                                new_user Level 1 Level 1 (0 points)

                                An example of a key with Bit and Octet strings:

                                -----BEGIN PRIVATE KEY-----
                                MIGTAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBHkwdwIBAQQgU208KCg/doqiSzsV
                                F5sknVtYSgt8/3oiYGbvryIRrzSgCgYIKoZIzj0DAQehRANCAAQfrvDWizEnWAzB
                                2Hx2r/NyvIBO6KGBDL7wkZoKnz4Sm4+1P1dhD9fVEhbsdoq9RKEf8dvzTOZMaC/i
                                LqZFKSN6
                                -----END PRIVATE KEY-----
                                
                                
                                
                                
                                
                                
                                
                                
                                
                                
                                

                                 

                                Dumpasn1 output:

                                SEQUENCE (3 elem)
                                    INTEGER 0
                                    SEQUENCE (2 elem)
                                        OBJECT IDENTIFIER 1.2.840.10045.2.1 ecPublicKey (ANSI X9.62 public key type)
                                        OBJECT IDENTIFIER 1.2.840.10045.3.1.7 prime256v1 (ANSI X9.62 named elliptic curve)
                                    OCTET STRING (1 elem)
                                        SEQUENCE (4 elem)
                                            INTEGER 1
                                            OCTET STRING (32 byte) 536D3C28283F768AA24B3B15179B249D5B584A0B7CFF7A226066EFAF2211AF34
                                            [0] (1 elem)
                                                 OBJECT IDENTIFIER 1.2.840.10045.3.1.7 prime256v1 (ANSI X9.62 named elliptic curve)
                                            [1] (1 elem)
                                                 BIT STRING (520 bit) 0000010000011111101011101111000011010110100010110011000100100111010110...
                                
                                // Octet string from ASN1 dump:
                                0420536D3C28283F768AA24B3B15179B249D5B584A0B7CFF7A226066EFAF2211AF34
                                "MzA3NzAyMDEwMTA0MjA1MzZEM0MyODI4M0Y3NjyMjYwNjZFRkFGMjIxMUFGMzQ="
                                // Bit string from ASN1 dump:
                                034200041FAEF0D68B3127580CC1D87C76AFF372BC804EE8A1810CBEF0919A0A9F3E129B8FB53F57610FD7D51216EC768ABD44A11FF1DBF34CE64C682FE22EA64529237A
                                "MDM0MjAwMDQxRkFFRjBENjhCMzEyNzU4MENDMUQ4N0M3NkFGRjM3MkJDODA0RUU4QTE4MTBDQkVGMDkxOUEwQTlGM0UxMjlCOEZCNTNGNTc2MTBGRDdENTEyMTZFQzc2OEFCRDQ0QTExRkYxREJGMzRDRTY0QzY4MkZFMjJFQTY0NTI5MjM3QQ=="
                                

                                 

                                OpenSSL parse result:

                                $ openssl asn1parse -in private.key
                                    0:d=0  hl=3 l= 147 cons: SEQUENCE  
                                    3:d=1  hl=2 l=   1 prim: INTEGER           :00
                                    6:d=1  hl=2 l=  19 cons: SEQUENCE  
                                    8:d=2  hl=2 l=   7 prim: OBJECT            :id-ecPublicKey
                                   17:d=2  hl=2 l=   8 prim: OBJECT            :prime256v1
                                   27:d=1  hl=2 l= 121 prim: OCTET STRING      [HEX DUMP]:30770201010420536D3C28283F768AA24B3B15179B249D5B584A0B7CFF7A226066EFAF2211AF34A00A06082A8648CE3D030107A144034200041FAEF0D68B3127580CC1D87C76AFF372BC804EE8A1810CBEF0919A0A9F3E129B8FB53F57610FD7D51216EC768ABD44A11FF1DBF34CE64C682FE22EA64529237A
                                
                                // Octet string from OpenSSL parse:
                                30770201010420536D3C28283F768AA24B3B15179B249D5B584A0B7CFF7A226066EFAF2211AF34A00A06082A8648CE3D030107A144034200041FAEF0D68B3127580CC1D87C76AFF372BC804EE8A1810CBEF0919A0A9F3E129B8FB53F57610FD7D51216EC768ABD44A11FF1DBF34CE64C682FE22EA64529237A
                                "MzA3NzAyMDEwMTA0MjA1MzZEM0MyODI4M0Y3NjhBQTI0QjNCMTUxNzlCMjQ5RDVCNTg0QTBCN0NGRjdBMjI2MDY2RUZBRjIyMTFBRjM0QTAwQTA2MDgyQTg2NDhDRTNEMDMwMTA3QTE0NDAzNDIwMDA0MUZBRUYwRDY4QjMxMjc1ODBDQzFEODdDNzZBRkYzNzJCQzgwNEVFOEExODEwQ0JFRjA5MTlBMEE5RjNFMTI5QjhGQjUzRjU3NjEwRkQ3RDUxMjE2RUM3NjhBQkQ0NEExMUZGMURCRjM0Q0U2NEM2ODJGRTIyRUE2NDUyOTIzN0E="
                                
                                

                                 

                                Test method for generating the key:

                                func test(b64: String) {
                                    guard let data = Data(base64Encoded: b64, options: [.ignoreUnknownCharacters]) else {fatalError("Unknown Format")}
                                    var error: Unmanaged<CFError>? = nil
                                    let params = [kSecAttrKeyType: kSecAttrKeyTypeECSECPrimeRandom, kSecAttrKeyClass: kSecAttrKeyClassPrivate] as CFDictionary
                                    if let key = SecKeyCreateWithData(data as CFData, params, &error) {
                                        print("Key", key)
                                    } else if let e = error {
                                        print("Error", e)
                                    }  else {
                                        print("Error")
                                    }
                                }
                                
                                
                                
                                
                                
                                
                                
                                
                                
                                
                                

                                 

                                I've tried your suggestions in the previous posts as well as tried to combine the Octet and the Bit strings with no success yet. `SecKeyCreateWithData` continues to return an `Error -50` in all scenarios. Please let me know if I'm using the right API to handle such keys? Thanks in advance.

                                  • Re: MacOS: EC public key creation from data failed
                                    eskimo Apple Staff Apple Staff (11,805 points)

                                    Reading your post it was unclear as to exactly which data you’re passing to SecKeyCreateWithData.  I think you’re passing the data from line 11 of your third listing to the b64 parameter of the test(b64:) method.  Is that right?

                                    If so, you definitely have an extra level of ASN.1 to deal with.  Consider this:

                                    $ xxd -p tmp.dat 
                                    30770201010420536d3c28283f768aa24b3b15179b249d5b584a0b7cff7a
                                    226066efaf2211af34a00a06082a8648ce3d030107a144034200041faef0
                                    d68b3127580cc1d87c76aff372bc804ee8a1810cbef0919a0a9f3e129b8f
                                    b53f57610fd7d51216ec768abd44a11ff1dbf34ce64c682fe22ea6452923
                                    7a
                                    $ dumpasn1 -p tmp.dat
                                    SEQUENCE {
                                      INTEGER 1
                                      OCTET STRING
                                        53 6D 3C 28 28 3F 76 8A A2 4B 3B 15 17 9B 24 9D
                                        5B 58 4A 0B 7C FF 7A 22 60 66 EF AF 22 11 AF 34
                                      [0] {
                                        OBJECT IDENTIFIER ansiX9p256r1 (1 2 840 10045 3 1 7)
                                        }
                                      [1] {
                                        BIT STRING
                                          04 1F AE F0 D6 8B 31 27 58 0C C1 D8 7C 76 AF F3
                                          72 BC 80 4E E8 A1 81 0C BE F0 91 9A 0A 9F 3E 12
                                          9B 8F B5 3F 57 61 0F D7 D5 12 16 EC 76 8A BD 44
                                          A1 1F F1 DB F3 4C E6 4C 68 2F E2 2E A6 45 29 23
                                          7A
                                        }
                                      }

                                    In situations like this I recommend creating a small test project with hard-wired data and then posting that.  That’ll ensure we’re talking about the same thing.

                                    Share and Enjoy

                                    Quinn “The Eskimo!”
                                    Apple Developer Relations, Developer Technical Support, Core OS/Hardware
                                    let myEmail = "eskimo" + "1" + "@apple.com"

                                      • Re: MacOS: EC public key creation from data failed
                                        new_user Level 1 Level 1 (0 points)

                                        You're right. I'm passing the base 64 string as a value to the argument `b64`. I've tried with the values in L11, L17 and L20. Here is a test project:

                                        func test(b64: String) {
                                          guard let data = Data(base64Encoded: b64, options: [.ignoreUnknownCharacters]) else {fatalError("Unknown Format")}
                                          var error: Unmanaged<CFError>? = nil
                                          let params = [kSecAttrKeyType: kSecAttrKeyTypeECSECPrimeRandom, kSecAttrKeyClass: kSecAttrKeyClassPrivate] as CFDictionary
                                          if let key = SecKeyCreateWithData(data as CFData, params, &error) {
                                              print("Key", key)
                                          } else if let e = error {
                                              print("Error", e)
                                          }  else {
                                              print("Error")
                                          }
                                        }
                                        
                                        // Base 64 strings as found in L11, L17 and L20 in my previous post
                                        let base64FromOctetStringInOpenSslParse = "MzA3NzAyMDEwMTA0MjA1MzZEM0MyODI4M0Y3NjhBQTI0QjNCMTUxNzlCMjQ5RDVCNTg0QTBCN0NGRjdBMjI2MDY2RUZBRjIyMTFBRjM0QTAwQTA2MDgyQTg2NDhDRTNEMDMwMTA3QTE0NDAzNDIwMDA0MUZBRUYwRDY4QjMxMjc1ODBDQzFEODdDNzZBRkYzNzJCQzgwNEVFOEExODEwQ0JFRjA5MTlBMEE5RjNFMTI5QjhGQjUzRjU3NjEwRkQ3RDUxMjE2RUM3NjhBQkQ0NEExMUZGMURCRjM0Q0U2NEM2ODJGRTIyRUE2NDUyOTIzN0E="
                                        let base64FromBitStringInAsn1Dump = "MDM0MjAwMDQxRkFFRjBENjhCMzEyNzU4MENDMUQ4N0M3NkFGRjM3MkJDODA0RUU4QTE4MTBDQkVGMDkxOUEwQTlGM0UxMjlCOEZCNTNGNTc2MTBGRDdENTEyMTZFQzc2OEFCRDQ0QTExRkYxREJGMzRDRTY0QzY4MkZFMjJFQTY0NTI5MjM3QQ=="
                                        let base64FromOctetStringInAsn1Dump = "MDQyMDUzNkQzQzI4MjgzRjc2OEFBMjRCM0IxNTE3OUIyNDlENUI1ODRBMEI3Q0ZGN0EyMjYwNjZFRkFGMjIxMUFGMzQ="
                                        let base64FromMergedOctetAndBitStringsInAsn1Dump = "MDQyMDUzNkQzQzI4MjgzRjc2OEFBMjRCM0IxNTE3OUIyNDlENUI1ODRBMEI3Q0ZGN0EyMjYwNjZFRkFGMjIxMUFGMzQwMzQyMDAwNDFGQUVGMEQ2OEIzMTI3NTgwQ0MxRDg3Qzc2QUZGMzcyQkM4MDRFRThBMTgxMENCRUYwOTE5QTBBOUYzRTEyOUI4RkI1M0Y1NzYxMEZEN0Q1MTIxNkVDNzY4QUJENDRBMTFGRjFEQkYzNENFNjRDNjgyRkUyMkVBNjQ1MjkyMzdB"
                                        
                                        // Test the base 64 strings
                                        test(b64: base64FromOctetStringInOpenSslParse)
                                        test(b64: base64FromBitStringInAsn1Dump)
                                        test(b64: base64FromOctetStringInAsn1Dump)
                                        test(b64: base64FromMergedOctetAndBitStringsInAsn1Dump)
                                        
                                        
                                        
                                        
                                        

                                         

                                        Error message:

                                        Error Unmanaged<CFError>(_value: Error Domain=NSOSStatusErrorDomain Code=-50 "EC public key creation from data failed" (paramErr: error in user parameter list) UserInfo={NSDescription=EC public key creation from data failed})
                                        
                                        
                                          • Re: MacOS: EC public key creation from data failed
                                            eskimo Apple Staff Apple Staff (11,805 points)

                                            Thanks for the focused test example.  The problem here is that your input data is for a public key and you’re trying to import it as a private key.

                                            Consider the bit string from the ASN.1 dump from my previous post:

                                            $ xxd -p tmp.dat
                                            041faef0d68b3127580cc1d87c76aff372bc804ee8a1810cbef0919a0a9f
                                            3e129b8fb53f57610fd7d51216ec768abd44a11ff1dbf34ce64c682fe22e
                                            a64529237a

                                            If you convert it to Base64 you get this:

                                            $ base64 tmp.dat 
                                            BB+u8NaLMSdYDMHYfHav83K8gE7ooYEMvvCRmgqfPhKbj7U/V2EP19USFux2ir1EoR/x2/NM5kxoL+IupkUpI3o=

                                            I plugged that into your test snippet and change it to import a public key (kSecAttrKeyClassPublic), like so:

                                            import Foundation
                                            
                                            func test(b64: String) {
                                              guard let data = Data(base64Encoded: b64, options: [.ignoreUnknownCharacters]) else {fatalError("Unknown Format")}
                                              var error: Unmanaged<CFError>? = nil
                                              let params = [kSecAttrKeyType: kSecAttrKeyTypeECSECPrimeRandom, kSecAttrKeyClass: kSecAttrKeyClassPublic] as CFDictionary
                                              if let key = SecKeyCreateWithData(data as CFData, params, &error) {
                                                  print("Key", key)
                                              } else if let e = error {
                                                  print("Error", e)
                                              }  else {
                                                  print("Error")
                                              }
                                            }
                                            
                                            test(b64: "BB+u8NaLMSdYDMHYfHav83K8gE7ooYEMvvCRmgqfPhKbj7U/V2EP19USFux2ir1EoR/x2/NM5kxoL+IupkUpI3o=")

                                            It successfully imports the key, printing:

                                            Key <SecKeyRef curve type: kSecECCurveSecp256r1, algorithm id: 3, key type: ECPublicKey, version: 4, block size: 256 bits, y: 8FB53F57610FD7D51216EC768ABD44A11FF1DBF34CE64C682FE22EA64529237A, x: 1FAEF0D68B3127580CC1D87C76AFF372BC804EE8A1810CBEF0919A0A9F3E129B, addr: 0x101b5d4f0>

                                            To further explore this I wrote a tiny test project to generate a new, random EC p256r1 key pair and then dumped the private and public key bytes:

                                            let privateKey = SecKeyCreateRandomKey([
                                                kSecAttrKeyType: kSecAttrKeyTypeECSECPrimeRandom,
                                                kSecAttrKeySizeInBits: 256
                                            ] as NSDictionary, nil)!
                                            
                                            let publicKey = SecKeyCopyPublicKey(privateKey)!
                                            
                                            let privateData = SecKeyCopyExternalRepresentation(privateKey, nil)! as Data
                                            let publicData = SecKeyCopyExternalRepresentation(publicKey, nil)! as Data
                                            print("private: ", privateData as NSData)
                                            print("public: ", publicData as NSData)

                                            Here’s an example of its output:

                                            private:  <04a21f94 07831a37 d9ba294c 2b9c16db 599496de 8a44e909 fd8b6fba f947ed51 c775152f 806af756 9409f18e 87261847 54d19e9a 63ccfd49 af2f7c1f 642da582 84c682d0 e2ac6c42 dcac9417 b31cdccc 2962926d fe088ff3 1dfc3c60 e19c02fb b9>
                                            public:  <04a21f94 07831a37 d9ba294c 2b9c16db 599496de 8a44e909 fd8b6fba f947ed51 c775152f 806af756 9409f18e 87261847 54d19e9a 63ccfd49 af2f7c1f 642da582 84>

                                            Note how the public key is 65 bytes long, a length that matches the key in your example, but the private key is longer (97 bytes).

                                            I’m not sure why your PEM is labelled as a private key; you’ll need to have a chat with whoever generated it.

                                            Share and Enjoy

                                            Quinn “The Eskimo!”
                                            Apple Developer Relations, Developer Technical Support, Core OS/Hardware
                                            let myEmail = "eskimo" + "1" + "@apple.com"

                              • Re: MacOS: EC public key creation from data failed
                                EliBEast37 Level 1 Level 1 (0 points)

                                Thanks Quinn. I finally got this working with secp384r1 public keys but I hit pitfalls along the way so I've got tips for other folks.

                                 

                                SecKeyCreateWithData does work with different EC curves. It doesn't use the OID (which we strip out) but instead detects the curve from the key's parameters.

                                 

                                SecKeyCreateWithData appears to completely ignore the kSecAttrKeySizeInBits attribute.

                                 

                                If SecKeyCreateWithData fails, start by looking at the public key using dumpasn1. (get yourself a copy with brew: https://github.com/philpennock/homebrew-protocols ) Make sure you are using a public key not a private key.

                                After you extract the bit string, compare the output of hexdump with dumpasn1 to ensure you have the correct bytes.

                                FWIW, on all of the keys I looked, the important bytes started at offset 23 (hard coded as skip=23 in my script below)

                                 

                                Here's a script covering all the steps to generate a key pair, extract the public, extract the bit string, and base64 encode it. If you already have a public key, skip the first two steps.

                                 

                                #!/bin/sh
                                # generate secp384r1 keypair, export public
                                openssl ecparam -name secp384r1 -genkey -noout -out keypair.pem
                                openssl ec -in keypair.pem -pubout -out pubkey.pem
                                
                                # strip PEM header/footer, decode to DER
                                tail -n +2 pubkey.pem  | sed  -e '$ d' > pubkey.b64
                                base64 -D -i pubkey.b64 -o pubkey.der
                                
                                # extract bitstring and re-encode to base64
                                dd skip=23 if=pubkey.der of=barekey.der bs=1
                                base64 barekey.der -o barekey.b64
                                
                                # you can compare the output of these to verify the BIT STRING is correct
                                #dumpasn1 pubkey.der
                                #hexdump -Cv barekey.der
                                echo "embed this in your code"
                                cat barekey.b64

                                 

                                 

                                Your pubkey.pem should look like:

                                 

                                -----BEGIN PUBLIC KEY-----
                                MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEAs5xEIm001FFsRpXSRFEy57+swcr3nW9
                                SP3ERlrT539LE/x2auTwUVTCkaFS6R5IBl2QIvEml+UXgBU0sDK3PqZsqHcQzvBz
                                Z/lX7NehqphbVCQBr3nkhDwyq0tkrmyD
                                -----END PUBLIC KEY-----

                                 

                                 

                                And the final output will look like:

                                BALOcRCJtNNRRbEaV0kRRMue/rMHK951vUj9xEZa0+d/SxP8dmrk8FFUwpGhUukeSAZdkCLxJpflF4AVNLAytz6mbKh3EM7wc2f5V+zXoaqYW1QkAa955IQ8MqtLZK5sgw==

                                 

                                Code to parse the sample key produced by the script above.

                                 

                                let base64PubKey = """
                                BALOcRCJtNNRRbEaV0kRRMue/rMHK951vUj9xEZa0+d/SxP8dmrk8FFUwpGhUukeSAZdkCLxJpflF4AVNLAytz6mbKh3EM7wc2f5V+zXoaqYW1QkAa955IQ8MqtLZK5sgw==
                                """
                                let pubKeyData = Data(base64Encoded: base64PubKey)!
                                var error: Unmanaged? = nil
                                let attributes = [kSecAttrKeyType: kSecAttrKeyTypeECSECPrimeRandom,
                                                kSecAttrKeyClass: kSecAttrKeyClassPublic] as NSDictionary
                                
                                if let pubKey = SecKeyCreateWithData(pubKeyData as NSData, attributes, &error) {
                                    print("pubKey = \(pubKey)")
                                } else {
                                    print("Failed to import public key: \(String(describing: error))")
                                }

                                 

                                Produces the output:

                                pubKey = < SecKeyRef curve type: kSecECCurveSecp384r1, 
                                algorithm id: 3, key type: ECPublicKey, version: 4, block size: 384 bits, 
                                y: 065D9022F12697E517801534B032B73EA66CA87710CEF07367F957ECD7A1AA985B542401AF79E4843C32AB4B64AE6C83, 
                                x: 02CE711089B4D35145B11A57491144CB9EFEB3072BDE75BD48FDC4465AD3E77F4B13FC766AE4F05154C291A152E91E48, 
                                addr: 0x7fd6cf112ff0>
                              • Re: MacOS: EC public key creation from data failed
                                Craz1k0ek Level 1 Level 1 (10 points)

                                To answer your question shortly, SecKeyCreateWithData expects DER formatted data, not PEM (DER is pretty much the PEM without the headers). Also note that at least kSecAttrKeyType, kSecAttrKeyClass and kSecAttrKeySizeInBits must be defined in the attributes. You are correct that the size attribute doesn’t matter (for now) as I have experienced that too, but it’s still required in the recreation attributes. Hope this helps! Craz1k0ek