该库提供了安全远程密码协议的 Swift 实现。安全远程密码(SRP)提供用户名和密码认证,而无需向服务器提供您的密码。 由于服务器永远不会看到您的密码,因此它永远不会将其泄露给任何人。
服务器会收到一个密码验证器,该验证器源自密码以及用于生成此验证器的 salt 值。 客户端和服务器都会生成大的私钥和公钥,并使用它们生成共享密钥。 然后,客户端发送一个证明它拥有密钥的凭据,如果通过验证,服务器也会这样做以验证服务器。
SRP 协议在 RFC2945 中有详细说明。 该库实现了协议的 6a 版本,其中包括 salt 中的用户名,以避免恶意服务器尝试了解两个用户是否具有相同密码的问题。 我相信它也符合 RFC5054。
首先,您创建一个配置对象。 这将保存您使用的哈希算法、所需的大型安全素数和生成器值。 有一个枚举包含示例素数和生成器。 通常,使用这些值更安全,因为它们是 RFC5054 中提供的并且经过了实战测试。 以下代码使用 SHA256 和 2048 位安全素数生成配置。 您需要确保客户端和服务器使用相同的配置。
let configuration = SRPConfiguration<SHA256>(.N2048)
当客户端想要创建一个新用户时,他们会为其用户名和密码生成 salt 值和密码验证器。
let client = SRPClient(configuration: configuration)
let (salt, verifier) = client.generateSaltAndVerifier(username: username, password: password)
这些被传递给服务器,服务器会将它们与用户名一起存储在数据库中。
当客户端想要使用服务器进行身份验证时,他们首先需要生成一个公钥/私钥对。 这些密钥应该只使用一次。 如果您想再次进行身份验证,则应生成一个新的密钥对。
let client = SRPClient(configuration: configuration)
let clientKeys = client.generateKeys()
let clientPublicKey = clientKeys.public
clientPublicKey
变量的内容与用户名一起传递到服务器,以启动身份验证。
然后,服务器将在其数据库中查找用户名,并提取与该用户名一起存储的密码验证器和 salt 值。 密码验证器用于生成服务器的密钥对。
let server = SRPServer(configuration: configuration)
let serverKeys = server.generateKeys(verifier: values.verifier)
let serverPublicKey = serverKeys.public
服务器使用 serverPublicKey
和与用户关联的 salt 值进行回复。 此时,服务器将需要存储 serverKeys
以及从客户端收到的公钥,最有可能是在数据库中。
然后,客户端使用用户名、密码、salt 值、其自己的密钥对和服务器公钥创建共享密钥。 然后,它必须生成一个证明它拥有共享密钥的凭据。 此凭据由共享密钥以及任何可用的公共数据生成。
let clientSharedSecret = try client.calculateSharedSecret(
username: username,
password: password,
salt: salt,
clientKeys: clientKeys,
serverPublicKey: serverPublicKey
)
let clientProof = client.calculateClientProof(
username: username,
salt: salt,
clientPublicKey: clientPublicKey,
serverPublicKey: serverPublicKey,
sharedSecret: clientSharedSecret
)
此 clientProof
传递到服务器。 然后,服务器生成其自己的共享密钥版本并验证 clientProof
是否有效,如果是,则会回复它自己的凭据,证明它拥有共享密钥。
let serverSharedSecret = try server.calculateSharedSecret(
clientPublicKey: clientPublicKey,
serverKeys: serverKeys,
verifier: verifier
)
let serverProof = try server.verifyClientProof(
proof: clientProof,
username: username,
salt: salt,
clientPublicKey: clientPublicKey,
serverPublicKey: serverPublicKey,
sharedSecret: serverSharedSecret
)
最后,客户端可以验证服务器凭据是否有效
try client.verifyServerProof(
serverProof: serverProof,
clientProof: clientProof,
clientPublicKey: clientPublicKey,
sharedSecret: clientSharedSecret
)
如果在任何时候这些函数中的任何一个失败,都应中止该过程。
该库符合 RFC5054,应该可以与任何实现此标准的服务器一起使用。 该库已针对以下内容进行验证:
对于生成客户端和服务器的共享密钥凭据,我使用 RFC2945 中详述的方法,并将所有内容填充到 N 的大小,但并非所有服务器都使用此方法。 因此,我将 sharedSecret 的生成与凭据的生成分开,因此您可以插入自己的版本。