Android'de MD5 karma oluşturma


92

Basit bir C # HTTP dinleyicisiyle 'konuşması' gereken basit bir android istemcim var. POST isteklerinde kullanıcı adı / şifreyi geçirerek temel bir kimlik doğrulama düzeyi sağlamak istiyorum.

MD5 hashing, C # için önemsizdir ve ihtiyaçlarım için yeterli güvenlik sağlar, ancak bunu android tarafında nasıl yapacağımı bulamıyorum.

DÜZENLEME: Sadece MD5 zayıflığı ile ilgili endişeleri gidermek için - C # sunucusu android istemcimin kullanıcılarının bilgisayarlarında çalışıyor. Çoğu durumda, sunucuya kendi LAN'larında wi-fi kullanarak erişeceklerdir, ancak kendi riskleri dahilinde, internetten erişmeyi seçebilirler. Ayrıca, sunucudaki hizmetin MD5 için üzerinde kontrolüm olmayan bir 3. taraf uygulamasına geçiş kullanması gerekiyor.


6
MD5 kullanmayın. SHA512'yi kullanın.
SLaks

1
Neden? SHA512, MD5'ten daha zor değildir. MD5 kullanan eski istemcilerle beş yıl sonra takılıp kalmak istemezsiniz.
SLaks

2
Umarım protokolünüzde bir nonce kullanıyorsunuzdur, böylece tekrarlama saldırılarını atabilirsiniz.
sarnold

1
@NickJohnson: Sorunuzu yanıtlamak için neden kasıtlı olarak daha zayıf seçeneği seçiyorsunuz ? başka bir soruyla ... 16 ay önce göndermiş olduğum bir soruya neden yorum yapma ihtiyacı duyuyorsunuz? Ama gerçekten bilmek istiyorsanız (sizinkinin üzerindeki SLaks'a yapılan yoruma bakarsanız), bu alfa aşama koduydu ve PC ucu (benim tarafımdan yazılmamış) MD5 hashing kullanıyordu. Gereksinim, temelde ekstra karmaşıklık içermeyen bir geçiş senaryosu içindi. O sırada riskleri bilen yaklaşık 10 alfa aşaması test edicim vardı. Soruyu sorduğumdan beri daha karmaşık güvenlik dahil edildi.
Squonk

1
...ne? Hayır, bu sadece yanlış değil, tehlikeli derecede yanlış.
Nick Johnson

Yanıtlar:


232

İşte kullanabileceğiniz bir uygulama (daha güncel Java kuralları kullanmak için güncellendi - for:eachdöngü StringBuilderyerine 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 "";
}

Temel düzeyde güvenlik içeren sistemler için tavsiye edilmese de (MD5 bozuk olarak kabul edilir ve kolayca kullanılabilir ), bazen temel görevler için yeterlidir.


Teşekkürler, hile yapacak. MD5'in neden bu aşamada yeterli olacağını öğrenmek için düzenlememe bakın.
Squonk

7
Aşağıdakilerden daha doğru yanıtların ortaya çıkması için bunu IMO'yu aşağı oylayın.
Adam

4
Aşağıda yanıtlandığı gibi 0 beslenmemiştir.
SohailAziz

Daha yeni java standartlarını kullanmak üzere güncellendi (için: her biri, StringBuilder)
loeschg

3
MD5 uygulanmamış herhangi bir android işletim sistemi var NoSuchAlgorithmExceptionmı (fırlatmaya neden olur )?
VSB

51

Kabul edilen cevap Android 2.2'de benim için işe yaramadı. Nedenini bilmiyorum ama bazı sıfırlarımı (0) "yiyordu". Apache commons , yalnızca Android 2.3.x'ten itibaren desteklenen yöntemleri kullandığı için Android 2.2'de de çalışmadı. Ayrıca, bir dizgeyi sadece MD5 istiyorsanız, Apache commons bunun için çok karmaşıktır. Neden küçük bir işlevi kullanmak için bütün bir kitaplığı saklamalı ...

Sonunda burada benim için mükemmel çalışan aşağıdaki kod parçacığını buldum . Umarım birisi için faydalı olur ...

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;
}

4
Benim için çalıştı. Ben değiştim md5.getBytes ( "UTF-8") . Ben onu kontrol ettim: q4m'x68n6_YDB4ty8VC4 &} wqBtn ^ 68W yukarıdaki kod ile, sonucudur 0c70bb931f03b75af1591f261eb77d0b DEĞİL, c70bb931f03b75af1591f261eb77d0b . 0 yerinde
Inoy

29

Androidsnippets.com kodu güvenilir bir şekilde çalışmıyor, çünkü sonuçta elde edilen hash'den 0'lar kesilmiş gibi görünüyor.

Daha iyi bir uygulama burada .

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;
}

Bu durumda "m" Android'de boş olabilir mi?
android geliştiricisi

3
@androiddeveloper Kesinlikle haklısın. Catch bloğu burada zayıf bir şekilde uygulanmıştır, bir return ifadesi olması gerekir veya m.update çağrıldığında boş bir referans hatası olacaktır. Ayrıca emin değilim, ancak bu tek tek baytlarda 0'ları soymayabilir, ancak yine de 32 karakterlik karmanın tümünde 0'ların başını kaldırabileceğini düşünüyorum. ToString (16) yerine String.Format ("% 032X", bigInt) amaçlandığı gibi çalışıyor. Ayrıca, onaltılık harfin büyük veya küçük harf olmasını isteyip istemediğinizi de seçebilirsiniz (küçük harf için "% 032x").
rsimp

1
Bu sürüm kusurlu. MD5'iniz "0" ile başlıyorsa, oluşturulan MD5'in başında 0 olmayacaktır. Lütfen bu çözümü kullanmayın.
elcuco

21

Apache Commons Codec'i kullanmak bir seçenekse, bu daha kısa bir uygulama olacaktır:

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

Veya SHA:

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

Yukarıdakiler için kaynak .

Lütfen bağlantıyı takip edin ve doğru kişiyi ödüllendirmek için çözümünü yükseltin.


Maven repo bağlantısı: https://mvnrepository.com/artifact/commons-codec/commons-codec

Mevcut Maven bağımlılığı (6 Temmuz 2016 itibariyle):

<!-- https://mvnrepository.com/artifact/commons-codec/commons-codec -->
<dependency>
    <groupId>commons-codec</groupId>
    <artifactId>commons-codec</artifactId>
    <version>1.10</version>
</dependency>

1
Standart kitaplıkta zaten var olan bir API için harici bir kitaplık kullanmanızın herhangi bir nedeni var mı?
m0skit0

12

DigestUtils kullanarak yukarıdaki bir çözüm benim için işe yaramadı. Apache commons sürümümde (2013 için en son sürüm) böyle bir sınıf yok.

Burada bir blogda başka bir çözüm buldum . Mükemmel çalışır ve Apache commons'a ihtiyaç duymaz. Yukarıdaki kabul edilen cevaptaki koddan biraz daha kısa görünüyor.

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;
    }
}

Bu ithalatlara ihtiyacınız olacak:

import java.math.BigInteger;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

MD5 hash değerinin 32 karakter veya daha kısa olduğunu bilmek önemlidir, teşekkür ederim!
Pelanes

3
Son birkaç satır muhtemelen şununla değiştirilebilir: return String.Format ("% 032X", sayı); Aksi takdirde bu cevabı gerçekten çok beğendim.
rsimp

10

Bu, Andranik ve Den Delimarsky'nin yukarıdaki cevaplarının küçük bir varyasyonudur, ancak biraz daha özlüdür ve bitsel mantık gerektirmez. Bunun yerine String.format, baytları iki karakterli onaltılık dizelere dönüştürmek için yerleşik yöntemi kullanır (0'ları soymaz). Normalde cevapları hakkında yorum yapardım ama bunu yapacak saygınlığım yok.

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;
    }
}

Bunun yerine bir küçük harf dizesi dönmek isterseniz, o zaman sadece değiştirmek %02Xiçin %02x.

Düzenleme: BigInteger'ı wzbozon'un cevabında olduğu gibi kullanarak, cevabı daha da kısa hale getirebilirsiniz:

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;
    }
}

4

Kotlin'de basit bir Kütüphane yaptım.

Kök build.gradle'a ekleyin

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

App build.gradle adresinde

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

Kullanım

Kotlin'de

val ob = Hasher()

Ardından hash () yöntemini kullanın

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

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

Sırasıyla MD5 ve SHA-1'i döndürecektir.

Kütüphane hakkında daha fazla bilgi

https://github.com/ihimanshurawat/Hasher


3

İşte @Andranik cevabından Kotlin versiyonu. Biz değişime ihtiyaç getBytesiçin toByteArray(varsayılan charset çünkü charset utf-8 eklemek gerekmez toByteArraytamsayıya ve dökme dizisi [i] UTF-8)

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
}

Umarım yardımcı olur


1

MVC uygulamamızda uzun param için ürettiğimiz

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;
    }

ve Android uygulamasında aynı (thenk, Andranik'e yardım ediyor)

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();
}

1

md5 almak istediğiniz dizeyi geçerek bana md5 vermek için aşağıdaki yöntemi kullandım

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 "";
}

1

Lütfen SHA-512 kullanın, MD5 güvenli değil

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;
}

0

MD5 biraz eski, SHA-1 daha iyi bir algoritmadır, burada bir örnek var .

( Ayrıca bu gönderide belirttikleri gibi, Java bunu kendi başına hallediyor, Android'e özel kod yok. )


4
Hayır - Ocak 2011'de (19 ay önce) bu soruyu sorduğumda MD5'in alternatiflerini istemedim ve bu noktada soruma yanıt verme ihtiyacını neden hissettiğinden emin değilim.
Squonk

21
@Squonk Yanıt verdim çünkü stackoverflow'un arkasındaki genel fikir bu. Olaydan ne kadar sonra olursa olsun, soruyla daha sonra karşılaşabilecek kişiler için daima daha iyi yanıtlar almaya çalışın. SHA-1'i önermeye gelince, özellikle SHA-1'e karşı olduğunuzu bilmemin bir yolu yoktu, ancak diğerleri olmayacak, bu yüzden gelecekte bununla karşılaşan diğer insanlara yardımcı olabilir ve onları yönlendirebilir daha modern bir algoritmaya.
Adam

3
MD5'in kötü bir seçim olduğu, ancak SHA1'in iyi bir seçim olduğu tek bir durum düşünemiyorum. Çarpışma direncine ihtiyacınız varsa, SHA1'e değil SHA2'ye ihtiyacınız var. Şifreleri karıştırırsanız, bcrypt veya PBKDF2'ye ihtiyacınız vardır. Veya OP'nin durumunda uygun çözüm muhtemelen SSL'dir.
CodesInChaos

3
@Adam bu bir cevap değil, bu bir yorum.
Antzi

0

Gerçekten çok fazla savurgan toHex () dönüşümü diğer önerilerde hakimdir.

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);
}

Cevap MD5 ile ilgili olduğu için "daha iyi" bir toHex hakkındadır, bu nedenle yanıt vermez. Not: Donald Knuth Gerçek sorun, programcıların yanlış yerlerde ve yanlış zamanlarda verimlilik konusunda endişelenmek için çok fazla zaman harcamalarıdır; erken optimizasyon, programlamadaki tüm kötülüklerin (veya en azından çoğunun) köküdür.
zaph

0

bu benim için mükemmel çalışıyor, bunu LIST Array üzerinde MD5 elde etmek için kullandım (sonra onu JSON nesnesine dönüştürdüm), ancak yalnızca verilerinize uygulamanız gerekiyorsa. format yazın, JsonObject'i sizinkiyle değiştirin.

Özellikle python MD5 uygulamasıyla uyumsuzluğunuz varsa bunu kullanın!

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;


}

0

Faydalı Kotlin Uzantı Fonksiyonu Örneği

fun String.toMD5(): String {
    val bytes = MessageDigest.getInstance("MD5").digest(this.toByteArray())
    return bytes.toHex()
}

fun ByteArray.toHex(): String {
    return joinToString("") { "%02x".format(it) }
}

-1

Scala dili için sağlanan çözümler (biraz daha kısa):

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
    }
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.