libsodium no PHP 7.2

Quem sou eu?

O que é criptografia?

é a prática e o estudo de técnicas para comunicação segura na presença de terceiros
é a construção e análise de protocolos que previnam terceiros de ler mensagens privadas

Tipos de criptografia

Simétrica

  • Utiliza uma mesma chave para criptografar e descriptografar os textos
public function encrypt($data) {
    $iv = openssl_random_pseudo_bytes(
        openssl_cipher_iv_length('aes-256-ctr')
    );

    return base64_encode(
        $iv . openssl_encrypt(
            $data, 'aes-256-ctr', '@rw97`b#1,EquJ[L2P2',
            OPENSSL_RAW_DATA, $iv
        )
    );
}
public function decrypt($data) {
    $data = base64_decode($data);
    $ivSize = openssl_cipher_iv_length('aes-256-ctr');
    $iv = substr($data, 0, $ivSize);
    $data = substr($data, $ivSize);

    return openssl_decrypt(
        $data, 'aes-256-ctr', '@rw97`b#1,EquJ[L2P2',
        OPENSSL_RAW_DATA, $iv
    );
}

Assimétrica

  • Chave pública: utilizada para criptografar (escrever)
  • Chave privada: utilizada para descriptografar (ler)
public function encrypt($data, $publicKey) {
    $public = openssl_get_publickey($publicKey);
    openssl_public_encrypt($data, $crypted, $public);
    return $crypted;
}
public function decrypt($data, $privateKey, $passphrase) {
    $key = openssl_pkey_get_private($privateKey, $passphrase);
    openssl_private_decrypt($data, $decrypted, $key);
    return $decrypted;
}

Tenho certeza que ao invés de omitir o parâmetro $padding nos códigos anteriores, todos usam OPENSSL_PKCS1_OAEP_PADDING, certo?

Afinal, é claro que o parâmetro default (OPENSSL_PKCS1_PADDING) utiliza o padrão PKCS#1 v1.5, que é vulnerável a Padding attacks.

E sabemos que o algoritmo RSA com uma chave de 2048 bits só consegue processar dados de até 214 bytes.

Hashing

é uma função que mapeia dados de tamanho arbitrário para dados de tamanho fixo

Mas eu já sei usar hash!

if (hash('sha512', $_POST['password']) !== $senhaDoBanco) {
    throw new InvalidCredentialsException('Senha não confere!');
}

E você sabe o que é Timing Attack?

ataque que explora operações que não possuem tempo constante

libsodium

Encrypt

// Lê a chave
$key = trim(file_get_contents('02-encrypt.key'));

// Gera um nonce
$nonce = random_bytes(SODIUM_CRYPTO_SECRETBOX_NONCEBYTES);

// Prefixa o nonce aos dados para poder ser recuperado pelo decrypt
$ciphertext = sodium_bin2hex(
    $nonce . sodium_crypto_secretbox($plaintext, $nonce, $key)
);
// 7641ab3d68fedf4c52cc026aa1dcf611575a5843058483d281efa95b1577eddc6cb4ee37f5a8d8413e7ba6cd50

Decrypt

$ciphertext = sodium_hex2bin($ciphertext);

// Lê a chave
$key = trim(file_get_contents('02-encrypt.key'));

// Separa o nonce do texto
$nonce = substr($ciphertext, 0, SODIUM_CRYPTO_SECRETBOX_NONCEBYTES);
$ciphertext = substr($ciphertext, SODIUM_CRYPTO_SECRETBOX_NONCEBYTES);

// Descriptografa
$plaintext = sodium_crypto_secretbox_open($ciphertext, $nonce, $key);

Assinatura

esquema matemático para demonstrar a autenticidade de uma mensagem

Assinatura

// Lê a chave
$key = trim(file_get_contents('03-auth.key'));

// Gera a assinatura para o $ciphertext
$auth = sodium_bin2hex(sodium_crypto_auth($ciphertext, $key));

Assinatura - Validando

$auth = sodium_hex2bin($auth);

// Lê a chave
$key = trim(file_get_contents('03-auth.key'));

// Verifica a assinatura
return sodium_crypto_auth_verify($auth, $ciphertext, $key);

Crypto Box

// Servidor 1 - Alice
$aliceKeyPair = sodium_crypto_box_keypair();
$alicePublic = sodium_crypto_box_publickey($aliceKeyPair);
$aliceSecret = sodium_crypto_box_secretkey($aliceKeyPair);

// Servidor 2 - Bob
$bobKeyPair = sodium_crypto_box_keypair();
$bobPublic = sodium_crypto_box_publickey($bobKeyPair);
$bobSecret = sodium_crypto_box_secretkey($bobKeyPair);

Crypto Box - Alice

$nonce = random_bytes(SODIUM_CRYPTO_BOX_NONCEBYTES);

$key = sodium_crypto_box_keypair_from_secretkey_and_publickey(
    $aliceSecret, $bobPublic
);

$encrypted = sodium_crypto_box($message, $nonce, $key);
$ciphertext = $nonce . $encrypted;

Crypto Box - Bob

$nonce = substr($ciphertext, 0, SODIUM_CRYPTO_BOX_NONCEBYTES);
$ciphertext = substr($ciphertext, SODIUM_CRYPTO_BOX_NONCEBYTES);

$key = sodium_crypto_box_keypair_from_secretkey_and_publickey(
    $bobSecret, $alicePublic
);
echo sodium_crypto_box_open($encrypted, $nonce, $key);

Persistindo senhas

sodium_crypto_pwhash_str(
    $password,
    SODIUM_CRYPTO_PWHASH_OPSLIMIT_INTERACTIVE,
    SODIUM_CRYPTO_PWHASH_MEMLIMIT_INTERACTIVE
);
// $argon2id$v=19$m=65536,t=2,p=1$20H8uU9EFq7GO2NFPrfDyg$Om/qimxzk9/7mub1s7bVEz/UbbIyikxBIrMlxZKPc/c

Validando senhas

sodium_crypto_pwhash_str_verify(
    $storedPassword,
    $inputPassword
);

Obrigado!