Is it safe to exchange cryptographic salt and initialization vector in messages? I have a client which does the following:

salt = randomBytes(16)
iv = randomBytes(16)

// secret is a user-specified passphrase
key = pbkdf2(secret, salt)

message[0] = salt.toHex() + iv.toHex()
message[1..n] = encrypt('message content', key, iv)

// to notify server that message stream is ended
message[n+1] = end_message 


I'm wondering if it is safe to send both salt and iv to the server like this?

The server does:

if(count == 0) {
  salt = message[count][0..15].toBytes()
  iv = message[count][16..31].toBytes()
  count++
  return
}

if(message[count] === end_message) {
  log(output)
  count = 0
  output = ''
  return
}

// for every subsequent message until end_message
key = pbkdf2(secret, salt)
output += decrypt(message[count++], key, iv)


AES-256-CTR is the encryption used.
The answer is yes. There is no problem with sending the IV in the clear. So, this is fine. Likewise, the salt is not there to add entropy so this is also fine.

Having said that, I understand from the code that the application is not using a uniformly distributed (and so high entropy) key. This is a problem and very bad, since it is easy to carry out a brute-force search over the password space. In practice, this is extremely effective.

The salt helps a little bit since it makes it impossible to prepare a time/space tradeoff attack (often called a Rainbow table attack, since this is one instance of the attack). However, it still will not be secure unless a very high entropy key is used.

Another thing which is very strange (and a bit out of scope so I'll refer to it anyway) is that the server is regenerating the key for every block. This is really inefficient (both the key derivation costs and the key schedule for AES is run every time).