diff --git a/README.md b/README.md index 9a72b1c3..d8f93421 100644 --- a/README.md +++ b/README.md @@ -130,10 +130,14 @@ SemVer and Swift Crypto's Public API guarantees should result in a working progr Swift Crypto 2.0.0 was released in September 2021. The only breaking change between Swift Crypto 2.0.0 and 1.0.0 was the addition of new cases in the `CryptoKitError` enumeration. For most users, then, it's safe to depend on either the 1.0.0 _or_ 2.0.0 series of releases. +Swift Crypto 3.0.0 was released in September 2023. The only breaking change between Swift Crypto 3.0.0 and 2.0.0 was the addition of new cases in the `CryptoKitError` enumeration. For most users, then, it's safe to depend on either the 1.0.0 _or_ 2.0.0 _or_ 3.0.0 series of releases. + +Swift Crypto 4.0.0 was released in October 2024. The only breaking change was the removal of the non-functional setters for `blockByteSize` on the hash functions, which triggered a `fatalError` if they were ever called. For most users, then, it is safe to depend on the entire range from 1.0.0 to 4.0.0 inclusive. + To do so, please use the following dependency in your `Package.swift`: ```swift -.package(url: "https://github.com/apple/swift-crypto.git", "1.0.0" ..< "3.0.0"), +.package(url: "https://github.com/apple/swift-crypto.git", "1.0.0" ..< "5.0.0"), ``` ### Developing Swift Crypto on macOS diff --git a/Sources/Crypto/AEADs/AES/GCM/AES-GCM.swift b/Sources/Crypto/AEADs/AES/GCM/AES-GCM.swift index d122556e..b287a8b6 100644 --- a/Sources/Crypto/AEADs/AES/GCM/AES-GCM.swift +++ b/Sources/Crypto/AEADs/AES/GCM/AES-GCM.swift @@ -14,14 +14,17 @@ #if CRYPTO_IN_SWIFTPM && !CRYPTO_IN_SWIFTPM_FORCE_BUILD_API @_exported import CryptoKit #else -#if !CRYPTO_IN_SWIFTPM_FORCE_BUILD_API +#if (!CRYPTO_IN_SWIFTPM_FORCE_BUILD_API) || CRYPTOKIT_NO_ACCESS_TO_FOUNDATION typealias AESGCMImpl = CoreCryptoGCMImpl -import Security #else typealias AESGCMImpl = OpenSSLAESGCMImpl #endif +#if CRYPTOKIT_NO_ACCESS_TO_FOUNDATION +import SwiftSystem +#else import Foundation +#endif extension AES { /// The Advanced Encryption Standard (AES) Galois Counter Mode (GCM) cipher diff --git a/Sources/Crypto/AEADs/ChachaPoly/ChaChaPoly.swift b/Sources/Crypto/AEADs/ChachaPoly/ChaChaPoly.swift index 5b180f60..f21b48cd 100644 --- a/Sources/Crypto/AEADs/ChachaPoly/ChaChaPoly.swift +++ b/Sources/Crypto/AEADs/ChachaPoly/ChaChaPoly.swift @@ -14,14 +14,18 @@ #if CRYPTO_IN_SWIFTPM && !CRYPTO_IN_SWIFTPM_FORCE_BUILD_API @_exported import CryptoKit #else -#if !CRYPTO_IN_SWIFTPM_FORCE_BUILD_API +#if (!CRYPTO_IN_SWIFTPM_FORCE_BUILD_API) || CRYPTOKIT_NO_ACCESS_TO_FOUNDATION typealias ChaChaPolyImpl = CoreCryptoChaChaPolyImpl -import Security #else typealias ChaChaPolyImpl = OpenSSLChaChaPolyImpl #endif +#if CRYPTOKIT_NO_ACCESS_TO_FOUNDATION +import SwiftSystem +#else import Foundation +#endif + /// An implementation of the ChaCha20-Poly1305 cipher. public enum ChaChaPoly: Cipher { diff --git a/Sources/Crypto/AEADs/Cipher.swift b/Sources/Crypto/AEADs/Cipher.swift index 62cf4639..ceadb60c 100644 --- a/Sources/Crypto/AEADs/Cipher.swift +++ b/Sources/Crypto/AEADs/Cipher.swift @@ -14,7 +14,13 @@ #if CRYPTO_IN_SWIFTPM && !CRYPTO_IN_SWIFTPM_FORCE_BUILD_API @_exported import CryptoKit #else + +#if CRYPTOKIT_NO_ACCESS_TO_FOUNDATION +import SwiftSystem +#else import Foundation +#endif + protocol AEADSealedBox { associatedtype Nonce: Sequence diff --git a/Sources/Crypto/AEADs/Nonces.swift b/Sources/Crypto/AEADs/Nonces.swift index 9837275e..e92dadb4 100644 --- a/Sources/Crypto/AEADs/Nonces.swift +++ b/Sources/Crypto/AEADs/Nonces.swift @@ -14,11 +14,18 @@ #if CRYPTO_IN_SWIFTPM && !CRYPTO_IN_SWIFTPM_FORCE_BUILD_API @_exported import CryptoKit #else +#if CRYPTOKIT_NO_ACCESS_TO_FOUNDATION +import SwiftSystem +#else import Foundation +#endif // MARK: - Generated file, do NOT edit // any edits of this file WILL be overwritten and thus discarded // see section `gyb` in `README` for details. + + + // MARK: - AES.GCM + Nonce extension AES.GCM { /// A value used once during a cryptographic operation and then discarded. @@ -47,8 +54,8 @@ extension AES.GCM { /// ``init()`` method to instead create a random nonce. /// /// - Parameters: - /// - data: A 12-byte data representation of the nonce. The initializer throws an - /// error if the data has a length other than 12 bytes. +/// - data: A data representation of the nonce. +/// The initializer throws an error if the data has a length smaller than 12 bytes. public init(data: D) throws { if data.count < AES.GCM.defaultNonceByteCount { throw CryptoKitError.incorrectParameterSize @@ -109,8 +116,8 @@ extension ChaChaPoly { /// ``init()`` method to instead create a random nonce. /// /// - Parameters: - /// - data: A 12-byte data representation of the nonce. The initializer throws an - /// error if the data has a length other than 12 bytes. +/// - data: A 12-byte data representation of the nonce. +/// The initializer throws an error if the data isn't 12 bytes long. public init(data: D) throws { if data.count != ChaChaPoly.nonceByteCount { throw CryptoKitError.incorrectParameterSize diff --git a/Sources/Crypto/AEADs/Nonces.swift.gyb b/Sources/Crypto/AEADs/Nonces.swift.gyb index 91dd918a..5e73ed0e 100644 --- a/Sources/Crypto/AEADs/Nonces.swift.gyb +++ b/Sources/Crypto/AEADs/Nonces.swift.gyb @@ -14,18 +14,31 @@ #if CRYPTO_IN_SWIFTPM && !CRYPTO_IN_SWIFTPM_FORCE_BUILD_API @_exported import CryptoKit #else +#if CRYPTOKIT_NO_ACCESS_TO_FOUNDATION +import SwiftSystem +#else import Foundation +#endif // MARK: - Generated file, do NOT edit // any edits of this file WILL be overwritten and thus discarded // see section `gyb` in `README` for details. + %{ -ciphers = [{"name": "AES.GCM", "recommendedNonceSize": "AES.GCM.defaultNonceByteCount", "nonceValidation": "< AES.GCM.defaultNonceByteCount"},{"name": "ChaChaPoly", "recommendedNonceSize": "ChaChaPoly.nonceByteCount", "nonceValidation": "!= ChaChaPoly.nonceByteCount"}] +ciphers = [{"name": "AES.GCM", "recommendedNonceSize": "AES.GCM.defaultNonceByteCount", "nonceValidation": "< AES.GCM.defaultNonceByteCount", "dataDescription": "/// - data: A data representation of the nonce.\n/// The initializer throws an error if the data has a length smaller than 12 bytes."}] + +if "NO_CHACHAPOLY" in globals(): + pass +else: + ciphers.append({"name": "ChaChaPoly", "recommendedNonceSize": "ChaChaPoly.nonceByteCount", "nonceValidation": "!= ChaChaPoly.nonceByteCount", "dataDescription": "/// - data: A 12-byte data representation of the nonce.\n/// The initializer throws an error if the data isn't 12 bytes long."}) }% + + % for cipher in ciphers: %{ name = cipher["name"] nonceSize = cipher["recommendedNonceSize"] nonceValidation = cipher["nonceValidation"] +dataDescription = cipher["dataDescription"] }% // MARK: - ${name} + Nonce @@ -56,8 +69,7 @@ extension ${name} { /// ``init()`` method to instead create a random nonce. /// /// - Parameters: - /// - data: A 12-byte data representation of the nonce. The initializer throws an - /// error if the data has a length other than 12 bytes. +${dataDescription} public init(data: D) throws { if data.count ${nonceValidation} { throw CryptoKitError.incorrectParameterSize diff --git a/Sources/Crypto/ASN1/ASN1.swift b/Sources/Crypto/ASN1/ASN1.swift index 2f946ec3..4fb72010 100644 --- a/Sources/Crypto/ASN1/ASN1.swift +++ b/Sources/Crypto/ASN1/ASN1.swift @@ -14,7 +14,12 @@ #if CRYPTO_IN_SWIFTPM && !CRYPTO_IN_SWIFTPM_FORCE_BUILD_API @_exported import CryptoKit #else + +#if CRYPTOKIT_NO_ACCESS_TO_FOUNDATION +import SwiftSystem +#else import Foundation +#endif // This module implements "just enough" ASN.1. Specifically, we implement exactly enough ASN.1 DER parsing to handle // the following use-cases: diff --git a/Sources/Crypto/ASN1/Basic ASN1 Types/ASN1Any.swift b/Sources/Crypto/ASN1/Basic ASN1 Types/ASN1Any.swift index e43a0185..d6f842d7 100644 --- a/Sources/Crypto/ASN1/Basic ASN1 Types/ASN1Any.swift +++ b/Sources/Crypto/ASN1/Basic ASN1 Types/ASN1Any.swift @@ -14,7 +14,12 @@ #if CRYPTO_IN_SWIFTPM && !CRYPTO_IN_SWIFTPM_FORCE_BUILD_API @_exported import CryptoKit #else + +#if CRYPTOKIT_NO_ACCESS_TO_FOUNDATION +import SwiftSystem +#else import Foundation +#endif extension ASN1 { /// An ASN1 ANY represents...well, anything. diff --git a/Sources/Crypto/ASN1/Basic ASN1 Types/ASN1BitString.swift b/Sources/Crypto/ASN1/Basic ASN1 Types/ASN1BitString.swift index 3bca15ab..0dcf4965 100644 --- a/Sources/Crypto/ASN1/Basic ASN1 Types/ASN1BitString.swift +++ b/Sources/Crypto/ASN1/Basic ASN1 Types/ASN1BitString.swift @@ -14,7 +14,12 @@ #if CRYPTO_IN_SWIFTPM && !CRYPTO_IN_SWIFTPM_FORCE_BUILD_API @_exported import CryptoKit #else + +#if CRYPTOKIT_NO_ACCESS_TO_FOUNDATION +import SwiftSystem +#else import Foundation +#endif extension ASN1 { /// A bitstring is a representation of...well...some bits. diff --git a/Sources/Crypto/ASN1/Basic ASN1 Types/ASN1Boolean.swift b/Sources/Crypto/ASN1/Basic ASN1 Types/ASN1Boolean.swift index 02a005bf..ef514d5a 100644 --- a/Sources/Crypto/ASN1/Basic ASN1 Types/ASN1Boolean.swift +++ b/Sources/Crypto/ASN1/Basic ASN1 Types/ASN1Boolean.swift @@ -14,7 +14,12 @@ #if CRYPTO_IN_SWIFTPM && !CRYPTO_IN_SWIFTPM_FORCE_BUILD_API @_exported import CryptoKit #else + +#if CRYPTOKIT_NO_ACCESS_TO_FOUNDATION +import SwiftSystem +#else import Foundation +#endif extension Bool: ASN1ImplicitlyTaggable { static var defaultIdentifier: ASN1.ASN1Identifier { diff --git a/Sources/Crypto/ASN1/Basic ASN1 Types/ASN1Identifier.swift b/Sources/Crypto/ASN1/Basic ASN1 Types/ASN1Identifier.swift index 90cfeb3f..02635be6 100644 --- a/Sources/Crypto/ASN1/Basic ASN1 Types/ASN1Identifier.swift +++ b/Sources/Crypto/ASN1/Basic ASN1 Types/ASN1Identifier.swift @@ -14,7 +14,12 @@ #if CRYPTO_IN_SWIFTPM && !CRYPTO_IN_SWIFTPM_FORCE_BUILD_API @_exported import CryptoKit #else + +#if CRYPTOKIT_NO_ACCESS_TO_FOUNDATION +import SwiftSystem +#else import Foundation +#endif extension ASN1 { /// An `ASN1Identifier` is a representation of the abstract notion of an ASN.1 identifier. Identifiers have a number of properties that relate to both the specific diff --git a/Sources/Crypto/ASN1/Basic ASN1 Types/ASN1Integer.swift b/Sources/Crypto/ASN1/Basic ASN1 Types/ASN1Integer.swift index 47e329ac..da1b18cb 100644 --- a/Sources/Crypto/ASN1/Basic ASN1 Types/ASN1Integer.swift +++ b/Sources/Crypto/ASN1/Basic ASN1 Types/ASN1Integer.swift @@ -14,10 +14,15 @@ #if CRYPTO_IN_SWIFTPM && !CRYPTO_IN_SWIFTPM_FORCE_BUILD_API @_exported import CryptoKit #else + +#if CRYPTOKIT_NO_ACCESS_TO_FOUNDATION +import SwiftSystem +#else import Foundation +#endif -/// A protocol that represents any internal object that can present itself as an INTEGER, or be parsed from -/// an INTEGER. +/// A protocol that represents any internal object that can present itself as a INTEGER, or be parsed from +/// a INTEGER. /// /// This is not a very good solution for a fully-fledged ASN.1 library: we'd rather have a better numerics /// protocol that could both initialize from and serialize to either bytes or words. However, no such diff --git a/Sources/Crypto/ASN1/Basic ASN1 Types/ASN1Null.swift b/Sources/Crypto/ASN1/Basic ASN1 Types/ASN1Null.swift index 53259ea0..1dbfa65d 100644 --- a/Sources/Crypto/ASN1/Basic ASN1 Types/ASN1Null.swift +++ b/Sources/Crypto/ASN1/Basic ASN1 Types/ASN1Null.swift @@ -14,7 +14,12 @@ #if CRYPTO_IN_SWIFTPM && !CRYPTO_IN_SWIFTPM_FORCE_BUILD_API @_exported import CryptoKit #else + +#if CRYPTOKIT_NO_ACCESS_TO_FOUNDATION +import SwiftSystem +#else import Foundation +#endif extension ASN1 { /// An ASN1 NULL represents nothing. diff --git a/Sources/Crypto/ASN1/Basic ASN1 Types/ASN1OctetString.swift b/Sources/Crypto/ASN1/Basic ASN1 Types/ASN1OctetString.swift index e3f889cf..90d6735e 100644 --- a/Sources/Crypto/ASN1/Basic ASN1 Types/ASN1OctetString.swift +++ b/Sources/Crypto/ASN1/Basic ASN1 Types/ASN1OctetString.swift @@ -14,7 +14,12 @@ #if CRYPTO_IN_SWIFTPM && !CRYPTO_IN_SWIFTPM_FORCE_BUILD_API @_exported import CryptoKit #else + +#if CRYPTOKIT_NO_ACCESS_TO_FOUNDATION +import SwiftSystem +#else import Foundation +#endif extension ASN1 { /// An octet string is a representation of a string of octets. diff --git a/Sources/Crypto/ASN1/Basic ASN1 Types/ASN1Strings.swift b/Sources/Crypto/ASN1/Basic ASN1 Types/ASN1Strings.swift index d2a9517b..a8c19ba0 100644 --- a/Sources/Crypto/ASN1/Basic ASN1 Types/ASN1Strings.swift +++ b/Sources/Crypto/ASN1/Basic ASN1 Types/ASN1Strings.swift @@ -14,7 +14,12 @@ #if CRYPTO_IN_SWIFTPM && !CRYPTO_IN_SWIFTPM_FORCE_BUILD_API @_exported import CryptoKit #else + +#if CRYPTOKIT_NO_ACCESS_TO_FOUNDATION +import SwiftSystem +#else import Foundation +#endif extension ASN1 { /// A UTF8String is roughly what it sounds like. We note that all the string types are encoded as implicitly tagged diff --git a/Sources/Crypto/ASN1/Basic ASN1 Types/ArraySliceBigint.swift b/Sources/Crypto/ASN1/Basic ASN1 Types/ArraySliceBigint.swift index b472489f..604b4e04 100644 --- a/Sources/Crypto/ASN1/Basic ASN1 Types/ArraySliceBigint.swift +++ b/Sources/Crypto/ASN1/Basic ASN1 Types/ArraySliceBigint.swift @@ -15,6 +15,12 @@ @_exported import CryptoKit #else +#if CRYPTOKIT_NO_ACCESS_TO_FOUNDATION +import SwiftSystem +#else +import Foundation +#endif + // For temporary purposes we pretend that ArraySlice is our "bigint" type. We don't really need anything else. extension ArraySlice: ASN1Serializable where Element == UInt8 { } diff --git a/Sources/Crypto/ASN1/Basic ASN1 Types/GeneralizedTime.swift b/Sources/Crypto/ASN1/Basic ASN1 Types/GeneralizedTime.swift index 63d73874..6c2721e5 100644 --- a/Sources/Crypto/ASN1/Basic ASN1 Types/GeneralizedTime.swift +++ b/Sources/Crypto/ASN1/Basic ASN1 Types/GeneralizedTime.swift @@ -14,7 +14,12 @@ #if CRYPTO_IN_SWIFTPM && !CRYPTO_IN_SWIFTPM_FORCE_BUILD_API @_exported import CryptoKit #else + +#if CRYPTOKIT_NO_ACCESS_TO_FOUNDATION +import SwiftSystem +#else import Foundation +#endif extension ASN1 { struct GeneralizedTime: ASN1ImplicitlyTaggable, Hashable { diff --git a/Sources/Crypto/ASN1/Basic ASN1 Types/ObjectIdentifier.swift b/Sources/Crypto/ASN1/Basic ASN1 Types/ObjectIdentifier.swift index a7dd5ce5..62664e06 100644 --- a/Sources/Crypto/ASN1/Basic ASN1 Types/ObjectIdentifier.swift +++ b/Sources/Crypto/ASN1/Basic ASN1 Types/ObjectIdentifier.swift @@ -14,7 +14,12 @@ #if CRYPTO_IN_SWIFTPM && !CRYPTO_IN_SWIFTPM_FORCE_BUILD_API @_exported import CryptoKit #else + +#if CRYPTOKIT_NO_ACCESS_TO_FOUNDATION +import SwiftSystem +#else import Foundation +#endif extension ASN1 { /// An Object Identifier is a representation of some kind of object: really any kind of object. diff --git a/Sources/Crypto/ASN1/ECDSASignature.swift b/Sources/Crypto/ASN1/ECDSASignature.swift index 85686409..e933eab1 100644 --- a/Sources/Crypto/ASN1/ECDSASignature.swift +++ b/Sources/Crypto/ASN1/ECDSASignature.swift @@ -12,9 +12,18 @@ // //===----------------------------------------------------------------------===// #if CRYPTO_IN_SWIFTPM && !CRYPTO_IN_SWIFTPM_FORCE_BUILD_API +#if CRYPTOKIT_STATIC_LIBRARY +@_exported import CryptoKit_Static +#else @_exported import CryptoKit +#endif +#else + +#if CRYPTOKIT_NO_ACCESS_TO_FOUNDATION +import SwiftSystem #else import Foundation +#endif extension ASN1 { /// An ECDSA signature is laid out as follows: diff --git a/Sources/Crypto/ASN1/PEMDocument.swift b/Sources/Crypto/ASN1/PEMDocument.swift index 98ba079d..5a844903 100644 --- a/Sources/Crypto/ASN1/PEMDocument.swift +++ b/Sources/Crypto/ASN1/PEMDocument.swift @@ -12,9 +12,18 @@ // //===----------------------------------------------------------------------===// #if CRYPTO_IN_SWIFTPM && !CRYPTO_IN_SWIFTPM_FORCE_BUILD_API +#if CRYPTOKIT_STATIC_LIBRARY +@_exported import CryptoKit_Static +#else @_exported import CryptoKit +#endif +#else + +#if CRYPTOKIT_NO_ACCESS_TO_FOUNDATION +import SwiftSystem #else import Foundation +#endif extension ASN1 { /// A PEM document is some data, and a discriminator type that is used to advertise the content. diff --git a/Sources/Crypto/ASN1/PKCS8PrivateKey.swift b/Sources/Crypto/ASN1/PKCS8PrivateKey.swift index 8df9dec1..a573b4bb 100644 --- a/Sources/Crypto/ASN1/PKCS8PrivateKey.swift +++ b/Sources/Crypto/ASN1/PKCS8PrivateKey.swift @@ -14,7 +14,11 @@ #if CRYPTO_IN_SWIFTPM && !CRYPTO_IN_SWIFTPM_FORCE_BUILD_API @_exported import CryptoKit #else +#if CRYPTOKIT_NO_ACCESS_TO_FOUNDATION +import SwiftSystem +#else import Foundation +#endif extension ASN1 { // A PKCS#8 private key is one of two formats, depending on the version: diff --git a/Sources/Crypto/ASN1/SEC1PrivateKey.swift b/Sources/Crypto/ASN1/SEC1PrivateKey.swift index dd347123..cfb9f624 100644 --- a/Sources/Crypto/ASN1/SEC1PrivateKey.swift +++ b/Sources/Crypto/ASN1/SEC1PrivateKey.swift @@ -12,9 +12,18 @@ // //===----------------------------------------------------------------------===// #if CRYPTO_IN_SWIFTPM && !CRYPTO_IN_SWIFTPM_FORCE_BUILD_API +#if CRYPTOKIT_STATIC_LIBRARY +@_exported import CryptoKit_Static +#else @_exported import CryptoKit +#endif +#else + +#if CRYPTOKIT_NO_ACCESS_TO_FOUNDATION +import SwiftSystem #else import Foundation +#endif extension ASN1 { // For private keys, SEC 1 uses: diff --git a/Sources/Crypto/ASN1/SubjectPublicKeyInfo.swift b/Sources/Crypto/ASN1/SubjectPublicKeyInfo.swift index 31f6b45b..6a6b4d6c 100644 --- a/Sources/Crypto/ASN1/SubjectPublicKeyInfo.swift +++ b/Sources/Crypto/ASN1/SubjectPublicKeyInfo.swift @@ -12,9 +12,18 @@ // //===----------------------------------------------------------------------===// #if CRYPTO_IN_SWIFTPM && !CRYPTO_IN_SWIFTPM_FORCE_BUILD_API +#if CRYPTOKIT_STATIC_LIBRARY +@_exported import CryptoKit_Static +#else @_exported import CryptoKit +#endif +#else + +#if CRYPTOKIT_NO_ACCESS_TO_FOUNDATION +import SwiftSystem #else import Foundation +#endif extension ASN1 { struct SubjectPublicKeyInfo: ASN1ImplicitlyTaggable { diff --git a/Sources/Crypto/CMakeLists.txt b/Sources/Crypto/CMakeLists.txt index da0fb6ec..01c68514 100644 --- a/Sources/Crypto/CMakeLists.txt +++ b/Sources/Crypto/CMakeLists.txt @@ -63,6 +63,7 @@ add_library(Crypto "Key Agreement/BoringSSL/ECDH_boring.swift" "Key Agreement/DH.swift" "Key Agreement/ECDH.swift" + "Key Derivation/ANSIx963.swift" "Key Derivation/HKDF.swift" "Key Wrapping/AESWrap.swift" "Key Wrapping/BoringSSL/AESWrap_boring.swift" diff --git a/Sources/Crypto/CryptoKitErrors.swift b/Sources/Crypto/CryptoKitErrors.swift index 31c4523f..98955ed6 100644 --- a/Sources/Crypto/CryptoKitErrors.swift +++ b/Sources/Crypto/CryptoKitErrors.swift @@ -12,7 +12,11 @@ // //===----------------------------------------------------------------------===// #if CRYPTO_IN_SWIFTPM && !CRYPTO_IN_SWIFTPM_FORCE_BUILD_API +#if CRYPTOKIT_STATIC_LIBRARY +@_exported import CryptoKit_Static +#else @_exported import CryptoKit +#endif #else /// General cryptography errors used by CryptoKit. public enum CryptoKitError: Error { diff --git a/Sources/Crypto/Digests/Digest.swift b/Sources/Crypto/Digests/Digest.swift index 653a026a..648db474 100644 --- a/Sources/Crypto/Digests/Digest.swift +++ b/Sources/Crypto/Digests/Digest.swift @@ -12,9 +12,18 @@ // //===----------------------------------------------------------------------===// #if CRYPTO_IN_SWIFTPM && !CRYPTO_IN_SWIFTPM_FORCE_BUILD_API +#if CRYPTOKIT_STATIC_LIBRARY +@_exported import CryptoKit_Static +#else @_exported import CryptoKit +#endif +#else + +#if CRYPTOKIT_NO_ACCESS_TO_FOUNDATION +import SwiftSystem #else import Foundation +#endif /// A type that represents the output of a hash. public protocol Digest: Hashable, ContiguousBytes, CustomStringConvertible, Sequence where Element == UInt8 { @@ -79,7 +88,7 @@ extension Digest { return safeCompare(lhs, rhs.regions.first!) } } - + public var description: String { return "\(Self.self): \(Array(self).hexString)" } diff --git a/Sources/Crypto/Digests/Digests.swift b/Sources/Crypto/Digests/Digests.swift index ff08b436..6b0c8208 100644 --- a/Sources/Crypto/Digests/Digests.swift +++ b/Sources/Crypto/Digests/Digests.swift @@ -18,6 +18,8 @@ // any edits of this file WILL be overwritten and thus discarded // see section `gyb` in `README` for details. + + // MARK: - SHA256Digest + DigestPrivate /// The output of a Secure Hashing Algorithm 2 (SHA-2) hash with a 256-bit digest. public struct SHA256Digest: DigestPrivate { diff --git a/Sources/Crypto/Digests/Digests.swift.gyb b/Sources/Crypto/Digests/Digests.swift.gyb index 401e576c..45539c36 100644 --- a/Sources/Crypto/Digests/Digests.swift.gyb +++ b/Sources/Crypto/Digests/Digests.swift.gyb @@ -17,9 +17,15 @@ // MARK: - Generated file, do NOT edit // any edits of this file WILL be overwritten and thus discarded // see section `gyb` in `README` for details. + %{ -digests_and_length = [{"name": "SHA256", "count": 32},{"name": "SHA384","count":48},{"name":"SHA512", "count": 64},{"name":"SHA1", "count":20, "prefix":"Insecure "},{"name":"MD5", "count":16, "prefix":"Insecure "}] +digests_and_length = [{"name": "SHA256", "count": 32},{"name": "SHA384","count":48},{"name":"SHA512", "count": 64}] +if "NO_INSECURE_DIGEST" in globals(): + pass +else: + digests_and_length.extend([{"name":"SHA1", "count":20, "prefix":"Insecure "},{"name":"MD5", "count":16, "prefix":"Insecure "}]) }% + % for HF in digests_and_length: %{ name = HF["name"] diff --git a/Sources/Crypto/Digests/HashFunctions.swift b/Sources/Crypto/Digests/HashFunctions.swift index 20280e06..fefc747b 100644 --- a/Sources/Crypto/Digests/HashFunctions.swift +++ b/Sources/Crypto/Digests/HashFunctions.swift @@ -14,13 +14,17 @@ #if CRYPTO_IN_SWIFTPM && !CRYPTO_IN_SWIFTPM_FORCE_BUILD_API @_exported import CryptoKit #else -#if !CRYPTO_IN_SWIFTPM_FORCE_BUILD_API +#if (!CRYPTO_IN_SWIFTPM_FORCE_BUILD_API) || CRYPTOKIT_NO_ACCESS_TO_FOUNDATION typealias DigestImpl = CoreCryptoDigestImpl #else typealias DigestImpl = OpenSSLDigestImpl #endif +#if CRYPTOKIT_NO_ACCESS_TO_FOUNDATION +import SwiftSystem +#else import Foundation +#endif /// A type that performs cryptographically secure hashing. /// @@ -43,9 +47,13 @@ import Foundation public protocol HashFunction { /// The number of bytes that represents the hash function’s internal state. static var blockByteCount: Int { get } - #if !CRYPTO_IN_SWIFTPM_FORCE_BUILD_API + #if (!CRYPTO_IN_SWIFTPM_FORCE_BUILD_API) || CRYPTOKIT_NO_ACCESS_TO_FOUNDATION /// The type of the digest returned by the hash function. + #if CRYPTOKIT_STATIC_LIBRARY + associatedtype Digest: CryptoKit_Static.Digest + #else associatedtype Digest: CryptoKit.Digest + #endif #else associatedtype Digest: Crypto.Digest #endif @@ -107,7 +115,7 @@ extension HashFunction { return hasher.finalize() } - /// Computes the SHA1 digest of the bytes in the given data instance and + /// Computes the digest of the bytes in the given data instance and /// returns the computed digest. /// /// Use this method if all your data fits into a single data instance. If diff --git a/Sources/Crypto/Digests/HashFunctions_SHA2.swift b/Sources/Crypto/Digests/HashFunctions_SHA2.swift index d14b9c04..116a857a 100644 --- a/Sources/Crypto/Digests/HashFunctions_SHA2.swift +++ b/Sources/Crypto/Digests/HashFunctions_SHA2.swift @@ -28,17 +28,9 @@ /// data, and then calling the ``finalize()`` method to get the result. public struct SHA256: HashFunctionImplementationDetails { /// The number of bytes that represents the hash function’s internal state. - public static var blockByteCount: Int { - get { 64 } - - set { fatalError("Cannot set SHA256.blockByteCount") } - } + public static let blockByteCount: Int = 64 /// The number of bytes in a SHA256 digest. - public static var byteCount: Int { - get { 32 } - - set { fatalError("Cannot set SHA256.byteCount") } - } + public static let byteCount: Int = 32 /// The digest type for a SHA256 hash function. public typealias Digest = SHA256Digest @@ -110,17 +102,9 @@ public struct SHA256: HashFunctionImplementationDetails { /// data, and then calling the ``finalize()`` method to get the result. public struct SHA384: HashFunctionImplementationDetails { /// The number of bytes that represents the hash function’s internal state. - public static var blockByteCount: Int { - get { 128 } - - set { fatalError("Cannot set SHA384.blockByteCount") } - } + public static let blockByteCount: Int = 128 /// The number of bytes in a SHA384 digest. - public static var byteCount: Int { - get { 48 } - - set { fatalError("Cannot set SHA384.byteCount") } - } + public static let byteCount: Int = 48 /// The digest type for a SHA384 hash function. public typealias Digest = SHA384Digest @@ -193,17 +177,9 @@ public struct SHA384: HashFunctionImplementationDetails { /// data, and then calling the ``finalize()`` method to get the result. public struct SHA512: HashFunctionImplementationDetails { /// The number of bytes that represents the hash function’s internal state. - public static var blockByteCount: Int { - get { 128 } - - set { fatalError("Cannot set SHA512.blockByteCount") } - } + public static let blockByteCount: Int = 128 /// The number of bytes in a SHA512 digest. - public static var byteCount: Int { - get { 64 } - - set { fatalError("Cannot set SHA512.byteCount") } - } + public static let byteCount: Int = 64 /// The digest type for a SHA512 hash function. public typealias Digest = SHA512Digest diff --git a/Sources/Crypto/HPKE/Ciphersuite/HPKE-AEAD.swift b/Sources/Crypto/HPKE/Ciphersuite/HPKE-AEAD.swift index 19248974..a73a6319 100644 --- a/Sources/Crypto/HPKE/Ciphersuite/HPKE-AEAD.swift +++ b/Sources/Crypto/HPKE/Ciphersuite/HPKE-AEAD.swift @@ -14,7 +14,12 @@ #if CRYPTO_IN_SWIFTPM && !CRYPTO_IN_SWIFTPM_FORCE_BUILD_API @_exported import CryptoKit #else + +#if CRYPTOKIT_NO_ACCESS_TO_FOUNDATION +import SwiftSystem +#else import Foundation +#endif extension HPKE { @@ -31,6 +36,7 @@ extension HPKE { /// In export-only mode, HPKE negotiates key derivation, but you can't use it to encrypt or decrypt data. case exportOnly + /// Return the AEAD algorithm identifier as defined in section 7.3 of [RFC 9180](https://www.ietf.org/rfc/rfc9180.pdf). internal var value: UInt16 { switch self { case .AES_GCM_128: return 0x0001 @@ -44,6 +50,7 @@ extension HPKE { return self == .exportOnly } + /// Return the AEAD key size in bytes internal var keyByteCount: Int { switch self { case .AES_GCM_128: @@ -57,6 +64,7 @@ extension HPKE { } } + /// Return the AEAD nonce size in bytes internal var nonceByteCount: Int { switch self { case .AES_GCM_128, .AES_GCM_256, .chaChaPoly: @@ -66,6 +74,7 @@ extension HPKE { } } + /// Return the AEAD tag size in bytes internal var tagByteCount: Int { switch self { case .AES_GCM_128, .AES_GCM_256, .chaChaPoly: diff --git a/Sources/Crypto/HPKE/Ciphersuite/HPKE-Ciphersuite.swift b/Sources/Crypto/HPKE/Ciphersuite/HPKE-Ciphersuite.swift index 25e5b08c..fbc08c13 100644 --- a/Sources/Crypto/HPKE/Ciphersuite/HPKE-Ciphersuite.swift +++ b/Sources/Crypto/HPKE/Ciphersuite/HPKE-Ciphersuite.swift @@ -14,7 +14,12 @@ #if CRYPTO_IN_SWIFTPM && !CRYPTO_IN_SWIFTPM_FORCE_BUILD_API @_exported import CryptoKit #else + +#if CRYPTOKIT_NO_ACCESS_TO_FOUNDATION +import SwiftSystem +#else import Foundation +#endif extension HPKE { diff --git a/Sources/Crypto/HPKE/Ciphersuite/HPKE-KDF.swift b/Sources/Crypto/HPKE/Ciphersuite/HPKE-KDF.swift index 1d596f12..d055815c 100644 --- a/Sources/Crypto/HPKE/Ciphersuite/HPKE-KDF.swift +++ b/Sources/Crypto/HPKE/Ciphersuite/HPKE-KDF.swift @@ -12,9 +12,18 @@ // //===----------------------------------------------------------------------===// #if CRYPTO_IN_SWIFTPM && !CRYPTO_IN_SWIFTPM_FORCE_BUILD_API +#if CRYPTOKIT_STATIC_LIBRARY +@_exported import CryptoKit_Static +#else @_exported import CryptoKit +#endif +#else + +#if CRYPTOKIT_NO_ACCESS_TO_FOUNDATION +import SwiftSystem #else import Foundation +#endif extension HPKE { /// The key derivation functions to use in HPKE. @@ -26,7 +35,7 @@ extension HPKE { /// An HMAC-based key derivation function that uses SHA-2 hashing with a 512-bit digest. case HKDF_SHA512 - /// Assigned value + /// Return the KDF algorithm identifier as defined in section 7.2 of [RFC 9180](https://www.ietf.org/rfc/rfc9180.pdf). internal var value: UInt16 { switch self { case .HKDF_SHA256: return 0x0001 diff --git a/Sources/Crypto/HPKE/Ciphersuite/HPKE-KexKeyDerivation.swift b/Sources/Crypto/HPKE/Ciphersuite/HPKE-KexKeyDerivation.swift index 0e02a54e..efd1a894 100644 --- a/Sources/Crypto/HPKE/Ciphersuite/HPKE-KexKeyDerivation.swift +++ b/Sources/Crypto/HPKE/Ciphersuite/HPKE-KexKeyDerivation.swift @@ -14,7 +14,13 @@ #if CRYPTO_IN_SWIFTPM && !CRYPTO_IN_SWIFTPM_FORCE_BUILD_API @_exported import CryptoKit #else + +#if CRYPTOKIT_NO_ACCESS_TO_FOUNDATION +import SwiftSystem +#else import Foundation +#endif + private let suiteIDLabel = Data("KEM".utf8) @@ -24,9 +30,14 @@ 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 + #if !CRYPTO_IN_SWIFTPM_FORCE_BUILD_API + #if CRYPTOKIT_STATIC_LIBRARY + return CryptoKit_Static.ExtractAndExpand(zz: dh, kemContext: kemContext(enc: enc, pkRm: pkRm, pkSm: pkSm), + suiteID: suiteID, kem: kem, kdf: kdf) + #else return CryptoKit.ExtractAndExpand(zz: dh, kemContext: kemContext(enc: enc, pkRm: pkRm, pkSm: pkSm), suiteID: suiteID, kem: kem, kdf: kdf) + #endif #else return Crypto.ExtractAndExpand(zz: dh, kemContext: kemContext(enc: enc, pkRm: pkRm, pkSm: pkSm), suiteID: suiteID, kem: kem, kdf: kdf) @@ -37,7 +48,7 @@ extension HPKE { var context = Data() context.append(enc) context.append(pkRm) - if let pkSm = pkSm { context.append(pkSm) } + if let pkSm { context.append(pkSm) } return context } } diff --git a/Sources/Crypto/HPKE/Ciphersuite/HPKE-LabeledExtract.swift b/Sources/Crypto/HPKE/Ciphersuite/HPKE-LabeledExtract.swift index da22c83d..dfc1b63f 100644 --- a/Sources/Crypto/HPKE/Ciphersuite/HPKE-LabeledExtract.swift +++ b/Sources/Crypto/HPKE/Ciphersuite/HPKE-LabeledExtract.swift @@ -14,7 +14,13 @@ #if CRYPTO_IN_SWIFTPM && !CRYPTO_IN_SWIFTPM_FORCE_BUILD_API @_exported import CryptoKit #else + +#if CRYPTOKIT_NO_ACCESS_TO_FOUNDATION +import SwiftSystem +#else import Foundation +#endif + private let protocolLabel = Data("HPKE-v1".utf8) private let eaePRKLabel = Data("eae_prk".utf8) diff --git a/Sources/Crypto/HPKE/Ciphersuite/HPKE-Utils.swift b/Sources/Crypto/HPKE/Ciphersuite/HPKE-Utils.swift index 92c9657f..8207acac 100644 --- a/Sources/Crypto/HPKE/Ciphersuite/HPKE-Utils.swift +++ b/Sources/Crypto/HPKE/Ciphersuite/HPKE-Utils.swift @@ -14,13 +14,24 @@ #if CRYPTO_IN_SWIFTPM && !CRYPTO_IN_SWIFTPM_FORCE_BUILD_API @_exported import CryptoKit #else + +#if CRYPTOKIT_NO_ACCESS_TO_FOUNDATION +import SwiftSystem +#else import Foundation +#endif + internal func I2OSP(value: Int, outputByteCount: Int) -> Data { precondition(outputByteCount > 0, "Cannot I2OSP with no output length.") precondition(value >= 0, "I2OSP requires a non-null value.") + #if !CRYPTOKIT_NO_ACCESS_TO_FOUNDATION let requiredBytes = Int(ceil(log2(Double(max(value, 1) + 1)) / 8)) + #else + let requiredBytes = Int((log2_bridge(Double(max(value, 1) + 1)) / 8).rounded(.up)) + #endif + precondition(outputByteCount >= requiredBytes) var data = Data(repeating: 0, count: outputByteCount) diff --git a/Sources/Crypto/HPKE/Ciphersuite/KEM/Conformances/DHKEM.swift b/Sources/Crypto/HPKE/Ciphersuite/KEM/Conformances/DHKEM.swift index e41183e1..fcea1cb8 100644 --- a/Sources/Crypto/HPKE/Ciphersuite/KEM/Conformances/DHKEM.swift +++ b/Sources/Crypto/HPKE/Ciphersuite/KEM/Conformances/DHKEM.swift @@ -14,7 +14,12 @@ #if CRYPTO_IN_SWIFTPM && !CRYPTO_IN_SWIFTPM_FORCE_BUILD_API @_exported import CryptoKit #else + +#if CRYPTOKIT_NO_ACCESS_TO_FOUNDATION +import SwiftSystem +#else import Foundation +#endif /// A type that ``HPKE`` uses to encode the public key. public protocol HPKEPublicKeySerialization { @@ -40,7 +45,6 @@ public protocol HPKEDiffieHellmanPublicKey: HPKEPublicKeySerialization where Eph } /// A type that represents the private key in a Diffie-Hellman key exchange. - public protocol HPKEDiffieHellmanPrivateKey: DiffieHellmanKeyAgreement where PublicKey: HPKEDiffieHellmanPublicKey {} /// A type that represents the generation of private keys in a Diffie-Hellman key exchange. @@ -56,8 +60,12 @@ extension HPKE { let kem: HPKE.KEM let key: DHPK - #if !CRYPTO_IN_SWIFTPM_FORCE_BUILD_API + #if !CRYPTO_IN_SWIFTPM_FORCE_BUILD_API + #if CRYPTOKIT_STATIC_LIBRARY + typealias EncapsulationResult = CryptoKit_Static.KEM.EncapsulationResult + #else typealias EncapsulationResult = CryptoKit.KEM.EncapsulationResult + #endif #else typealias EncapsulationResult = Crypto.KEM.EncapsulationResult #endif diff --git a/Sources/Crypto/HPKE/Ciphersuite/KEM/Conformances/HPKE-KEM-Curve25519.swift b/Sources/Crypto/HPKE/Ciphersuite/KEM/Conformances/HPKE-KEM-Curve25519.swift index e846526e..71ad919e 100644 --- a/Sources/Crypto/HPKE/Ciphersuite/KEM/Conformances/HPKE-KEM-Curve25519.swift +++ b/Sources/Crypto/HPKE/Ciphersuite/KEM/Conformances/HPKE-KEM-Curve25519.swift @@ -14,10 +14,15 @@ #if CRYPTO_IN_SWIFTPM && !CRYPTO_IN_SWIFTPM_FORCE_BUILD_API @_exported import CryptoKit #else + +#if CRYPTOKIT_NO_ACCESS_TO_FOUNDATION +import SwiftSystem +#else import Foundation +#endif -extension Curve25519.KeyAgreement.PrivateKey: HPKEDiffieHellmanPrivateKeyGeneration {} +extension Curve25519.KeyAgreement.PrivateKey: HPKEDiffieHellmanPrivateKeyGeneration {} extension Curve25519.KeyAgreement.PublicKey: HPKEDiffieHellmanPublicKey { /// The type of the ephemeral private key associated with this public key. diff --git a/Sources/Crypto/HPKE/Ciphersuite/KEM/Conformances/HPKE-NIST-EC-KEMs.swift b/Sources/Crypto/HPKE/Ciphersuite/KEM/Conformances/HPKE-NIST-EC-KEMs.swift index 1b921297..8a251580 100644 --- a/Sources/Crypto/HPKE/Ciphersuite/KEM/Conformances/HPKE-NIST-EC-KEMs.swift +++ b/Sources/Crypto/HPKE/Ciphersuite/KEM/Conformances/HPKE-NIST-EC-KEMs.swift @@ -12,11 +12,18 @@ // //===----------------------------------------------------------------------===// #if CRYPTO_IN_SWIFTPM && !CRYPTO_IN_SWIFTPM_FORCE_BUILD_API +#if CRYPTOKIT_STATIC_LIBRARY +@_exported import CryptoKit_Static +#else @_exported import CryptoKit +#endif #else -import Foundation - +#if CRYPTOKIT_NO_ACCESS_TO_FOUNDATION +import SwiftSystem +#else +import Foundation +#endif extension P256.KeyAgreement.PrivateKey: HPKEDiffieHellmanPrivateKeyGeneration { /// Creates a NIST P-256 elliptic curve private key for use with Diffie-Hellman key exchange. diff --git a/Sources/Crypto/HPKE/Ciphersuite/KEM/HPKE-KEM.swift b/Sources/Crypto/HPKE/Ciphersuite/KEM/HPKE-KEM.swift index c9c9ad96..0c0755f0 100644 --- a/Sources/Crypto/HPKE/Ciphersuite/KEM/HPKE-KEM.swift +++ b/Sources/Crypto/HPKE/Ciphersuite/KEM/HPKE-KEM.swift @@ -14,7 +14,11 @@ #if CRYPTO_IN_SWIFTPM && !CRYPTO_IN_SWIFTPM_FORCE_BUILD_API @_exported import CryptoKit #else +#if CRYPTOKIT_NO_ACCESS_TO_FOUNDATION +import SwiftSystem +#else import Foundation +#endif extension HPKE { /// The key encapsulation mechanisms to use in HPKE. @@ -32,6 +36,7 @@ extension HPKE { /// and SHA-2 hashing with a 256-bit digest. case Curve25519_HKDF_SHA256 + /// Return the KEM algorithm identifier as defined in section 7.1 of [RFC 9180](https://www.ietf.org/rfc/rfc9180.pdf). internal var value: UInt16 { switch self { case .P256_HKDF_SHA256: return 0x0010 @@ -62,6 +67,16 @@ extension HPKE { case .Curve25519_HKDF_SHA256: return 32 } } + + /// Return the size of the encapsulation in bytes + internal var nEnc: UInt16 { + switch self { + case .P256_HKDF_SHA256: return 65 + case .P384_HKDF_SHA384: return 97 + case .P521_HKDF_SHA512: return 133 + case .Curve25519_HKDF_SHA256: return 32 + } + } } } diff --git a/Sources/Crypto/HPKE/HPKE-Errors.swift b/Sources/Crypto/HPKE/HPKE-Errors.swift index ffc621a6..d357c9e8 100644 --- a/Sources/Crypto/HPKE/HPKE-Errors.swift +++ b/Sources/Crypto/HPKE/HPKE-Errors.swift @@ -14,7 +14,12 @@ #if CRYPTO_IN_SWIFTPM && !CRYPTO_IN_SWIFTPM_FORCE_BUILD_API @_exported import CryptoKit #else + +#if CRYPTOKIT_NO_ACCESS_TO_FOUNDATION +import SwiftSystem +#else import Foundation +#endif extension HPKE { /// Hybrid public key encryption (HPKE) errors that CryptoKit uses. diff --git a/Sources/Crypto/HPKE/HPKE.swift b/Sources/Crypto/HPKE/HPKE.swift index 93fb7f1e..af55b410 100644 --- a/Sources/Crypto/HPKE/HPKE.swift +++ b/Sources/Crypto/HPKE/HPKE.swift @@ -12,9 +12,17 @@ // //===----------------------------------------------------------------------===// #if CRYPTO_IN_SWIFTPM && !CRYPTO_IN_SWIFTPM_FORCE_BUILD_API +#if CRYPTOKIT_STATIC_LIBRARY +@_exported import CryptoKit_Static +#else @_exported import CryptoKit +#endif +#else +#if CRYPTOKIT_NO_ACCESS_TO_FOUNDATION +import SwiftSystem #else import Foundation +#endif /// A container for hybrid public key encryption (HPKE) operations. /// @@ -48,6 +56,10 @@ import Foundation public enum HPKE {} extension HPKE { + /// Static constant used to store the fixed-string label for the HPKE export API + /// See: https://datatracker.ietf.org/doc/html/rfc9180#name-secret-export + fileprivate static let exportLabel = Data("sec".utf8) + /// A type that represents the sending side of an HPKE message exchange. /// /// To create encrypted messages, initialize a `Sender` specifying the appropriate cipher suite, @@ -60,7 +72,7 @@ extension HPKE { private var context: Context /// The encapsulated symmetric key that the recipient uses to decrypt messages. public let encapsulatedKey: Data - + /// The exporter secret. internal var exporterSecret: SymmetricKey { return context.keySchedule.exporterSecret @@ -74,13 +86,13 @@ extension HPKE { public func exportSecret(context: Context, outputByteCount: Int) throws -> SymmetricKey { precondition(outputByteCount > 0); return LabeledExpand(prk: self.exporterSecret, - label: Data("sec".utf8), + label: exportLabel, 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). @@ -196,12 +208,12 @@ extension HPKE { public struct Recipient { private var context: Context - + /// The exporter secret. 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. @@ -210,13 +222,13 @@ extension HPKE { public func exportSecret(context: Context, outputByteCount: Int) throws -> SymmetricKey { precondition(outputByteCount > 0); return LabeledExpand(prk: self.exporterSecret, - label: Data("sec".utf8), + label: exportLabel, 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). diff --git a/Sources/Crypto/HPKE/Key Schedule/HPKE-Context.swift b/Sources/Crypto/HPKE/Key Schedule/HPKE-Context.swift index e63c81b8..966e119b 100644 --- a/Sources/Crypto/HPKE/Key Schedule/HPKE-Context.swift +++ b/Sources/Crypto/HPKE/Key Schedule/HPKE-Context.swift @@ -14,7 +14,12 @@ #if CRYPTO_IN_SWIFTPM && !CRYPTO_IN_SWIFTPM_FORCE_BUILD_API @_exported import CryptoKit #else + +#if CRYPTOKIT_NO_ACCESS_TO_FOUNDATION +import SwiftSystem +#else import Foundation +#endif extension HPKE { struct Context { @@ -45,7 +50,7 @@ extension HPKE { let skRKEM = try HPKE.DHKEM.PrivateKey(skR, kem: ciphersuite.kem) let sharedSecret: SymmetricKey - if let pkS = pkS { + if let pkS { sharedSecret = try skRKEM.decapsulate(enc, authenticating: pkS) } else { sharedSecret = try skRKEM.decapsulate(enc) diff --git a/Sources/Crypto/HPKE/Key Schedule/HPKE-KeySchedule.swift b/Sources/Crypto/HPKE/Key Schedule/HPKE-KeySchedule.swift index 02960a31..bcf33576 100644 --- a/Sources/Crypto/HPKE/Key Schedule/HPKE-KeySchedule.swift +++ b/Sources/Crypto/HPKE/Key Schedule/HPKE-KeySchedule.swift @@ -14,7 +14,12 @@ #if CRYPTO_IN_SWIFTPM && !CRYPTO_IN_SWIFTPM_FORCE_BUILD_API @_exported import CryptoKit #else + +#if CRYPTOKIT_NO_ACCESS_TO_FOUNDATION +import SwiftSystem +#else import Foundation +#endif extension HPKE { internal struct KeySchedule { @@ -101,8 +106,19 @@ extension HPKE { self.ciphersuite = ciphersuite } + var maxSequenceNumber: UInt64 { + get { + let nonceBitCount = UInt64(self.ciphersuite.aead.nonceByteCount * 8) + if (nonceBitCount >= 64) { + return UInt64.max + } + + return ((UInt64(1) << nonceBitCount) - 1) + } + } + mutating func incrementSequenceNumber() throws { - if self.sequenceNumber >= ((1 << (self.ciphersuite.aead.nonceByteCount)) - 1) { + if self.sequenceNumber >= maxSequenceNumber { throw HPKE.Errors.outOfRangeSequenceNumber } sequenceNumber += 1 diff --git a/Sources/Crypto/Insecure/Insecure.swift b/Sources/Crypto/Insecure/Insecure.swift index 1fe53ee1..962ceccf 100644 --- a/Sources/Crypto/Insecure/Insecure.swift +++ b/Sources/Crypto/Insecure/Insecure.swift @@ -12,7 +12,11 @@ // //===----------------------------------------------------------------------===// #if CRYPTO_IN_SWIFTPM && !CRYPTO_IN_SWIFTPM_FORCE_BUILD_API +#if CRYPTOKIT_STATIC_LIBRARY +@_exported import CryptoKit_Static +#else @_exported import CryptoKit +#endif #else /// A container for older, cryptographically insecure algorithms. /// diff --git a/Sources/Crypto/Insecure/Insecure_HashFunctions.swift b/Sources/Crypto/Insecure/Insecure_HashFunctions.swift index 5352e6d8..a0e70d0a 100644 --- a/Sources/Crypto/Insecure/Insecure_HashFunctions.swift +++ b/Sources/Crypto/Insecure/Insecure_HashFunctions.swift @@ -34,18 +34,10 @@ extension Insecure { public struct SHA1: HashFunctionImplementationDetails { /// The number of bytes that represents the hash function’s internal /// state. - public static var blockByteCount: Int { - get { 64 } - - set { fatalError("Cannot set SHA1.blockByteCount") } - } + public static let blockByteCount: Int = 64 /// The number of bytes in a SHA1 digest. - public static var byteCount: Int { - get { 20 } - - set { fatalError("Cannot set SHA1.byteCount") } - } + public static let byteCount: Int = 20 /// The digest type for a SHA1 hash function. public typealias Digest = Insecure.SHA1Digest @@ -122,17 +114,9 @@ extension Insecure { public struct MD5: HashFunctionImplementationDetails { /// The number of bytes that represents the hash function’s internal /// state. - public static var blockByteCount: Int { - get { 64 } - - set { fatalError("Cannot set MD5.blockByteCount") } - } + public static let blockByteCount: Int = 64 /// The number of bytes in an MD5 digest. - public static var byteCount: Int { - get { 16 } - - set { fatalError("Cannot set MD5.byteCount") } - } + public static let byteCount: Int = 16 /// The digest type for a MD5 hash function. public typealias Digest = Insecure.MD5Digest diff --git a/Sources/Crypto/KEM/KEM.swift b/Sources/Crypto/KEM/KEM.swift index 80bd46ae..57886703 100644 --- a/Sources/Crypto/KEM/KEM.swift +++ b/Sources/Crypto/KEM/KEM.swift @@ -12,9 +12,18 @@ // //===----------------------------------------------------------------------===// #if CRYPTO_IN_SWIFTPM && !CRYPTO_IN_SWIFTPM_FORCE_BUILD_API +#if CRYPTOKIT_STATIC_LIBRARY +@_exported import CryptoKit_Static +#else @_exported import CryptoKit +#endif +#else + +#if CRYPTOKIT_NO_ACCESS_TO_FOUNDATION +import SwiftSystem #else import Foundation +#endif /// A Key Encapsulation Mechanism public enum KEM { diff --git a/Sources/Crypto/Key Agreement/DH.swift b/Sources/Crypto/Key Agreement/DH.swift index 42326b49..98631f1b 100644 --- a/Sources/Crypto/Key Agreement/DH.swift +++ b/Sources/Crypto/Key Agreement/DH.swift @@ -14,7 +14,12 @@ #if CRYPTO_IN_SWIFTPM && !CRYPTO_IN_SWIFTPM_FORCE_BUILD_API @_exported import CryptoKit #else + +#if CRYPTOKIT_NO_ACCESS_TO_FOUNDATION +import SwiftSystem +#else import Foundation +#endif /// A Diffie-Hellman Key Agreement Key public protocol DiffieHellmanKeyAgreement { @@ -36,7 +41,7 @@ public protocol DiffieHellmanKeyAgreement { /// Generate a shared secret by calling your private key’s /// `sharedSecretFromKeyAgreement(publicKeyShare:)` method with the public key /// from another party. The other party computes the same secret by passing your -/// public key to the equivalent method on their own private key. +/// public key to the the equivalent method on their own private key. /// /// The shared secret isn’t suitable as a symmetric cryptographic key /// (``SymmetricKey``) by itself. However, you use it to generate a key by @@ -49,7 +54,15 @@ public protocol DiffieHellmanKeyAgreement { /// ``ChaChaPoly`` or ``AES``. public struct SharedSecret: ContiguousBytes { var ss: SecureBytes - + + internal init(withExternalSS ss: SS) { + self.ss = SecureBytes(bytes: ss) + } + + internal init(ss: SecureBytes){ + self.ss = ss + } + /// Invokes the given closure with a buffer pointer covering the raw bytes /// of the shared secret. /// @@ -72,57 +85,10 @@ public struct SharedSecret: ContiguousBytes { /// /// - Returns: The derived symmetric key. public func x963DerivedSymmetricKey(using hashFunction: H.Type, sharedInfo: SI, outputByteCount: Int) -> SymmetricKey { - // SEC1 defines 3 inputs to the KDF: - // - // 1. An octet string Z which is the shared secret value. That's `self` here. - // 2. An integer `keydatalen` which is the length in octets of the keying data to be generated. Here that's `outputByteCount`. - // 3. An optional octet string `SharedInfo` which consists of other shared data. Here, that's `sharedInfo`. - // - // We then need to perform the following steps: - // - // 1. Check that keydatalen < hashlen × (2³² − 1). If keydatalen ≥ hashlen × (2³² − 1), fail. - // 2. Initiate a 4 octet, big-endian octet string Counter as 0x00000001. - // 3. For i = 1 to ⌈keydatalen/hashlen⌉, do the following: - // 1. Compute: Ki = Hash(Z || Counter || [SharedInfo]). - // 2. Increment Counter. - // 3. Increment i. - // 4. Set K to be the leftmost keydatalen octets of: K1 || K2 || . . . || K⌈keydatalen/hashlen⌉. - // 5. Output K. - // - // The loop in step 3 is not very Swifty, so instead we generate the counter directly. - // Step 1: Check that keydatalen < hashlen × (2³² − 1). - // We do this math in UInt64-space, because we'll overflow 32-bit integers. - guard UInt64(outputByteCount) < (UInt64(H.Digest.byteCount) * UInt64(UInt32.max)) else { - fatalError("Invalid parameter size") - } - - var key = SecureBytes() - key.reserveCapacity(outputByteCount) - - var remainingBytes = outputByteCount - var counter = UInt32(1) - while remainingBytes > 0 { - // 1. Compute: Ki = Hash(Z || Counter || [SharedInfo]). - var hasher = H() - hasher.update(self) - hasher.update(counter.bigEndian) - hasher.update(data: sharedInfo) - let digest = hasher.finalize() - - // 2. Increment Counter. - counter += 1 - - // Append the bytes of the digest. We don't want to append more than the remaining number of bytes. - let bytesToAppend = min(remainingBytes, H.Digest.byteCount) - digest.withUnsafeBytes { digestPtr in - key.append(digestPtr.prefix(bytesToAppend)) - } - remainingBytes -= bytesToAppend + return self.ss.withUnsafeBytes { ssBytes in + return ANSIKDFx963.deriveKey(inputKeyMaterial: SymmetricKey(data: ssBytes), info: sharedInfo, outputByteCount: outputByteCount) } - - precondition(key.count == outputByteCount) - return SymmetricKey(data: key) } /// Derives a symmetric encryption key from the secret using HKDF key @@ -173,7 +139,7 @@ extension SharedSecret: CustomStringConvertible, Equatable { return safeCompare(lhs, rhs.regions.first!) } } - + public var description: String { return "\(Self.self): \(ss.hexString)" } diff --git a/Sources/Crypto/Key Agreement/ECDH.swift b/Sources/Crypto/Key Agreement/ECDH.swift index 941fc61b..a6ceb8da 100644 --- a/Sources/Crypto/Key Agreement/ECDH.swift +++ b/Sources/Crypto/Key Agreement/ECDH.swift @@ -14,7 +14,7 @@ #if CRYPTO_IN_SWIFTPM && !CRYPTO_IN_SWIFTPM_FORCE_BUILD_API @_exported import CryptoKit #else -#if !CRYPTO_IN_SWIFTPM_FORCE_BUILD_API +#if (!CRYPTO_IN_SWIFTPM_FORCE_BUILD_API) || CRYPTOKIT_NO_ACCESS_TO_FOUNDATION typealias NISTCurvePublicKeyImpl = CoreCryptoNISTCurvePublicKeyImpl typealias NISTCurvePrivateKeyImpl = CoreCryptoNISTCurvePrivateKeyImpl #else @@ -22,7 +22,11 @@ typealias NISTCurvePublicKeyImpl = OpenSSLNISTCurvePublicKeyImpl typealias NISTCurvePrivateKeyImpl = OpenSSLNISTCurvePrivateKeyImpl #endif +#if CRYPTOKIT_NO_ACCESS_TO_FOUNDATION +import SwiftSystem +#else import Foundation +#endif // MARK: - Generated file, do NOT edit // any edits of this file WILL be overwritten and thus discarded @@ -1325,7 +1329,7 @@ extension P256.KeyAgreement.PrivateKey: DiffieHellmanKeyAgreement { /// key from this user to create the shared secret. /// - Returns: The computed shared secret. public func sharedSecretFromKeyAgreement(with publicKeyShare: P256.KeyAgreement.PublicKey) throws -> SharedSecret { - #if !CRYPTO_IN_SWIFTPM_FORCE_BUILD_API + #if (!CRYPTO_IN_SWIFTPM_FORCE_BUILD_API) || CRYPTOKIT_NO_ACCESS_TO_FOUNDATION return try self.coreCryptoSharedSecretFromKeyAgreement(with: publicKeyShare) #else return try self.openSSLSharedSecretFromKeyAgreement(with: publicKeyShare) @@ -1341,7 +1345,7 @@ extension P384.KeyAgreement.PrivateKey: DiffieHellmanKeyAgreement { /// key from this user to create the shared secret. /// - Returns: The computed shared secret. public func sharedSecretFromKeyAgreement(with publicKeyShare: P384.KeyAgreement.PublicKey) throws -> SharedSecret { - #if !CRYPTO_IN_SWIFTPM_FORCE_BUILD_API + #if (!CRYPTO_IN_SWIFTPM_FORCE_BUILD_API) || CRYPTOKIT_NO_ACCESS_TO_FOUNDATION return try self.coreCryptoSharedSecretFromKeyAgreement(with: publicKeyShare) #else return try self.openSSLSharedSecretFromKeyAgreement(with: publicKeyShare) @@ -1357,7 +1361,7 @@ extension P521.KeyAgreement.PrivateKey: DiffieHellmanKeyAgreement { /// key from this user to create the shared secret. /// - Returns: The computed shared secret. public func sharedSecretFromKeyAgreement(with publicKeyShare: P521.KeyAgreement.PublicKey) throws -> SharedSecret { - #if !CRYPTO_IN_SWIFTPM_FORCE_BUILD_API + #if (!CRYPTO_IN_SWIFTPM_FORCE_BUILD_API) || CRYPTOKIT_NO_ACCESS_TO_FOUNDATION return try self.coreCryptoSharedSecretFromKeyAgreement(with: publicKeyShare) #else return try self.openSSLSharedSecretFromKeyAgreement(with: publicKeyShare) diff --git a/Sources/Crypto/Key Agreement/ECDH.swift.gyb b/Sources/Crypto/Key Agreement/ECDH.swift.gyb index 5c738f0c..a40e9dc9 100644 --- a/Sources/Crypto/Key Agreement/ECDH.swift.gyb +++ b/Sources/Crypto/Key Agreement/ECDH.swift.gyb @@ -14,7 +14,7 @@ #if CRYPTO_IN_SWIFTPM && !CRYPTO_IN_SWIFTPM_FORCE_BUILD_API @_exported import CryptoKit #else -#if !CRYPTO_IN_SWIFTPM_FORCE_BUILD_API +#if (!CRYPTO_IN_SWIFTPM_FORCE_BUILD_API) || CRYPTOKIT_NO_ACCESS_TO_FOUNDATION typealias NISTCurvePublicKeyImpl = CoreCryptoNISTCurvePublicKeyImpl typealias NISTCurvePrivateKeyImpl = CoreCryptoNISTCurvePrivateKeyImpl #else @@ -22,7 +22,11 @@ typealias NISTCurvePublicKeyImpl = OpenSSLNISTCurvePublicKeyImpl typealias NISTCurvePrivateKeyImpl = OpenSSLNISTCurvePrivateKeyImpl #endif +#if CRYPTOKIT_NO_ACCESS_TO_FOUNDATION +import SwiftSystem +#else import Foundation +#endif // MARK: - Generated file, do NOT edit // any edits of this file WILL be overwritten and thus discarded @@ -278,7 +282,7 @@ extension ${CURVE}.KeyAgreement.PrivateKey: DiffieHellmanKeyAgreement { /// key from this user to create the shared secret. /// - Returns: The computed shared secret. public func sharedSecretFromKeyAgreement(with publicKeyShare: ${CURVE}.KeyAgreement.PublicKey) throws -> SharedSecret { - #if !CRYPTO_IN_SWIFTPM_FORCE_BUILD_API + #if (!CRYPTO_IN_SWIFTPM_FORCE_BUILD_API) || CRYPTOKIT_NO_ACCESS_TO_FOUNDATION return try self.coreCryptoSharedSecretFromKeyAgreement(with: publicKeyShare) #else return try self.openSSLSharedSecretFromKeyAgreement(with: publicKeyShare) diff --git a/Sources/Crypto/Key Derivation/ANSIx963.swift b/Sources/Crypto/Key Derivation/ANSIx963.swift new file mode 100644 index 00000000..b1bb2c5a --- /dev/null +++ b/Sources/Crypto/Key Derivation/ANSIx963.swift @@ -0,0 +1,70 @@ +//===----------------------------------------------------------------------===// +// +// This source file is part of the SwiftCrypto open source project +// +// Copyright (c) 2019-2020 Apple Inc. and the SwiftCrypto project authors +// Licensed under Apache License v2.0 +// +// See LICENSE.txt for license information +// See CONTRIBUTORS.md for the list of SwiftCrypto project authors +// +// SPDX-License-Identifier: Apache-2.0 +// +//===----------------------------------------------------------------------===// +#if CRYPTO_IN_SWIFTPM && !CRYPTO_IN_SWIFTPM_FORCE_BUILD_API +@_exported import CryptoKit +#else + +#if CRYPTOKIT_NO_ACCESS_TO_FOUNDATION +import SwiftSystem +#else +import Foundation +#endif + +internal struct ANSIKDFx963 { + public static func deriveKey(inputKeyMaterial: SymmetricKey, info: Info, outputByteCount: Int) -> SymmetricKey { + + guard UInt64(outputByteCount) < (UInt64(H.Digest.byteCount) * UInt64(UInt32.max)) else { + fatalError("Invalid parameter size") + } + + var key = SecureBytes() + key.reserveCapacity(outputByteCount) + + var remainingBytes = outputByteCount + var counter = UInt32(1) + + while remainingBytes > 0 { + // 1. Compute: Ki = Hash(Z || Counter || [SharedInfo]). + var hasher = H() + inputKeyMaterial.withUnsafeBytes { ikmBytes in + hasher.update(data: ikmBytes) + } + hasher.update(counter.bigEndian) + hasher.update(data: info) + let digest = hasher.finalize() + + // 2. Increment Counter. + counter += 1 + + // Append the bytes of the digest. We don't want to append more than the remaining number of bytes. + let bytesToAppend = min(remainingBytes, H.Digest.byteCount) + digest.withUnsafeBytes { digestPtr in + key.append(digestPtr.prefix(bytesToAppend)) + } + remainingBytes -= bytesToAppend + } + + precondition(key.count == outputByteCount) + return SymmetricKey(data: key) + } + + public static func deriveKey(inputKeyMaterial: SymmetricKey, + outputByteCount: Int) -> SymmetricKey { + return deriveKey(inputKeyMaterial: inputKeyMaterial, info: [UInt8](), outputByteCount: outputByteCount) + } +} + + +#endif + diff --git a/Sources/Crypto/Key Derivation/HKDF.swift b/Sources/Crypto/Key Derivation/HKDF.swift index 5f47c2fb..62ff2a26 100644 --- a/Sources/Crypto/Key Derivation/HKDF.swift +++ b/Sources/Crypto/Key Derivation/HKDF.swift @@ -14,7 +14,12 @@ #if CRYPTO_IN_SWIFTPM && !CRYPTO_IN_SWIFTPM_FORCE_BUILD_API @_exported import CryptoKit #else + +#if CRYPTOKIT_NO_ACCESS_TO_FOUNDATION +import SwiftSystem +#else import Foundation +#endif /// A standards-based implementation of an HMAC-based Key Derivation Function /// (HKDF). @@ -112,7 +117,7 @@ public struct HKDF { /// hashed authentication code. public static func extract(inputKeyMaterial: SymmetricKey, salt: Salt?) -> HashedAuthenticationCode { let key: SymmetricKey - if let salt = salt { + if let salt { if salt.regions.count != 1 { let contiguousBytes = Array(salt) key = SymmetricKey(data: contiguousBytes) @@ -142,21 +147,23 @@ public struct HKDF { /// /// - Returns: The derived symmetric key. public static func expand(pseudoRandomKey prk: PRK, info: Info?, outputByteCount: Int) -> SymmetricKey { - let iterations: UInt8 = UInt8(ceil((Float(outputByteCount) / Float(H.Digest.byteCount)))) + + let iterations: UInt8 = UInt8((Double(outputByteCount) / Double(H.Digest.byteCount)).rounded(.up)) + var output = SecureBytes() let key = SymmetricKey(data: prk) var TMinusOne = SecureBytes() for i in 1...iterations { var hmac = HMAC(key: key) hmac.update(data: TMinusOne) - if let info = info { + if let info { hmac.update(data: info) } withUnsafeBytes(of: i) { counter in hmac.update(bufferPointer: counter) } - TMinusOne = SecureBytes(hmac.finalize()) + TMinusOne = SecureBytes(bytes: hmac.finalize()) output.append(TMinusOne) } diff --git a/Sources/Crypto/Key Wrapping/AESWrap.swift b/Sources/Crypto/Key Wrapping/AESWrap.swift index 50519d63..935a113e 100644 --- a/Sources/Crypto/Key Wrapping/AESWrap.swift +++ b/Sources/Crypto/Key Wrapping/AESWrap.swift @@ -2,7 +2,7 @@ // // This source file is part of the SwiftCrypto open source project // -// Copyright (c) 2019-2021 Apple Inc. and the SwiftCrypto project authors +// Copyright (c) 2019-2020 Apple Inc. and the SwiftCrypto project authors // Licensed under Apache License v2.0 // // See LICENSE.txt for license information @@ -14,9 +14,14 @@ #if CRYPTO_IN_SWIFTPM && !CRYPTO_IN_SWIFTPM_FORCE_BUILD_API @_exported import CryptoKit #else + +#if CRYPTOKIT_NO_ACCESS_TO_FOUNDATION +import SwiftSystem +#else import Foundation +#endif -#if !CRYPTO_IN_SWIFTPM_FORCE_BUILD_API +#if (!CRYPTO_IN_SWIFTPM_FORCE_BUILD_API) || CRYPTOKIT_NO_ACCESS_TO_FOUNDATION typealias AESWRAPImpl = CoreCryptoAESWRAPImpl #else typealias AESWRAPImpl = BoringSSLAESWRAPImpl diff --git a/Sources/Crypto/Keys/EC/Ed25519Keys.swift b/Sources/Crypto/Keys/EC/Ed25519Keys.swift index 71e8ba45..1d72de96 100644 --- a/Sources/Crypto/Keys/EC/Ed25519Keys.swift +++ b/Sources/Crypto/Keys/EC/Ed25519Keys.swift @@ -14,7 +14,11 @@ #if CRYPTO_IN_SWIFTPM && !CRYPTO_IN_SWIFTPM_FORCE_BUILD_API @_exported import CryptoKit #else +#if CRYPTOKIT_NO_ACCESS_TO_FOUNDATION +import SwiftSystem +#else import Foundation +#endif extension Curve25519.Signing { static var keyByteCount: Int { @@ -26,7 +30,7 @@ extension Curve25519 { /// A mechanism used to create or verify a cryptographic signature using /// Ed25519. public enum Signing { - #if !CRYPTO_IN_SWIFTPM_FORCE_BUILD_API + #if (!CRYPTO_IN_SWIFTPM_FORCE_BUILD_API) || CRYPTOKIT_NO_ACCESS_TO_FOUNDATION typealias Curve25519PrivateKeyImpl = Curve25519.Signing.CoreCryptoCurve25519PrivateKeyImpl typealias Curve25519PublicKeyImpl = Curve25519.Signing.CoreCryptoCurve25519PublicKeyImpl #else diff --git a/Sources/Crypto/Keys/EC/NISTCurvesKeys.swift b/Sources/Crypto/Keys/EC/NISTCurvesKeys.swift index fe0541e9..3cd7f086 100644 --- a/Sources/Crypto/Keys/EC/NISTCurvesKeys.swift +++ b/Sources/Crypto/Keys/EC/NISTCurvesKeys.swift @@ -11,12 +11,16 @@ // SPDX-License-Identifier: Apache-2.0 // //===----------------------------------------------------------------------===// +#if CRYPTOKIT_NO_ACCESS_TO_FOUNDATION +import SwiftSystem +#else import Foundation +#endif #if CRYPTO_IN_SWIFTPM && !CRYPTO_IN_SWIFTPM_FORCE_BUILD_API @_exported import CryptoKit #else -#if !CRYPTO_IN_SWIFTPM_FORCE_BUILD_API +#if (!CRYPTO_IN_SWIFTPM_FORCE_BUILD_API) || CRYPTOKIT_NO_ACCESS_TO_FOUNDATION typealias SupportedCurveDetailsImpl = CorecryptoSupportedNISTCurve #else typealias SupportedCurveDetailsImpl = OpenSSLSupportedNISTCurve diff --git a/Sources/Crypto/Keys/EC/X25519Keys.swift b/Sources/Crypto/Keys/EC/X25519Keys.swift index acb04e9e..495e0d47 100644 --- a/Sources/Crypto/Keys/EC/X25519Keys.swift +++ b/Sources/Crypto/Keys/EC/X25519Keys.swift @@ -14,7 +14,11 @@ #if CRYPTO_IN_SWIFTPM && !CRYPTO_IN_SWIFTPM_FORCE_BUILD_API @_exported import CryptoKit #else +#if CRYPTOKIT_NO_ACCESS_TO_FOUNDATION +import SwiftSystem +#else import Foundation +#endif extension Curve25519.KeyAgreement { static var keyByteCount: Int { @@ -26,7 +30,7 @@ extension Curve25519 { /// A mechanism used to create a shared secret between two users by /// performing X25519 key agreement. public enum KeyAgreement { - #if !CRYPTO_IN_SWIFTPM_FORCE_BUILD_API + #if (!CRYPTO_IN_SWIFTPM_FORCE_BUILD_API) || CRYPTOKIT_NO_ACCESS_TO_FOUNDATION typealias Curve25519PrivateKeyImpl = Curve25519.KeyAgreement.CoreCryptoCurve25519PrivateKeyImpl typealias Curve25519PublicKeyImpl = Curve25519.KeyAgreement.CoreCryptoCurve25519PublicKeyImpl #else diff --git a/Sources/Crypto/Keys/Symmetric/SymmetricKeys.swift b/Sources/Crypto/Keys/Symmetric/SymmetricKeys.swift index 1696436d..2d059a81 100644 --- a/Sources/Crypto/Keys/Symmetric/SymmetricKeys.swift +++ b/Sources/Crypto/Keys/Symmetric/SymmetricKeys.swift @@ -14,7 +14,12 @@ #if CRYPTO_IN_SWIFTPM && !CRYPTO_IN_SWIFTPM_FORCE_BUILD_API @_exported import CryptoKit #else + +#if CRYPTOKIT_NO_ACCESS_TO_FOUNDATION +import SwiftSystem +#else import Foundation +#endif /// The sizes that a symmetric cryptographic key can take. /// diff --git a/Sources/Crypto/Message Authentication Codes/HMAC/HMAC.swift b/Sources/Crypto/Message Authentication Codes/HMAC/HMAC.swift index 53b1f15a..4baaea33 100644 --- a/Sources/Crypto/Message Authentication Codes/HMAC/HMAC.swift +++ b/Sources/Crypto/Message Authentication Codes/HMAC/HMAC.swift @@ -12,9 +12,17 @@ // //===----------------------------------------------------------------------===// #if CRYPTO_IN_SWIFTPM && !CRYPTO_IN_SWIFTPM_FORCE_BUILD_API +#if CRYPTOKIT_STATIC_LIBRARY +@_exported import CryptoKit_Static +#else @_exported import CryptoKit +#endif +#else +#if CRYPTOKIT_NO_ACCESS_TO_FOUNDATION +import SwiftSystem #else import Foundation +#endif /// A hash-based message authentication algorithm. /// diff --git a/Sources/Crypto/Message Authentication Codes/MACFunctions.swift b/Sources/Crypto/Message Authentication Codes/MACFunctions.swift index 012423dd..b51debe0 100644 --- a/Sources/Crypto/Message Authentication Codes/MACFunctions.swift +++ b/Sources/Crypto/Message Authentication Codes/MACFunctions.swift @@ -14,12 +14,20 @@ #if CRYPTO_IN_SWIFTPM && !CRYPTO_IN_SWIFTPM_FORCE_BUILD_API @_exported import CryptoKit #else +#if CRYPTOKIT_NO_ACCESS_TO_FOUNDATION +import SwiftSystem +#else import Foundation +#endif protocol MACAlgorithm { associatedtype Key - #if !CRYPTO_IN_SWIFTPM_FORCE_BUILD_API + #if (!CRYPTO_IN_SWIFTPM_FORCE_BUILD_API) || CRYPTOKIT_NO_ACCESS_TO_FOUNDATION + #if CRYPTOKIT_STATIC_LIBRARY + associatedtype MAC: CryptoKit_Static.MessageAuthenticationCode + #else associatedtype MAC: CryptoKit.MessageAuthenticationCode + #endif #else associatedtype MAC: Crypto.MessageAuthenticationCode #endif diff --git a/Sources/Crypto/Message Authentication Codes/MessageAuthenticationCode.swift b/Sources/Crypto/Message Authentication Codes/MessageAuthenticationCode.swift index 10b6e12c..8e30b662 100644 --- a/Sources/Crypto/Message Authentication Codes/MessageAuthenticationCode.swift +++ b/Sources/Crypto/Message Authentication Codes/MessageAuthenticationCode.swift @@ -12,9 +12,17 @@ // //===----------------------------------------------------------------------===// #if CRYPTO_IN_SWIFTPM && !CRYPTO_IN_SWIFTPM_FORCE_BUILD_API +#if CRYPTOKIT_STATIC_LIBRARY +@_exported import CryptoKit_Static +#else @_exported import CryptoKit +#endif +#else +#if CRYPTOKIT_NO_ACCESS_TO_FOUNDATION +import SwiftSystem #else import Foundation +#endif /// A type that represents a message authentication code. public protocol MessageAuthenticationCode: Hashable, ContiguousBytes, CustomStringConvertible, Sequence where Element == UInt8 { @@ -59,7 +67,7 @@ extension MessageAuthenticationCode { return Array(buffPtr.bindMemory(to: UInt8.self)).makeIterator() }) } - + public var description: String { return "\(Self.self): \(Array(self).hexString)" } diff --git a/Sources/Crypto/Signatures/ECDSA.swift b/Sources/Crypto/Signatures/ECDSA.swift index a609aed3..fef7cee7 100644 --- a/Sources/Crypto/Signatures/ECDSA.swift +++ b/Sources/Crypto/Signatures/ECDSA.swift @@ -14,7 +14,11 @@ #if CRYPTO_IN_SWIFTPM && !CRYPTO_IN_SWIFTPM_FORCE_BUILD_API @_exported import CryptoKit #else +#if !CRYPTOKIT_NO_ACCESS_TO_FOUNDATION import Foundation +#else +import SwiftSystem +#endif // MARK: - Generated file, do NOT edit // any edits of this file WILL be overwritten and thus discarded // see section `gyb` in `README` for details. @@ -140,7 +144,7 @@ extension P256.Signing.PrivateKey: DigestSigner { /// algorithm employs randomization to generate a different signature on /// every call, even for the same data and key. public func signature(for digest: D) throws -> P256.Signing.ECDSASignature { - #if !CRYPTO_IN_SWIFTPM_FORCE_BUILD_API + #if (!CRYPTO_IN_SWIFTPM_FORCE_BUILD_API) || CRYPTOKIT_NO_ACCESS_TO_FOUNDATION return try self.coreCryptoSignature(for: digest) #else return try self.openSSLSignature(for: digest) @@ -173,7 +177,7 @@ extension P256.Signing.PublicKey: DigestValidator { /// - Returns: A Boolean value that’s `true` if the signature is valid for /// the given digest; otherwise, `false`. public func isValidSignature(_ signature: P256.Signing.ECDSASignature, for digest: D) -> Bool { - #if !CRYPTO_IN_SWIFTPM_FORCE_BUILD_API + #if (!CRYPTO_IN_SWIFTPM_FORCE_BUILD_API) || CRYPTOKIT_NO_ACCESS_TO_FOUNDATION return self.coreCryptoIsValidSignature(signature, for: digest) #else return self.openSSLIsValidSignature(signature, for: digest) @@ -303,7 +307,7 @@ extension P384.Signing.PrivateKey: DigestSigner { /// algorithm employs randomization to generate a different signature on /// every call, even for the same data and key. public func signature(for digest: D) throws -> P384.Signing.ECDSASignature { - #if !CRYPTO_IN_SWIFTPM_FORCE_BUILD_API + #if (!CRYPTO_IN_SWIFTPM_FORCE_BUILD_API) || CRYPTOKIT_NO_ACCESS_TO_FOUNDATION return try self.coreCryptoSignature(for: digest) #else return try self.openSSLSignature(for: digest) @@ -336,7 +340,7 @@ extension P384.Signing.PublicKey: DigestValidator { /// - Returns: A Boolean value that’s `true` if the signature is valid for /// the given digest; otherwise, `false`. public func isValidSignature(_ signature: P384.Signing.ECDSASignature, for digest: D) -> Bool { - #if !CRYPTO_IN_SWIFTPM_FORCE_BUILD_API + #if (!CRYPTO_IN_SWIFTPM_FORCE_BUILD_API) || CRYPTOKIT_NO_ACCESS_TO_FOUNDATION return self.coreCryptoIsValidSignature(signature, for: digest) #else return self.openSSLIsValidSignature(signature, for: digest) @@ -466,7 +470,7 @@ extension P521.Signing.PrivateKey: DigestSigner { /// algorithm employs randomization to generate a different signature on /// every call, even for the same data and key. public func signature(for digest: D) throws -> P521.Signing.ECDSASignature { - #if !CRYPTO_IN_SWIFTPM_FORCE_BUILD_API + #if (!CRYPTO_IN_SWIFTPM_FORCE_BUILD_API) || CRYPTOKIT_NO_ACCESS_TO_FOUNDATION return try self.coreCryptoSignature(for: digest) #else return try self.openSSLSignature(for: digest) @@ -499,7 +503,7 @@ extension P521.Signing.PublicKey: DigestValidator { /// - Returns: A Boolean value that’s `true` if the signature is valid for /// the given digest; otherwise, `false`. public func isValidSignature(_ signature: P521.Signing.ECDSASignature, for digest: D) -> Bool { - #if !CRYPTO_IN_SWIFTPM_FORCE_BUILD_API + #if (!CRYPTO_IN_SWIFTPM_FORCE_BUILD_API) || CRYPTOKIT_NO_ACCESS_TO_FOUNDATION return self.coreCryptoIsValidSignature(signature, for: digest) #else return self.openSSLIsValidSignature(signature, for: digest) diff --git a/Sources/Crypto/Signatures/ECDSA.swift.gyb b/Sources/Crypto/Signatures/ECDSA.swift.gyb index 56bceed8..d3a11eb5 100644 --- a/Sources/Crypto/Signatures/ECDSA.swift.gyb +++ b/Sources/Crypto/Signatures/ECDSA.swift.gyb @@ -14,7 +14,11 @@ #if CRYPTO_IN_SWIFTPM && !CRYPTO_IN_SWIFTPM_FORCE_BUILD_API @_exported import CryptoKit #else +#if !CRYPTOKIT_NO_ACCESS_TO_FOUNDATION import Foundation +#else +import SwiftSystem +#endif // MARK: - Generated file, do NOT edit // any edits of this file WILL be overwritten and thus discarded // see section `gyb` in `README` for details. @@ -150,7 +154,7 @@ extension ${CURVE}.Signing.PrivateKey: DigestSigner { /// algorithm employs randomization to generate a different signature on /// every call, even for the same data and key. public func signature(for digest: D) throws -> ${CURVE}.Signing.ECDSASignature { - #if !CRYPTO_IN_SWIFTPM_FORCE_BUILD_API + #if (!CRYPTO_IN_SWIFTPM_FORCE_BUILD_API) || CRYPTOKIT_NO_ACCESS_TO_FOUNDATION return try self.coreCryptoSignature(for: digest) #else return try self.openSSLSignature(for: digest) @@ -183,7 +187,7 @@ extension ${CURVE}.Signing.PublicKey: DigestValidator { /// - Returns: A Boolean value that’s `true` if the signature is valid for /// the given digest; otherwise, `false`. public func isValidSignature(_ signature: ${CURVE}.Signing.ECDSASignature, for digest: D) -> Bool { - #if !CRYPTO_IN_SWIFTPM_FORCE_BUILD_API + #if (!CRYPTO_IN_SWIFTPM_FORCE_BUILD_API) || CRYPTOKIT_NO_ACCESS_TO_FOUNDATION return self.coreCryptoIsValidSignature(signature, for: digest) #else return self.openSSLIsValidSignature(signature, for: digest) diff --git a/Sources/Crypto/Signatures/Ed25519.swift b/Sources/Crypto/Signatures/Ed25519.swift index a5151361..fca8819d 100644 --- a/Sources/Crypto/Signatures/Ed25519.swift +++ b/Sources/Crypto/Signatures/Ed25519.swift @@ -14,7 +14,11 @@ #if CRYPTO_IN_SWIFTPM && !CRYPTO_IN_SWIFTPM_FORCE_BUILD_API @_exported import CryptoKit #else +#if CRYPTOKIT_NO_ACCESS_TO_FOUNDATION +import SwiftSystem +#else import Foundation +#endif protocol DigestValidator { associatedtype Signature @@ -44,7 +48,7 @@ extension Curve25519.Signing.PublicKey: DataValidator { /// - Returns: A Boolean value that’s `true` when the signature is valid for /// the given data. public func isValidSignature(_ signature: S, for data: D) -> Bool { - #if !CRYPTO_IN_SWIFTPM_FORCE_BUILD_API + #if (!CRYPTO_IN_SWIFTPM_FORCE_BUILD_API) || CRYPTOKIT_NO_ACCESS_TO_FOUNDATION return self.coreCryptoIsValidSignature(signature, for: data) #else return self.openSSLIsValidSignature(signature, for: data) @@ -65,7 +69,7 @@ extension Curve25519.Signing.PrivateKey: Signer { /// different signature on every call, even for the same data and key, to /// guard against side-channel attacks. public func signature(for data: D) throws -> Data { - #if !CRYPTO_IN_SWIFTPM_FORCE_BUILD_API + #if (!CRYPTO_IN_SWIFTPM_FORCE_BUILD_API) || CRYPTOKIT_NO_ACCESS_TO_FOUNDATION return try self.coreCryptoSignature(for: data) #else return try self.openSSLSignature(for: data) diff --git a/Sources/Crypto/Signatures/Signature.swift b/Sources/Crypto/Signatures/Signature.swift index 9aa952a6..e0f84e14 100644 --- a/Sources/Crypto/Signatures/Signature.swift +++ b/Sources/Crypto/Signatures/Signature.swift @@ -14,7 +14,11 @@ #if CRYPTO_IN_SWIFTPM && !CRYPTO_IN_SWIFTPM_FORCE_BUILD_API @_exported import CryptoKit #else +#if CRYPTOKIT_NO_ACCESS_TO_FOUNDATION +import SwiftSystem +#else import Foundation +#endif protocol SignatureVerification { func verifySignature(signature: Data, data: Data) throws -> Bool diff --git a/Sources/Crypto/Util/PrettyBytes.swift b/Sources/Crypto/Util/PrettyBytes.swift index 2733f9ed..7e39a052 100644 --- a/Sources/Crypto/Util/PrettyBytes.swift +++ b/Sources/Crypto/Util/PrettyBytes.swift @@ -11,7 +11,11 @@ // SPDX-License-Identifier: Apache-2.0 // //===----------------------------------------------------------------------===// +#if CRYPTOKIT_NO_ACCESS_TO_FOUNDATION +import SwiftSystem +#else import Foundation +#endif enum ByteHexEncodingErrors: Error { case incorrectHexValue @@ -50,16 +54,17 @@ extension DataProtocol { } } - return String(bytes: hexChars, encoding: .utf8)! + return String(decoding: hexChars, as: UTF8.self) } } -extension MutableDataProtocol { +extension RangeReplaceableCollection where Element == UInt8 { mutating func appendByte(_ byte: UInt64) { - withUnsafePointer(to: byte.littleEndian, { self.append(contentsOf: UnsafeRawBufferPointer(start: $0, count: 8)) }) + withUnsafeBytes(of: byte.littleEndian, { self.append(contentsOf: $0) }) } } +#if !CRYPTOKIT_NO_ACCESS_TO_FOUNDATION extension Data { init(hexString: String) throws { self.init() @@ -98,3 +103,4 @@ extension Array where Element == UInt8 { } } +#endif diff --git a/Sources/Crypto/Util/SafeCompare.swift b/Sources/Crypto/Util/SafeCompare.swift index 97c80d1c..29f8d56f 100644 --- a/Sources/Crypto/Util/SafeCompare.swift +++ b/Sources/Crypto/Util/SafeCompare.swift @@ -12,12 +12,20 @@ // //===----------------------------------------------------------------------===// #if CRYPTO_IN_SWIFTPM && !CRYPTO_IN_SWIFTPM_FORCE_BUILD_API +#if CRYPTOKIT_STATIC_LIBRARY +@_exported import CryptoKit_Static +#else @_exported import CryptoKit +#endif +#else +#if CRYPTOKIT_NO_ACCESS_TO_FOUNDATION +import SwiftSystem #else import Foundation +#endif internal func safeCompare(_ lhs: LHS, _ rhs: RHS) -> Bool { - #if !CRYPTO_IN_SWIFTPM_FORCE_BUILD_API + #if (!CRYPTO_IN_SWIFTPM_FORCE_BUILD_API) || CRYPTOKIT_NO_ACCESS_TO_FOUNDATION return coreCryptoSafeCompare(lhs, rhs) #else return openSSLSafeCompare(lhs, rhs) diff --git a/Sources/Crypto/Util/SecureBytes.swift b/Sources/Crypto/Util/SecureBytes.swift index b67f6970..513d2583 100644 --- a/Sources/Crypto/Util/SecureBytes.swift +++ b/Sources/Crypto/Util/SecureBytes.swift @@ -12,9 +12,17 @@ // //===----------------------------------------------------------------------===// #if CRYPTO_IN_SWIFTPM && !CRYPTO_IN_SWIFTPM_FORCE_BUILD_API +#if CRYPTOKIT_STATIC_LIBRARY +@_exported import CryptoKit_Static +#else @_exported import CryptoKit +#endif +#else +#if CRYPTOKIT_NO_ACCESS_TO_FOUNDATION +import SwiftSystem #else import Foundation +#endif private let emptyStorage:SecureBytes.Backing = SecureBytes.Backing.createEmpty() @@ -170,11 +178,11 @@ extension SecureBytes: RangeReplaceableCollection { // The default implementation of this from RangeReplaceableCollection can't take advantage of `ContiguousBytes`, so we override it here @inlinable - public mutating func append(contentsOf newElements: Elements) where Elements.Element == UInt8 { + public mutating func append(contentsOf newElements: some Sequence) { let done:Void? = newElements.withContiguousStorageIfAvailable { replaceSubrange(endIndex..(_ body: (UnsafeBufferPointer) throws -> R) rethrows -> R? { return try self.backing.withContiguousStorageIfAvailable(body) @@ -248,12 +256,12 @@ extension SecureBytes { @usableFromInline internal class Backing: ManagedBuffer { - + @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()) @@ -445,7 +453,7 @@ extension SecureBytes.Backing: ContiguousBytes { return try body(UnsafeMutableRawBufferPointer(start: elementsPtr, count: capacity)) } } - + func withContiguousStorageIfAvailable(_ body: (UnsafeBufferPointer) throws -> R) rethrows -> R? { let count = self.count @@ -493,6 +501,12 @@ extension Data { /// This is our best-effort attempt to expose the data in an auto-zeroing fashion. Any mutating function called on /// the constructed `Data` object will cause the bytes to be copied out: we can't avoid that. init(_ secureBytes: SecureBytes) { + #if CRYPTOKIT_NO_ACCESS_TO_FOUNDATION + self = secureBytes.withUnsafeBytes { + // We make a mutable copy of this pointer here because we know Data won't write through it. + return Data($0) + } + #else // We need to escape into unmanaged land here in order to keep the backing storage alive. let unmanagedBacking = Unmanaged.passRetained(secureBytes.backing) @@ -502,6 +516,7 @@ extension Data { // We make a mutable copy of this pointer here because we know Data won't write through it. return Data(bytesNoCopy: UnsafeMutableRawPointer(mutating: $0.baseAddress!), count: $0.count, deallocator: .custom { (_: UnsafeMutableRawPointer, _: Int) in unmanagedBacking.release() }) } + #endif } /// A custom initializer for Data that attempts to share the same storage as the current SecureBytes instance. @@ -513,7 +528,16 @@ extension Data { let base = secureByteSlice.base let baseOffset = secureByteSlice.startIndex.offset let endOffset = secureByteSlice.endIndex.offset + + #if CRYPTOKIT_NO_ACCESS_TO_FOUNDATION + self = base.withUnsafeBytes { + // Slice the base pointer down to just the range we want. + let slicedPointer = UnsafeRawBufferPointer(rebasing: $0[baseOffset.. Bool { - switch (lhs, rhs) { - case (.incorrectKeySize, .incorrectKeySize): - return true - case (.incorrectParameterSize, .incorrectParameterSize): - return true - case (.authenticationFailure, .authenticationFailure): - return true - case (.wrapFailure, .wrapFailure): - return true - case (.unwrapFailure, .unwrapFailure): - return true - case (.underlyingCoreCryptoError(let lhsError), .underlyingCoreCryptoError(let rhsError)): - return lhsError == rhsError - default: - return false - } - } -} - -#endif // Linux or !SwiftPM diff --git a/Tests/CryptoTests/SecureBytes/SecureBytesTests.swift b/Tests/CryptoTests/SecureBytes/SecureBytesTests.swift index 031bc1ce..b41c1cfd 100644 --- a/Tests/CryptoTests/SecureBytes/SecureBytesTests.swift +++ b/Tests/CryptoTests/SecureBytes/SecureBytesTests.swift @@ -172,12 +172,7 @@ final class SecureBytesTests: XCTestCase { throw CryptoKitError.incorrectKeySize } } - XCTAssertThrowsError(try testThrowingInitialization()) { error in - guard case .some(.incorrectKeySize) = error as? CryptoKitError else { - XCTFail("unexpected error: \(error)") - return - } - } + XCTAssertThrowsError(try testThrowingInitialization(), error: CryptoKitError.incorrectKeySize) } func testAppendingDataPerformsACoW() { diff --git a/Tests/CryptoTests/Signatures/ECDSA/ECDSASignatureTests.swift b/Tests/CryptoTests/Signatures/ECDSA/ECDSASignatureTests.swift index 6dbb64ef..25009685 100644 --- a/Tests/CryptoTests/Signatures/ECDSA/ECDSASignatureTests.swift +++ b/Tests/CryptoTests/Signatures/ECDSA/ECDSASignatureTests.swift @@ -226,26 +226,12 @@ class SignatureTests: XCTestCase { } func testProperSignatureSizes() throws { - XCTAssertThrowsError(try P256.Signing.ECDSASignature(rawRepresentation: Array("hello".utf8))) { error in - guard case .some(.incorrectParameterSize) = error as? CryptoKitError else { - XCTFail("Incorrect error: \(error)") - return - } - } - - XCTAssertThrowsError(try P384.Signing.ECDSASignature(rawRepresentation: Array("hello".utf8))) { error in - guard case .some(.incorrectParameterSize) = error as? CryptoKitError else { - XCTFail("Incorrect error: \(error)") - return - } - } - - XCTAssertThrowsError(try P521.Signing.ECDSASignature(rawRepresentation: Array("hello".utf8))) { error in - guard case .some(.incorrectParameterSize) = error as? CryptoKitError else { - XCTFail("Incorrect error: \(error)") - return - } - } + XCTAssertThrowsError(try P256.Signing.ECDSASignature(rawRepresentation: Array("hello".utf8)), + error: CryptoKitError.incorrectParameterSize) + XCTAssertThrowsError(try P384.Signing.ECDSASignature(rawRepresentation: Array("hello".utf8)), + error: CryptoKitError.incorrectParameterSize) + XCTAssertThrowsError(try P521.Signing.ECDSASignature(rawRepresentation: Array("hello".utf8)), + error: CryptoKitError.incorrectParameterSize) } func testP256SigningDiscontiguousData() throws { diff --git a/Tests/CryptoTests/Signatures/EdDSA/Ed25519-Runner.swift b/Tests/CryptoTests/Signatures/EdDSA/Ed25519-Runner.swift index dc33f013..47d93681 100644 --- a/Tests/CryptoTests/Signatures/EdDSA/Ed25519-Runner.swift +++ b/Tests/CryptoTests/Signatures/EdDSA/Ed25519-Runner.swift @@ -57,7 +57,7 @@ class Ed25519Tests: XCTestCase { let signatureOnContiguous = try orFail { try privateKey.signature(for: someContiguousData) } let signatureOnDiscontiguous = try orFail { try privateKey.signature(for: someDiscontiguousData) } - #if !(canImport(Darwin)) + #if !canImport(Darwin) XCTAssertEqual(signatureOnContiguous, signatureOnDiscontiguous) #endif diff --git a/Tests/CryptoTests/Utils/PrettyBytes.swift b/Tests/CryptoTests/Utils/PrettyBytes.swift index 2733f9ed..7e39a052 100644 --- a/Tests/CryptoTests/Utils/PrettyBytes.swift +++ b/Tests/CryptoTests/Utils/PrettyBytes.swift @@ -11,7 +11,11 @@ // SPDX-License-Identifier: Apache-2.0 // //===----------------------------------------------------------------------===// +#if CRYPTOKIT_NO_ACCESS_TO_FOUNDATION +import SwiftSystem +#else import Foundation +#endif enum ByteHexEncodingErrors: Error { case incorrectHexValue @@ -50,16 +54,17 @@ extension DataProtocol { } } - return String(bytes: hexChars, encoding: .utf8)! + return String(decoding: hexChars, as: UTF8.self) } } -extension MutableDataProtocol { +extension RangeReplaceableCollection where Element == UInt8 { mutating func appendByte(_ byte: UInt64) { - withUnsafePointer(to: byte.littleEndian, { self.append(contentsOf: UnsafeRawBufferPointer(start: $0, count: 8)) }) + withUnsafeBytes(of: byte.littleEndian, { self.append(contentsOf: $0) }) } } +#if !CRYPTOKIT_NO_ACCESS_TO_FOUNDATION extension Data { init(hexString: String) throws { self.init() @@ -98,3 +103,4 @@ extension Array where Element == UInt8 { } } +#endif diff --git a/Tests/CryptoTests/Utils/XCTestUtils.swift b/Tests/CryptoTests/Utils/XCTestUtils.swift index 01ff197a..69e4b907 100644 --- a/Tests/CryptoTests/Utils/XCTestUtils.swift +++ b/Tests/CryptoTests/Utils/XCTestUtils.swift @@ -12,6 +12,7 @@ // //===----------------------------------------------------------------------===// import XCTest +import Crypto // Xcode 11.4 catches errors thrown during tests and reports them on the // correct line. But Linux and older Xcodes do not, so we need to use this @@ -52,5 +53,17 @@ extension XCTestCase { return wrapped } +} +func XCTAssertThrowsError( + _ expression: @autoclosure () throws -> T, + error: E, + _ message: @autoclosure () -> String = "", + file: StaticString = #file, + line: UInt = #line) +{ + XCTAssertThrowsError(try expression(), message(), file: file, line: line) { foundError in + XCTAssertEqual(foundError as? E, error, message(), file: file, line: line) + } } +