Swift SRP

该库提供了安全远程密码协议的 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 的生成与凭据的生成分开,因此您可以插入自己的版本。