Bon*_*ono 6 python django one-time-password google-authenticator two-factor-authentication
我已经尝试直接插入默认密码:'thiswasmysecretkeyused'和秘密
的base64.b32encode()编码版本:
'ORUGS43XMFZW26LTMVRXEZLUNNSXS5LTMVSA===='在Google身份验证器应用程序中,但这些都生成了与服务器不同的代码.
我读到====密钥的尾随可能导致它不起作用,所以我尝试添加一个没有那些.仍然没有好的结果(他们生成相同的代码)
我尝试使用不同的算法来生成TOTP代码,因为我使用的算法(django-otp)不太可能.我使用的不同算法来自这个答案.当使用相同的密钥时,两种算法都生成相同的代码.
我检查了我的系统上的时间.我看到操作系统显示15:03就像我的智能手机一样.用两者在python中转储时间后time.time(),datetime.datetime.now()我看到返回的时间比操作系统时间晚了一个小时; 显示14:03.我尝试3600在用于代码生成的时间戳中添加秒,但无济于事.
我已经尝试过其他一些东西,但不能完全回想起它们是什么.
我查找了接受Google身份验证器中密钥的代码,并验证了它是否需要一个base32字符串.因此,据我所知,我的密钥编码是正确的.从代码(EnterKeyActivity.java,第78行):
验证输入字段是否包含有效的base32字符串
def generate_shared_key(self):
# create hash etc.
return base64.b32encode(hasher.hexdigest())
Run Code Online (Sandbox Code Playgroud)
生成QR码;
key = authenticator.generate_shared_key()
qrcode = pyqrcode.create('otpauth://totp/someurl.nl?secret=' + key)
Run Code Online (Sandbox Code Playgroud)
生成TOTP代码;
def generate_code(self, drift_steps=0, creation_interval=30, digits=6, t0=0):
code = str(totp(self.generate_shared_key(), creation_interval, timestamp, digits, drift_steps))
return code.zfill(digits)
Run Code Online (Sandbox Code Playgroud)
如果您需要更多代码,例如django-otp actual totp生成代码,请告诉我.
我还注意到在另一个算法中我使用的秘密首先被解码;
key = base64.b32decode(secret, True)
Run Code Online (Sandbox Code Playgroud)
我的原始密钥(SHA512哈希)是错误的吗?我应该或不应该编码base64.b32encode()吗?如果我尝试扫描生成的QR代码而不对哈希进行编码,Google身份验证器表示它不会将其识别为(有效)密钥.
好吧,在深入了解Google身份验证器的代码之后,我终于找到了我做错的事情.
就这么清楚:Google Authenticator 确实希望base32编码的字符串是一个秘密.因此,无论您是手动输入还是通过QR码输入,都必须确保base32在将其提供给Google身份验证器时,您的密码是编码字符串.
/*
* Verify that the input field contains a valid base32 string,
* and meets minimum key requirements.
*/
private boolean validateKeyAndUpdateStatus(boolean submitting) {
//...
}
Run Code Online (Sandbox Code Playgroud)
Google身份验证器会按原样存储您在数据库中提供的密钥.所以这意味着它将base32您的秘密字符串直接存储在数据库中.
private String getEnteredKey() {
String enteredKey = mKeyEntryField.getText().toString();
return enteredKey.replace('1', 'I').replace('0', 'O');
}
protected void onRightButtonPressed() {
//...
if (validateKeyAndUpdateStatus(true)) {
AuthenticatorActivity.saveSecret(this, mAccountName.getText().toString(), getEnteredKey(), null, mode, AccountDb.DEFAULT_HOTP_COUNTER);
exitWizard();
}
//...
}
Run Code Online (Sandbox Code Playgroud)
static boolean saveSecret(Context context, String user, String secret, String originalUser, OtpType type, Integer counter) {
//...
if (secret != null) {
AccountDb accountDb = DependencyInjector.getAccountDb();
accountDb.update(user, secret, originalUser, type, counter);
//...
}
}
Run Code Online (Sandbox Code Playgroud)
当Google身份验证器从数据库中检索秘密时,它会对base32字符串进行解码,以便它可以使用真正的秘密.
来自OtpProvider:
private String computePin(String secret, long otp_state, byte[] challenge) throws OtpSourceException {
//...
try {
Signer signer = AccountDb.getSigningOracle(secret);
//...
}
}
Run Code Online (Sandbox Code Playgroud)
来自AccountDb:
static Signer getSigningOracle(String secret) {
try {
byte[] keyBytes = decodeKey(secret);
//...
}
}
private static byte[] decodeKey(String secret) throws DecodingException {
return Base32String.decode(secret);
}
Run Code Online (Sandbox Code Playgroud)
我的错误是,在服务器端,我使用base32编码密钥生成TOTP代码,因为我认为Google身份验证器也使用了它.事后看来,它当然非常符合逻辑,但我找不到太多关于此的信息.希望这将有助于将来更多的人.
确保传递给Google身份验证器的密钥/密钥是base32编码字符串.确保在服务器端您没有使用base32编码的字符串,而是使用已解码的字符串.在Python中,您可以对密码/密钥进行编码和解码,如下所示:
import base64
base64.b32encode(self.key)
base64.b32decode(self.key)
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
1621 次 |
| 最近记录: |