Hello Queens and Kings, Leo here. The topic today is Hash Functions in Swift and how you can really understand the importance of this cryptographic technique.
We’ll explore one of the basic concepts of cryptography, of course, I’m talking about hashing. Hashing is so important that it’s baked into Swift Standard Library, because it enables two out of three main swift data structures, the Dictionary, and the Set, among other things too. With iOS 13 or later we have CryptoKit to help us with various cryptography methods.
Even if you don’t use hashing functions directly it’s an important concept to know that it’s behind the scenes making everything work well.
The painting I choose is Wood splitters, an 1886 painting by the Australian artist Thomas William Roberts (8 March 1856 – 14 September 1931) was an English-born Australian artist and a key member of the Heidelberg School art movement, also known as Australian impressionism. The reason is that the *hash* word origin from the hatchet French word and as a hatchet is a small axe… we have a wood chopping paint.
Stay tuned to the cryptography trip of hashing functions. Let’s go!
Problem – Hash Functions in Swift
You were asked to generate a SHA512 hash of some data to the backend.
Let’s take a step back and discover what is and why hashing in your daily life.
Hashing is an algorithm that calculates a fixed-size bit data value from any kind of data input. Hashing transforms this data into a far shorter fixed-length (it can be not fixed length but instead have a target range length too) value or key which represents the original string. At the end of the day, the hashing function is a map function that produces a resume of the input data.
Hashing in Swift
One main use of hashing is to compare two data for equality. With this technique you can without opening two documents compare them bit-for-bit, the calculated hash values of these files will allow the owner to know immediately if they are different.
The properties of hashing functions are:
- PreImage Resistance: says that the digest should be hard to revert.
- Second preimage resistance: this means that given input and its hash, it should be computationally hard to find another input with the same hash.
- Collision resistance: This states that should be very hard to find two inputs with the same hash.
Collision resistance is especially important in hashing functions because of the birthday problem. This problem states that in a set of n randomly chosen people, some pairs of them will have the same birthday. In a group of 23 people, the probability of a shared birthday exceeds 50%, while a group of 70 has a 99.9% chance of a shared birthday. By the pigeonhole principle, the probability reaches 100% when the number of people reaches 367, since there are only 366 possible birthdays, including February 29.
This problem relates to hashing because of the birthday attack. The example:
A message *m* is typically signed by first computing f(m) , where f is a cryptographic hash function, and then using some secret key to sign f(m). Suppose Mallory wants to trick Bob into signing a fraudulent contract. Mallory prepares a fair contract *m* and a fraudulent one *m′*.
She then finds a number of positions where *m* can be changed without changing the meaning, such as inserting commas, empty lines, one versus two spaces after a sentence, replacing synonyms etc. By combining these changes, she can create a huge number of variations on m which are all fair contracts. This is way it’s important when you change the input data you generate new output data avoiding hash collisions.
As the property stated hash collisions are hard but not impossible. To calculate a SHA256 input to be equal to an already given SHA256 output we have to do a “what if” situation here . If we assume that we will use brute force to calculate each one of the 2^128 operations, we could take the entire chip manufacturing capability of the world (currently circa 300+ billion dollars us), and devote the entire output for just one year to making dedicated attack chips, with each chip costing one dollar, and is able to compute 230 hashes per second, well, that gives us an attack in only 300 million years.
So yes, it’s breakable but it’s unlikely to break in the near future.
Examples of Hash Functions in Swift
First, we’ll observe what a hash result (digest is a word used to hash result too) looks like, you have to import CryptoKit that is iOS 13 or higher compatible:
let data = "This text will be hashed".data(using: .utf8)! // mark 1 print(CryptoKit.SHA256.hash(data: data)) // mark 2 print(CryptoKit.SHA384.hash(data: data)) // mark 3 print(CryptoKit.SHA512.hash(data: data))
Resulting in:
As you can see in the image above, the digest (hash result) of hashing the 24 characters length text “This text will be hashed” have different outputs based on how big is the hashing digest. As you can see in the code example above, all the digest were bigger than the input, that’s because all hashing algorithms have a minimum length of result digest. But what happens if the input is bigger than the generated digest?
Let’s see:
let data = "Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo ligula eget dolor. Aenean massa. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Donec".data(using: .utf8)! print(CryptoKit.SHA256.hash(data: data),"Count: \(CryptoKit.SHA256.hash(data: data).description.count)") print(CryptoKit.SHA384.hash(data: data),"Count: \(CryptoKit.SHA384.hash(data: data).description.count)") print(CryptoKit.SHA512.hash(data: data),"Count: \(CryptoKit.SHA512.hash(data: data).description.count)")
And the result:
This demonstrates one characteristic of hashing: the fixed-size output. Given any kind of input, the hashing size is the same (or basically the same). This guarantee a fixed time to search in data structures. You don’t have to traverse the whole data structure to know where the data is. Instead, you only need to calculate the hash that is an O(1) operation compared to an O(N) search in data structures like Linked Lists or Arrays.
If you are curious about what SHA2 stands for its Secure Hash Algorithm 2 is a set of cryptographic hash functions designed by the United States National Security Agency (NSA) and first published in 2001. They were built using the Merkle–Damgård techniques. That is from a one-way compression function itself built using the Davies–Meyer structure from a specialized block cipher. And SHA2 is what CryptoKit implements in its hashing algorithms.
Swift Standard Library and Hashing
Swift is deeply involved with hashing with the Hashable protocol.
Many types in the standard library conform to Hashable: Strings, integers, floating-point and Boolean values, and even sets are hashable by default. Some other types, such as optionals, arrays and ranges automatically become hashable when their type arguments implement the same.
Even if you don’t know you are using hashing functions every day while coding in Swift. Dictionary keys and sets are hashable too, look at their declarations in Swift:
@frozen public struct Dictionary<Key, Value> where Key : Hashable {...} @frozen public struct Set<Element> where Element : Hashable {...} // and even string extension String : Hashable {...}
And this is the end!
Continue Studying Cryptography in Swift
To get a full overview about symmetric and asymmetric keys cryptography you can follow this article tutorial about Cryptography Keys in Swift. There you can check the differences between those two types of cryptography and much more!
Continuing in the hash part, you can use those to authenticate messages between peers. Check this article to see how you can send and receive messages and know that the message wasn’t changed or corrupted in any way.
Summary – Hash Functions in Swift
Hashing is a very very important subject to understand and learn even if just to know what it is. Today we learned what a hash is, its properties, and how can you use it with CryptoKit (iOS 13+). And also the importance of Hashable in Swift Standard Library.
This is my second article about security and iOS. In the next one, we should talk about another cryptography technique broad used, stay tuned!
That’s all my people, I hope you liked reading this article as much as I enjoyed writing it. If you want to support this blog you can Buy Me a Coffee or leave a comment saying hello. You can also sponsor posts and I’m open to freelance writing!
You can reach me on LinkedIn or Twitter and send me an e-mail through the contact page.
Thanks for reading and… That’s all folks.
Credits: image