我找到了自己问题的答案,想分享一下,因为这对其他人有用。
服务器团队使用 Scrypt 库 (https://github.com/wg/scrypt) 为给定的密码和盐生成哈希字符串。
在分析了服务端库后,我们得知生成的哈希字符串包含以下组件。
1) Scrypt 版本 ($s0$)
2) 参数
(这是使用以下公式计算的:
字符串参数 = Long.toString(log2(N)
3) base64 字符串格式的盐
4) 生成base64字符串格式的派生键
最终哈希字符串的格式为$s0$params$salt$key
(更多信息请参考此问题What's the is maximum length of scrypt output?)
如问题中所述,我在客户端使用 NAChloride 库来生成哈希字符串。
该类包含以下生成哈希字符串的方法:
open class func scrypt(_ password: Data!, salt: Data!, n N: UInt64, r: UInt32, p: UInt32, length: Int) throws -> Data
在我们的示例中,我们传递了以下值:
n=16,
r=16,
p=16,
长度(字节)= 32,
盐=数据(字节:[0x73、0x61、0x6c、0x74、0x44、0x61、0x74、0x61、0x73、0x61、0x6c、0x74、0x44、0x61、0x74、0x61、0x73、0x61、4、0x6c、07 0x44, 0x61, 0x74, 0x61,0x73, 0x61, 0x6c, 0x74, 0x44, 0x61, 0x74, 0x61])
此方法将仅生成“数据”格式的派生密钥,因此我认为与服务器端生成的密钥相比,它是不同的。
我必须在生成派生密钥后编写一个逻辑,以匹配服务器生成的哈希字符串的格式(服务器端哈希字符串格式)。
下面是用 Swift 3.0 编写的代码,用于使用 NAChloride 库为给定密码生成哈希字符串,该库内部使用 Scrypt 哈希算法:
func passwordHashingUsingScrypt(password: String) -> String{
let N = 16
let r = 16
let p = 16
let term1 = Int(log2(Double(N))) << 16
let term2 = r << 8
let paramsDecimal = term1 | term2 | p
let params = String(format:"%2X", paramsDecimal)
print(params)
let message = password.data(using:.utf8)!
let salt = Data(bytes:[0x73, 0x61, 0x6c, 0x74, 0x44, 0x61, 0x74, 0x61,0x73, 0x61, 0x6c, 0x74, 0x44, 0x61, 0x74, 0x61,0x73, 0x61, 0x6c, 0x74, 0x44, 0x61, 0x74, 0x61,0x73, 0x61, 0x6c, 0x74, 0x44, 0x61, 0x74, 0x61])
let saltBase64String = salt.base64EncodedString()
print(saltBase64String)
let hashData = try! NAScrypt.scrypt(message, salt: salt, n: 16, r: 16, p: 16, length: 32)
let hashBase64String = hashData.base64EncodedString()
print(hashBase64String)
let result = saltBase64String+"$"+hashBase64String
print(result)
var hashString = String()
hashString.append("$s0$")
hashString.append(params)
hashString.append("$")
hashString.append(saltBase64String)
hashString.append("$")
hashString.append(hashBase64String)
print(hashString)
return hashString
}
您也可以使用以下方法生成随机盐:
func randomBytes(numberOfBytes:Int) -> [UInt8] {
var randomBytes = [UInt8](repeating: 0, count: numberOfBytes) // array to hold randoms bytes
let result = SecRandomCopyBytes(kSecRandomDefault, numberOfBytes, &randomBytes)
print(result)
return randomBytes
}
结果:
密码:
admin1234
哈希字符串: $s0$41010$c2FsdERhdGFzYWx0RGF0YXNhbHREYXRhc2FsdERhdGE=$GrMF1P3VH8YrgUEaOJDVSc4as/XTSWhCbbp4DLie00I=