Как вычислить TOTP номер аутентификатора Google в R? - PullRequest
1 голос
/ 30 октября 2019

Я хотел бы добавить двухфакторную аутентификацию в блестящее приложение, поэтому я пытался отработать реализацию TOTP в Google для аутентификатора Google. Я могу создать шестизначное число, но мое не соответствуетприложение. Мое лучшее предположение состоит в том, что SHA1 не выполняется должным образом, где я хэширую, используя ключ времени, а затем использую этот хеш в качестве ключа для второго хеша. Или, может быть, я не правильно понимаю нижнюю клевую или битовую маску?

Кто-нибудь может увидеть, где я ошибаюсь?

Я использую этот сайт в качестве руководства, в том числессылка на его код Go: https://garbagecollected.org/2014/09/14/how-google-authenticator-works/

Я также пытался digest::digest(x, algo="sha1", serialize=FALSE), но он не позволяет мне указать ключ, поэтому я не знаю, может ли это сработать.

library(qrcode)
library(openssl)
library(base64url)

secret <- "supersecret"
secret32 <- base64url::base32_encode(secret)
secretmsg <- paste0("otpauth://totp/R%20Authenticator%20test?secret=", secret32, "&issuer=test")
qrcode::qrcode_gen(secretmsg)

# use math to convert from raw to integer, allow for lower nibble and unsign
rawToInt <- function(x, part=NULL, bits=FALSE) {
    if(!bits) x <- rawToBits(x)
    logivect <- as.logical(x)
    if(length(part)) {
        if(part == "l") logivect <- logivect[1:4] # lower nibble
        else if(part == "m") logivect[length(logivect)] <- FALSE # mask most sig. bit
    }
    sum(2^(which(logivect)-1))
} 

# Generate a six-digit number
authenticator <- function(secret) {
    # Unix time
    n <- as.numeric(Sys.time())
    # The hash
    hmac <- openssl::sha1(secret, key=openssl::sha1(secret, key=format(n%/%30)))
    # Convert hash to raw
    hmac_raw <- charToRaw(hmac)
    # Take the last byte
    last_byte <- hmac_raw[(length(hmac_raw)-1):length(hmac_raw)]
    # Use only the first 4 bits (lower nibble), R puts least sig bits at left
    offset <- rawToInt(last_byte, part='l')
    # multiply by 2 because R reports each byte as 2 hex chars, 
    # add 1 because R indexes from 1
    offset <- (offset*2+1):(offset*2+8)
    four_bytes <- hmac_raw[offset]
    # Convert to int
    large_integer <- readBin(four_bytes, integer(), size=4)
    # Mask most sig. bit
    large_integer <- intToBits(large_integer)
    large_integer[length(large_integer)] <- as.raw(0)
    large_integer <- rawToInt(large_integer, bits=TRUE)
    small_integer <- large_integer %% 1e6
    # Make it print pretty
    nc <- nchar(small_integer)
    small_int_print <- paste0(paste0(rep(0, 6-nc), collapse=""), format(small_integer, big.mark=" "))
    # Time remaining
    remain <- round(30-n%%30)
    cat(
        remain, "seconds remaining\n",
        small_int_print, "\n"
    )
    invisible(small_integer)
}

authenticator(secret=secret)

1 Ответ

1 голос
/ 31 октября 2019

Подтвердили ли вы, что время синхронизируется на сервере, на котором вы генерируете 6-значный код, и на телефоне, на котором запущено приложение? Обязательно настройте NTP на промежуточном сервере и синхронизируйте время, а также, возможно, синхронизируйте время в приложении Google Authenticator на своем телефоне.

Из Документов Google:

По умолчанию токены действительны в течение 30 секунд, и для компенсации возможного перекоса времени между клиентом и сервером мы разрешаем дополнительный токен до и после текущего времени. Если у вас возникают проблемы с плохой синхронизацией времени, вы можете увеличить размер окна по умолчанию от 1: 30 минут до примерно 4 минут.

Сравните минуты и секунды с некоторыми ссылками на сайты следующим образом: https://www.timeanddate.com/

Время синхронизации в приложении Google Authenticator для Android / iOS:

https://support.google.com/accounts/answer/185834?hl=en

Прокрутите до самого нижнего раздела: «Мои коды Google Authenticator не работают (Android)»

...