def crypto_initiate(self, cookiepacket) -> bytes: """ Validate the cookie packet and create the corresponding initate packet consisting of: * 8 bytes: the ASCII bytes "oqQN2kaI". * 96 bytes: the server's cookie. * 8 bytes: a client-selected compressed nonce in little-endian form. This compressed nonce is implicitly prefixed by "splonebox-client" to form a 24-byte nonce. * 144 bytes: a cryptographic box encrypted and authenticated to the server's short-term public key S' from the client's short-term public key C' using this 24-byte nonce. The (96+M)-byte plaintext inside the box has the following contents: * 32 bytes: the client's long-term public key C. * 16 bytes: a client-selected compressed nonce in little-endian form. This compressed nonce is implicitly prefixed by "splonePV" to form a 24-byte nonce. * 80 bytes: a cryptographic box encrypted and authenticated to the server's long-term public key S from the client's long-term public key C using this 24-byte nonce. The 32-byte plaintext inside the box has the following contents: * 32 bytes: the client's short-term public key C'. * 32 bytes: server's short term public key S' cookiepacket -- the cookie packet sent by server :return: client initiate packet """ cookie = self._verify_cookiepacket(cookiepacket) vouch_payload = b"".join( [self.clientshorttermpk, self.servershorttermpk]) vouch_nonce = self.safenonce() vouch_nonce_expanded = struct.pack("<8s16s", b"splonePV", vouch_nonce) vouch_box = libnacl.crypto_box(vouch_payload, vouch_nonce_expanded, self.serverlongtermpk, self.clientlongtermsk) payload = b"".join([self.clientlongtermpk, vouch_nonce, vouch_box]) self.crypto_nonce_update() payload_nonce = struct.pack("<16sQ", b"splonebox-client", self.nonce) payload_box = libnacl.crypto_box(payload, payload_nonce, self.servershorttermpk, self.clientshorttermsk) identifier = struct.pack("<8s", b"oqQN2kaI") nonce = struct.pack("<Q", self.nonce) initiatepacket = b"".join([identifier, cookie, nonce, payload_box]) self.crypto_established.set() return initiatepacket
def test_040_verify_cookiepacket(self): """ Check whether cookie is properly extraced. """ identifier = struct.pack("<8s", b"rZQTd2nC") nonce = libnacl.randombytes(16) nonce_expanded = struct.pack("<8s16s", b"splonePK", nonce) cookie = libnacl.randombytes(96) payload = b''.join([self.servershorttermpk, cookie]) box = libnacl.crypto_box(payload, nonce_expanded, self.crypt.clientshorttermpk, self.serverlongtermsk) # good case data = b''.join([identifier, nonce, box]) cookie_extracted = self.crypt._verify_cookiepacket(data) self.assertEqual(cookie, cookie_extracted) # too short self.assertRaises(InvalidPacketException, self.crypt._verify_cookiepacket, data[:167]) # message has illegal identifier data = b''.join([struct.pack("<8s", b'foobar'), nonce, box]) self.assertRaises(InvalidPacketException, self.crypt._verify_cookiepacket, data) # manipulated payload data = b''.join([identifier, nonce, libnacl.randombytes(len(box))]) self.assertRaises(InvalidPacketException, self.crypt._verify_cookiepacket, data)
def crypto_hello(self) -> bytes: """Create a client tunnel packet consisting of: * 8 bytes: the ASCII bytes "oqQN2kaH" * 32 bytes: client's short-term public key C' * 64 bytes: all zero * 8 bytes: a client-selected compressed nonce in little-endian form. This compressed nonce is implicitly prefixed by "splonebox-client" to form a 24-byte nonce * 80 bytes: a cryptographic box encrypted and authenticated to the server's long-term public key S from the client's short-term public key C' using this 24-byte nonce. The 64-byte plaintext inside the box has the following contents: * 64 bytes: all zero :return: client hello packet """ self.crypto_nonce_update() identifier = struct.pack("<8s", b"oqQN2kaH") nonce = struct.pack("<16sQ", b"splonebox-client-H", self.nonce) zeros = bytearray(64) self.clientshorttermpk, \ self.clientshorttermsk = libnacl.crypto_box_keypair() box = libnacl.crypto_box(zeros, nonce, self.serverlongtermpk, self.clientshorttermsk) nonce = struct.pack("<Q", self.nonce) return b"".join( [identifier, self.clientshorttermpk, zeros, nonce, box])
def confirm(request, addr, publicKey, password): her_public = b64decode(request['pk'][0]) response = { 'credentials': { ('%s:%s' % addr): { 'publicKey': publicKey, 'password': password } } } response = json.dumps(response) my_public, my_private = libnacl.crypto_box_keypair() nonce = libnacl.utils.rand_nonce() encrypted = b64encode( libnacl.crypto_box(response, nonce, her_public, my_private)) offer = { 'type': 'credentials', 'interface': 'udp', 'message': encrypted, 'n': b64encode(nonce), 'pk': b64encode(my_public), 'wrbtVersion': WRBT_VERSION } return PREFIX + '#' + urlencode(offer)
def crypto_write(self, data: bytes) -> bytes: """Create a client message packet consisting of: * 8 bytes: the ASCII bytes "oqQN2kaM" * 8 bytes: a client-selected compressed nonce in little-endian form. This compressed nonce is implicitly prefixed by "splonebox-server" to form a 24-byte nonce. * 24 bytes: a cryptographic box encrypted and authenticated to the client's short-term public key C' from the server's short-term public key S' using this 24-byte nonce. The M-byte plaintext inside the box has the following contents: * 8 bytes: length * n bytes: a cryptographic box encrypted and authenticated to the client's short-term public key C' from the server's short-term public key S' using this 24-byte nonce. The plaintext inside the box has the following contents: * m bytes: data NOTE: This function NOT thread safe. The nonce needs to be updated for every individual message AFTER it was sent. :return: client message packet :raises: :CryptError on failure """ self.crypto_nonce_update() message_nonce = struct.pack("<Q", self.nonce) length = struct.pack("<Q", 56 + len(data)) length_nonce = struct.pack("<16sQ", b"splonebox-client", self.nonce) length_boxed = libnacl.crypto_box(length, length_nonce, self.servershorttermpk, self.clientshorttermsk) self.crypto_nonce_update() identifier = struct.pack("<8s", b"oqQN2kaM") data_nonce = struct.pack("<16sQ", b"splonebox-client", self.nonce) box = libnacl.crypto_box(data, data_nonce, self.servershorttermpk, self.clientshorttermsk) return b"".join([identifier, message_nonce, length_boxed, box])
def test_box(self): msg = b'Are you suggesting coconuts migrate?' # run 1 nonce1 = libnacl.utils.rand_nonce() pk1, sk1 = libnacl.crypto_box_keypair() pk2, sk2 = libnacl.crypto_box_keypair() enc_msg = libnacl.crypto_box(msg, nonce1, pk2, sk1) self.assertNotEqual(msg, enc_msg) clear_msg = libnacl.crypto_box_open(enc_msg, nonce1, pk1, sk2) self.assertEqual(clear_msg, msg) # run 2 nonce2 = libnacl.utils.rand_nonce() pk3, sk3 = libnacl.crypto_box_keypair() pk4, sk4 = libnacl.crypto_box_keypair() enc_msg2 = libnacl.crypto_box(msg, nonce2, pk4, sk3) self.assertNotEqual(msg, enc_msg2) clear_msg2 = libnacl.crypto_box_open(enc_msg2, nonce2, pk3, sk4) self.assertEqual(clear_msg2, msg) # Check bits self.assertNotEqual(nonce1, nonce2) self.assertNotEqual(enc_msg, enc_msg2)
def encrypt_to(self, message, recipients): """Encrypt a secret message to ``recipients`` using our private key.""" nonce = os.urandom(24) key = os.urandom(32) secret = dict( sender=json_bytes(self.publicKey), nonce=json_bytes(nonce), secret=json_bytes(libnacl.crypto_secretbox(message, nonce, key)), keys={}, ) print recipients for pub in recipients: box = libnacl.crypto_box(key, nonce, pub, self.privateKey) secret['keys'][json_bytes(pub)] = json_bytes(box) return secret
def _encryptQuery(self, queryContent, resolverCert, nonce, tcp=False): header = resolverCert.clientMagic + self._publicKey + nonce requiredSize = len(header) + self.DNSCRYPT_MAC_SIZE + len(queryContent) paddingSize = self.DNSCRYPT_PADDED_BLOCK_SIZE - (len(queryContent) % self.DNSCRYPT_PADDED_BLOCK_SIZE) # padding size should be DNSCRYPT_PADDED_BLOCK_SIZE <= padding size <= 4096 if not tcp and requiredSize < self.DNSCRYPT_MIN_UDP_LENGTH: paddingSize += self.DNSCRYPT_MIN_UDP_LENGTH - requiredSize requiredSize = self.DNSCRYPT_MIN_UDP_LENGTH padding = '\x80' idx = 0 while idx < (paddingSize - 1): padding = padding + '\x00' idx += 1 data = queryContent + padding nonce = nonce + ('\x00'*(self.DNSCRYPT_NONCE_SIZE / 2)) box = libnacl.crypto_box(data, nonce, resolverCert.publicKey, self._privateKey) return header + box
def _encryptQuery(self, queryContent, resolverCert, nonce): header = resolverCert.clientMagic + self._publicKey + nonce requiredSize = len(header) + self.DNSCRYPT_MAC_SIZE + len(queryContent) paddingSize = self.DNSCRYPT_PADDED_BLOCK_SIZE - (len(queryContent) % self.DNSCRYPT_PADDED_BLOCK_SIZE) # padding size should be DNSCRYPT_PADDED_BLOCK_SIZE <= padding size <= 4096 if requiredSize < self.DNSCRYPT_MIN_UDP_LENGTH: paddingSize += self.DNSCRYPT_MIN_UDP_LENGTH - requiredSize requiredSize = self.DNSCRYPT_MIN_UDP_LENGTH padding = '\x80' idx = 0 while idx < (paddingSize - 1): padding = padding + '\x00' idx += 1 data = queryContent + padding nonce = nonce + ('\x00'*(self.DNSCRYPT_NONCE_SIZE / 2)) box = libnacl.crypto_box(data, nonce, resolverCert.publicKey, self._privateKey) return header + box
def test_080_crypto_read(self): """ Verifying that crypto_read properly handles message packets. """ nonce_length = 6 data = libnacl.randombytes(10) nonce_expanded = struct.pack("<16sQ", b"splonebox-server", nonce_length + 2) box = libnacl.crypto_box(data, nonce_expanded, self.crypt.clientshorttermpk, self.servershorttermsk) self.crypt.crypto_verify_length = mock.Mock(return_value=40 + len(box)) self.crypt._verify_nonce = mock.Mock() packet = b''.join([ bytearray(8), struct.pack("<Q", nonce_length), bytearray(24), box ]) payload = self.crypt.crypto_read(packet) self.assertEqual(payload, data) # corrupt box packet = b''.join([ bytearray(8), struct.pack("<Q", nonce_length), bytearray(24), libnacl.randombytes(len(box)) ]) self.assertRaises(InvalidPacketException, self.crypt.crypto_read, packet) # corrupt nonce packet = b''.join( [bytearray(8), libnacl.randombytes(8), bytearray(24), box]) self.assertRaises(InvalidPacketException, self.crypt.crypto_read, packet)
def test_030_verify_length(self): """ Verify whether length is properly extraced. """ payload = libnacl.randombytes(40) nonce = self.crypt.last_received_nonce + 2 nonce_length = struct.pack("<16sQ", b"splonebox-server", nonce) length = 40 + len(payload) packed_length = struct.pack("<Q", length) boxed_length = libnacl.crypto_box(packed_length, nonce_length, self.crypt.clientshorttermpk, self.servershorttermsk) identifier = struct.pack("<8s", b"rZQTd2nM") packed_nonce = struct.pack("<Q", nonce) data = b''.join([identifier, packed_nonce, boxed_length, payload]) # good case length_extracted = self.crypt.crypto_verify_length(data) self.assertEqual(length, length_extracted) # message too short to hold proper length information self.assertRaises(InvalidPacketException, self.crypt.crypto_verify_length, data[:39]) # message has illegal identifier data = b''.join([ struct.pack("<8s", b'foobar'), packed_nonce, boxed_length, payload ]) self.assertRaises(InvalidPacketException, self.crypt.crypto_verify_length, data) # length has been altered data = b''.join( [identifier, packed_nonce, libnacl.randombytes(32), payload]) self.assertRaises(InvalidPacketException, self.crypt.crypto_verify_length, data)
def pubkey_encrypt(self,data,nonce,pk,sk): return libnacl.crypto_box(data,nonce,pk,sk)
def pubkey_encrypt(self, data, nonce, pk, sk): return libnacl.crypto_box(data, nonce, pk, sk)
def test_crypto_init_functional(self): # generate hello packet data = self.crypt.crypto_hello() # extract key and generate cookie response extracted_key, = struct.unpack("<32s", data[8:40]) identifier = struct.pack("<8s", b"rZQTd2nC") nonce = libnacl.randombytes(16) nonce_expanded = struct.pack("<8s16s", b"splonePK", nonce) cookie = libnacl.randombytes(96) payload = b''.join([self.servershorttermpk, cookie]) box = libnacl.crypto_box(payload, nonce_expanded, extracted_key, self.serverlongtermsk) data = b''.join([identifier, nonce, box]) # generate initiate-packet from cookiepacket self.crypt.crypto_initiate(data) # test if the crypto is able to decrypt a server message identifier = struct.pack("<8s", b"rZQTd2nM") server_nonce = self.crypt.crypto_random_mod(281474976710656) server_nonce += 0 if server_nonce % 2 == 0 else 1 nonce_expanded = struct.pack("<16sQ", b"splonebox-server", server_nonce) payload = libnacl.randombytes(96) length = struct.pack("<Q", 56 + len(payload)) length_boxed = libnacl.crypto_box(length, nonce_expanded, extracted_key, self.servershorttermsk) server_nonce += 2 nonce_expanded = struct.pack("<16sQ", b"splonebox-server", server_nonce) box = libnacl.crypto_box(payload, nonce_expanded, extracted_key, self.servershorttermsk) msg = b"".join([identifier, struct.pack("<Q", server_nonce - 2), length_boxed, box]) extr = self.crypt.crypto_read(msg) self.assertEqual(extr, payload) # test if the crypto is able to encrypt a message properly payload = libnacl.randombytes(96) data = self.crypt.crypto_write(payload) identifier, = struct.unpack("<8s", data[:8]) nonce, = struct.unpack("<Q", data[8:16]) nonceexpanded = struct.pack("<16sQ", b"splonebox-client", nonce) length = libnacl.crypto_box_open(data[16:40], nonceexpanded, self.crypt.clientshorttermpk, self.servershorttermsk) nonceexpanded = struct.pack("<16sQ", b"splonebox-client", nonce+2) plaintext = libnacl.crypto_box_open(data[40:], nonceexpanded, self.crypt.clientshorttermpk, self.servershorttermsk) self.assertEqual(plaintext, payload)