def __exit__(self, exc_type, exc_val, exc_tb): """ Re-encrypt. """ # Derive the key from the passphrase. derived = util.derive_passphrase(self.passphrase) # Generate two random nonces. nonce1 = random(SecretBox.NONCE_SIZE) nonce2 = random(SecretBox.NONCE_SIZE) sign_box = SecretBox(derived) enc_box = SecretBox(derived) s_p = self.sign.encode() e_p = self.encrypt.encode() s_e = sign_box.encrypt(s_p, nonce1) e_e = enc_box.encrypt(e_p, nonce2) # Update `self.key`. self.key._private_key_raw = e_e.ciphertext self.key._private_signing_key_raw = s_e.ciphertext # Bit of a mixed up name. self.key._private_nonce = e_e.nonce self.key._private_signing_nonce = s_e.nonce if exc_type is not None: raise exc_type(exc_val)
def randrange(n): a = (n.bit_length() + 7) // 8 # number of bytes to store n b = 8 * a - n.bit_length() # number of shifts to have good bit number r = int.from_bytes(random(a), byteorder='big') >> b while r >= n: r = int.from_bytes(random(a), byteorder='big') >> b return r
def keystore_seal(private_key, password, address, name=""): # password salt = nacl_utils.random(argon2id.SALTBYTES) mem = argon2id.MEMLIMIT_MODERATE ops = argon2id.OPSLIMIT_MODERATE key = argon2id.kdf(secret.SecretBox.KEY_SIZE, password.encode(), salt, opslimit=ops, memlimit=mem) # ciphertext box = secret.SecretBox(key) nonce = nacl_utils.random(secret.SecretBox.NONCE_SIZE) sk = private_key.encode(encoder=RawEncoder) + private_key.verify_key.encode(encoder=RawEncoder) ciphertext = box.encrypt(sk, nonce=nonce).ciphertext # build the keystore k = { "public_key": address, "crypto": { "secret_type": "ed25519", "symmetric_alg": "xsalsa20-poly1305", "ciphertext": bytes.hex(ciphertext), "cipher_params": { "nonce": bytes.hex(nonce) }, "kdf": "argon2id", "kdf_params": { "memlimit_kib": round(mem / 1024), "opslimit": ops, "salt": bytes.hex(salt), "parallelism": 1 # pynacl 1.3.0 doesnt support this parameter } }, "id": str(uuid.uuid4()), "name": name, "version": 1 } return k
def keystore_seal(secret_key, password, name="", secret_type=SECRET_TYPE_SLIP0010): """ Seal a keystore :param secret_key: the secret key to store in the keystore :param password: the keystore password :param name: the optional name of the keystore :param secret_type: type of the secret to store (default: ed25519-slip0010-masterkey) """ # password salt = nacl_utils.random(argon2id.SALTBYTES) mem = argon2id.MEMLIMIT_MODERATE ops = argon2id.OPSLIMIT_MODERATE key = argon2id.kdf(secret.SecretBox.KEY_SIZE, password.encode(), salt, opslimit=ops, memlimit=mem) # ciphertext box = secret.SecretBox(key) nonce = nacl_utils.random(secret.SecretBox.NONCE_SIZE) if isinstance(secret_key, SigningKey): sk = secret_key.encode() + secret_key.verify_key.encode() else: sk = secret_key.encode('utf-8') ciphertext = box.encrypt(sk, nonce=nonce).ciphertext # build the keystore k = { "crypto": { "secret_type": secret_type, "symmetric_alg": "xsalsa20-poly1305", "ciphertext": bytes.hex(ciphertext), "cipher_params": { "nonce": bytes.hex(nonce) }, "kdf": "argon2id", "kdf_params": { "memlimit_kib": round(mem / 1024), "opslimit": ops, "salt": bytes.hex(salt), "parallelism": 1 # pynacl 1.3.0 doesn't support this parameter } }, "id": str(uuid.uuid4()), "name": name, "version": 1 } return k
def create_default(cls, enable_auth_key=False): """ Create default settings for encryption key derivation from password. original source: https://pynacl.readthedocs.io/en/stable/password_hashing/#key-derivation :param bool enable_auth_key: generate a key for full data signatures via HMAC :rtype: DerivedKeySetup """ return cls(ops=pwhash.argon2i.OPSLIMIT_SENSITIVE, mem=pwhash.argon2i.MEMLIMIT_SENSITIVE, construct='argon2i', salt_key_enc=utils.random(pwhash.argon2i.SALTBYTES), salt_key_sig=utils.random(pwhash.argon2i.SALTBYTES) if enable_auth_key else b'', key_size_enc=secret.SecretBox.KEY_SIZE, key_size_sig=64 if enable_auth_key else 0)
def encode(self, is_originating, uri, args=None, kwargs=None): """ Encrypt the given WAMP URI, args and kwargs into an EncodedPayload instance, or None if the URI should not be encrypted. """ assert (type(is_originating) == bool) assert (type(uri) == six.text_type) assert (args is None or type(args) in (list, tuple)) assert (kwargs is None or type(kwargs) == dict) box = self._get_box(is_originating, uri) if not box: # if we didn't find a crypto box, then return None, which # signals that the payload travel unencrypted (normal) return None payload = {u'uri': uri, u'args': args, u'kwargs': kwargs} nonce = random(Box.NONCE_SIZE) payload_ser = _json_dumps(payload).encode('utf8') payload_encr = box.encrypt(payload_ser, nonce, encoder=RawEncoder) # above returns an instance of http://pynacl.readthedocs.io/en/latest/utils/#nacl.utils.EncryptedMessage # which is a bytes _subclass_! hence we apply bytes() to get at the underlying plain # bytes "scalar", which is the concatenation of `payload_encr.nonce + payload_encr.ciphertext` payload_bytes = bytes(payload_encr) payload_key = None return EncodedPayload(payload_bytes, u'cryptobox', u'json', enc_key=payload_key)
def _encrypt_data(self, key, data): assert isinstance(key, type(b"")), type(key) assert isinstance(data, type(b"")), type(data) assert len(key) == SecretBox.KEY_SIZE, len(key) box = SecretBox(key) nonce = utils.random(SecretBox.NONCE_SIZE) return box.encrypt(data, nonce)
def encrypt(self, is_originator, uri, args=None, kwargs=None): """ Encrypt the given WAMP URI, args and kwargs into an EncryptedPayload instance, or None if the URI should not be encrypted. """ assert (type(uri) == six.text_type) assert (type(is_originator) == bool) assert (args is None or type(args) in (list, tuple)) assert (kwargs is None or type(kwargs) == dict) box = self._get_box(is_originator, uri) if not box: return payload = {u'uri': uri, u'args': args, u'kwargs': kwargs} nonce = random(Box.NONCE_SIZE) payload_ser = json.dumps(payload) payload_encr = box.encrypt(payload_ser, nonce, encoder=Base64Encoder) payload_bytes = payload_encr.encode().decode('ascii') payload_key = None return EncryptedPayload(u'cryptobox', payload_key, u'json', payload_bytes)
def step4_api2(): hkdf_salt = random(32) nodeid = do_priv("get_nodeid") to_server_key = get_subkey("to_server", hkdf_salt) ciphertext = SecretBox(to_server_key).encrypt(nodeid.encode()) try: with socket.socket(socket.AF_INET6, socket.SOCK_STREAM) as s: s.settimeout(5) s.connect((bootstrap_ipv6, 1337)) assert(len(hkdf_salt) < 256) s.sendall(len(hkdf_salt).to_bytes(1, byteorder='big') + hkdf_salt) assert(len(ciphertext) < 256) s.sendall(len(ciphertext).to_bytes(1, byteorder='big') + ciphertext) num_bytes = int.from_bytes(s.recv(1), byteorder='big') resp=b'' while len(resp) < num_bytes: resp += s.recv(num_bytes - len(resp)) except (OSError, socket.timeout): abort(404, "Not found") from_server_key = get_subkey("from_server", hkdf_salt) global network_id network_id = SecretBox(from_server_key).decrypt(resp).decode() #XXX Do we need to leave networks with overlapping IP space? Better to warn? do_priv("leaveall private") do_priv("join %s" % network_id) return "ok"
def test_encrypt_key_with_path_tuple(self): key = random(32) path = b'/foo/bar' enc_keys = self.client.encrypt_key(key, path=path) self.assertEqual(3, len(enc_keys)) self.assertTrue(key not in enc_keys)
def test_build_header_prealpha(self): enc_keys = [random(148), random(148), random(148)] version = 100 header, length = self.client._build_header(enc_keys, version=version) self.assertEqual(len(header), length) try: msgpack.loads(header) except Exception as E: self.fail("Failed to unpack header:\n{}".format(E)) self.assertIn((3).to_bytes(4, byteorder='big'), header) for key in enc_keys: self.assertIn(key, header) self.assertIn(version.to_bytes(4, byteorder='big'), header)
def encrypt(self, plaintext, nonce=None, encoder=encoding.RawEncoder): """ Encrypts the plaintext message using the given `nonce` (or generates one randomly if omitted) and returns the ciphertext encoded with the encoder. .. warning:: It is **VITALLY** important that the nonce is a nonce, i.e. it is a number used only once for any given key. If you fail to do this, you compromise the privacy of the messages encrypted. :param plaintext: [:class:`bytes`] The plaintext message to encrypt :param nonce: [:class:`bytes`] The nonce to use in the encryption :param encoder: The encoder to use to encode the ciphertext :rtype: [:class:`nacl.utils.EncryptedMessage`] """ if nonce is None: nonce = random(self.NONCE_SIZE) if len(nonce) != self.NONCE_SIZE: raise ValueError("The nonce must be exactly %s bytes long" % self.NONCE_SIZE) ciphertext = nacl.bindings.crypto_box_afternm(plaintext, nonce, self._shared_key) encoded_nonce = encoder.encode(nonce) encoded_ciphertext = encoder.encode(ciphertext) return EncryptedMessage._from_parts(encoded_nonce, encoded_ciphertext, encoder.encode(nonce + ciphertext))
def pwashtest(): password = b"password" message = b"This is a message for Bob's eyes only" kdf = pwhash.argon2i.kdf salt = b'\xa3\x95\\\xec\x1cFpr8\xb7\x92\x7f\x18%)\x88' ops = pwhash.argon2i.OPSLIMIT_SENSITIVE mem = pwhash.argon2i.MEMLIMIT_SENSITIVE Alices_key = kdf(secret.SecretBox.KEY_SIZE, password, salt, opslimit=ops, memlimit=mem) Alices_box = secret.SecretBox(Alices_key) nonce = utils.random(secret.SecretBox.NONCE_SIZE) print(salt) encrypted = Alices_box.encrypt(message, nonce) # now Alice must send to Bob both the encrypted message # and the KDF parameters: salt, opslimit and memlimit; # using the same kdf mechanism, parameters **and password** # Bob is able to derive the correct key to decrypt the message Bobs_key = kdf(secret.SecretBox.KEY_SIZE, password, salt, opslimit=ops, memlimit=mem) Bobs_box = secret.SecretBox(Bobs_key) received = Bobs_box.decrypt(encrypted) print(received.decode('utf-8'))
def encrypt(self, plaintext, nonce=None, aad=None, encoder=RawEncoder): """ Encrypts the plaintext message using the given `nonce` (or generates one randomly if omitted) and returns the ciphertext encoded with the encoder. .. warning:: It is **VITALLY** important that the nonce is a nonce, i.e. it is a number used only once for any given key. If you fail to do this, you compromise the privacy of the messages encrypted. Give your nonces a different prefix, or have one side use an odd counter and one an even counter. Just make sure they are different. :param plaintext: [:class:`bytes`] The plaintext message to encrypt :param nonce: [:class:`bytes`] The nonce to use in the encryption :param encoder: The encoder to use to encode the ciphertext :rtype: [:class:`nacl.utils.EncryptedMessage`] """ if nonce is None: nonce = random(self.NONCE_SIZE) exc.ensure( isinstance(plaintext, bytes) or isinstance(plaintext, bytearray), "Plaintext type must be bytes or bytearray", raising=exc.TypeError, ) ciphertext = nacl.bindings.crypto_aead_xchacha20poly1305_ietf_encrypt( plaintext if isinstance(plaintext, bytes) else bytes(plaintext), aad, nonce, self._key ) encoded_nonce = encoder.encode(nonce) encoded_ciphertext = encoder.encode(ciphertext) return EncryptedMessage._from_parts( encoded_nonce, encoded_ciphertext, encoder.encode(nonce + ciphertext) )
def _encrypt_data(self, key, data): assert isinstance(key, type(b"")), type(key) assert isinstance(data, type(b"")), type(data) if len(key) != SecretBox.KEY_SIZE: raise UsageError box = SecretBox(key) nonce = utils.random(SecretBox.NONCE_SIZE) return box.encrypt(data, nonce)
def send(): # event is passed by binders. msg = my_msg.get() my_msg.set("") # Clears input field. r = post('http://127.0.0.1:5000/qkuser/A', json={"receiver": "B"}) print(r.json()) data = r.json() print("Symmetric key retrieved for B: " + data['status']) qkey = data['status'] nonce = utils.random(secret.SecretBox.NONCE_SIZE) print("Nonce") print(nonce) print("Message") print(msg) ctext = cipher.encrypt(msg, qkey, nonce) print("Ciphertext") print(ctext) print("Qkey") print(qkey) texttosend = str(ctext) + "###" + base64.encodebytes(nonce).decode("utf-8") client_socket.send(bytes(texttosend, "utf8")) if msg == "{quit}": client_socket.close() top.quit()
def setUpClass(cls): cls.public_ip = '123.45.67.89' cls.port = 12345 cls.own_addr = (cls.public_ip, cls.port) cls.addr1 = ('132.54.76.98', 54321) cls.addr2 = ('231.76.45.89', 15243) cls.privkey1_hex = '71d1054068b224a4d9013104881dc7f46c6fec9a618f4574ae21059723e6c4f8' cls.privkey1 = public.PrivateKey(cls.privkey1_hex, encoder=encoding.HexEncoder) cls.pubkey1 = cls.privkey1.public_key cls.pubkey1_bytes = cls.pubkey1.encode(encoder=encoding.RawEncoder) cls.privkey2_hex = '4c107b7844368d0fb608f3d91ae194f2d62c7ff91b713e5b05c279e8b7fc61b3' cls.privkey2 = public.PrivateKey(cls.privkey2_hex, encoder=encoding.HexEncoder) cls.pubkey2 = cls.privkey2.public_key cls.pubkey2_bytes = cls.pubkey2.encode(encoder=encoding.RawEncoder) cls.remote_crypto_box = public.Box(cls.privkey2, cls.pubkey1) cls.nonce = utils.random(cls.remote_crypto_box.NONCE_SIZE) cls.local_crypto_box = public.Box(cls.privkey1, cls.pubkey2) cls.privkey3_hex = '40246691a4362a220606dd302b03e992b5b5fe21026377fa56c9fe3f5afbcbd0' cls.privkey3 = public.PrivateKey(cls.privkey3_hex, encoder=encoding.HexEncoder) cls.pubkey3 = cls.privkey3.public_key cls.pubkey3_bytes = cls.pubkey3.encode(encoder=encoding.RawEncoder) cls.other_crypto_box = public.Box(cls.privkey3, cls.pubkey1)
def __init__(self, cfg: Config, password: str) -> None: self.l = DBLogger(self, cfg) kdf = pwhash.argon2i.kdf salt = utils.random(pwhash.argon2i.SALTBYTES) ops = pwhash.argon2i.OPSLIMIT_SENSITIVE mem = pwhash.argon2i.MEMLIMIT_SENSITIVE self.l.info( "Deriving wallet encryption key, might take a couple seconds") self.key = kdf(secret.SecretBox.KEY_SIZE, password, salt, opslimit=ops, memlimit=mem) self.box = secret.SecretBox(Alices_key) self._uxto_storage = SqliteUXTOStorage(cfg) self._chain = BlockChain( SqliteBlockChainStorage(cfg), SqliteTransactionStorage(cfg), self._uxto_storage, cfg) self._conn = sqlite3.connect(cfg.wallet_path()) self._conn.execute(CREATE_TABLE_SQL) self._conn.commit()
def generate_key(self, password, salt): # generate key that will be used to encrypt inner box userKey = utils.random(secret.SecretBox.KEY_SIZE) # generate key that will be used to encrypt outer box key = pwhash.kdf_scryptsalsa208sha256( secret.SecretBox.KEY_SIZE, password, salt, opslimit=pwhash.SCRYPT_OPSLIMIT_INTERACTIVE, memlimit=pwhash.SCRYPT_MEMLIMIT_INTERACTIVE) nonce = utils.random(secret.SecretBox.NONCE_SIZE) box = secret.SecretBox(key) encrypted = box.encrypt(userKey, nonce) return encrypted
def encrypt_data(key, plaintext): assert isinstance(key, type(b"")), type(key) assert isinstance(plaintext, type(b"")), type(plaintext) assert len(key) == SecretBox.KEY_SIZE, len(key) box = SecretBox(key) nonce = utils.random(SecretBox.NONCE_SIZE) return box.encrypt(plaintext, nonce)
def generate(cls): """ Generates a random :class:`~nacl.public.PrivateKey` object :rtype: :class:`~nacl.public.PrivateKey` """ return cls(random(PrivateKey.SIZE), encoder=encoding.RawEncoder)
def encrypt(file, privkey, recipients): # ignores privkey and recipients for now key = random(SecretBox.KEY_SIZE) box = SecretBox(key) enc = box.encrypt(file.encode("utf-8")) jsondata = json.dumps({"version":"0.1","key":base64.b64encode(key).decode("utf-8")}) return jsondata.encode("utf-8")+_separator+enc
def create_keys(self, location): # create the server key and stores in a local file. server_key = utils.random(secret.SecretBox.KEY_SIZE) with open(location, "a") as f: f.write("SECRET=") f.write(base64.encodebytes(server_key).decode('ascii')) return server_key
async def make_box(self, secret_key: bytes = None) -> Tuple[SecretBox, bytes]: if not secret_key: # If a secret key isn't provided then create a random one secret_key = random(self.secret_size) # Return a tuple with the instance of SecretBox and the secret key itself return SecretBox(secret_key), secret_key
def test_when_encrypting_with_a_key_the_decrypter_works_when_using_the_shared_key( self): nonce = random(SecretBox.NONCE_SIZE) shared_key = random(SecretBox.KEY_SIZE) box = SecretBox(shared_key) plaintext = 'The ship has arrived at the port' encrypted_msg = box.encrypt(bytes(plaintext, 'utf-8'), nonce) nonce_str = b64encode(encrypted_msg.nonce).decode("utf-8") encrypted_msg_str = b64encode(encrypted_msg.ciphertext).decode("utf-8") message = f'{nonce_str}:{encrypted_msg_str}' decrypter = util.create_decrypter(shared_key) decrypted_text = decrypter(message) self.assertNotEqual(plaintext, encrypted_msg.ciphertext) self.assertEqual(plaintext, decrypted_text)
def encrypt(self, plaintext, nonce=None, encoder=encoding.RawEncoder): """ Encrypts the plaintext message using the given `nonce` (or generates one randomly if omitted) and returns the ciphertext encoded with the encoder. .. warning:: It is **VITALLY** important that the nonce is a nonce, i.e. it is a number used only once for any given key. If you fail to do this, you compromise the privacy of the messages encrypted. Give your nonces a different prefix, or have one side use an odd counter and one an even counter. Just make sure they are different. :param plaintext: [:class:`bytes`] The plaintext message to encrypt :param nonce: [:class:`bytes`] The nonce to use in the encryption :param encoder: The encoder to use to encode the ciphertext :rtype: [:class:`nacl.utils.EncryptedMessage`] """ if nonce is None: nonce = random(self.NONCE_SIZE) if len(nonce) != self.NONCE_SIZE: raise exc.ValueError( "The nonce must be exactly %s bytes long" % self.NONCE_SIZE, ) ciphertext = nacl.bindings.crypto_secretbox(plaintext, nonce, self._key) encoded_nonce = encoder.encode(nonce) encoded_ciphertext = encoder.encode(ciphertext) return EncryptedMessage._from_parts( encoded_nonce, encoded_ciphertext, encoder.encode(nonce + ciphertext), )
def encrypt(self, is_originator, uri, args=None, kwargs=None): """ Encrypt the given WAMP URI, args and kwargs into an EncryptedPayload instance, or None if the URI should not be encrypted. """ assert(type(uri) == six.text_type) assert(type(is_originator) == bool) assert(args is None or type(args) in (list, tuple)) assert(kwargs is None or type(kwargs) == dict) box = self._get_box(is_originator, uri) if not box: return payload = { u'uri': uri, u'args': args, u'kwargs': kwargs } nonce = random(Box.NONCE_SIZE) payload_ser = json.dumps(payload) payload_encr = box.encrypt(payload_ser, nonce, encoder=Base64Encoder) payload_bytes = payload_encr.encode().decode('ascii') payload_key = None return EncryptedPayload(u'cryptobox', payload_key, u'json', payload_bytes)
def store(secret): while True: try: # Again, mkdir is an atomic operation on POSIX file systems. # Two concurrent requests cannot store data into the same # directory. sid = generate_sid() mkdir(join(DATA, sid)) break except FileExistsError: continue key_bytes = random(SecretBox.KEY_SIZE) box = SecretBox(key_bytes) with open(join(DATA, sid, 'secret'), 'wb') as fp: fp.write(box.encrypt(secret.encode('UTF-8'))) # Turn key into base64 and remove padding, because it has the # potential of confusing users. ("Is this part of the URL?") key = str(b64encode(key_bytes), 'ASCII') key = key.replace('/', '_') key = key.rstrip('=') return sid, key
def encode(self, is_originating, uri, args=None, kwargs=None): """ Encrypt the given WAMP URI, args and kwargs into an EncodedPayload instance, or None if the URI should not be encrypted. """ assert(type(is_originating) == bool) assert(type(uri) == six.text_type) assert(args is None or type(args) in (list, tuple)) assert(kwargs is None or type(kwargs) == dict) box = self._get_box(is_originating, uri) if not box: # if we didn't find a crypto box, then return None, which # signals that the payload travel unencrypted (normal) return None payload = { u'uri': uri, u'args': args, u'kwargs': kwargs } nonce = random(Box.NONCE_SIZE) payload_ser = _json_dumps(payload).encode('utf8') payload_encr = box.encrypt(payload_ser, nonce, encoder=RawEncoder) # above returns an instance of http://pynacl.readthedocs.io/en/latest/utils/#nacl.utils.EncryptedMessage # which is a bytes _subclass_! hence we apply bytes() to get at the underlying plain # bytes "scalar", which is the concatenation of `payload_encr.nonce + payload_encr.ciphertext` payload_bytes = bytes(payload_encr) payload_key = None return EncodedPayload(payload_bytes, u'cryptobox', u'json', enc_key=payload_key)
def test_decrypt_key_no_path(self): key = random(32) enc_key = self.client.encrypt_key(key) self.assertNotEqual(key, enc_key) dec_key = self.client.decrypt_key(enc_key) self.assertEqual(key, dec_key)
def newKey(self): """Generate a new encryption key. Returns: (str): encryption key """ key = random(SecretBox.KEY_SIZE) return binascii.hexlify(key).decode("utf-8")
def encrypt_payload(self, symKey, payload): # payload = payload.encode() nonce = utils.random(secret.SecretBox.NONCE_SIZE) box = secret.SecretBox(symKey) encrypted = box.encrypt(payload, nonce) return encrypted
def setUpClass(self): self.my_app.db = MotorClient(**MONGODB_HOST)[MONGODB_DBNAME] self.my_app.executor = ThreadPoolExecutor(WORKERS) self.my_app.whitelist = WHITELIST self.my_app.hmac_key = random(size=APP_SECRETKEY_SIZE)
def test_when_encrypting_with_a_key_the_decrypter_fails_when_not_using_the_shared_key( self): nonce = random(SecretBox.NONCE_SIZE) shared_key = random(SecretBox.KEY_SIZE) box = SecretBox(shared_key) plaintext = b'The ship has arrived at the port' encrypted_msg = box.encrypt(plaintext, nonce) nonce_str = b64encode(encrypted_msg.nonce).decode("utf-8") encrypted_msg_str = b64encode(encrypted_msg.ciphertext).decode("utf-8") message = f'{nonce_str}:{encrypted_msg_str}' incorrect_key = random(SecretBox.KEY_SIZE) decrypter = util.create_decrypter(incorrect_key) with self.assertRaises(Exception): decrypter(message) self.assertNotEqual(plaintext, encrypted_msg.ciphertext)
def create_key(self, key_id=None): key = random(SecretBox.KEY_SIZE) if not key_id: h = sha256(key, HexEncoder) key_id = h.decode('utf-8')[:16] self.keys[key_id] = key log_debug("Key {} was created.".format(key_id)) self.save_key(key_id) return key_id
def _encrypt(self, plaintext): plaintext = plaintext.encode('utf-8') nonce = random(SecretBox.NONCE_SIZE) encrypted = self.box.encrypt(plaintext, nonce) ciphertext = encrypted.ciphertext return dict( salt=self.salt.encode('hex'), iterations=self.iterations, nonce=nonce.encode('hex'), ciphertext=ciphertext.encode('hex') )
def generate(cls): """ Generates a random :class:`~nacl.signing.SigningKey` object. :rtype: :class:`~nacl.signing.SigningKey` """ return cls( random(nacl.bindings.crypto_sign_SEEDBYTES), encoder=encoding.RawEncoder, )
def dumps(self, session_state): """Encrypt session state. :type session_state: :class:`dict` / picklable mapping :param session_state: the session state to be encrypted. :rtype: bytes :returns: the encrypted session state """ pickled = pickle.dumps(session_state) nonce = random(SecretBox.NONCE_SIZE) return urlsafe_b64encode(self.box.encrypt(pickled, nonce))
def dumps(self, session_state): """Encrypt session state. :type session_state: :class:`dict` / picklable mapping :param session_state: the session state to be encrypted. :rtype: bytes :returns: the encrypted session state """ cstruct = self.serializer.dumps(session_state) nonce = random(SecretBox.NONCE_SIZE) fstruct = self.box.encrypt(cstruct, nonce) return urlsafe_b64encode(fstruct).rstrip(b'=')
def _encrypt_data(self, key, data): # Without predefined roles, we can't derive predictably unique keys # for each side, so we use the same key for both. We use random # nonces to keep the messages distinct, and we automatically ignore # reflections. # TODO: HKDF(side, nonce, key) ?? include 'side' to prevent # reflections, since we no longer compare messages assert isinstance(key, type(b"")), type(key) assert isinstance(data, type(b"")), type(data) assert len(key) == SecretBox.KEY_SIZE, len(key) box = SecretBox(key) nonce = utils.random(SecretBox.NONCE_SIZE) return box.encrypt(data, nonce)
def __init__(self, passphrase, salt=None, iterations=None): passphrase = passphrase.encode('utf-8') if salt is None: salt = random(16) iterations = self.ITERATIONS else: salt = salt.decode('hex') key = PBKDF2(passphrase, salt, 32, iterations) self.salt = salt self.iterations = iterations self.box = SecretBox(key)
def generate_secret(as_hex=True): """Generate a random, 32-byte secret. :type as_hex: boolean :param as_hex: If true, convert the secret to hex. :rtype: bytes :returns: the secret (perhaps converted to hex). """ secret = random(SecretBox.KEY_SIZE) if as_hex: secret = binascii.hexlify(secret) return secret
def _gen_equivalent_raw_keys_couple(self): rwk1 = bytearray(random(crypto_box_SECRETKEYBYTES)) rwk2 = bytearray(rwk1) # mask rwk1 bits rwk1[0] &= 248 rwk1[31] &= 127 rwk1[31] |= 64 # set rwk2 bits rwk2[0] |= 7 rwk2[31] |= 128 rwk2[31] &= 191 sk1 = PrivateKey(bytes(rwk1)) sk2 = PrivateKey(bytes(rwk2)) return sk1, sk2
def __init__(self, passphrase, salt=None, iterations=None): warn(("CoinOp no longer uses libsodium - you should only see this " "message in migration utilities."), DeprecationWarning) passphrase = passphrase.encode('utf-8') if salt is None: salt = random(16) iterations = self.ITERATIONS else: salt = salt.decode('hex') key = PBKDF2(passphrase, salt, 32, iterations) self.salt = salt self.iterations = iterations self.box = SecretBox(key)
def __init__( self, proto, handler, own_addr, dest_addr, relay_addr=None, private_key=None ): """ Create a new connection and register it with the protocol. Args: proto: Handler to underlying protocol. handler: Upstream recipient of received messages and handler of other events. Should minimally implement `receive_message` and `handle_shutdown`. own_addr: Tuple of local host address (ip, port). dest_addr: Tuple of remote host address (ip, port). relay_addr: Tuple of relay host address (ip, port). private_key: A private key for Curve25519, as a hex-encoded public.PrivateKey. The instance will automatically generate a new such key if one is not provided. If a relay address is specified, all outgoing packets are sent to that adddress, but the packets contain the address of their final destination. This is used for routing. """ super(CryptoConnection, self).__init__( proto, handler, own_addr, dest_addr, relay_addr ) if private_key is None: self._private_key = public.PrivateKey.generate() else: self._private_key = public.PrivateKey( private_key, encoder=encoding.HexEncoder ) self._public_key = self._private_key.public_key self._crypto_box = None self._remote_public_key = None self._left_nonce_bytes = utils.random(public.Box.NONCE_SIZE // 2)
def encrypt(value, signingPrivateKey, realPublicKey): """encrypt and sign a value, and base64-encode the result :param value: a secret :type value: string :param signingPrivateKey: base64 encoded NaCl private key :type signingPrivateKey: string :param realPublicKey: base64 encoded NaCl private key :type realPublicKey: string :rtype: string """ signingPrivateKey = npublic.PrivateKey(base64.decodestring(signingPrivateKey)) realPublicKey = npublic.PublicKey(base64.decodestring(realPublicKey)) box = npublic.Box(signingPrivateKey, realPublicKey) nonce = nutils.random(npublic.Box.NONCE_SIZE) encrypted = box.encrypt(value, nonce) encoded = base64.encodestring(encrypted) oneline = "".join(encoded.splitlines()) return oneline
def setUpClass(cls): cls.public_ip = '123.45.67.89' cls.port = 12345 cls.own_addr = (cls.public_ip, cls.port) cls.addr1 = ('132.54.76.98', 54321) cls.addr2 = ('231.76.45.89', 15243) cls.privkey1_hex = '71d1054068b224a4d9013104881dc7f46c6fec9a618f4574ae21059723e6c4f8' cls.privkey1 = public.PrivateKey( cls.privkey1_hex, encoder=encoding.HexEncoder ) cls.pubkey1 = cls.privkey1.public_key cls.pubkey1_bytes = cls.pubkey1.encode(encoder=encoding.RawEncoder) cls.privkey2_hex = '4c107b7844368d0fb608f3d91ae194f2d62c7ff91b713e5b05c279e8b7fc61b3' cls.privkey2 = public.PrivateKey( cls.privkey2_hex, encoder=encoding.HexEncoder ) cls.pubkey2 = cls.privkey2.public_key cls.pubkey2_bytes = cls.pubkey2.encode(encoder=encoding.RawEncoder) cls.remote_crypto_box = public.Box(cls.privkey2, cls.pubkey1) cls.nonce = utils.random(cls.remote_crypto_box.NONCE_SIZE) cls.local_crypto_box = public.Box(cls.privkey1, cls.pubkey2) cls.privkey3_hex = '40246691a4362a220606dd302b03e992b5b5fe21026377fa56c9fe3f5afbcbd0' cls.privkey3 = public.PrivateKey( cls.privkey3_hex, encoder=encoding.HexEncoder ) cls.pubkey3 = cls.privkey3.public_key cls.pubkey3_bytes = cls.pubkey3.encode(encoder=encoding.RawEncoder) cls.other_crypto_box = public.Box(cls.privkey3, cls.pubkey1)
def keypair(cls): pri = random(cls.PRIVATE_KEY_SIZE) pub = cls.public_key(pri) return pri, pub
def _encrypt_data(self, key, data): assert len(key) == SecretBox.KEY_SIZE box = SecretBox(key) nonce = utils.random(SecretBox.NONCE_SIZE) return box.encrypt(data, nonce)
def generate(cls): return cls(random(PrivateKey.SIZE), encoder=encoding.RawEncoder)
def generate(cls, email: str, name: str, passphrase: str) -> typing.Tuple['Key', 'Key']: """ Generate a new public/private key pair. This handles encipherment of the private keys. :param email: The email for the initial User ID. :param name: The name for the initial User ID. :param passphrase: The passphrase to encrypt the private key with. :return: A tuple containing a public and a private key. """ privatekey = public.PrivateKey.generate() publickey = privatekey.public_key assert isinstance(privatekey, public.PrivateKey) assert isinstance(publickey, public.PublicKey) pub, priv = publickey.encode(), privatekey.encode() # Generate the signing key seed. seed = random(32) # Create the signing private key, temporary usage to extract the verify key. s_privatekey = signing.SigningKey(seed) s_publickey = s_privatekey.verify_key s_pub = s_publickey.encode() # Encrypt both private keys. key = derive_passphrase(passphrase.encode()) # Use a random nonce, for now. nonce1 = random(SecretBox.NONCE_SIZE) nonce2 = random(SecretBox.NONCE_SIZE) # Encrypt both. sbox1 = SecretBox(key) sbox2 = SecretBox(key) priv = sbox1.encrypt(priv, nonce1) # Don't encrypt the s_privatekey; encrypt the seed. s_priv = sbox2.encrypt(seed, nonce2) # Create a pair of Keys. public_key = Key(public_key=pub, public_signing_key=s_pub) private_key = Key(private_key=priv.ciphertext, private_signing_seed=s_priv.ciphertext, private_nonce=priv.nonce, private_signing_nonce=s_priv.nonce) del privatekey, priv, s_privatekey, s_priv # Force a GC collect. gc.collect() # Create the requested User ID. u = UserID(0, email, name) # We only add the user ID to the public key. public_key.userid = u # Generate the self-signature. to_hash = u.get_hash() # Sign the message using the private key. signature = private_key.sign_raw(passphrase, to_hash) public_key.self_signature = signature verified = public_key.verify_self_signature() if not verified: raise exc.BadSignature("The self-signature was invalid.") return public_key, private_key
def init(server, username, keydir, action, message, recipients): """ SHSM CLI client. """ global serverurl serverurl = server if action == "register": master_signing_key = SigningKey.generate() device_signing_key = SigningKey.generate() device_private_key = PrivateKey.generate() enc_master_verify_key = master_signing_key.verify_key.encode(encoder=HexEncoder) register(username, enc_master_verify_key) # TODO: make sure keydir exists save_key(master_signing_key.encode(encoder=HexEncoder), keydir + "/master_signing_key") save_key(device_signing_key.encode(encoder=HexEncoder), keydir + "/device_signing_key") save_key(device_private_key.encode(encoder=HexEncoder), keydir + "/device_private_key") else: try: master_signing_key = SigningKey(load_key(keydir + "/master_signing_key"), encoder=HexEncoder) device_signing_key = SigningKey(load_key(keydir + "/device_signing_key"), encoder=HexEncoder) device_private_key = PrivateKey(load_key(keydir + "/device_private_key"), encoder=HexEncoder) except TypeError: print "bad key, exiting." exit() if action == "add-device": enc_device_verify_key = device_signing_key.verify_key.encode(encoder=HexEncoder) enc_signed_device_verify_key = b64encode(master_signing_key.sign(enc_device_verify_key)) enc_device_public_key = device_private_key.public_key.encode(encoder=HexEncoder) enc_signed_device_public_key = b64encode(master_signing_key.sign(enc_device_public_key)) add_device(username, enc_signed_device_verify_key, enc_signed_device_public_key) if action == "send-message": ephemeral_key = PrivateKey.generate() enc_ephemeral_public_key = b64encode( device_signing_key.sign(ephemeral_key.public_key.encode(encoder=HexEncoder)) ) # TODO:: should sign binary text, no? b"bob" destination_usernames = recipients.split(",") enc_dest_usernames = b64encode( device_signing_key.sign(json.dumps({"destination_usernames": destination_usernames})) ) symmetric_key = random(SecretBox.KEY_SIZE) symmetric_box = SecretBox(symmetric_key) nonce = random(SecretBox.NONCE_SIZE) msg_manifest = {} msg_manifest["recipients"] = {} msg_manifest["msg"] = b64encode(symmetric_box.encrypt(str(message), nonce)) for dest_user in destination_usernames: msg_manifest["recipients"][dest_user] = {} for recipient_key in get_recipient_keys( device_signing_key.verify_key.encode(encoder=HexEncoder), b64encode(device_signing_key.sign(str(dest_user))), ): # TODO:: should sign binary text, no? crypt_box = Box(ephemeral_key, recipient_key) nonce = random(Box.NONCE_SIZE) crypt_key = b64encode(crypt_box.encrypt(symmetric_key, nonce)) dest_key = recipient_key.encode(encoder=HexEncoder) msg_manifest["recipients"][dest_user][dest_key] = crypt_key enc_signed_crypt_msg = b64encode(device_signing_key.sign(json.dumps(msg_manifest))) send_message( device_signing_key.verify_key.encode(encoder=HexEncoder), enc_dest_usernames, enc_signed_crypt_msg, enc_ephemeral_public_key, ) if action == "get-messages": enc_device_verify_key = device_signing_key.verify_key.encode(encoder=HexEncoder) enc_signed_device_verify_key = b64encode(device_signing_key.sign(enc_device_verify_key)) messages = get_messages(enc_device_verify_key, enc_signed_device_verify_key) for message_public_key in messages["messages"].keys(): try: crypto_box = Box(device_private_key, PublicKey(b64decode(message_public_key), encoder=HexEncoder)) except TypeError: print "not a valid public key" exit() packed_msg = json.loads(messages["messages"][message_public_key]) msg_manifest = json.loads(b64decode(packed_msg["message_manifest"])) dest_pub_key = device_private_key.public_key.encode(encoder=HexEncoder) symmetric_key = crypto_box.decrypt(b64decode(msg_manifest["recipients"][username][dest_pub_key])) symmetric_box = SecretBox(symmetric_key) print ("From: %s\nMessage: %s") % ( packed_msg["reply_to"], symmetric_box.decrypt(b64decode(msg_manifest["msg"])), )
def get_fake_key(self): return random(SecretBox.KEY_SIZE)
def test_generate_private_key_from_random_seed(): PrivateKey.from_seed(random(PrivateKey.SEED_SIZE))
def test_sk_and_pk_hashes_are_different(self): sk = PrivateKey(random(crypto_box_SECRETKEYBYTES)) assert hash(sk) != hash(sk.public_key)
def create_node(name): secret = random(32) # FIXME: set blockchain/network correctly tree = bip32.Wallet.from_master_secret(secret, netcode='XTN') return tree