4

I encountered an issue with creating SecKey from NSData. Basically my client-server communication is based on signature created with private key and verified on the server with public key.

I am implementing session transfer between two devices and in order to continue communication I need those keys to be transferred as well. I am converting SecKey to NSData and sending it via bluetooth, but on other side I cannot convert NSData to SecKey back to use encryption.

Could you help please?

Oleg Novosad
  • 2,261
  • 1
  • 27
  • 28

3 Answers3

7

More complete example (swift 4, iOS 10+) - assuming you have a Base64 encoded string. Note that the other side of the connection needs to also be creating key payloads using the same format (i.e. RSA - PKCS #1, also verify key size ). This function handles public or private keys (security caveats omitted for brevity).

// Extract secKey from encoded string - defaults to extracting public keys
func decodeSecKeyFromBase64(encodedKey: String, isPrivate: Bool = false) -> SecKey? {
    var keyClass = kSecAttrKeyClassPublic
    if isPrivate {
        keyClass = kSecAttrKeyClassPrivate
    }
    let attributes: [String:Any] =
    [
        kSecAttrKeyClass as String: keyClass,
        kSecAttrKeyType as String: kSecAttrKeyTypeRSA,
        kSecAttrKeySizeInBits as String: 2048,
    ]

    guard let secKeyData = Data.init(base64Encoded: encodedKey) else {
        print("Error: invalid encodedKey, cannot extract data")
        return nil
    }
    guard let secKey = SecKeyCreateWithData(secKeyData as CFData, attributes as CFDictionary, nil) else {
        print("Error: Problem in SecKeyCreateWithData()")
        return nil
    }

    return secKey
}
John Robi
  • 345
  • 2
  • 8
4

Starting from iOS 10 you can use the following code:

let attributes: [String:Any] = [
            kSecAttrKeyClass as String: kSecAttrKeyClassPublic,
            kSecAttrKeyType as String: kSecAttrKeyTypeRSA,
            kSecAttrKeySizeInBits as String: blockSize,
            ]
secKey = SecKeyCreateWithData(secKeyData as CFData, attributes as CFDictionary, nil)
Mahmoud Adam
  • 5,772
  • 5
  • 41
  • 62
1

what I use with success ...

func obtainKeyData(tag: String) -> NSData? {
    var keyRef: AnyObject?
    let query: Dictionary<String, AnyObject> = [
        String(kSecAttrKeyType): kSecAttrKeyTypeRSA,
        String(kSecReturnData): kCFBooleanTrue as CFBoolean,
        String(kSecClass): kSecClassKey as CFStringRef,
        String(kSecAttrApplicationTag): tag as CFStringRef,
        ]

    let result: NSData?

    switch SecItemCopyMatching(query, &keyRef) {
    case noErr:
        result = keyRef as? NSData
    default:
        result = nil
    }

    return result
}

func insertPublicKey(publicTag: String, data: NSData) -> SecKeyRef? {
    let query: Dictionary<String, AnyObject> = [
        String(kSecAttrKeyType): kSecAttrKeyTypeRSA,
        String(kSecClass): kSecClassKey as CFStringRef,
        String(kSecAttrApplicationTag): publicTag as CFStringRef,
        String(kSecValueData): data as CFDataRef,
        String(kSecReturnPersistentRef): true as CFBooleanRef]

    var persistentRef: AnyObject?
    let status = SecItemAdd(query, &persistentRef)

    if status != noErr && status != errSecDuplicateItem {
        return nil
    }

    return obtainKey(publicTag)
}
func obtainKey(tag: String) -> SecKey? {
    var keyRef: AnyObject?
    let query: Dictionary<String, AnyObject> = [
        String(kSecAttrKeyType): kSecAttrKeyTypeRSA,
        String(kSecReturnRef): kCFBooleanTrue as CFBoolean,
        String(kSecClass): kSecClassKey as CFStringRef,
        String(kSecAttrApplicationTag): tag as CFStringRef,
        ]

    let status = SecItemCopyMatching(query, &keyRef)

    switch status {
    case noErr:
        if let ref = keyRef {
            return (ref as! SecKeyRef)
        }
    default:
        break
    }

    return nil
}

There is no easy way to transfer private part of the key pair( it is possible, but try to avoid it )

user3441734
  • 16,722
  • 2
  • 40
  • 59
  • Yes, I also have this part of code, but the problem here is that it is strictly bound to tag, which might be auto-generated. – Oleg Novosad Jun 29 '16 at 12:31
  • can I do the same with tag for private key? Or I need to do it in a different way? – Oleg Novosad Jun 29 '16 at 13:43
  • No, with the private key this is unusable. The reason is, that private key should be private, so generally not easily transferable to other devices. Try first to change your program flow. – user3441734 Jun 29 '16 at 14:15
  • @Array .. to be more specific, SecItemAdd will fail with private key ... (iOS) – user3441734 Jun 29 '16 at 14:27