Download integrity check

I have a small text file I need to download, and I want to add an integrity check to the process. I have reason to believe that a malicious third-party app running on the same machine may try to intercept the network packets and substitute a different file, and I need to be able to prevent that.

A hash won’t work, because the hash would also need to be downloaded, and the malicious app could then simply substitute a fake hash as well. Encryption also wouldn’t work, because the decryption key would need to be stored in the app, where the hackers behind the malicious app could find it.

Ideally, I’d like some kind of lightweight public/private key signing scheme. Is it possible to sign a file with my Developer ID and verify the signature on the user’s machine, without having to rely on the codesign tool to be installed on the user end? Any other ideas?

Thanks in advance!

The Crypto would likely be your best choice. You generate a key pair, then produce a signature using the private key (which you keep private) and verify the signature using the public key stored in your app. This method is foolproof with one exception. If a third-party app modifies your app, it is possible to replace the public key stored in your app, so it will trust a different private key instead of yours. This is an unavoidable risk though, since once the app is on the computer, there is no way to defend it. It’ll be signed though, and modifying the public key will break the signature, so there is that defense, but it’s not perfect.

Still, I think the signature is your best bet. Nothing is perfect of course, but this will be very good.

The only advice I can offer is what I’ve recently done in producing a ‘secure’ update system for one of my apps.

It downloads a data file (which is mainly text). The contents are signed before writing to the file, so once the contents are extracted the signature is validated.

The data file also contains a hash of the update file, so upon download the ‘update’ file hash is compared with the data file.

Last line of defense, we’re now using Apple Installer Packages for updating (as it’ll work for Sandboxed applications), but importantly it is code signed, so before launching the installer it verifies the code signature of the updater.

I know it’s not impossible for someone to crack all 3 security checks, but it’s a lot of work just to use my update system to deliver something malicious.

They need to crack my application and understand what basing method I’m using for verifying the data file.

They then need to understand what method I’m using for hashing the update file.

Lastly they need to crack the code signature check. This one is the bottle neck, as they can’t sign their installer with my code signature, so my app will never launch the update as the code signature will be invalid, which means that their cracked version which would validate their signature won’t be installed automatically on the customers machine.

The only way around it, would be for a cracker to crack the site, and the application at the same time. Which is not impossible, just less likely to happen.

Anything can be cracked, it’s just a matter of how time a cracker is willing to put in.

First, the obvious: you are using https to do the download, right?

Second, you can work around the potential https proxy server by using certificate pinning. This should detect an entity attempting to man-in-the-middle attack you with its own intermediate certificate.

Third, it is possible to use your Developer ID certificate to generate a signature for the text file, but this assume that file is not changed when you build the application. You can then use your Developer ID to verify the file itself once it’s been downloaded.

Fourth, if there is already suspected malware on your host system, you have pretty big issues that may not be solvable through software…

I suggest a AES crypted sqllite file as container for all your demands. You can put all your license information, expiration date, counter and of course the binary file data inside without any hassle. The most important issue as Phillipe pointed out that eleminate any Man in the Middle Attacks. In order to prevent this you have to use SSL connections AND you have to check the certs and servernames you’re recieving your files from.

This will certainly prevent a man in the middle attack.

AFAIK, yes this will. Also specifying a fixed IP will prevent that, but I understand that SSL certs can only work with domain names.

Yes and no, yes you can code sign a regular file, however you’ll need to Zip or Tar it as the code signature is stored in the xattrs of a regular file (as opposed to within the file for an executable or installer package).[quote=140207:@Philippe Casgrain]Fourth, if there is already suspected malware on your host system, you have pretty big issues that may not be solvable through software…[/quote]
Totally agree.

Thats a pretty clever idea. You could also use an encrypted zip file (that way the data would also get compressed). Thinking about this route, what if you were to create a code signed installer package? In theory you can put what ever you want in a OS X installer and with the right commands you can also extract specific files to specific locations. You could encrypt each file, but the key is that the installer package will contain a code signature, so it can be validated on the end users machine, yet it would be almost impossible for a man in the middle to code sign an installer with your certificate.

Well, it took me a while to get this worked out, but here’s what I did. First, I generated private and public keys with openssl:

openssl genrsa -out private.pem 4096 openssl rsa -in private.pem -pubout -out public.pem

The public.pem key is added to my app’s Resources folder, while the private.pem key is kept securely on my computer.

Next, I created an AppleScript to create a signed hash of the file whenever I need to release an update:

[code]set xmlFile to “/path/somefile.xml”
set xmlFileHash to “/path/somefile.sha1”
set privkey to “/path/private.pem”
set pubkey to “/path/public.pem”

tell application “System Events” to set hashExists to exists disk item xmlFileHash
if hashExists then
do shell script “mv " & xmlFileHash & " ~/.Trash/”
end if

do shell script "openssl dgst -sha1 -sign " & privkey & " -out " & xmlFileHash & " " & xmlFile[/code]

This gives me a separate “somefile.sha1” file that contains a signed SHA1 hash of “somefile.xml”. I upload both of these files to my website, rather than just “somefile.xml” as I did before.

Now, in my Xojo app, I download both of these files (rather than just somefile.xml), then verify like this:

[code]Verify as Boolean
dim xmlFile, hashFile, pubKey as FolderItem
dim sh as Shell

xmlFile = GetTheXMLFile
hashFile = GetTheHashFile
pubKey = App.ExecutableFile.Parent.Parent.Child("Resources").Child("public.pem")

sh = new Shell
sh.Execute("openssl dgst -sha1 -verify " + pubKey.ShellPath + " -signature " + hashFile.ShellPath + " " + xmlFile.ShellPath)
return (sh.ErrorCode = 0)

End[/code]

Works like a charm! I realize that it’s not bulletproof, but as has been pointed out, code running on an end-user machine really can’t be bulletproof. But it’s good enough for what I need.

It’s quite a complex procedure you have there. I have a couple of suggestions.

  • Use the TPSF module https://forum.xojo.com/15318-modules-for-you-updated-9-28 to get the path to the resources folder.
  • In your verify routine, don’t return a boolean, return the sh.Errorcode and then add independent checks through the other places in your code. It prevents a cracker from making one switch.