Encriptar clave

This commit is contained in:
Juan Pablo Vial
2024-03-13 21:24:52 -03:00
parent 8caa80459e
commit 57f9169cc7
4 changed files with 106 additions and 21 deletions

View File

@ -0,0 +1,3 @@
@push('page_scripts')
<script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.2.0/crypto-js.min.js" integrity="sha512-a+SUDuwNzXDvz4XrIcXHuCf089/iJAoN4lmrXJg18XnduKK6YlDHNRalv4yd1N40OKI80tFidF+rqTFKGPoWFQ==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
@endpush

View File

@ -16,19 +16,24 @@
</div>
@endsection
@include('layout.body.scripts.cryptojs')
@push('page_scripts')
<script type="text/javascript">
function encryptPassword(password) {
const passphrase = Math.floor(Math.random() * Date.now()).toString()
const encrypted = CryptoJS.AES.encrypt(password, passphrase)
return [passphrase, encrypted.toString()].join('')
}
function sendLogin(name, password) {
const data = new FormData()
data.append('name', name)
data.append('password', password)
return fetch('{{$urls->base}}/login', {
method: 'post',
headers: {
Accept: 'json'
},
body: data
}).then(response => {
const method = 'post'
const headers = {
Accept: 'json'
}
const body = new FormData()
body.append('name', name)
body.append('password', encryptPassword(password))
return fetch('{{$urls->base}}/login', {method, headers, body}).then(response => {
if (response.ok) {
return response.json()
}

View File

@ -1,14 +1,16 @@
<?php
namespace Incoviba\Controller;
use Incoviba\Common\Implement\Exception\EmptyResult;
use PDOException;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Incoviba\Common\Alias\View;
use Incoviba\Common\Ideal\Controller;
use Incoviba\Repository;
use Incoviba\Service;
class Login
class Login extends Controller
{
public function form(ServerRequestInterface $request, ResponseInterface $response, View $view, Service\Login $service): ResponseInterface
{
@ -20,14 +22,17 @@ class Login
public function login(ServerRequestInterface $request, ResponseInterface $response, Repository\User $userRepository, Service\Login $service): ResponseInterface
{
$body = $request->getParsedBody();
$user = $userRepository->fetchByName($body['name']);
$output = [
'name' => $user->name,
'name' => $body['name'],
'login' => false
];
if ($user->validate($body['password'])) {
$output['login'] = $service->login($user);
}
try {
$user = $userRepository->fetchByName($body['name']);
if ($service->validateUser($user, $body['password'])) {
$output['login'] = $service->login($user);
}
} catch (EmptyResult) {}
$response->getBody()->write(json_encode($output));
return $response->withHeader('Content-Type', 'application/json');
}

View File

@ -47,7 +47,16 @@ class Login
}
return $login->user;
}
public function validateUser(Model\User $user, string $encryptedPassword): bool
{
list($passphrase, $encrypted) = $this->splitPassword($encryptedPassword);
try {
$password = $this->cryptoJs_aes_decrypt($encrypted, $passphrase);
} catch (Exception) {
return false;
}
return $user->validate($password);
}
public function login(Model\User $user): bool
{
try {
@ -104,9 +113,12 @@ class Login
setcookie(
$this->cookie_name,
implode($this->cookie_separator, [$selector, $token]),
$expires->getTimestamp(),
$this->path,
$this->domain
[
'expires' => $expires->getTimestamp(),
'path' => $this->path,
'domain' => $this->domain,
'samesite' => 'Strict'
]
);
$this->selector = $selector;
$this->token = $token;
@ -126,10 +138,70 @@ class Login
{
return password_verify($this->token, $login->token);
}
protected function generateToken(Model\Login $login)
protected function generateToken(Model\Login $login): array
{
$selector = bin2hex(random_bytes(12));
$token = bin2hex(random_bytes(20));
return ['selector' => $selector, 'token' => $token];
}
protected function splitPassword(string $input): array
{
$ini = strpos($input, 'U');
$passphrase = substr($input, 0, $ini);
$message = substr($input, $ini);
return [$passphrase, $message];
}
protected function cryptoJs_aes_decrypt($data, $key): string
{
$data = base64_decode($data);
if (substr($data, 0, 8) != "Salted__") {
return false;
}
$salt = substr($data, 8, 8);
$keyAndIV = $this->aes_evpKDF($key, $salt);
$decrypted = openssl_decrypt(
substr($data, 16),
"aes-256-cbc",
$keyAndIV["key"],
OPENSSL_RAW_DATA, // base64 was already decoded
$keyAndIV["iv"]
);
if ($decrypted === false) {
throw new Exception();
}
return $decrypted;
}
protected function aes_evpKDF($password, $salt, $keySize = 8, $ivSize = 4, $iterations = 1, $hashAlgorithm = "md5"): array
{
$targetKeySize = $keySize + $ivSize;
$derivedBytes = "";
$numberOfDerivedWords = 0;
$block = NULL;
$hasher = hash_init($hashAlgorithm);
while ($numberOfDerivedWords < $targetKeySize) {
if ($block != NULL) {
hash_update($hasher, $block);
}
hash_update($hasher, $password);
hash_update($hasher, $salt);
$block = hash_final($hasher, TRUE);
$hasher = hash_init($hashAlgorithm);
// Iterations
for ($i = 1; $i < $iterations; $i++) {
hash_update($hasher, $block);
$block = hash_final($hasher, TRUE);
$hasher = hash_init($hashAlgorithm);
}
$derivedBytes .= substr($block, 0, min(strlen($block), ($targetKeySize - $numberOfDerivedWords) * 4));
$numberOfDerivedWords += strlen($block) / 4;
}
return array(
"key" => substr($derivedBytes, 0, $keySize * 4),
"iv" => substr($derivedBytes, $keySize * 4, $ivSize * 4)
);
}
}