MD5 хеширование в Android
У меня есть простой клиент android, который должен "говорить" с простым слушателем HTTP C#. Я хочу предоставить базовый уровень аутентификации, передавая имя пользователя / пароль в запросах POST.
MD5 хеширование тривиально в C# и обеспечивает достаточную безопасность для моих нужд, но я не могу найти, как это сделать в конце android.
EDIT: просто для решения проблем, поднятых о слабости MD5-сервер C# работает на ПК пользователей моего клиента android. Во многом в случаях, они будут получать доступ к серверу с помощью wi-fi на своих собственных LANs, но, на свой страх и риск, они могут выбрать доступ к нему из интернета. Также службе на сервере необходимо использовать сквозной доступ для MD5 к стороннему приложению, над которым у меня нет контроля.
12 ответов
здесь - это реализация, которую вы можете использовать (обновлено, чтобы использовать более современные соглашения Java -for:each
цикл StringBuilder
вместо StringBuffer
):
public static final 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 считается сломанным и может быть легко использован), этого иногда достаточно для основных задач.
принятый ответ не работа для меня в Android 2.2. Я не знаю почему, но он "съел" некоторые из моих нулей (0) . Apache commons также не работает на Android 2.2, потому что он использует методы, которые поддерживаются только начиная с Android 2.3.X. Кроме того, если вы хотите просто MD5 строку, Apache commons слишком сложен для этого. Зачем держать целую библиотеку использовать только небольшую функцию...
наконец-то я нашел следующий фрагмент кода здесь что отлично сработало для меня. Надеюсь, это кому-то пригодится...
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;
}
androidsnippets.com код не работает надежно, потому что 0, похоже, вырезаны из полученного хэша.
лучшая реализация здесь.
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; }
Если использование кодека Apache Commons является опцией, то это будет более короткая реализация:
String md5Hex = new String(Hex.encodeHex(DigestUtils.md5(data)));
или Ша:
String shaHex= new String(Hex.encodeHex(DigestUtils.sha("textToHash")));
источник для выше.
пожалуйста, перейдите по ссылке и upvote его решение, чтобы наградить правильного человека.
Maven РЕПО ссылка:https://mvnrepository.com/artifact/commons-codec/commons-codec
текущая зависимость Maven (по состоянию на 6 июля 2016 года):
<!-- https://mvnrepository.com/artifact/commons-codec/commons-codec -->
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
<version>1.10</version>
</dependency>
решение выше использования DigestUtils не сработало для меня. В моей версии Apache commons (последней для 2013 года) такого класса нет.
Я нашел другое решение вот в одном блоге. Он работает идеально и не нуждается в Apache commons. Он выглядит немного короче, чем код в принятом ответе выше.
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;
Это небольшая вариация ответов Андраника и Ден Делимарского выше, но ее немного более сжатая и не требует какой-либо побитовой логики. Вместо этого он использует встроенный String.format
метод преобразования байтов в две символьные шестнадцатеричные строки (не удаляет 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;
}
}
Я сделал простую библиотеку в Котлине.
добавить в корневой сборке.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 соответственно.
подробнее о библиотеке
MD5 немного старый, SHA-1-лучший алгоритм,здесь есть пример.
(также, как они отмечают в этом посте, Java обрабатывает это самостоятельно, без конкретного кода для Android.)
в нашем приложении MVC мы генерируем для long param
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 помогает Андранику)
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();
}
я использовал ниже метод, чтобы дать мне 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 "";
}
слишком расточительное преобразование 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);
}
предоставленные решения для языка 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
}