Protocol::HAP::SRP(3p) Perl Library Manual Protocol::HAP::SRP(3p)

Protocol::HAP::SRP - SRP-6a implementation for HAP pairing

    use Protocol::HAP::SRP;
    # Server side
    my $srp = Protocol::HAP::SRP->new(password => $pin);
    my $salt = $srp->generate_salt();
    my $v = $srp->compute_verifier;
    my $B = $srp->generate_server_public();
    my $B_bytes = $srp->server_public_bytes();   # 384 bytes, for M2
    # After receiving client's A
    my $K = $srp->compute_session_key($A);
    my $valid = $srp->verify_client_proof($M1);
    my $M2 = $srp->generate_server_proof();

This module implements the server (accessory) role of the SRP-6a exchange that HAP pair-setup uses. The module owns the RFC 5054 3072-bit group parameters, because SRP is their only user. The modular arithmetic comes from Math::BigInt. Math::BigInt uses the GMP backend when that backend is installed. This is important: the pure-Perl backend takes seconds for each exponentiation at 3072 bits.

The module also owns the wire encoding of the values it produces. "server_public_bytes" returns B padded to the length of N, which is what M2 must carry and what both sides hash for u. About one B in 256 is small enough that its natural encoding is one byte short, so a caller that packed the number itself would break one pairing in 256.

The same file holds "Protocol::HAP::SRP::Client": the controller side of the exchange, with the same group, hash, and padding rules. One module holds both roles, so the conformance vectors exercise them against each other.

    my $srp = Protocol::HAP::SRP::Client->new(password => $pin);
    my $A   = $srp->compute_public;
    my $M1  = $srp->compute_proof($salt, $B);   # undef on bogus B
    $srp->verify_server_proof($M2) or die 'server proof invalid';
    my $K = $srp->session_key;

Protocol::HAP::Pairing, Protocol::HAP::Controller, spec/HAP-Pairing.md

2026-08-18 OpenBSD