Reputation: 1593
My wordpress backend is using phpass hash algorithm and giving me phpass using web service. In ios end in swift I am trying to generate same phpass hash in swift. Below are codes in swift and php. Both have same input but output is different. So question is that how can i get same output. Am I missing anything?
Php code :
<?php
function phpassHash($password, $salt,$iterations){
$hash = hash('md5', $salt.$password, TRUE);
for($i = 0; $i < $iterations; $i++){
$hash = hash('md5', $hash.$password, TRUE);
}
return $hash;
}
$result = phpassHash("a_test_password","MsdvACyA", 8192);
echo bin2hex($result);
?>
Swift code :
func md5(string: String) -> String {
var digest = [UInt8](count: Int(CC_MD5_DIGEST_LENGTH), repeatedValue: 0)
if let data = string.dataUsingEncoding(NSUTF8StringEncoding) {
CC_MD5(data.bytes, CC_LONG(data.length), &digest)
}
var digestHex = ""
for index in 0..<Int(CC_MD5_DIGEST_LENGTH) {
digestHex += String(format: "%02x", digest[index])
}
return digestHex
}
func phpassHash(password: String, salt: String, iterations: Int) -> String {
var hash = md5(salt+password)
for _ in 0..<iterations {
hash = md5(hash+password)
}
return hash;
}
Upvotes: 2
Views: 329
Reputation: 93181
You were too eager to convert the bytes array into String
in your md5
function. As an example, this changes the meaning of the integer 0x47
to the string 47
. Your first call to md5()
returns the correct hash, but if you md5()
that again, it will go wrong since it's a string now instead of an array of bytes as in PHP. Notice that in PHP, you call bin2hex
at the very last step.
Since the CC_MD5
function in CommonCrypt like to deal with array of bytes, keep everything as bytes and writer wrapper if necessary.
First, let's define some helper functions:
extension String {
// Return the bytes that make up the string according to UTF-8 encoding
var bytes: [UInt8] {
get {
return self.cStringUsingEncoding(NSUTF8StringEncoding)!
.dropLast() // C strings are null-terminated so we need to drop the last byte
.map { UInt8(bitPattern: $0) }
}
}
}
// Convert an array of bytes to a hex string
func toHexString(bytes: [UInt8]) -> String {
return bytes.map { String(format: "%02x", $0) }.joinWithSeparator("")
}
Now you can write your hash fucntions:
// Allow you to quickly hash a string. We don't really use it here
func md5(string: String) -> [UInt8] {
return md5(string.bytes)
}
func md5(bytes: [UInt8]) -> [UInt8] {
var digest = [UInt8](count: Int(CC_MD5_DIGEST_LENGTH), repeatedValue: 0)
CC_MD5(bytes, CC_LONG(bytes.count), &digest)
return digest
}
func phpassHash(password: String, salt: String, iterations: Int) -> [UInt8] {
let passwordBytes = password.bytes
let saltBytes = salt.bytes
var hash = md5(saltBytes + passwordBytes)
for _ in 0..<iterations {
hash = md5(hash + passwordBytes)
}
return hash
}
let password = "a_test_password"
let salt = "MsdvACyA"
let iterations = 8192
let assHash = phpassHash(password, salt: salt, iterations: iterations)
print(toHexString(assHash)) // 42a89278a28860f223a10fdb43b5d4b2
Upvotes: 1