This is an example of how to derive the authentication key. This example uses Python. Authentication is required where you connect to the codec over IP. This is not required for serial connections.

# Copyright (c) StarLeaf Ltd. 2015

import hashlib
import hmac
import pbkdf2
import binascii

def endpoint_api_key(password, salt_hex, iterations, verbose=False):
  if verbose:
    print "Key is PBKDF2(HMAC-SHA256, '%s', '%s', %d, 32)." % (password, salt_hex, iterations)

  salt = binascii.unhexlify(salt_hex)
  key = pbkdf2.PBKDF2(passphrase=password, salt=salt, iterations=iterations,
                      digestmodule=hashlib.sha256, macmodule=hmac)
  key_hex = key.hexread(32)
  if verbose:
    print "Key is '%s'." % key_hex

  return key_hex

def endpoint_api_response(key, challenge, verbose=False):
  if verbose:
    print "Response is HMAC-SHA256('%s', '%s')." % (key, challenge)

  key_bytes = binascii.unhexlify(key)
  hash =, challenge, hashlib.sha256)
  response = hash.hexdigest()
  if verbose:
    print "Response is '%s'." % response

  return response

if __name__ == '__main__':
  from optparse import OptionParser

  parser = OptionParser()

  parser.add_option("--password", dest='password', help="API password, as set in portal.")
  parser.add_option("--salt", dest='salt', help="Salt to apply to the password during key derivation.")
  parser.add_option("--iterations", dest='iterations', type='int', help="Number of iterations to hash during key derivation.")
  parser.add_option("--key", dest='key', help="Key derived from password.")
  parser.add_option("--challenge", dest='challenge', help="Challenge returned by server.")

  parser.add_option("--mode", type='choice', choices=['key', 'respond'], dest='mode', default='respond',
                    help="Mode: key (derive key from password) or respond (build response to challenge).")
  parser.add_option("--format", type='choice', choices=['text', 'query', 'json'], dest='format', default='text',
                    help="Output format for response: (text (plain text), query (HTTP URI query format) or json (JSON object)).")

  parser.add_option("--verbose", action='store_true', dest='verbose', help="Print details of intermediate steps.")

  (opt, args) = parser.parse_args()

  if opt.key:
    key = opt.key
    key = endpoint_api_key(opt.password, opt.salt, opt.iterations, opt.verbose)

  if opt.mode == 'key':
    print key

  elif opt.mode == 'respond':
    response = endpoint_api_response(key, opt.challenge, opt.verbose)

    if opt.format == 'query':
      print "challenge=%s&response=%s" % (opt.challenge, response)
    elif opt.format == 'json':
      print "{\n  \"challenge\": \"%s\",\n  \"response\": \"%s\"\n}" % (opt.challenge, response)
      print opt.response

    print "Invalid mode '%s'." % opt.mode