2016-11-01 8 views
3

現在、Googleワンタイムパスワードジェネレータを再作成しようとしています。 Google認証システムを設定するときに生成された共有秘密情報を使用します。 私はGoogle Authenticatorのソースを調べ、実際にインターネット上のすべてを調べてみましたが、コードとの類似点はたくさんありますが、私が間違っている場所を見つけることはできません。 最初の部分は正しいようです。 hmacに関しては、私はここで混乱するとは思わないが、私は間違っているかもしれない。切り詰め部分はまだ私のために少しぼやけていて、私はさまざまな実装を試しましたが、私はうまくいくOTPを手に入れることができません。 (私は結果を比較するためにGoogle認証を使用しています)Google OTP生成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: 私はコピーを試してみましたが、アンドリューRueckertの応答者のリンクからコードだけでなく、この1 https://github.com/wstrange/GoogleAuth/blob/master/src/main/java/com/warrenstrange/googleauth/GoogleAuthenticator.javaRFC 4226から1を貼り付けます。これらのどちらも正しいOTPを教えてくれません

誰も私を啓発できますか?

答えて

0

私は自分の問題を解決したので、誰かがそれを必要とする場合に備えてそこに投稿すると思った。
私が使用していたBase32クラスが正しいキーを返さなかったために部分的でした。切り詰めも正しくありませんでした。

Google認証システムアプリと互換性があります。

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[]は時間のバイト表現である必要があり、現時点では数字の文字列としてのその数字のバイト表現のようです。

// 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); 

は、私はあなたに見て1つの以上のリソースをしたい場合は、this guideを次によって設定GoogleのTOTPの実装を取得するために管理:その代わり

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

のあなたのような何かをしたいと思います。

+0

ねえ、アドバイスに感謝。しかし、それはまだ動作していないようです。私はあなたのリンクだけでなく、この1つのhttps://github.com/wstrange/GoogleAuth/blob/master/src/main/java/com/warrenstrange/googleauth/GoogleAuthenticator.javaのコードをコピーして貼り付けようと試みました。 RFC 4226から。どちらも正しいOTPを与えてくれません。 –

+0

'hmacSha1'では、' return new Hex()。encode(rawHmac); 'の代わりに、' return rawHmac; 'を試してください。私は私の実装でHexを全く使用していません。 –

関連する問題