es.davy.ai

Preguntas y respuestas de programación confiables

¿Tienes una pregunta?

Si tienes alguna pregunta, puedes hacerla a continuación o ingresar lo que estás buscando.

Cómo manejar una clave secreta de 26 bytes para una contraseña única basada en el tiempo (Time-based One Time Password)?

El Secreto de la Contraseña de un Solo Uso Basado en el Tiempo generalmente es una cadena codificada en base32 de 16 bytes. Por ejemplo, la autenticación de dos factores (2FA) de GitHub.

Pero para algunos escenarios, tiene una longitud de 26 bytes. Por ejemplo, el OTP (Contraseña de un Solo Uso) de Tutanota. A menudo en minúsculas con espacios en blanco, como: vev2 qjea un45 3sr4 q4h3 ais4 ci

He intentado con el algoritmo TOTP implementado en dgryski/dgoogauth y tilaklodha/google-authenticator. Ambos pueden manejar bien el secreto de 16 bytes, pero dan error para el secreto de 26 bytes.

Por ejemplo, para el secreto de 16 bytes VEV2QJEAUN453SR4:

bash
Tiempo: 2021-12-17 14:31:46
Obtenido: 079119

Para el secreto de 26 bytes VEV2QJEAUN453SR4Q4H3AIS4CI:

bash
Error: "datos base32 no válidos en el byte de entrada 24"

Aquí está el fragmento de código:

func getHOTPToken(secret string, interval int64) (string, error) {
    // Convierte el secreto a Codificación base32
    key, err := base32.StdEncoding.DecodeString(secret)
    if err != nil {
        return "", err
    }

    // Firmar el valor usando el Algoritmo HMAC-SHA1
    hash := hmac.New(sha1.New, key)
    err = binary.Write(hash, binary.BigEndian, uint64(interval))
    if err != nil {
        return "", err
    }
    h := hash.Sum(nil)

    // Obtener un fragmento de 32 bits del hash comenzando en el desplazamiento
    offset := h[19] & 0x0f
    truncated := binary.BigEndian.Uint32(h[offset : offset+4])
    truncated &= 0x7fffffff
    code := truncated % 1000000

    return fmt.Sprintf("%06d", code), nil
}

¿Puede decirme por favor cómo manejar un secreto de 26 bytes?

Tags:  , , ,

Answer

  1. Avatar for davy.ai

    Para manejar un secreto de 26 bytes, es necesario modificar el fragmento de código para manejar la entrada más grande. Una opción es usar una codificación base32 diferente, como “z-base-32”, que puede manejar entradas de hasta 40 bytes. Otra opción es utilizar un algoritmo diferente para generar el HMAC, como SHA256. Aquí hay una modificación de ejemplo del fragmento de código para manejar un secreto de 26 bytes utilizando la codificación z-base-32:

    import "github.com/crosscode-nl/z-base32"
    
    func getHOTPToken(secret string, interval int64) (string, error) {
        // Decodificar el secreto utilizando z-base-32
        key, err := zbase32.DecodeString(secret)
        if err != nil {
            return "", err
        }
    
        // Firmar el valor utilizando el algoritmo HMAC-SHA1
        hash := hmac.New(sha1.New, key)
        err = binary.Write(hash, binary.BigEndian, uint64(interval))
        if err != nil {
            return "", err
        }
        h := hash.Sum(nil)
    
        // Obtener un fragmento de 32 bits del hash desde el desplazamiento
        offset := h[19] & 0x0f
        truncated := binary.BigEndian.Uint32(h[offset : offset+4])
        truncated &= 0x7fffffff
        code := truncated % 1000000
    
        return fmt.Sprintf("%06d", code), nil
    }
    

    Ten en cuenta que esta modificación utiliza el paquete z-base32, que se puede instalar utilizando go get github.com/crosscode-nl/z-base32. Alternativamente, puedes elegir una biblioteca de codificación diferente que admita z-base-32 u otra codificación adecuada.

Comments are closed.