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: clientKeys.public, 
    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: serverKeys.public, 
    sharedSecret: serverSharedSecret
)

最后,客户端可以验证服务器证明是否有效。

try client.verifyServerProof(
    serverProof: serverProof, 
    clientProof: clientProof, 
    clientKeys: clientKeys, 
    sharedSecret: clientSharedSecret
)

如果在任何时候这些函数中的任何一个失败,都应该中止该过程。

兼容性

该库符合 RFC5054,并且应该与任何实现此标准的服务器一起使用。 该库已针对以下内容进行了验证:

密钥证明

对于生成上述证明,我使用了 RFC2945 中详细说明的方法,但并非所有服务器都使用此方法。 因此,我将 sharedSecret 的生成与证明的生成分开,因此您可以插入自己的版本。

我还提供了一个简单的证明函数 server.verifySimpleClientProofclient.verifySimpleServerProof,它们使用维基百科 页面 中关于安全远程密码中的证明,如果您更喜欢使用这些证明。