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�ɹ??�%l�3~��.

이진 텍스트 인코딩

이를 위해 이진 - 텍스트 인코딩에 사용됩니다. 해시에서 가장 많이 사용되는 것은 HEX 인코딩 또는 Base16 입니다. 기본적 바이트의 값을 가질 수 0로 255(또는 -128행 127의 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.