henrinormak / Heimdall

Heimdall is a wrapper around the Security framework for simple encryption/decryption operations.
MIT License
401 stars 68 forks source link

Heimdall fails to decrypt it's own data after upgrading to Xcode 11/iOS 13 SDK #81

Open patgoley opened 4 years ago

patgoley commented 4 years ago

The problem is simple but I'm having trouble reproducing it in a standalone project so I'm wondering if you have any ideas off the top of your head. I have a project that was previously building with Xcode 10.1 and used Heimdall to encrypt and decrypt data. After upgrading to Xcode 11, encryption still works but decryption does not. Or perhaps encryption reports a success but actually generates malformed data.

Here is what I'm doing in my app. I have no idea why this works fine in a minimal example project but fails in my app. Maybe you've encountered similar when building with Xcode 11? Thanks in advance!

let hd = Heimdall(publicTag: "pubTag", privateTag: "privTag")!
let encrypted = hd.encrypt("hello")!
let decrypted = hd.decrypt(encrypted)! // crash - decrypted string is nil

Just to provide some more info. The input String is 5 bytes, but the Data returned from the internal call to self.decrypt is 16 bytes for some reason, and not a valid UTF-8 String which is why the method ultimately returns nil.

patgoley commented 4 years ago

I'm not sure if this repository is actively maintained, but I'm going to leave some findings here in case anyone else has this issue.

I was able to get decryption working again by copying Heimdall.swift into my project and removing the Cocoapod. I don't know off the top of my head why this would fix the issue, unless there were some changes in Swift 5 regarding cross-module compilation or optimizations. However, the pod works fine in a new project created with Xcode 11. Perhaps there are particular compiler flags or other maybe type extensions in my project that cause it to work incorrectly.

Thanks and happy coding :)

henrinormak commented 4 years ago

Sorry, indeed, I unfortunately don't have much time these days to work on Heimdall.

Do I understand correctly that it does actually work, but for some reason not "out-of-the-box" with Cocoapods? One item that would be a nice addition to Heimdall (a PR is very welcome) would be the addition of it to SPM, perhaps that would alleviate these problems?

patgoley commented 4 years ago

To clarify:

  1. After upgrading to Xcode 11/iOS 13 SDK, the Heimdall pod in my project stopped working as described above.
  2. Creating a blank new project using the Heimdall pod worked fine (so nothing wrong with the pod itself, it seems)
  3. Copying Heimdall.swift from the pod into my main project file and removing the pod fixed my original issue.

I have no idea what could cause this kind of bug or how moving the file between modules fixed it.

patgoley commented 4 years ago

Just to provide an update here, I was able to get the Heimdall pod working in my project by setting Swift compiler code generation "Optimization level" setting to -Onone in the pod target.

It seems that pod targets default to "Optimize for speed" setting for the Swift code gen setting (debug and release builds). My main project target has -Onone for debug builds which is why moving Heimdall.swift there fixed the issue. The issue cropped back up in my next TestFlight build as my main target uses "Optimize for speed" in release builds.

Here is how I'm overriding those settings in my Podfile:

post_install do |installer|
      installer.pods_project.targets.each do |target|
          if target.name == 'Heimdall'
              target.build_configurations.each do |config|
                  # Heimdall does not work properly with the "Optimize for speed"
                  # optimization setting. Until that's fixed, resort to no optimizations
                  # for all builds, debug and release
                  config.build_settings['SWIFT_OPTIMIZATION_LEVEL'] = '-Onone'
              end
          end
      end
  end

Of course, I don't think optimization levels should ever change the semantics of the resulting program, so this could be a bug in the Swift compiler, possibly exacerbated by Heimdall's usage of raw memory and pointers.

As a second note, it seems that the real issue is the String encoding, not in the encryption or decryption process. The data successfully decrypts, but the resulting data is not a valid UTF-8 string.