Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

obtainingKey, SecKeyRef is nil #24

Closed
goksucapar opened this issue Sep 28, 2015 · 16 comments
Closed

obtainingKey, SecKeyRef is nil #24

goksucapar opened this issue Sep 28, 2015 · 16 comments
Labels

Comments

@goksucapar
Copy link

While obtaining key before encyption,

let status = SecItemCopyMatching(query, &keyRef)
status is 0 but keyRef is nil only on iOS9. it works well on iOS8.

Could you help ?

Thanks

@henrinormak
Copy link
Owner

Hi,

I need more context than that, are you sure the device testing on iOS 9 has the key (private key for example may only exist on one device)? If this is an extract from Heimdall, then which one is it, there are several places (and ways) that the line shown could be called.

@goksucapar
Copy link
Author

Actually I'm testing on both physical devices and simulators. (on ios8 & ios9). We're making RSA encryption. I'm getting exponent and modulus from the server for public key. And I'm using init that contains exponent modulus and publicTag. It works on all devices on iOS8 but not on ios9

@goksucapar
Copy link
Author

private class func obtainKey(tag: String) -> SecKeyRef?  {
   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
}

this is the part that getting error. Status equals noErr but keyRef is nil.

@henrinormak
Copy link
Owner

How are you storing the modulus and exponent? Could you put together a small example application that demonstrates the problem?

@goksucapar
Copy link
Author

Hi,

I'm storing modulus and exponent to KeyChain as String first, then read as String again, then that's what I did only.

    let modulusData = NSData(base64EncodedString: modulusStr, options:NSDataBase64DecodingOptions())

    let exponentData = NSData(base64EncodedString: exponentStr, options: NSDataBase64DecodingOptions())

    var param = ""

    if let localHeimdall = Heimdall(publicTag: "TestPT", publicKeyModulus: modulusData!, publicKeyExponent: exponentData!) {

        let message = "TestMessage"
        let encMessage = localHeimdall.encrypt(message)

        param = encMessage!
    }

modulusStr & exponentStr are the values that read from the keyChain.

@henrinormak
Copy link
Owner

And at which point do you detect the nil? I assume initialisation works and the problem surfaces when you are trying to use encrypt()?

@goksucapar
Copy link
Author

if let publicKey = obtainKey(.Public) goes to this function

private class func obtainKey(tag: String) -> SecKeyRef? {

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
}

at the this line let status = SecItemCopyMatching(query, &keyRef), status == noErr but keyRef is nil

@rhavekost
Copy link

I'm having exactly the same issue on iOS9 (in both simulator and actual device). Everything worked correctly in iOS8, but in iOS9 in the obtainKey method, keyRef is always nil.

@rhavekost
Copy link

I think I may have figured out the problem. I was generating a modulus and exponent on the server, and sending that to the device. However, the modulus was only 256 bytes - (not signed). After inspecting the Heimdall tests, I realized that the modulus in the test was 257 bytes - with a leading zero. Once I prepended this leading zero to the modulus on the server, everything started working again. I'm guessing that iOS9 is just pickier about encoding on encryption keys?

@goksucapar
Copy link
Author

Hi,

I'm using 128 bytes modulus. Leading zero makes no sense i think. I'm stuck. Maybe there is a problem while insertingPublicKey ?

@rhavekost
Copy link

It seems like other people are having similar issues:
StCredZero/SCZ-BasicEncodingRules-iOS#6

@henrinormak
Copy link
Owner

Could one of you guys give an example modulus/exponent that you can reproduce this with? I think I can fix this, but I do need to have some test data (to verify + write a new test case, so please make sure that these are not production values).

@goksucapar
Copy link
Author

Hi,
Test values from server.

Modulus: 3JvrTKthRgmLnmugBwN3z3MCh9WiDIv+GX0rm181taXimmz/ZKP8kfuaZL4eLnqCejCM8CEKhX+2tJRpIrht360Sx7gBii5TUibumfMxTEZb/+1aGZCA/a/JjZUOrvGABDYqqn5FdZ7RFgrUtQsnpM7is0UXtV86omPw9Fh8HwU=

Exponent:
AQAB

@henrinormak
Copy link
Owner

Could you verify with 0.2.1 (06196d3) that this is fixed. The example modulus you gave seemed to work.

@goksucapar
Copy link
Author

Thanks Henri it solved. Before I'm closing let me ask one more thing. I've changed the encryption like below.

  public func encrypt(data: NSData) -> NSData? {

 if let publicKey = obtainKey(.Public) {
        // Determine appropriate AES key size
        let blockSize = SecKeyGetBlockSize(publicKey)
        let keySize: Int
        if blockSize >= 256 {
            keySize = Int(kCCKeySizeAES256)
        } else if blockSize >= 192 {
            keySize = Int(kCCKeySizeAES192)
        } else {
            keySize = Int(kCCKeySizeAES128)
        }

       // if let aesKey = Heimdall.generateSymmetricKey(keySize), encrypted = Heimdall.encrypt(data, key: aesKey, algorithm: CCAlgorithm(kCCAlgorithmAES128)) {
           I'm not using aesKey!!!!!!

            // Final resulting data
            let result = NSMutableData()

            // Encrypt the AES key with our public key
            var encryptedData = [UInt8](count: Int(blockSize), repeatedValue: 0)
            var encryptedLength = blockSize
            let dataByte = UnsafePointer<UInt8>(data.bytes) //changed here!!!! 

            switch SecKeyEncrypt(publicKey, .PKCS1, dataByte, Int(data.length), &encryptedData, &encryptedLength) {
            case noErr:
                result.appendBytes(&encryptedData, length: encryptedLength)
            default:
                return nil
            }

            // result.appendData(encrypted)  // and not appending here to make size correct.!!!!!

            return result
        //}
    }

    return nil
}

Is it correct ? It's working. Is this cause any security problems?

Thanks.

@henrinormak
Copy link
Owner

This is a separate topic (the fact that you are only trying to do RSA encryption versus what Heimdall actually does), please read the README and create a separate issue. Closing this for now.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

3 participants