def locate_pack_recipient_key(recipients: Sequence[dict], my_verkey: bytes,
                              my_sigkey: bytes) -> (bytes, str, str):
    """
    Locate pack recipient key.

    Decode the encryption key and sender verification key from a
    corresponding recipient block, if any is defined.

    Args:
        recipients: Recipients to locate
        find_key: Function used to find private key

    Returns:
        A tuple of (cek, sender_vk, recip_vk_b58)

    Raises:
        ValueError: If no corresponding recipient key found

    """
    not_found = []
    for recip in recipients:
        if not recip or "header" not in recip or "encrypted_key" not in recip:
            raise ValueError("Invalid recipient header")

        recip_vk_b58 = recip["header"].get("kid")

        if bytes_to_b58(my_verkey) != recip_vk_b58:
            not_found.append(recip_vk_b58)
            continue

        recip_vk = b58_to_bytes(recip_vk_b58)
        pk = pysodium.crypto_sign_pk_to_box_pk(my_verkey)
        sk = pysodium.crypto_sign_sk_to_box_sk(my_sigkey)

        encrypted_key = b64_to_bytes(recip["encrypted_key"], urlsafe=True)

        nonce_b64 = recip["header"].get("iv")
        nonce = b64_to_bytes(nonce_b64, urlsafe=True) if nonce_b64 else None
        sender_b64 = recip["header"].get("sender")
        enc_sender = b64_to_bytes(sender_b64,
                                  urlsafe=True) if sender_b64 else None

        if nonce and enc_sender:
            sender_vk_bin = pysodium.crypto_box_seal_open(enc_sender, pk, sk)
            sender_vk = sender_vk_bin.decode("ascii")
            sender_pk = pysodium.crypto_sign_pk_to_box_pk(
                b58_to_bytes(sender_vk_bin))
            cek = pysodium.crypto_box_open(encrypted_key, nonce, sender_pk, sk)
        else:
            sender_vk = None
            cek = pysodium.crypto_box_seal_open(encrypted_key, pk, sk)
        return cek, sender_vk, recip_vk_b58
    raise ValueError(
        "No corresponding recipient key found in {}".format(not_found))
Beispiel #2
0
 def handle(self):
     data, socket = self.request
     unsealed = pysodium.crypto_box_seal_open(data, pk, sk)
     ap = unsealed[:pysodium.crypto_box_PUBLICKEYBYTES]
     challenge = unsealed[pysodium.crypto_box_PUBLICKEYBYTES:]
     packets.append(ap)
     nonce = pysodium.randombytes(pysodium.crypto_box_NONCEBYTES)
     response = pysodium.crypto_box(challenge, nonce, ap, sk)
     dst = (src2dst(self.client_address[0]), REG_PORT)
     socket.setsockopt(SOL_SOCKET, SO_BROADCAST, 1)
     socket.sendto(nonce + response, dst)
Beispiel #3
0
    def decrypt_news(news_item):
        assert ('to' in news_item)

        # Message was sent to a team, so we need to decode and decrypt it
        decoded_msg = b64decode(news_item['msg'].encode("utf-8"))
        try:
            team_pk, team_sk = team['crypt_pk'], TeamSecrets['crypt_sk']
            decrypted_msg = pysodium.crypto_box_seal_open(
                decoded_msg, team_pk, team_sk)
        except:
            decrypted_msg = b'<Failed to decrypt>'

        news_item['msg'] = decrypted_msg.decode("utf-8")
        return news_item
Beispiel #4
0
def test0():
    if not pysodium.sodium_version_check(1, 0, 9): return

    pk, sk = pysodium.crypto_box_keypair()
    #print(pk)
    #print(sk)
    p = binascii.hexlify(pk)
    s = binascii.hexlify(sk)
    print(p)
    print(s)

    c = pysodium.crypto_box_seal(b"passwd", pk)
    print(binascii.hexlify(c))
    print(pysodium.crypto_box_seal_open(c, pk, sk))
Beispiel #5
0
    def decrypt_report(self, encrypted_report_blob):
        """
        Decrypt a report blob using libnacl public encryption or throw 
        an exception if in case there is a problem with decryption

        Args:
        report: The report as json string in base64 encoding

        Returns:
        The original report.
        """
        return pysodium.crypto_box_seal_open(
            base64.decodestring(encrypted_report_blob), self.receiver_pub_key,
            self.receiver_secret_key)
def anon_decrypt_message(enc_message: bytes, secret: bytes) -> bytes:
    """
    Apply anon_decrypt to a binary message.

    Args:
        enc_message: The encrypted message
        secret: The seed to use

    Returns:
        The decrypted message

    """
    sign_pk, sign_sk = create_keypair(secret)
    pk = pysodium.crypto_sign_pk_to_box_pk(sign_pk)
    sk = pysodium.crypto_sign_sk_to_box_sk(sign_sk)

    message = pysodium.crypto_box_seal_open(enc_message, pk, sk)
    return message
Beispiel #7
0
    def data_received(self, data):
        if verbose: print('Data received: ', data, file=sys.stderr)

        try:
            data = pysodium.crypto_sign_open(data, self.handler.getserverkey())
        except ValueError:
            raise ValueError('invalid signature.\nabort')

        if data != b'ok' and (data[:-42] == b'fail' or
                              len(data) != sphinxlib.DECAF_255_SER_BYTES + 90):
            raise ValueError('fail')

        if not self.b:
            self.cb()
            return

        rwd = sphinxlib.finish(self.pwd, self.b,
                               data[:sphinxlib.DECAF_255_SER_BYTES])

        if self.handler.namesite is not None:
            if self.handler.namesite['name'].encode() not in self.handler.list(
                    self.handler.namesite['site']):
                self.handler.cacheuser(self.handler.namesite)

        rule = data[sphinxlib.DECAF_255_SER_BYTES:]
        esk = self.handler.getkey()
        sk = pysodium.crypto_sign_sk_to_box_sk(esk)
        epk = pysodium.crypto_sign_sk_to_pk(esk)
        pk = pysodium.crypto_sign_pk_to_box_pk(epk)
        rule = pysodium.crypto_box_seal_open(rule, pk, sk)
        if len(rule) != 42:
            raise ValueError('fail')
        rk = pysodium.crypto_generichash(self.handler.getkey(),
                                         self.handler.getsalt())
        rule = pysodium.crypto_secretbox_open(rule[24:], rule[:24], rk)
        rule = struct.unpack(">H", rule)[0]
        size = (rule & 0x7f)
        rule = {
            c
            for i, c in enumerate(('u', 'l', 's', 'd'))
            if (rule >> 7) & (1 << i)
        }
        self.cb(bin2pass.derive(rwd, rule, size).decode())
Beispiel #8
0
def test_box_seal():
    #p1 = b'~\x8b8\xf0%\xef\xba\x86\xe6\xcd\xd8\x16\x8b,\xf7\xa9\xc7a@F\x08\x84sx6\x1c\x18\xf5\x03\xbd"\x05'
    #s1 = b'\xe1\xa2\xfd\xc0\xbb\xe9\x1f,\x8a\xe8)D\x1dII\xe0\x9e{\xf1\xbe0\x04\x04\x8c\xde9V\x97\x9f\xe5&\x1a'

    pk_s = '7e8b38f025efba86e6cdd8168b2cf7a9c761404608847378361c18f503bd2205'
    sk_s = 'e1a2fdc0bbe91f2c8ae829441d4949e09e7bf1be3004048cde3956979fe5261a'

    # string to bytes (hexadecimal )
    pk_h = bytes(pk_s, 'utf8')
    sk_h = bytes(sk_s, 'utf8')

    # hexadecimal to binary data
    pk_b = binascii.unhexlify(pk_h)
    sk_b = binascii.unhexlify(sk_h)

    x_s = '1f4fa3ccb8d877a7c8a26d4c86c6866eba50c8ad03567ac7e6f84cff3069e97e7576bc506c55de41501419fd49dadd13755b426b018d'
    x_b = bytes(x_s, 'utf8')

    s = binascii.unhexlify(x_b)

    print(pysodium.crypto_box_seal_open(s, pk_b, sk_b))
Beispiel #9
0
    def data_received(self, data):
        res = b''

        if verbose:
            print('Data received: {!r}'.format(data))

        esk, xsk, xpk = getkey(keydir)
        data = pysodium.crypto_box_seal_open(data, xpk, xsk)
        clearmem(xsk)

        if data[64] == 0:
            res = self.create(data)
        elif data[64] == GET:
            # needs id, challenge, sig(id)
            # returns output from ./response | fail
            res = self.get(data)
        elif data[64] == CHANGE:
            # needs id, challenge, sig(id)
            # changes stored secret
            # returns output from ./response | fail
            res = self.change(data)
        elif data[64] == DELETE:
            # needs id, sig(id)
            # returns ok|fail
            res = self.delete(data)
        elif data[64] == COMMIT:
            # needs id, sig(id)
            # returns ok|fail
            res = self.commit(data)

        if verbose:
            print('Send: {!r}'.format(res))

        res = pysodium.crypto_sign(res, esk)
        clearmem(esk)
        self.transport.write(res)

        if verbose:
            print('Close the client socket')
        self.transport.close()
def auth_decrypt_message(enc_message: bytes, my_verkey: bytes,
                         my_sigkey: bytes) -> (bytes, str):
    """
    Apply auth_decrypt to a binary message.

    Args:
        enc_message: The encrypted message
        secret: Secret for signing keys

    Returns:
        A tuple of (decrypted message, sender verkey)

    """
    pk = pysodium.crypto_sign_pk_to_box_pk(my_verkey)
    sk = pysodium.crypto_sign_sk_to_box_sk(my_sigkey)
    body = pysodium.crypto_box_seal_open(enc_message, pk, sk)

    unpacked = msgpack.unpackb(body, raw=False)
    sender_vk = unpacked["sender"]
    nonce = b64_to_bytes(unpacked["nonce"])
    enc_message = b64_to_bytes(unpacked["msg"])
    sender_pk = pysodium.crypto_sign_pk_to_box_pk(b58_to_bytes(sender_vk))
    message = pysodium.crypto_box_open(enc_message, nonce, sender_pk, sk)
    return message, sender_vk
Beispiel #11
0
 def test_crypto_box_seal(self):
     pk, sk = pysodium.crypto_box_keypair()
     c = pysodium.crypto_box_seal(b"howdy", pk)
     self.assertEqual(pysodium.crypto_box_seal_open(c, pk, sk), b'howdy')
Beispiel #12
0
 def test_crypto_box_seal(self):
     if not pysodium.sodium_version_check(1, 0, 3): return
     pk, sk = pysodium.crypto_box_keypair()
     c = pysodium.crypto_box_seal(b"howdy", pk)
     self.assertEqual(pysodium.crypto_box_seal_open(c, pk, sk), b'howdy')
Beispiel #13
0
def test_pysodium():
    """
    Test all the functions needed from pysodium libarary (libsodium)

    """
    # crypto_sign signatures with Ed25519 keys

    # create keypair without seed
    verkey, sigkey = pysodium.crypto_sign_keypair()
    assert len(verkey) == 32 == pysodium.crypto_sign_PUBLICKEYBYTES
    assert len(sigkey) == 64 == pysodium.crypto_sign_SECRETKEYBYTES

    assert 32 == pysodium.crypto_sign_SEEDBYTES
    sigseed = pysodium.randombytes(pysodium.crypto_sign_SEEDBYTES)
    assert len(sigseed) == 32
    # seed = (b'J\xeb\x06\xf2BA\xd6/T\xe1\xe2\xe2\x838\x8a\x99L\xd9\xb5(\\I\xccRb\xc8\xd5\xc7Y\x1b\xb6\xf0')

    # Ann's seed
    sigseed = (
        b'PTi\x15\xd5\xd3`\xf1u\x15}^r\x9bfH\x02l\xc6\x1b\x1d\x1c\x0b9\xd7{\xc0_\xf2K\x93`'
    )
    assert len(sigseed) == 32

    #  try key stretching from 16 bytes using  pysodium.crypto_pwhash()
    assert 16 == pysodium.crypto_pwhash_SALTBYTES
    salt = pysodium.randombytes(pysodium.crypto_pwhash_SALTBYTES)
    assert len(salt) == 16
    #  salt = b'\x19?\xfa\xc7\x8f\x8b\x7f\x8b\xdbS"$\xd7[\x85\x87'

    # algorithm default is argon2id
    sigseed = pysodium.crypto_pwhash(
        outlen=32,
        passwd="",
        salt=salt,
        opslimit=pysodium.crypto_pwhash_OPSLIMIT_INTERACTIVE,
        memlimit=pysodium.crypto_pwhash_MEMLIMIT_INTERACTIVE,
        alg=pysodium.crypto_pwhash_ALG_DEFAULT)

    assert len(sigseed) == 32
    #  seed = (b'\xa9p\x89\x7f+\x0e\xc4\x9c\xf2\x01r\xafTI\xc0\xfa\xac\xd5\x99\xf8O\x8f=\x843\xa2\xb6e\x9fO\xff\xd0')

    # creates signing/verification key pair from seed
    verkey, sigkey = pysodium.crypto_sign_seed_keypair(sigseed)
    assert len(verkey) == 32
    assert len(sigkey) == 64
    #  sigkey is seed and verkey concatenated. Libsodium does this as an optimization
    #  because the signing scheme needs both the private key (seed) and the public key so
    #  instead of recomputing the public key each time from the secret key it requires
    #  the public key as an input of and instead of two separate inputs, one for the
    #  secret key and one for the public key, it uses a concatenated form.
    #  Essentially crypto_sign_seed_keypair and crypto_sign_keypair return redundant
    #  information in the duple (verkey, sigkey) because sigkey includes verkey
    #  so one could just store sigkey and extract verkey or sigseed when needed
    #  or one could just store verkey and sigseed and reconstruct sigkey when needed.
    #  crypto_sign_detached requires sigkey (sigseed + verkey)
    #  crypto_sign_verify_detached reqires verkey only
    #  https://crypto.stackexchange.com/questions/54353/why-are-nacl-secret-keys-64-bytes-for-signing-but-32-bytes-for-box
    assert sigseed == sigkey[:32]
    assert verkey == sigkey[32:]
    assert sigkey == sigseed + verkey
    # vk = (b'B\xdd\xbb}8V\xa0\xd6lk\xcf\x15\xad9\x1e\xa7\xa1\xfe\xe0p<\xb6\xbex\xb0s\x8d\xd6\xf5\xa5\xe8Q')

    #  utility function to extract seed from secret sigkey (really just extracting from front half)
    assert sigseed == pysodium.crypto_sign_sk_to_seed(sigkey)

    assert 64 == pysodium.crypto_sign_BYTES

    msg = "The lazy dog jumped over the river"
    msgb = msg.encode(
        "utf-8")  # must convert unicode string to bytes in order to sign it
    assert msgb == b'The lazy dog jumped over the river'
    sig = pysodium.crypto_sign_detached(msgb, sigseed +
                                        verkey)  #  sigkey = seed + verkey
    assert len(sig) == 64
    """
    sig = (b"\x99\xd2<9$$0\x9fk\xfb\x18\xa0\x8c@r\x122.k\xb2\xc7\x1fp\x0e'm\x8f@"
           b'\xaa\xa5\x8c\xc8n\x85\xc8!\xf6q\x91p\xa9\xec\xcf\x92\xaf)\xde\xca'
           b'\xfc\x7f~\xd7o|\x17\x82\x1d\xd4<o"\x81&\t')

    """
    #siga = pysodium.crypto_sign(msg.encode("utf-8"), sk)[:pysodium.crypto_sign_BYTES]
    #assert len(siga) == 64
    #assert sig == siga

    try:  #  verify returns None if valid else raises ValueError
        result = pysodium.crypto_sign_verify_detached(sig, msgb, verkey)
    except Exception as ex:
        assert False
    assert not result
    assert result is None

    sigbad = sig[:-1]
    sigbad += b'A'

    try:  #  verify returns None if valid else raises ValueError
        result = pysodium.crypto_sign_verify_detached(sigbad, msgb, verkey)
    except Exception as ex:
        assert True
        assert isinstance(ex, ValueError)

    # crypto_box authentication encryption with X25519 keys

    apubkey, aprikey = pysodium.crypto_box_keypair()
    assert len(apubkey) == 32 == pysodium.crypto_box_SECRETKEYBYTES
    assert len(aprikey) == 32 == pysodium.crypto_box_PUBLICKEYBYTES

    repubkey = pysodium.crypto_scalarmult_curve25519_base(aprikey)
    assert repubkey == apubkey

    assert 32 == pysodium.crypto_box_SEEDBYTES

    boxseed = pysodium.randombytes(pysodium.crypto_box_SEEDBYTES)
    assert len(boxseed) == 32

    bpubkey, bprikey = pysodium.crypto_box_seed_keypair(boxseed)
    assert len(bpubkey) == 32
    assert len(bprikey) == 32

    repubkey = pysodium.crypto_scalarmult_curve25519_base(bprikey)
    assert repubkey == bpubkey

    assert 24 == pysodium.crypto_box_NONCEBYTES
    nonce = pysodium.randombytes(pysodium.crypto_box_NONCEBYTES)
    assert len(nonce) == 24
    # nonce = b'\x11\xfbi<\xf2\xb6k\xa05\x0c\xf9\x86t\x07\x8e\xab\x8a\x97nG\xe8\x87,\x94'

    atob_tx = "Hi Bob I'm Alice"
    atob_txb = atob_tx.encode("utf-8")

    # Detached recomputes shared key every time.
    # A encrypt to B
    acrypt, amac = pysodium.crypto_box_detached(atob_txb, nonce, bpubkey,
                                                aprikey)
    amacl = pysodium.crypto_box_MACBYTES
    assert amacl == 16
    #  amac =  b'\xa1]\xc6ML\xe2\xa9:\xc0\xdc\xab\xa5\xc4\xc7\xf4\xdb'
    #  acrypt = (b'D\n\x17\xb6z\xd8+t)\xcc`y\x1d\x10\x0cTC\x02\xb5@\xe2\xf2\xc9-(\xec*O\xb8~\xe2\x1a\xebO')
    # when transmitting prepend amac to crypt

    acipher = pysodium.crypto_box(atob_txb, nonce, bpubkey, aprikey)
    assert acipher == amac + acrypt

    atob_rxb = pysodium.crypto_box_open_detached(acrypt, amac, nonce, apubkey,
                                                 bprikey)
    atob_rx = atob_rxb.decode("utf-8")
    assert atob_rx == atob_tx
    assert atob_rxb == atob_txb

    atob_rxb = pysodium.crypto_box_open(acipher, nonce, apubkey, bprikey)
    atob_rx = atob_rxb.decode("utf-8")
    assert atob_rx == atob_tx
    assert atob_rxb == atob_txb

    btoa_tx = "Hello Alice I am Bob"
    btoa_txb = btoa_tx.encode("utf-8")

    # B encrypt to A
    bcrypt, bmac = pysodium.crypto_box_detached(btoa_txb, nonce, apubkey,
                                                bprikey)
    # bmac = b'\x90\xe07=\xd22\x8fh2\xff\xdd\x84tC\x053'
    # bcrypt = (b'8\xb5\xba\xe7\xcc\xae B\xefx\xe6{U\xf7\xefA\x00\xc7|\xdbu\xcfc\x01$\xa9\xa2P\xa7\x84\xa5\xae\x180')
    # when transmitting prepend amac to crypt

    bcipher = pysodium.crypto_box(btoa_txb, nonce, apubkey, bprikey)
    assert bcipher == bmac + bcrypt

    btoa_rxb = pysodium.crypto_box_open_detached(bcrypt, bmac, nonce, bpubkey,
                                                 aprikey)
    btoa_rx = btoa_rxb.decode("utf-8")
    assert btoa_rx == btoa_tx
    assert btoa_rxb == btoa_txb

    btoa_rxb = pysodium.crypto_box_open(bcipher, nonce, bpubkey, aprikey)
    btoa_rx = btoa_rxb.decode("utf-8")
    assert btoa_rx == btoa_tx
    assert btoa_rxb == btoa_txb

    # compute shared key
    asymkey = pysodium.crypto_box_beforenm(bpubkey, aprikey)
    bsymkey = pysodium.crypto_box_beforenm(apubkey, bprikey)
    assert asymkey == bsymkey

    acipher = pysodium.crypto_box_afternm(atob_txb, nonce, asymkey)
    atob_rxb = pysodium.crypto_box_open_afternm(acipher, nonce, bsymkey)
    assert atob_rxb == atob_txb

    bcipher = pysodium.crypto_box_afternm(btoa_txb, nonce, bsymkey)
    btoa_rxb = pysodium.crypto_box_open_afternm(bcipher, nonce, asymkey)
    assert btoa_rxb == btoa_txb

    # crypto_box_seal public key encryption with X25519 keys
    #  uses same X25519 type of keys as crypto_box authenticated encryption
    #  so when converting sign key Ed25519 to X25519 can use for both types of encryption

    pubkey, prikey = pysodium.crypto_box_keypair()
    assert len(pubkey) == 32 == pysodium.crypto_box_PUBLICKEYBYTES
    assert len(prikey) == 32 == pysodium.crypto_box_SECRETKEYBYTES

    assert 48 == pysodium.crypto_box_SEALBYTES

    msg_txb = "Catch me if you can.".encode("utf-8")
    assert msg_txb == b'Catch me if you can.'
    cipher = pysodium.crypto_box_seal(msg_txb, pubkey)
    assert len(cipher) == 48 + len(msg_txb)

    msg_rxb = pysodium.crypto_box_seal_open(cipher, pubkey, prikey)
    assert msg_rxb == msg_txb

    #  convert Ed25519 key pair to X25519 key pair
    #  https://blog.filippo.io/using-ed25519-keys-for-encryption/
    #  https://libsodium.gitbook.io/doc/advanced/ed25519-curve25519
    #  crypto_sign_ed25519_pk_to_curve25519
    #  crypto_sign_ed25519_sk_to_curve25519

    pubkey = pysodium.crypto_sign_pk_to_box_pk(verkey)
    assert len(pubkey) == pysodium.crypto_box_PUBLICKEYBYTES

    prikey = pysodium.crypto_sign_sk_to_box_sk(sigkey)
    assert len(prikey) == pysodium.crypto_box_SECRETKEYBYTES

    repubkey = pysodium.crypto_scalarmult_curve25519_base(prikey)
    assert repubkey == pubkey

    msg_txb = "Encoded using X25519 key converted from Ed25519 key".encode(
        "utf-8")
    cipher = pysodium.crypto_box_seal(msg_txb, pubkey)
    assert len(cipher) == 48 + len(msg_txb)

    msg_rxb = pysodium.crypto_box_seal_open(cipher, pubkey, prikey)
    assert msg_rxb == msg_txb
    """
Beispiel #14
0
 def test_crypto_box_seal(self):
     if not pysodium.sodium_version_check(1, 0, 3): return
     pk, sk = pysodium.crypto_box_keypair()
     c = pysodium.crypto_box_seal(b"howdy", pk)
     self.assertEqual(pysodium.crypto_box_seal_open(c, pk, sk), b'howdy')
Beispiel #15
0
    def decrypt_msg(msg):
        team_pk, team_sk = team['crypt_pk'], TeamSecrets['crypt_sk']

        # TODO Check if that's the better approach
        # reference: https://download.libsodium.org/doc/public-key_cryptography/sealed_boxes.html
        return pysodium.crypto_box_seal_open(msg, team_pk, team_sk)
Beispiel #16
0
 def test_crypto_box_seal(self):
     pk, sk = pysodium.crypto_box_keypair()
     c = pysodium.crypto_box_seal(b"howdy", pk)
     self.assertEqual(pysodium.crypto_box_seal_open(c, pk, sk), b'howdy')