6 Replies
      Latest reply: Feb 16, 2017 1:43 PM by Zorjan RSS
      Zorjan Level 1 Level 1 (0 points)

        How to get a public key in any way(preferred in String) from OpenSSL library on Swift3?

          let rsaKeyPair = RSA_new()

        //KeyPair

        RSA_generate_key_ex(rsaKeyPair, 2048, 13, nil)

        What i found is

          var rc = i2d_RSAPublicKey(rsaKeyPair, &p)

        (it is in libcripto.a, but not in headers) ...autocomplete shows as

          var a1= i2d_RSAPublicKey(a: UnsafePointer<RSA>!, out: UnsafeMutablePointer<UnsafeMutablePointer<UInt8>?>!)

        Have no idea how to get it. In my dirty way in

          let cT = String(cString: p!)

        print(cT)

        it shows definitely not a key

        • Re: OpenSSL RSA in Swift. Get a public key into a String
          eskimo Apple Staff Apple Staff (6,480 points)

          Calling complex C APIs is possible from Swift, but it’s not a lot of fun.  Honestly I think you’d be better off writing this code in Objective-C and then calling that Objective-C code from Swift.  Objective-C is nice for this job because it interfaces well with both low-level C APIs and Swift.

          If you decide you have to do this solely in Swift, I still recommend that you write a prototype in C.  That way you’ll be able to take advantage of the various OpenSSL support resources out there on the ’net.  Once you’ve got that C prototype working, you can then look at how to port that to Swift.

          The problem with going directly from Swift to OpenSSL is that the set of people who have expertise in both of those environments is pretty darned small )-:  For example, I can help you with Swift issues, and especially with Swift issues calling C APIs, but I can’t help you with OpenSSL API issues because I don’t know that API at all.

          Oh, and why are you doing this using OpenSSL anyway?  Don’t get me wrong, there are good reasons to use OpenSSL, but what you’re doing here (creating an RSA key pair and exporting the public key as PEM) is quite possible using the not-really-Swift-friendly-but-still-a-lot-more-Swift-friendly-than-OpenSSL Security framework.

          Share and Enjoy

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

            • Re: OpenSSL RSA in Swift. Get a public key into a String
              Zorjan Level 1 Level 1 (0 points)

              Does exist any example on Swift 3 with basic RSA Security Framework operations(macosx)?

                • Re: OpenSSL RSA in Swift. Get a public key into a String
                  eskimo Apple Staff Apple Staff (6,480 points)

                  There’s no official Apple samples that meets these criteria.  The standard sample I point folks to is iCryptoCompatibility, but that’s in Objective-C.  OTOH, the core code would be relatively simple to port to Swift, or you could just add the NSOperation subclasses to your project and then call them from Swift via bridging.

                  Share and Enjoy

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

                • Re: OpenSSL RSA in Swift. Get a public key into a String
                  Zorjan Level 1 Level 1 (0 points)

                  I did "c" working sample as you recommended.

                   

                  Have some difficulties to port in swift 3

                   

                   

                          var bio = BIO_new(BIO_s_mem());
                          var ret = PEM_write_bio_RSAPublicKey(bio, rsaKeyPair);
                  
                          var keylen = BIO_ctrl(bio,BIO_CTRL_PENDING,0,nil)// BIO_pending(bio);
                        
                          var pem_key = calloc(keylen+1, 1); / Null-terminate */
                          BIO_read(bio, pem_key, Int32(keylen));
                          let cT1 = String(cString: pem_key), 
                          print(cT1)//printf("%s", pem_key);
                  
                  
                  
                  
                  
                  

                   

                  to port nulled-string pem-key into String(Line 8).

                  The error is: Cannot invoke initializer for type 'String' with an argument list of type '(cString: UnsafeMutableRawPointer?)'. Overloads for 'String' exist with these partially matching parameter lists: (cString: UnsafePointer<CChar>), (cString: UnsafePointer<UInt8>).

                   

                  How to get String from pem_key at line 8?

                    • Re: OpenSSL RSA in Swift. Get a public key into a String
                      eskimo Apple Staff Apple Staff (6,480 points)

                      Swift 3 does not, in general, allow you to convert pointers of one type to pointers of a different type.  The rules of the road here are outlined in SE-0107 UnsafeRawPointer API, which puts Swift’s type aliasing rules on a firm footing.  I strongly recommend you read the UnsafeRawPointer Migration doc before going further.

                      In this case, calloc returns a raw pointer, that is, a pointer to memory whose type isn’t specified.  String(cString:), OTOH, expects a C string pointer, that is, a pointer to a CChar, and you can’t just freely cast between the two.  You can convert a raw pointer to a typed pointer, but you have to be careful when you do so because it can be very easy to run into aliasing problems.  Here’s an example of code that actually compiles.

                      let cT1 = String(cString: pem_key!.assumingMemoryBound(to: CChar.self))
                      

                      However, there are better options.  My preferred option in situations like this is to allocate the memory with the right type in Swift and then pass its address to the underlying read function.  For example.

                      var buffer = [CChar](repeating: 0, count: keylen)
                      BIO_read(bio, &buffer, Int32(buffer.count))
                      let cT1 = String(cString: buffer)
                      

                      Finally, I have to stress that, if you’re working with a low-level C API like OpenSSL, you’re really going to need to understanding Swift’s pointer rules, as discussed in the docs I referenced above.

                      Share and Enjoy

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