d = h.digest() assert len(d) == 32 def get_button(byte): ibyte = ord(byte) if ibyte < 6: return 1 return ibyte % 5 + 1 b1, b2, b3 = get_button(d[0]), get_button(d[15]), get_button(d[31]) print('Sending the payload to the OnlyKey...') ok.send_large_message2(msg=Message.OKDECRYPT, payload=payload, slot_id=101) # Tim - The OnlyKey can send the code to enter but it would be better if the app generates # the code, this way in order to trick a user into approving an unauthorized signature # the app, in this case this python code would have to be hacked on the user's system. # How the OnlyKey creates the three digit code: # SHA256_CTX CRYPTO; # sha256_init(&CRYPTO); # sha256_update(&CRYPTO, large_buffer, large_data_offset); //step 1 create a sha256 hash of # sha256_final(&CRYPTO, rsa_signature); //the data to sign # if (rsa_signature[0] < 6) Challenge_button1 = '1'; //step 2 Convert first byte of hash to # else { //first button to press (remainder of byte is a base 6 number 0 - 5) # Challenge_button1 = rsa_signature[0] % 5; # Challenge_button1 = Challenge_button1 + '0' + 1; //Add '0' and 1 so number will be ASCII 1 - 6 # } # if (rsa_signature[15] < 6) Challenge_button2 = '1'; //step 3 do the same with 16th byte to
class Client(object): """Client wrapper for SSH authentication device.""" def __init__(self, curve=formats.CURVE_NIST256): """Connect to hardware device.""" self.device_name = 'OnlyKey' self.ok = OnlyKey() self.curve = curve def __enter__(self): """Start a session, and test connection.""" self.ok.read_string(timeout_ms=50) empty = 'a' while not empty: empty = self.ok.read_string(timeout_ms=50) return self def __exit__(self, *args): """Forget PIN, shutdown screen and disconnect.""" log.info('disconnected from %s', self.device_name) self.ok.close() def get_identity(self, label, index=0): """Parse label string into Identity protobuf.""" identity = string_to_identity(label) identity['proto'] = 'ssh' identity['index'] = index print 'identity', identity return identity def get_public_key(self, label): log.info('getting public key from %s...', self.device_name) log.info('Trying to read the public key...') # Compute the challenge pin h = hashlib.sha256() h.update(label) data = h.hexdigest() if self.curve == formats.CURVE_NIST256: data = '02' + data else: data = '01' + data data = data.decode("hex") log.info('Identity hash =%s', repr(data)) self.ok.send_message(msg=Message.OKGETPUBKEY, slot_id=132, payload=data) time.sleep(.5) for _ in xrange(2): ok_pubkey = self.ok.read_bytes(64, to_str=True, timeout_ms=10) if len(ok_pubkey) == 64: break log.info('received= %s', repr(ok_pubkey)) if len(set(ok_pubkey[34:63])) == 1: ok_pubkey = ok_pubkey[0:32] log.info('Received Public Key generated by OnlyKey= %s', repr(ok_pubkey)) vk = ed25519.VerifyingKey(ok_pubkey) return formats.export_public_key(vk=vk, label=label) else: ok_pubkey = ok_pubkey[0:64] log.info('Received Public Key generated by OnlyKey= %s', repr(ok_pubkey)) vk = ecdsa.VerifyingKey.from_string(ok_pubkey, curve=ecdsa.NIST256p) return formats.export_public_key(vk=vk, label=label) def sign_ssh_challenge(self, label, blob): """Sign given blob using a private key, specified by the label.""" msg = _parse_ssh_blob(blob) log.debug('%s: user %r via %r (%r)', msg['conn'], msg['user'], msg['auth'], msg['key_type']) log.debug('nonce: %s', binascii.hexlify(msg['nonce'])) log.debug('fingerprint: %s', msg['public_key']['fingerprint']) log.debug('hidden challenge size: %d bytes', len(blob)) # self.ok.send_large_message(payload=blob, msg=Message.OKSIGNSSHCHALLENGE) log.info('please confirm user "%s" login to "%s" using %s', msg['user'], label, self.device_name) h1 = hashlib.sha256() h1.update(label) data = h1.hexdigest() data = data.decode("hex") test_payload = blob + data # Compute the challenge pin h2 = hashlib.sha256() h2.update(test_payload) d = h2.digest() assert len(d) == 32 def get_button(byte): ibyte = ord(byte) return ibyte % 6 + 1 b1, b2, b3 = get_button(d[0]), get_button(d[15]), get_button(d[31]) log.info('blob to send', repr(test_payload)) # Determine type of key to derive on OnlyKey for signature # 201 = ed25519 # 202 = P256 # 203 = secp256k1 keytype = msg['key_type'] if msg['key_type'].startswith('ssh-ed25519'): this_slot_id = 201 log.info('Key type ed25519') elif msg['key_type'].startswith('ecdsa-sha2-nistp256'): this_slot_id = 202 log.info('Key type P256') else: this_slot_id = 203 log.info('Key type secp256k1') self.ok.send_large_message2(msg=Message.OKSIGNCHALLENGE, payload=test_payload, slot_id=this_slot_id) #TODO ping messages so that we don't need enter key to tell when done. print 'Please confirm user', msg[ 'user'], 'login to', label, 'using', self.device_name print( 'Enter the 3 digit challenge code shown below on OnlyKey to authenticate' ) print '{} {} {}'.format(b1, b2, b3) raw_input() for _ in xrange(10): result = self.ok.read_bytes(64, to_str=True, timeout_ms=200) if len(result) >= 60: log.info('received= %s', repr(result)) while len(result) < 64: result.append(0) log.info('disconnected from %s', self.device_name) self.ok.close() return result raise Exception('failed to sign challenge')
h = hashlib.sha256() h.update(ciphertext) d = h.digest() assert len(d) == 32 def get_button(byte): ibyte = ord(byte) if ibyte < 6: return 1 return ibyte % 5 + 1 b1, b2, b3 = get_button(d[0]), get_button(d[15]), get_button(d[31]) print 'Sending the payload to the OnlyKey...' ok.send_large_message2(msg=Message.OKDECRYPT, payload=ciphertext, slot_id=1) print 'Please enter the 3 digit challenge code on OnlyKey (and press ENTER if necessary)' print '{} {} {}'.format(b1, b2, b3) raw_input() print 'Trying to read the decrypted data from OnlyKey...' ok_decrypted = '' while ok_decrypted == '': time.sleep(0.5) ok_decrypted = ok.read_bytes(len(message), to_str=True) dsize = len(message) sentinel = Random.new().read(15+dsize) plaintext = cipher.decrypt(ciphertext, sentinel) print 'Decrypted by OnlyKey, data=', repr(ok_decrypted)
assert len(d) == 32 def get_button(byte): ibyte = ord(byte) if ibyte < 6: return 1 return ibyte % 5 + 1 b1, b2, b3 = get_button(d[0]), get_button(d[15]), get_button(d[31]) print 'Sending the payload to the OnlyKey...' ok.send_large_message2(msg=Message.OKSIGNCHALLENGE, payload=test_payload, slot_id=101) # Tim - The OnlyKey can send the code to enter but it would be better if the app generates # the code, this way in order to trick a user into approving an unauthorized signature # the app, in this case this python code would have to be hacked on the user's system. # How the OnlyKey creates the three digit code: # SHA256_CTX CRYPTO; # sha256_init(&CRYPTO); # sha256_update(&CRYPTO, large_buffer, large_data_offset); //step 1 create a sha256 hash of # sha256_final(&CRYPTO, rsa_signature); //the data to sign # if (rsa_signature[0] < 6) Challenge_button1 = '1'; //step 2 Convert first byte of hash to # else { //first button to press (remainder of byte is a base 6 number 0 - 5) # Challenge_button1 = rsa_signature[0] % 5; # Challenge_button1 = Challenge_button1 + '0' + 1; //Add '0' and 1 so number will be ASCII 1 - 6 # }