这个问题可能听起来有点愚蠢,但缺乏文档。
为了在Android中散列字符串,我们可以使用来自java.security包的MessageDigest
。
但是,基本设置如下:
MessageDigest.getInstance( "SHA-512" );
因此,这并不酷:
我们可以知道当前设备上有哪些算法可用吗?它取决于什么? Android SDK? Java SDK?这在Android中很痛苦,因为我们要处理的细分......
为什么我们没有这个字符串的常量/枚举?它们对全世界都不常见吗?
我希望你能回答我的两个问题。
感谢。
答案 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 )
哦,请注意,取决于:
计算可能是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
或相关命令获得的值。