Executando verificação de segurança...
4

HOTP & TOTP Migration - O que o "QR-Code para migração" carrega de informação?

Relato

Precisando migrar de dispositivo o gerador de token TOTP (ou HOTP), notei que vários aplicativos autenticadores 2FA permitem transferir as configurações do algoritmo de hash, quantidade de dígitos gerados e chave secreta por meio de QR-Code. Com tal tecnologia para transferência de dados evita-se erros caso fosse necessário copiar manualmente tais detalhes. A longa chave secreta (cerca de 20 bytes), apesar de ser codificada em BASE32 ao invés de BASE64 ou sequência hexadecimal, torna-se ainda uma string relativamente mais longa.

!QR-CODE image supressed!

Aprendizado

Do QR-Code gerado pelo aplicativo para fins de migração é possivel obter a raw string usando algum leitor offline para tais QR-Codes.

[!CAUTION]
OFFLINE já que os segredos contidos no QR-Code jamais devem ser revelados com aplicações online, loggers etc. ou mantidos visíveis após a tranferência do conteúdo para outros dispositivos. Em seguida entende-se as razões, sabendo-se o conteúdo que carregam.

otpauth-migration://offline?data=CkoKD/EwZ5q6g80oq98RRQnD2hIgX0ZpY3RpY2lvdXNfTmFtZTp1c2VyQGRvbWFpbi50bGQaD0lzc3Vlcl9Db21wYW55ZSABKAEwAhABGAEgAA=='

cujo conteúdo em data, codificado em BASE64, pode ser decodificado usando algumas aplicações na linha de comando do terminal Linux:

$ data='CkoKD/EwZ5q6g80oq98RRQnD2hIgX0ZpY3RpY2lvdXNfTmFtZTp1c2VyQGRvbWFpbi50bGQaD0lzc3Vlcl9Db21wYW55ZSABKAEwAhABGAEgAA=='

$ echo -ne "${data}" | base64 -d | hexdump -Cv 

que resulta

00000000  0a 4a 0a 0f f1 30 67 9a  ba 83 cd 28 ab df 11 45  |.J...0g....(...E|
00000010  09 c3 da 12 20 5f 46 69  63 74 69 63 69 6f 75 73  |.... _Ficticious|
00000020  5f 4e 61 6d 65 3a 75 73  65 72 40 64 6f 6d 61 69  |_Name:user@domai|
00000030  6e 2e 74 6c 64 1a 0f 49  73 73 75 65 72 5f 43 6f  |n.tld..Issuer_Co|
00000040  6d 70 61 6e 79 65 20 01  28 01 30 02 10 01 18 01  |mpanye .(.0.....|
00000050  20 00                                             | .|
00000052

O conteúdo é uma stream binária que traz algumas informações em texto e parte em sequências hexadecimais. A rigor, o conteúdo está em formato Protobuf contendo alguns parâmetros aqui interpretados "manualmente" usando algumas receitas [1] [2] [3] disponíveis na internet:

0a 4a

Secret:
0a 0f
f1 30 67 9a  ba 83 cd 28  ab df 11 45  09 c3 da

Name:
12 20
5f 46 69 63  74 69 63 69  6f 75 73 5f  4e 61 6d 65  3a 75 73 65  72 40 64 6f  6d 61 69 6e  2e 74 6c 64

Issuer:
1a 0f
49 73 73 75  65 72 5f 43  6f 6d 70 61  6e 79 65

Algorithm:
20 01

Digits:
28 01

Type:
30 02

Version:
10 01 

Batch size:
18 01

Batch index
20 00                                           

O mesmo pode ser facilmente decodificado utilizando o seguinte proto file disponibilizado em alexbakker e a aplicação protoc instalável em Debian com sudo apt-get install protobuf-compiler

O arquivo *.proto contém a definição do pacote de bytes e torna possível a extração dos dados segundo seus tipos definidos neste arquivo de esquema.

Arquivo: migration.proto

syntax = "proto3";

message MigrationPayload {
  enum Algorithm {
    ALGORITHM_UNSPECIFIED = 0;
    ALGORITHM_SHA1 = 1;
    ALGORITHM_SHA256 = 2;
    ALGORITHM_SHA512 = 3;
    ALGORITHM_MD5 = 4;
  }

  enum DigitCount {
    DIGIT_COUNT_UNSPECIFIED = 0;
    DIGIT_COUNT_SIX = 1;
    DIGIT_COUNT_EIGHT = 2;
  }

  enum OtpType {
    OTP_TYPE_UNSPECIFIED = 0;
    OTP_TYPE_HOTP = 1;
    OTP_TYPE_TOTP = 2;
  }

  message OtpParameters {
    bytes secret = 1;
    string name = 2;
    string issuer = 3;
    Algorithm algorithm = 4;
    DigitCount digits = 5;
    OtpType type = 6;
    int64 counter = 7;
  }

  repeated OtpParameters otp_parameters = 1;
  int32 version = 2;
  int32 batch_size = 3;
  int32 batch_index = 4;
  int32 batch_id = 5;
}

e agora chamando tudo junto na linha de comando do terminal

$ echo -ne "${data}" | base64 -d | protoc --decode=MigrationPayload --proto_path=./ migration.proto

produz-se uma saída mais amigável

otp_parameters {
  secret: "\3610g\232\272\203\315(\253\337\021E\t\303\332"
  name: "_Ficticious_Name:[email protected]"
  issuer: "Issuer_Companye"
  algorithm: ALGORITHM_SHA1
  digits: DIGIT_COUNT_SIX
  type: OTP_TYPE_TOTP
}
version: 1
batch_size: 1

Aqui a chave secreta, com apenas 15 bytes, é dada numa sequência de caracteres ASCII e códigos em base octal para aqueles caracteres não imprimíveis.

Ideias

A chave secreta pode então ser utilizada em outras aplicações standalone [1], online [2], [3], embarcadas em microcontroladores [4], entre outras possibilidades para geração dos tokens TOTP. Deve-se considerar o mesmo algoritmo hash e quantidade de dígitos sendo que a chave secreta jamais deve ser revelada. Se implementado em um microcontrolador, escolher dispositivos que possuam trava lógica anticópia do seu firmware.

Lições revisadas

  • TOTP, HOTP
  • Protobuf
  • BASE32, BASE64

Siglas utilizadas

TOTP = Time-Based One-Time Password
HOTP = HMAC-Based One-Time Password
HMAC = Hashed Message Authentication Code

Esse pequeno reporte apresentou uma solução ligeiramente diferente em comparação ao conteúdo de uma matéria publicada no Medium recentemente. Espera-se que o conteúdo apresentado seja útil para quem já teve a mesma curiosidade, seja para entender esses recursos utilizados em 2FA ou mesmo implementar soluções independentes de bibliotecas de terceiros para suas aplicações online ou standalone embarcadas.


Post-Scriptum: Após postar este conteúdo encontrei mais uma postagem aqui no Tabnews criada há cerca de dois anos.

Carregando publicação patrocinada...