std::shared_ptr<Tox_Pass_Key> Core::createPasskey(const QString& password, uint8_t* salt) { std::shared_ptr<Tox_Pass_Key> encryptionKey(tox_pass_key_new(), tox_pass_key_free); CString str(password); if (salt) tox_pass_key_derive_with_salt(encryptionKey.get(), str.data(), str.size(), salt, nullptr); else tox_pass_key_derive(encryptionKey.get(), str.data(), str.size(), nullptr); return encryptionKey; }
QString ClientConfiguration::toBackup(QString const& password) const { QByteArray encryptionKey(BACKUP_ENCRYPTION_KEY_BYTES, 0x00); // Generate a Salt QByteArray salt(BACKUP_SALT_BYTES, 0x00); randombytes_buf(salt.data(), BACKUP_SALT_BYTES); // Convert the password into bytes QByteArray password8Bit = password.toUtf8(); // Generate the encryption key for the Backup from the Salt and the Password PKCS5_PBKDF2_HMAC(reinterpret_cast<unsigned char*>(password8Bit.data()), password8Bit.size(), reinterpret_cast<unsigned char*>(salt.data()), BACKUP_SALT_BYTES, BACKUP_KEY_PBKDF_ITERATIONS, BACKUP_ENCRYPTION_KEY_BYTES, reinterpret_cast<unsigned char*>(encryptionKey.data())); QByteArray nonceBytes(crypto_stream_NONCEBYTES, 0x00); // The backup content QByteArray clientId(IdentityHelper::uint64ToIdentityString(getClientIdentity().getContactId()).toLatin1()); if (clientId.size() != BACKUP_IDENTITY_BYTES) { throw InternalErrorException() << QString("Could not build backup - invalid client identity length (%1 vs. %2 Bytes).").arg(clientId.size()).arg(BACKUP_IDENTITY_BYTES).toStdString(); } QByteArray clientSecKey(getClientLongTermKeyPair().getPrivateKey()); if (clientSecKey.size() != PROTO_KEY_LENGTH_BYTES) { throw InternalErrorException() << QString("Could not build backup - invalid client secret key length (%1 vs. %2 Bytes).").arg(clientSecKey.size()).arg(PROTO_KEY_LENGTH_BYTES).toStdString(); } QByteArray backup(salt); backup.append(clientId); backup.append(clientSecKey); // Compute Hash QByteArray controlHash(crypto_hash_sha256_BYTES, 0x00); crypto_hash_sha256(reinterpret_cast<unsigned char*>(controlHash.data()), reinterpret_cast<unsigned char*>(backup.data() + BACKUP_SALT_BYTES), BACKUP_IDENTITY_BYTES + PROTO_KEY_LENGTH_BYTES); backup.append(controlHash.left(BACKUP_HASH_BYTES)); if (backup.size() != (BACKUP_SALT_BYTES + BACKUP_IDENTITY_BYTES + PROTO_KEY_LENGTH_BYTES + BACKUP_HASH_BYTES)) { throw InternalErrorException() << QString("Could not build backup - invalid packet length (%1 vs. %2 Bytes).").arg(clientSecKey.size()).arg(BACKUP_SALT_BYTES + BACKUP_IDENTITY_BYTES + PROTO_KEY_LENGTH_BYTES + BACKUP_HASH_BYTES).toStdString(); } // The Backup is build from SALT + IDENTITY + KEY + HASH crypto_stream_xor(reinterpret_cast<unsigned char*>(backup.data() + BACKUP_SALT_BYTES), reinterpret_cast<unsigned char*>(backup.data() + BACKUP_SALT_BYTES), BACKUP_IDENTITY_BYTES + PROTO_KEY_LENGTH_BYTES + BACKUP_HASH_BYTES, reinterpret_cast<unsigned char*>(nonceBytes.data()), reinterpret_cast<unsigned char*>(encryptionKey.data())); // Encode in Base32 return Base32::encodeBase32Sequence(backup); }