JavaScript Python PHP
import * as __biblioteca0 from "hash-wasm";
import * as __biblioteca3 from "bcryptjs";
async function executar(values = { "left": "00", "right": "00", "mode": "direct", "format": "hex", "algorithm": "SHA-256" }) {
const encoder = new TextEncoder();
function toHex(bytes) { return [...bytes].map(byte => byte.toString(16).padStart(2, '0')).join(''); }
function toBase64(bytes) {
let binary = '';
for (let i = 0; i < bytes.length; i += 8192)
binary += String.fromCharCode(...bytes.subarray(i, i + 8192));
return btoa(binary);
}
function fromBase64(value) {
const clean = value.replace(/\s/g, '');
if (!/^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/.test(clean))
throw new Error('Base64 inválido. Confira caracteres e padding (=).');
const bytes = Uint8Array.from(atob(clean), c => c.charCodeAt(0));
if (toBase64(bytes) !== clean)
throw new Error('Base64 não canônico.');
return bytes;
}
function fromHex(value) {
if (!/^(?:[a-fA-F0-9]{2})+$/.test(value))
throw new Error('Hexadecimal inválido: use pares de caracteres, sem espaços.');
return Uint8Array.from(value.match(/../g), byte => parseInt(byte, 16));
}
function option(values, key, options, fallback) {
const value = values[key] ?? fallback;
if (!options.includes(value))
throw new Error(`Opção inválida: ${key}.`);
return value;
}
function required(values, key) {
if (!values[key])
throw new Error(`Preencha o campo ${key}.`);
return values[key];
}
async function digest(text, algorithm) {
if (algorithm === 'MD5') {
const { md5 } = await __biblioteca0;
return md5(encoder.encode(text));
}
if (!['SHA-1', 'SHA-256', 'SHA-512'].includes(algorithm))
throw new Error('Algoritmo de hash não suportado.');
return toHex(new Uint8Array(await crypto.subtle.digest(algorithm, encoder.encode(text))));
}
function compareBytes(left, right) {
let difference = left.length ^ right.length;
for (let i = 0; i < Math.max(left.length, right.length); i++)
difference |= (left[i] ?? 0) ^ (right[i] ?? 0);
return difference === 0;
}
async function runSecurityTool(kind, values) {
if (!crypto.subtle)
throw new Error('Esta ferramenta requer Web Crypto em HTTPS ou localhost.');
if (Object.values(values).some(value => value.length > 1000000))
throw new Error('Limite de entrada: 1 milhão de caracteres por campo.');
{
{
const mode = option(values, 'mode', ['direct', 'digest', 'bcrypt', 'argon2'], 'direct');
let valid;
if (mode === 'direct') {
const format = option(values, 'format', ['hex', 'base64'], 'hex');
const decode = format === 'hex' ? fromHex : fromBase64;
valid = compareBytes(decode(required(values, 'left').trim()), decode(required(values, 'right').trim()));
}
else if (mode === 'digest')
valid = compareBytes(fromHex(await digest(values.left ?? '', option(values, 'algorithm', ['MD5', 'SHA-1', 'SHA-256', 'SHA-512'], 'SHA-256'))), fromHex(required(values, 'right').trim()));
else if (mode === 'bcrypt') {
const hash = required(values, 'right').trim();
if (!/^\$2[aby]\$(0[4-9]|1[0-4])\$[./A-Za-z0-9]{53}$/.test(hash))
throw new Error('Hash bcrypt inválido ou custo acima do limite local (14).');
if (encoder.encode(values.left ?? '').length > 72)
throw new Error('A entrada excede 72 bytes UTF-8.');
const { compare } = await __biblioteca3;
valid = await compare(values.left ?? '', hash);
}
else {
const hash = required(values, 'right').trim();
const params = /^\$argon2id\$v=19\$m=(\d+),t=(\d+),p=(\d+)\$([A-Za-z0-9+/]+)\$([A-Za-z0-9+/]+)$/.exec(hash);
if (!params || Number(params[1]) < 8192 || Number(params[1]) > 131072 || Number(params[2]) < 1 || Number(params[2]) > 10 || Number(params[3]) < 1 || Number(params[3]) > 4 || params[4].length > 128 || params[5].length > 128)
throw new Error('Hash Argon2id inválido ou parâmetros fora dos limites locais.');
const { argon2Verify } = await __biblioteca0;
valid = await argon2Verify({ password: values.left ?? '', hash });
}
return { text: valid ? 'Os hashes correspondem.' : 'Os hashes não correspondem.', valid };
}
}
}
return await runSecurityTool("hash-compare", values);
}
import hashlib
import hmac
import base64
import re
def executar(values=None):
values = {'left': '00', 'right': '00', 'mode': 'direct', 'format': 'hex', 'algorithm': 'SHA-256'} if values is None else values
if not isinstance(values, dict) or any(not isinstance(v,str) or len(v.encode('utf-16-le',errors='surrogatepass')) // 2 > 1000000 for v in values.values()): raise ValueError('Informe campos textuais de até 1 milhão de caracteres')
def integer(key):
raw = values.get(key,'')
if not re.fullmatch(r'[0-9]+',raw): raise ValueError('Informe inteiro válido: ' + key)
return int(raw)
def process(left='00', right='00', mode='direct', algorithm='sha256', format='hex'):
if mode not in ('direct', 'digest') or format not in ('hex', 'base64'):
raise ValueError('Este exemplo suporta comparação direta e digest')
if mode == 'digest':
if algorithm not in ('md5', 'sha1', 'sha256', 'sha512'):
raise ValueError('Algoritmo inválido')
raw = hashlib.new(algorithm, left.encode('utf-8')).digest()
left = raw.hex() if format == 'hex' else base64.b64encode(raw).decode('ascii')
def decode(value):
return bytes.fromhex(value) if format == 'hex' else base64.b64decode(value, validate=True)
return hmac.compare_digest(decode(left), decode(right))
mode = values.get('mode','direct')
if mode in ('bcrypt','argon2'):
password, encoded = values.get('left',''), values.get('right','').strip()
if mode == 'bcrypt':
import bcrypt
if len(password.encode()) > 72 or not re.fullmatch(r'\$2[aby]\$(0[4-9]|1[0-4])\$[./A-Za-z0-9]{53}',encoded): raise ValueError('bcrypt fora dos limites')
valid = bcrypt.checkpw(password.encode(),encoded.encode())
else:
from argon2 import PasswordHasher
from argon2.exceptions import VerifyMismatchError
match = re.fullmatch(r'\$argon2id\$v=19\$m=([0-9]+),t=([0-9]+),p=([0-9]+)\$([A-Za-z0-9+/]+)\$([A-Za-z0-9+/]+)',encoded)
if not match or not 8192 <= int(match[1]) <= 131072 or not 1 <= int(match[2]) <= 10 or not 1 <= int(match[3]) <= 4 or len(match[4])>128 or len(match[5])>128: raise ValueError('Argon2id fora dos limites')
try: valid = PasswordHasher().verify(encoded,password)
except VerifyMismatchError: valid = False
else:
valid = process(left=values.get('left',''),right=values.get('right',''),mode=mode,algorithm=values.get('algorithm','SHA-256').lower().replace('-',''),format=values.get('format','hex'))
return {'text':'Os hashes correspondem.' if valid else 'Os hashes não correspondem.', 'valid':valid}
<?php
function executar($values = ['left'=>'00','right'=>'00','mode'=>'direct','format'=>'hex','algorithm'=>'SHA-256']) {
foreach ($values as $value) if (!is_string($value) || strlen($value)>1000000) throw new InvalidArgumentException("Informe campos textuais de até 1 milhão de bytes");
$integer = function ($key) use ($values) { $raw = $values[$key] ?? ""; if (!preg_match("/^[0-9]+$/D",$raw)) throw new InvalidArgumentException("Inteiro inválido: " . $key); return (int)$raw; };
$process = function ($left = '00', $right = '00', $mode = 'direct', $algorithm = 'sha256', $format = 'hex') {
if (!in_array($mode,['direct','digest'],true) || !in_array($format,['hex','base64'],true)) throw new InvalidArgumentException('Este exemplo suporta comparação direta e digest');
if ($mode === 'digest') {
if (!in_array($algorithm,['md5','sha1','sha256','sha512'],true)) throw new InvalidArgumentException('Algoritmo inválido');
$raw=hash($algorithm,$left,true); $left=$format === 'hex' ? bin2hex($raw) : base64_encode($raw);
}
$decode = function ($value) use ($format) {
if ($format === 'hex' && !preg_match('/^(?:[0-9a-f]{2})+$/iD',$value)) throw new InvalidArgumentException('Hex inválido');
$raw=$format === 'hex' ? hex2bin($value) : base64_decode($value,true);
if ($raw === false) throw new InvalidArgumentException('Hash inválido');
return $raw;
};
return hash_equals($decode($left),$decode($right));
};
$mode = $values['mode'] ?? 'direct';
if (in_array($mode,['bcrypt','argon2'],true)) {
$hash = trim($values['right'] ?? ''); $password = $values['left'] ?? '';
if ($mode === 'bcrypt' && (strlen($password)>72 || !preg_match('/^\$2[aby]\$(0[4-9]|1[0-4])\$[.\/A-Za-z0-9]{53}$/D',$hash))) throw new InvalidArgumentException('bcrypt fora dos limites');
if ($mode === 'argon2') {
if (!preg_match('/^\$argon2id\$v=19\$m=([0-9]+),t=([0-9]+),p=([0-9]+)\$([A-Za-z0-9+\/]+)\$([A-Za-z0-9+\/]+)$/D',$hash,$parts) || (int)$parts[1]<8192 || (int)$parts[1]>131072 || (int)$parts[2]<1 || (int)$parts[2]>10 || (int)$parts[3]<1 || (int)$parts[3]>4 || strlen($parts[4])>128 || strlen($parts[5])>128) throw new InvalidArgumentException('Argon2id fora dos limites');
if (!defined('PASSWORD_ARGON2ID')) throw new RuntimeException('Instale PHP com suporte a Argon2id');
}
$result = password_verify($password,$hash);
return ['text'=>$result ? 'Os hashes correspondem.' : 'Os hashes não correspondem.', 'valid'=>$result];
}
$result = $process($values['left'] ?? '', $values['right'] ?? '', $values['mode'] ?? '', strtolower(str_replace('-', '', $values['algorithm'] ?? 'SHA-256')), $values['format'] ?? '');
return ['text'=>$result ? 'Os hashes correspondem.' : 'Os hashes não correspondem.', 'valid'=>$result];
}