AndroidでのMD5ハッシュ


91

単純なC#HTTPリスナーと「話す」必要がある単純なAndroidクライアントがあります。POSTリクエストでユーザー名/パスワードを渡すことにより、基本レベルの認証を提供したいと考えています。

MD5ハッシュはC#では些細なことであり、私のニーズに十分なセキュリティを提供しますが、Android側でこれを行う方法を見つけることができないようです。

編集:MD5の弱点について提起された懸念に対処するためだけです-C#サーバーは私のAndroidクライアントのユーザーのPCで実行されます。多くの場合、彼らは自分のLANでwi-fiを使用してサーバーにアクセスしますが、自分のリスクで、インターネットからアクセスすることを選択する場合があります。また、サーバー上のサービスは、私が制御できないサードパーティ製アプリケーションへのMD5のパススルーを使用する必要があります。


6
MD5は使用しないでください。SHA512を使用します。
SLaks、2011年

1
どうして?SHA512はMD5よりも難しくありません。5年後にMD5を使用するレガシークライアントに行き詰まるのは望ましくありません。
SLaks、2011年

2
プロトコルでnonceを使用しているので、リプレイ攻撃を破棄できます。
sarnold 2011年

1
@NickJohnson:質問に答えるために、なぜ弱いオプションを故意に選択するのですか?16か月前に投稿した質問にコメントする必要があるのはなぜですか。しかし、あなたが本当に知りたいのであれば(あなたの上のSLakへのコメントを見れば)、それはアルファ段階のコードであり、PC側(私が書いたものではありません)はMD5ハッシュを使用しました。要件は基本的に、余分な複雑さを伴うことのないパススルーシナリオに対するものでした。リスクを知っていた当時、私には10人ほどのアルファ段階テスターがいました。質問してから、より複雑なセキュリティが組み込まれました。
Squonk 2012年

1
...何?いいえ、それは単に間違っているのではなく、危険なほど間違っています。
ニックジョンソン

回答:


231

ここにあなたが使用できる実装があります(より最新のJava規約を使用するように更新されました-の代わりにfor:eachループ):StringBuilderStringBuffer

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

基本レベルのセキュリティ(MD5 は壊れていると見なされ簡単に悪用される可能性があります)を含むシステムには推奨されませんが、基本的なタスクには十分な場合があります。


おかげでうまくいくでしょう。この段階でMD5で十分である理由については、私の編集を参照してください。
Squonk 2011年

6
この下のIMOに投票して、以下のより正確な回答が表示されるようにしてください。
アダム

4
以下の回答のとおり、0は提供されません。
SohailAziz

新しいJava標準(for:each、StringBuilder)を使用するように更新
loeschg 2014年

3
MD5が実装されていない(のスローの原因となるNoSuchAlgorithmException)Androidオペレーティングシステムはありますか?
VSB 2016

50

受け入れられた回答は、Android 2.2では機能しませんでした。理由はわかりませんが、ゼロ(0)の一部を「食べる」ことでした。 また、Apache commonsはAndroid 2.2では動作しませんでした。これは、Android 2.3.x以降でのみサポートされているメソッドを使用しているためです。また、文字列をMD5にしたいだけの場合、Apacheコモンズはそのために複雑すぎます。そこから小さな関数を使用するためにライブラリ全体を保持する必要があるのはなぜですか...

最後に、私は次のコードスニペット見つけ、ここで私のために完全に働きました。私はそれが誰かのために役立つことを願っています...

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
私のために働いた。md5.getBytes( "UTF-8")を変更しました。上記のコードでq4m'x68n6_YDB4ty8VC4&} wqBtn ^ 68Wで確認しました。結果は0c70bb931f03b75af1591f261eb77d0bであり、c70bb931f03b75af1591f261eb77d0bではありません。0が設定されている
イノイ

28

結果のハッシュから0が切り取られているように見えるため、androidsnippets.comコードは確実に機能しません。

より良い実装はこちらです。

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

この場合、Androidで「m」をnullにすることはできますか?
Android開発者

3
@androiddeveloperその通りです。catchブロックの実装が不十分です。returnステートメントが必要です。そうしないと、m.updateが呼び出されたときにnull参照エラーが発生します。また、確かではありませんが、これは個々のバイトの0を削除しない可能性がありますが、32文字のハッシュ全体の先頭の0を削除する可能性はあります。toString(16)の代わりに、String.Format( "%032X"、bigInt)が意図したとおりに機能すると思います。さらに、ヘックスを大文字にするか小文字にするかを選択できます(小文字の場合は "%032x")。
rsimp

1
このバージョンには欠陥があります。MD5が「0」で始まる場合、生成されたMD5は先頭に0がありません。このソリューションは使用しないでください。
elcuco

20

Apache Commons Codecの使用がオプションである場合、これはより短い実装になります。

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

またはSHA:

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

上記のソース

リンクをたどり、彼の解決策に賛成票を投じて正しい人物を表彰してください。


Mavenリポジトリリンク:https : //mvnrepository.com/artifact/commons-codec/commons-codec

現在のMaven依存関係(2016年7月6日現在):

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

1
標準ライブラリにすでに存在するAPIに外部ライブラリを使用する理由は何ですか?
m0skit0

12

上記のDigestUtilsを使用した解決策は私にとってはうまくいきませんでした。私のバージョンのApacheコモンズ(2013年の最新バージョン)では、そのようなクラスはありません。

1つのブログで別の解決策を見つけました。それは完璧に動作し、Apacheコモンズを必要としません。上記の受け入れられた回答のコードよりも少し短く見えます。

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

これらのインポートが必要になります。

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

MD5ハッシュの長さが32文字以下であることを確認することが重要です。ありがとうございます。
Pelanes 2014年

3
最後の数行は、おそらく次のように置き換えることができます。return String.Format( "%032X"、number); そうでなければ私はこの答えが本当に好きです。
rsimp

10

これは上記のAndranikとDen Delimarskyの回答のわずかなバリエーションですが、少し簡潔で、ビットごとのロジックは必要ありません。代わりに、組み込みのString.formatメソッドを使用して、バイトを2つの文字の16進文字列に変換します(0は取り除きません)。通常、私は彼らの答えについてコメントするだけですが、そうする評判はありません。

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

代わりに小文字の文字列を返したい場合は、に変更%02Xしてください%02x

編集:BigIntegerをwzbozonの回答と同様に使用すると、回答をさらに簡潔にすることができます。

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で簡単なライブラリを作成しました。

ルートbuild.gradleに追加

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

アプリbuild.gradleで

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

使用法

コトリンで

val ob = Hasher()

次にhash()メソッドを使用します

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

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

MD5とSHA-1をそれぞれ返します。

ライブラリの詳細

https://github.com/ihimanshurawat/Hasher


2

@Andranik回答のKotlinバージョンを以下に示します。に変更getBytesしてtoByteArray(デフォルトの文字セットはUTF-8であるため、文字セットUTF-8を追加する必要はありませんtoByteArray)、array [i]を整数にキャストする必要があります。

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
}

それが役に立てば幸い


1

MVCアプリケーションでは、長いパラメーター用に生成します

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

そしてAndroidアプリケーションでも同じです(thenkは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();
}

1

私はあなたがmd5を取得したい文字列を渡すことでmd5を与えるために以下の方法を使用しました

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

SHA-512を使用してください。MD5は安全ではありません

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は少し古く、SHA-1はより優れたアルゴリズムですここに例があります

また、彼らがその投稿で指摘しているように、Javaは独自にこれを処理し、Android固有のコードは処理しません。


4
いいえ-2011年1月(19か月前)にこの質問をしたとき、MD5に代わるものを望んでいませんでした。この時点で私の質問に答える必要性を感じた理由がわかりません。
Squonk 2012

21
@Squonk私が答えたのは、それがstackoverflowの背後にある一般的な考え方だからです。事後何年経っても、後で質問に遭遇する可能性のある人々のために、常により良い答えを得るようにしてください。SHA-1を提案することに関しては、あなたがSHA-1に明確に反対していることを知る方法はありませんでしたが、他の多くはそうではないので、これは、これに遭遇した将来の他の人々を助け、彼らに指示するかもしれませんより近代的なアルゴリズムに。
アダム

3
MD5が悪い選択でSHA1が良い選択という単一の状況を考えることはできません。衝突抵抗が必要な場合は、SHA1ではなくSHA2が必要です。パスワードをハッシュする場合は、bcryptまたはPBKDF2が必要です。または、OPの場合、適切なソリューションはおそらくSSLです。
CodesInChaos 2014

3
@Adamこれは回答ではなく、これはコメントです。
Antzi

0

あまりにも無駄なtoHex()変換は、実際には他の提案で優勢です。

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

答えは、クエストがMD5に関するものである場合、「より良い」toHexに関するものです。注:ドナルドクヌース本当の問題は、プログラマーが間違った場所や間違った時間での効率を心配するのに非常に多くの時間を費やしていることです。時期尚早な最適化は、プログラミングにおけるすべての悪(または少なくともその大部分)の原因です。
zaph 2016年

0

これは私にとっては完璧に機能しています。これを使用してLISTアレイでMD5を取得し(それをJSONオブジェクトに変換します)、データにのみ適用する必要がある場合。形式を入力し、JsonObjectをyoursに置き換えます。

特に、Python MD5実装との不一致がある場合は、これを使用してください。

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;


}

-1

Scala言語用に提供されているソリューション(少し短い):

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
    }
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.