该库提供了一个安全远程密码协议的 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.verifySimpleClientProof
和 client.verifySimpleServerProof
,它们使用维基百科 页面 中关于安全远程密码中的证明,如果您更喜欢使用这些证明。