Skip to content

Commit

Permalink
Release 2.3.0
Browse files Browse the repository at this point in the history
  • Loading branch information
leif-ibsen committed Feb 7, 2024
1 parent 9d9f946 commit c0e33a5
Show file tree
Hide file tree
Showing 276 changed files with 370 additions and 359 deletions.
20 changes: 10 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,20 +1,20 @@
<h2><b>SwiftHPKE</b></h2>
## SwiftHPKE

SwiftHPKE implements the Hybrid Public Key Encryption standard as defined in RFC 9180
including all four modes of operation:
<ul>
<li>Base mode</li>
<li>Preshared key mode</li>
<li>Authenticated mode</li>
<li>Authenticated, preshared key mode</li>
</ul>
SwiftHPKE requires Swift 5.0. It also requires that the Int and UInt types be 64 bit types.

Its documentation is build with Apple's DocC tool and published on GitHub Pages at this location
* Base mode
* Preshared key mode
* Authenticated mode
* Authenticated, preshared key mode

SwiftHPKE requires Swift 5.0. It also requires that the `Int` and `UInt` types be 64 bit types.

Its documentation is build with the DocC tool and published on GitHub Pages at this location:

https://leif-ibsen.github.io/SwiftHPKE/documentation/swifthpke

The documentation is also available in the <i>SwiftHPKE.doccarchive</i> file.
The documentation is also available in the *SwiftHPKE.doccarchive* file.



Expand Down
6 changes: 2 additions & 4 deletions Sources/SwiftHPKE/AEAD.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,10 @@

import CryptoKit

///
/// AEAD Encryption Algorithms
///
/// AEAD encryption algorithms
public enum AEAD: CustomStringConvertible, CaseIterable {

/// Textual description of *self*
/// Textual description of `self`
public var description: String {
switch self {
case .AESGCM128:
Expand Down
12 changes: 6 additions & 6 deletions Sources/SwiftHPKE/Base64.swift
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ public struct Base64 {
/// - Parameters:
/// - input: Bytes to encode
/// - pem: The PEM header- and footer string
/// - Returns: The Base64 PEM encoding of *input*
/// - Returns: The Base64 PEM encoding of `input`
public static func pemEncode(_ input: Bytes, _ pem: String) -> String {
return "-----BEGIN " + pem + "-----\n" + encode(input, 64) + "\n-----END " + pem + "-----"
}
Expand All @@ -34,8 +34,8 @@ public struct Base64 {
/// - Parameters:
/// - input: String to decode
/// - pem: The expected PEM header- and footer string
/// - Returns: The Base64 PEM decoding of *input*
/// - Throws: A *base64* exception or a *pemStructure* exception if the input is malformed
/// - Returns: The Base64 PEM decoding of `input`
/// - Throws: A `base64` exception or a `pemStructure` exception if the input is malformed
public static func pemDecode(_ input: String, _ pem: String) throws -> Bytes {
let parts = input.components(separatedBy: "-----")
if parts.count != 5 {
Expand All @@ -52,7 +52,7 @@ public struct Base64 {
/// - Parameters:
/// - input: Bytes to encode
/// - linesize: Number of characters per line - 76 is default
/// - Returns: The Base64 encoding of *input*
/// - Returns: The Base64 encoding of `input`
public static func encode(_ input: Bytes, _ linesize: Int = 76) -> String {
var base64 = ""
var i = 0
Expand Down Expand Up @@ -95,8 +95,8 @@ public struct Base64 {
///
/// - Parameters:
/// - input: String to decode
/// - Returns: The Base64 decoding of *input*
/// - Throws: A *base64* exception if the input is malformed
/// - Returns: The Base64 decoding of `input`
/// - Throws: A `base64` exception if the input is malformed
public static func decode(_ input: String) throws -> Bytes {
var bytes: Bytes = []
var eq = 0
Expand Down
44 changes: 23 additions & 21 deletions Sources/SwiftHPKE/CipherSuite.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,11 @@ typealias Limbs = [UInt64]

/// Unsigned 8 bit value
public typealias Byte = UInt8

/// Array of unsigned 8 bit values
public typealias Bytes = [UInt8]

/// The CipherSuite structure
public struct CipherSuite: CustomStringConvertible {

let kemStructure: KEMStructure
Expand Down Expand Up @@ -94,26 +96,26 @@ public struct CipherSuite: CustomStringConvertible {

// MARK: Computed properties

/// A textual representation of *self*
/// A textual representation of `self`
public var description: String { get { return "(KEM:" + self.kem.description + " KDF:" + self.kdf.description + " AEAD:" + self.aead.description + ")"} }


// MARK: Instance Methods

/// Derives a public- and private HPKE key pair for *self* based on keying material
/// Derives a public- and private HPKE key pair for `self` based on keying material
///
/// - Parameters:
/// - ikm: The keying material
/// - Returns: The public key and private key pair
/// - Throws: A *derivedKeyError* exception in extremely rare cases
/// - Throws: A `derivedKeyError` exception in extremely rare cases
public func deriveKeyPair(ikm: Bytes) throws -> (PublicKey, PrivateKey) {
return try self.kemStructure.deriveKeyPair(ikm)
}

/// Generates a public- and private HPKE key pair for *self*
/// Generates a public- and private HPKE key pair for `self`
///
/// - Returns: The public key and private key pair
/// - Throws: A *derivedKeyError* exception in extremely rare cases
/// - Throws: A `derivedKeyError` exception in extremely rare cases
public func makeKeyPair() throws -> (PublicKey, PrivateKey) {
var ikm = Bytes(repeating: 0, count: self.kemStructure.Nsk)
KEMStructure.randomBytes(&ikm)
Expand All @@ -131,7 +133,7 @@ public struct CipherSuite: CustomStringConvertible {
/// - pt: The plain text to encrypt
/// - aad: The associated data
/// - Returns: The encapsulated key and cipher text
/// - Throws: An exception if *publicKey* does not match *self* or the encryption fails or *self.aead* is EXPORTONLY
/// - Throws: An exception if `publicKey` does not match `self` or the encryption fails or `self.aead` is EXPORTONLY
public func seal(publicKey: PublicKey, info: Bytes, pt: Bytes, aad: Bytes) throws -> (encap: Bytes, ct: Bytes) {
let sender = try Sender(suite: self, publicKey: publicKey, info: info)
return (sender.encapsulatedKey, try sender.seal(pt: pt, aad: aad))
Expand All @@ -146,7 +148,7 @@ public struct CipherSuite: CustomStringConvertible {
/// - aad: The associated data
/// - encap: The encapsulated key
/// - Returns: The plain text
/// - Throws: An exception if one of the keys does not match *self* or the decryption fails or *self.aead* is EXPORTONLY
/// - Throws: An exception if one of the keys does not match `self` or the decryption fails or `self.aead` is EXPORTONLY
public func open(privateKey: PrivateKey, info: Bytes, ct: Bytes, aad: Bytes, encap: Bytes) throws -> Bytes {
let recipient = try Recipient(suite: self, privateKey: privateKey, info: info, encap: encap)
return try recipient.open(ct: ct, aad: aad)
Expand All @@ -160,7 +162,7 @@ public struct CipherSuite: CustomStringConvertible {
/// - context: The export context
/// - L: The length of the export secret
/// - Returns: The encapsulated key and export secret
/// - Throws: An exception if *publicKey* does not match *self* or L is negative or too large
/// - Throws: An exception if `publicKey` does not match `self` or L is negative or too large

public func sendExport(publicKey: PublicKey, info: Bytes, context: Bytes, L: Int) throws -> (encapsulatedKey: Bytes, secret: Bytes) {
try self.checkExportSize(L)
Expand All @@ -179,7 +181,7 @@ public struct CipherSuite: CustomStringConvertible {
/// - L: The length of the export secret
/// - encap: The encapsulated key
/// - Returns: The export secret
/// - Throws: An exception if one of the keys does not match *self* or L is negative or too large
/// - Throws: An exception if one of the keys does not match `self` or L is negative or too large
public func receiveExport(privateKey: PrivateKey, info: Bytes, context: Bytes, L: Int, encap: Bytes) throws -> Bytes {
try self.checkExportSize(L)
try self.checkPrivKey(privateKey)
Expand All @@ -201,7 +203,7 @@ public struct CipherSuite: CustomStringConvertible {
/// - pt: The plain text to encrypt
/// - aad: The associated data
/// - Returns: The encapsulted key and cipher text
/// - Throws: An exception if *publicKey* does not match *self* or the encryption fails or the *psk* parameters are inconsistent or *self.aead* is EXPORTONLY
/// - Throws: An exception if `publicKey` does not match `self` or the encryption fails or the `psk` parameters are inconsistent or `self.aead` is EXPORTONLY
public func seal(publicKey: PublicKey, info: Bytes, psk: Bytes, pskId: Bytes, pt: Bytes, aad: Bytes) throws -> (encap: Bytes, ct: Bytes) {
let sender = try Sender(suite: self, publicKey: publicKey, info: info, psk: psk, pskId: pskId)
return (sender.encapsulatedKey, try sender.seal(pt: pt, aad: aad))
Expand All @@ -218,7 +220,7 @@ public struct CipherSuite: CustomStringConvertible {
/// - aad: The associated data
/// - encap: The encapsulated key
/// - Returns: The plain text
/// - Throws: An exception if one of the keys does not match *self* or the decryption fails or the *psk* parameters are inconsistent or *self.aead* is EXPORTONLY
/// - Throws: An exception if one of the keys does not match `self` or the decryption fails or the `psk` parameters are inconsistent or `self.aead` is EXPORTONLY
public func open(privateKey: PrivateKey, info: Bytes, psk: Bytes, pskId: Bytes, ct: Bytes, aad: Bytes, encap: Bytes) throws -> Bytes {
let recipient = try Recipient(suite: self, privateKey: privateKey, info: info, psk: psk, pskId: pskId, encap: encap)
return try recipient.open(ct: ct, aad: aad)
Expand All @@ -234,7 +236,7 @@ public struct CipherSuite: CustomStringConvertible {
/// - psk: The preshared key
/// - pskId: The preshared key id
/// - Returns: The encapsulated key and export secret
/// - Throws: An exception if *publicKey* does not match *self* or the *psk* parameters are inconsistent or L is negative or too large
/// - Throws: An exception if `publicKey` does not match `self` or the `psk` parameters are inconsistent or L is negative or too large
public func sendExport(publicKey: PublicKey, info: Bytes, context: Bytes, L: Int, psk: Bytes, pskId: Bytes) throws -> (encapsulatedKey: Bytes, secret: Bytes) {
try self.checkExportSize(L)
try self.checkPubKey(publicKey)
Expand All @@ -254,7 +256,7 @@ public struct CipherSuite: CustomStringConvertible {
/// - pskId: The preshared key id
/// - encap: The encapsulated key
/// - Returns: The export secret
/// - Throws: An exception if one of the keys does not match *self* or the *psk* parameters are inconsistent or L is negative or too large
/// - Throws: An exception if one of the keys does not match `self` or the `psk` parameters are inconsistent or L is negative or too large
public func receiveExport(privateKey: PrivateKey, info: Bytes, context: Bytes, L: Int, psk: Bytes, pskId: Bytes, encap: Bytes) throws -> Bytes {
try self.checkExportSize(L)
try self.checkPrivKey(privateKey)
Expand All @@ -275,7 +277,7 @@ public struct CipherSuite: CustomStringConvertible {
/// - pt: The plain text to encrypt
/// - aad: The associated data
/// - Returns: The encapsulted key and cipher text
/// - Throws: An exception if one of the keys does not match *self* or the encryption fails or *self.aead* is EXPORTONLY
/// - Throws: An exception if one of the keys does not match `self` or the encryption fails or `self.aead` is EXPORTONLY
public func seal(publicKey: PublicKey, info: Bytes, authentication: PrivateKey, pt: Bytes, aad: Bytes) throws -> (encap: Bytes, ct: Bytes) {
let sender = try Sender(suite: self, publicKey: publicKey, info: info, authentication: authentication)
return (sender.encapsulatedKey, try sender.seal(pt: pt, aad: aad))
Expand All @@ -291,7 +293,7 @@ public struct CipherSuite: CustomStringConvertible {
/// - aad: The associated data
/// - encap: The encapsulated key
/// - Returns: The plain text
/// - Throws: An exception if one of the keys does not match *self* or the decryption fails or *self.aead* is EXPORTONLY
/// - Throws: An exception if one of the keys does not match `self` or the decryption fails or `self.aead` is EXPORTONLY
public func open(privateKey: PrivateKey, info: Bytes, authentication: PublicKey, ct: Bytes, aad: Bytes, encap: Bytes) throws -> Bytes {
let recipient = try Recipient(suite: self, privateKey: privateKey, info: info, authentication: authentication, encap: encap)
return try recipient.open(ct: ct, aad: aad)
Expand All @@ -306,7 +308,7 @@ public struct CipherSuite: CustomStringConvertible {
/// - L: The length of the export secret
/// - authentication: The sender private key
/// - Returns: The encapsulated key and export secret
/// - Throws: An exception if one of the keys does not match *self* or L is negative or too large
/// - Throws: An exception if one of the keys does not match `self` or L is negative or too large
public func sendExport(publicKey: PublicKey, info: Bytes, context: Bytes, L: Int, authentication: PrivateKey) throws -> (encapsulatedKey: Bytes, secret: Bytes) {
try self.checkExportSize(L)
try self.checkPubKey(publicKey)
Expand All @@ -328,7 +330,7 @@ public struct CipherSuite: CustomStringConvertible {
/// - pskId: The preshared key id
/// - encap: The encapsulated key
/// - Returns: The export secret
/// - Throws: An exception if one of the keys does not match *self* or L is negative or too large
/// - Throws: An exception if one of the keys does not match `self` or L is negative or too large
public func receiveExport(privateKey: PrivateKey, info: Bytes, context: Bytes, L: Int, authentication: PublicKey, encap: Bytes) throws -> Bytes {
try self.checkExportSize(L)
try self.checkPrivKey(privateKey)
Expand All @@ -352,7 +354,7 @@ public struct CipherSuite: CustomStringConvertible {
/// - pt: The plain text to encrypt
/// - aad: The associated data
/// - Returns: The encapsulted key and cipher text
/// - Throws: An exception if one of the keys does not match *self* or the encryption fails or the *psk* parameters are inconsistent or *self.aead* is EXPORTONLY
/// - Throws: An exception if one of the keys does not match `self` or the encryption fails or the `psk` parameters are inconsistent or `self.aead` is EXPORTONLY
public func seal(publicKey: PublicKey, info: Bytes, authentication: PrivateKey, psk: Bytes, pskId: Bytes, pt: Bytes, aad: Bytes) throws -> (encap: Bytes, ct: Bytes) {
let sender = try Sender(suite: self, publicKey: publicKey, info: info, authentication: authentication, psk: psk, pskId: pskId)
return (sender.encapsulatedKey, try sender.seal(pt: pt, aad: aad))
Expand All @@ -370,7 +372,7 @@ public struct CipherSuite: CustomStringConvertible {
/// - aad: The associated data
/// - encap: The encapsulated key
/// - Returns: The plain text
/// - Throws: An exception if one of the keys does not match *self* or the decryption fails or the *psk* parameters are inconsistent or *self.aead* is EXPORTONLY
/// - Throws: An exception if one of the keys does not match `self` or the decryption fails or the `psk` parameters are inconsistent or `self.aead` is EXPORTONLY
public func open(privateKey: PrivateKey, info: Bytes, authentication: PublicKey, psk: Bytes, pskId: Bytes, ct: Bytes, aad: Bytes, encap: Bytes) throws -> Bytes {
let recipient = try Recipient(suite: self, privateKey: privateKey, info: info, authentication: authentication, psk: psk, pskId: pskId, encap: encap)
return try recipient.open(ct: ct, aad: aad)
Expand All @@ -387,7 +389,7 @@ public struct CipherSuite: CustomStringConvertible {
/// - psk: The preshared key
/// - pskId: The preshared key id
/// - Returns: The encapsulated key and export secret
/// - Throws: An exception if one of the keys does not match *self* or the *psk* parameters are inconsistent or L is negative or too large
/// - Throws: An exception if one of the keys does not match `self` or the `psk` parameters are inconsistent or L is negative or too large
public func sendExport(publicKey: PublicKey, info: Bytes, context: Bytes, L: Int, authentication: PrivateKey, psk: Bytes, pskId: Bytes) throws -> (encapsulatedKey: Bytes, secret: Bytes) {
try self.checkExportSize(L)
try self.checkPubKey(publicKey)
Expand All @@ -409,7 +411,7 @@ public struct CipherSuite: CustomStringConvertible {
/// - pskId: The preshared key id
/// - encap: The encapsulated key
/// - Returns: The export secret
/// - Throws: An exception if one of the keys does not match *self* or the *psk* parameters are inconsistent or L is negative or too large
/// - Throws: An exception if one of the keys does not match `self` or the `psk` parameters are inconsistent or L is negative or too large
public func receiveExport(privateKey: PrivateKey, info: Bytes, context: Bytes, L: Int, authentication: PublicKey, psk: Bytes, pskId: Bytes, encap: Bytes) throws -> Bytes {
try self.checkExportSize(L)
try self.checkPrivKey(privateKey)
Expand Down
4 changes: 1 addition & 3 deletions Sources/SwiftHPKE/Exception.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,10 @@
// Created by Leif Ibsen on 18/02/2020.
//

///
/// HPKE exceptions
///
public enum HPKEException: Error, CustomStringConvertible {

/// Textual description of *self*
/// Textual description of `self`
public var description: String {
switch self {
case .base64:
Expand Down
6 changes: 2 additions & 4 deletions Sources/SwiftHPKE/KDF.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,10 @@

import Digest

///
/// Key Derivation Functions
///
/// Key derivation functions
public enum KDF: CustomStringConvertible, CaseIterable {

/// Textual description of *self*
/// Textual description of `self`
public var description: String {
switch self {
case .KDF256:
Expand Down
6 changes: 2 additions & 4 deletions Sources/SwiftHPKE/KEM.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,10 @@
import Foundation
import BigInt

///
/// Key Encapsulation Mechanisms
///
/// Key encapsulation mechanisms
public enum KEM: CustomStringConvertible, CaseIterable {

/// Textual description of *self*
/// Textual description of `self`
public var description: String {
switch self {
case .P256:
Expand Down
13 changes: 7 additions & 6 deletions Sources/SwiftHPKE/PrivateKey.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import ASN1
import BigInt

/// The PrivateKey structure
public struct PrivateKey: CustomStringConvertible, Equatable {

let kem: KEM
Expand All @@ -20,7 +21,7 @@ public struct PrivateKey: CustomStringConvertible, Equatable {
/// - Parameters:
/// - kem: The key type
/// - bytes: The key bytes
/// - Throws: An exception if *bytes* has wrong size for the key type
/// - Throws: An exception if `bytes` has wrong size for the key type
public init(kem: KEM, bytes: Bytes) throws {
self.kem = kem
switch self.kem {
Expand Down Expand Up @@ -160,7 +161,7 @@ public struct PrivateKey: CustomStringConvertible, Equatable {

// MARK: Computed Properties

/// The ASN1 encoding of *self*
/// The ASN1 encoding of `self`
public var asn1: ASN1 { get { do {
switch self.kem {
case .P256:
Expand Down Expand Up @@ -208,11 +209,11 @@ public struct PrivateKey: CustomStringConvertible, Equatable {
.add(ASN1OctetString(ASN1OctetString(self.bytes).encode()))
}
} } }
/// The DER encoding of *self*
/// The DER encoding of `self`
public var der: Bytes { get { return self.asn1.encode() } }
/// The PEM base 64 encoding of *self*
/// The PEM base 64 encoding of `self`
public var pem: String { get { return Base64.pemEncode(self.der, "PRIVATE KEY") } }
/// A textual representation of the ASN1 encoding of *self*
/// A textual representation of the ASN1 encoding of `self`
public var description: String { get { return self.asn1.description } }


Expand All @@ -223,7 +224,7 @@ public struct PrivateKey: CustomStringConvertible, Equatable {
/// - Parameters:
/// - key1: a private key
/// - key2: a private key
/// - Returns: *true* if key1 and key2 are equal, *false* otherwise
/// - Returns: `true` if key1 and key2 are equal, `false` otherwise
public static func == (key1: PrivateKey, key2: PrivateKey) -> Bool {
return key1.kem == key2.kem && key1.bytes == key2.bytes
}
Expand Down
Loading

0 comments on commit c0e33a5

Please sign in to comment.