phpass散列在swift中的类似功能

时间:2021-03-08 19:17:08

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?

我的wordpress后台使用phpass散列算法,并用web服务提供phpass。在ios结尾的swift中,我尝试在swift中生成相同的phpass散列。下面是swift和php代码。两者都有相同的输入,但输出不同。问题是如何得到相同的输出。我错过什么吗?

Php code :

Php代码:

<?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;
    }

1 个解决方案

#1


1  

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.

在md5函数中,您太急于将字节数组转换为字符串。例如,这会将整数0x47的含义更改为字符串47。第一次对md5()的调用返回了正确的散列,但是如果再次调用md5(),就会出错,因为它现在是字符串,而不是PHP中的字节数组。注意,在PHP中,在最后一步调用bin2hex。

Since the CC_MD5 function in CommonCrypt like to deal with array of bytes, keep everything as bytes and writer wrapper if necessary.

因为CommonCrypt中的CC_MD5函数喜欢处理字节数组,所以如果需要的话,请将所有内容保存为字节和写入器包装器。

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:

现在你可以写你的散列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

#1


1  

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.

在md5函数中,您太急于将字节数组转换为字符串。例如,这会将整数0x47的含义更改为字符串47。第一次对md5()的调用返回了正确的散列,但是如果再次调用md5(),就会出错,因为它现在是字符串,而不是PHP中的字节数组。注意,在PHP中,在最后一步调用bin2hex。

Since the CC_MD5 function in CommonCrypt like to deal with array of bytes, keep everything as bytes and writer wrapper if necessary.

因为CommonCrypt中的CC_MD5函数喜欢处理字节数组,所以如果需要的话,请将所有内容保存为字节和写入器包装器。

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:

现在你可以写你的散列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