diff --git a/Package.swift b/Package.swift index b143760..7c245b4 100644 --- a/Package.swift +++ b/Package.swift @@ -14,7 +14,7 @@ let package = Package( ], dependencies: [ // Dependencies declare other packages that this package depends on. - .package(url: "https://github.com/leif-ibsen/BigInt", from: "1.13.0"), + .package(url: "https://github.com/leif-ibsen/BigInt", from: "1.14.0"), .package(url: "https://github.com/leif-ibsen/ASN1", from: "2.1.0"), ], targets: [ diff --git a/README.md b/README.md index 70681e5..f83856b 100755 --- a/README.md +++ b/README.md @@ -8,6 +8,7 @@
  • Encryption and Decryption
  • Secret Export
  • CryptoKit Compatibility
  • +
  • Performance
  • Dependencies
  • References
  • @@ -16,7 +17,7 @@ SwiftHPKE implements the Hybrid Public Key Encryption standard as defined in RFC In your project Package.swift file add a dependency like
    dependencies: [ - .package(url: "https://github.com/leif-ibsen/SwiftHPKE", from: "1.3.0"), + .package(url: "https://github.com/leif-ibsen/SwiftHPKE", from: "1.4.0"), ] SwiftHPKE requires Swift 5.0. It also requires that the Int and UInt types be 64 bit types. SwiftHPKE uses Apple's CryptoKit framework. Therefore, for macOS the version must be at least 10.15, @@ -246,33 +247,51 @@ is also possible. The SwiftHPKE keys of type .P256, .P384, .P521 and .X25519 are equivalent to CryptoKit keys of type P256, P384, P521 and Curve25519. Keys of type .X448 is not supported in CryptoKit. -To convert CryptoKit P256 keys (similarly for P384 and P521) - say *cc256priv* and *cc256pub*: +To convert CryptoKit P256 keys (similarly for P384 and P521) - say *ckPriv* and *ckPub* to SwiftHPKE keys: - let hpke256priv = try PrivateKey(der: Bytes(cc256priv.derRepresentation)) - let hpke256pub = try PublicKey(der: Bytes(cc256pub.derRepresentation)) + let hpkePriv = try PrivateKey(der: Bytes(ckPriv.derRepresentation)) + let hpkePub = try PublicKey(der: Bytes(ckPub.derRepresentation)) -To convert CryptoKit Curve25519 keys - say *cc25519priv* and *cc25519pub*: +To convert CryptoKit Curve25519 keys - say *ckPriv* and *ckPub* to SwiftHPKE keys: - let hpke25519priv = try PrivateKey(kem: .X25519, bytes: Bytes(cc25519priv.rawRepresentation)) - let hpke25519pub = try PublicKey(kem: .X25519, bytes: Bytes(cc25519pub.rawRepresentation)) + let hpkePriv = try PrivateKey(kem: .X25519, bytes: Bytes(ckPriv.rawRepresentation)) + let hpkePub = try PublicKey(kem: .X25519, bytes: Bytes(ckPub.rawRepresentation)) -To convert SwiftHPKE .P256 keys (similarly for .P384 and .P521) - say *hpke256priv* and *hpke256pub*: +To convert SwiftHPKE .P256 keys (similarly for .P384 and .P521) - say *hpkePriv* and *hpkePub* to CryptoKit keys: - let cc256priv = try CryptoKit.P256.KeyAgreement.PrivateKey(derRepresentation: hpke256priv.der) - let cc256pub = try CryptoKit.P256.KeyAgreement.PublicKey(derRepresentation: hpke256pub.der) + let ckPriv = try CryptoKit.P256.KeyAgreement.PrivateKey(derRepresentation: hpkePriv.der) + let ckPub = try CryptoKit.P256.KeyAgreement.PublicKey(derRepresentation: hpkePub.der) -To convert SwiftHPKE .X25519 keys - say *hpke25519priv* and *hpke25519pub*: +To convert SwiftHPKE .X25519 keys - say *hpkePriv* and *hpkePub* to CryptoKit keys: - let cc25519priv = try CryptoKit.Curve25519.KeyAgreement.PrivateKey(rawRepresentation: hpke25519priv.bytes) - let cc25519pub = try CryptoKit.Curve25519.KeyAgreement.PublicKey(rawRepresentation: hpke25519pub.bytes) + let ckPriv = try CryptoKit.Curve25519.KeyAgreement.PrivateKey(rawRepresentation: hpkePriv.bytes) + let ckPub = try CryptoKit.Curve25519.KeyAgreement.PublicKey(rawRepresentation: hpkePub.bytes) -

    Dependencies

    +

    Performance

    +SwiftHPKE's encryption and decryption performance was measured on an iMac 2021, Apple M1 chip. +The time to create a *Sender* and *Recipient* instance in base mode is shown in the table below, depending on the KEM type - units are milliseconds. + + + + + + + +
    KEMSenderRecipient
    P2567 mSec6 mSec
    P38420 mSec17 mSec
    P52146 mSec39 mSec
    X255190.14 mSec0.09 mSec
    X4481.1 mSec0.5 mSec
    +The encryption and decryption speed in base mode, once the *Sender* or *Recipient* instance is created, is shown in the table below, depending on the AEAD type - units are MBytes / Sec. + + + + + +
    AEADEncryption speedDecryption speed
    AESGCM1283500 MB/Sec (0.91 cycles / byte)3340 MB/Sec (0.96 cycles / byte)
    AESGCM2563640 MB/Sec (0.88 cycles / byte)3630 MB/Sec (0.88 cycles / byte)
    CHACHAPOLY555 MB/Sec (5.8 cycles / byte)557 MB/Sec (5.7 cycles / byte)
    +

    Dependencies

    The SwiftHPKE package depends on the ASN1 and BigInt packages dependencies: [ .package(url: "https://github.com/leif-ibsen/ASN1", from: "2.1.0"), - .package(url: "https://github.com/leif-ibsen/BigInt", from: "1.13.0"), + .package(url: "https://github.com/leif-ibsen/BigInt", from: "1.14.0"), ],

    References

    diff --git a/Sources/SwiftHPKE/CipherSuite.swift b/Sources/SwiftHPKE/CipherSuite.swift index 4f3a651..8774dc9 100644 --- a/Sources/SwiftHPKE/CipherSuite.swift +++ b/Sources/SwiftHPKE/CipherSuite.swift @@ -10,9 +10,6 @@ public typealias Byte = UInt8 /// Array of unsigned 8 bit values public typealias Bytes = [UInt8] - -/// A HPKE CipherSuite -/// /// A CipherSuite instance combines a *Key Encapsulation Mechanism* (KEM), a *Key Derivation Function* (KDF) /// and a *AEAD Encryption Algorithm* (AEAD). /// It can encrypt or decrypt a single message in one of four modes: diff --git a/Sources/SwiftHPKE/PrivateKey.swift b/Sources/SwiftHPKE/PrivateKey.swift index 4f64826..c39d827 100644 --- a/Sources/SwiftHPKE/PrivateKey.swift +++ b/Sources/SwiftHPKE/PrivateKey.swift @@ -8,8 +8,6 @@ import ASN1 import BigInt -/// A HPKE private key -/// /// There are five different private key types corresponding to the five KEM's /// /// * P256 - the key is a 32 byte value corresponding to a NIST curve secp256r1 private key diff --git a/Sources/SwiftHPKE/PublicKey.swift b/Sources/SwiftHPKE/PublicKey.swift index e3ec49d..a30a95c 100644 --- a/Sources/SwiftHPKE/PublicKey.swift +++ b/Sources/SwiftHPKE/PublicKey.swift @@ -8,8 +8,6 @@ import ASN1 import BigInt -/// A HPKE public key -/// /// There are five different public key types corresponding to the five KEM's /// /// * P256 - the key is a 65 byte value corresponding to a NIST secp256r1 uncompressed curve point @@ -26,7 +24,9 @@ public struct PublicKey: CustomStringConvertible, Equatable { // MARK: Initializers - /// Creates a PublicKey from its type and key bytes + /// Creates a PublicKey from its type and key bytes.
    + /// For types P256, P384 and P521 the key bytes represents + /// either a compressed curve point or an uncompressed curve point. /// /// - Parameters: /// - kem: The key type diff --git a/Sources/SwiftHPKE/Recipient.swift b/Sources/SwiftHPKE/Recipient.swift index 57cdcc9..89d5916 100644 --- a/Sources/SwiftHPKE/Recipient.swift +++ b/Sources/SwiftHPKE/Recipient.swift @@ -5,8 +5,6 @@ // Created by Leif Ibsen on 19/06/2023. // -/// Recipient -/// /// Based on its *CipherSuite*, a *Recipient* instance can decrypt a sequence of messages in one of four modes: /// /// * Base mode @@ -14,7 +12,8 @@ /// * Authenticated mode /// * Authenticated, preshared key mode /// -/// The decryption of the messages must be done in the order in which they were encrypted +/// The decryption of the messages must be done in the order in which they were encrypted.
    +/// A *Recipient* instance can also retrieve a generated export secret. public class Recipient { let suite: CipherSuite diff --git a/Sources/SwiftHPKE/Sender.swift b/Sources/SwiftHPKE/Sender.swift index d4e3597..c6ee001 100644 --- a/Sources/SwiftHPKE/Sender.swift +++ b/Sources/SwiftHPKE/Sender.swift @@ -5,13 +5,13 @@ // Created by Leif Ibsen on 19/06/2023. // -/// Sender -/// /// Based on its *CipherSuite*, a *Sender* instance can encrypt a sequence of messages in one of four modes: /// * Base mode /// * Preshared key mode /// * Authenticated mode /// * Authenticated, preshared key mode +/// +/// A *Sender* instance can also generate an export secret that only the recipient can know. public class Sender { let suite: CipherSuite diff --git a/Sources/SwiftHPKE/X255_448/Field25519.swift b/Sources/SwiftHPKE/X255_448/Field25519.swift index d2e88fc..79deef4 100644 --- a/Sources/SwiftHPKE/X255_448/Field25519.swift +++ b/Sources/SwiftHPKE/X255_448/Field25519.swift @@ -140,23 +140,23 @@ struct Field25519: CustomStringConvertible { } func add(_ x: Field25519) -> Field25519 { - var v = Field25519( - self.l0 + x.l0, - self.l1 + x.l1, - self.l2 + x.l2, - self.l3 + x.l3, - self.l4 + x.l4) + var v = self + v.l0 += x.l0 + v.l1 += x.l1 + v.l2 += x.l2 + v.l3 += x.l3 + v.l4 += x.l4 v.carryPropagate() return v } func sub(_ x: Field25519) -> Field25519 { - var v = Field25519( - (self.l0 + 0xfffffffffffda) - x.l0, - (self.l1 + 0xffffffffffffe) - x.l1, - (self.l2 + 0xffffffffffffe) - x.l2, - (self.l3 + 0xffffffffffffe) - x.l3, - (self.l4 + 0xffffffffffffe) - x.l4) + var v = self + v.l0 += 0xfffffffffffda - x.l0 + v.l1 += 0xffffffffffffe - x.l1 + v.l2 += 0xffffffffffffe - x.l2 + v.l3 += 0xffffffffffffe - x.l3 + v.l4 += 0xffffffffffffe - x.l4 v.carryPropagate() return v } diff --git a/Sources/SwiftHPKE/X255_448/Field448.swift b/Sources/SwiftHPKE/X255_448/Field448.swift index a66f49a..ae9b093 100644 --- a/Sources/SwiftHPKE/X255_448/Field448.swift +++ b/Sources/SwiftHPKE/X255_448/Field448.swift @@ -84,9 +84,14 @@ struct Field448: CustomStringConvertible { func add(_ a: Field448) -> Field448 { var x = self - for i in 0 ..< 8 { - x.l[i] &+= a.l[i] - } + x.l[0] &+= a.l[0] + x.l[1] &+= a.l[1] + x.l[2] &+= a.l[2] + x.l[3] &+= a.l[3] + x.l[4] &+= a.l[4] + x.l[5] &+= a.l[5] + x.l[6] &+= a.l[6] + x.l[7] &+= a.l[7] x.reduce() return x } diff --git a/Tests/SwiftHPKETests/WycheproofP256Test.swift b/Tests/SwiftHPKETests/WycheproofP256Test.swift new file mode 100644 index 0000000..e9b5398 --- /dev/null +++ b/Tests/SwiftHPKETests/WycheproofP256Test.swift @@ -0,0 +1,85 @@ +// +// WycheproofP256Test.swift +// +// +// Created by Leif Ibsen on 06/09/2023. +// + +import XCTest +@testable import SwiftHPKE + +// Test vectors from project Wycheproof - ecdh_secp256r1_test.json +final class WycheproofP256Test: XCTestCase { + + static func hex2bytes(_ x: String) -> Bytes { + let b = [Byte](x.utf8) + var bytes = Bytes(repeating: 0, count: b.count / 2) + for i in 0 ..< bytes.count { + let b0 = b[2 * i] + let b1 = b[2 * i + 1] + bytes[i] = ((b0 > 57 ? b0 - 97 + 10 : b0 - 48) << 4) | (b1 > 57 ? b1 - 97 + 10 : b1 - 48) + } + return bytes + } + + struct dhTest { + + let pubKey: Bytes + let privKey: Bytes + let shared: Bytes + + init(_ pubKey: String, _ privKey: String, _ shared: String) { + self.pubKey = hex2bytes(pubKey) + self.privKey = hex2bytes(privKey) + self.shared = hex2bytes(shared) + } + } + + let tests256: [dhTest] = [ + // tcId = 1, normal case + dhTest( + "0462d5bd3372af75fe85a040715d0f502428e07046868b0bfdfa61d731afe44f26ac333a93a9e70a81cd5a95b5bf8d13990eb741c8c38872b4a07d275a014e30cf", + "0612465c89a023ab17855b0a6bcebfd3febb53aef84138647b5352e02c10c346", + "53020d908b0219328b658b525f26780e3ae12bcd952bb25a93bc0895e1714285"), + // tcId = 2, compressed public key + dhTest( + "0362d5bd3372af75fe85a040715d0f502428e07046868b0bfdfa61d731afe44f26", + "0612465c89a023ab17855b0a6bcebfd3febb53aef84138647b5352e02c10c346", + "53020d908b0219328b658b525f26780e3ae12bcd952bb25a93bc0895e1714285"), + // tcId = 3, shared secret has x-coordinate that satisfies x**2 = 0 + dhTest( + "0458fd4168a87795603e2b04390285bdca6e57de6027fe211dd9d25e2212d29e62080d36bd224d7405509295eed02a17150e03b314f96da37445b0d1d29377d12c", + "0a0d622a47e48f6bc1038ace438c6f528aa00ad2bd1da5f13ee46bf5f633d71a", + "0000000000000000000000000000000000000000000000000000000000000000"), + // tcId = 4, shared secret has x-coordinate p-3 + dhTest( + "04a1ecc24bf0d0053d23f5fd80ddf1735a1925039dc1176c581a7e795163c8b9ba2cb5a4e4d5109f4527575e3137b83d79a9bcb3faeff90d2aca2bed71bb523e7e", + "0a0d622a47e48f6bc1038ace438c6f528aa00ad2bd1da5f13ee46bf5f633d71a", + "ffffffff00000001000000000000000000000000fffffffffffffffffffffffc"), + // tcId = 45, y-coordinate of the public key is small + dhTest( + "043cbc1b31b43f17dc200dd70c2944c04c6cb1b082820c234a300b05b7763844c74fde0a4ef93887469793270eb2ff148287da9265b0334f9e2609aac16e8ad503", + "0a0d622a47e48f6bc1038ace438c6f528aa00ad2bd1da5f13ee46bf5f633d71a", + "7fffffffffffffffffffffffeecf2230ffffffffffffffffffffffffffffffff"), + // tcId = 51, y-coordinate of the public key is large + dhTest( + "043cbc1b31b43f17dc200dd70c2944c04c6cb1b082820c234a300b05b7763844c7b021f5b006c778ba686cd8f14d00eb7d78256d9b4fccb061d9f6553e91752afc", + "0a0d622a47e48f6bc1038ace438c6f528aa00ad2bd1da5f13ee46bf5f633d71a", + "7fffffffffffffffffffffffeecf2230ffffffffffffffffffffffffffffffff"), + // tcId = 228, point with coordinate y = 1 + dhTest( + "0409e78d4ef60d05f750f6636209092bc43cbdd6b47e11a9de20a9feb2a50bb96c0000000000000000000000000000000000000000000000000000000000000001", + "00809c461d8b39163537ff8f5ef5b977e4cdb980e70e38a7ee0b37cc876729e9ff", + "28f67757acc28b1684ba76ffd534aed42d45b8b3f10b82a5699416eff7199a74"), + ] + + func test256() throws { + let kem = KEMStructure(.P256) + for test in tests256 { + let priv = try PrivateKey(kem: .P256, bytes: test.privKey) + let pub = try PublicKey(kem: .P256, bytes: test.pubKey) + XCTAssertEqual(try kem.DH(priv, pub), test.shared) + } + } + +} diff --git a/Tests/SwiftHPKETests/WycheproofP384Test.swift b/Tests/SwiftHPKETests/WycheproofP384Test.swift new file mode 100644 index 0000000..1512aca --- /dev/null +++ b/Tests/SwiftHPKETests/WycheproofP384Test.swift @@ -0,0 +1,80 @@ +// +// WycheproofP384Test.swift +// +// +// Created by Leif Ibsen on 06/09/2023. +// + +import XCTest +@testable import SwiftHPKE + +// Test vectors from project Wycheproof - ecdh_secp384r1_test.json +final class WycheproofP384Test: XCTestCase { + + static func hex2bytes(_ x: String) -> Bytes { + let b = [Byte](x.utf8) + var bytes = Bytes(repeating: 0, count: b.count / 2) + for i in 0 ..< bytes.count { + let b0 = b[2 * i] + let b1 = b[2 * i + 1] + bytes[i] = ((b0 > 57 ? b0 - 97 + 10 : b0 - 48) << 4) | (b1 > 57 ? b1 - 97 + 10 : b1 - 48) + } + return bytes + } + + struct dhTest { + + let pubKey: Bytes + let privKey: Bytes + let shared: Bytes + + init(_ pubKey: String, _ privKey: String, _ shared: String) { + self.pubKey = hex2bytes(pubKey) + self.privKey = hex2bytes(privKey) + self.shared = hex2bytes(shared) + } + } + + let tests384: [dhTest] = [ + // tcId = 1, normal case + dhTest( + "04790a6e059ef9a5940163183d4a7809135d29791643fc43a2f17ee8bf677ab84f791b64a6be15969ffa012dd9185d8796d9b954baa8a75e82df711b3b56eadff6b0f668c3b26b4b1aeb308a1fcc1c680d329a6705025f1c98a0b5e5bfcb163caa", + "766e61425b2da9f846c09fc3564b93a6f8603b7392c785165bf20da948c49fd1fb1dee4edd64356b9f21c588b75dfd81", + "6461defb95d996b24296f5a1832b34db05ed031114fbe7d98d098f93859866e4de1e229da71fef0c77fe49b249190135"), + // tcId = 2, compressed public key + dhTest( + "02790a6e059ef9a5940163183d4a7809135d29791643fc43a2f17ee8bf677ab84f791b64a6be15969ffa012dd9185d8796", + "766e61425b2da9f846c09fc3564b93a6f8603b7392c785165bf20da948c49fd1fb1dee4edd64356b9f21c588b75dfd81", + "6461defb95d996b24296f5a1832b34db05ed031114fbe7d98d098f93859866e4de1e229da71fef0c77fe49b249190135"), + // tcId = 3, shared secret has x-coordinate that satisfies x**2 = 0 + dhTest( + "04490e96d17f4c6ceccd45def408cea33e9704a5f1b01a3de2eaaa3409fd160d78d395d6b3b003d71fd1f590fad95bf1c9d8665efc2070d059aa847125c2f707435955535c7c5df6d6c079ec806dce6b6849d337140db7ca50616f9456de1323c4", + "00a2b6442a37f8a3759d2cb91df5eca75b14f5a6766da8035cc1943b15a8e4ebb6025f373be334080f22ab821a3535a6a7", + "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"), + // tcId = 49, y-coordinate of the public key is small + dhTest( + "04bfeb47fb40a65878e6b642f40b8e15022ade9ecfa8cb618043063494e2bc5d2df10d36f37869b58ef12dcc35e3982835fd2e55ec41fdfe8cabbbb7bcd8163645a19e9dac59630f3fe93b208094ff87cd461b53cef53482e70e2e8ea87200cc3f", + "00a2b6442a37f8a3759d2cb91df5eca75b14f5a6766da8035cc1943b15a8e4ebb6025f373be334080f22ab821a3535a6a7", + "0000000000000000000000000000000000000000000000000000000036a2907c00000000000000000000000000000000"), + // tcId = 51, y-coordinate of the public key is large + dhTest( + "04bfeb47fb40a65878e6b642f40b8e15022ade9ecfa8cb618043063494e2bc5d2df10d36f37869b58ef12dcc35e398283502d1aa13be0201735444484327e9c9ba5e616253a69cf0c016c4df7f6b007831b9e4ac300acb7d18f1d171588dff33c0", + "00a2b6442a37f8a3759d2cb91df5eca75b14f5a6766da8035cc1943b15a8e4ebb6025f373be334080f22ab821a3535a6a7", + "0000000000000000000000000000000000000000000000000000000036a2907c00000000000000000000000000000000"), + // tcId = 585, point with coordinate y = 1 + dhTest( + "042261b2bf605c22f2f3aef6338719b2c486388ad5240719a5257315969ef01ba27f0a104c89704773a81fdabee6ab5c78000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001", + "00c1781d86cac2c052b7e4f48cef415c5c133052f4e504397e75e4d7cd0ca149da0b4988b8a6ded5ceae4b580691376187", + "c923fb0d4b24e996e5e0d5df151d3c26b1f61c05b17b7fb39fc8590b47eeaff34709f6f7328923bdcaf7e8e413d77ddc"), + ] + + func test384() throws { + let kem = KEMStructure(.P384) + for test in tests384 { + let priv = try PrivateKey(kem: .P384, bytes: test.privKey) + let pub = try PublicKey(kem: .P384, bytes: test.pubKey) + XCTAssertEqual(try kem.DH(priv, pub), test.shared) + } + } + +} diff --git a/Tests/SwiftHPKETests/WycheproofP521Test.swift b/Tests/SwiftHPKETests/WycheproofP521Test.swift new file mode 100644 index 0000000..c52a3a2 --- /dev/null +++ b/Tests/SwiftHPKETests/WycheproofP521Test.swift @@ -0,0 +1,80 @@ +// +// WycheproofP521Test.swift +// +// +// Created by Leif Ibsen on 06/09/2023. +// + +import XCTest +@testable import SwiftHPKE + +// Test vectors from project Wycheproof - ecdh_secp521r1_test.json +final class WycheproofP521Test: XCTestCase { + + static func hex2bytes(_ x: String) -> Bytes { + let b = [Byte](x.utf8) + var bytes = Bytes(repeating: 0, count: b.count / 2) + for i in 0 ..< bytes.count { + let b0 = b[2 * i] + let b1 = b[2 * i + 1] + bytes[i] = ((b0 > 57 ? b0 - 97 + 10 : b0 - 48) << 4) | (b1 > 57 ? b1 - 97 + 10 : b1 - 48) + } + return bytes + } + + struct dhTest { + + let pubKey: Bytes + let privKey: Bytes + let shared: Bytes + + init(_ pubKey: String, _ privKey: String, _ shared: String) { + self.pubKey = hex2bytes(pubKey) + self.privKey = hex2bytes(privKey) + self.shared = hex2bytes(shared) + } + } + + let tests521: [dhTest] = [ + // tcId = 1, normal case + dhTest( + "040064da3e94733db536a74a0d8a5cb2265a31c54a1da6529a198377fbd38575d9d79769ca2bdf2d4c972642926d444891a652e7f492337251adf1613cf3077999b5ce00e04ad19cf9fd4722b0c824c069f70c3c0e7ebc5288940dfa92422152ae4a4f79183ced375afb54db1409ddf338b85bb6dbfc5950163346bb63a90a70c5aba098f7", + "01939982b529596ce77a94bc6efd03e92c21a849eb4f87b8f619d506efc9bb22e7c61640c90d598f795b64566dc6df43992ae34a1341d458574440a7371f611c7dcd", + "01f1e410f2c6262bce6879a3f46dfb7dd11d30eeee9ab49852102e1892201dd10f27266c2cf7cbccc7f6885099043dad80ff57f0df96acf283fb090de53df95f7d87"), + // tcId = 2, compressed public key + dhTest( + "030064da3e94733db536a74a0d8a5cb2265a31c54a1da6529a198377fbd38575d9d79769ca2bdf2d4c972642926d444891a652e7f492337251adf1613cf3077999b5ce", + "01939982b529596ce77a94bc6efd03e92c21a849eb4f87b8f619d506efc9bb22e7c61640c90d598f795b64566dc6df43992ae34a1341d458574440a7371f611c7dcd", + "01f1e410f2c6262bce6879a3f46dfb7dd11d30eeee9ab49852102e1892201dd10f27266c2cf7cbccc7f6885099043dad80ff57f0df96acf283fb090de53df95f7d87"), + // tcId = 3, shared secret has x-coordinate that satisfies x**2 = 0 + dhTest( + "04014c643329691ba27459a40dfe7c4ce17b3ea14d0cd7aa47b01f1315404db51436fbbfe6de0842e0f7e1265f6ff3aca28750677d3370b2fb2a6ef497356f4b95811201051b14178639a09a41465c72d3743436ee1c191ff7388a40140b34d5317de5911ea03cdbb0329fdeb446695a3b92d437271a9f3c318b02dec4d473908158140e97", + "00a2b6442a37f8a3759d2cb91df5eca75af6b89e27baf2f6cbf971dee5058ffa9d8dac805c7bc72f3718489d6a9cb2787af8c93a17ddeb1a19211ab23604d47b7646", + "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"), + // tcId = 45, ephemeral key has x-coordinate that satisfies x**2 = 0 + dhTest( + "0400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000d20ec9fea6b577c10d26ca1bb446f40b299e648b1ad508aad068896fee3f8e614bc63054d5772bf01a65d412e0bcaa8e965d2f5d332d7f39f846d440ae001f4f87", + "012bc15cf3981eab6102c39f9a925aa130763d01ed6edaf14306eb0a14dd75dff504070def7b88d8b165082f69992de0ffa5ee922cb3ab39917da8524cac73f0a09c", + "0053bf137fee8922769f8d0fe279caa4dac9c6054ad0460995588a845d0a959e24bc0fc2391a2b92f7bd400f50a11a9db37f07bef7fa8dad2a903fcf534abc8736f7"), + // tcId = 46, ephemeral key has x-coordinate that satisfies x**2 = 1 + dhTest( + "040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010010e59be93c4f269c0269c79e2afd65d6aeaa9b701eacc194fb3ee03df47849bf550ec636ebee0ddd4a16f1cd9406605af38f584567770e3f272d688c832e843564", + "012bc15cf3981eab6102c39f9a925aa130763d01ed6edaf14306eb0a14dd75dff504070def7b88d8b165082f69992de0ffa5ee922cb3ab39917da8524cac73f0a09c", + "01c95ac417c90a520149b29105cdab36f528a23efb5621520dbdafea95a7d43499c4c8be02cd1c2de000da18104fa84a1e9ece6386f0e0efa5234a24595d7c4c96f4"), + // tcId = 539, point with coordinate y = 1 + dhTest( + "0400703dde202ea03d1d673735002cc62cc740536104d81fc9fd8ebdb7dfa908f599d8fea46debc190a5b2ef5f4493f9b5ecd8da9407bf4fc8e1732803a74ee65f747b017c9b038d86afc941403facaa1e2a6376dec075c035ab2c1f42db5fcda3ad3fec67bcf22baf6c81b4241b4a9257f8c2126880e1d6a69a3e5ac7e98710fb24d505df", + "01781d86cac2c052b7e4f48cef415c5c1319e07db70db92a497c2ac764e9509ac0b07322801f5ae1f28c9d7db71f79e5f51bf646790af988d62339a6d1543192e327", + "01b248dbd8dfa667a10ab32af68fa8967c69496ebf80c11fd0efb769ea93f84f5a2968b7ed81b2fd9aa913accec701ddce0d1f8b43b1c671f547822f796efb12d559"), + ] + + func test521() throws { + let kem = KEMStructure(.P521) + for test in tests521 { + let priv = try PrivateKey(kem: .P521, bytes: test.privKey) + let pub = try PublicKey(kem: .P521, bytes: test.pubKey) + XCTAssertEqual(try kem.DH(priv, pub), test.shared) + } + } + +} diff --git a/Tests/SwiftHPKETests/WycheproofX25519Test.swift b/Tests/SwiftHPKETests/WycheproofX25519Test.swift new file mode 100644 index 0000000..f5de871 --- /dev/null +++ b/Tests/SwiftHPKETests/WycheproofX25519Test.swift @@ -0,0 +1,138 @@ +// +// Wycheproof25519Test.swift +// +// +// Created by Leif Ibsen on 06/09/2023. +// + +import XCTest +@testable import SwiftHPKE + +// Test vectors from project Wycheproof - x25519_test.json +final class WycheproofX25519Test: XCTestCase { + + static func hex2bytes(_ x: String) -> Bytes { + let b = [Byte](x.utf8) + var bytes = Bytes(repeating: 0, count: b.count / 2) + for i in 0 ..< bytes.count { + let b0 = b[2 * i] + let b1 = b[2 * i + 1] + bytes[i] = ((b0 > 57 ? b0 - 97 + 10 : b0 - 48) << 4) | (b1 > 57 ? b1 - 97 + 10 : b1 - 48) + } + return bytes + } + + struct dhTest { + + let pubKey: Bytes + let privKey: Bytes + let shared: Bytes + + init(_ pubKey: String, _ privKey: String, _ shared: String) { + self.pubKey = hex2bytes(pubKey) + self.privKey = hex2bytes(privKey) + self.shared = hex2bytes(shared) + } + } + + let tests25519: [dhTest] = [ + // tcId = 1, normal case + dhTest( + "504a36999f489cd2fdbc08baff3d88fa00569ba986cba22548ffde80f9806829", + "c8a9d5a91091ad851c668b0736c1c9a02936c0d3ad62670858088047ba057475", + "436a2c040cf45fea9b29a0cb81b1f41458f863d0d61b453d0a982720d6d61320"), + // tcId = 2, public key on twist + dhTest( + "63aa40c6e38346c5caf23a6df0a5e6c80889a08647e551b3563449befcfc9733", + "d85d8c061a50804ac488ad774ac716c3f5ba714b2712e048491379a500211958", + "279df67a7c4611db4708a0e8282b195e5ac0ed6f4b2f292c6fbd0acac30d1332"), + // tcId = 34, edge case public key + dhTest( + "0400000000000000000000000000000000000000000000000000000000000000", + "a8386f7f16c50731d64f82e6a170b142a4e34f31fd7768fcb8902925e7d1e25a", + "34b7e4fa53264420d9f943d15513902342b386b172a0b0b7c8b8f2dd3d669f59"), + // tcId = 99, non-canonical public key + dhTest( + "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "c85f08e60c845f82099141a66dc4583d2b1040462c544d33d0453b20b1a6377e", + "e9db74bc88d0d9bf046ddd13f943bccbe6dbb47d49323f8dfeedc4a694991a3c"), + // tcId = 126, special case public key + dhTest( + "0000000000000000000000000000000000000000000000000000008000000000", + "d818fd6971e546447f361d33d3dbb3eadcf02fb28f246f1d5107b9073a93cd4f", + "7ed8f2d5424e7ebb3edbdf4abe455447e5a48b658e64abd06c218f33bd151f64"), + // tcId = 153, special case public key + dhTest( + "ebffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "b0f6c28dbdc647068a76d71805ef770f087cf76b82afdc0d26c45b71ace49768", + "f0097fa0ba70d019126277ab15c56ecc170ca88180b2bf9d80fcda3d7d74552a"), + // tcId = 511, private key == -1 (mod order) + dhTest( + "6c05871352a451dbe182ed5e6ba554f2034456ffe041a054ff9cc56b8e946376", + "a023cdd083ef5bb82f10d62e59e15a6800000000000000000000000000000050", + "6c05871352a451dbe182ed5e6ba554f2034456ffe041a054ff9cc56b8e946376"), + // tcId = 515, special case private key + dhTest( + "be3b3edeffaf83c54ae526379b23dd79f1cb41446e3687fef347eb9b5f0dc308", + "4855555555555555555555555555555555555555555555555555555555555555", + "cfa83e098829fe82fd4c14355f70829015219942c01e2b85bdd9ac4889ec2921"), + // tcId = 516, spspecial case private key + dhTest( + "3e3e7708ef72a6dd78d858025089765b1c30a19715ac19e8d917067d208e0666", + "b8aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa6a", + "4782036d6b136ca44a2fd7674d8afb0169943230ac8eab5160a212376c06d778"), + ] + + let tests25519smallOrder: [dhTest] = [ + // tcId = 32, public key = 0 + dhTest( + "0000000000000000000000000000000000000000000000000000000000000000", + "88227494038f2bb811d47805bcdf04a2ac585ada7f2f23389bfd4658f9ddd45e", + "0000000000000000000000000000000000000000000000000000000000000000"), + // tcId = 33, public key = 1 + dhTest( + "0100000000000000000000000000000000000000000000000000000000000000", + "48232e8972b61c7e61930eb9450b5070eae1c670475685541f0476217e48184f", + "0000000000000000000000000000000000000000000000000000000000000000"), + // tcId = 63, public key with low order + dhTest( + "e0eb7a7c3b41b8ae1656e3faf19fc46ada098deb9c32b1fd866205165f49b800", + "e0f978dfcd3a8f1a5093418de54136a584c20b7b349afdf6c0520886f95b1272", + "0000000000000000000000000000000000000000000000000000000000000000"), + // tcId = 64, public key with low order + dhTest( + "5f9c95bca3508c24b1d0b1559c83ef5b04445cc4581c8e86d8224eddd09f1157", + "387355d995616090503aafad49da01fb3dc3eda962704eaee6b86f9e20c92579", + "0000000000000000000000000000000000000000000000000000000000000000"), + // tcId = 154, special case public key + dhTest( + "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "18630f93598637c35da623a74559cf944374a559114c7937811041fc8605564a", + "0000000000000000000000000000000000000000000000000000000000000000"), + ] + + func test25519() throws { + let kem = KEMStructure(.X25519) + for test in tests25519 { + let priv = try PrivateKey(kem: .X25519, bytes: test.privKey) + let pub = try PublicKey(kem: .X25519, bytes: test.pubKey) + XCTAssertEqual(try kem.DH(priv, pub), test.shared) + } + } + + func test25519smallOrder() throws { + let kem = KEMStructure(.X25519) + for test in tests25519smallOrder { + let priv = try PrivateKey(kem: .X25519, bytes: test.privKey) + do { + let pub = try PublicKey(kem: .X25519, bytes: test.pubKey) + let _ = try kem.DH(priv, pub) + XCTFail("Expected smallOrder exception") + } catch HPKEException.smallOrder { + } catch { + XCTFail("Expected smallOrder exception") + } + } + } + +} diff --git a/Tests/SwiftHPKETests/DHTest.swift b/Tests/SwiftHPKETests/WycheproofX448Test.swift similarity index 59% rename from Tests/SwiftHPKETests/DHTest.swift rename to Tests/SwiftHPKETests/WycheproofX448Test.swift index d35f72d..7c86a1b 100644 --- a/Tests/SwiftHPKETests/DHTest.swift +++ b/Tests/SwiftHPKETests/WycheproofX448Test.swift @@ -1,15 +1,15 @@ // -// DHTest.swift +// Wycheproof448Test.swift // // -// Created by Leif Ibsen on 21/08/2023. +// Created by Leif Ibsen on 06/09/2023. // import XCTest @testable import SwiftHPKE -// Test vectors from project Wycheproof -final class DHTest: XCTestCase { +// Test vectors from project Wycheproof - x448_test.json +final class WycheproofX448Test: XCTestCase { static func hex2bytes(_ x: String) -> Bytes { let b = [Byte](x.utf8) @@ -34,130 +34,59 @@ final class DHTest: XCTestCase { self.shared = hex2bytes(shared) } } - - let tests25519: [dhTest] = [ - // Normal case - dhTest( - "504a36999f489cd2fdbc08baff3d88fa00569ba986cba22548ffde80f9806829", - "c8a9d5a91091ad851c668b0736c1c9a02936c0d3ad62670858088047ba057475", - "436a2c040cf45fea9b29a0cb81b1f41458f863d0d61b453d0a982720d6d61320"), - // Public key on twist - dhTest( - "63aa40c6e38346c5caf23a6df0a5e6c80889a08647e551b3563449befcfc9733", - "d85d8c061a50804ac488ad774ac716c3f5ba714b2712e048491379a500211958", - "279df67a7c4611db4708a0e8282b195e5ac0ed6f4b2f292c6fbd0acac30d1332"), - // Edge case public key - dhTest( - "0400000000000000000000000000000000000000000000000000000000000000", - "a8386f7f16c50731d64f82e6a170b142a4e34f31fd7768fcb8902925e7d1e25a", - "34b7e4fa53264420d9f943d15513902342b386b172a0b0b7c8b8f2dd3d669f59"), - // Special case public key - dhTest( - "ebffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", - "b0f6c28dbdc647068a76d71805ef770f087cf76b82afdc0d26c45b71ace49768", - "f0097fa0ba70d019126277ab15c56ecc170ca88180b2bf9d80fcda3d7d74552a"), - // Spspecial case public key - dhTest( - "0000000000000000000000000000000000000000000000000000008000000000", - "d818fd6971e546447f361d33d3dbb3eadcf02fb28f246f1d5107b9073a93cd4f", - "7ed8f2d5424e7ebb3edbdf4abe455447e5a48b658e64abd06c218f33bd151f64"), - // Non-canonical public key - dhTest( - "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", - "c85f08e60c845f82099141a66dc4583d2b1040462c544d33d0453b20b1a6377e", - "e9db74bc88d0d9bf046ddd13f943bccbe6dbb47d49323f8dfeedc4a694991a3c"), - // Private key == -1 (mod order) - dhTest( - "6c05871352a451dbe182ed5e6ba554f2034456ffe041a054ff9cc56b8e946376", - "a023cdd083ef5bb82f10d62e59e15a6800000000000000000000000000000050", - "6c05871352a451dbe182ed5e6ba554f2034456ffe041a054ff9cc56b8e946376"), - // Special case private key - dhTest( - "be3b3edeffaf83c54ae526379b23dd79f1cb41446e3687fef347eb9b5f0dc308", - "4855555555555555555555555555555555555555555555555555555555555555", - "cfa83e098829fe82fd4c14355f70829015219942c01e2b85bdd9ac4889ec2921"), - // Spspecial case private key - dhTest( - "3e3e7708ef72a6dd78d858025089765b1c30a19715ac19e8d917067d208e0666", - "b8aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa6a", - "4782036d6b136ca44a2fd7674d8afb0169943230ac8eab5160a212376c06d778"), - ] - - let tests25519smallOrder: [dhTest] = [ - dhTest( - "0000000000000000000000000000000000000000000000000000000000000000", - "88227494038f2bb811d47805bcdf04a2ac585ada7f2f23389bfd4658f9ddd45e", - "0000000000000000000000000000000000000000000000000000000000000000"), - dhTest( - "0100000000000000000000000000000000000000000000000000000000000000", - "48232e8972b61c7e61930eb9450b5070eae1c670475685541f0476217e48184f", - "0000000000000000000000000000000000000000000000000000000000000000"), - dhTest( - "e0eb7a7c3b41b8ae1656e3faf19fc46ada098deb9c32b1fd866205165f49b800", - "e0f978dfcd3a8f1a5093418de54136a584c20b7b349afdf6c0520886f95b1272", - "0000000000000000000000000000000000000000000000000000000000000000"), - dhTest( - "5f9c95bca3508c24b1d0b1559c83ef5b04445cc4581c8e86d8224eddd09f1157", - "387355d995616090503aafad49da01fb3dc3eda962704eaee6b86f9e20c92579", - "0000000000000000000000000000000000000000000000000000000000000000"), - dhTest( - "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", - "18630f93598637c35da623a74559cf944374a559114c7937811041fc8605564a", - "0000000000000000000000000000000000000000000000000000000000000000"), - ] let tests448: [dhTest] = [ - // Normal case + // tcId = 1, normal case dhTest( "f8073fc01c8358362c08740c914b419847ef1e409f4e40d9440febc26f00551adb1c37c6c2a87d8283b8cb453e928a0d42793f72894e0f81", "e41c63d5159c89de12163fde9d04cf1f430f346b8b2c1f2a4b1f5aee63d17aec29d4b1debf8b6457e7809d2b15ff9779c97becb04b824efa", "acd496ceb5f68bf9c267196b405f59701a40ec88744b7e5e60bf8f81e8b13df448efe402001750edb0b695a0512f08c572a2e356493d170b"), - // Public key on twist + // tcId = 2, public key on twist dhTest( "f8d9144304bd8c4d1fa68957026fc5c1b75020365b0991d2eb1541a4dfa3f15e7a70285cd3828b529bece021d3e03a415e4f8c02eb89ef19", "fcb4ed3afa64c84b7844965c848ad88819241911cd65d35a2bc26a073c08d8e191bcfa04b2dbd94e219f746df929d3298e03afeb73b4fbdb", "3f97c3f87b967daac4e5d12eae05a80c751c3b3e1070886b083e90bb8f63cf76aea0cd4bf5032187e52b1d0513c96f1ac830debcd37887ab"), - // Edge case public key + // tcId = 20, public key on twist + dhTest( + "ffffff030000f8ffff1f0000c0ffffff000000feffff070000f0ffff3f000080ffffff010000fcffff0f0000e0ffff7f000000ffffff0300", + "24cc1c2bd03321210d80e7ba12bac1851cffafcd787383d7383faff669d51e07554d006af14baae0818e7d270445670e53f22b7effbfa689", + "efe4b32d8ccf5f42e48d7cfe3817a7b82a13a7b76805394d7775c649a8880c2379ed546f37c0ebd9ebb5dcb0d260b7c3d241703797b1f54a"), + // tcId = 34, edge case public key dhTest( "0200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "28110debb1242a869407f21a1a07616326e2bba0ae3ddca3d43edde9f3e7b799045f9ac3793d4a9277dadeadc41bec0290f81f744f7377df", "021ea3e58bb9ff27a1109079a8c5a05bb09760864bca1650ed3d825640c5134d0631f529d79510f062883b1217beda88f52801fd5bfae91e"), - // Edge case public key + // tcId = 55, edge case public key dhTest( "fffffffffffffffffffffffffffffffffffffffffffffffffefffffffeffffffffffffffffffffffffffffffffffffffffffffffffffffff", "2c7cd8e41330954cecdc9caf7e079a6f09e4b40637dd6e40252d771f965484a7fc208e13fdc492025cabe98aa55336a7dba36ac3ae4d838f", "887492e4557c0b6ecab34ecc6bdf0608febe33fb05b2aa4ab8d89ec6b476515c90a66e1cfd3cde5b3240ef8fbe0bb53cfa6b2532d0c94caf"), - // Non-canonical public key - dhTest( - "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", - "742b8c0b0ab0104a9ef9634c0aad023f35e41fb953717121ce4c2aebc1a128e7c0431cd1347a6241685f7174a8512d417ebaaa46ee780a8a", - "d92b02d7bb9952f4ca826b2b51f1a3d4de1fd4459f0d019853f3a960d54f3354d8e40fb28d1be65637bb7dba0571ff83797b7106c7497459"), - // Non-canonical public key + // tcId = 74, non-canonical public key dhTest( "03000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "fca784f039798be596afeedaec5b3868f0c8298927721fb82ad04546b7e4c4f42fa1fc3fc7d12f43f5a2e8a96362fcc71a34b44b559e0b96", "a729e6ece3db18b7e9423be4e7fae18caa291e61ce84b608569ab461b270724fd92f3e2b8086fe067673ca7ac05357ee701d69e4056d5b4b"), - // Edge case for shared secret + // tcId = 75, non-canonical public key + dhTest( + "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "742b8c0b0ab0104a9ef9634c0aad023f35e41fb953717121ce4c2aebc1a128e7c0431cd1347a6241685f7174a8512d417ebaaa46ee780a8a", + "d92b02d7bb9952f4ca826b2b51f1a3d4de1fd4459f0d019853f3a960d54f3354d8e40fb28d1be65637bb7dba0571ff83797b7106c7497459"), + // tcId = 89, edge case for shared secret dhTest( "b91a0c5ad497d95f15df62e4231edaaaab21d82953fcde09eab164209745aab6fe9d353a0da328fa8147939e63ad56d1c0d2c0bddd95da50", "70ef97865bee47cf00de84606408e2701ad8bf6ed311039764a3a4f130b98a5be4b1cedb7cb85584a3520e142d474dc9ccb909a073a976bf", "0500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"), - // Public key on twist - dhTest( - "ffffff030000f8ffff1f0000c0ffffff000000feffff070000f0ffff3f000080ffffff010000fcffff0f0000e0ffff7f000000ffffff0300", - "24cc1c2bd03321210d80e7ba12bac1851cffafcd787383d7383faff669d51e07554d006af14baae0818e7d270445670e53f22b7effbfa689", - "efe4b32d8ccf5f42e48d7cfe3817a7b82a13a7b76805394d7775c649a8880c2379ed546f37c0ebd9ebb5dcb0d260b7c3d241703797b1f54a"), - // Private key == -1 (mod order) + // tcId = 503, private key == -1 (mod order) dhTest( "a71742c472d8eee636a974dd98f554ad2f89911f80abdb3d8fa03bbb981917b19d925581bcce7193c8839f6b2e0ff6c1da7c202970b3da46", "be58b958ddcc5bb1a9ccdbc43ccc1fa7d0102f6a70488ad590b3f26ffdffffffffffffffffffffffffffffffffffffffffffffffffffff3f", "caba0271ea05eabf9d92314311cedf54df44739623a60004dd62d5ccac1f4302644b2f0b75e35b11a1831a87548238b9c36e71e5f7c57d10"), - // Special case private key + // tcId = 507, special case private key dhTest( "a667c6ac3de44c8d89c8f82025dab50470fa2da4efa153fb03adb167cef143cdffb825e927e0badfd720f28c1033f3e9d86de7158f00718c", "fcffffffffffffffffffffffffffffffffffffffffffffffffffffffa9aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", "b2ba5057f1f1183b1970b7844537784670da55c5e3207de1d0f76427b2663811426107941022d9bf85a373a7840eb017cf8fa23e53067a7d"), - // Special case private key + // tcId = 508, special case private key dhTest( "f8de0d52427ddc57d9fe1d9bf9f3704d7d43a2633307374a8b05bb6e422a7085a8dbee3ccc28ad328ea3c8cea637ad3c2913ae4ffc1f7638", "00000000000000000000000000000000000000000000000000000000565555555555555555555555555555555555555555555555555555d5", @@ -165,44 +94,33 @@ final class DHTest: XCTestCase { ] let tests448smallOrder: [dhTest] = [ + // tcId = 32, public key = 0 dhTest( "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "04f04638d565bea83ac37703510d647568dbac58218813748a227494038f2bb811d47805bcdf04a2ac585ada7f2f23389bfd4658f9ddd4de", "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"), + // tcId = 33, public key = 1 dhTest( "0100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "281f41a8a853441f1d5014bc6c616e564fce4372ac2216814f232e8972b61c7e61930eb9450b5070eae1c670475685541f0476217e4818cf", "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"), + // tcId = 63, public key with low order dhTest( "fefffffffffffffffffffffffffffffffffffffffffffffffffffffffeffffffffffffffffffffffffffffffffffffffffffffffffffffff", "ac23f2c29dd7910ebdb47efc5ccb345dc9392bb5def5018dc8cb410635f56e63ab92bcdac4177c6bd3450b098493b68bb54ea47b769334c4", "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"), + // tcId = 64, public key with low order + dhTest( + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "c05bd19c61d1c2c0e79414345cfb9c138eed88054fac8f74b2c4b5e1e817aaad629d159903bef40c10c85a8b90b8433c7f35248d72bea2d1", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"), + // tcId = 131, special case public key + dhTest( + "fefffffffffffffffffffffffffffffffffffffffffffffffffffffffeffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "582bf63ee54d47ae5517cf74fdfed1d4bcd544c95e61c8c95605ea323a4d1820fdc40fafb1a5cbe4f4ce1f89a99f99a3361961e5b30bd896", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"), ] - func test25519() throws { - let kem = KEMStructure(.X25519) - for test in tests25519 { - let priv = try PrivateKey(kem: .X25519, bytes: test.privKey) - let pub = try PublicKey(kem: .X25519, bytes: test.pubKey) - XCTAssertEqual(try kem.DH(priv, pub), test.shared) - } - } - - func test25519smallOrder() throws { - let kem = KEMStructure(.X25519) - for test in tests25519smallOrder { - let priv = try PrivateKey(kem: .X25519, bytes: test.privKey) - do { - let pub = try PublicKey(kem: .X25519, bytes: test.pubKey) - let _ = try kem.DH(priv, pub) - XCTFail("Expected smallOrder exception") - } catch HPKEException.smallOrder { - } catch { - XCTFail("Expected smallOrder exception") - } - } - } - func test448() throws { let kem = KEMStructure(.X448) for test in tests448 { diff --git a/docs/Classes.html b/docs/Classes.html index 89e2705..1110d8c 100644 --- a/docs/Classes.html +++ b/docs/Classes.html @@ -116,9 +116,7 @@

    Classes

    -

    Recipient

    - -

    Based on its CipherSuite, a Recipient instance can decrypt a sequence of messages in one of four modes:

    +

    Based on its CipherSuite, a Recipient instance can decrypt a sequence of messages in one of four modes:

    -

    The decryption of the messages must be done in the order in which they were encrypted

    +

    The decryption of the messages must be done in the order in which they were encrypted.
    +A Recipient instance can also retrieve a generated export secret.

    See more
    @@ -155,9 +154,7 @@

    Declaration

    -

    Sender

    - -

    Based on its CipherSuite, a Sender instance can encrypt a sequence of messages in one of four modes:

    +

    Based on its CipherSuite, a Sender instance can encrypt a sequence of messages in one of four modes:

    • Base mode
    • @@ -166,6 +163,8 @@

      Declaration

    • Authenticated, preshared key mode
    +

    A Sender instance can also generate an export secret that only the recipient can know.

    + See more
    @@ -184,7 +183,7 @@

    Declaration

    diff --git a/docs/Classes/Recipient.html b/docs/Classes/Recipient.html index 47c7949..3d276c6 100644 --- a/docs/Classes/Recipient.html +++ b/docs/Classes/Recipient.html @@ -104,9 +104,7 @@

    Recipient

    -

    Recipient

    - -

    Based on its CipherSuite, a Recipient instance can decrypt a sequence of messages in one of four modes:

    +

    Based on its CipherSuite, a Recipient instance can decrypt a sequence of messages in one of four modes:

    -

    The decryption of the messages must be done in the order in which they were encrypted

    +

    The decryption of the messages must be done in the order in which they were encrypted.
    +A Recipient instance can also retrieve a generated export secret.

    @@ -702,7 +701,7 @@

    Return Value

    diff --git a/docs/Classes/Sender.html b/docs/Classes/Sender.html index c83d592..4beb96b 100644 --- a/docs/Classes/Sender.html +++ b/docs/Classes/Sender.html @@ -104,9 +104,7 @@

    Sender

    -

    Sender

    - -

    Based on its CipherSuite, a Sender instance can encrypt a sequence of messages in one of four modes:

    +

    Based on its CipherSuite, a Sender instance can encrypt a sequence of messages in one of four modes:

    +

    A Sender instance can also generate an export secret that only the recipient can know.

    +
    @@ -692,7 +692,7 @@

    Return Value

    diff --git a/docs/Enums.html b/docs/Enums.html index dab7159..fd8aca0 100644 --- a/docs/Enums.html +++ b/docs/Enums.html @@ -220,7 +220,7 @@

    Declaration

    diff --git a/docs/Enums/AEAD.html b/docs/Enums/AEAD.html index 4c69a45..6979759 100644 --- a/docs/Enums/AEAD.html +++ b/docs/Enums/AEAD.html @@ -250,7 +250,7 @@

    Declaration

    diff --git a/docs/Enums/HPKEException.html b/docs/Enums/HPKEException.html index 2108c69..866ac9c 100644 --- a/docs/Enums/HPKEException.html +++ b/docs/Enums/HPKEException.html @@ -466,7 +466,7 @@

    Declaration

    diff --git a/docs/Enums/KDF.html b/docs/Enums/KDF.html index 153930c..114e1d5 100644 --- a/docs/Enums/KDF.html +++ b/docs/Enums/KDF.html @@ -223,7 +223,7 @@

    Declaration

    diff --git a/docs/Enums/KEM.html b/docs/Enums/KEM.html index 16ef847..8c38120 100644 --- a/docs/Enums/KEM.html +++ b/docs/Enums/KEM.html @@ -277,7 +277,7 @@

    Declaration

    diff --git a/docs/Structs.html b/docs/Structs.html index eae3ecd..7be0447 100644 --- a/docs/Structs.html +++ b/docs/Structs.html @@ -145,9 +145,7 @@

    Declaration

    -

    A HPKE CipherSuite

    - -

    A CipherSuite instance combines a Key Encapsulation Mechanism (KEM), a Key Derivation Function (KDF) +

    A CipherSuite instance combines a Key Encapsulation Mechanism (KEM), a Key Derivation Function (KDF) and a AEAD Encryption Algorithm (AEAD). It can encrypt or decrypt a single message in one of four modes:

    @@ -184,9 +182,7 @@

    Declaration

    -

    A HPKE private key

    - -

    There are five different private key types corresponding to the five KEM’s

    +

    There are five different private key types corresponding to the five KEM’s

    • P256 - the key is a 32 byte value corresponding to a NIST curve secp256r1 private key
    • @@ -222,9 +218,7 @@

      Declaration

      -

      A HPKE public key

      - -

      There are five different public key types corresponding to the five KEM’s

      +

      There are five different public key types corresponding to the five KEM’s

      • P256 - the key is a 65 byte value corresponding to a NIST secp256r1 uncompressed curve point
      • @@ -252,7 +246,7 @@

        Declaration

    diff --git a/docs/Structs/Base64.html b/docs/Structs/Base64.html index 94f3530..3c623ce 100644 --- a/docs/Structs/Base64.html +++ b/docs/Structs/Base64.html @@ -371,7 +371,7 @@

    Return Value

    diff --git a/docs/Structs/CipherSuite.html b/docs/Structs/CipherSuite.html index 7a56915..905661f 100644 --- a/docs/Structs/CipherSuite.html +++ b/docs/Structs/CipherSuite.html @@ -104,9 +104,7 @@

    CipherSuite

    -

    A HPKE CipherSuite

    - -

    A CipherSuite instance combines a Key Encapsulation Mechanism (KEM), a Key Derivation Function (KDF) +

    A CipherSuite instance combines a Key Encapsulation Mechanism (KEM), a Key Derivation Function (KDF) and a AEAD Encryption Algorithm (AEAD). It can encrypt or decrypt a single message in one of four modes:

    @@ -2359,7 +2357,7 @@

    Return Value

    diff --git a/docs/Structs/PrivateKey.html b/docs/Structs/PrivateKey.html index e5df8b5..d35f368 100644 --- a/docs/Structs/PrivateKey.html +++ b/docs/Structs/PrivateKey.html @@ -104,9 +104,7 @@

    PrivateKey

    -

    A HPKE private key

    - -

    There are five different private key types corresponding to the five KEM’s

    +

    There are five different private key types corresponding to the five KEM’s