I had found answer for my own question, thought of sharing as it will be useful for others.
The server team was using Scrypt library (https://github.com/wg/scrypt) to generate hash string for given password and salt.
After analysing the server side library we came to know that the generated hash string contains following components.
1) Scrypt version ($s0$)
2) params
(This is calculated using below formula:
String params = Long.toString(log2(N) << 16L | r << 8 | p, 16))
3) Salt in base64 string format
4) Generated derived key in base64 string format
The Format of final hash string is $s0$params$salt$key
(Refer to this question for more information What's the is maximum length of scrypt output?)
As stated in the question I have used NAChloride library at the client side to generate hash string.
This class contains below method for generating hash string:
open class func scrypt(_ password: Data!, salt: Data!, n N: UInt64, r: UInt32, p: UInt32, length: Int) throws -> Data
In our example we have passed below values:
n= 16,
r= 16,
p= 16,
length (bytes) = 32,
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])
This method will generate only derived key in 'Data' format, thus I was thinking that it is different when compared to the key generated at server side.
I had to write a logic after generating the derived key to match to the format of the hash string (server side hash string format) generated at the server.
Below is the code written in Swift 3.0 to generate hash string for given password using NAChloride library which internally uses Scrypt hash algorithm:
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
}
You can also generate the random salt using below method:
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
}
Result:
Password:
admin1234<
Hash String: $s0$41010$c2FsdERhdGFzYWx0RGF0YXNhbHREYXRhc2FsdERhdGE=$GrMF1P3VH8YrgUEaOJDVSc4as/XTSWhCbbp4DLie00I=