Java calcula la representación hexadecimal de un resumen SHA-1 de un String

Estoy almacenando la contraseña de usuario en el archivo db como un hash sha1.

Lamentablemente recibo respuestas extrañas.

Estoy almacenando la cadena así:

MessageDigest cript = MessageDigest.getInstance("SHA-1"); cript.reset(); cript.update(userPass.getBytes("utf8")); this.password = new String(cript.digest()); 

Yo quería algo como esto ->

aff -> “0c05aa56405c447e6678b7f3127febde5c3a9238”

más bien que

aff -> V @ \ D ~ fx : 8

Esto sucede porque cript.digest () devuelve una matriz de bytes, que está tratando de imprimir como una Cadena de caracteres. Desea convertirlo en una cadena hexadecimal imprimible.

Solución fácil: use la biblioteca commons-codec de Apache:

 String password = new String(Hex.encodeHex(cript.digest()), CharSet.forName("UTF-8")); 

Usando la biblioteca de códec común de apache:

 DigestUtils.sha1Hex("aff") 

El resultado es 0c05aa56405c447e6678b7f3127febde5c3a9238

Eso es 🙂

Una iteración de un algoritmo hash no es segura. Es demasiado rápido. Debe realizar el fortalecimiento de la clave iterando el hash muchas veces.

Además, no estás salteando la contraseña. Esto crea una vulnerabilidad a los diccionarios precalculados, como “tablas de arcoíris”.

En lugar de intentar rodar su propio código (o usar algún software incompleto de bloatware de terceros) para hacer esto correctamente, puede usar el código incorporado en el tiempo de ejecución de Java. Vea esta respuesta para más detalles.

Una vez que haya cifrado la contraseña correctamente, tendrá un byte[] . Una forma fácil de convertir esto a una String hexadecimal es con la clase BigInteger :

 String passwordHash = new BigInteger(1, cript.digest()).toString(16); 

Si desea asegurarse de que su cadena siempre tenga 40 caracteres, es posible que necesite hacer algo de relleno con ceros a la izquierda (puede hacerlo con String.format() .

Si no desea agregar dependencias adicionales a su proyecto, también puede usar

 MessageDigest digest = MessageDigest.getInstance("SHA-1"); digest.update(message.getBytes("utf8")); byte[] digestBytes = digest.digest(); String digestStr = javax.xml.bind.DatatypeConverter.printHexBinary(digestBytes); 

El método crypt.digest () devuelve un byte []. Esta matriz de bytes es la sum correcta de SHA-1, pero los hashes de cifrado se muestran típicamente a los humanos en forma hexadecimal. Cada byte en tu hash dará como resultado dos dígitos hexadecimales.

Para convertir un byte a hexadecimal de forma segura, usa esto:

 // %1$ == arg 1 // 02 == pad with 0's // x == convert to hex String hex = String.format("%1$02x", byteValue); 

Este fragmento de código se puede usar para convertir un char en hexadecimal :

 /* * Copyright (c) 1995, 2008, Oracle and/or its affiliates. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * - Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * - Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * - Neither the name of Oracle or the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ import java.io.*; public class UnicodeFormatter { static public String byteToHex(byte b) { // Returns hex String representation of byte b char hexDigit[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' }; char[] array = { hexDigit[(b >> 4) & 0x0f], hexDigit[b & 0x0f] }; return new String(array); } static public String charToHex(char c) { // Returns hex String representation of char c byte hi = (byte) (c >>> 8); byte lo = (byte) (c & 0xff); return byteToHex(hi) + byteToHex(lo); } } 

Tenga en cuenta que trabajar con bytes en Java es muy propenso a errores. Verificaría todo dos veces y también probaría algunos casos extraños.

También deberías considerar usar algo más fuerte que SHA-1. http://csrc.nist.gov/groups/ST/hash/statement.html

Si usas Spring es bastante simple:

 MessageDigestPasswordEncoder encoder = new MessageDigestPasswordEncoder("SHA-1"); String hash = encoder.encodePassword(password, "salt goes here"); 

Hay más que simples algoritmos de hash estándar involucrados en el almacenamiento de contraseñas no reversibles.

  1. Haz múltiples rondas para hacer que los ataques de fuerza bruta sean más lentos
  2. Use una “sal” de registro como entrada para el algoritmo hash además de la contraseña para hacer que los ataques de diccionario sean menos factibles y evitar colisiones de salida.
  3. Use “pimienta”, un ajuste de configuración de la aplicación como entrada al algoritmo hash para hacer inútil un volcado de base de datos robado con un “pimiento” desconocido.
  4. Rellene la entrada para evitar debilidades en algunos algoritmos hash, por ejemplo, donde puede agregar un carácter a la contraseña sin conocer la contraseña, modificando el hash.

Para obtener más información, consulte, por ejemplo,

También puede utilizar un http://en.wikipedia.org/wiki/Password-authenticated_key_agreement método para evitar pasar la contraseña en texto claro al servidor en absoluto.

digest () devuelve una matriz de bytes, que está convirtiendo a una cadena utilizando la encoding predeterminada. Lo que quieres hacer es codificarlo en base64.

Para usar UTF-8, haz esto:

 userPass.getBytes("UTF-8"); 

Y para obtener una Cadena Base64 del resumen, puedes hacer algo como esto:

 this.password = new BASE64Encoder().encode(cript.digest()); 

Como MessageDigest.digest() devuelve una matriz de bytes, puede convertirla a String usando la encoding hexadecimal de Apache (más simple).

P.ej

 this.password = Hex.encodeHexString(cript.digest()); 

¿Qué hay de convertir byte [] a la cadena base64?

  byte[] chkSumBytArr = digest.digest(); BASE64Encoder encoder = new BASE64Encoder(); String base64CheckSum = encoder.encode(chkSumBytArr); 

también puedes usar este código (desde crackstation.net):

private static String toHex(byte[] array) { BigInteger bi = new BigInteger(1, array); String hex = bi.toString(16); int paddingLength = (array.length * 2) - hex.length(); if(paddingLength > 0) return String.format("%0" + paddingLength + "d", 0) + hex; else return hex; }

Puedes usar Google Guava :

Maven:

  guava com.google.guava 14.0.1  

Muestra:

 HashFunction hashFunction = Hashing.sha1(); HashCode hashCode = hashFunction.newHasher() .putString(password,Charsets.UTF_8) .hash(); String hash = BaseEncoding.base16().lowerCase().encode(hashCode.asBytes()); 
  MessageDigest messageDigest = MessageDigest.getInstance("SHA-1"); messageDigest.reset(); messageDigest.update(password.getBytes("UTF-8")); String sha1String = new BigInteger(1, messageDigest.digest()).toString(16); 

Primero debe codificar hexadecimal el resultado. MessageDigest devuelve un hash “en bruto” en lugar de uno legible por humanos.

Editar:

@thejh proporcionó un enlace al código que debería funcionar. Personalmente, sugiero usar Bouncycastle o Apache Commons Codec para hacer el trabajo. Bouncycastle sería bueno si quieres hacer otras operaciones relacionadas con la criptografía.