Quiero hacer algún tipo de archivo de almacenamiento. Quiero almacenar archivos cifrados en una tabla MySQL, y la clave para cifrarlos y descifrarlos nunca se almacena, sino que solo la conoce el usuario (ese es el objetivo, de todos modos).
El usuario debe iniciar sesión para ver una lista de sus archivos. Luego, para ver un archivo, el usuario debe ingresar una clave para descifrar un archivo para leerlo. Entonces, asumiendo que la cuenta de un usuario fue hackeada y se descubrió su contraseña, quiero que el pirata informático aún no pueda descifrar los archivos, ya que el pirata informático no conoce la clave utilizada para cifrarla.
¿Cuáles son los agujeros más grandes en esto? Por favor, ayúdame a mejorarlo en lugar de decir "esto es terrible". Sé que la seguridad de esto depende de otro código que no puse aquí. Acabo de intentar poner las partes más relevantes.
Aquí hay un código del controlador para agregar un nuevo archivo:
public function addFile($request, $response) {
$user = Security::getUser();
if (!$user) { $this->denyAccess('add-file'); }
$unencrypted_content = $request->getParam('content');
$key = $request->getParam('key');
if (Security::authenticate($user->username, $key)) {
$this->flash->addMessage('error', 'You can not use your password as the key to your files.');
return $this->redirect('new-file');
}
$otherFile = $user->files()->first();
if ($otherFile && !Crypt::decrypt($otherFile->content, $key, $otherFile->iv)) {
$this->flash->addMessage('error', 'The key you entered failed to decrypt another one of your files. You must always use the same key.');
return $this->redirect('new-file');
}
$iv = Crypt::iv();
$encrypted_content = Crypt::encrypt($unencrypted_content, $key, $iv);
$file = new File;
$file->owner()->associate($user);
$file->name = $request->getParam('name');
$file->content = $encrypted_content;
$file->iv = $iv;
$file->save();
return $this->redirect('all-files');
}
Aquí está la clase Crypt:
public static function iv() {
$letters = 'abcdefghijklmnopqrstuvwxyz0123456789';
$iv = '';
for ($i = 0; $i < 16; $i++) {
$iv .= substr($letters, rand(0, 35), 1);
}
return $iv;
}
public static function encrypt($content, $key, $iv) {
return openssl_encrypt($content, 'aes-256-cbc', $key, 0, $iv);
}
public static function decrypt($content, $key, $iv) {
return openssl_decrypt($content, 'aes-256-cbc', $key, 0, $iv);
}
Y otra vez en el controlador para ver un archivo:
public function viewFile($request, $response) {
$csrf_name = $request->getAttribute('csrf_name');
$csrf_value = $request->getAttribute('csrf_value');
$file = File::find($request->getAttribute('id'));
if ($file->owner->id !== Security::getUser()->id) { $this->denyAccess('view-file/' . $file->id); }
$key = $request->getParam('key');
$decrypted_content = Crypt::decrypt($file->content, $key, $file->iv);
if (!$decrypted_content) {
$this->flash->addMessage('error', 'The key you entered is not valid.');
return $this->redirect('authorize', ['id' => $file->id]);
}
$file->content = $decrypted_content;
$file->key = $key;
return $this->render($response, 'file/view.html.twig', compact('file', 'csrf_value', 'csrf_name'));
}