2010-07-13 18 views
5

Sé que esto parece una pregunta amplia, pero puedo limitarla con un ejemplo. Soy MUY nuevo en Java. Para uno de mis proyectos de "aprendizaje", quería crear un hasher de archivo MD5 interno para que lo usemos. Empecé de manera muy simple intentando manipular una cadena y luego pasar a un archivo más adelante. He creado un archivo llamado MD5Hasher.java y escribió lo siguiente:¿Cómo va una persona a aprender Java? (convertir matriz de bytes a cadena hexadecimal)

import java.security.*; 
import java.io.*; 
public class MD5Hasher{ 
    public static void main(String[] args){ 
     String myString = "Hello, World!"; 
     byte[] myBA = myString.getBytes(); 
     MessageDigest myMD; 
     try{ 
      myMD = MessageDigest.getInstance("MD5"); 
      myMD.update(myBA); 
      byte[] newBA = myMD.digest(); 
      String output = newBA.toString(); 
      System.out.println("The Answer Is: " + output); 
     } catch(NoSuchAlgorithmException nsae){ 
      // print error here 
     } 
    } 
} 

Visité java.sun.com para ver los javadocs para java.security para averiguar cómo utilizar MessageDigest clase. Después de leer, supe que tenía que usar un método "getInstance" para obtener un objeto MessageDigest utilizable que pudiera usar. El Javadoc continuó diciendo "Los datos se procesan a través de él utilizando los métodos de actualización". Así que miré los métodos de actualización y determiné que necesitaba usar el que lo alimentaba con una matriz de bytes de mi cadena, así que agregué esa parte. El Javadoc pasó a decir: "Una vez que se actualicen todos los datos que se actualizarán, se debe llamar a uno de los métodos de resumen para completar el cálculo de hash". Una vez más, miré los métodos y vi que el resumen devolvía una matriz de bytes, así que agregué esa parte. Luego usé el método "toString" en la nueva matriz de bytes para obtener una cadena que podría imprimir. Sin embargo, cuando compilé y corrió el código todo lo que imprimió fue la siguiente:

La respuesta es: [B @ 4cb162d5

he hecho algunos mirando por aquí en StackOverflow y se encontró alguna información aquí:

How can I generate an MD5 hash?

que dio el siguiente ejemplo:

String plaintext = 'your text here'; 
MessageDigest m = MessageDigest.getInstance("MD5"); 
m.reset(); 
m.update(plaintext.getBytes()); 
byte[] digest = m.digest(); 
BigInteger bigInt = new BigInteger(1,digest); 
String hashtext = bigInt.toString(16); 
// Now we need to zero pad it if you actually want the full 32 chars. 
while(hashtext.length() < 32){ 
    hashtext = "0"+hashtext; 
} 

parece que la única parte que MAY falta es la parte "BigInteger", pero no estoy seguro.

Entonces, después de todo esto, creo que lo que estoy preguntando es, ¿cómo sabes utilizar la parte "BigInteger"? Supuse erróneamente que el método "toString" en mi objeto newBA lo convertiría en una salida legible, pero aparentemente estaba equivocado. ¿Cómo se supone que una persona debe saber qué camino tomar en Java? Tengo un fondo en C así que esta cosa de Java parece bastante extraña. ¿Algún consejo sobre cómo puedo mejorar sin tener que "hacer trampas" buscando en Google cómo hacer algo todo el tiempo?

Gracias a todos por tomarse el tiempo para leer. :-)

+1

de la manera difícil :) – Bozho

+2

Parte de ser un buen programador es aprender quién y cuáles son sus recursos, y cuándo y cómo usarlos. Google es un recurso, y no hay vergüenza en usarlo y abusar de él para convertirte en un desarrollador más experimentado. Otros recursos son tus compañeros desarrolladores y/o libros de autoaprendizaje. – Jagd

+0

posible duplicado de [¿Cuáles son los mejores recursos para aprender Java (libros, sitios web, etc.)?] (Http://stackoverflow.com/questions/77839/what-are-the-best-resources-for-learning- java-books-websites-etc) – gnovice

Respuesta

2

En realidad se ha digerido con éxito el mensaje. Simplemente no sabes cómo presentar el valor de resumen encontrado correctamente. Lo que tienes es una matriz de bytes. Eso es un poco difícil de leer, y un toString de una matriz de bytes produce [[email protected] que no es útil en absoluto.

BigInteger se presenta como una herramienta para formatear la matriz de bytes en un solo número.

Lo que se hace es:

  • construct un BigInteger con el valor adecuado (en este caso ese valor pasa a ser codificado en forma de una matriz de bytes - su digerir
  • Instruir al objeto BigInteger a devolver una representación de cadena (por ejemplo, el texto legible) de ese número, base 16 (por ejemplo hexagonal)

Y los prefijos bucle while que valoran con 0 caracteres para obtener una anchura de 32. probablemente haría uso de cuerdas .formato para eso, pero lo que sea que flote su bote :)

+0

Muy bueno ... gracias. Agregué las siguientes líneas y escupió lo que estaba buscando: BigInteger newBI = new BigInteger (newBA); String outupt = newBI.toString (16); – Brian

+0

@Brian: esta es también la solución incorrecta. Devolverá una cadena de caracteres negativa (!!!) cuando el byte inicial sea negativo. Ver mi respuesta para el enfoque correcto de conversión de hexstring. También verá que algunos usuarios pueden sugerir utilizar 'nuevos BigInteger (bytes) .abs(). ToString (16)' en su lugar, pero esto también es fundamentalmente erróneo. Con un byte líder negativo, esto da como resultado una cadena hexadecimal incorrecta que no es convertible a los * mismos * bytes. Y, por lo tanto, no puede compartirse/usarse de forma cruzada con otros generadores MD5 de producción de cadenas hexagonales que el mundo conoce. – BalusC

+0

No estoy seguro de qué parte tengo mal. Construí un BigInteger con "BigInteger newBI = new BigInteger (newBA);" y luego utilicé toString (16) para devolver una cadena hexadecimal legible por humanos. ¿Dónde me equivoqué? – Brian

2

No hay problema en google en busca de respuestas, siempre y cuando (con el tiempo) entender lo que copiar-pegar en su aplicación :-)

En general, yo recomiendo empezar con un buen libro introductorio de Java, o tutorial web. Ver estos hilos para obtener más consejos:

+0

¿Y el motivo del voto a favor es ...? –

2

MessageDigests calcular una matriz de bytes de algo, la cadena que se suele ver (como 1f3870be274f6c49b3e31a0c6728957f) es en realidad sólo una conversión de la matriz de bytes a una cadena hexadecimal.

Cuando se llama a MessageDigest.toString(), llama MessageDigest.digest().toString(), y en Java, el método toString para un byte[] (devuelto por MessageDigest.digest()) devuelve una especie de referencia a los bytes, no los bytes reales.

En el código que ha publicado, la matriz de bytes se cambia a un número entero (en este caso un BigInteger porque sería extremadamente grande), y luego se convierte a hexadecimal para imprimirse en una cadena.

La matriz de bytes calculada por el resumen representa un número (un número de 128 bits según http://en.wikipedia.org/wiki/MD5), y ese número se puede convertir a cualquier otra base, por lo que el resultado del MD5 podría representarse como base-10 número, un número de base 2 (como en una matriz de bytes) o, más comúnmente, un número de base 16.

0

Use un IDE que muestre de dónde viene el método "toString()". En la mayoría de los casos es solo de la clase Object y no será muy útil. En general, se recomienda sobrescribir el método toString para proporcionar un resultado limpio, pero muchas clases no lo hacen.

+0

Oh sí ... Yo uso NetBeans. Ha sido INMENSALMENTE útil para llegar tan lejos como yo. – Brian

1

Aunque me temo que no tengo ninguna experiencia usando Java para jugar con hashes MD5, puedo recomendar Sun's Java Tutorials como un recurso fantástico para aprender Java. Pasan por la mayor parte del idioma y me ayudaron mucho cuando estaba aprendiendo Java.

También busque otros mensajes que le pregunten lo mismo y vea qué sugerencias aparecieron allí.

1

Se utiliza el motivo BigInteger porque la matriz de bytes es muy larga, demasiado grande para encajar en int o long. Sin embargo, si desea ver todo en la matriz de bytes, hay un enfoque alternativo. Se podía reemplazar la línea:

String output = newBA.toString(); 

con:

String output = Arrays.toString(newBA); 

Esto imprimirá las contenidos de la matriz, no la dirección de referencia.

+0

"Salida de cadena = Arrays.toString (newBA)" - no es realmente útil. Mostraría el contenido de la matriz como una serie de valores de bytes, p. Ej. "[-33, 1, 93, -104, ..." en lugar de DF015D98 ... –

+0

@Jason: Tiene razón, en esta aplicación específica 'Arrays.toString()' no proporciona la mejor representación. Dejaré mi respuesta porque * es * útil para la mayoría de los casos de impresión de matrices. –

6

La clave en este caso particular es que debe tener en cuenta que los bytes no son "legibles por humanos", pero los caracteres sí lo son. Entonces necesita convertir bytes a caracteres en un formato determinado. Para bytes arbitrarios, como hashes, generalmente el hexadecimal se usa como formato de "lectura humana". Cada byte se convierte en una cadena hexadecimal de 2 caracteres que a su vez se concatenan.

Esto no está relacionado con el idioma que utiliza. Solo tiene que entender/darse cuenta de cómo funciona "bajo los capós" de una manera independiente del idioma. Debe comprender lo que tiene (una matriz de bytes) y lo que quiere (una cadena hexadecimal). El lenguaje de programación es solo una herramienta para lograr el resultado deseado. Simplemente busca en google el "requisito funcional" junto con el lenguaje de programación que le gustaría usar para lograr el requisito. P.ej. "convert byte array to hex string in java".


Dicho esto, el ejemplo de código que ha encontrado es incorrecto.Debería determinar realmente cada byte dentro de un bucle y probar si es menor que 0x10 y luego rellenarlo con cero en lugar de rellenar el cero según la longitud de la cadena resultante (que puede no ser necesariamente causado por el primer byte) siendo menor que 0x10!).

StringBuilder hex = new StringBuilder(bytes.length * 2); 
for (byte b : bytes) { 
    if ((b & 0xff) < 0x10) hex.append("0"); 
    hex.append(Integer.toHexString(b & 0xff)); 
} 
String hexString = hex.toString(); 

actualización de acuerdo con los comentarios sobre la respuesta de @extraneon, utilizando new BigInteger(byte[]) es también la solución equivocada. Esto no anula los bytes. Los bytes (como todos los números primitivos) en Java están firmados. Ellos tienen un rango negativo. El byte en Java varía de -128 a 127 mientras que desea tener un rango de 0 a 255 para obtener una cadena hexadecimal adecuada. Básicamente, solo necesitas quitar el signo para que no estén firmados. El & 0xff en el ejemplo anterior hace exactamente eso.

La cadena hexadecimal obtenida de new BigInteger(bytes).toString(16) NO es compatible con el resultado de todas las otras cadenas hexagonales que producen generadores MD5 de los que el mundo conoce. Diferirán siempre que tengas un byte negativo en el resumen de MD5.

0

que supone erróneamente que el método "toString" en mi objeto newBA podría convertirla en una salida fácil de leer, pero yo era, al parecer, mal. ¿Cómo se supone que una persona debe saber qué camino tomar en Java?

Puede reemplazar aquí Java con el idioma de su elección que aún no domina. Incluso si trabajó 10 años en un idioma específico, aún obtendrá esos "Aha! ¡Esta es la manera en que está funcionando!" -efectos, aunque no tan a menudo como al principio.

El punto que debe aprender aquí es que toString() no devuelve la representación que desea/espera, pero cualquier implementador ha elegido. La implementación predeterminada de toString() es así (javadoc):

Devuelve una representación de cadena del objeto. En general, el método toString devuelve una cadena que "representa textualmente" este objeto. El resultado debe ser una representación concisa pero informativa que sea fácil de leer para una persona. Se recomienda que todas las subclases anulen este método.

El método toString para la clase Object devuelve una cadena que consiste en el nombre de la clase de la cual el objeto es una instancia, el caracter en el signo `@ 'y la representación hexadecimal sin signo del código hash del objeto. En otras palabras, este método devuelve una cadena igual al valor de:.

getClass() getName() + '@' + Integer.toHexString (hashCode())

0

También soy un novato en el desarrollo. Para el problema actual, sugiero el libro "Introducción a la criptografía con Java Applets" by David Bishop. Demuestra lo que necesita y así sucesivamente ...

0

Cualquier consejo sobre cómo puedo mejorar sin tener que "hacer trampa" buscando en Google cómo hacer algo todo el tiempo?

¡Al no comenzar con un hasher MD5! En serio, sube poco a poco en programas que puedes completar sin preocuparte por cosas específicas de un dominio como MD5.

Si está volcando todo en main, no está programando Java.

En un programa de esta escala, su main() debería hacer una cosa: crear un objeto MD5Hasher y luego llamar a algunos métodos sobre él. Debería tener un constructor que tome una cadena inicial, un método para "hacer el trabajo" (actualización, resumen) y un método para imprimir el resultado.

Obtenga algunos tutoriales y pase tiempo en ejercicios simples y tradicionales (un generador de Fibonacci, un programa para resolver algunos acertijos lógicos), para que pueda entender los conceptos básicos del lenguaje antes de molestarse con las bibliotecas, que es lo que está luchando ahora. Luego puede comenzar a hacer cosas útiles.

0

¿Cómo se supone que una persona sepa qué camino a tomar en Java? Tengo un fondo de en C, por lo que esta cosa de Java parece bastante extraña . Cualquier consejo sobre cómo puedo obtener mejor sin tener que "hacer trampa" por buscando en Google cómo hacer algo todo el tiempo ?

Las respuestas obvias son 1 - google cuando tiene preguntas (y no se considera infidelidad) y 2 - lee libros sobre el tema.

Aparte de estos dos, recomendaría tratar de encontrar un mentor para usted. Si no tiene experimentados desarrolladores de Java en el trabajo, intente unirse a un grupo local de desarrolladores de Java. Puede encontrar desarrolladores más experimentados allí y tal vez elegir sus cerebros para obtener respuestas a sus preguntas.

Cuestiones relacionadas