How to encode SecKey to base64 string using swift
To convert a string to its base64 representation, you need to take a trip through Data
.
let s = "string to encode as base64"
let d = s.data(using: .utf8)
let b64 = base64EncodedString()
Swift 3 export SecKey to String
Export Key (iOS 10 only)
var error:Unmanaged<CFError>?
if let cfdata = SecKeyCopyExternalRepresentation(publicKey!, &error) {
let data:Data = cfdata as Data
let b64Key = data.base64EncodedString()
}
See https://stackoverflow.com/a/30662270/5276890 and https://stackoverflow.com/a/27935528/5276890 for longer ways which probably support iOS < 10.
Reimport Key
guard let data2 = Data.init(base64Encoded: b64Key) else {
return
}
let keyDict:[NSObject:NSObject] = [
kSecAttrKeyType: kSecAttrKeyTypeRSA,
kSecAttrKeyClass: kSecAttrKeyClassPublic,
kSecAttrKeySizeInBits: NSNumber(value: 512),
kSecReturnPersistentRef: true as NSObject
]
guard let publicKey = SecKeyCreateWithData(data2 as CFData, keyDict as CFDictionary, nil) else {
return
}
Note: This generates a base64 key and not a certificate. A lot of code samples online deal with how to generate a public key from a certificate using SecCertificateCreateWithData
Also: 512 bit is fast to generate but worthless. Pick a longer and secure value once you're satisfied with the results.
I got valid results back when importing the key I generated and exported, so I assume it works, but I did not try to encrypt and decrypt with it.
How do I export a public key SecKey that was generated using SecKeyGeneratePair to be used on a server?
SecItemCopyMatching
is for you:
var dataPtr:Unmanaged<AnyObject>?
let query: [String:AnyObject] = [
kSecClass: kSecClassKey,
kSecAttrApplicationTag: "com.example.site.public",
kSecReturnData: kCFBooleanTrue
]
let qResult = SecItemCopyMatching(query, &dataPtr)
// error handling with `qResult` ...
let publicKeyData = dataPtr!.takeRetainedValue() as NSData
// convert to Base64 string
let base64PublicKey = publicKeyData.base64EncodedStringWithOptions(nil)
Swift 4:
var dataPtr:CFTypeRef?
let query: [String: Any] = [
kSecClass as String: kSecClassKey,
kSecAttrApplicationTag as String: "com.example.site.public",
kSecReturnData as String: true
]
let qResult = SecItemCopyMatching(query as CFDictionary, &dataPtr)
// error handling with `qResult` ...
let data = dataPtr as! Data
let base64PublicKey = data.base64EncodedString()
Note that the size of the data is 270, not the same as block size of the key. See this question on the crypto.stackexchange.com.
Getting a string representation of a SecKey
The normal way to encode a binary blob, like a certificate or RSA key as a string is to use base64 encoding. You can convert a Data
to base64 quite easily with the function base64EncodedString(options:)
. i.e.
let myString = myData.base64EncodedString()
whether that is exactly what you need for this application is hard to tell because your question doesn't give much context.
Looking at your screen shot, as well as the base64 encoded string, you need a header and footer. Most of the apparently random letters in the data structure are the base64 string (the JSON conversion has encoded the line feeds with \n
and something else has doubled up the backslashes). Your last step is therefore to prepend the string with -----BEGIN PUBLIC KEY-----
and a new line, ad append a new line and -----END PUBLIC KEY-----
One more thing: you can get the original data back from the base64 string quite easily with Data.init?((base64Encoded base64String:,options:). i.e.
guard let myDataCopy = Data(base64Encoded: myString)
else { fatalError("the string was not really base64") }
Seckey from public key string from server in Swift
For mac:
let pubKey = "-----BEGIN PUBLIC KEY-----MIICIjANBgAgK.......InbFk1FkucQqruMyUCAwEAAQ==-----END PUBLIC KEY-----"
let pubKeyData = pubKey.dataUsingEncoding(NSASCIIStringEncoding)
var error: Unmanaged<CFErrorRef>?
let secKey = SecKeyCreateFromData(NSDictionary(), pubKeyData!, &error)
Where pubKey is a string representation of your public key.
If you don't know your public key, you can infer it from your private key with the following command:
openssl rsa -in server.key -pubout > mykey.pub
Where server.key is the file containing -----BEGIN RSA PRIVATE KEY-----
as the first line.
For iOS:
It's a bit more complicate.
You need a der
file. It's a binary representation of your certificate.
If you need to convert an existing certificate, you can do so with the following command:
openssl x509 -outform der -in file.crt|pem -out mycert.der
The .crt
or .pem
file contains -----BEGIN CERTIFICATE-----
as the first line.
Put the der
file in your bundle and do:
let certificateData = NSData(contentsOfURL:NSBundle.mainBundle().URLForResource("mycert", withExtension: "der")!)
let certificate = SecCertificateCreateWithData(nil, certificateData!)
var trust: SecTrustRef?
let policy = SecPolicyCreateBasicX509()
let status = SecTrustCreateWithCertificates(certificate!, policy, &trust)
if status == errSecSuccess {
let key = SecTrustCopyPublicKey(trust!)!;
}
Yatta ! Key now contains a SecKey
representation of your public key. Happy Pinning.
Related Topics
Swift Access to Variable Length Array
Swiftui: Is There Exist Modifier to Highlight Substring of Text() View
How to Draw a Cosine or Sine Curve in Swift
What Makes a Property a Computed Property in Swift
Cannot Convert Value of Type '()' to Specified Type Bool
How to Transfer the User's Score to Another Scene in Swift and Spritekit
Default Optional Parameter in Swift Function
Swift Convert Time to Time Ago
How to Dismiss a Uisearchcontroller? (iOS 8 and Follow)
Why Swift Closure Not Capture Self
What Is the Use of the Validate() Method in Alamofire.Request
How to Implement iOServicematchingcallback in Swift
How to Call the More Specific Method of Overloading
How to Subclass Nsoperation in Swift to Queue Skaction Objects for Serial Execution
How to Check If a Property Has Been Set Using Swift Reflection