Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update to CryptoKit 2023 final API #199

Merged
merged 2 commits into from
Sep 13, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions Sources/Crypto/HPKE/Ciphersuite/HPKE-KexKeyDerivation.swift
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,13 @@ extension HPKE {
pkRm: Data, pkSm: Data? = nil, kem: HPKE.KEM, kdf: HPKE.KDF) -> SymmetricKey {
var suiteID = suiteIDLabel
suiteID.append(kem.identifier)
#if !CRYPTO_IN_SWIFTPM_FORCE_BUILD_API
return CryptoKit.ExtractAndExpand(zz: dh, kemContext: kemContext(enc: enc, pkRm: pkRm, pkSm: pkSm),
suiteID: suiteID, kem: kem, kdf: kdf)
#else
return Crypto.ExtractAndExpand(zz: dh, kemContext: kemContext(enc: enc, pkRm: pkRm, pkSm: pkSm),
suiteID: suiteID, kem: kem, kdf: kdf)
#endif
}

static func kemContext(enc: Data, pkRm: Data, pkSm: Data? = nil) -> Data {
Expand Down
4 changes: 2 additions & 2 deletions Sources/Crypto/HPKE/Ciphersuite/HPKE-LabeledExtract.swift
Original file line number Diff line number Diff line change
Expand Up @@ -41,12 +41,12 @@ internal func LabeledExtract(salt: Data?, label: Data, ikm: ContiguousBytes?, su
return kdf.extract(salt: salt ?? Data(), ikm: SymmetricKey(data: labeled_ikm))
}

internal func LabeledExpand(prk: SymmetricKey, label: Data, info: Data, outputByteCount: UInt16, suiteID: Data, kdf: HPKE.KDF) -> SymmetricKey {
internal func LabeledExpand<Info: DataProtocol>(prk: SymmetricKey, label: Data, info: Info, outputByteCount: UInt16, suiteID: Data, kdf: HPKE.KDF) -> SymmetricKey {
var labeled_info = I2OSP(value: Int(outputByteCount), outputByteCount: 2)
labeled_info.append(protocolLabel)
labeled_info.append(suiteID)
labeled_info.append(label)
labeled_info.append(info)
labeled_info.append(contentsOf: info)
return kdf.expand(prk: prk, info: labeled_info, outputByteCount: Int(outputByteCount))
}

Expand Down
10 changes: 8 additions & 2 deletions Sources/Crypto/HPKE/Ciphersuite/KEM/Conformances/DHKEM.swift
Original file line number Diff line number Diff line change
Expand Up @@ -56,21 +56,27 @@ extension HPKE {
let kem: HPKE.KEM
let key: DHPK

#if !CRYPTO_IN_SWIFTPM_FORCE_BUILD_API
typealias EncapsulationResult = CryptoKit.KEM.EncapsulationResult
#else
typealias EncapsulationResult = Crypto.KEM.EncapsulationResult
#endif

init(_ publicKey: DHPK, kem: HPKE.KEM) throws {
// TODO: Validate Ciphersuite Mismatches
_ = try publicKey.hpkeRepresentation(kem: kem)
self.key = publicKey
self.kem = kem
}

func encapsulate() throws -> Crypto.KEM.EncapsulationResult {
func encapsulate() throws -> EncapsulationResult {
let ephemeralKeys = DHPK.EphemeralPrivateKey()
let dh =
try ephemeralKeys.sharedSecretFromKeyAgreement(with: key)

let enc = try! ephemeralKeys.publicKey.hpkeRepresentation(kem: kem)
let selfRepresentation = try self.key.hpkeRepresentation(kem: kem)
return Crypto.KEM.EncapsulationResult(sharedSecret: HPKE.KexUtils.ExtractAndExpand(dh: dh,
return EncapsulationResult(sharedSecret: HPKE.KexUtils.ExtractAndExpand(dh: dh,
enc: enc,
pkRm: selfRepresentation,
kem: kem,
Expand Down
36 changes: 34 additions & 2 deletions Sources/Crypto/HPKE/HPKE.swift
Original file line number Diff line number Diff line change
Expand Up @@ -60,11 +60,27 @@ extension HPKE {
private var context: Context
/// The encapsulated symmetric key that the recipient uses to decrypt messages.
public let encapsulatedKey: Data

/// The exporter secret.
public var exporterSecret: SymmetricKey {
internal var exporterSecret: SymmetricKey {
return context.keySchedule.exporterSecret
}

/// Exports a secret given domain-separation context and the desired output length.
/// - Parameters:
/// - context: Application-specific information providing context on the use of this key.
/// - outputByteCount: The desired length of the exported secret.
/// - Returns: The exported secret.
public func exportSecret<Context: DataProtocol>(context: Context, outputByteCount: Int) throws -> SymmetricKey {
precondition(outputByteCount > 0);
return LabeledExpand(prk: self.exporterSecret,
label: Data("sec".utf8),
info: context,
outputByteCount: UInt16(outputByteCount),
suiteID: self.context.keySchedule.ciphersuite.identifier,
kdf: self.context.keySchedule.ciphersuite.kdf)
}

/// Creates a sender in base mode.
///
/// The `Sender` encrypts messages in base mode with a symmetric encryption key it derives using a key derivation function (KDF).
Expand Down Expand Up @@ -180,11 +196,27 @@ extension HPKE {
public struct Recipient {

private var context: Context

/// The exporter secret.
public var exporterSecret: SymmetricKey {
internal var exporterSecret: SymmetricKey {
return context.keySchedule.exporterSecret
}

/// Exports a secret given domain-separation context and the desired output length.
/// - Parameters:
/// - context: Application-specific information providing context on the use of this key.
/// - outputByteCount: The desired length of the exported secret.
/// - Returns: The exported secret.
public func exportSecret<Context: DataProtocol>(context: Context, outputByteCount: Int) throws -> SymmetricKey {
precondition(outputByteCount > 0);
return LabeledExpand(prk: self.exporterSecret,
label: Data("sec".utf8),
info: context,
outputByteCount: UInt16(outputByteCount),
suiteID: self.context.keySchedule.ciphersuite.identifier,
kdf: self.context.keySchedule.ciphersuite.kdf)
}

/// Creates a recipient in base mode.
///
/// The `Receiver` decrypts messages in base mode using the encapsulated key with the key schedule information (`info` data).
Expand Down
41 changes: 40 additions & 1 deletion Sources/Crypto/Util/SecureBytes.swift
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@
#else
import Foundation

private let emptyStorage:SecureBytes.Backing = SecureBytes.Backing.createEmpty()

struct SecureBytes {
@usableFromInline
var backing: Backing
Expand All @@ -27,7 +29,11 @@ struct SecureBytes {

@usableFromInline
init(count: Int) {
self.backing = SecureBytes.Backing.create(randomBytes: count)
if count == 0 {
self.backing = emptyStorage
} else {
self.backing = SecureBytes.Backing.create(randomBytes: count)
}
}

init<D: ContiguousBytes>(bytes: D) {
Expand Down Expand Up @@ -161,6 +167,20 @@ extension SecureBytes: RangeReplaceableCollection {
self.backing.replaceSubrangeFittingWithinCapacity(offsetRange, with: newElements)
}
}

// The default implementation of this from RangeReplaceableCollection can't take advantage of `ContiguousBytes`, so we override it here
@inlinable
public mutating func append<Elements: Sequence>(contentsOf newElements: Elements) where Elements.Element == UInt8 {
let done:Void? = newElements.withContiguousStorageIfAvailable {
replaceSubrange(endIndex..<endIndex, with: $0)
}

if done == nil {
for element in newElements {
append(element)
}
}
}
}

// MARK: - ContiguousBytes conformance
Expand All @@ -178,6 +198,11 @@ extension SecureBytes: ContiguousBytes {

return try self.backing.withUnsafeMutableBytes(body)
}

@inlinable
func withContiguousStorageIfAvailable<R>(_ body: (UnsafeBufferPointer<UInt8>) throws -> R) rethrows -> R? {
return try self.backing.withContiguousStorageIfAvailable(body)
}
}

// MARK: - DataProtocol conformance
Expand Down Expand Up @@ -223,6 +248,12 @@ extension SecureBytes {

@usableFromInline
internal class Backing: ManagedBuffer<BackingHeader, UInt8> {

@usableFromInline
class func createEmpty() -> Backing {
return Backing.create(minimumCapacity: 0, makingHeaderWith: { _ in BackingHeader(count: 0, capacity: 0) }) as! Backing
}

@usableFromInline
class func create(capacity: Int) -> Backing {
let capacity = Int(UInt32(capacity).nextPowerOf2ClampedToMax())
Expand Down Expand Up @@ -414,6 +445,14 @@ extension SecureBytes.Backing: ContiguousBytes {
return try body(UnsafeMutableRawBufferPointer(start: elementsPtr, count: capacity))
}
}

func withContiguousStorageIfAvailable<R>(_ body: (UnsafeBufferPointer<UInt8>) throws -> R) rethrows -> R? {
let count = self.count

return try self.withUnsafeMutablePointerToElements { elementsPtr in
return try body(UnsafeBufferPointer(start: elementsPtr, count: count))
}
}
}

extension UInt32 {
Expand Down