Encriptar clave
This commit is contained in:
@ -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
|
@ -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()
|
||||
}
|
||||
|
@ -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');
|
||||
}
|
||||
|
@ -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)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user