जावा स्ट्रिंग SHA1 के लिए


158

मैं जावा में SHA1 कनवर्टर के लिए एक साधारण स्ट्रिंग बनाने की कोशिश कर रहा हूं और यही मुझे मिला है ...

public static String toSHA1(byte[] convertme) {
    MessageDigest md = null;
    try {
        md = MessageDigest.getInstance("SHA-1");
    }
    catch(NoSuchAlgorithmException e) {
        e.printStackTrace();
    } 
    return new String(md.digest(convertme));
}

जब मैं इसे पास करता toSHA1("password".getBytes())हूं, मुझे [�a�ɹ??�%l�3~��.पता चलता है कि यह संभवत: UTF-8 की तरह एक साधारण एन्कोडिंग फिक्स है, लेकिन क्या कोई मुझे बता सकता है कि मुझे जो चाहिए वह पाने के लिए मुझे क्या करना चाहिए 5baa61e4c9b93f3f0682250b6cf8331b7ee68fd8? या मैं यह पूरी तरह से गलत कर रहा हूँ?


एल्गोरिथ्म SHA1हाइफ़न के बिना है, पता नहीं कि क्या इससे कोई फर्क पड़ेगा।
द स्क्रीम मिस्टर

जब आप कॉल करते हैं getBytes(), तो वर्ण एन्कोडिंग को निर्दिष्ट करना अच्छा है , उदाहरण के लिएtoSHA1("password".getBytes("UTF-8"))
Qwerky

जवाबों:


183

अद्यतन
आप अपाचे कॉमन्स कोडेक (संस्करण 1.7+) का उपयोग करके आपके लिए यह काम कर सकते हैं।

DigestUtils.sha1Hex (stringToConvertToSHexRepresentation)

इस सुझाव के लिए @ जॉन ओनस्टॉट को धन्यवाद ।


पुराना उत्तर
अपने बाइट ऐरे को हेक्स स्ट्रिंग में परिवर्तित करें। रियल का हाउ टू यू कैसे

return byteArrayToHexString(md.digest(convertme))

और (रियल की हाउ टू से कॉपी की गई)

public static String byteArrayToHexString(byte[] b) {
  String result = "";
  for (int i=0; i < b.length; i++) {
    result +=
          Integer.toString( ( b[i] & 0xff ) + 0x100, 16).substring( 1 );
  }
  return result;
}

BTW, आपको बेस 64 का उपयोग करके अधिक कॉम्पैक्ट प्रतिनिधित्व मिल सकता है। अपाचे कॉमन्स कोडेक एपीआई 1.4 , सभी दर्द को दूर करने के लिए यह अच्छी उपयोगिता है। यहाँ देखें


4
base64 और sha1 बहुत अलग हैं - उन्हें विकल्प के रूप में सुझाव न दें।
रयान ए।

13
@ राणा: जैसा कि मैं इसे समझता हूं, वह SH641 हैश को हेक्स-एन्कोडिंग के विकल्प के रूप में बेस 64 का सुझाव देता है (पूरी तरह से SHA1 के विकल्प के रूप में नहीं)।
हेल्बर्ट

मैंने अभी तक इसकी कोशिश नहीं की है, लेकिन क्या आप यह समझाने की परवाह करेंगे कि यह कैसे काम करता है?
जीव

11
DigestUtils.sha1Hex("my string")पहिया को सुदृढ़ करने के बजाय पुस्तकालय का उपयोग क्यों न करें (हालांकि यह जानना दिलचस्प है कि हाथ से हेक्स को कैसे बदलना है)?
जॉन ऑनस्टॉट

3
क्योंकि जब इस जवाब को DigestUtils लिखा गया था (1.7 सितंबर 2012 में जारी किया गया था) में यह सुविधा नहीं थी। इस पर ध्यान दिलाने के लिए धन्यवाद। +1
निशांत

67

यह स्ट्रिंग को sha1 में परिवर्तित करने का मेरा समाधान है। यह मेरे एंड्रॉइड ऐप में अच्छा काम करता है:

private static String encryptPassword(String password)
{
    String sha1 = "";
    try
    {
        MessageDigest crypt = MessageDigest.getInstance("SHA-1");
        crypt.reset();
        crypt.update(password.getBytes("UTF-8"));
        sha1 = byteToHex(crypt.digest());
    }
    catch(NoSuchAlgorithmException e)
    {
        e.printStackTrace();
    }
    catch(UnsupportedEncodingException e)
    {
        e.printStackTrace();
    }
    return sha1;
}

private static String byteToHex(final byte[] hash)
{
    Formatter formatter = new Formatter();
    for (byte b : hash)
    {
        formatter.format("%02x", b);
    }
    String result = formatter.toString();
    formatter.close();
    return result;
}

7
यह निर्दिष्ट करना चाहते हैं कि यह java.util है। चेतावनी से बचने के लिए अंत में एक फॉर्मेटर।क्लोज़ () की आवश्यकता है।
एरिक चेन

Shoudl't encryptPassword("test")और echo test|sha1sumlinux टर्मिनल आउटपुट में एक ही परिणाम? वे नहीं करते।
ट्यूलेंस कोरडोवा

@ TulainsCórdova कंसोल आमंत्रण के बारे में: यदि आप उपयोग करते हैं echo test, तो लाइन ब्रेक सहित आउटपुट को पाइप किया जाएगा sha1sum। यदि आप लाइनिंग ब्रेक के बिना एक सादे स्ट्रिंग हैश करना चाहते हैं, तो आप उपयोग कर सकते हैं echo -n test | sha1sum-nपैरामीटर बनाता echoलाइन ब्रेक को छोड़ते हुए।

प्रश्न से कम, लेकिन सामान्य रूप से अधिक: आपकी encryptPassword()आवाज़ ऐसी है जो प्रमाणीकरण डेटा संग्रहीत करने के लिए उपयोग की जा रही है। ध्यान दें कि आपकी कोडिंग डिक्शनरी हमलों के लिए असुरक्षित है, क्योंकि कोई सीडिंग लागू नहीं होती है। अपने सुरक्षा वातावरण की जाँच करें कि क्या यह आपके आवेदन के लिए कोई समस्या है!
ईगलीनरो


32

SHA-1 (और अन्य सभी हैशिंग एल्गोरिदम) बाइनरी डेटा लौटाते हैं। इसका मतलब है कि (जावा में) वे एक उत्पादन करते हैं byte[]। यह byteसरणी किसी भी विशिष्ट वर्ण का प्रतिनिधित्व नहीं करती है, जिसका अर्थ है कि आप इसे Stringवैसे ही नहीं बदल सकते जैसे आपने किया।

यदि आपको एक की आवश्यकता है String, तो आपको उस प्रारूप को प्रारूपित करना होगा जिसे byte[]एक के रूप में दर्शाया जा सकता है String(अन्यथा, बस byte[]आसपास रखें )।

byte[]मुद्रण योग्य वर्णों के रूप में मनमाने ढंग से प्रतिनिधित्व करने के दो सामान्य तरीके BASE64 या सरल हेक्स-स्ट्रिंग्स हैं (यानी byteदो हेक्साडेसिमल अंकों द्वारा प्रत्येक का प्रतिनिधित्व करते हैं )। ऐसा लगता है कि आप एक हेक्स-स्ट्रिंग का उत्पादन करने की कोशिश कर रहे हैं।

एक और नुकसान यह भी है: यदि आप एक जावा के SHA-1 को प्राप्त करना चाहते हैं String, तो आपको Stringइसे byte[]पहले में बदलने की आवश्यकता है (जैसा कि SHA-1 का इनपुट एक byte[]समान है)। यदि आप बस myString.getBytes()दिखाए गए अनुसार उपयोग करते हैं, तो यह प्लेटफ़ॉर्म डिफ़ॉल्ट एन्कोडिंग का उपयोग करेगा और जैसा कि आप इसे चलाने वाले वातावरण पर निर्भर करेंगे (उदाहरण के लिए यह आपके ओएस की भाषा / स्थानीय सेटिंग के आधार पर अलग-अलग डेटा वापस कर सकता है)।

एक बेहतर समाधान के लिए उपयोग करने के लिए एन्कोडिंग निर्दिष्ट करने के लिए है String-to- byte[]इस तरह रूपांतरण: myString.getBytes("UTF-8")। UTF-8 (या एक और एन्कोडिंग जो हर यूनिकोड वर्ण का प्रतिनिधित्व कर सकता है) चुनना यहां सबसे सुरक्षित विकल्प है।


27

यह एक सरल समाधान है जिसका उपयोग स्ट्रिंग को हेक्स प्रारूप में परिवर्तित करते समय किया जा सकता है:

private static String encryptPassword(String password) throws NoSuchAlgorithmException, UnsupportedEncodingException {

    MessageDigest crypt = MessageDigest.getInstance("SHA-1");
    crypt.reset();
    crypt.update(password.getBytes("UTF-8"));

    return new BigInteger(1, crypt.digest()).toString(16);
}

चेतावनी: हैश पीढ़ी '0' से शुरू होने वाले हैश के लिए गलत है। आपको 39 अक्षरों वाला एक स्ट्रिंग प्राप्त होगा।
12

@philn आप समाधान सुझा सकते हैं?
निकिता कोकश्रोव

1
मुझे लगता है कि यदि आप एक बाइट से एक बड़ा पूर्णांक बनाते हैं [] पर्याप्त अग्रणी शून्य के साथ, ये 0 खो जाते हैं। इस प्रकार, हेक्स स्ट्रिंग प्रतिनिधित्व "0" नहीं होगा, जो 39 या उससे भी कम वर्ण वाले हैश की ओर ले जाएगा। मैं ऊपर petrnohejls समाधान का इस्तेमाल किया और यह ठीक काम करता है ...
21

25

बस अपाचे कॉमन्स कोडेक लाइब्रेरी का उपयोग करें। उनकी एक उपयोगिता वर्ग है जिसे डाइजेस्टयूल्स कहा जाता है

विवरण में आने की आवश्यकता नहीं है।


51
मैं असहमत हूं, विवरण में जाना पूरे बिंदु की तरह है
ninesided

12
सवाल यह है कि क्या आपके पास विवरणों में आने का समय है या नहीं। पूरे बिंदु को आमतौर पर समय पर पूरा किया जा रहा है। हर कोई छात्र नहीं है या सभी विवरणों को सीखने की लक्जरी है।
DaTroop

DigestUtils एक बाइट सरणी देता है ताकि स्ट्रिंग प्रतिनिधित्व प्राप्त करने के लिए आपको इसे Hex.encodeHexString के माध्यम से चलाने की आवश्यकता हो। जावा: यह 2014 है और हमारे पास अभी भी एक चरण की विधि नहीं है
रायर

5
एक कदम SHA-1 विधि: String result = DigestUtils.sha1Hex("An input string")o)
जॉन ऑनस्टॉट

18

जैसा कि उपयोग करने से पहले उल्लेख किया गया है अपाचे कॉमन्स कोडेक। यह स्प्रिंग लोगों द्वारा भी अनुशंसित है (स्प्रिंग डॉक में DigestUtils देखें)। उदाहरण के लिए:

DigestUtils.sha1Hex(b);

निश्चित रूप से यहां टॉप रेटेड उत्तर का उपयोग नहीं किया जाएगा।


6

यह सही ढंग से प्रिंट नहीं हो रहा है क्योंकि आपको बेस 64 एनकोडिंग का उपयोग करने की आवश्यकता है। जावा 8 के साथ आप बेस 64 एनकोडर वर्ग का उपयोग कर सांकेतिक शब्दों में बदलना कर सकते हैं ।

public static String toSHA1(byte[] convertme) {
    md = MessageDigest.getInstance("SHA-1");
    return Base64.getEncoder().encodeToString((md.digest(convertme));
}

परिणाम

यह आपको अपना अपेक्षित आउटपुट देगा 5baa61e4c9b93f3f0682250b6cf8331b7ee68fd8


1
@Devenv यह SHA-1 है तीन बिंदुओं का मतलब है कि यह अपने मूल कोड को बनाए रखेगा जो sha1 में परिवर्तित होता है। ओपी का मूल मुद्दा स्ट्रिंग को सही ढंग से प्रिंट करते समय था।
एडुआर्डो डेनिस

4

संदेश डाइजेस्ट (हैश) बाइट [] बाइट में [] बाहर है

एक संदेश डाइजेस्ट को एक फ़ंक्शन के रूप में परिभाषित किया गया है जो एक कच्ची बाइट सरणी लेता है और एक कच्ची बाइट सरणी (उर्फ byte[]) देता है। उदाहरण के लिए SHA-1 (सिक्योर हैश अल्गोरिथम 1) का पाचन आकार 160 बिट या 20 बाइट है। कच्चे बाइट सरणियों की व्याख्या आमतौर पर UTF-8 जैसे चरित्र एन्कोडिंग के रूप में नहीं की जा सकती है , क्योंकि प्रत्येक क्रम में हर बाइट एक कानूनी नहीं है जो एन्कोडिंग है। इसलिए उन्हें एक साथ परिवर्तित करना :String

new String(md.digest(subject), StandardCharsets.UTF_8)

कुछ गैरकानूनी अनुक्रम बना सकते हैं या अपरिभाषित यूनिकोड मैपिंग के लिए कोड-पॉइंटर्स हो सकते हैं :

[�a�ɹ??�%l3~��.

बाइनरी-टू-टेक्स्ट एन्कोडिंग

उसके लिए बाइनरी-टू-टेक्स्ट एन्कोडिंग का उपयोग किया जाता है। हैश के साथ, जो सबसे अधिक उपयोग किया जाता है वह एचईएक्स एन्कोडिंग या बेस 16 है । मूल रूप से एक बाइट से मान हो सकता है 0करने के लिए 255(या -128करने के लिए 127, जिनमें से हेक्स प्रतिनिधित्व के बराबर है पर हस्ताक्षर किए) 0x00- 0xFF। इसलिए हेक्स आउटपुट की आवश्यक लंबाई को दोगुना कर देगा, इसका मतलब है कि 20 बाइट आउटपुट 40 कैरेक्टर लंबा हेक्स स्ट्रिंग बनाएंगे, जैसे:

2fd4e1c67a2d28fced849ee1bb76e7391b93eb12

ध्यान दें कि हेक्स एन्कोडिंग का उपयोग करना आवश्यक नहीं है। तुम भी base64 की तरह कुछ का उपयोग कर सकते हैं । हेक्स को अक्सर पसंद किया जाता है क्योंकि यह मनुष्यों द्वारा आसानी से पढ़ा जा सकता है और पैडिंग की आवश्यकता के बिना एक परिभाषित आउटपुट लंबाई है।

आप अकेले बाइट सरणी को JDK कार्यक्षमता के साथ हेक्स में बदल सकते हैं:

new BigInteger(1, token).toString(16)

ध्यान दें कि संख्या केBigInteger रूप में बाइट सरणी की व्याख्या करेगा और बाइट स्ट्रिंग के रूप में नहीं। इसका मतलब है कि अग्रणी शून्य आउटपुट नहीं किया जाएगा और परिणामस्वरूप स्ट्रिंग 40 वर्णों से कम हो सकती है।

HEX को एनकोड करने के लिए पुस्तकालयों का उपयोग करना

अब आप स्टैक ओवरफ्लो से एक अप्रयुक्त बाइट-टू-हेक्स विधि को कॉपी या पेस्ट कर सकते हैं या अमरूद जैसे बड़े पैमाने पर निर्भरता का उपयोग कर सकते हैं ।

अधिकांश बाइट से संबंधित मुद्दों के लिए एक समाधान के लिए मैंने इन मामलों को संभालने के लिए एक उपयोगिता लागू की: बाइट्स-जावा (गिथब)

अपना संदेश डाइजेस्ट बाइट सरणी में बदलने के लिए आप बस कर सकते हैं

String hex = Bytes.wrap(md.digest(subject)).encodeHex();

या आप केवल अंतर्निहित हैश सुविधा का उपयोग कर सकते हैं

String hex =  Bytes.from(subject).hashSha1().encodeHex();

2

बेस 64 SHA1हैश का प्रतिनिधित्व :

String hashedVal = Base64.getEncoder().encodeToString(DigestUtils.sha1(stringValue.getBytes(Charset.forName("UTF-8"))));

1

इसका कारण यह नहीं है कि जब आप कॉल String(md.digest(convertme))करते हैं, तो आप जावा को एक स्ट्रिंग के रूप में एन्क्रिप्टेड बाइट्स के अनुक्रम की व्याख्या करने के लिए कह रहे हैं। आप जो चाहते हैं वह बाइट्स को हेक्साडेसिमल वर्णों में बदलना है।


0

बाइट सरणी को हेक्स स्ट्रिंग में बदलें।

public static String toSHA1(byte[] convertme) {
    final char[] HEX_CHARS = "0123456789ABCDEF".toCharArray();
    MessageDigest md = null;
    try {
        md = MessageDigest.getInstance("SHA-1");
    }
    catch(NoSuchAlgorithmException e) {
        e.printStackTrace();
    }
    byte[] buf = md.digest(convertme);
    char[] chars = new char[2 * buf.length];
    for (int i = 0; i < buf.length; ++i) {
        chars[2 * i] = HEX_CHARS[(buf[i] & 0xF0) >>> 4];
        chars[2 * i + 1] = HEX_CHARS[buf[i] & 0x0F];
    }
    return new String(chars);
}
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.