SHA1에 Java 문자열


158

Java에서 간단한 String to 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에는 하이픈이 없으므로 차이가 있는지 알 수 없습니다.
Scrum Meister

호출 할 때 문자 인코딩을 지정하는 것이 좋습니다 ( getBytes()예 :toSHA1("password".getBytes("UTF-8"))
Qwerky

답변:


183

UPDATE
당신은 사용할 수 있습니다 아파치 코 몬즈 코덱 당신을 위해이 일을 할 (버전 1.7+).

DigestUtils.sha1Hex (stringToConvertToSHexRepresentation)

이 제안에 대해 @ Jon Onstott 에게 감사합니다 .


이전 답변
바이트 배열을 16 진 문자열로 변환하십시오. 레알의 방법은 방법을 알려줍니다 .

return byteArrayToHexString(md.digest(convertme))

(Real의 How To에서 복사)

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, Base64를 사용하여 더 간결하게 표현할 수 있습니다. Apache Commons Codec API 1.4 는 모든 고통을 없애기위한 훌륭한 유틸리티입니다. 여기를 참조하십시오


4
base64와 sha1은 매우 다르므로 대안으로 제안하지 마십시오.
Ryan A.

13
@RyanA .: 알다시피, 그는 SHA1 해시를 16 진수 인코딩의 대안으로 base64를 제안합니다 (SHA1의 대안이 아니라).
helmbert

아직 시도하지는 않았지만 어떻게 작동하는지 설명하고 싶습니까?
Jivay

11
DigestUtils.sha1Hex("my string")바퀴를 재발 명하는 대신 같은 라이브러리를 사용하지 않는 이유는 무엇 입니까? (수동으로 16 진수로 변환하는 방법을 아는 것이 흥미 롭습니다)?
Jon Onstott 2016 년

3
이 답변이 작성되었을 때 DigestUtils (1.7는 2012 년 9 월에 릴리스 됨)에 해당 기능이 없었기 때문입니다. 이것을 지적 해 주셔서 감사합니다. +1
Nishant 2016 년

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.Formatter임을 지정하고 경고를 피하기 위해 끝에 formatter.close ()가 필요합니다.
Eric Chen

Shoudln encryptPassword("test")echo test|sha1sumLinux 터미널에서 동일한 결과를 출력하지 않습니까? 그들은하지 않습니다.
Tulains Córdova

@ TulainsCórdova 콘솔 호출 관련 :을 사용 echo test하면 줄 바꿈을 포함한 출력이로 파이프됩니다 sha1sum. 후행 줄 바꿈없이 일반 문자열을 해시하려면을 사용할 수 있습니다 echo -n test | sha1sum. 이 -n매개 변수는 echo줄 바꿈 을 생략합니다.
MrSnrub

의문의 여지가 없지만 일반적으로 더 많이 : encryptPassword()인증 데이터를 저장하는 데 사용되는 것처럼 들립니다. 시딩이 적용되지 않기 때문에 코딩은 사전 공격에 취약합니다. 보안 환경에서 응용 프로그램에 문제가 있는지 확인하십시오!
EagleRainbow


32

SHA-1 (및 기타 모든 해싱 알고리즘)은 이진 데이터를 반환합니다. 그것은 (자바에서)을 생성한다는 것을 의미합니다 byte[]. 그 byte배열은 않습니다 하지 당신이 단순히으로 바꿀 수 없음을 의미합니다 특정 문자를 나타냅니다 String당신이했던 것처럼합니다.

이 필요한 경우 로 표현할 수있는 방식으로 String형식을 지정해야 byte[]합니다 String(그렇지 않으면 byte[]주변을 유지하십시오 ).

byte[]인쇄 가능한 문자로 임의를 나타내는 두 가지 일반적인 방법 은 BASE64 또는 간단한 16 진 문자열입니다 (즉, 각각 byte16 진수 두 개로 표시). 16 진수 문자열을 생성하려고하는 것 같습니다.

또 다른 함정이있다 : 당신은 SHA-1 자바의를 얻으려면 String, 당신은 그것을 변환해야 StringA를 byte[](SHA-1의 입력이 그대로 첫번째 byte[]뿐만 아니라). 표시 myString.getBytes()한대로 간단히 사용 하는 경우 플랫폼 기본 인코딩을 사용하므로 실행하는 환경에 따라 다릅니다 (예 : OS의 언어 / 로캘 설정에 따라 다른 데이터를 반환 할 수 있음).

더 나은 솔루션은에 사용할 인코딩을 지정하는 것입니다 StringDi의 byte[]이 같은 변환 : myString.getBytes("UTF-8"). UTF-8 (또는 모든 유니 코드 문자를 나타낼 수있는 다른 인코딩)을 선택하는 것이 가장 안전한 선택입니다.


27

이것은 문자열을 16 진 형식으로 변환 할 때 사용할 수있는 간단한 솔루션입니다.

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 자로 된 문자열을 받게됩니다.
philn November

@ philn 솔루션을 제안 할 수 있습니까?
Nikita Koksharov

1
충분한 선행 0으로 byte []에서 큰 정수를 만들면 이러한 0이 손실됩니다. 따라서 16 진 문자열 표현 "0"은 존재하지 않으므로 39 자 이하의 문자로 해시가 발생합니다. 나는 위에서 petrnohejls 솔루션을 사용했고 잘 작동합니다.
philn

25

Apache Commons 코덱 라이브러리를 사용하십시오. DigestUtils 라는 유틸리티 클래스가 있습니다.

세부 정보를 얻을 필요가 없습니다.


51
나는 세부 사항으로 점점 종류의 전체 지점입니다, 동의
ninesided

12
문제는 세부 정보를 얻을 시간이 있는지 여부입니다. 모든 요점은 일반적으로 정시에 완료되는 것입니다. 모든 사람이 학생이거나 모든 세부 사항을 배울 수있는 사치가 아닙니다.
DaTroop

DigestUtils는 바이트 배열을 반환하므로 Hex.encodeHexString을 통해이를 실행하는 데 필요한 문자열 표현을 얻을 수 있습니다. 자바 : 그것은 2014 년 그리고 우리는 여전히 한 단계 샤 방법이 없습니다
ryber

5
하나는 SHA-1 단계에있어서 String result = DigestUtils.sha1Hex("An input string"), O)
존 Onstott

18

앞서 언급했듯이 아파치 커먼즈 코덱을 사용하십시오. Spring 사람들도 추천합니다 (Spring Doc의 DigestUtils 참조). 예 :

DigestUtils.sha1Hex(b);

여기에 최고 등급의 답변을 사용하지 않을 것입니다.


7

Base64 인코딩을 사용해야하므로 제대로 인쇄되지 않습니다. Java 8에서는 Base64 인코더 클래스를 사용하여 인코딩 할 수 있습니다 .

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

결과

이것은 당신에게 당신의 예상 출력을 줄 것입니다 5baa61e4c9b93f3f0682250b6cf8331b7ee68fd8


1
@Devenv는 SHA-1이며 세 개의 점은 sha1로 변환되는 원래 코드를 유지한다는 것을 의미합니다. OP의 원래 문제는 문자열을 올바르게 인쇄 할 때 발생했습니다.
Eduardo Dennis

4

메시지 요약 (해시)은 byte [] in byte [] out

메시지 다이제스트는 원시 바이트 배열을 사용하여 원시 바이트 배열 (일명 byte[])을 반환하는 함수로 정의됩니다 . 예를 들어 SHA-1 (Secure Hash Algorithm 1) 의 다이제스트 크기는 160 비트 또는 20 바이트입니다. 원시 바이트 배열은 일반적으로 UTF-8 과 같은 문자 인코딩 으로 해석 할 수 없습니다 . 모든 순서의 모든 바이트가 올바른 인코딩이 아니기 때문입니다. 따라서 와 함께 로 변환 :String

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

잘못된 시퀀스를 만들거나 정의되지 않은 유니 코드 매핑에 대한 코드 포인터가있을 수 있습니다 .

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

이진 텍스트 인코딩

이를 위해 이진 - 텍스트 인코딩에 사용됩니다. 해시에서 가장 많이 사용되는 것은 HEX 인코딩 또는 Base16 입니다. 기본적 바이트의 값을 가질 수 0255(또는 -128127의 HEX 표현에 해당 서명을) 0x00- 0xFF. 따라서 16 진수는 필요한 출력 길이의 두 배가됩니다. 즉, 20 바이트 출력은 40 자 길이의 16 진 문자열을 작성합니다.

2fd4e1c67a2d28fced849ee1bb76e7391b93eb12

16 진 인코딩을 사용할 필요는 없습니다. base64 와 같은 것을 사용할 수도 있습니다 . 16 진은 사람이 쉽게 읽을 수 있고 패딩없이 출력 길이가 정의되어 있기 때문에 종종 선호됩니다.

JDK 기능만으로 바이트 배열을 16 진으로 변환 할 수 있습니다.

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

그러나 BigInteger주어진 바이트 배열을 바이트 문자열이 아닌 숫자 로 해석 합니다. 즉, 선행 0이 출력되지 않고 결과 문자열이 40 자보다 짧을 수 있습니다.

라이브러리를 사용하여 HEX로 인코딩

이제 스택 오버플로에서 테스트되지 않은 바이트 대 16 진수 방법을 복사하여 붙여 넣거나 Guava 와 같은 대규모 종속성을 사용할 수 있습니다 .

대부분의 바이트 관련 문제에 대한 해결책을 찾기 위해 다음과 같은 경우를 처리하는 유틸리티를 구현했습니다. bytes-java (Github)

메시지 다이제스트 바이트 배열을 변환하려면 다음을 수행하십시오.

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

또는 내장 해시 기능을 사용할 수 있습니다

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

2

SHA1해시의 기본 64 표현 :

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

1

이것이 작동하지 않는 이유는를 호출 할 때 String(md.digest(convertme))암호화 된 바이트 시퀀스를 문자열로 해석하도록 Java에 지시하기 때문입니다. 원하는 것은 바이트를 16 진수 문자로 변환하는 것입니다.


0

바이트 배열을 16 진 문자열로 변환하십시오.

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);
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.