• Stars
    star
    478
  • Rank 88,987 (Top 2 %)
  • Language
    Swift
  • License
    MIT License
  • Created over 9 years ago
  • Updated 5 months ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

A wrapper for Apple's Common Crypto library written in Swift.

IDZSwiftCommonCrypto

Carthage compatible Build Status Coverage Status

A Swift wrapper for Apple's CommonCrypto library.

IDZSwiftCommonCrypto works with both CocoaPods and Cathage. For more details on how to install it into your projects see INSTALL.md

If you are using CococaPods you must use pod cache clean IDZSwiftCommonCrypto --all after you upgrade Xcode. This is needed to avoid stale module maps being used from the CocoaPods cache. Removing your Podfile.lock and Pods directory is not sufficient.

IDZSwiftCommonCrypto provides the following classes:

  • Digest for calculating message digests,
  • HMAC for calculating Hash-based Message Authentication Codes,
  • Cryptor for encrypting and decrypting bounded buffers,
  • StreamCryptor for encrypting and decrypting streaming information, and
  • PBKDF for deriving key material from a password or passphrase.

Which Release to Use

Which version you use depends on which version of Xcode and Swift you are currently using. Please refer to the list below:

  • 0.7.4 -- Xcode 7.3.1, Swift 2.2
  • 0.8.0 -- Xcode 7.3.1, Swift 2.2, with additional APIs for CCMode
  • 0.8.3 -- Xcode 8.0, Swift 2.3
  • 0.9.x -- Xcode 8.0, Swift 3.0
  • 0.10.x -- Xcode 9.0, Swift 4.0
  • 0.11.x -- Xcode 10.0, Swift 4.2
  • 0.12.x -- Xcode 10.2, Swift 5.0
  • 0.13.x -- Xcode 11.0, Swift 5.1, iOS 13.0

Using Digest

To calculate a message digest you create an instance of Digest, call update one or more times with the data over which the digest is being calculated and finally call final to obtain the digest itself.

The update method can take a String

let  s = "The quick brown fox jumps over the lazy dog."
var md5s2 : Digest = Digest(algorithm:.MD5)
md5s2.update(s)
let digests2 = md5s2.final()

// According to Wikipedia this should be
// e4d909c290d0fb1ca068ffaddf22cbd0
hexStringFromArray(digests2)
assert(digests2 == arrayFromHexString("e4d909c290d0fb1ca068ffaddf22cbd0"))

or an array of UInt8 elements:

let b : [UInt8] = 
[0x54,0x68,0x65,0x20,0x71,0x75,0x69,0x63,
0x6b,0x20,0x62,0x72,0x6f,0x77,0x6e,0x20,
0x66,0x6f,0x78,0x2e]
var md5s1 : Digest = Digest(algorithm:.MD5)
md5s1.update(b)
let digests1 = md5s1.final()

If you only have a single buffer you can simply write

  var digests3 = Digest(algorithm: .md5).update(b)?.final() // digest is of type [UInt8]?

or

  var digests4 = Digest(algorithm: .md5).update(s)?.final() // digest is of type [UInt8]?

Supported Algorithms

The Digest class supports the following algorithms:

  • .md2
  • .md4
  • .md5
  • .sha1
  • .sha224
  • .sha256
  • .sha384
  • .sha512

Using HMAC

Calculating a keyed-Hash Message Authentication Code (HMAC) is very similar to calculating a message digest, except that the initialization routine now takes a key as well as an algorithm parameter.

var keys5 = arrayFrom(hexString: "0102030405060708090a0b0c0d0e0f10111213141516171819")
var datas5 : [UInt8] = Array(count:50, repeatedValue:0xcd)
var expecteds5 = arrayFrom(hexString: "4c9007f4026250c6bc8414f9bf50c86c2d7235da")
var hmacs5 = HMAC(algorithm:.sha1, key:keys5).update(datas5)?.final()

// RFC2202 says this should be 4c9007f4026250c6bc8414f9bf50c86c2d7235da
let expectedRFC2202 = arrayFrom(hexString: "4c9007f4026250c6bc8414f9bf50c86c2d7235da")
assert(hmacs5! == expectedRFC2202)

Supported Algorithms

  • .md5
  • .sha1
  • .sha224
  • .sha256
  • .sha384
  • .sha512

Using Cryptor

let algorithm = Cryptor.Algorithm.aes
var iv = try! Random.generateBytes(byteCount: algorithm.blockSize())
var key = arrayFrom(hexString: "2b7e151628aed2a6abf7158809cf4f3c")
var plainText = "The quick brown fox jumps over the lazy dog. The fox has more or less had it at this point."

var cryptor = Cryptor(operation:.encrypt, algorithm:algorithm, options:.PKCS7Padding, key:key, iv:iv)
var cipherText = cryptor.update(plainText)?.final()

cryptor = Cryptor(operation:.decrypt, algorithm:algorithm, options:.PKCS7Padding, key:key, iv:iv)
var decryptedPlainText = cryptor.update(cipherText!)?.final()
var decryptedString = String(bytes: decryptedPlainText!, encoding: .utf8)
decryptedString
assert(decryptedString == plainText)

Supported Algorithms

  • .AES
  • .DES
  • .TripleDES
  • .CAST
  • .RC2
  • .Blowfish

Using StreamCryptor

To encrypt a large file or a network stream use StreamCryptor. The StreamCryptor class does not accumulate the encrypted or decrypted data, instead each call to update produces an output buffer.

The example below shows how to use StreamCryptor to encrypt and decrypt an image file.

func crypt(sc : StreamCryptor,  inputStream: InputStream, outputStream: OutputStream, bufferSize: Int) -> (bytesRead: Int, bytesWritten: Int)
{
    var inputBuffer = Array<UInt8>(repeating:0, count:1024)
    var outputBuffer = Array<UInt8>(repeating:0, count:1024)


    var cryptedBytes : Int = 0
    var totalBytesWritten = 0
    var totalBytesRead = 0
    while inputStream.hasBytesAvailable
    {
        let bytesRead = inputStream.read(&inputBuffer, maxLength: inputBuffer.count)
        totalBytesRead += bytesRead
        let status = sc.update(bufferIn: inputBuffer, byteCountIn: bytesRead, bufferOut: &outputBuffer, byteCapacityOut: outputBuffer.count, byteCountOut: &cryptedBytes)
        assert(status == Status.success)
        if(cryptedBytes > 0)
        {
            let bytesWritten = outputStream.write(outputBuffer, maxLength: Int(cryptedBytes))
            assert(bytesWritten == Int(cryptedBytes))
            totalBytesWritten += bytesWritten
        }
    }
    let status = sc.final(bufferOut: &outputBuffer, byteCapacityOut: outputBuffer.count, byteCountOut: &cryptedBytes)    
    assert(status == Status.success)
    if(cryptedBytes > 0)
    {
        let bytesWritten = outputStream.write(outputBuffer, maxLength: Int(cryptedBytes))
        assert(bytesWritten == Int(cryptedBytes))
        totalBytesWritten += bytesWritten
    }
    return (totalBytesRead, totalBytesWritten)
}

let imagePath = Bundle.main.path(forResource: "Riscal", ofType:"jpg")!
let tmp = NSTemporaryDirectory() as NSString
let encryptedFilePath = "\(tmp)/Riscal.xjpgx"
var decryptedFilePath = "\(tmp)/RiscalDecrypted.jpg"

// Prepare the input and output streams for the encryption operation
guard let imageInputStream = InputStream(fileAtPath: imagePath) else {
    fatalError("Failed to initialize the image input stream.")
}
imageInputStream.open()
guard let  encryptedFileOutputStream = OutputStream(toFileAtPath: encryptedFilePath, append:false) else
{
    fatalError("Failed to open output stream.")
}
encryptedFileOutputStream.open()

// Generate a new, random initialization vector
let initializationVector = try! Random.generateBytes(byteCount: algorithm.blockSize())

// A common way to communicate the initialization vector is to write it at the beginning of the encrypted data.
let bytesWritten = encryptedFileOutputStream.write(initializationVector, maxLength: initializationVector.count)

// Now write the encrypted data
var sc = StreamCryptor(operation:.encrypt, algorithm:algorithm, options:.PKCS7Padding, key:key, iv:initializationVector)
guard  bytesWritten == initializationVector.count else
{
    fatalError("Failed to write initialization vector to encrypted output file.")
}
let outputResult = crypt(sc: sc, inputStream: imageInputStream, outputStream: encryptedFileOutputStream, bufferSize: 1024)
encryptedFileOutputStream.close()
outputResult

// Uncomment this line to verify that the file is encrypted
//var encryptedImage = NSImage(contentsOfFile:encryptedFile)

// Prepare the input and output streams for the decryption operation
guard let encryptedFileInputStream = InputStream(fileAtPath: encryptedFilePath) else
{
    fatalError("Failed to open the encrypted file for input.")
}
encryptedFileInputStream.open()
guard let decryptedFileOutputStream = OutputStream(toFileAtPath: decryptedFilePath, append:false) else {
    fatalError("Failed to open the file for the decrypted output file.")
}
decryptedFileOutputStream.open()

// Read back the initialization vector.
var readbackInitializationVector = Array<UInt8>(repeating: 0, count: algorithm.blockSize())
let bytesRead = encryptedFileInputStream.read(&readbackInitializationVector, maxLength: readbackInitializationVector.count)

// Uncomment this to verify that we did indeed read back the initialization vector.
//assert(readbackInitializationVector == initializationVector)

// Now use the read back initialization vector (along with the key) to
sc = StreamCryptor(operation:.decrypt, algorithm:algorithm, options:.PKCS7Padding, key:key, iv:readbackInitializationVector)
let inputResult = crypt(sc: sc, inputStream: encryptedFileInputStream, outputStream: decryptedFileOutputStream, bufferSize: 1024)

// Uncomment this to verify that decrypt operation consumed all the encrypted data
// and produced the correct number of bytes of plaintext output.
//assert(inputResult.bytesRead == outputResult.bytesWritten && inputResult.bytesWritten == outputResult.bytesRead)

var image = NSImage(named:"Riscal.jpg")
var decryptedImage = NSImage(contentsOfFile:decryptedFilePath)
decryptedImage

Using PBKDF

The PBKDF class provides a method of deriving keys from a user password. The following example derives a 20-byte key:

let keys6 = PBKDF.deriveKey("password", salt: "salt", prf: .SHA1, rounds: 1, derivedKeyLength: 20)
// RFC 6070 - Should derive 0c60c80f961f0e71f3a9b524af6012062fe037a6
let expectedRFC6070 = arrayFrom(hexString: "0c60c80f961f0e71f3a9b524af6012062fe037a6")
assert(keys6 == expectedRFC6070)

Supported Pseudo-Random Functions

  • .sha1
  • .sha224
  • .sha256
  • .sha384
  • .sha512

More Repositories

1

IDZAQAudioPlayer

Play Ogg Vorbis using Audio Queues on iOS
Objective-C
71
star
2

360Video

A simple project to demonstrate using SceneKit to create an iOS 360º video player in Swift.
Swift
50
star
3

IDZPrecompiledSpeex

Speex 1.2rc1 for armv7, armv7s and i386
C
46
star
4

IDZPrecompiledOgg

libogg compiled for iOS armv7, armv7s, arm64, i386, x86_64
C
31
star
5

GettingStartedWithModelIO

Swift source code to demonstrate loading and texturing a .OBJ file using ModelIO
Swift
27
star
6

PanoView

Demo of using CoreMortion and SceneKit to view 360º Panoramic Photos
Swift
27
star
7

IDZPrecompiledVorbis

libvorbis compiled for iOS armv7, armv7, arm64, i386, x86_64
C
25
star
8

IDZPrecompiledFLAC

FLAC compiled for armv7, armv7s, arm64, i386 and x86_64.
C++
23
star
9

IDZWebBrowser

Update version of "Building a Web Browser with UIWebView" tutorial series source code.
Objective-C
18
star
10

SwiftStandardLibraryPlaygrounds

A collection of playground demonstrating the use of the Swift Standard Library
Swift
15
star
11

IDZSwiftCoreImage

Type-safe Swift wrappers for Core Image.
Swift
13
star
12

IDZBuild

A set of scripts for building Open Source Projects.
Shell
11
star
13

IDZSwiftScriptingGoodies

Some (hopefully) useful functions for writing scripts in Swift.
Swift
5
star
14

IDZGunzip

A category on NSData for gunzipping data.
5
star
15

Emarcam

An attempt to undo some of the knots in Swift `String`s.
Swift
4
star
16

BitcoinOSXXcodeproj

An Xcode project for compiling and debugging Bitcoin Core
Shell
2
star
17

IDZTabView

A multi-tabbed view controller for iOS similar to Safari for iPad based on TabView by Ian McDowell.
Swift
2
star
18

IDZPrecompiledTheora

libtheora compiled for iOS armv7, armv7s, arm64, i386 and x86_64
C
2
star
19

Radars

Source code to accompany radars on OpenRadar.
Swift
1
star
20

SwiftVBigNum

A Swift wrapper around Apple's 256, 512 and 1024-bit integer types.
Swift
1
star
21

IDZSwiftKeychain

A type-safe Swift wrapper for Apple's keychain
1
star
22

BenEaterBreadboard6502

Files related to building Ben Eater's 8-bit Breadboard 6502-based Computer.
Swift
1
star
23

ShinkansenSpeed

Code for a blog post using CoreLocation and MapKit to measure train speed and show location.
Swift
1
star
24

IDZGzip

A category on NSData for gzipping data.
Objective-C
1
star
25

IDZSwiftGLKit

Swift extensions to Apple's GLKit
Swift
1
star
26

word2vec

Automatically exported from code.google.com/p/word2vec
C
1
star
27

IDZSwiftDataTaskPublisher

A (probably very naïve) attempt at implementing the `dataTaskPublisher(for: URLRequest)` extension on `URLSession` mentioned in WWDC 2019, Session 712.
Swift
1
star