Skip to content

Commit

Permalink
Release 3.9.0
Browse files Browse the repository at this point in the history
  • Loading branch information
leif-ibsen committed Jul 24, 2023
1 parent 3563104 commit 2b67250
Show file tree
Hide file tree
Showing 107 changed files with 14,593 additions and 49,107 deletions.
2 changes: 1 addition & 1 deletion Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ let package = Package(
],
dependencies: [
// Dependencies declare other packages that this package depends on.
.package(url: "https://github.com/leif-ibsen/BigInt", from: "1.11.0"),
.package(url: "https://github.com/leif-ibsen/BigInt", from: "1.13.0"),
.package(url: "https://github.com/leif-ibsen/ASN1", from: "2.1.0"),
],
targets: [
Expand Down
97 changes: 83 additions & 14 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,13 @@
<li><a href="#basic1">Creating New Keys</a></li>
<li><a href="#basic2">Loading Existing Keys</a></li>
<li><a href="#basic3">Encrypted Private Keys</a></li>
<li><a href="#basic5">Encryption and Decryption</a></li>
<li><a href="#basic4">AEAD Encryption and Decryption</a></li>
<li><a href="#basic6">Signing and Verifying</a></li>
<li><a href="#basic7">Secret Key Agreement</a></li>
<li><a href="#basic8">Creating New Domains</a></li>
<li><a href="#basic9">Elliptic Curve Arithmetic</a></li>
<li><a href="#basic4">Encryption and Decryption</a></li>
<li><a href="#basic5">AEAD Encryption and Decryption</a></li>
<li><a href="#basic6">HPKE Encryption and Decryption</a></li>
<li><a href="#basic7">Signing and Verifying</a></li>
<li><a href="#basic8">Secret Key Agreement</a></li>
<li><a href="#basic9">Creating New Domains</a></li>
<li><a href="#basic10">Elliptic Curve Arithmetic</a></li>
<li><a href="#perf">Performance</a></li>
<li><a href="#dep">Dependencies</a></li>
<li><a href="#ref">References</a></li>
Expand All @@ -23,6 +24,7 @@ This encompasses:
<li>Creating, loading and storing public and private keys</li>
<li>Encryption and decryption using the ECIES algorithm based on the AES block cipher and six different block modes</li>
<li>AEAD (Authenticated Encryption with Associated Data) encryption and decryption using the ECIES algorithm with the ChaCha20/Poly1305 or the AES/GCM cipher</li>
<li>HPKE (Hybrid Public Key Encryption) encryption and decryption according to RFC 9180</li>
<li>Signature signing and verifying using the ECDSA algorithm, including the option of deterministic signatures</li>
<li>Secret key agreement using the Diffie-Hellman key agreement algorithm - ECDH</li>
<li>Ability to create your own domains</li>
Expand All @@ -32,7 +34,7 @@ This encompasses:
In your project Package.swift file add a dependency like<br/>

dependencies: [
.package(url: "https://github.com/leif-ibsen/SwiftECC", from: "3.8.0"),
.package(url: "https://github.com/leif-ibsen/SwiftECC", from: "3.9.0"),
]
SwiftECC requires Swift 5.0. It also requires that the Int and UInt types be 64 bit types.
SwiftECC uses Apple's CryptoKit framework. Therefore, for macOS the version must be at least 10.15,
Expand Down Expand Up @@ -164,7 +166,7 @@ giving:

SwiftECC can read encrypted private key files provided they were encrypted with one of the ciphers AES-128, AES-192 or AES-256 in CBC mode.

<h2 id="basic5"><b>Encryption and Decryption</b></h2>
<h2 id="basic4"><b>Encryption and Decryption</b></h2>
Encryption and decryption is done using the ECIES algorithm based on the AES block cipher using one of
AES-128, AES-192 or AES-256 ciphers, depending on your choice.<br/>
The following cipher block modes are supported:
Expand Down Expand Up @@ -277,7 +279,7 @@ can be decrypted by SwiftECC using EC256r1 with AES128/GCM, EC384r1 with AES256/
giving<br/>

The quick brown fox jumps over the lazy dog!
<h2 id="basic4"><b>AEAD Encryption and Decryption</b></h2>
<h2 id="basic5"><b>AEAD Encryption and Decryption</b></h2>
Authenticated Encryption with Associated Data (AEAD) is implemented with the ChaCha20/Poly1305 algorithm and the AES/GCM algorithm.
Both implementations use Apple's CryptoKit framework, that takes advantage of hardware support for the AES and GCM algorithms.
<h3><b>Example</b></h3>
Expand Down Expand Up @@ -340,8 +342,74 @@ KDF generates 44 bytes.

AES encryption/decryption key = bytes 0 ..< 32<br/>
Nonce = bytes 32 ..< 44<br/>
<h2 id="basic6"><b>HPKE Encryption and Decryption</b></h2>
SwiftECC contains an implementation of the new Hybrid Public Key Encryption (HPKE) standard defined in RFC 9180.
It operates with the concepts of a sender and a recipient. A sender encrypts (or seals) cleartext messages intended for a given recipient,
and a recipient decrypts (or opens) the resulting ciphertext messages. A sender is represented by the Sender class,
and a recipient is represented by the Recipient class. Using them, you can:
<ul>
<li>Create a CipherSuite consisting of a Key Encapsulation Mechanism (KEM), a Key Derivation Function (KDF) and a AEAD Encryption Algorithm (AEAD)</li>
<li>The CipherSuite can encrypt a single plain text message or decrypt a single ciphertext</li>
<li>You can create a Sender instance based on a CipherSuite and use it to encrypt a sequence of plaintext messages</li>
<li>You can create a Recipient instance based on a CipherSuite and use it to decrypt a sequence of ciphertexts</li>
</ul>
<h3><b>Example 1</b></h3>

// Encryption and decryption of a single message in base mode

import SwiftECC

do {
let plainText = Bytes("Hi, there".utf8)
let suite1 = CipherSuite(kem: .X448, kdf: .KDF512, aead: .AESGCM256)
let (recipientPub, recipientPriv) = try suite1.makeKeyPair()
let (encapsulatedKey, cipherText) = try suite1.seal(publicKey: recipientPub, info: [1, 2, 3], pt: plainText, aad: [4, 5, 6])
let decrypted = try suite1.open(privateKey: recipientPriv, info: [1, 2, 3], ct: cipherText, aad: [4, 5, 6], encap: encapsulatedKey)
print(String(bytes: decrypted, encoding: .utf8)!)
} catch {
print("Exception: \(error)")
}

giving:

Hi, there

<h3><b>Example 2</b></h3>

// Encryption and decryption of several messages in authenticated mode

import SwiftECC

do {
let plainText1 = Bytes("Hi, there 1".utf8)
let plainText2 = Bytes("Hi, there 2".utf8)
let plainText3 = Bytes("Hi, there 3".utf8)
let suite2 = CipherSuite(kem: .P384, kdf: .KDF384, aead: .CHACHAPOLY)
let (senderPub, senderPriv) = try suite2.makeKeyPair()
let (recipientPub, recipientPriv) = try suite2.makeKeyPair()
let sender = try Sender(suite: suite2, publicKey: recipientPub, info: [1, 2, 3], authentication: senderPriv)
let cipherText1 = try sender.seal(pt: plainText1, aad: [4, 5])
let cipherText2 = try sender.seal(pt: plainText2, aad: [6, 7])
let cipherText3 = try sender.seal(pt: plainText3, aad: [])

let recipient = try Recipient(suite: suite2, privateKey: recipientPriv, info: [1, 2, 3], authentication: senderPub, encap: sender.encapsulatedKey)
let decrypted1 = try recipient.open(ct: cipherText1, aad: [4, 5])
let decrypted2 = try recipient.open(ct: cipherText2, aad: [6, 7])
let decrypted3 = try recipient.open(ct: cipherText3, aad: [])
print(String(bytes: decrypted1, encoding: .utf8)!)
print(String(bytes: decrypted2, encoding: .utf8)!)
print(String(bytes: decrypted3, encoding: .utf8)!)
} catch {
print("Exception: \(error)")
}

giving:

Hi, there 1
Hi, there 2
Hi, there 3

<h2 id="basic6"><b>Signing and Verifying</b></h2>
<h2 id="basic7"><b>Signing and Verifying</b></h2>
Signing data and verifying signatures is performed using the ECDSA algorithm. It is possible to generate
deterministic signatures as specified in [RFC-6979] by setting the <i>deterministic</i> parameter to <i>true</i> in the sign operation.

Expand Down Expand Up @@ -406,7 +474,7 @@ giving (for example):<br/>

Signature is good

<h2 id="basic7"><b>Secret Key Agreement</b></h2>
<h2 id="basic8"><b>Secret Key Agreement</b></h2>
Given your own private key and another party's public key, you can generate a byte array that can be used as a symmetric encryption key.
The other party can generate the same byte array by using his own private key and your public key.<br/>
SwiftECC supports three mechanisms:
Expand Down Expand Up @@ -519,7 +587,7 @@ To convert SwiftECC keys - e.g. <i>eccPubKey</i>, <i>eccPrivKey</i> - to the cor
let ckPubKey = try P256.KeyAgreement.PublicKey(pemRepresentation: eccPubKey.pem)
let ckPrivKey = try P256.KeyAgreement.PrivateKey(pemRepresentation: eccPrivKey.pem)

<h2 id="basic8"><b>Creating New Domains</b></h2>
<h2 id="basic9"><b>Creating New Domains</b></h2>
You can create your own domains as illustrated by the two examples below.
<h3><b>Example</b></h3>

Expand Down Expand Up @@ -595,7 +663,7 @@ giving<br/>
Integer: 22
Integer: 2

<h2 id="basic9"><b>Elliptic Curve Arithmetic</b></h2>
<h2 id="basic10"><b>Elliptic Curve Arithmetic</b></h2>
SwiftECC implements the common elliptic curve arithmetic operations:
<ul>
<li>Point multiplication</li>
Expand Down Expand Up @@ -659,7 +727,7 @@ The SwiftECC package depends on the ASN1 and BigInt packages

dependencies: [
.package(url: "https://github.com/leif-ibsen/ASN1", from: "2.1.0"),
.package(url: "https://github.com/leif-ibsen/BigInt", from: "1.11.0"),
.package(url: "https://github.com/leif-ibsen/BigInt", from: "1.13.0"),
],

<h2 id="ref"><b>References</b></h2>
Expand All @@ -676,6 +744,7 @@ There are references in the source code where appropriate.
<li>[PKCS#5] - Password-Based Cryptography Specification - Version 2.0, September 2000</li>
<li>[RFC-5869] - HMAC-based Extract-and-Expand Key Derivation Function (HKDF), May 2010</li>
<li>[RFC-6979] - Deterministic Usage of the Digital Signature Algorithm (DSA) and Elliptic Curve Digital Signature Algorithm (ECDSA), August 2013</li>
<li>[RFC-9180] - Hybrid Public Key Encryption, February 2022</li>
<li>[SAVACS] - E. Savacs, C.K. Koc: The Montgomery Modular Inverse - Revisited, July 2000</li>
<li>[SEC 1] - Standards for Efficient Cryptography 1 (SEC 1), Certicom Corp. 2009</li>
<li>[SEC 2] - Standards for Efficient Cryptography 2 (SEC 2), Certicom Corp. 2010</li>
Expand Down
6 changes: 3 additions & 3 deletions Sources/SwiftECC/Exception.swift
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,9 @@ public enum ECException: Error, CustomStringConvertible {
/// Not enough input to decrypt
case notEnoughInput

/// Point not on curve
case notOnCurve

/// Padding is wrong
case padding

Expand All @@ -83,7 +86,4 @@ public enum ECException: Error, CustomStringConvertible {
/// Unknown domain OID
case unknownOid

/// Point not on curve
case notOnCurve

}
51 changes: 51 additions & 0 deletions Sources/SwiftECC/HPKE/AEAD.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
//
// AEAD.swift
// SwiftHPKETest
//
// Created by Leif Ibsen on 22/06/2023.
//

import CryptoKit

struct AEADStructure {

let aead: AEAD

init(_ aead: AEAD) {
self.aead = aead
}

func seal(_ key: Bytes, _ nonce: Bytes, _ aad: Bytes, _ pt: Bytes) throws -> Bytes {
switch self.aead {
case .AESGCM128, .AESGCM256:
let cryptoKitKey = CryptoKit.SymmetricKey(data: key)
let cryptoKitNonce = try CryptoKit.AES.GCM.Nonce(data: nonce)
let sealbox = try CryptoKit.AES.GCM.seal(pt, using: cryptoKitKey, nonce: cryptoKitNonce, authenticating: aad)
return Bytes(sealbox.ciphertext + sealbox.tag)

case .CHACHAPOLY:
let cryptoKitKey = CryptoKit.SymmetricKey(data: key)
let cryptoKitNonce = try CryptoKit.ChaChaPoly.Nonce(data: nonce)
let sealbox = try CryptoKit.ChaChaPoly.seal(pt, using: cryptoKitKey, nonce: cryptoKitNonce, authenticating: aad)
return Bytes(sealbox.ciphertext + sealbox.tag)

case .EXPORTONLY:
throw HPKEException.exportOnlyError
}
}

func open(_ key: Bytes, _ aad: Bytes, _ ct: Bytes) throws -> Bytes {
let cryptoKitKey = CryptoKit.SymmetricKey(data: key)
switch self.aead {
case .AESGCM128, .AESGCM256:
return try Bytes(CryptoKit.AES.GCM.open(CryptoKit.AES.GCM.SealedBox(combined: ct), using: cryptoKitKey, authenticating: aad))

case .CHACHAPOLY:
return try Bytes(CryptoKit.ChaChaPoly.open(ChaChaPoly.SealedBox(combined: ct), using: cryptoKitKey, authenticating: aad))

case .EXPORTONLY:
throw HPKEException.exportOnlyError
}
}

}
Loading

0 comments on commit 2b67250

Please sign in to comment.