web-dev-qa-db-ja.com

Java文字列からSHA1

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である必要なものを取得するために何をすべきか教えてもらえますか?それとも私はこれを完全に間違っていますか?

135
Brian

UPDATE
Apache Commons Codec (バージョン1.7+)を使用して、このジョブを実行できます。

DigestUtils.sha1Hex(stringToConvertToSHexRepresentation)

この提案をしてくれた@ Jon Onstott に感謝します。


古い回答
バイト配列を16進文字列に変換します。 Real's How To tell you how

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;
}

ところで、Base64を使用すると、よりコンパクトな表現が得られる場合があります。 Apache Commons Codec API 1.4には、すべての痛みを取り除くためのこの素敵なユーティリティがあります。 こちらを参照

166
Nishant

これは、文字列をsha1に変換する私のソリューションです。私のAndroidアプリでうまく機能します:

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;
}
62
petrnohejl

Guava Hashing class を使用:

Hashing.sha1().hashString( "password", Charsets.UTF_8 ).toString()
51
Jan Schaefer

SHA-1(および他のすべてのハッシュアルゴリズム)はバイナリデータを返します。つまり、(Javaでは)byte[]を生成します。 byte配列はnotを使用して特定の文字を表します。つまり、単純にStringに変換することはできません。

Stringが必要な場合は、Stringとして表現できる方法でbyte[]をフォーマットする必要があります(そうでない場合は、byte[]をそのままにしておきます) 。

任意のbyte[]を印刷可能文字として表す2つの一般的な方法は、BASE64または単純な16進文字列(つまり、各byteを2桁の16進数で表す)です。 16進文字列を生成しようとしているようです。

別の落とし穴もあります:Java StringのSHA-1を取得したい場合、そのStringを最初にbyte[]に変換する必要があります(SHA-1の入力もbyte[]であるため) 。示したように単にmyString.getBytes()を使用する場合、プラットフォームのデフォルトエンコーディングが使用され、それを実行する環境に依存します(たとえば、OSの言語/ロケール設定に基づいて異なるデータを返すことができます)。

よりよい解決策は、String- to -byte[]変換に使用するエンコードを次のように指定することです:myString.getBytes("UTF-8")。ここでは、UTF-8(またはすべてのUnicode文字を表すことができる別のエンコーディング)を選択するのが最も安全な選択です。

28
Joachim Sauer

Apache commons codec libraryを使用するだけです。これらには DigestUtils というユーティリティクラスがあります

詳細に入る必要はありません。

26
DaTroop

これは、文字列を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);
}
23

前述のように、Apache commons codecを使用します。 Springの連中にも推奨されています(SpringドキュメントのDigestUtilsを参照)。例えば。:

DigestUtils.sha1Hex(b);

ここでは間違いなく最高評価の回答を使用しません。

18
kazuar

Base64エンコードを使用する必要があるため、正しく印刷されません。 Java 8では、 Base64 エンコーダークラスを使用してエンコードできます。

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

結果

これにより、5baa61e4c9b93f3f0682250b6cf8331b7ee68fd8の期待される出力が得られます。

4
Eduardo Dennis

SHA1ハッシュのBase 64表現:

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

メッセージダイジェスト(ハッシュ)はbyte [] in byte [] out

メッセージダイジェストは、生のバイト配列を受け取り、生のバイト配列(別名byte[])を返す関数として定義されます。たとえば、 SHA-1(Secure Hash Algorithm 1) のダイジェストサイズは160ビットまたは20バイトです。通常、生のバイト配列は 文字エンコードTF-8 のように解釈できません。これは、すべての順序のすべてのバイトがそのエンコードではないためです。したがって、それらをStringに変換するには:

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

いくつかの違法なシーケンスを作成したり、未定義のコードポインターを持っている可能性があります nicode マッピング:

[�a�ɹ??�%l�3~��.

バイナリからテキストへのエンコード

そのために binary-to-text エンコーディングが使用されます。ハッシュでは、最もよく使用されるのは HEX encodingまたはBase16 です。基本的に、バイトは0から255(または-128から127符号付き)の値を持つことができ、これは0x00-0xFFのHEX表現と同等です。したがって、16進数は出力の必要な長さを2倍にします。つまり、20バイトの出力では40文字の16進数文字列が作成されます。

2fd4e1c67a2d28fced849ee1bb76e7391b93eb12

16進エンコードを使用する必要はないことに注意してください。 base64 のようなものを使用することもできます。 16進数は、人間が読みやすく、パディングを必要とせずに出力長が定義されているため、しばしば好まれます。

JDK機能のみでバイト配列を16進数に変換できます。

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

ただし、BigIntegerは、指定されたバイト配列をバイト文字列ではなくnumberとして解釈することに注意してください。つまり、先行ゼロは出力されず、結果の文字列は40文字より短くなる可能性があります。

ライブラリを使用してHEXにエンコードする

スタックオーバーフローからテストされていないバイトから16進数のメソッドをコピーして貼り付ける 、または Guava のような大規模な依存関係を使用できます。

ほとんどのバイト関連の問題を解決するために、これらのケースを処理するユーティリティを実装しました。 bytes-Java(Github)

メッセージダイジェストバイト配列を変換するには、次のようにします。

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

または、組み込みのハッシュ機能を使用できます

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

これが機能しない理由は、String(md.digest(convertme))を呼び出すときに、Javaに暗号化されたバイトのシーケンスを文字列として解釈するように指示しているためです。必要なのは、バイトを16進文字に変換することです。

1
Zarkonnen

バイト配列を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);
}
0
abhihere