Android中有哪些哈希算法?

时间:2014-04-29 20:04:54

标签: java android security hash

这个问题可能听起来有点愚蠢,但缺乏文档。

为了在Android中散列字符串,我们可以使用来自java.security包的MessageDigest

但是,基本设置如下:

MessageDigest.getInstance( "SHA-512" );

因此,这并不酷:

  1. 我们可以知道当前设备上有哪些算法可用吗?它取决于什么? Android SDK? Java SDK?这在Android中很痛苦,因为我们要处理的细分......

  2. 为什么我们没有这个字符串的常量/枚举?它们对全世界都不常见吗?

  3. 我希望你能回答我的两个问题。

    感谢。

3 个答案:

答案 0 :(得分:3)

正如有人已经提到的那样,没有明确的方法可以找出哪些算法可用。所以我决定做的就是为此创建一个帮手。

import android.util.Base64;

import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.spec.KeySpec;

import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.PBEKeySpec;

/**
 * Created by sergi.castellsague on 04/05/2014.
 */
public class SecurityManager
{
private static final int ITERATIONS = 1000;

public enum HashMethod
{
    PBKDF2(){
        @Override
        public String getHashString()
        {
            return "PBKDF2WithHmacSHA1";
        }
    }, SHA512(){
        @Override
        public String getHashString() {
            return "SHA-512";
        }
    }, SHA384() {
        @Override
        public String getHashString() {
            return "SHA-384";
        }
    }, SHA256() {
        @Override
        public String getHashString () {
            return "SHA-256";
        }
    }
    , SHA1()
    {
        @Override
        public String getHashString() {
            return "SHA-1";
        }
    };

    public abstract String getHashString();

}

public static HashMethod getAppropriateHash()
{
    HashMethod method = null;

    if ( isPBKDFAvailable() )
    {
        method = HashMethod.PBKDF2;
    }
    else if( isDigestAvailable( HashMethod.SHA512.getHashString() ) )
    {
        method = HashMethod.SHA512;
    }
    else if( isDigestAvailable( HashMethod.SHA384.getHashString() ) )
    {
        method = HashMethod.SHA384;
    }
    else if( isDigestAvailable( HashMethod.SHA256.getHashString() ) )
    {
        method = HashMethod.SHA256;
    }
    else if( isDigestAvailable( HashMethod.SHA1.getHashString() ) )
    {
        method = HashMethod.SHA1;
    }

    return method;
}


private static boolean isPBKDFAvailable()
{
    try
    {
        SecretKeyFactory.getInstance( HashMethod.PBKDF2.getHashString() );
    }
    catch ( Exception notAvailable)
    {
        return false;
    }
    return true;
}

private static boolean isDigestAvailable( String method )
{
    try
    {
        MessageDigest.getInstance( method );
    }
    catch ( Exception notAvailable )
    {
        return false;
    }

    return true;
}

public static String getHashedPassword( HashMethod method, String password )
{
    String hashed;

    if ( HashMethod.PBKDF2.getHashString().equals( method.getHashString() ) )
    {
        hashed = generatePBKDF( password );
    }
    else
    {
        hashed = password;
        for ( int i = 0; i < ITERATIONS; i++ )
        {
            hashed = generateDigestPassword( password, method.getHashString() );
        }
    }

    return hashed;
}

private static String generatePBKDF( String password )
{
    // Generate a 512-bit key
    final int outputKeyLength = 512;

    char[] chars = new char[password.length()];
    password.getChars( 0, password.length(), chars, 0 );
    byte[] salt = "salt_on_client_is_funny".getBytes(); // In security terms, this is worthess. However, it's required.

    byte[] hashedPassBytes = new byte[0];
    try
    {
        SecretKeyFactory secretKeyFactory = SecretKeyFactory.getInstance( HashMethod.PBKDF2.getHashString() );
        KeySpec keySpec = new PBEKeySpec( chars, salt, ITERATIONS, outputKeyLength );

        hashedPassBytes = secretKeyFactory.generateSecret( keySpec ).getEncoded();
    }
    catch ( Exception shouldNotHappen )
    {}

    return Base64.encodeToString( hashedPassBytes, Base64.DEFAULT );
}

private static String generateDigestPassword( String password, String algorithm )
{
    byte[] digest = new byte[0];
    byte[] buffer = password.getBytes();

    try {
        MessageDigest messageDigest = MessageDigest.getInstance( algorithm );
        messageDigest.reset();
        messageDigest.update( buffer );
        digest = messageDigest.digest();
    }
    catch ( NoSuchAlgorithmException ex )
    {}

    return Base64.encodeToString(digest, Base64.DEFAULT);
}
}

用法非常简单:

String password = "BestPasswordEver123!!";
SecurityManager.HashMethod hashMethod = SecurityManager.getAppropriateHash();
SecurityManager.getHashedPassword( hashMethod, password )

哦,请注意,取决于:

  1. 使用的算法
  2. 迭代量
  3. 设备
  4. 计算可能是0.5s到10s(或更多......),所以你最好在另一个Thread中做这个=)

答案 1 :(得分:2)

https://developer.android.com/reference/java/security/MessageDigest.html显示以下内容:

Name    | Supported (API Levels)
MD5     | 1+
SHA-1   | 1+
SHA-224 | 1–8,22+
SHA-256 | 1+
SHA-384 | 1+
SHA-512 | 1+

这有帮助吗?

答案 2 :(得分:0)

我能想到的只是反复试验。找出hasher instantiator将接受哪些值,并确保它正确的哈希比较输出与从sha256sum或相关命令获得的值。