Как я могу сгенерировать хеш MD5?

Есть ли способ сгенерировать хеш MD5 строки в Java?


person Akshay    schedule 06.01.2009    source источник
comment
stackoverflow.com/questions/304268 /   -  person Leif Gruenwoldt    schedule 08.09.2012
comment
MD5 может быть небезопасным как односторонняя функция безопасности, но он по-прежнему хорош для общих приложений контрольной суммы.   -  person rustyx    schedule 06.02.2015
comment
вы можете попробовать на php, очень легко решается.   -  person Anupam Haldkar    schedule 10.05.2020


Ответы (33)


Вам понадобится _1 _ .

Вызов _ 2_, чтобы получить MD5-экземпляр MessageDigest, который вы можете использовать.

Вычислить хэш, выполнив одно из следующих действий:

  • Подайте весь ввод как byte[] и вычислите хэш за одну операцию с помощью _ 5_.
  • Подавать MessageDigest по одному byte[] фрагменту за раз, вызывая _ 8_. Когда вы закончите добавлять входные байты, вычислите хэш с помощью _ 9_.

byte[], возвращаемый md.digest(), является хешем MD5.

person Bombe    schedule 06.01.2009
comment
Одна вещь, о которой здесь не упоминается, застала меня врасплох. Классы MessageDigest НЕ являются потокобезопасными. Если они будут использоваться разными потоками, просто создайте новый, вместо того, чтобы пытаться использовать их повторно. - person mjuarez; 07.03.2013
comment
Он использует несколько методов для изменения своего внутреннего состояния. Как вообще может удивлять отсутствие безопасности потоков? - person Bombe; 25.04.2013
comment
@Bombe: почему мы должны ожидать иметь информацию о внутреннем состоянии MessageDigest? - person Dan Barowy; 01.07.2014
comment
@DanBarowy ну, вы изменяете его (т.е. вызываете методы, которые не возвращают значения, но заставляют другие методы возвращать другие значения), поэтому, пока не будет доказано обратное, вы всегда должны предполагать, что это небезопасно для потоков. . - person Bombe; 09.07.2014
comment
@Traubenfuchs MessageDigest позволяет вводить данные по частям. Это было бы невозможно со статическим методом. Хотя вы можете утверждать, что им все равно следовало добавить один для удобства, когда вы можете передавать все данные сразу. - person user253751; 16.08.2015
comment
Имеет смысл. Я думаю, вы не всегда хотели бы перемещать байтовые массивы с несколькими гигабайтами! Тем не менее, просто позвольте ему взять поток. - person ASA; 17.08.2015
comment
@Traubenfuchs, и что он будет делать с байтами, прочитанными из этого потока, выбросить их? - person kbolino; 28.05.2016
comment
Думаю, когда я писал это, я думал о доработанном и готовом к употреблению InputStream, который будет полностью истощен статическим методом. Любое необходимое состояние будет сохранено в теле метода. - person ASA; 28.05.2016
comment
Это не ответ на вопрос, это всего лишь пара ссылок. stackoverflow.com/help/how-to-answer - person Fran Marzoa; 20.02.2018

Класс MessageDigest может предоставить вам экземпляр дайджеста MD5.

При работе со строками и криптографическими классами обязательно всегда указывайте кодировку, в которой вы хотите представлять байтовое представление. Если вы просто используете string.getBytes(), будет использоваться платформа по умолчанию. (Не все платформы используют одни и те же значения по умолчанию)

import java.security.*;

..

byte[] bytesOfMessage = yourString.getBytes("UTF-8");

MessageDigest md = MessageDigest.getInstance("MD5");
byte[] thedigest = md.digest(bytesOfMessage);

Если у вас много данных, обратите внимание на метод .update(byte[]), который можно вызывать повторно. Затем вызовите .digest(), чтобы получить результирующий хеш.

person koregan    schedule 06.01.2009
comment
«LATIN1»! = «ASCII» (или «US-ASCII»). ASCII - это 7-битный набор символов, Latin1 - 8-битный набор символов. Они не одинаковы. - person Bombe; 07.01.2009
comment
(см. joelonsoftware.com/articles/Unicode.html для лучшего обоснования и объяснения) - person Piskvor left the building; 07.01.2009
comment
Эта тема также полезна, если вам нужно преобразовать полученные байты в шестнадцатеричную строку. - person weekens; 22.05.2012
comment
а что, если мне нужна чистая строка? - person albanx; 05.11.2015
comment
@albanx: чистой строки не существует, если только вы не имели в виду сериализованное содержимое самого объекта Java. Пожалуйста, обратитесь к ранее размещенной ссылке на Joel On Software. - person Daniel Kamil Kozar; 21.02.2016
comment
@DanielKamilKozar Мне нужна была шестнадцатеричная строка для сохранения в БД. dac2009 опубликовал решение для этого - person albanx; 21.02.2016
comment
Это было очень легко и просто, я бы порекомендовал это всем посетителям. - person Humphrey; 03.11.2017
comment
Тогда как преобразовать этот дайджест в строку, чтобы мы могли вставить его в mysql? - person Humphrey; 08.11.2017
comment
А еще лучше, где возможно, используйте yourString.getBytes(StandardCharsets.UTF_8). Это предотвращает обработку UnsupportedEncodingException. - person Hummeling Engineering BV; 07.03.2019

Если вы действительно хотите получить ответ в виде строки, а не массива байтов, вы всегда можете сделать что-то вроде этого:

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;
}
person user49913    schedule 07.01.2009
comment
@BalusC: неверно, метод BigInteger.toString вернет полное число в указанной базе. 0x0606 будет напечатан как 606, только конечные нули опущены, - person Spidey; 30.08.2010
comment
Незначительная придирка: m.reset () не требуется сразу после вызова getInstance. Более мелкие: «ваш текст здесь» требует двойных кавычек. - person David Leppik; 19.04.2011
comment
Начиная с Java 11, вы можете использовать hashtext = "0".repeat(32 - hashtext.length()) + hashtext вместо while, поэтому редакторы не будут предупреждать вас о том, что вы выполняете конкатенацию строк внутри цикла. - person tom; 14.05.2019
comment
Вместо m.update (plaintext.getBytes ()); Я бы рекомендовал указать кодировку. например m.update (plaintext.getBytes (UTF-8)); getBytes () не гарантирует кодировку и может варьироваться от системы к системе, что может привести к разным результатам MD5 между системами для одной и той же строки. - person user1819780; 27.03.2020

Вы также можете посмотреть ссылку DigestUtils проекта commons codec проекта apache , который предоставляет очень удобные методы для создания дайджестов MD5 или SHA.

person lutzh    schedule 06.01.2009
comment
В частности, методы, которые возвращают безопасные закодированные представления байтовых данных в строковой форме. - person Rob; 07.01.2009
comment
Однако нет простого способа добавить класс DigestUtils в ваш проект без добавления тонны библиотек или переноса класса на руку, что требует как минимум еще двух классов. - person iuiz; 24.07.2011
comment
Не могу найти его и в репозиториях maven. Grrrr. - person sparkyspider; 04.10.2011
comment
Должен быть в центральных репозиториях Maven, если я не схожу с ума: groupId = commons-codec artifactId = commons-codec version = 1.5 - person Nick Spacek; 12.10.2011

Нашел это:

public String MD5(String md5) {
   try {
        java.security.MessageDigest md = java.security.MessageDigest.getInstance("MD5");
        byte[] array = md.digest(md5.getBytes());
        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) {
    }
    return null;
}

на сайте ниже, я не беру на себя ответственность за это, но это решение, которое работает! Для меня много другого кода не работало должным образом, я пропустил нули в хэше. Кажется, это то же самое, что и в PHP. источник: http://m2tec.be/blog/2010/02/03/java-md5-hex-0093

person dac2009    schedule 03.07.2011
comment
Вы должны указать кодировку, которая будет использоваться в getBytes(), иначе ваш код будет иметь разные результаты на разных платформах / пользовательских настройках. - person Paŭlo Ebermann; 04.07.2011
comment
@ PaŭloEbermann делает MessageDigest.getInstance (MD5); недостаточно? Я попытался добавить MD5 в getBytes (), но он вернул ошибку - person Blaze Tama; 19.02.2014
comment
@BlazeTama MD5 - это не кодировка, это алгоритм дайджеста сообщения (и не тот, который следует использовать в новых приложениях). Кодирование - это пара алгоритмов, которая преобразует байты в строки и строки в байты. Примером может быть UTF-8, US-ASCII, ISO-8859-1, UTF-16BE и т.п. Используйте ту же кодировку, что и любая другая сторона, которая вычисляет хэш этой строки, иначе вы получите разные результаты. - person Paŭlo Ebermann; 21.02.2014
comment
В качестве примера набора символов ... (используйте UTF-8, который, на мой взгляд, является лучшим и наиболее совместимым) ... byte[] array = md.digest(md5.getBytes(Charset.forName("UTF-8"))); - person Richard; 25.11.2014
comment
Поскольку это не мое решение, и я сам не тестировал все сценарии, я оставлю его без изменений, хотя я думаю, что указание кодировки и т. Д., Вероятно, является хорошей идеей. - person dac2009; 08.07.2019

Вот как я его использую:

final MessageDigest messageDigest = MessageDigest.getInstance("MD5");
messageDigest.reset();
messageDigest.update(string.getBytes(Charset.forName("UTF8")));
final byte[] resultByte = messageDigest.digest();
final String result = new String(Hex.encodeHex(resultByte));

где Hex: org.apache.commons.codec.binary.Hex из проекта Apache Commons.

person adranale    schedule 01.10.2010
comment
Если вы все равно используете кодек Apache Commons, вы можете использовать: commons.apache.org/codec/api-release/org/apache/commons/codec/ - person squiddle; 25.10.2010
comment
Я бы заменил последнюю строку на это: String result = Hex.encodeHexString(resultByte); - person bluish; 24.05.2011

Я только что загрузил commons-codec.jar и получил идеальный php, такой как md5. Вот руководство .

Просто импортируйте его в свой проект и используйте

String Url = "your_url";

System.out.println( DigestUtils.md5Hex( Url ) );

и вот оно что.

person Eugene    schedule 30.07.2011
comment
Это метод, который обеспечивает то же возвращаемое значение, что и функция MySQL md5 (str). Многие другие ответы вернули другие значения. - person rwitzel; 18.03.2015
comment
Это не работает правильно на Android, потому что Android связывает commons-codec 1.2, для которого вам нужен этот обходной путь: stackoverflow.com/a/9284092 / 2413303 - person EpicPandaForce; 19.03.2015

Я считаю, что это наиболее четкий и краткий способ сделать это:

MessageDigest md5 = MessageDigest.getInstance("MD5");
md5.update(StandardCharsets.UTF_8.encode(string));
return String.format("%032x", new BigInteger(1, md5.digest()));
person rednoah    schedule 08.05.2015
comment
Большой. Он не попадает в ловушку вырезания ведущих нулей. - person Markus Pscheidt; 10.06.2016
comment
Помните, что это не сработает для Android, если вы используете уровень API 19, но вам просто нужно изменить вторую строку с помощью md5.update (string.getBytes (UTF-8)); Это добавит еще одно проверенное исключение для обработки, хотя ... - person Fran Marzoa; 20.02.2018

Другая реализация:

import javax.xml.bind.DatatypeConverter;

String hash = DatatypeConverter.printHexBinary( 
           MessageDigest.getInstance("MD5").digest("SOMESTRING".getBytes("UTF-8")));
person stacker    schedule 24.04.2014
comment
Я видел только однострочник, который не использует внешнюю библиотеку. - person holmis83; 07.02.2017
comment
Если я не ошибаюсь, это всегда возвращается в верхнем регистре, что не будет соответствовать md5, сделанному без использования шестнадцатеричного кода. Даже не совсем уверен, что это настоящий md5 - person walshie4; 29.06.2017

Нашел это решение, которое намного чище с точки зрения получения представления String из хеша MD5.

import java.security.*;
import java.math.*;

public class MD5 {
    public static void main(String args[]) throws Exception{
        String s="This is a test";
        MessageDigest m=MessageDigest.getInstance("MD5");
        m.update(s.getBytes(),0,s.length());
        System.out.println("MD5: "+new BigInteger(1,m.digest()).toString(16));
    }
}

Код был извлечен здесь.

person Heshan Perera    schedule 10.05.2012
comment
Почему у этого ответа -1, а у другого, более короткого и менее информативного ответа +146? - person Nilzor; 12.02.2013
comment
Приятно использовать BigInteger для получения шестнадцатеричного значения +1 - person Dave.B; 14.03.2013
comment
Я только что узнал, что в некоторых случаях это генерирует только сумму MD5 длиной 31 символ, а не 32, как должно быть - person kovica; 29.03.2013
comment
@kovica, это потому, что начальные нули обрезаются, если я правильно помню .. String.format("%032x", new BigInteger(1, hash)); Это должно решить эту проблему. «хеш» - это байт [] хеша. - person Heshan Perera; 01.04.2013
comment
В этом ответе есть ошибка с типом кодировки! - person Dawid Drozd; 13.04.2015
comment
@HeshanPerera Как получилось, что вы упомянули в своем ответе о получении представления String из хэша MD5 !!? Но ваш код показывает логику преобразования String в хеш Md5. Если я не ошибаюсь, хеш MD5 - это односторонний алгоритм, и его нельзя преобразовать обратно в исходную строку. - person supernova; 17.09.2015
comment
Это кажется намного лучше. Вам даже не нужно фиксировать столько исключений. - person JGFMK; 03.01.2020

Другой вариант - использовать методы хеширования Guava:

Hasher hasher = Hashing.md5().newHasher();
hasher.putString("my string");
byte[] md5 = hasher.hash().asBytes();

Удобно, если вы уже используете Guava (что, если вы этого не сделаете, вам, вероятно, следует).

person andrewrjones    schedule 12.11.2012
comment
или используя один из быстрых методов: Hashing.md5().hashString("my string").asBytes(); - person Kurt Alfred Kluever; 17.11.2015
comment
@KurtAlfredKluever, не забудьте вставить кодировку вроде 'Hashing.md5 (). HashString (моя строка, Charsets.UTF_8) .asBytes ()' - person Justin; 21.04.2016

Не нужно усложнять его.
DigestUtils отлично работает и позволяет удобно работать с md5 хешами.

DigestUtils.md5Hex(_hash);

or

DigestUtils.md5(_hash);

Либо вы можете использовать любые другие методы шифрования, такие как sha или md.

person Fatih Karatana    schedule 31.10.2012

У меня есть класс (Hash) для преобразования простого текста в хеш в форматах: md5 или sha1, аналогично функциям php (md5, sha1):

public class Hash {
    /**
     * 
     * @param txt, text in plain format
     * @param hashType MD5 OR SHA1
     * @return hash in hashType 
     */
    public static String getHash(String txt, String hashType) {
        try {
                    java.security.MessageDigest md = java.security.MessageDigest.getInstance(hashType);
                    byte[] array = md.digest(txt.getBytes());
                    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) {
                //error action
            }
            return null;
    }

    public static String md5(String txt) {
        return Hash.getHash(txt, "MD5");
    }

    public static String sha1(String txt) {
        return Hash.getHash(txt, "SHA1");
    }
}

Тестирование с JUnit и PHP

Скрипт PHP:

<?php

echo 'MD5 :' . md5('Hello World') . "\n";
echo 'SHA1:' . sha1('Hello World') . "\n";

Выходной PHP-скрипт:

MD5 :b10a8db164e0754105b7a99be72e3fe5
SHA1:0a4d55a8d778e5022fab701977c5d840bbc486d0

Используя пример и тестирование с JUnit:

    public class HashTest {

    @Test
    public void test() {
        String txt = "Hello World";
        assertEquals("b10a8db164e0754105b7a99be72e3fe5", Hash.md5(txt));
        assertEquals("0a4d55a8d778e5022fab701977c5d840bbc486d0", Hash.sha1(txt));
    }

}

Код в GitHub

https://github.com/fitorec/java-hashes

person fitorec    schedule 11.08.2014
comment
Как сказал @CedricSimon, это именно то, что я искал. Проголосовать здесь .. Спасибо! - person Joabe Lucena; 02.12.2016

Мой не очень показательный ответ:

private String md5(String s) {
    try {
        MessageDigest m = MessageDigest.getInstance("MD5");
        m.update(s.getBytes(), 0, s.length());
        BigInteger i = new BigInteger(1,m.digest());
        return String.format("%1$032x", i);         
    } catch (NoSuchAlgorithmException e) {
        e.printStackTrace();
    }
    return null;
}
person marioosh    schedule 17.04.2012
comment
и String.format("%1$032X", big) для формата в верхнем регистре - person alex; 23.05.2014

В Spring также есть класс DigestUtils:

http://static.springsource.org/spring/docs/3.0.x/javadoc-api/org/springframework/util/DigestUtils.html.

Этот класс содержит метод md5DigestAsHex(), который выполняет эту работу.

person Raul Luna    schedule 13.09.2012
comment
Кстати: производительность этого намного лучше, чем при использовании BigInteger для создания шестнадцатеричного строкового представления. - person James; 17.04.2018

Вы можете попробовать следующее. Подробную информацию и коды загрузки можно найти здесь: http://jkssweetlife.com/java-hashgenerator-md5-sha-1/

import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

public class MD5Example {

public static void main(String[] args) throws Exception {

    final String inputString = "Hello MD5";

    System.out.println("MD5 hex for '" + inputString + "' :");
    System.out.println(getMD5Hex(inputString));
}

public static String getMD5Hex(final String inputString) throws NoSuchAlgorithmException {

    MessageDigest md = MessageDigest.getInstance("MD5");
    md.update(inputString.getBytes());

    byte[] digest = md.digest();

    return convertByteToHex(digest);
}

private static String convertByteToHex(byte[] byteData) {

    StringBuilder sb = new StringBuilder();
    for (int i = 0; i < byteData.length; i++) {
        sb.append(Integer.toString((byteData[i] & 0xff) + 0x100, 16).substring(1));
    }

    return sb.toString();
}
}
person ylu    schedule 12.03.2014

Ответ Bombe правильный, однако обратите внимание, что, если вы не должны использовать MD5 (например, принудительно для взаимодействия), лучшим выбором будет SHA1, поскольку MD5 имеет слабые места для длительного использования.

Добавлю, что SHA1 тоже имеет теоретические уязвимости, но не такие серьезные. Текущее состояние хеширования состоит в том, что существует ряд хэш-функций для замены кандидатов, но ни одна из них еще не стала стандартной передовой практикой для замены SHA1. Итак, в зависимости от ваших потребностей вам будет полезно сделать свой алгоритм хеширования настраиваемым, чтобы его можно было заменить в будущем.

person frankodwyer    schedule 06.01.2009
comment
Не могли бы вы указать мне на некоторые ресурсы, где я могу прочитать об относительных достоинствах и недостатках каждого из них? - person Akshay; 06.01.2009
comment
Вероятно, лучшее, что вы можете сделать на данный момент, - это использовать SHA1 и быть готовым заменить его в будущем. Вы можете использовать более новые функции, но они еще не были предметом большого количества исследований. Вы можете отслеживать онлайн-ресурсы по безопасности, чтобы узнать, когда это изменится - например, блог Брюса Шнайера. - person frankodwyer; 06.01.2009
comment
SHA1 является излишним, если вам не нужен криптографически безопасный хэш, то есть вы не хотите, чтобы хеш помогал реконструировать исходное сообщение, и при этом вы не хотите, чтобы умный злоумышленник создал другое сообщение, которое соответствует хешу. Если оригинал не является секретом и хэш не используется для безопасности, MD5 будет быстрым и простым. Например, Google Web Toolkit использует хэши MD5 в URL-адресах JavaScript (например, foo.js? Hash = 12345). - person David Leppik; 19.04.2011

Другая реализация: Быстрая реализация MD5 на Java

String hash = MD5.asHex(MD5.getHash(new File(filename)));
person Lukasz R.    schedule 16.03.2011
comment
Это надежная автономная библиотека с минимальными зависимостями. Хорошая вещь. - person Ajax; 22.03.2014
comment
Я нахожу это очень полезным. Для файла размером 4,57 ГБ потребовалось 15357 мс, тогда как для встроенной реализации Java потребовалось 19094 мс. - person bkrish; 02.05.2016
comment
Это было очень полезно. У меня возникли проблемы с MessageDigest.getInstance (MD5). - person arun; 19.09.2020

Я не знаю, актуально ли это для всех, кто это читает, но у меня просто возникла проблема, которую я хотел

  • скачать файл с заданного URL и
  • сравните его MD5 с известным значением.

Я хотел сделать это только с классами JRE (без Apache Commons или подобных). Быстрый поиск в Интернете не показал мне примеров фрагментов кода, выполняющих оба одновременно, только каждую задачу отдельно. Поскольку для этого требуется дважды прочитать один и тот же файл, я подумал, что, возможно, стоит написать код, который объединяет обе задачи, вычисляя контрольную сумму на лету при загрузке файла. Это мой результат (извините, если это не идеальная Java, но я думаю, вы все равно поняли идею):

import java.io.FileOutputStream;
import java.io.IOException;
import java.math.BigInteger;
import java.net.URL;
import java.nio.ByteBuffer;
import java.nio.channels.Channels;
import java.nio.channels.ReadableByteChannel;
import java.nio.channels.WritableByteChannel;
import java.security.DigestOutputStream;        // new
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

void downloadFile(String fromURL, String toFile, BigInteger md5)
    throws IOException, NoSuchAlgorithmException
{
    ReadableByteChannel in = Channels.newChannel(new URL(fromURL).openStream());
    MessageDigest md5Digest = MessageDigest.getInstance("MD5");
    WritableByteChannel out = Channels.newChannel(
        //new FileOutputStream(toFile));  // old
        new DigestOutputStream(new FileOutputStream(toFile), md5Digest));  // new
    ByteBuffer buffer = ByteBuffer.allocate(1024 * 1024);  // 1 MB

    while (in.read(buffer) != -1) {
        buffer.flip();
        //md5Digest.update(buffer.asReadOnlyBuffer());  // old
        out.write(buffer);
        buffer.clear();
    }

    BigInteger md5Actual = new BigInteger(1, md5Digest.digest()); 
    if (! md5Actual.equals(md5))
        throw new RuntimeException(
            "MD5 mismatch for file " + toFile +
            ": expected " + md5.toString(16) +
            ", got " + md5Actual.toString(16)
        );
}
person kriegaex    schedule 25.06.2012
comment
О, кстати, прежде чем кто-либо, кроме меня, заметит, насколько плохо я знаю JRE: я только что обнаружил DigestInputStream и DigestOutputStream. Я собираюсь отредактировать свое исходное решение, чтобы отразить то, что я только что узнал. - person kriegaex; 26.06.2012

В отличие от PHP, где вы можете выполнить хеширование вашего текста MD5, просто вызвав функцию md5, то есть md5($text), в Java это было немного усложнено. Я обычно реализовывал это, вызывая функцию, которая возвращает хеш-текст md5. Вот как я это реализовал. Сначала создайте функцию с именем md5hashing внутри вашего основного класса, как указано ниже.

public static String md5hashing(String text)
    {   String hashtext = null;
        try 
        {
            String plaintext = text;
            MessageDigest m = MessageDigest.getInstance("MD5");
            m.reset();
            m.update(plaintext.getBytes());
            byte[] digest = m.digest();
            BigInteger bigInt = new BigInteger(1,digest);
            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;   
            }
        } catch (Exception e1) 
        {
            // TODO: handle exception
            JOptionPane.showMessageDialog(null,e1.getClass().getName() + ": " + e1.getMessage());   
        }
        return hashtext;     
    }

Теперь вызывайте функцию всякий раз, когда вам нужно, как указано ниже.

String text = textFieldName.getText();
String pass = md5hashing(text);

Здесь вы можете видеть, что к хэш-тексту добавлен ноль, чтобы он соответствовал хешированию md5 в PHP.

person Geordy James    schedule 26.03.2016

Как бы то ни было, я наткнулся на это, потому что хочу синтезировать идентификаторы GUID из естественного ключа для программы, которая будет устанавливать компоненты COM; Я хочу синхронизировать, чтобы не управлять жизненным циклом GUID. Я буду использовать MD5, а затем воспользуюсь классом UUID, чтобы получить из него строку. (http://stackoverflow.com/questions/2190890/how-can-i-generate-guid-for-a-string-values/12867439 вызывает эту проблему).

В любом случае java.util.UUID может дать вам красивую строку из байтов MD5.

return UUID.nameUUIDFromBytes(md5Bytes).toString();
person Mihai Danila    schedule 26.10.2012
comment
фактически он принимает не только массив байтов MD5 (размер == 16). Вы можете передавать байтовый массив любой длины. Он будет преобразован в массив байтов MD5 с помощью MD5 MessageDigest (см. исходный код nameUUIDFromBytes ()) - person Lu55; 21.10.2017

MD5 отлично подходит, если вам не нужна лучшая безопасность, и если вы делаете что-то вроде проверки целостности файла, безопасность не рассматривается. В таком случае вы можете подумать о чем-то более простом и быстром, например, Adler32, который также поддерживается библиотеками Java.

person Community    schedule 08.01.2009
comment
Что заставляет вас думать, что целостность файла не является проблемой безопасности? - person Jeremy Huiskamp; 13.10.2011

это дает точный md5, как вы получаете из функции mysql md5 или функций php md5 и т. д. Это тот, который я использую (вы можете изменить в соответствии с вашими потребностями)

public static String md5( String input ) {
    try {
        java.security.MessageDigest md = java.security.MessageDigest.getInstance("MD5");
        byte[] array = md.digest(input.getBytes( "UTF-8" ));
        StringBuffer sb = new StringBuffer();
        for (int i = 0; i < array.length; i++) {
            sb.append( String.format( "%02x", array[i]));
        }
        return sb.toString();
    } catch ( NoSuchAlgorithmException | UnsupportedEncodingException e) {
        return null;            
    }

}
person Aurangzeb    schedule 18.04.2016

попробуй это:

public static String getHashMD5(String string) {
    try {
        MessageDigest md = MessageDigest.getInstance("MD5");
        BigInteger bi = new BigInteger(1, md.digest(string.getBytes()));
        return bi.toString(16);
    } catch (NoSuchAlgorithmException ex) {
        Logger.getLogger(MD5Utils.class
                .getName()).log(Level.SEVERE, null, ex);

        return "";
    }
}
person Marcelo Lopes    schedule 13.01.2015
comment
Это, вероятно, худшее решение, так как оно удаляет ведущие нули. - person Jannick; 13.08.2015

Вы можете сгенерировать хеш MD5 для заданного текста. с помощью методов класса MessageDigest в пакете java.security. Ниже приведен полный фрагмент кода,

import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import javax.xml.bind.DatatypeConverter;

public class MD5HashGenerator 
{

   public static void main(String args[]) throws NoSuchAlgorithmException
   {
       String stringToHash = "MyJavaCode"; 
       MessageDigest messageDigest = MessageDigest.getInstance("MD5");
       messageDigest.update(stringToHash.getBytes());
       byte[] digiest = messageDigest.digest();
       String hashedOutput = DatatypeConverter.printHexBinary(digiest);
       System.out.println(hashedOutput);
   }
}

Результатом функции MD5 является 128-битный хэш, представленный 32 шестнадцатеричными числами.

В случае, если вы используете такую ​​базу данных, как MySQL, вы можете сделать это и более простым способом. Запрос Select MD5(“text here”) вернет хеш MD5 текста в скобках.

person Prasanna L M    schedule 03.01.2019

Я пришел сюда ради удобной функции scala, которая возвращает строку хэша MD5:

def md5(text: String) : String = java.security.MessageDigest.getInstance("MD5").digest(text.getBytes()).map(0xFF & _).map { "%02x".format(_) }.foldLeft(""){_ + _}
person Priyank Desai    schedule 20.10.2015

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

/**
* MD5 encryption
*
* @author Hongten
*
*/
public class MD5 {

 public static void main(String[] args) {
     System.out.println(MD5.getMD5("123456"));
 }

 /**
  * Use md5 encoded code value
  *
  * @param sInput
  * clearly
  * @ return md5 encrypted password
  */
 public static String getMD5(String sInput) {

     String algorithm = "";
     if (sInput == null) {
         return "null";
     }
     try {
         algorithm = System.getProperty("MD5.algorithm", "MD5");
     } catch (SecurityException se) {
     }
     MessageDigest md = null;
     try {
         md = MessageDigest.getInstance(algorithm);
     } catch (NoSuchAlgorithmException e) {
         e.printStackTrace();
     }
     byte buffer[] = sInput.getBytes();

     for (int count = 0; count < sInput.length(); count++) {
         md.update(buffer, 0, count);
     }
     byte bDigest[] = md.digest();
     BigInteger bi = new BigInteger(bDigest);
     return (bi.toString(16));
 }
}

Об этом есть статья на Codingkit. Проверьте: http://codingkit.com/a/JAVA/2013/1020/2216.html

person shouyu    schedule 20.10.2013

Вы можете попробовать использовать Caesar.

Первый вариант:

byte[] hash =
    new Hash(
        new ImmutableMessageDigest(
            MessageDigest.getInstance("MD5")
        ),
        new PlainText("String to hash...")
    ).asArray();

Второй вариант:

byte[] hash =
    new ImmutableMessageDigest(
        MessageDigest.getInstance("MD5")
    ).update(
        new PlainText("String to hash...")
    ).digest();
person Janez Kuhar    schedule 17.01.2021

Я сделал это ... Вроде работает нормально - я уверен, что кто-нибудь укажет на ошибки ...

public final class MD5 {
public enum SaltOption {
    BEFORE, AFTER, BOTH, NONE;
}
private static final String ALG = "MD5";
//For conversion to 2-char hex
private static final char[] digits = {
    '0' , '1' , '2' , '3' , '4' , '5' ,
    '6' , '7' , '8' , '9' , 'a' , 'b' ,
    'c' , 'd' , 'e' , 'f' , 'g' , 'h' ,
    'i' , 'j' , 'k' , 'l' , 'm' , 'n' ,
    'o' , 'p' , 'q' , 'r' , 's' , 't' ,
    'u' , 'v' , 'w' , 'x' , 'y' , 'z'
};

private SaltOption opt;

/**
 * Added the SaltOption constructor since everybody
 * has their own standards when it comes to salting
 * hashes.
 * 
 * This gives the developer the option...
 * 
 * @param option The salt option to use, BEFORE, AFTER, BOTH or NONE.
 */
public MD5(final SaltOption option) {
    //TODO: Add Char Encoding options too... I was too lazy!
    this.opt = option;
}

/**
 * 
 * Returns the salted MD5 checksum of the text passed in as an argument.
 * 
 * If the salt is an empty byte array - no salt is applied.
 * 
 * @param txt The text to run through the MD5 algorithm.
 * @param salt The salt value in bytes.
 * @return The salted MD5 checksum as a <code>byte[]</code>
 * @throws NoSuchAlgorithmException
 */
private byte[] createChecksum(final String txt, final byte[] salt) throws NoSuchAlgorithmException {
    final MessageDigest complete = MessageDigest.getInstance(ALG);
    if(opt.equals(SaltOption.BEFORE) || opt.equals(SaltOption.BOTH)) {
        complete.update(salt);
    }
    complete.update(txt.getBytes());
    if(opt.equals(SaltOption.AFTER) || opt.equals(SaltOption.BOTH)) {
        complete.update(salt);
    }
    return complete.digest();
}

/**
 * 
 * Returns the salted MD5 checksum of the file passed in as an argument.
 * 
 * If the salt is an empty byte array - no salt is applied.
 * 
 * @param fle The file to run through the MD5 algorithm.
 * @param salt The salt value in bytes.
 * @return The salted MD5 checksum as a <code>byte[]</code>
 * @throws IOException
 * @throws NoSuchAlgorithmException
 */
private byte[] createChecksum(final File fle, final byte[] salt)
        throws IOException, NoSuchAlgorithmException {
    final byte[] buffer = new byte[1024];
    final MessageDigest complete = MessageDigest.getInstance(ALG);
            if(opt.equals(SaltOption.BEFORE) || opt.equals(SaltOption.BOTH)) {
            complete.update(salt);
        }
    int numRead;
    InputStream fis = null;
    try {
        fis = new FileInputStream(fle);
        do {
            numRead = fis.read(buffer);
            if (numRead > 0) {
                complete.update(buffer, 0, numRead);
            }
        } while (numRead != -1);
    } finally {
    if (fis != null) {
            fis.close();
        }
    }
            if(opt.equals(SaltOption.AFTER) || opt.equals(SaltOption.BOTH)) {
            complete.update(salt);
        }
    return complete.digest();
}

/**
 * 
 * Efficiently converts a byte array to its 2 char per byte hex equivalent.
 * 
 * This was adapted from JDK code in the Integer class, I just didn't like
 * having to use substrings once I got the result...
 *
 * @param b The byte array to convert
 * @return The converted String, 2 chars per byte...
 */
private String convertToHex(final byte[] b) {
    int x;
    int charPos;
    int radix;
    int mask;
    final char[] buf = new char[32];
    final char[] tmp = new char[3];
    final StringBuilder md5 = new StringBuilder();
    for (int i = 0; i < b.length; i++) {
        x = (b[i] & 0xFF) | 0x100;
        charPos = 32;
        radix = 1 << 4;
        mask = radix - 1;
        do {
            buf[--charPos] = digits[x & mask];
            x >>>= 4;
        } while (x != 0);
        System.arraycopy(buf, charPos, tmp, 0, (32 - charPos));
        md5.append(Arrays.copyOfRange(tmp, 1, 3));
    }
    return md5.toString();
}

/**
 * 
 * Returns the salted MD5 checksum of the file passed in as an argument.
 * 
 * @param fle The file you want want to run through the MD5 algorithm.
 * @param salt The salt value in bytes
 * @return The salted MD5 checksum as a 2 char per byte HEX <code>String</code>
 * @throws NoSuchAlgorithmException
 * @throws IOException
 */
public String getMD5Checksum(final File fle, final byte[] salt)
        throws NoSuchAlgorithmException, IOException {
    return convertToHex(createChecksum(fle, salt));
}

/**
 * 
 * Returns the MD5 checksum of the file passed in as an argument.
 * 
 * @param fle The file you want want to run through the MD5 algorithm.
 * @return The MD5 checksum as a 2 char per byte HEX <code>String</code>
 * @throws NoSuchAlgorithmException
 * @throws IOException
 */
public String getMD5Checksum(final File fle)
        throws NoSuchAlgorithmException, IOException {
    return convertToHex(createChecksum(fle, new byte[0]));
}

/**
 * 
 * Returns the salted MD5 checksum of the text passed in as an argument.
 * 
 * @param txt The text you want want to run through the MD5 algorithm.
 * @param salt The salt value in bytes.
 * @return The salted MD5 checksum as a 2 char per byte HEX <code>String</code>
 * @throws NoSuchAlgorithmException
 * @throws IOException
 */
public String getMD5Checksum(final String txt, final byte[] salt)
        throws NoSuchAlgorithmException {
    return convertToHex(createChecksum(txt, salt));
}

/**
 * 
 * Returns the MD5 checksum of the text passed in as an argument.
 * 
 * @param txt The text you want want to run through the MD5 algorithm.
 * @return The MD5 checksum as a 2 char per byte HEX <code>String</code>
 * @throws NoSuchAlgorithmException
 * @throws IOException
 */
public String getMD5Checksum(final String txt)
        throws NoSuchAlgorithmException {

    return convertToHex(createChecksum(txt, new byte[0]));
}
}
person jokillsya    schedule 25.06.2012

Я сделал это с помощью php следующим образом

<?php
$goodtext = "Not found";
// If there is no parameter, this code is all skipped
if ( isset($_GET['md5']) ) {
    $time_pre = microtime(true);
    $md5 = $_GET['md5'];
    // This is our alphabet
    $txt = "0123456789";
    $show = 15;
    // Outer loop go go through the alphabet for the
    // first position in our "possible" pre-hash
    // text
    for($i=0; $i<strlen($txt); $i++ ) {
        $ch1 = $txt[$i];   // The first of two characters
        // Our inner loop Note the use of new variables
        // $j and $ch2 
        for($j=0; $j<strlen($txt); $j++ ) {
            $ch2 = $txt[$j];  // Our second character
            for($k=0; $k<strlen($txt); $k++ ) {
                $ch3 = $txt[$k];
                for($l=0; $l<strlen($txt); $l++){
                    $ch4 = $txt[$l];
                    // Concatenate the two characters together to 
                    // form the "possible" pre-hash text
                    $try = $ch1.$ch2.$ch3.$ch4;
                    // Run the hash and then check to see if we match
                    $check = hash('md5', $try);
                    if ( $check == $md5 ) {
                        $goodtext = $try;
                        break;   // Exit the inner loop
                    }
                    // Debug output until $show hits 0
                    if ( $show > 0 ) {
                        print "$check $try\n";
                        $show = $show - 1;
                    }
                    if($goodtext == $try){
                        break;
                    }
                }
                if($goodtext == $try){
                    break;
                }
            }
            if($goodtext == $try) {
                break;  
            }
        }
        if($goodtext == $try){
            break;
        }
    }
    // Compute ellapsed time
    $time_post = microtime(true);
    print "Ellapsed time: ";
    print $time_post-$time_pre;
    print "\n";
}
?>

вы можете сослаться на это - источник

person Anupam Haldkar    schedule 10.05.2020

Я знаю, что вопрос касается Java, но я хотел бы перечислить здесь исходный код ActionScript 1 (здесь лицензия), чтобы сгенерировать MD5 другим способом, чем ответы, перечисленные на этой странице.

Приведенная ниже функция работает хорошо и, несомненно, может быть преобразована в Java:

/* MD5 implementation from http://www.webtoolkit.info */

function md5(string) {

    function RotateLeft(lValue, iShiftBits) {
        return (lValue<<iShiftBits) | (lValue>>>(32-iShiftBits));
    }

    function AddUnsigned(lX,lY) {
        var lX4,lY4,lX8,lY8,lResult;
        lX8 = (lX & 0x80000000);
        lY8 = (lY & 0x80000000);
        lX4 = (lX & 0x40000000);
        lY4 = (lY & 0x40000000);
        lResult = (lX & 0x3FFFFFFF)+(lY & 0x3FFFFFFF);
        if (lX4 & lY4) {
            return (lResult ^ 0x80000000 ^ lX8 ^ lY8);
        }
        if (lX4 | lY4) {
            if (lResult & 0x40000000) {
                return (lResult ^ 0xC0000000 ^ lX8 ^ lY8);
            } else {
                return (lResult ^ 0x40000000 ^ lX8 ^ lY8);
            }
        } else {
            return (lResult ^ lX8 ^ lY8);
        }
    }

    function F(x,y,z) { return (x & y) | ((~x) & z); }
    function G(x,y,z) { return (x & z) | (y & (~z)); }
    function H(x,y,z) { return (x ^ y ^ z); }
    function I(x,y,z) { return (y ^ (x | (~z))); }

    function FF(a,b,c,d,x,s,ac) {
        a = AddUnsigned(a, AddUnsigned(AddUnsigned(F(b, c, d), x), ac));
        return AddUnsigned(RotateLeft(a, s), b);
    };

    function GG(a,b,c,d,x,s,ac) {
        a = AddUnsigned(a, AddUnsigned(AddUnsigned(G(b, c, d), x), ac));
        return AddUnsigned(RotateLeft(a, s), b);
    };

    function HH(a,b,c,d,x,s,ac) {
        a = AddUnsigned(a, AddUnsigned(AddUnsigned(H(b, c, d), x), ac));
        return AddUnsigned(RotateLeft(a, s), b);
    };

    function II(a,b,c,d,x,s,ac) {
        a = AddUnsigned(a, AddUnsigned(AddUnsigned(I(b, c, d), x), ac));
        return AddUnsigned(RotateLeft(a, s), b);
    };

    function ConvertToWordArray(string) {
        var lWordCount;
        var lMessageLength = string.length;
        var lNumberOfWords_temp1=lMessageLength + 8;
        var lNumberOfWords_temp2=(lNumberOfWords_temp1-(lNumberOfWords_temp1 % 64))/64;
        var lNumberOfWords = (lNumberOfWords_temp2+1)*16;
        var lWordArray=Array(lNumberOfWords-1);
        var lBytePosition = 0;
        var lByteCount = 0;
        while ( lByteCount < lMessageLength ) {
            lWordCount = (lByteCount-(lByteCount % 4))/4;
            lBytePosition = (lByteCount % 4)*8;
            lWordArray[lWordCount] = (lWordArray[lWordCount] | 
                (string.charCodeAt(lByteCount)<<lBytePosition));
            lByteCount++;
        }
        lWordCount = (lByteCount-(lByteCount % 4))/4;
        lBytePosition = (lByteCount % 4)*8;
        lWordArray[lWordCount] = lWordArray[lWordCount] | (0x80<<lBytePosition);
        lWordArray[lNumberOfWords-2] = lMessageLength<<3;
        lWordArray[lNumberOfWords-1] = lMessageLength>>>29;
        return lWordArray;
    };

    function WordToHex(lValue) {
        var WordToHexValue="",WordToHexValue_temp="",lByte,lCount;
        for (lCount = 0;lCount<=3;lCount++) {
            lByte = (lValue>>>(lCount*8)) & 255;
            WordToHexValue_temp = "0" + lByte.toString(16);
            WordToHexValue = WordToHexValue + 
                WordToHexValue_temp.substr(WordToHexValue_temp.length-2,2);
        }
        return WordToHexValue;
    };

    function Utf8Encode(string) {

        var utftext = "";

        for (var n = 0; n < string.length; n++) {

            var c = string.charCodeAt(n);

            if (c < 128) {
                utftext += String.fromCharCode(c);
            }
            else if((c > 127) && (c < 2048)) {
                utftext += String.fromCharCode((c >> 6) | 192);
                utftext += String.fromCharCode((c & 63) | 128);
            }
            else {
                utftext += String.fromCharCode((c >> 12) | 224);
                utftext += String.fromCharCode(((c >> 6) & 63) | 128);
                utftext += String.fromCharCode((c & 63) | 128);
            }

        }

        return utftext;
    };

    var x=Array();
    var k,AA,BB,CC,DD,a,b,c,d;
    var S11=7, S12=12, S13=17, S14=22;
    var S21=5, S22=9 , S23=14, S24=20;
    var S31=4, S32=11, S33=16, S34=23;
    var S41=6, S42=10, S43=15, S44=21;

    string = Utf8Encode(string);

    x = ConvertToWordArray(string);

    a = 0x67452301; b = 0xEFCDAB89; c = 0x98BADCFE; d = 0x10325476;

    for (k=0;k<x.length;k+=16) {
        AA=a; BB=b; CC=c; DD=d;
        a=FF(a,b,c,d,x[k+0], S11,0xD76AA478);
        d=FF(d,a,b,c,x[k+1], S12,0xE8C7B756);
        c=FF(c,d,a,b,x[k+2], S13,0x242070DB);
        b=FF(b,c,d,a,x[k+3], S14,0xC1BDCEEE);
        a=FF(a,b,c,d,x[k+4], S11,0xF57C0FAF);
        d=FF(d,a,b,c,x[k+5], S12,0x4787C62A);
        c=FF(c,d,a,b,x[k+6], S13,0xA8304613);
        b=FF(b,c,d,a,x[k+7], S14,0xFD469501);
        a=FF(a,b,c,d,x[k+8], S11,0x698098D8);
        d=FF(d,a,b,c,x[k+9], S12,0x8B44F7AF);
        c=FF(c,d,a,b,x[k+10],S13,0xFFFF5BB1);
        b=FF(b,c,d,a,x[k+11],S14,0x895CD7BE);
        a=FF(a,b,c,d,x[k+12],S11,0x6B901122);
        d=FF(d,a,b,c,x[k+13],S12,0xFD987193);
        c=FF(c,d,a,b,x[k+14],S13,0xA679438E);
        b=FF(b,c,d,a,x[k+15],S14,0x49B40821);
        a=GG(a,b,c,d,x[k+1], S21,0xF61E2562);
        d=GG(d,a,b,c,x[k+6], S22,0xC040B340);
        c=GG(c,d,a,b,x[k+11],S23,0x265E5A51);
        b=GG(b,c,d,a,x[k+0], S24,0xE9B6C7AA);
        a=GG(a,b,c,d,x[k+5], S21,0xD62F105D);
        d=GG(d,a,b,c,x[k+10],S22,0x2441453);
        c=GG(c,d,a,b,x[k+15],S23,0xD8A1E681);
        b=GG(b,c,d,a,x[k+4], S24,0xE7D3FBC8);
        a=GG(a,b,c,d,x[k+9], S21,0x21E1CDE6);
        d=GG(d,a,b,c,x[k+14],S22,0xC33707D6);
        c=GG(c,d,a,b,x[k+3], S23,0xF4D50D87);
        b=GG(b,c,d,a,x[k+8], S24,0x455A14ED);
        a=GG(a,b,c,d,x[k+13],S21,0xA9E3E905);
        d=GG(d,a,b,c,x[k+2], S22,0xFCEFA3F8);
        c=GG(c,d,a,b,x[k+7], S23,0x676F02D9);
        b=GG(b,c,d,a,x[k+12],S24,0x8D2A4C8A);
        a=HH(a,b,c,d,x[k+5], S31,0xFFFA3942);
        d=HH(d,a,b,c,x[k+8], S32,0x8771F681);
        c=HH(c,d,a,b,x[k+11],S33,0x6D9D6122);
        b=HH(b,c,d,a,x[k+14],S34,0xFDE5380C);
        a=HH(a,b,c,d,x[k+1], S31,0xA4BEEA44);
        d=HH(d,a,b,c,x[k+4], S32,0x4BDECFA9);
        c=HH(c,d,a,b,x[k+7], S33,0xF6BB4B60);
        b=HH(b,c,d,a,x[k+10],S34,0xBEBFBC70);
        a=HH(a,b,c,d,x[k+13],S31,0x289B7EC6);
        d=HH(d,a,b,c,x[k+0], S32,0xEAA127FA);
        c=HH(c,d,a,b,x[k+3], S33,0xD4EF3085);
        b=HH(b,c,d,a,x[k+6], S34,0x4881D05);
        a=HH(a,b,c,d,x[k+9], S31,0xD9D4D039);
        d=HH(d,a,b,c,x[k+12],S32,0xE6DB99E5);
        c=HH(c,d,a,b,x[k+15],S33,0x1FA27CF8);
        b=HH(b,c,d,a,x[k+2], S34,0xC4AC5665);
        a=II(a,b,c,d,x[k+0], S41,0xF4292244);
        d=II(d,a,b,c,x[k+7], S42,0x432AFF97);
        c=II(c,d,a,b,x[k+14],S43,0xAB9423A7);
        b=II(b,c,d,a,x[k+5], S44,0xFC93A039);
        a=II(a,b,c,d,x[k+12],S41,0x655B59C3);
        d=II(d,a,b,c,x[k+3], S42,0x8F0CCC92);
        c=II(c,d,a,b,x[k+10],S43,0xFFEFF47D);
        b=II(b,c,d,a,x[k+1], S44,0x85845DD1);
        a=II(a,b,c,d,x[k+8], S41,0x6FA87E4F);
        d=II(d,a,b,c,x[k+15],S42,0xFE2CE6E0);
        c=II(c,d,a,b,x[k+6], S43,0xA3014314);
        b=II(b,c,d,a,x[k+13],S44,0x4E0811A1);
        a=II(a,b,c,d,x[k+4], S41,0xF7537E82);
        d=II(d,a,b,c,x[k+11],S42,0xBD3AF235);
        c=II(c,d,a,b,x[k+2], S43,0x2AD7D2BB);
        b=II(b,c,d,a,x[k+9], S44,0xEB86D391);
        a=AddUnsigned(a,AA);
        b=AddUnsigned(b,BB);
        c=AddUnsigned(c,CC);
        d=AddUnsigned(d,DD);
    }

    var temp = WordToHex(a)+WordToHex(b)+WordToHex(c)+WordToHex(d);

    return temp.toLowerCase();
}
person Alexander Farber    schedule 01.08.2015

person    schedule
comment
Это язык Котлин? - person Isuru; 18.06.2017
comment
@Isuru выглядит как Scala - person gildor; 03.10.2017

person    schedule
comment
Добро пожаловать в StackOverflow. Перед тем, как сделать это, вы можете прочитать как опубликовать ответ . Вкратце объясните, почему вы разместили этот код и для чего он нужен. Также подумайте о том, чтобы отформатировать свой ответ, чтобы читатели могли его легко понять. - person Nacho; 11.04.2016