Simple and secure hashing in Swift with the SipHash algorithm

Related tags

Encryption SipHash
Overview

SipHash

Swift 4.0 License Platform

Build Status Code Coverage

Carthage compatible CocoaPod Version

⚠️ WARNING
This package has been obsoleted by the Hasher type and the Hashable.hash(into:) requirement introduced in Swift 4.2. Using this package in not recommended in modern Swift code; instead, simply implement the standard Hashable. (The standard library changes introduced in SE-0206 are sort of like a version 2 of this package.)

SipHash is a pure Swift implementation of the SipHash hashing algorithm designed by Jean-Philippe Aumasson and Daniel J. Bernstein in 2012:

SipHash is a family of pseudorandom functions (a.k.a. keyed hash functions) optimized for speed on short messages.

Target applications include network traffic authentication and defense against hash-flooding DoS attacks.

SipHash is secure, fast, and simple (for real):

  • SipHash is simpler and faster than previous cryptographic algorithms (e.g. MACs based on universal hashing)
  • SipHash is competitive in performance with insecure non-cryptographic algorithms (e.g. MurmurHash)

-- 131002.net

SipHash has a variety of flavors; this package implements the one called SipHash-2-4.

Note that the Swift Standard Library already includes an implementation of SipHash-2-4 and SipHash-1-3; however, the APIs are currently private and not available for use outside of stdlib. This package provides an independent implementation that's available for use in third-party code.

The current release of SipHash requires Swift 4.

Sample Code

import SipHash

// `SipHashable` is like `Hashable`, but simpler.
struct Book: SipHashable {
    let title: String
    let pageCount: Int

    // You need to implement this method instead of `hashValue`.
    func appendHashes(to hasher: inout SipHasher) {
         // Simply append the fields you want to include in the hash.
         hasher.append(title)
         hasher.append(pageCount)
    }

    static func ==(left: Book, right: Book) -> Bool {
         return left.title == right.title && left.pageCount == right.pageCount
    }
}

// You can now use Books in sets or as dictionary keys.
let book = Book(title: "The Colour of Magic", pageCount: 206)
let books: Set<Book> = [book]


// If you prefer to do so, you may also create & use hashers directly.
var hasher = SipHasher()
hasher.add(book)
hasher.add(42)
// Finalizing the hasher extracts the hash value and invalidates it.
let hash = hasher.finalize()

Why Would I Use SipHash?

Unless you're targeting an ancient Swift release (<4.2), you shouldn't use SipHash. This package is obsolete; it remains here for posterity and for compatibility only. Do not import it into new code.

What follows is the original documentation, contrasting SipHashable to the original (now deprecated) Hashable.hashValue protocol requirement.

Repeated for emphasis: Do not import this package into newly written code.


Writing a good implementation of hashValue is hard, even if we just need to combine the values of a couple of fields. We need to come up with a deterministic function that blends the field values well, producing a fixed-width result without too many collisions on typical inputs. But how many collisions are "too many"? Do we even know what our "typical inputs" look like? For me, the answer to both of these questions is usually "I have absolutely no idea", and I bet you have the same problem.

Thus, verifying that our hashValue implementations work well is an exercise in frustration.

We need to somehow check the properties of the hash function by looking at its behavior given various inputs. It is easy enough to write tests for the requirement that equal values have equal hashValues. But verifying that the hash has few collisions requires making some assumptions on the statistical properties of "typical" inputs -- and even if we'd be somehow confident enough to do that, writing the code to do it is way too complicated.

Instead of rolling your own ad-hoc hash function, why not just use an algorithm designed specifically to blend data into a hash? Using a standardized algorithm means we don't need to worry about collision behavior any more: if the algorithm was designed well, we'll always have good results.

The SipHash algorithm is a particularly good choice for hashing. It implements a 64-bit cryptographic message-authentication code (MAC) with a 256-bit internal state initialized from a 128-bit secret key that's (typically) randomly generated for each execution of the binary. SipHash is designed to protect against hash collision attacks, while remaining simple to use and fast. It is already used by Perl, Python, Ruby, Rust, and even Swift itself -- which is why the documentation of Hashable explicitly warns that the value returned by hashValue may be different across executions.

The standard library already implements SipHash, but the implementation is private. (It is technically available for use, but it is not formally part of the stdlib API, and it is subject to change/removal across even point releases.) I expect a refactored version of stdlib's SipHash will become available as public API in a future Swift release. But while we're waiting for that, this package provides an alternative implementation that is available today.

Is this code full of bugs?

Indubitably. Please report all bugs you find!

The package has 100% unit test coverage. Unfortunately this doesn't tell you much about its reliability in practice.

The test suite verifies that the package generates values that match the test vectors supplied by SipHash's original authors, which makes me reasonably confident that this package implements SipHash correctly. Obviously, your mileage may vary.

Reference docs

Nicely formatted reference docs are available courtesy of Jazzy.

Installation

CocoaPods

If you use CocoaPods, you can start using SipHash by including it as a dependency in your Podfile:

pod 'SipHash', '~> 1.2'

Carthage

For Carthage, add the following line to your Cartfile:

github "attaswift/SipHash" ~> 1.2

Swift Package Manager

For Swift Package Manager, add SipHash to the dependencies list inside your Package.swift file:

import PackageDescription

let package = Package(
    name: "MyPackage",
    dependencies: [
        .Package(url: "https://github.com/attaswift/SipHash.git", from: "1.2.1")
    ]
)

Standalone Development

If you don't use a dependency manager, you need to clone this repo somewhere near your project, and add a reference to SipHash.xcodeproj to your project's xcworkspace. You can put the clone of SipHash wherever you like on disk, but it is a good idea to set it up as a submodule of your app's top-level Git repository.

To link your application binary with SipHash, just add SipHash.framework from the SipHash project to the Embedded Binaries section of your app target's General page in Xcode. As long as the SipHash project file is referenced in your workspace, this framework will be listed in the "Choose items to add" sheet that opens when you click on the "+" button of your target's Embedded Binaries list.

There is no need to do any additional setup beyond adding the framework targets to Embedded Binaries.

Comments
  • Fix Linux randomUInt64 for Swift 4.1

    Fix Linux randomUInt64 for Swift 4.1

    Using private library methods is not sustainable. In Swift 4.1 the randomUInt64 function is broken for Linux. So I wrote an implementation which is a little bit unconventional and maybe a little bit slower than the old one but it is reliable and should work on all Linux and FreeBSD systems across different Swift versions. Like I said it may perform a little bit worse than the macOS implementation or the old one but because it will only be used once per process to generate the key, it doesn't really matter.

    opened by koraykoska 10
  • Different hash values every time for the same string

    Different hash values every time for the same string

    I had detect a problem with the hasher, every time I execute them I get a different hash for the same exact string:

    My simply test code:

    var hasherTest = SipHasher() hasherTest.append("Test") let hashVal = hasherTest.finalize()

    I run one time:

    Printing description of hashVal: 434885335948154737

    Then I run again:

    Printing description of hashVal: -3387410001051536137

    And so on, the hash value is always different, happend on Device and Simulator.

    If I use several hashers in the same execution, then I get the same value, but when I run the code again, values are not the same than in the previous execution.

    I am using version 1.2.

    opened by daniel-lahoz 1
  • v1.2.0 violates semantic versioning

    v1.2.0 violates semantic versioning

    The latest SipHash, 1.2.0, requires Swift 4.

    The last version of BigInt to support Swift 3, v2.1.2, depended on SipHash ~> 1.1. This means that SipHash 1.2.0 is now being used by CocoaPods, which is incompatible and results in failed compilation.

    Seems like v2.0.0 would've been a better version to use for this breaking change.


    For those that are having the same issue with BigInt, just add SipHash explicitly to your Podfile. You can just specify pod 'SipHash', '1.1.2' to pin that version and prevent CocoaPods from implicitly choosing a higher version.

    opened by allewun 1
  • Fix for installing Swift4 branch from CocoaPods

    Fix for installing Swift4 branch from CocoaPods

    The current 'master' of SipHash uses a folder named 'sources' for the source code to SipHash. The swift4 branch now has that code in a folder named 'SipHash', but the podspec wasn't updated to reflect this. This caused 'pod install' of the swift4 branch to not download the Swift code for SipHash, making the pod not buildable.

    This also prevented manual Podfile overrides of BigInt's SipHash dependency, as it would result in an invalid SipHash module.

    Once this is merged, installing SipHash via Podfile will work on the Swift4 branch (allowing BigInt for swift4 to be compilable via a Podfile override).

    Related BigInt issue: https://github.com/attaswift/BigInt/issues/22

    opened by amyleecodes 1
  • UnsafeRawBufferPointer errors when building

    UnsafeRawBufferPointer errors when building

    I installed SipHash through BigInt 3.1 with Cocoapods and got 2 errors when building the project. I'm using XCode 9.2, deployment target is ios11.2 (Swift 4).

    ! Cannot invoke initializer for type 'UnsafeRawBufferPointer' with an argument list of type '(rebasing: Slice<UnsafeRawBufferPointer>)'
    
    ! Value of type 'UnsafeMutableRawBufferPointer' has no member 'copyMemory'
    

    capture d ecran 2018-08-12 a 13 24 29

    capture d ecran 2018-08-12 a 13 23 56

    I both cleaned my build folder (Cmd+Shift+K) and did again a pod install but the issue persists.

    opened by romain64 5
Releases(v1.2.2)
  • v1.2.2(Jun 8, 2018)

  • v1.2.1(May 27, 2018)

  • v1.2.0(Sep 7, 2017)

    This release contains the following changes:

    • The package requires Swift 4.
    • SipHasher now has a method for appending slices of UnsafeRawBufferPointers.
    • In the supplied Xcode project, bundle identifiers have been updated. The new ones start with org.attaswift..

    Note that the URL to the package's Git repository has changed; please update your references.

    Source code(tar.gz)
    Source code(zip)
  • v1.1.2(May 5, 2017)

  • v1.1.1(Feb 7, 2017)

  • v1.1.0(Nov 23, 2016)

    This release contains the following changes:

    • SipHasher now supports appending optional values directly.
    • The deployment target for Carthage and standalone builds was set back to iOS 8.0 and macOS 10.9, the earliest possible OS versions for Swift frameworks. This change does not affect CocoaPod builds, which already had the same settings.
    Source code(tar.gz)
    Source code(zip)
  • v1.0.0(Nov 15, 2016)

Owner
A collection of useful Swift packages
null
An easy way for hashing and encryption.

CatCrypto include a series of hashing and encryption functions and more functions in progress! CatCrypto also contains Swift bindings of Argon2, the p

Kcat 62 Sep 27, 2022
CryptoSwift is a growing collection of standard and secure cryptographic algorithms implemented in Swift

CryptoSwift Crypto related functions and helpers for Swift implemented in Swift. (#PureSwift) Note: The main branch follows the latest currently relea

Marcin Krzyzanowski 9.4k Jan 9, 2023
Secure your app by obfuscating all the hard-coded security-sensitive strings.

App Obfuscator for iOS Apps Secure your app by obfuscating all the hard-coded security-sensitive strings. Security Sensitive strings can be: REST API

pj 601 Dec 16, 2022
Demonstration library for using the Secure Enclave on iOS

SecureEnclaveCrypto This project shows you how to create a keypair where as the private key is stored in the secure enclave sign a string / some data

Trail of Bits 272 Jan 7, 2023
A simple and opinionated AES encrypt / decrypt Objective-C class that just works.

AESCrypt-ObjC - Simple AES encryption / decryption for iOS and OS X AESCrypt is a simple to use, opinionated AES encryption / decryption Objective-C c

Gurpartap Singh 782 Oct 12, 2022
BitWiser - A simple library to help you in dealing with bytes, bits and nibbles

BitWiser Bitwiser is a collection of methods and properties that makes you work

Andrea Finollo 19 Dec 27, 2022
Safe and easy to use crypto for iOS and macOS

Swift-Sodium Swift-Sodium provides a safe and easy to use interface to perform common cryptographic operations on macOS, iOS, tvOS and watchOS. It lev

Frank Denis 483 Jan 5, 2023
A tiny and easy to use Swift class to encrypt strings using HMAC algorithms.

#Sweet HMAC SweetHMAC is a tiny and easy to use Swift class to encrypt strings using HMAC algorithms. A special thanks to jernejstrasner for shared HM

Jan Cássio 37 Jul 27, 2022
RSA public/private key generation, RSA, AES encryption/decryption, RSA sign/verify in Swift with CommonCrypto in iOS and OS X

SwCrypt Create public and private RSA keys in DER format let (privateKey, publicKey) = try! CC.RSA.generateKeyPair(2048) Convert them to PEM format l

soyer 695 Dec 8, 2022
CCCryptor (AES encryption) wrappers for iOS and Mac in Swift. -- For ObjC, see RNCryptor/RNCryptor-objc

RNCryptor Cross-language AES Encryptor/Decryptor data format. The primary targets are Swift and Objective-C, but implementations are available in C, C

null 3.3k Jan 7, 2023
A framework for the JOSE standards JWS, JWE, and JWK written in Swift.

JOSESwift is a modular and extensible framework for the JOSE standards JWS, JWE, and JWK written in Swift. ?? Please note that this implementation of

Airside Mobile, Inc. 162 Dec 15, 2022
Util for generation RSA keys on your client and save to keychain or convert into Data 🔑 🔐

RSASwiftGenerator ?? ?? To run the example project, clone the repo, and run pod install from the Example directory first. Requirements ⚠️ SWIFT 4 XCod

null 21 Apr 30, 2022
A KeePass/Password Safe Client for iOS and OS X

Strongbox A Personal Password Manager for iOS & OSX that can be found on the Apple App Store here: https://apps.apple.com/app/strongbox-password-safe/

Strongbox 976 Jan 3, 2023
A wrapper for Apple's Common Crypto library written in Swift.

IDZSwiftCommonCrypto A Swift wrapper for Apple's CommonCrypto library. IDZSwiftCommonCrypto works with both CocoaPods and Cathage. For more details on

idz 472 Dec 12, 2022
Read my answer here Importing CommonCrypto in a Swift framework

Read my answer here Importing CommonCrypto in a Swift framework

Khoa 281 Sep 17, 2022
A pure Swift implementation of MD5

SwiftMD5 SwiftMD5 is a pure Swift implementation for the MD5 algorithm. Usage import SwiftMD5 "The quick brown fox jumps over the lazy dog".md5 // "9

Matthew Purland 11 Sep 25, 2021
🍕 MD5 in pure Swift

SwiftHash ❤️ Support my app ❤️ Push Hero - pure Swift native macOS application to test push notifications Quick Access - Organise files in the Mac men

Khoa 207 Dec 24, 2022
RSA public/private key encryption in Swift

SwiftyRSA Maintainer(s): @ikeith Public key RSA encryption in Swift. SwiftyRSA is used in the Scoop iOS app to encrypt driver license numbers before s

Scoop 1.1k Jan 5, 2023
Enigma encryption in Swift

?????????????????? ?????????? // Will create an Enigma with an empty plugboard, rotors I, II, III and reflector B (wide). let enigma = Enigma() // Wil

Joakim Gyllström 113 Dec 16, 2022