Example #1
0
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
Example #2
0
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
# }