Pergunta

Eu tenho algumas cordas que foram criptografadas usando o Função PHP crypt().

As saídas se parecem com a seguinte:

$1$Vf/.4.1.$CgCo33ebiHVuFhpwS.kMI0
$1$84..vD4.$Ps1PdaLWRoaiWDKCfjLyV1
$1$or1.RY4.$v3xo04v1yfB7JxDj1sC/J/

Enquanto eu acredito que o Crypt () está usando o algoritmo MD5, as saídas não são hashes md5 válidos.

Existe uma maneira de converter os hashes produzidos em hashes md5 válidos (valores de 16 bytes)?


Atualizar:

Obrigado pelas respostas, então as respostas até agora. Tenho certeza de que a função de cripta usada está usando algum tipo de algoritmo MD5. O que estou procurando fazer é converter o grupo que tenho em um hash do MD5 que se parece com o seguinte:

9e107d9d372bb6826bd81d3542a419d6  
e4d909c290d0fb1ca068ffaddf22cbd0  
d41d8cd98f00b204e9800998ecf8427e

(Tirado de Wikipedia)

Existe uma maneira de se converter dos hashes que tenho para aqueles como o acima?

Foi útil?

Solução

OK, então talvez essa resposta esteja um ano atrasada, mas eu vou tentar. Em sua própria resposta, você observa que crypt() está usando o FreeBSD MD5, que também faz algumas transformações interessantes no sal antes de executar o hash, então o resultado do que estou prestes a dar você nunca combinará com os resultados de uma chamada para md5(). Dito isto, a única diferença entre a saída que você está vendo e o formato que você está acostumado é que a saída que você está vendo é codificada da seguinte maneira

$1$        # this indicates that it is MD5
Vf/.4.1.   # these eight characters are the significant portion of the salt
$          # this character is technically part of the salt, but it is ignored
CgCo33eb   # the last 22 characters are the actual hash
iHVuFhpw   # they are base64 encoded (to be printable) using crypt's alphabet
S.kMI0     # floor(22 * 6 / 8) = 16 (the length in bytes of a raw MD5 hash)

Que eu saiba, o alfabeto usado pela cripta é assim:

./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz

Então, com tudo isso em mente, aqui está como você pode converter o hash de 22 caracteres da cripta-Base64 em um hash de 32 caracteres base16 (hexadecimal):

Primeiro, você precisa de algo para converter o Base64 (com alfabeto personalizado) em um hash de 16 bytes MD5.

define('CRYPT_ALPHA','./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz');
/**
 * Decodes a base64 string based on the alphabet set in constant CRYPT_ALPHA
 * Uses string functions rather than binary transformations, because said
 * transformations aren't really much faster in PHP
 * @params string $str  The string to decode
 * @return string       The raw output, which may include unprintable characters
 */
function base64_decode_ex($str) {
    // set up the array to feed numerical data using characters as keys
    $alpha = array_flip(str_split(CRYPT_ALPHA));
    // split the input into single-character (6 bit) chunks
    $bitArray = str_split($str);
    $decodedStr = '';
    foreach ($bitArray as &$bits) {
        if ($bits == '$') { // $ indicates the end of the string, to stop processing here
            break;
        }
        if (!isset($alpha[$bits])) { // if we encounter a character not in the alphabet
            return false;            // then break execution, the string is invalid
        }
        // decbin will only return significant digits, so use sprintf to pad to 6 bits
        $decodedStr .= sprintf('%06s', decbin($alpha[$bits]));
    }
    // there can be up to 6 unused bits at the end of a string, so discard them
    $decodedStr = substr($decodedStr, 0, strlen($decodedStr) - (strlen($decodedStr) % 8));
    $byteArray = str_split($decodedStr, 8);
    foreach ($byteArray as &$byte) {
        $byte = chr(bindec($byte));
    }
    return join($byteArray);
}

Agora que você tem os dados brutos, precisará de um método para convertê-los no formato Base-16 que está esperando, o que não poderia ser mais fácil.

/**
 * Takes an input in base 256 and encodes it to base 16 using the Hex alphabet
 * This function will not be commented.  For more info:
 * @see http://php.net/str-split
 * @see http://php.net/sprintf
 *
 * @param string $str   The value to convert
 * @return string       The base 16 rendering
 */
function base16_encode($str) {
    $byteArray = str_split($str);
    foreach ($byteArray as &$byte) {
        $byte = sprintf('%02x', ord($byte));
    }
    return join($byteArray);
}

Finalmente, como a saída da cripta inclui muitos dados de que não precisamos (e, de fato, não podem usar) para esse processo, uma função curta e doce não apenas vincula esses dois, mas também para permitir a entrada direta da saída de cripta.

/**
 * Takes a 22 byte crypt-base-64 hash and converts it to base 16
 * If the input is longer than 22 chars (e.g., the entire output of crypt()),
 * then this function will strip all but the last 22.  Fails if under 22 chars
 *
 * @param string $hash  The hash to convert
 * @param string        The equivalent base16 hash (therefore a number)
 */
function md5_b64tob16($hash) {
    if (strlen($hash) < 22) {
        return false;
    }
    if (strlen($hash) > 22) {
        $hash = substr($hash,-22);
    }
    return base16_encode(base64_decode_ex($hash));
}

Dadas essas funções, a representação base16 de seus três exemplos é:

3ac3b4145aa7b9387a46dd7c780c1850
6f80dba665e27749ae88f58eaef5fe84
ec5f74086ec3fab34957d3ef0f838154

Obviamente, é importante lembrar que eles sempre eram válidos, apenas formatados de maneira diferente.

Outras dicas

$ 1 $ realmente significa que este é um hash do MD5, mas a cripta gera um sal aleatório. É por isso que você encontra um valor MD5 diferente. Se você incluir o sal gerado, encontrará o mesmo resultado.

O sal é base64 codificado na saída, como o hash.

O algoritmo usado é um parâmetro amplo do sistema. Geralmente é MD5, você está certo.

Acredito que a resposta para minha pergunta original é não, você não pode se converter de um formato para o outro.

Os hashes gerados por php Crypt () parecem ser gerados por uma versão da implementação do hash FreeBSD MD5 criada pelo Kamp de Henning.

http://people.freebsd.org/~phk/

A partir da documentação, isso depende do sistema. Você pode forçar o algoritmo usado definindo o parâmetro de sal. Dos documentos:

O tipo de criptografia é desencadeado pelo argumento do sal. No momento da instalação, o PHP determina os recursos da função da cripta e aceitará sais para outros tipos de criptografia. Se nenhum sal for fornecido, o PHP gerará automaticamente um sal padrão de dois caracteres por padrão, a menos que o tipo de criptografia padrão no sistema seja MD5, caso em que um sal compatível com MD5 aleatório será gerado.

A partir de http://php.net/crypt:

Crypt () retornará uma string criptografada usando o algoritmo de criptografia baseado em UNIX DEIX ou algoritmos alternativos que podem estar disponíveis no sistema.

Você quer o md5() função:

Calcula o hash do MD5 de STR usando o algoritmo de mession-digest »RSA Data Security, Inc. MD5 e retornos que hash.
Se o RAW_OUTPUT opcional for definido como true, o MD5 Digest será retornado em formato binário bruto com um comprimento de 16. Padrões para false.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top