2016-11-01 20 views
3

В настоящее время я пытаюсь воссоздать генератор паролей Google One Time. Я использую общий секрет, созданный при настройке Google Authenticator. Я пробовал смотреть в источники Google Authenticator и по всему интернету, и я нахожу много общего с моим кодом, но я не могу найти, где я ошибаюсь. Первая часть похоже правильный. Что касается hmac, я не думаю, что могу испортить здесь, но я могу ошибаться. Усекающая часть по-прежнему немного размыта для меня, и я пробовал много разных реализаций, но я просто не могу получить рабочий OTP. (Я использую Google Authenticator для сравнения результатов)Google OTP Generation Java

private String truncateHash(byte[] hash) { 
    int offset = hash[hash.length - 1] & 0xF; 

    long truncatedHash = 0; 
    for (int i = 0; i < 4; ++i) { 
     truncatedHash <<= 8; 
     truncatedHash |= (hash[offset + i] & 0xFF); 
    } 

    truncatedHash &= 0x7FFFFFFF; 
    truncatedHash %= 1000000; 

    int code = (int) truncatedHash; 
    String result = Integer.toString(code); 
    for (int i = result.length(); i < 6; i++) { 
     result = "0" + result; 
    } 
    return result; 
} 

private byte[] hmacSha1(byte[] value, byte[] keyBytes) { 
    try { 
     Mac mac = HmacUtils.getHmacSha1(keyBytes); 

     byte[] rawHmac = mac.doFinal(value); 

     return new Hex().encode(rawHmac); 
    } catch (Exception e) { 
     throw new RuntimeException(e); 
    } 
} 

public String GoogleAuthenticatorCode(String secret) throws UnsupportedEncodingException { 
    Base32 base = new Base32(); 
    byte[] key = base.decode(secret); 

    //Update from Andrew Rueckert's response 
    long value = new Date().getTime()/TimeUnit.SECONDS.toMillis(30); 

    byte[] data = new byte[8]; 
    for (int i = 8; i-- > 0; value >>>= 8) { 
     data[i] = (byte) value; 
    } 
    // 

    System.out.println("Time remaining : " + new Date().getTime()/1000 % 30); 

    byte[] hash = hmacSha1(data, key); 

    return truncateHash(hash); 
} 

UPDATE: Я попытался скопировать и вставить код из ссылки ответа сервлета Эндрю Рюкерт, а также этот https://github.com/wstrange/GoogleAuth/blob/master/src/main/java/com/warrenstrange/googleauth/GoogleAuthenticator.java и один из RFC 4226. Ни один из них не дает мне правильный OTP

Может ли кто-нибудь просветить меня, пожалуйста?

ответ

0

Я решил свою проблему, поэтому решил, что отправлю ее там, если кому-то это понадобится.
Это было частично из-за использования класса Base32, который не возвращал правильный ключ. Усечение не было правильным.

Он совместим с приложением Google Authenticator.

import org.apache.commons.codec.binary.Hex; 
import javax.crypto.Mac; 
import javax.crypto.spec.SecretKeySpec; 
import java.util.Date; 
import java.util.concurrent.TimeUnit; 

public class Authentication { 

    Authentication() {}; 

    private String truncateHash(byte[] hash) { 
     String hashString = new String(hash); 
     int offset = Integer.parseInt(hashString.substring(hashString.length() - 1, hashString.length()), 16); 

     String truncatedHash = hashString.substring(offset * 2, offset * 2 + 8); 

     int val = Integer.parseUnsignedInt(truncatedHash, 16) & 0x7FFFFFFF; 

     String finalHash = String.valueOf(val); 
     finalHash = finalHash.substring(finalHash.length() - 6, finalHash.length()); 

     return finalHash; 
    } 

    private byte[] hmacSha1(byte[] value, byte[] keyBytes) { 
     SecretKeySpec signKey = new SecretKeySpec(keyBytes, "HmacSHA1"); 
     try { 
      Mac mac = Mac.getInstance("HmacSHA1"); 

      mac.init(signKey); 

      byte[] rawHmac = mac.doFinal(value); 

      return new Hex().encode(rawHmac); 
     } catch (Exception e) { 
      throw new RuntimeException(e); 
     } 
    } 

    public String GoogleAuthenticatorCode(String secret) throws Exception { 
     if (secret == null || secret == "") { 
      throw new Exception("Secret key does not exist."); 
     } 
     long value = new Date().getTime()/TimeUnit.SECONDS.toMillis(30); 

     Base32 base = new Base32(Base32.Alphabet.BASE32, false, true); 
     byte[] key = base.fromString(secret); 

     byte[] data = new byte[8]; 
     for (int i = 8; i-- > 0; value >>>= 8) { 
      data[i] = (byte) value; 
     } 

     byte[] hash = hmacSha1(data, key); 

     return truncateHash(hash); 
    } 

} 

Base32 я доступен здесь при необходимости вместе с остальной частью проекта:
https://github.com/Poncholay/OTPGenerator/blob/master/src/main/java/com/requireris/app/web/rest/Base32.java

2

Ваш byte value[] должен быть байтовым представлением времени как длинным, и похоже, что в настоящее время это байтовое представление этого числа как строка символов цифр. Вместо

Double time = floor(new Date().getTime()/1000/30); 
String message = String.valueOf(time.intValue()); 
byte[] value = message.getBytes("UTF-8"); 
byte[] hash = hmacSha1(value, key); 

Вы бы хотели что-то вроде:

// decimal truncation is free when dealing with int/long 
long value = new Date().getTime()/1000/30; 
byte[] data = new byte[8]; 
for (int i = 8; i-- > 0; value >>>= 8) { 
    data[i] = (byte) value; 
} 
byte[] hash = hmacSha1(data, key); 

мне удалось получить реализацию Google TOTP создать, следуя this guide, если вы хотите еще один ресурс, чтобы заглянуть.

+0

Эй, спасибо за совет. Но он все еще не работает. Я даже пытался копировать и вставлять код из вашей ссылки, а также этот https://github.com/wstrange/GoogleAuth/blob/master/src/main/java/com/warrenstrange/googleauth/GoogleAuthenticator.java и тот из RFC 4226. Ни один из них не дает мне правильный ОТП. –

+0

В 'hmacSha1' вместо' return new Hex(). Encode (rawHmac); ', попробуйте' return rawHmac; '. Я не использую Hex вообще в моей реализации. –

 Смежные вопросы

  • Нет связанных вопросов^_^