Skip to content

Commit

Permalink
Release 1.5.0
Browse files Browse the repository at this point in the history
  • Loading branch information
leif-ibsen committed Oct 3, 2023
1 parent 1012c87 commit 8ff241b
Show file tree
Hide file tree
Showing 39 changed files with 139 additions and 78 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,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<br/>

dependencies: [
.package(url: "https://github.com/leif-ibsen/SwiftHPKE", from: "1.4.0"),
.package(url: "https://github.com/leif-ibsen/SwiftHPKE", from: "1.5.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,
Expand Down
6 changes: 6 additions & 0 deletions Sources/SwiftHPKE/Curve.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ import BigInt

class CurveP256: Curve {

static let publicKeySize = 65
static let privateKeySize = 32
static let name = "secp256r1"
static let p = BInt("ffffffff00000001000000000000000000000000ffffffffffffffffffffffff", radix: 16)!
static let a = BInt("ffffffff00000001000000000000000000000000fffffffffffffffffffffffc", radix: 16)!
Expand All @@ -27,6 +29,8 @@ class CurveP256: Curve {

class CurveP384: Curve {

static let publicKeySize = 97
static let privateKeySize = 48
static let name = "secp384r1"
static let p = BInt("fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeffffffff0000000000000000ffffffff", radix: 16)!
static let a = BInt("fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeffffffff0000000000000000fffffffc", radix: 16)!
Expand All @@ -44,6 +48,8 @@ class CurveP384: Curve {

class CurveP521: Curve {

static let publicKeySize = 133
static let privateKeySize = 66
static let name = "secp521r1"
static let p = BInt("1ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", radix: 16)!
static let a = BInt("1fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc", radix: 16)!
Expand Down
20 changes: 10 additions & 10 deletions Sources/SwiftHPKE/KEM.swift
Original file line number Diff line number Diff line change
Expand Up @@ -63,36 +63,36 @@ struct KEMStructure {
let suite_id = Bytes("KEM".utf8) + [0x00, 0x10]
self.kdfStructure = KDFStructure(.KDF256, suite_id)
self.Nsecret = 32
self.Npk = 65
self.Nsk = 32
self.Npk = CurveP256.publicKeySize
self.Nsk = CurveP256.privateKeySize
self.bitmask = 0xff
case .P384:
let suite_id = Bytes("KEM".utf8) + [0x00, 0x11]
self.kdfStructure = KDFStructure(.KDF256, suite_id)
self.Nsecret = 48
self.Npk = 97
self.Nsk = 48
self.Npk = CurveP384.publicKeySize
self.Nsk = CurveP384.privateKeySize
self.bitmask = 0xff
case .P521:
let suite_id = Bytes("KEM".utf8) + [0x00, 0x12]
self.kdfStructure = KDFStructure(.KDF512, suite_id)
self.Nsecret = 64
self.Npk = 133
self.Nsk = 66
self.Npk = CurveP521.publicKeySize
self.Nsk = CurveP521.privateKeySize
self.bitmask = 0x01
case .X25519:
let suite_id = Bytes("KEM".utf8) + [0x00, 0x20]
self.kdfStructure = KDFStructure(.KDF256, suite_id)
self.Nsecret = 32
self.Npk = 32
self.Nsk = 32
self.Npk = Curve25519.keySize
self.Nsk = Curve25519.keySize
self.bitmask = 0x00
case .X448:
let suite_id = Bytes("KEM".utf8) + [0x00, 0x21]
self.kdfStructure = KDFStructure(.KDF512, suite_id)
self.Nsecret = 56
self.Npk = 56
self.Nsk = 56
self.Npk = Curve448.keySize
self.Nsk = Curve448.keySize
self.bitmask = 0x00
}
}
Expand Down
10 changes: 5 additions & 5 deletions Sources/SwiftHPKE/PrivateKey.swift
Original file line number Diff line number Diff line change
Expand Up @@ -37,24 +37,24 @@ public struct PrivateKey: CustomStringConvertible, Equatable {
guard self.s! > BInt.ZERO else {
throw HPKEException.privateKeyParameter
}
self.bytes = PrivateKey.int2bytes(self.s!, 32)
self.bytes = PrivateKey.int2bytes(self.s!, CurveP256.privateKeySize)
self.publicKey = try PublicKey(kem: .P256, bytes: Curve.p256.encodePoint(Curve.p256.multiplyG(self.s!), false))
case .P384:
self.s = BInt(magnitude: bytes).mod(CurveP384.order)
guard self.s! > BInt.ZERO else {
throw HPKEException.privateKeyParameter
}
self.bytes = PrivateKey.int2bytes(self.s!, 48)
self.bytes = PrivateKey.int2bytes(self.s!, CurveP384.privateKeySize)
self.publicKey = try PublicKey(kem: .P384, bytes: Curve.p384.encodePoint(Curve.p384.multiplyG(self.s!), false))
case .P521:
self.s = BInt(magnitude: bytes).mod(CurveP521.order)
guard self.s! > BInt.ZERO else {
throw HPKEException.privateKeyParameter
}
self.bytes = PrivateKey.int2bytes(self.s!, 66)
self.bytes = PrivateKey.int2bytes(self.s!, CurveP521.privateKeySize)
self.publicKey = try PublicKey(kem: .P521, bytes: Curve.p521.encodePoint(Curve.p521.multiplyG(self.s!), false))
case .X25519:
guard bytes.count == 32 else {
guard bytes.count == Curve25519.keySize else {
throw HPKEException.privateKeyParameter
}
var x = bytes
Expand All @@ -65,7 +65,7 @@ public struct PrivateKey: CustomStringConvertible, Equatable {
self.s = nil
self.publicKey = try PublicKey(kem: .X25519, bytes: Curve25519.X25519(self.bytes, Curve25519._9))
case .X448:
guard bytes.count == 56 else {
guard bytes.count == Curve448.keySize else {
throw HPKEException.privateKeyParameter
}
var x = bytes
Expand Down
47 changes: 34 additions & 13 deletions Sources/SwiftHPKE/PublicKey.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import BigInt

/// 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
/// * P256 - the key is a 65 byte value corresponding to a NIST secp256r1 uncompressed curve point
/// * P384 - the key is a 97 byte value corresponding to a NIST secp384r1 uncompressed curve point
/// * P521 - the key is a 133 byte value corresponding to a NIST secp521r1 uncompressed curve point
/// * X25519 - the key is a 32 byte value corresponding to a curve X25519 public key
Expand All @@ -33,34 +33,56 @@ public struct PublicKey: CustomStringConvertible, Equatable {
/// - bytes: The key bytes
/// - Throws: An exception if *bytes* has wrong size for the key type
public init(kem: KEM, bytes: Bytes) throws {
self.bytes = bytes
self.kem = kem
switch self.kem {
case .P256:
self.w = try Curve.p256.decodePoint(self.bytes)
self.w = try Curve.p256.decodePoint(bytes)
guard Curve.p256.contains(self.w!) && !self.w!.infinity else {
throw HPKEException.publicKeyParameter
}
if bytes[0] == 4 {
// uncompressed point
self.bytes = bytes
} else {
// compressed point
self.bytes = Curve.p256.encodePoint(self.w!, false)
}
case .P384:
self.w = try Curve.p384.decodePoint(self.bytes)
self.w = try Curve.p384.decodePoint(bytes)
guard Curve.p384.contains(self.w!) && !self.w!.infinity else {
throw HPKEException.publicKeyParameter
}
if bytes[0] == 4 {
// uncompressed point
self.bytes = bytes
} else {
// compressed point
self.bytes = Curve.p384.encodePoint(self.w!, false)
}
case .P521:
self.w = try Curve.p521.decodePoint(self.bytes)
self.w = try Curve.p521.decodePoint(bytes)
guard Curve.p521.contains(self.w!) && !self.w!.infinity else {
throw HPKEException.publicKeyParameter
}
if bytes[0] == 4 {
// uncompressed point
self.bytes = bytes
} else {
// compressed point
self.bytes = Curve.p521.encodePoint(self.w!, false)
}
case .X25519:
guard bytes.count == 32 else {
guard bytes.count == Curve25519.keySize else {
throw HPKEException.publicKeyParameter
}
self.bytes = bytes
self.w = nil
try checkZero()
case .X448:
guard bytes.count == 56 else {
guard bytes.count == Curve448.keySize else {
throw HPKEException.publicKeyParameter
}
self.bytes = bytes
self.w = nil
try checkZero()
}
Expand Down Expand Up @@ -90,9 +112,9 @@ public struct PublicKey: CustomStringConvertible, Equatable {
guard let oid = seq1.get(0) as? ASN1ObjectIdentifier else {
throw HPKEException.asn1Structure
}
if oid == Curve25519.OID && bitString.bits.count == 32 {
if oid == Curve25519.OID && bitString.bits.count == Curve25519.keySize {
try self.init(kem: .X25519, bytes: bitString.bits)
} else if oid == Curve448.OID && bitString.bits.count == 56 {
} else if oid == Curve448.OID && bitString.bits.count == Curve448.keySize {
try self.init(kem: .X448, bytes: bitString.bits)
} else {
throw HPKEException.asn1Structure
Expand All @@ -108,11 +130,11 @@ public struct PublicKey: CustomStringConvertible, Equatable {
guard let oid2 = seq1.get(1) as? ASN1ObjectIdentifier else {
throw HPKEException.asn1Structure
}
if oid2 == CurveP256.oid && bitString.bits.count == 65 {
if oid2 == CurveP256.oid && bitString.bits.count == CurveP256.publicKeySize {
try self.init(kem: .P256, bytes: bitString.bits)
} else if oid2 == CurveP384.oid && bitString.bits.count == 97 {
} else if oid2 == CurveP384.oid && bitString.bits.count == CurveP384.publicKeySize {
try self.init(kem: .P384, bytes: bitString.bits)
} else if oid2 == CurveP521.oid && bitString.bits.count == 133 {
} else if oid2 == CurveP521.oid && bitString.bits.count == CurveP521.publicKeySize {
try self.init(kem: .P521, bytes: bitString.bits)
} else {
throw HPKEException.asn1Structure
Expand Down Expand Up @@ -162,7 +184,6 @@ public struct PublicKey: CustomStringConvertible, Equatable {
return key1.kem == key2.kem && key1.bytes == key2.bytes
}


func getASN1() -> ASN1 {
switch self.kem {
case .P256:
Expand Down
4 changes: 3 additions & 1 deletion Sources/SwiftHPKE/X255_448/Curve25519.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,15 @@ import ASN1

struct Curve25519 {

static let keySize = 32

static let OID = ASN1ObjectIdentifier("1.3.101.110")!

static let _9: Bytes = [9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]

// RFC 7748 page 9
static func X25519(_ k: Bytes, _ u: Bytes) throws -> Bytes {
assert(k.count == 32 && u.count == 32)
assert(k.count == keySize && u.count == keySize)
let a24 = Field25519(121665, 0, 0, 0, 0)
var k1 = k
k1[0] &= 0xf8
Expand Down
4 changes: 3 additions & 1 deletion Sources/SwiftHPKE/X255_448/Curve448.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,16 @@ import ASN1

struct Curve448 {

static let keySize = 56

static let OID = ASN1ObjectIdentifier("1.3.101.111")!

static let _5: Bytes = [5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]

// RFC 7748 page 9
static func X448(_ k: Bytes, _ u: Bytes) throws -> Bytes {
assert(k.count == 56 && u.count == 56)
assert(k.count == keySize && u.count == keySize)
var k1 = k
k1[0] &= 0xfc
k1[55] |= 0x80
Expand Down
52 changes: 41 additions & 11 deletions Tests/SwiftHPKETests/KeysTest.swift
Original file line number Diff line number Diff line change
Expand Up @@ -77,67 +77,97 @@ final class KeysTest: XCTestCase {

func testPub() throws {

// Curve point = Generator point
// Curve point = Generator point * 10
do {
let _ = try PublicKey(kem: .P256, bytes: CurveP256().encodePoint(Point(CurveP256.gx, CurveP256.gy), false))
let curvePoint = Curve.p256.multiply(Point(CurveP256.gx, CurveP256.gy), BInt.TEN)
let pubKey1 = try PublicKey(kem: .P256, bytes: Curve.p256.encodePoint(curvePoint, false))
let pubKey2 = try PublicKey(kem: .P256, bytes: Curve.p256.encodePoint(curvePoint, true))
XCTAssertEqual(pubKey1, pubKey2)
} catch {
XCTFail("Did not expect exception")
}
do {
let _ = try PublicKey(kem: .P384, bytes: CurveP384().encodePoint(Point(CurveP384.gx, CurveP384.gy), false))
let curvePoint = Curve.p384.multiply(Point(CurveP384.gx, CurveP384.gy), BInt.TEN)
let pubKey1 = try PublicKey(kem: .P384, bytes: Curve.p384.encodePoint(curvePoint, false))
let pubKey2 = try PublicKey(kem: .P384, bytes: Curve.p384.encodePoint(curvePoint, true))
XCTAssertEqual(pubKey1, pubKey2)
} catch {
XCTFail("Did not expect exception")
}
do {
let _ = try PublicKey(kem: .P521, bytes: CurveP521().encodePoint(Point(CurveP521.gx, CurveP521.gy), false))
let curvePoint = Curve.p521.multiply(Point(CurveP521.gx, CurveP521.gy), BInt.TEN)
let pubKey1 = try PublicKey(kem: .P521, bytes: Curve.p521.encodePoint(curvePoint, false))
let pubKey2 = try PublicKey(kem: .P521, bytes: Curve.p521.encodePoint(curvePoint, true))
XCTAssertEqual(pubKey1, pubKey2)
} catch {
XCTFail("Did not expect exception")
}

// Curve point = INFINITY
do {
let _ = try PublicKey(kem: .P256, bytes: CurveP256().encodePoint(Point.INFINITY, false))
let _ = try PublicKey(kem: .P256, bytes: Curve.p256.encodePoint(Point.INFINITY, false))
XCTFail("Expected publicKeyParameter exception")
} catch HPKEException.publicKeyParameter {
} catch {
XCTFail("Expected publicKeyParameter exception")
}
do {
let _ = try PublicKey(kem: .P384, bytes: CurveP384().encodePoint(Point.INFINITY, false))
let _ = try PublicKey(kem: .P384, bytes: Curve.p384.encodePoint(Point.INFINITY, false))
XCTFail("Expected publicKeyParameter exception")
} catch HPKEException.publicKeyParameter {
} catch {
XCTFail("Expected publicKeyParameter exception")
}
do {
let _ = try PublicKey(kem: .P521, bytes: CurveP521().encodePoint(Point.INFINITY, false))
let _ = try PublicKey(kem: .P521, bytes: Curve.p521.encodePoint(Point.INFINITY, false))
XCTFail("Expected publicKeyParameter exception")
} catch HPKEException.publicKeyParameter {
} catch {
XCTFail("Expected publicKeyParameter exception")
}

// Curve point = (0, 0)
// Curve point not on curve
do {
let _ = try PublicKey(kem: .P256, bytes: CurveP256().encodePoint(Point(BInt.ZERO, BInt.ZERO), false))
let curvePoint = Point(CurveP256.gx, BInt.ZERO)
let _ = try PublicKey(kem: .P256, bytes: Curve.p256.encodePoint(curvePoint, false))
XCTFail("Expected publicKeyParameter exception")
} catch HPKEException.publicKeyParameter {
} catch {
XCTFail("Expected publicKeyParameter exception")
}
do {
let _ = try PublicKey(kem: .P384, bytes: CurveP384().encodePoint(Point(BInt.ZERO, BInt.ZERO), false))
let curvePoint = Point(CurveP384.gx, BInt.ZERO)
let _ = try PublicKey(kem: .P384, bytes: Curve.p384.encodePoint(curvePoint, false))
XCTFail("Expected publicKeyParameter exception")
} catch HPKEException.publicKeyParameter {
} catch {
XCTFail("Expected publicKeyParameter exception")
}
do {
let _ = try PublicKey(kem: .P521, bytes: CurveP521().encodePoint(Point(BInt.ZERO, BInt.ZERO), false))
let curvePoint = Point(CurveP521.gx, BInt.ZERO)
let _ = try PublicKey(kem: .P521, bytes: Curve.p521.encodePoint(curvePoint, false))
XCTFail("Expected publicKeyParameter exception")
} catch HPKEException.publicKeyParameter {
} catch {
XCTFail("Expected publicKeyParameter exception")
}
do {
let curvePoint = Point(CurveP256.gx, BInt.ZERO)
let _ = try PublicKey(kem: .P256, bytes: Curve.p256.encodePoint(curvePoint, true))
} catch {
XCTFail("Did not expect exception")
}
do {
let curvePoint = Point(CurveP384.gx, BInt.ZERO)
let _ = try PublicKey(kem: .P384, bytes: Curve.p384.encodePoint(curvePoint, true))
} catch {
XCTFail("Did not expect exception")
}
do {
let curvePoint = Point(CurveP521.gx, BInt.ZERO)
let _ = try PublicKey(kem: .P521, bytes: Curve.p521.encodePoint(curvePoint, true))
} catch {
XCTFail("Did not expect exception")
}
}
}
2 changes: 1 addition & 1 deletion docs/Classes.html
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,7 @@ <h4>Declaration</h4>
</section>
</section>
<section id="footer">
<p>&copy; 2023 <a class="link" href="" target="_blank" rel="external noopener"></a>. All rights reserved. (Last updated: 2023-10-02)</p>
<p>&copy; 2023 <a class="link" href="" target="_blank" rel="external noopener"></a>. All rights reserved. (Last updated: 2023-10-03)</p>
<p>Generated by <a class="link" href="https://github.com/realm/jazzy" target="_blank" rel="external noopener">jazzy ♪♫ v0.14.3</a>, a <a class="link" href="https://realm.io" target="_blank" rel="external noopener">Realm</a> project.</p>
</section>
</article>
Expand Down
2 changes: 1 addition & 1 deletion docs/Classes/Recipient.html
Original file line number Diff line number Diff line change
Expand Up @@ -701,7 +701,7 @@ <h4>Return Value</h4>
</section>
</section>
<section id="footer">
<p>&copy; 2023 <a class="link" href="" target="_blank" rel="external noopener"></a>. All rights reserved. (Last updated: 2023-10-02)</p>
<p>&copy; 2023 <a class="link" href="" target="_blank" rel="external noopener"></a>. All rights reserved. (Last updated: 2023-10-03)</p>
<p>Generated by <a class="link" href="https://github.com/realm/jazzy" target="_blank" rel="external noopener">jazzy ♪♫ v0.14.3</a>, a <a class="link" href="https://realm.io" target="_blank" rel="external noopener">Realm</a> project.</p>
</section>
</article>
Expand Down
2 changes: 1 addition & 1 deletion docs/Classes/Sender.html
Original file line number Diff line number Diff line change
Expand Up @@ -692,7 +692,7 @@ <h4>Return Value</h4>
</section>
</section>
<section id="footer">
<p>&copy; 2023 <a class="link" href="" target="_blank" rel="external noopener"></a>. All rights reserved. (Last updated: 2023-10-02)</p>
<p>&copy; 2023 <a class="link" href="" target="_blank" rel="external noopener"></a>. All rights reserved. (Last updated: 2023-10-03)</p>
<p>Generated by <a class="link" href="https://github.com/realm/jazzy" target="_blank" rel="external noopener">jazzy ♪♫ v0.14.3</a>, a <a class="link" href="https://realm.io" target="_blank" rel="external noopener">Realm</a> project.</p>
</section>
</article>
Expand Down
Loading

0 comments on commit 8ff241b

Please sign in to comment.