简体   繁体   中英

How to crypt string to sha1 in base64 with Swift?

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!

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM