Какие алгоритмы хэширования доступны в Android?
этот вопрос может показаться немного глупым, но есть недостаток документации.
чтобы хэшировать строки в Android, мы можем использовать MessageDigest
, который из java.пакет безопасности.
однако базовая настройка выглядит следующим образом:
MessageDigest.getInstance( "SHA-512" );
это не круто, поэтому:
можем ли мы знать, какие алгоритмы доступны на текущем устройстве? От чего это зависит? Android SDK? Java SDK? Это больно в Android, из-за сегментации, с которой мы должны справиться...
почему, черт возьми, у нас нет константы / перечисления для этой строки??? Разве они не обычны для всего мира?
Я надеюсь, что вы можете ответить на мои вопросы.
спасибо.
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.5 до 10 (или больше...), так что тебе лучше сделайте это в другом потоке =)
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+
это поможет?
Все, о чем я могу думать, это проб и ошибок. Узнайте, какие значения будет принимать hasher instantiator, и чтобы убедиться, что это правильный хэш, сравните вывод с тем, что вы получаете от sha256sum
или связанных команд.