0

I would like to calculate and validate some checksums of a property list in iOS.

The contents of the plist are the following:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>foo</key>
    <string>bar</string>
    <key>foornum</key>
    <integer>42</integer>
</dict>
</plist>

In order to calculate the hash (using OpenSSL) I have done the following:

# Convert the plist to binary format
plutil -convert binary1 Test.plist

openssl dgst -sha256 Test.plist    
# SHA256(Test.plist)= 187592fed5ad62620016c5d0b9f08bc58c93c8fdcc9fc7464aea8fdfdf75a48c

# Or by using the internal shasum method
shasum -a 256 Test.plist
# 187592fed5ad62620016c5d0b9f08bc58c93c8fdcc9fc7464aea8fdfdf75a48c  Test.plist

# Transform to base64 so it can be loaded easily into a Swift Data object
echo -n 187592fed5ad62620016c5d0b9f08bc58c93c8fdcc9fc7464aea8fdfdf75a48c | xxd -r -p | base64
# GHWS/tWtYmIAFsXQufCLxYyTyP3Mn8dGSuqP3991pIw=

Then in Swift I do the following:

import CommonCrypto

let testHash = Data(base64Encoded: "GHWS/tWtYmIAFsXQufCLxYyTyP3Mn8dGSuqP3991pIw=")!
print(testHash as NSData)
let fileURL = Bundle.main.url(forResource: "Test", withExtension: "plist")!

var fileData = try! Data(contentsOf: fileURL)

var digest = [UInt8](repeating: 0, count: Int(CC_SHA256_DIGEST_LENGTH))
fileData.withUnsafeBytes {
    _ = CC_SHA256($0.baseAddress, CC_LONG(fileData.count), &digest)
}
print(Data(digest) as NSData)

This gives me the following output to console:

<187592fe d5ad6262 0016c5d0 b9f08bc5 8c93c8fd cc9fc746 4aea8fdf df75a48c>
<24a5245b 317796a5 59cdee0b 86912974 28cc2491 20f6923c 87f59ba5 4e799345>

Why is the hash different and how can I solve it so I can calculate and validate the hash properly?

Bram
  • 2,718
  • 1
  • 22
  • 43
  • Have you double-checked that Test.plist in the iOS app is the same file? Are *both* files in the binary format? – Martin R Jun 07 '19 at 09:10
  • Yeah, ran the terminal in the iOS folder the Xcode project is in too. I did notice that the contents of the file is different too. `xxd -ps Test.plist` gives me different contents than `print(fileData as NSData)`. This does explain the difference in checksum, but why is the content different...? – Bram Jun 07 '19 at 09:12
  • And indeed the property list item in the inspector is set to `Default - Property List Binary` – Bram Jun 07 '19 at 09:14

1 Answers1

0

Although I'm not entirely sure what causes the problem, I did manage to solve it by using a python library.

import plistlib
import hashlib

def calc_hash(file_name):
    try:
        f = open(file_name, 'r')
        f_data = f.read()
        f.close()
        file = plistlib.loads(f_data.encode())
    except (ValueError, Exception) as e:
        print("Failed to load file {}".format(file_name))
        return
    dump = plistlib.dumps(file, fmt=plistlib.FMT_BINARY)

    hasher = hashlib.sha256()
    hasher.update(dump)
    digest = hasher.digest()

    print("{} {}".format(file_name, digest.hex()))

file_name = str(input('Please enter the relative path to the plist (i.e. path/to/plist.plist):\n'))
calc_hash(file_name)
Bram
  • 2,718
  • 1
  • 22
  • 43