OpenSSL RSA in Swift. Get a public key into a String

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

Accepted Reply

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"

Replies

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"

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

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"

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?

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"

YEs. Thanks a lot. Made me happy for a couple of days) Wish you that too..