How to translate Python HMAC Request into Swift

Viewed 68

I've been at this about 10 hours now and no matter what HMAC combination I use for swift I can not get it to match the key generated by python.

Python Code:

signature = hmac.new(secret.decode('hex'), msg=datastring, digestmod=hashlib.sha256).hexdigest()

Swift Code:

let key = SymmetricKey(data: self.secret.data(using: .utf8)!)
let hexData = HMAC<SHA256>.authenticationCode(for: datastring.data(using: .utf8)!, using: key)
let signature = Data(hexData).map { String(format: "%02hhx", $0) }.joined()

Any help with what I'm doing wrong (or missing) in Swift would be greatly appreciated.

1 Answers

Based on the assumption that self.secret is a String containing the hex representation of the secret key, the difference between the two comes down to your use of:

self.secret.data(using: .utf8)!

which will just perform a straight conversion to the underlying bytes instead of converting each character pair into the corresponding byte, as:

secret.decode('hex')

does in Python 2.

From what I can tell, there isn't a function to do this conversion in the Swift standard library, but you could do it with something like:

func bytes(fromHex input: String) -> Data {
  var result = Data()
  var byte: UInt8 = 0 

  for (index, character) in input.enumerated() {
    let codeUnit = character.utf8[character.utf8.startIndex]
    var nibble: UInt8 = 0 

    switch codeUnit {
    case 0x30..<0x3a:
      nibble = codeUnit - 0x30 
    case 0x61..<0x67:
      nibble = codeUnit - 0x57
    default:
      break
    }   

    if index % 2 == 0 { 
      byte |= (nibble << 4)
    } else {
      byte |= nibble
      result.append(contentsOf: [byte])
      byte = 0 
    }   
  }

  return result
}

and then your code would become:

let key = SymmetricKey(data: bytes(fromHex: self.secret))
let hexData = HMAC<SHA256>.authenticationCode(for: datastring.data(using: .utf8)!, using: key)
let signature = Data(hexData).map { String(format: "%02hhx", $0) }.joined()
Related