MD5-Hashing in Android

91

Ich habe einen einfachen Android-Client, der mit einem einfachen C # HTTP-Listener "sprechen" muss. Ich möchte eine grundlegende Authentifizierungsstufe bereitstellen, indem ich Benutzername / Passwort in POST-Anfragen übergebe.

MD5-Hashing ist in C # trivial und bietet genügend Sicherheit für meine Anforderungen, aber ich kann anscheinend nicht finden, wie dies am Android-Ende zu tun ist.

BEARBEITEN: Nur um die Bedenken bezüglich der MD5-Schwäche auszuräumen - der C # -Server läuft auf den PCs der Benutzer meines Android-Clients. In vielen Fällen greifen sie über WLAN in ihren eigenen LANs auf den Server zu, können jedoch auf eigenes Risiko über das Internet darauf zugreifen. Außerdem muss der Dienst auf dem Server das Pass-Through für das MD5 an eine Drittanbieteranwendung verwenden, über die ich keine Kontrolle habe.

Squonk
quelle
6
Verwenden Sie kein MD5. Verwenden Sie SHA512.
SLaks
1
Warum? SHA512 ist nicht schwerer als MD5. Sie möchten in fünf Jahren nicht mehr mit älteren Kunden arbeiten, die MD5 verwenden.
SLaks
2
Ich hoffe, Sie verwenden eine Nonce in Ihrem Protokoll, damit Sie Wiederholungsangriffe wegwerfen können.
Sarnold
1
@ NickJohnson: Um Ihre Frage zu beantworten, warum sollten Sie absichtlich die schwächere Option wählen? mit einer anderen Frage ... warum sollten Sie eine Frage kommentieren müssen, die ich vor 16 Monaten gepostet habe? Aber wenn Sie wirklich wissen wollen (wenn Sie sich den Kommentar zu SLaks über Ihrem ansehen), war es Alpha-Stage-Code und das PC-Ende (nicht von mir geschrieben) verwendete MD5-Hashing. Die Anforderung bestand im Wesentlichen aus einem Durchgangsszenario ohne zusätzliche Komplexität. Ich hatte damals ungefähr 10 Alpha-Tester, die die Risiken kannten. Seit ich die Frage gestellt habe, wurde eine komplexere Sicherheit integriert.
Squonk
1
...Was? Nein, das ist nicht nur falsch, es ist gefährlich falsch.
Nick Johnson

Antworten:

230

Hier ist eine Implementierung, die Sie verwenden können (aktualisiert, um aktuellere Java-Konventionen zu verwenden - for:eachSchleife StringBuilderanstelle von StringBuffer):

public static String md5(final String s) {
    final String MD5 = "MD5";
    try {
        // Create MD5 Hash
        MessageDigest digest = java.security.MessageDigest
                .getInstance(MD5);
        digest.update(s.getBytes());
        byte messageDigest[] = digest.digest();

        // Create Hex String
        StringBuilder hexString = new StringBuilder();
        for (byte aMessageDigest : messageDigest) {
            String h = Integer.toHexString(0xFF & aMessageDigest);
            while (h.length() < 2)
                h = "0" + h;
            hexString.append(h);
        }
        return hexString.toString();

    } catch (NoSuchAlgorithmException e) {
        e.printStackTrace();
    }
    return "";
}

Obwohl es nicht für Systeme empfohlen wird, die selbst die grundlegende Sicherheitsstufe beinhalten (MD5 gilt als defekt und kann leicht ausgenutzt werden ), reicht es manchmal für grundlegende Aufgaben aus.

Den Delimarsky
quelle
Danke, das wird den Trick machen. In meiner Bearbeitung erfahren Sie, warum MD5 zu diesem Zeitpunkt ausreicht.
Squonk
6
Stimmen Sie dies IMO ab, damit die korrekteren Antworten unten auftauchen.
Adam
4
0 wird nicht berücksichtigt, wie unten beantwortet.
SohailAziz
Aktualisiert, um neuere Java-Standards zu verwenden (für: jeden, StringBuilder)
loeschg
3
Gibt es ein Android-Betriebssystem, das MD5 nicht implementiert hat (Ursache werfen NoSuchAlgorithmException)?
VSB
49

Die akzeptierte Antwort hat bei Android 2.2 nicht funktioniert. Ich weiß nicht warum, aber es "aß" einige meiner Nullen (0). Apache Commons funktionierte auch unter Android 2.2 nicht, da Methoden verwendet werden, die nur ab Android 2.3.x unterstützt werden. Wenn Sie nur einen MD5-String verwenden möchten, ist Apache Commons dafür zu komplex. Warum sollte man eine ganze Bibliothek behalten, um nur eine kleine Funktion daraus zu verwenden ...

Schließlich habe ich hier das folgende Code-Snippet gefunden, das für mich perfekt funktioniert hat. Ich hoffe, es wird für jemanden nützlich sein ...

public String MD5(String md5) {
   try {
        java.security.MessageDigest md = java.security.MessageDigest.getInstance("MD5");
        byte[] array = md.digest(md5.getBytes("UTF-8"));
        StringBuffer sb = new StringBuffer();
        for (int i = 0; i < array.length; ++i) {
          sb.append(Integer.toHexString((array[i] & 0xFF) | 0x100).substring(1,3));
       }
        return sb.toString();
    } catch (java.security.NoSuchAlgorithmException e) {
    } catch(UnsupportedEncodingException ex){
    }
    return null;
}
Andranik
quelle
4
Hat für mich gearbeitet. Ich habe md5.getBytes ("UTF-8") geändert . Ich habe es überprüft mit: q4m'x68n6_YDB4ty8VC4 &} wqBtn ^ 68W mit dem obigen Code, das Ergebnis ist 0c70bb931f03b75af1591f261eb77d0b , NICHT das c70bb931f03b75af1591f261eb77d0b . 0 ist an Ort und Stelle
Inoy
27

Der androidsnippets.com-Code funktioniert nicht zuverlässig, da Nullen aus dem resultierenden Hash herausgeschnitten zu sein scheinen.

Eine bessere Umsetzung ist hier .

public static String MD5_Hash(String s) {
    MessageDigest m = null;

    try {
            m = MessageDigest.getInstance("MD5");
    } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
    }

    m.update(s.getBytes(),0,s.length());
    String hash = new BigInteger(1, m.digest()).toString(16);
    return hash;
}
Christian
quelle
Kann "m" unter Android in diesem Fall jemals null sein?
Android-Entwickler
3
@androiddeveloper Du hast vollkommen recht. Der catch-Block ist hier schlecht implementiert, es muss eine return-Anweisung vorhanden sein, oder es wird ein Nullreferenzfehler angezeigt, wenn m.update aufgerufen wird. Ich bin mir auch nicht sicher, aber während dies möglicherweise keine Nullen auf den einzelnen Bytes entfernt, denke ich, dass es immer noch führende Nullen auf dem gesamten 32-Zeichen-Hash entfernt. Anstelle von toString (16) funktioniert String.Format ("% 032X", bigInt) wie vorgesehen. Außerdem können Sie wählen, ob Sie das Hex in Groß- oder Kleinbuchstaben möchten ("% 032x" für Kleinbuchstaben).
Rsimp
1
Diese Version ist fehlerhaft. Wenn Ihr MD5 mit "0" beginnt, hat das generierte MD5 keine führende 0. Bitte verwenden Sie diese Lösung nicht.
Elcuco
20

Wenn die Verwendung von Apache Commons Codec eine Option ist, ist dies eine kürzere Implementierung:

String md5Hex = new String(Hex.encodeHex(DigestUtils.md5(data)));

Oder SHA:

String shaHex= new String(Hex.encodeHex(DigestUtils.sha("textToHash")));

Quelle für oben.

Bitte folgen Sie dem Link und stimmen Sie seiner Lösung zu, um die richtige Person zu bestimmen.


Maven-Repo-Link: https://mvnrepository.com/artifact/commons-codec/commons-codec

Aktuelle Maven-Abhängigkeit (Stand 6. Juli 2016):

<!-- https://mvnrepository.com/artifact/commons-codec/commons-codec -->
<dependency>
    <groupId>commons-codec</groupId>
    <artifactId>commons-codec</artifactId>
    <version>1.10</version>
</dependency>
tbraun
quelle
1
Gibt es einen Grund, warum Sie eine externe Bibliothek für eine API verwenden würden, die bereits in der Standardbibliothek vorhanden ist?
m0skit0
12

Eine der oben genannten Lösungen mit DigestUtils hat bei mir nicht funktioniert. In meiner Version von Apache Commons (die neueste für 2013) gibt es keine solche Klasse.

Ich habe hier in einem Blog eine andere Lösung gefunden . Es funktioniert perfekt und benötigt keine Apache Commons. Es sieht etwas kürzer aus als der Code in der oben akzeptierten Antwort.

public static String getMd5Hash(String input) {
    try {
        MessageDigest md = MessageDigest.getInstance("MD5");
        byte[] messageDigest = md.digest(input.getBytes());
        BigInteger number = new BigInteger(1, messageDigest);
        String md5 = number.toString(16);

        while (md5.length() < 32)
            md5 = "0" + md5;

        return md5;
    } catch (NoSuchAlgorithmException e) {
        Log.e("MD5", e.getLocalizedMessage());
        return null;
    }
}

Sie benötigen diese Importe:

import java.math.BigInteger;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
Denis Kutlubaev
quelle
Es ist wichtig zu wissen, dass der MD5-Hash eine Länge von 32 Zeichen oder weniger hat. Vielen Dank!
Pelanes
3
Die letzten Zeilen können wahrscheinlich nur ersetzt werden durch: return String.Format ("% 032X", number); Ansonsten gefällt mir diese Antwort sehr gut.
Rsimp
10

Dies ist eine geringfügige Variation der obigen Antworten von Andranik und Den Delimarsky, aber etwas prägnanter und erfordert keine bitweise Logik. Stattdessen wird die integrierte String.formatMethode verwendet, um die Bytes in hexadezimale Zeichenfolgen mit zwei Zeichen umzuwandeln (keine Nullen werden entfernt). Normalerweise würde ich nur ihre Antworten kommentieren, aber ich habe nicht den Ruf, dies zu tun.

public static String md5(String input) {
    try {
        MessageDigest md = MessageDigest.getInstance("MD5");

        StringBuilder hexString = new StringBuilder();
        for (byte digestByte : md.digest(input.getBytes()))
            hexString.append(String.format("%02X", digestByte));

        return hexString.toString();
    } catch (NoSuchAlgorithmException e) {
        e.printStackTrace();
        return null;
    }
}

Wenn Sie stattdessen eine Zeichenfolge in Kleinbuchstaben zurückgeben möchten, wechseln Sie einfach %02Xzu %02x.

Bearbeiten: Wenn Sie BigInteger wie bei der Antwort von wzbozon verwenden, können Sie die Antwort noch präziser gestalten:

public static String md5(String input) {
    try {
        MessageDigest md = MessageDigest.getInstance("MD5");
        BigInteger md5Data = new BigInteger(1, md.digest(input.getBytes()));
        return String.Format("%032X", md5Data);
    } catch (NoSuchAlgorithmException e) {
        e.printStackTrace();
        return null;
    }
}
rsimp
quelle
4

Ich habe eine einfache Bibliothek in Kotlin erstellt.

Fügen Sie bei Root build.gradle hinzu

allprojects {
        repositories {
            ...
            maven { url 'https://jitpack.io' }
        }
    }

bei App build.gradle

implementation 'com.github.1AboveAll:Hasher:-SNAPSHOT'

Verwendung

In Kotlin

val ob = Hasher()

Verwenden Sie dann die Methode hash ()

ob.hash("String_You_Want_To_Encode",Hasher.MD5)

ob.hash("String_You_Want_To_Encode",Hasher.SHA_1)

Es werden jeweils MD5 und SHA-1 zurückgegeben.

Mehr über die Bibliothek

https://github.com/ihimanshurawat/Hasher

Himanshu Rawat
quelle
2

Hier ist Kotlin Version von @Andranik Antwort. Wir müssen Veränderung getByteszu toByteArray(brauche nicht charset UTF-8 , da der Standard - Zeichensatz von hinzuzufügen toByteArrayist UTF-8) und Guss array [i] zu integer

fun String.md5(): String? {
    try {
        val md = MessageDigest.getInstance("MD5")
        val array = md.digest(this.toByteArray())
        val sb = StringBuffer()
        for (i in array.indices) {
            sb.append(Integer.toHexString(array[i].toInt() and 0xFF or 0x100).substring(1, 3))
        }
        return sb.toString()
    } catch (e: java.security.NoSuchAlgorithmException) {
    } catch (ex: UnsupportedEncodingException) {
    }
    return null
}

Hoffe es hilft

Phan Van Linh
quelle
1

MD5 ist etwas alt, SHA-1 ist ein besserer Algorithmus, hier gibt es ein Beispiel .

( Wie in diesem Beitrag erwähnt, erledigt Java dies selbstständig, ohne Android-spezifischen Code. )

Adam
quelle
4
Nein - Ich wollte keine Alternativen zu MD5, als ich diese Frage im Januar 2011 (vor 19 Monaten) stellte, und ich bin mir nicht sicher, warum Sie an dieser Stelle das Bedürfnis hatten, auf meine Frage zu antworten.
Squonk
21
@Squonk Ich habe geantwortet, weil dies die allgemeine Idee hinter dem Stackoverflow ist. Versuchen Sie immer, bessere Antworten für Personen zu erhalten, die später auf die Frage stoßen. Was den Vorschlag für SHA-1 angeht, gab es für mich keine Möglichkeit zu wissen, dass Sie speziell gegen SHA-1 waren, aber viele andere werden es nicht sein. Auch dies könnte anderen Menschen in Zukunft helfen, die darauf stoßen, und sie leiten zu einem moderneren Algorithmus.
Adam
3
Ich kann mir keine einzige Situation vorstellen, in der MD5 eine schlechte Wahl ist, SHA1 jedoch eine gute. Wenn Sie Kollisionsfestigkeit benötigen, benötigen Sie SHA2, nicht SHA1. Wenn Sie Passwörter hashen, benötigen Sie bcrypt oder PBKDF2. Oder im Fall des OP ist SSL wahrscheinlich die richtige Lösung.
CodesInChaos
3
@Adam das ist keine Antwort das ist ein Kommentar.
Antzi
1

In unserer MVC-Anwendung generieren wir für lange Parameter

using System.Security.Cryptography;
using System.Text;
    ...
    public static string getMD5(long id)
    {
        // convert
        string result = (id ^ long.MaxValue).ToString("X") + "-ANY-TEXT";
        using (MD5 md5Hash = MD5.Create())
        {
            // Convert the input string to a byte array and compute the hash. 
            byte[] data = md5Hash.ComputeHash(Encoding.UTF8.GetBytes(result));

            // Create a new Stringbuilder to collect the bytes and create a string.
            StringBuilder sBuilder = new StringBuilder();
            for (int i = 0; i < data.Length; i++)
                sBuilder.Append(data[i].ToString("x2"));

            // Return the hexadecimal string. 
            result = sBuilder.ToString().ToUpper();
        }

        return result;
    }

und das gleiche in der Android-Anwendung (thenk hilft Andranik)

import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
...
public String getIdHash(long id){
    String hash = null;
    long intId = id ^ Long.MAX_VALUE;
    String md5 = String.format("%X-ANY-TEXT", intId);
    try {
        MessageDigest md = java.security.MessageDigest.getInstance("MD5");
        byte[] arr = md.digest(md5.getBytes());
        StringBuffer sb = new StringBuffer();
        for (int i = 0; i < arr.length; ++i)
            sb.append(Integer.toHexString((arr[i] & 0xFF) | 0x100).substring(1,3));

        hash = sb.toString();
    } catch (NoSuchAlgorithmException e) {
        Log.e("MD5", e.getMessage());
    }

    return hash.toUpperCase();
}
Oleg Grabets
quelle
1

Ich habe die folgende Methode verwendet, um mir MD5 zu geben, indem ich einen String übergebe, für den Sie MD5 erhalten möchten

public static String getMd5Key(String password) {

//        String password = "12131123984335";

        try {
            MessageDigest md = MessageDigest.getInstance("MD5");
            md.update(password.getBytes());

            byte byteData[] = md.digest();

            //convert the byte to hex format method 1
            StringBuffer sb = new StringBuffer();
            for (int i = 0; i < byteData.length; i++) {
                sb.append(Integer.toString((byteData[i] & 0xff) + 0x100, 16).substring(1));
            }

            System.out.println("Digest(in hex format):: " + sb.toString());

            //convert the byte to hex format method 2
            StringBuffer hexString = new StringBuffer();
            for (int i = 0; i < byteData.length; i++) {
                String hex = Integer.toHexString(0xff & byteData[i]);
                if (hex.length() == 1) hexString.append('0');
                hexString.append(hex);
            }
            System.out.println("Digest(in hex format):: " + hexString.toString());

            return hexString.toString();

        } catch (Exception e) {
            // TODO: handle exception
        }

        return "";
}
Ghanshyam Patidar
quelle
1

Bitte verwenden Sie SHA-512, MD5 ist unsicher

public static String getSHA512SecurePassword(String passwordToHash) {
    String generatedPassword = null;
    try {
        MessageDigest md = MessageDigest.getInstance("SHA-512");
        md.update("everybreathyoutake".getBytes());
        byte[] bytes = md.digest(passwordToHash.getBytes());
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < bytes.length; i++) {
            sb.append(Integer.toString((bytes[i] & 0xff) + 0x100, 16).substring(1));
        }
        generatedPassword = sb.toString();
    } catch (NoSuchAlgorithmException e) {
        e.printStackTrace();
    }
    return generatedPassword;
}
Carlos Jesus Arancibia Taborga
quelle
0

In anderen Vorschlägen herrscht tatsächlich eine viel zu verschwenderische toHex () - Konvertierung vor.

private static final char[] HEX_ARRAY = "0123456789ABCDEF".toCharArray();

public static String md5string(String s) {
    return toHex(md5plain(s));
}

public static byte[] md5plain(String s) {
    final String MD5 = "MD5";
    try {
        // Create MD5 Hash
        MessageDigest digest = java.security.MessageDigest.getInstance(MD5);
        digest.update(s.getBytes());
        return digest.digest();
    } catch (NoSuchAlgorithmException e) {
        // never happens
        e.printStackTrace();
        return null;
    }
}

public static String toHex(byte[] buf) {
    char[] hexChars = new char[buf.length * 2];
    int v;
    for (int i = 0; i < buf.length; i++) {
        v = buf[i] & 0xFF;
        hexChars[i * 2] = HEX_ARRAY[v >>> 4];
        hexChars[i * 2 + 1] = HEX_ARRAY[v & 0x0F];
    }
    return new String(hexChars);
}
Gena Batsyan
quelle
Die Antwort handelt von einem "besseren" toHex, wenn es sich bei der Quest um MD5 handelt, da es nicht reagiert. Hinweis: Donald Knuth Das eigentliche Problem ist, dass Programmierer viel zu viel Zeit damit verbracht haben, sich an den falschen Orten und zu den falschen Zeiten um die Effizienz zu kümmern. Vorzeitige Optimierung ist die Wurzel allen Übels (oder zumindest des größten Teils davon) in der Programmierung.
Zaph
0

Dies funktioniert perfekt für mich. Ich habe dies verwendet, um MD5 auf dem LIST-Array abzurufen (und es dann in ein JSON-Objekt zu konvertieren), aber wenn Sie es nur auf Ihre Daten anwenden müssen. Geben Sie das Format ein und ersetzen Sie JsonObject durch Ihr Format.

Dies gilt insbesondere dann, wenn Sie mit der Python MD5-Implementierung nicht übereinstimmen.

private static String md5(List<AccelerationSensor> sensor) {

    Gson gson= new Gson();
    byte[] JsonObject = new byte[0];
    try {
        JsonObject = gson.toJson(sensor).getBytes("UTF-8");
    } catch (UnsupportedEncodingException e) {
        e.printStackTrace();
    }

    MessageDigest m = null;

    try {
        m = MessageDigest.getInstance("MD5");
    } catch (NoSuchAlgorithmException e) {
        e.printStackTrace();
    }

    byte[] thedigest = m.digest(JsonObject);
    String hash = String.format("%032x", new BigInteger(1, thedigest));
    return hash;


}
mehran sahandi weit
quelle
-1

Die bereitgestellten Lösungen für die Scala-Sprache (etwas kürzer):

def getMd5(content: Array[Byte]) =
    try {
        val md = MessageDigest.getInstance("MD5")
        val bytes = md.digest(content)
        bytes.map(b => Integer.toHexString((b + 0x100) % 0x100)).mkString
    } catch {
        case ex: Throwable => null
    }
david.perez
quelle