Files
Portal-Camera/mac/PortalKit/Tests/PortalKitTests/Rfc5054VectorsTests.swift
T

148 lines
6.1 KiB
Swift
Raw Normal View History

2026-09-13 12:15:36 -07:00
//
// Rfc5054VectorsTests.swift
// PortalKitTests
//
// Verification of RFC 5054 Appendix B test vectors (1024-bit group with SHA-1).
//
import XCTest
@testable import PortalKit
final class Rfc5054VectorsTests: XCTestCase {
let group = SrpGroup.rfc5054_1024
// RFC 5054 Appendix B inputs
let I = "alice"
let P = "password123"
let sHex = "BEB25379D1A8581EB5A727673A2441EE"
// RFC 5054 Appendix B expected values
let expectedKHex = "7556AA045AEF2CDD07ABAF0F665C3E818913186F"
let expectedXHex = "94B7555AABE9127CC58CCF4993DB6CF84D16C124"
let expectedVHex = """
7E273DE8696FFC4F4E337D05B4B375BEB0DDE1569E8FA00A9886D8129BADA1F1\
822223CA1A605B530E379BA4729FDC59F105B4787E5186F5C671085A1447B52A\
48CF1970B4FB6F8400BBF4CEBFBB168152E08AB5EA53D15C1AFF87B2B9DA6E04\
E058AD51CC72BFC9033B564E26480D78E955A5E29E7AB245DB2BE315E2099AFB
"""
let expectedAHex = "60975527035CF2AD1989806F0407210BC81EDC04E2762A56AFD529DDDA2D4393"
let expectedBHex = "E487CB59D31AC550471E81F00F6928E01DDA08E974A004F49E61F5D105284D20"
let expectedPubAHex = """
61D5E490F6F1B79547B0704C436F523DD0E560F0C64115BB72557EC44352E890\
3211C04692272D8B2D1A5358A2CF1B6E0BFCF99F921530EC8E39356179EAE45E\
42BA92AEACED825171E1E8B9AF6D9C03E1327F44BE087EF06530E69F66615261\
EEF54073CA11CF5858F0EDFDFE15EFEAB349EF5D76988A3672FAC47B0769447B
"""
let expectedPubBHex = """
BD0C61512C692C0CB6D041FA01BB152D4916A1E77AF46AE105393011BAF38964\
DC46A0670DD125B95A981652236F99D9B681CBF87837EC996C6DA04453728610\
D0C6DDB58B318885D7D82C7F8DEB75CE7BD4FBAA37089E6F9C6059F388838E7A\
00030B331EB76840910440B1B27AAEAEEB4012B7D7665238A8E3FB004B117B58
"""
let expectedUHex = "CE38B9593487DA98554ED47D70A7AE5F462EF019"
let expectedSHex = """
B0DC82BABCF30674AE450C0287745E7990A3381F63B387AAF271A10D233861E3\
59B48220F7C4693C9AE12B0A6F67809F0876E2D013800D6C41BB59B6D5979B5C\
00A172B4A2A5903A0BDCAF8A709585EB2AFAFA8F3499B200210DCC1F10EB3394\
3CD67FC88A2F39A4BE5BEC4EC0A3212DC346D7E474B29EDE8A469FFECA686E5A
"""
func testMultiplierK() {
let computedK = group.k
let computedKHex = SrpFormat.bytesToHex(computedK.serialize())
XCTAssertEqual(computedKHex.lowercased(), expectedKHex.lowercased(), "RFC 5054 multiplier k mismatch")
}
func testPrivateKeyX() {
guard let sData = SrpFormat.hexToBytes(sHex) else {
XCTFail("Failed to decode salt hex")
return
}
let x = SrpMath.computeRfc5054X(identity: I, password: P, salt: sData, hashAlgorithm: group.hashAlgorithm)
let xHex = SrpFormat.bytesToHex(x.serialize())
XCTAssertEqual(xHex.lowercased(), expectedXHex.lowercased(), "RFC 5054 private key x mismatch")
}
func testVerifierV() {
guard let xVal = BigUInt(expectedXHex, radix: 16) else {
XCTFail("Failed to parse expected x")
return
}
let v = SrpMath.computeVerifier(g: group.g, x: xVal, N: group.N)
let vHex = SrpFormat.bytesToHex(v.toPaddedData(byteCount: 128))
XCTAssertEqual(vHex.lowercased(), expectedVHex.lowercased(), "RFC 5054 verifier v mismatch")
}
func testPublicA() {
guard let aVal = BigUInt(expectedAHex, radix: 16) else {
XCTFail("Failed to parse expected a")
return
}
let A = SrpMath.computeA(g: group.g, a: aVal, N: group.N)
let aHex = SrpFormat.bytesToHex(A.toPaddedData(byteCount: 128))
XCTAssertEqual(aHex.lowercased(), expectedPubAHex.lowercased(), "RFC 5054 public key A mismatch")
}
func testPublicB() {
guard let bVal = BigUInt(expectedBHex, radix: 16),
let vVal = BigUInt(expectedVHex, radix: 16) else {
XCTFail("Failed to parse b or v")
return
}
let B = SrpMath.computeB(k: group.k, v: vVal, g: group.g, b: bVal, N: group.N)
let bHex = SrpFormat.bytesToHex(B.toPaddedData(byteCount: 128))
XCTAssertEqual(bHex.lowercased(), expectedPubBHex.lowercased(), "RFC 5054 public key B mismatch")
}
func testScramblerU() {
guard let aVal = BigUInt(expectedPubAHex, radix: 16),
let bVal = BigUInt(expectedPubBHex, radix: 16) else {
XCTFail("Failed to parse A or B")
return
}
let u = SrpMath.computeU(A: aVal, B: bVal, padLength: 128, hashAlgorithm: group.hashAlgorithm)
let uHex = SrpFormat.bytesToHex(u.serialize())
XCTAssertEqual(uHex.lowercased(), expectedUHex.lowercased(), "RFC 5054 scrambler u mismatch")
}
func testPremasterSecretS() {
guard let aVal = BigUInt(expectedAHex, radix: 16),
let bVal = BigUInt(expectedBHex, radix: 16),
let pubA = BigUInt(expectedPubAHex, radix: 16),
let pubB = BigUInt(expectedPubBHex, radix: 16),
let xVal = BigUInt(expectedXHex, radix: 16),
let vVal = BigUInt(expectedVHex, radix: 16),
let uVal = BigUInt(expectedUHex, radix: 16) else {
XCTFail("Failed to parse test parameters")
return
}
// Client computation: S = (B - k * (g^x mod N)) ^ (a + u * x) mod N
let clientS = SrpMath.computeClientS(
B: pubB,
k: group.k,
g: group.g,
x: xVal,
a: aVal,
u: uVal,
N: group.N
)
let clientSHex = SrpFormat.bytesToHex(clientS.toPaddedData(byteCount: 128))
XCTAssertEqual(clientSHex.lowercased(), expectedSHex.lowercased(), "Client premaster secret S mismatch")
// Server computation: S = (A * (v^u mod N)) ^ b mod N
let serverS = SrpMath.computeServerS(
A: pubA,
v: vVal,
u: uVal,
b: bVal,
N: group.N
)
let serverSHex = SrpFormat.bytesToHex(serverS.toPaddedData(byteCount: 128))
XCTAssertEqual(serverSHex.lowercased(), expectedSHex.lowercased(), "Server premaster secret S mismatch")
// Mutual agreement
XCTAssertEqual(clientS, serverS, "Client and Server premaster secrets do not match")
}
}