How to crypt string to sha1 in base64 with Swift?

北慕城南 提交于 2021-01-27 17:29:12

问题


I want to crypt privateKey & publicKey to sha1 in base64 with Swift, but the output is not the one I see in PHP urlencode base64_encode which I tried in Codecademy:"https://www.codecademy.com/courses/web-beginner-en-StaFQ/0/3?curriculum_id=5124ef4c78d510dd89003eb8".

Pls see the following codes in Swift and Codecademy:

Swift:

//pls see func dataFromHexadecimalString() details here "http://stackoverflow.com/questions/26501276/convert-string-to-hex-string-in-swift/26502285#26502285" 

extension String {

func dataFromHexadecimalString() -> NSData? {
    let trimmedString = self.stringByTrimmingCharactersInSet(NSCharacterSet(charactersInString: "<> ")).stringByReplacingOccurrencesOfString(" ", withString: "")

    var error: NSError?
    let regex = NSRegularExpression(pattern: "^[0-9a-f]*$", options: .CaseInsensitive, error: &error)
    let found = regex?.firstMatchInString(trimmedString, options: nil, range: NSMakeRange(0, count(trimmedString)))
    if found == nil || found?.range.location == NSNotFound || count(trimmedString) % 2 != 0 {
        return nil
    }

    let data = NSMutableData(capacity: count(trimmedString) / 2)

    for var index = trimmedString.startIndex; index < trimmedString.endIndex; index = index.successor().successor() {
        let byteString = trimmedString.substringWithRange(Range<String.Index>(start: index, end: index.successor().successor()))
        let num = UInt8(byteString.withCString { strtoul($0, nil, 16) })
        data?.appendBytes([num] as [UInt8], length: 1)
    }

    return data
  }
}

func URLEcodekey() -> String {
    let appid="a1b2c34d5e"
    let privateKey="ef7d6s0d"
    let areaid="101020900"
    let time="201507191254"
    let publicKey="http://open.weather.com.cn/data/?areaid=\(areaid)&type=forecast_v&date=\(time)&appid=\(appid)"

    let cPrivateKey=privateKey.dataUsingEncoding(NSUTF8StringEncoding)!
    let cPublicKey=publicKey.dataUsingEncoding(NSUTF8StringEncoding)!
    var cHMAC = [CUnsignedChar](count: Int(CC_SHA1_DIGEST_LENGTH), repeatedValue: 0)
    CCHmac(CCHmacAlgorithm(kCCHmacAlgSHA1), cPublicKey.bytes, Int(cPublicKey.length), cPrivateKey.bytes, Int(cPrivateKey.length), &cHMAC)

    let hexKeyString=NSMutableString(capacity: Int(CC_SHA1_DIGEST_LENGTH))
    for byte in cHMAC{
        hexKeyString.appendFormat("%02hhx", byte)
    }
    println("hexKeyString:\(encryptedKey)")

    let binaryData = hexKeyString.dataFromHexadecimalString()
    let base64String = binaryData?.base64EncodedStringWithOptions(nil)
    println("base64String:\(base64String)")

    var urlEncodeKey=base64String!.stringByAddingPercentEncodingWithAllowedCharacters(.URLHostAllowedCharacterSet())!
    println("urlEncodeKey:\(urlEncodeKey)")
    return urlEncodeMessage
}

the outputs are:

hexKeyString:d4433d42b1505c00a4aa80205171d0d04754d254

base64String:1EM9QrFQXACkqoAgUXHQ0EdU0lQ=

urlEncodeKey:1EM9QrFQXACkqoAgUXHQ0EdU0lQ=

PHP in Codecademy:

echo urlencode(base64_encode(hash_hmac('sha1', " http://open.weather.com.cn/data/?areaid=101020900&type=forecast_v&date=201507191254&appid=a1b2c34d5e", "ef7d6s0d", TRUE)));

the output is:

A5O59Y%2BFbGjhVwaI9JNB7DkcX%2F4%3D // the output is much like the example in API, which I think maybe the right one.

So, how can I receive the right urlEncodeKey for my privateKey & publicKey like in PHP?

Thank you very much in advance!


回答1:


You should read more about cryptography and hashing. In your case, there's no public key, private key, ... SHA stands for Secure hash algorithm and what you're trying to get is Hash based authentication code. Check Wikipedia articles about HMAC, SHA-1, Public key, ... I strongly recommend to read more about it otherwise you can create more damage if you misunderstand it.

Back to your problem. It's in one character:

  • Swift code - let publicKey="http://open.weather.com.cn...
  • PHP code - hash_hmac('sha1', " http://open.weather.com.cn...

Do you see where the problem is? In your PHP code, there's one space character just before http. This character is not in your Swift code.

Honestly, I didn't check your whole code, because I don't know why you're trying to convert it from hexadecimal string, etc. Used some parts only and rewrote it from scratch for you. Here's working example:

func URLEncodedKey() -> String? {
  let appid = "a1b2c34d5e"
  let time = "201507191254"
  let areaid = "101020900"

  let key = "ef7d6s0d"
  let string = " http://open.weather.com.cn/data/?areaid=\(areaid)&type=forecast_v&date=\(time)&appid=\(appid)"
  //            ^  <- in your PHP example, there's space

  guard let keyData = key.dataUsingEncoding(NSUTF8StringEncoding),
    stringData = string.dataUsingEncoding(NSUTF8StringEncoding),
    outputData = NSMutableData(length: Int(CC_SHA1_DIGEST_LENGTH)) else {
    return nil
  }
  outputData.length = Int(CC_SHA1_DIGEST_LENGTH)

  CCHmac(CCHmacAlgorithm(kCCHmacAlgSHA1),
    keyData.bytes, keyData.length,
    stringData.bytes, stringData.length,
    outputData.mutableBytes)

  return outputData
    .base64EncodedStringWithOptions([])
    .stringByAddingPercentEncodingWithAllowedCharacters(.URLQueryAllowedCharacterSet())
}

Return value is:

`Optional("A5O59Y+FbGjhVwaI9JNB7DkcX/4=")`

Which is what you get when you decode your PHP output.

Just replace URLQueryAllowedCharacterSet with any of the following character sets:

class func URLUserAllowedCharacterSet() -> NSCharacterSet    
class func URLPasswordAllowedCharacterSet() -> NSCharacterSet
class func URLHostAllowedCharacterSet() -> NSCharacterSet    
class func URLPathAllowedCharacterSet() -> NSCharacterSet
class func URLQueryAllowedCharacterSet() -> NSCharacterSet
class func URLFragmentAllowedCharacterSet() -> NSCharacterSet

Depends on your use case. IOW in which part of the URL your would like to use it.



来源:https://stackoverflow.com/questions/31516961/how-to-crypt-string-to-sha1-in-base64-with-swift

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!