Skip to content

Commit

Permalink
Release 2.1.0
Browse files Browse the repository at this point in the history
  • Loading branch information
leif-ibsen committed Jan 23, 2024
1 parent 24998f1 commit dfd04db
Show file tree
Hide file tree
Showing 234 changed files with 1,139 additions and 7,293 deletions.
4 changes: 0 additions & 4 deletions Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,6 @@ let package = Package(
name: "SwiftChaChaPoly",
targets: ["SwiftChaChaPoly"]),
],
dependencies: [
// Dependencies declare other packages that this package depends on.
// .package(url: /* package url */, from: "1.0.0"),
],
targets: [
// Targets are the basic building blocks of a package. A target can define a module or a test suite.
// Targets can depend on other targets in this package, and on products in packages this package depends on.
Expand Down
120 changes: 3 additions & 117 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,122 +1,8 @@
<h2><b>SwiftChaChaPoly</b></h2>
<h3><b>Contents:</b></h3>
<ul>
<li><a href="#use">Usage</a></li>
<li><a href="#ex">Example</a></li>
<li><a href="#comp">CryptoKit Compatibility</a></li>
<li><a href="#perf">Performance</a></li>
<li><a href="#dep">Dependencies</a></li>
<li><a href="#ref">References</a></li>
</ul>

SwiftChaChaPoly implements Authenticated Encryption with Associated Data as defined in [RFC-8439].
It is based on the ChaCha20 stream cipher and Poly1305 authentication.
<h2><b>Usage</b></h2>
In your project Package.swift file add a dependency like<br/>

dependencies: [
.package(url: "https://github.com/leif-ibsen/SwiftChaChaPoly", from: "2.0.0"),
]

<h2 id="ex"><b>Example</b></h2>
// This example is from section 2.8.2 in [RFC-8439].

import SwiftChaChaPoly

let key: Bytes = [
0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f]
let nonce: Bytes = [
0x07, 0x00, 0x00, 0x00, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47]
let aad: Bytes = [
0x50, 0x51, 0x52, 0x53, 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7]
let text = "Ladies and Gentlemen of the class of '99: If I could offer you only one tip for the future, sunscreen would be it."

var bytes = Bytes(text.utf8)

let chacha = try ChaChaPoly(key, nonce)
let tag = chacha.encrypt(&bytes, aad)
print(tag)
let ok = chacha.decrypt(&bytes, tag, aad)
print(ok && bytes == Bytes(text.utf8) ? "Ok" : "Fail")

Giving

[26, 225, 11, 89, 79, 9, 226, 106, 126, 144, 46, 203, 208, 96, 6, 145]
Ok

<h2 id="comp"><b>Compatibility with Apple's CryptoKit Framework</b></h2>
SwiftChaChaPoly is compatible with CryptoKit as the following examples show:

<h3><b>Example 1: SwiftChaChaPoly encrypts, CryptoKit opens</b></h3>

import CryptoKit

let msg = Bytes("Hi, there".utf8)
let aad = Bytes("The AAD".utf8)

let key = Bytes(repeating: 7, count: 32)
let nonce = Bytes(repeating: 1, count: 12)

let chacha = try ChaChaPoly(key, nonce)
var ct = msg
let tag = chacha.encrypt(&ct, aad)

// ct contains the ciphertext

let ckKey = CryptoKit.SymmetricKey(data: key)
let ckNonce = try CryptoKit.ChaChaPoly.Nonce(data: nonce)
let sealedBox = try CryptoKit.ChaChaPoly.SealedBox(nonce: ckNonce, ciphertext: ct, tag: tag)
let pt = try CryptoKit.ChaChaPoly.open(sealedBox, using: ckKey, authenticating: aad)
print(String(bytes: pt, encoding: .utf8)!)

giving:

Hi, there

<h3><b>Example 2: CrypotoKit seals, SwiftChaChaPoly decrypts</b></h3>
import CryptoKit

let msg = Bytes("Hi, there".utf8)
let aad = Bytes("The AAD".utf8)

let ckKey = CryptoKit.SymmetricKey(size: .bits256)
let sealedBox = try CryptoKit.ChaChaPoly.seal(msg, using: ckKey, authenticating: aad)

let key = ckKey.withUnsafeBytes {
return Bytes($0)
}
let nonce = Bytes(sealedBox.nonce)
let chacha = try ChaChaPoly(key, nonce)
var ct = Bytes(sealedBox.ciphertext)

// ct contains the ciphertext

let ok = chacha.decrypt(&ct, Bytes(sealedBox.tag), aad)
print(String(bytes: ct, encoding: .utf8)!)

giving:

Hi, there

<h2 id="perf"><b>Performance</b></h2>
The encryption and decryption speed was measured on a iMac 2021, Apple M1 chip. The results are:
<ul>
<li>Encryption: 290 MBytes / sec (11 cycles / byte)</li>
<li>Decryption: 290 MBytes / sec (11 cycles / byte)</li>
</ul>

<h2 id="dep"><b>Dependencies</b></h2>

SwiftChaChaPoly requires Swift 5.0. It does not depend on other packages.

<h2 id="ref"><b>References</b></h2>

Algorithms from the following papers have been used in the implementation.
There are references in the source code where appropriate.

<ul>
<li>[FILIPPO] - Filippo Valsorda: A GO IMPLEMENTATION OF POLY1305 THAT MAKES SENSE, April 2019</li>
<li>[RFC-8439] - ChaCha20 and Poly1305 for IETF Protocols, June 2018</li>
</ul>
Its documentation is build with Apple's DocC tool and published on GitHub Pages at this location</br></br>
https://leif-ibsen.github.io/SwiftChaChaPoly/documentation/swiftchachapoly</br></br>
The documentation is also available in the SwiftChaChaPoly.doccarchive file.
21 changes: 11 additions & 10 deletions Sources/SwiftChaChaPoly/ChaChaPoly.swift
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,10 @@ public struct ChaChaPoly {
// MARK: Exceptions

///
/// Exceptions
/// ChaChaPoly Exceptions
///
public enum Ex: Error, CustomStringConvertible {

/// Textual description of *self*
public var description: String {
switch self {
Expand All @@ -38,7 +38,8 @@ public struct ChaChaPoly {
case nonceSize
}

// MARK: Stored Properties

// MARK: Properties

/// The key - a 32 byte value
public internal(set) var key: Bytes
Expand All @@ -47,7 +48,7 @@ public struct ChaChaPoly {
public internal(set) var nonce: Bytes


// MARK: - Initializers
// MARK: - Constructor

/// Constructs a ChaChaPoly instance from key and nonce
///
Expand All @@ -67,13 +68,13 @@ public struct ChaChaPoly {
}


// MARK: Instance Methods
// MARK: Methods

/// Encrypts a byte array and computes the tag
///
/// - Parameters:
/// - plaintext: The bytes to encrypt - it is replaced by the corresponding ciphertext of the same length
/// - aad: The additional authenticated data - possibly 0 bytes
/// - plaintext: The bytes to encrypt - it is replaced with the corresponding ciphertext of the same length
/// - aad: The additional authenticated data - the default value is an empty array
/// - Returns: The tag computed from *plaintext* and *aad* - a 16 byte value
public func encrypt(_ plaintext: inout Bytes, _ aad: Bytes = []) -> Bytes {
let chacha = ChaCha20(self.key, self.nonce)
Expand All @@ -95,10 +96,10 @@ public struct ChaChaPoly {
/// Decrypts a byte array and verifies the tag
///
/// - Parameters:
/// - ciphertext: The bytes to decrypt - if *tag* is verified, it is replaced by the corresponding plaintext
/// - ciphertext: The bytes to decrypt - if *tag* is verified, it is replaced with the corresponding plaintext
/// - tag: The tag to verify against *ciphertext* and *aad* - a 16 byte value
/// - aad: The additional authenticated data - possibly 0 bytes
/// - Returns: *true* iff *tag* is verified
/// - aad: The additional authenticated data - the default value is an empty array
/// - Returns: *true* if *tag* is verified, else *false*
public func decrypt(_ ciphertext: inout Bytes, _ tag: Bytes, _ aad: Bytes = []) -> Bool {
let n = 16 * ((aad.count + 15) / 16)
let m = 16 * ((ciphertext.count + 15) / 16)
Expand Down
Binary file not shown.
60 changes: 60 additions & 0 deletions Sources/SwiftChaChaPoly/SwiftChaChaPoly.docc/Articles/CryptoKit.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
# CryptoKit Compatibility

##

SwiftChaChaPoly is compatible with Apple's CryptoKit framework as the following examples show:

### Example 1: SwiftChaChaPoly encrypts, CryptoKit opens
```Swift
import CryptoKit
import SwiftChaChaPoly

let msg = Bytes("Hi, there".utf8)
let aad = Bytes("The AAD".utf8)

let key = Bytes(repeating: 7, count: 32)
let nonce = Bytes(repeating: 1, count: 12)

let chacha = try ChaChaPoly(key, nonce)
var ct = msg
let tag = chacha.encrypt(&ct, aad)

// ct contains the ciphertext

let ckKey = CryptoKit.SymmetricKey(data: key)
let ckNonce = try CryptoKit.ChaChaPoly.Nonce(data: nonce)
let sealedBox = try CryptoKit.ChaChaPoly.SealedBox(nonce: ckNonce, ciphertext: ct, tag: tag)
let pt = try CryptoKit.ChaChaPoly.open(sealedBox, using: ckKey, authenticating: aad)
print(String(bytes: pt, encoding: .utf8)!)
```
giving:
```Swift
Hi, there
```
### Example 2: CrypotoKit seals, SwiftChaChaPoly decrypts
```Swift
import CryptoKit
import SwiftChaChaPoly

let msg = Bytes("Hi, there".utf8)
let aad = Bytes("The AAD".utf8)

let ckKey = CryptoKit.SymmetricKey(size: .bits256)
let sealedBox = try CryptoKit.ChaChaPoly.seal(msg, using: ckKey, authenticating: aad)

let key = ckKey.withUnsafeBytes {
return Bytes($0)
}
let nonce = Bytes(sealedBox.nonce)
let chacha = try ChaChaPoly(key, nonce)
var ct = Bytes(sealedBox.ciphertext)

// ct contains the ciphertext

let ok = chacha.decrypt(&ct, Bytes(sealedBox.tag), aad)
print(String(bytes: ct, encoding: .utf8)!)
```
giving:
```Swift
Hi, there
```
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# Dependencies

##

SwiftChaChaPoly does not depend on other packages.

29 changes: 29 additions & 0 deletions Sources/SwiftChaChaPoly/SwiftChaChaPoly.docc/Articles/Example.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# Example

##
This example is from section 2.8.2 in [RFC-8439].
```Swift
import SwiftChaChaPoly

let key: Bytes = [
0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f]
let nonce: Bytes = [
0x07, 0x00, 0x00, 0x00, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47]
let aad: Bytes = [
0x50, 0x51, 0x52, 0x53, 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7]
let text = "Ladies and Gentlemen of the class of '99: If I could offer you only one tip for the future, sunscreen would be it."

var bytes = Bytes(text.utf8)

let chacha = try ChaChaPoly(key, nonce)
let tag = chacha.encrypt(&bytes, aad)
print(tag)
let ok = chacha.decrypt(&bytes, tag, aad)
print(ok && bytes == Bytes(text.utf8) ? "Ok" : "Fail")
```
Giving
```Swift
[26, 225, 11, 89, 79, 9, 226, 106, 126, 144, 46, 203, 208, 96, 6, 145]
Ok
```
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# Performance

##
The encryption and decryption speed was measured on a iMac 2021, Apple M1 chip. The results are:

* Encryption: 290 MBytes / sec (11 cycles / byte)
* Decryption: 290 MBytes / sec (11 cycles / byte)

Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# References

##

Algorithms from the following papers have been used in the implementation.
There are references in the source code where appropriate.

* [FILIPPO] - Filippo Valsorda: A GO IMPLEMENTATION OF POLY1305 THAT MAKES SENSE, April 2019
* [RFC-8439] - ChaCha20 and Poly1305 for IETF Protocols, June 2018


Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# Usage

##

In your project Package.swift file add a dependency like<br/>

dependencies: [
.package(url: "https://github.com/leif-ibsen/SwiftChaChaPoly", from: "2.1.0"),
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# ``SwiftChaChaPoly/ChaChaPoly``

## Topics

### Properties

- ``key``
- ``nonce``

### Constructor

- ``init(_:_:)``

### Methods

- ``encrypt(_:_:)``
- ``decrypt(_:_:_:)``

### Exceptions

- ``Ex``
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# ``SwiftChaChaPoly/ChaChaPoly/Ex``

## Topics

### Properties

- ``description``

18 changes: 18 additions & 0 deletions Sources/SwiftChaChaPoly/SwiftChaChaPoly.docc/SwiftChaChaPoly.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# ``SwiftChaChaPoly``

## Overview

SwiftChaChaPoly implements Authenticated Encryption with Associated Data as defined in [RFC-8439].
It is based on the ChaCha20 stream cipher and Poly1305 authentication.

> Important:
SwiftChaChaPoly requires Swift 5.0. It also requires that the Int and UInt types be 64 bit types.

## Topics

- <doc:Usage>
- <doc:Example>
- <doc:CryptoKit>
- <doc:Performance>
- <doc:Dependencies>
- <doc:References>
9 changes: 9 additions & 0 deletions SwiftChaChaPoly.doccarchive/css/523.e9a069b0.css

Large diffs are not rendered by default.

9 changes: 9 additions & 0 deletions SwiftChaChaPoly.doccarchive/css/675.40c3bcb2.css

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Large diffs are not rendered by default.

9 changes: 9 additions & 0 deletions SwiftChaChaPoly.doccarchive/css/index.ff036a9e.css

Large diffs are not rendered by default.

9 changes: 9 additions & 0 deletions SwiftChaChaPoly.doccarchive/css/topic.672a9049.css

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Loading

0 comments on commit dfd04db

Please sign in to comment.