{"id":17295192,"url":"https://github.com/adam-fowler/swift-srp","last_synced_at":"2026-04-27T10:01:06.783Z","repository":{"id":50937241,"uuid":"261025408","full_name":"adam-fowler/swift-srp","owner":"adam-fowler","description":"Swift Secure Remote Password","archived":false,"fork":false,"pushed_at":"2026-04-22T21:57:17.000Z","size":73,"stargazers_count":39,"open_issues_count":2,"forks_count":16,"subscribers_count":1,"default_branch":"main","last_synced_at":"2026-04-23T01:37:50.247Z","etag":null,"topics":["authentication","rfc-2945","rfc-5054","secure-remote-password","security","srp","srp-6a","swift"],"latest_commit_sha":null,"homepage":null,"language":"Swift","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/adam-fowler.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null},"funding":{"github":"adam-fowler"}},"created_at":"2020-05-03T21:34:53.000Z","updated_at":"2026-03-25T14:29:16.000Z","dependencies_parsed_at":"2024-11-05T10:53:48.645Z","dependency_job_id":null,"html_url":"https://github.com/adam-fowler/swift-srp","commit_stats":{"total_commits":34,"total_committers":2,"mean_commits":17.0,"dds":0.02941176470588236,"last_synced_commit":"941f3280dc7b2810befe7fd0c6e8e7a0c21751eb"},"previous_names":[],"tags_count":12,"template":false,"template_full_name":null,"purl":"pkg:github/adam-fowler/swift-srp","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/adam-fowler%2Fswift-srp","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/adam-fowler%2Fswift-srp/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/adam-fowler%2Fswift-srp/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/adam-fowler%2Fswift-srp/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/adam-fowler","download_url":"https://codeload.github.com/adam-fowler/swift-srp/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/adam-fowler%2Fswift-srp/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32331305,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-26T23:26:28.701Z","status":"online","status_checked_at":"2026-04-27T02:00:06.769Z","response_time":128,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["authentication","rfc-2945","rfc-5054","secure-remote-password","security","srp","srp-6a","swift"],"created_at":"2024-10-15T11:09:41.076Z","updated_at":"2026-04-27T10:01:06.704Z","avatar_url":"https://github.com/adam-fowler.png","language":"Swift","funding_links":["https://github.com/sponsors/adam-fowler"],"categories":[],"sub_categories":[],"readme":"# Swift SRP\n\nThis library provides a swift implementation of the Secure Remote Password protocol. Secure Remote Password (SRP) provides username and password authentication without needing to provide your password to the server. As the server never sees your password it can never leak it to anyone else.\n\nThe server is provided with a cryptographic verifier that is derived from the password and a salt value that was used in the generation of this verifier. Both client and server generate large private and public keys and with these are able to generate a shared secret. The client then sends a proof they have the secret and if it is verified the server will do the same to verify the server as well.\n\nThe SRP protocol is detailed in [RFC2945](https://tools.ietf.org/html/rfc2945). This library implements version 6a of the protocol which includes the username in the salt to avoid the issue where a malicious server attempting to learn if two users have the same password. I believe it is also compliant with [RFC5054](https://tools.ietf.org/html/rfc5054). \n\n# Usage\n\nFirst you create a configuration object. This will hold the hashing algorithm you are using, the large safe prime number required and a generator value. There is an enum that holds example primes and generators. It is general safer to use these as they are the ones provided in RFC5054 and have been battle tested. The following generates a configuration using SHA256 and a 2048 bit safe prime. You need to be sure both client and server use the same configuration.\n```swift\nlet configuration = SRPConfiguration\u003cSHA256\u003e(.N2048)\n```\nWhen the client wants to create a new user they generate a salt and password verifier for their username and password. \n```swift\nlet client = SRPClient(configuration: configuration)\nlet (salt, verifier) = client.generateSaltAndVerifier(username: username, password: password)\n```\nThese are passed to the server who will store them alongside the username in a database.\n\nWhen the client wants to authenticate with the server they first need to generate a public/private key pair. These keys should only be used once. If you want to authenticate again you should generate a new pair.\n```swift\nlet client = SRPClient(configuration: configuration)\nlet clientKeys = client.generateKeys()\nlet clientPublicKey = clientKeys.public\n```\nThe contents of the `clientPublicKey` variable is passed to the server alongside the username to initiate authentication.\n\nThe server will then find the username in its database and extract the password verifier and salt that was stored with it. The password verifier is used to generate the servers key pair.\n```swift\nlet server = SRPServer(configuration: configuration)\nlet serverKeys = server.generateKeys(verifier: values.verifier)\nlet serverPublicKey = serverKeys.public\n```\nThe server replies with the `serverPublicKey` and the salt value associated with the user. At this point the server will need to store the `serverKeys` and the public key it received from the client, most likely in a database.  \n\nThe client then creates the shared secret using the username, password, salt, its own key pair and the server public key. It then has to generate a proof it has the shared secret. This proof is generated from shared secret plus any of the public data available.\n```swift\nlet clientSharedSecret = try client.calculateSharedSecret(\n    username: username, \n    password: password, \n    salt: salt, \n    clientKeys: clientKeys, \n    serverPublicKey: serverPublicKey\n)\nlet clientProof = client.calculateClientProof(\n    username: username, \n    salt: salt, \n    clientPublicKey: clientPublicKey, \n    serverPublicKey: serverPublicKey, \n    sharedSecret: clientSharedSecret\n)\n```\nThis `clientProof` is passed to the server. The server then generates its own version of the shared secret and verifies the `clientProof` is valid and if so will respond with it's own proof that it has the shared secret.\n```swift\nlet serverSharedSecret = try server.calculateSharedSecret(\n    clientPublicKey: clientPublicKey, \n    serverKeys: serverKeys, \n    verifier: verifier\n)\nlet serverProof = try server.verifyClientProof(\n    proof: clientProof, \n    username: username, \n    salt: salt, \n    clientPublicKey: clientPublicKey, \n    serverPublicKey: serverPublicKey, \n    sharedSecret: serverSharedSecret\n)\n```\nAnd finally the client can verify the server proof is valid\n```swift\ntry client.verifyServerProof(\n    serverProof: serverProof, \n    clientProof: clientProof, \n    clientPublicKey: clientPublicKey, \n    sharedSecret: clientSharedSecret\n)\n```\nIf at any point any of these functions fail the process should be aborted.\n\n# Compatibility\n\nThe library is compliant with RFC5054 and should work with any server implementing this. The library has been verified against \n- example data in RFC5054\n- Mozilla test vectors in https://wiki.mozilla.org/Identity/AttachedServices/KeyServerProtocol#SRP_Verifier\n- Python library [srptools](https://github.com/idlesign/srptools)\n- Typescript library [tssrp6a](https://github.com/midonet/tssrp6a)\n\n## Proof of shared secret\n\nFor generating the client and server proofs of the shared secret I use the method detailed in [RFC2945](https://tools.ietf.org/html/rfc2945#section-3) with everything padded out to the size of N, but not all servers use this method. For this reason I have kept the sharedSecret generation separate from the proof generation, so you can insert your own version. \n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fadam-fowler%2Fswift-srp","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fadam-fowler%2Fswift-srp","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fadam-fowler%2Fswift-srp/lists"}