publicado

Categories iOS
Stack SwiftUI, Keychain, iCloud, CryptoKit

overview

O Lockat é um aplicativo de autenticação de dois fatores com foco em privacidade, criado nativamente para iOS. Ele nasceu de um desafio na Apple Developer Academy: pegar uma ideia do zero e transformá-la num produto real, publicado na App Store. Chegamos no tema de 2FA depois de uma rodada de pesquisa sobre os concorrentes, que revelou algo curioso: a maioria dos apps existentes parecia inacabada, sem coisas simples como ordenação A–Z ou organização por pastas. Esse vazio nos pareceu um bom lugar para fincar a bandeira.

A estratégia de produto saiu naturalmente daí. Mantivemos tudo o que importa para manter as contas seguras (geração de códigos, importação, exportação) completamente gratuito e plenamente funcional. Reservamos os recursos mais avançados de organização e personalização para uma assinatura. O raciocínio era direto: ninguém deveria ter que pagar para se proteger online, mas quem quisesse uma ferramenta mais bem cuidada teria algo que valesse a pena pagar.

Por baixo do capô, os segredos ficam no próprio dispositivo, guardados no Keychain do iOS e protegidos pela criptografia em hardware da Apple, enquanto os metadados não sensíveis sincronizam via iCloud. Assim os códigos te acompanham entre iPhone, iPad e Mac. A versão para Mac roda pelo modo "Designed for iPad", o que permitiu a um time pequeno cobrir três plataformas a partir de uma única base de código em SwiftUI, sem abrir mão do feel nativo. Face ID, Touch ID e bloqueio por senha são integrados via LocalAuthentication, e o gerador de TOTP em si é uma implementação limpa, em conformidade com a RFC 6238, sobre o CryptoKit. Também existe uma migração com um toque a partir do Google Authenticator, que acabou sendo o recurso que mais pesou no onboarding.

Comercialmente, o Lockat não decolou. A categoria de 2FA é dominada por apps gratuitos de empresas em que os usuários já confiam. Furar essa barreira é difícil, e foi mais complicado do que prevíamos. Mas o que eu levo do projeto é concreto: um entendimento prático da stack de segurança da Apple, a disciplina de reduzir um produto ao escopo que um time pequeno consegue de fato finalizar e publicar, e uma percepção muito mais aguçada do abismo entre uma boa ideia no papel e algo que as pessoas vão instalar no lugar do app que já usam. Essas lições rodam silenciosamente por trás de tudo que construí desde então, e acho que isso vale mais do que os números do lançamento.

tech stack

SwiftUI
framework de UI nativo
Keychain
armazenamento seguro de segredos
iCloud
sincronização de metadados
CryptoKit
TOTP em conformidade com RFC 6238

code snippets

O contador é derivado do tempo Unix e passa por HMAC com o segredo do usuário. É então truncado em um código numérico conforme a especificação. As entradas são limitadas para evitar que problemas no tempo do sistema travem o app.

static func generateCode(
    secret: Data,
    algorithm: TOTPAlgorithm,
    digits: Int,
    period: Int,
    date: Date = .now
) -> String {
    let safePeriod = max(1, period)
    let safeDigits = max(1, min(9, digits))
    let timestamp = max(0, date.timeIntervalSince1970)
    let counter = UInt64(timestamp) / UInt64(safePeriod)
    var bigEndianCounter = counter.bigEndian
    let counterData = withUnsafeBytes(of: &bigEndianCounter) { Data($0) }
    let key = SymmetricKey(data: secret)

    let hmacBytes: [UInt8]
    switch algorithm {
    case .sha1:
        hmacBytes = Array(HMAC<Insecure.SHA1>.authenticationCode(for: counterData, using: key))
    case .sha256:
        hmacBytes = Array(HMAC<SHA256>.authenticationCode(for: counterData, using: key))
    case .sha512:
        hmacBytes = Array(HMAC<SHA512>.authenticationCode(for: counterData, using: key))
    }

    guard hmacBytes.count >= 4, let last = hmacBytes.last else {
        return String(repeating: "0", count: safeDigits)
    }

    let offset = Int(last & 0x0F)
    guard offset + 3 < hmacBytes.count else {
        return String(repeating: "0", count: safeDigits)
    }

    let truncated: UInt32 =
        (UInt32(hmacBytes[offset] & 0x7F) << 24)
        | (UInt32(hmacBytes[offset + 1]) << 16)
        | (UInt32(hmacBytes[offset + 2]) << 8)
        | UInt32(hmacBytes[offset + 3])

    var modulo: UInt32 = 1
    for _ in 0..<safeDigits {
        modulo *= 10
    }

    let code = truncated % modulo
    return String(format: "%0\(safeDigits)d", code)
}

design choices

palette

preto do sistema #000000
azul do sistema #0A84FF
branco do sistema #FFFFFF

typography

SF Pro / interface
Privado, seguro e simples.
SF Mono / códigos TOTP
482 913

some fonts used in this project are proprietary and may not display correctly if they are not installed on your system.

rationale

O design do Lockat segue à risca as Human Interface Guidelines da Apple. Foi uma decisão de produto deliberada, não um atalho. Boa parte de quem busca um app de 2FA de terceiros nem sabe que o iOS já traz um autenticador embutido, então eu queria que o Lockat parecesse nativo. Trocar da solução da própria Apple ou conviver com ela não deveria exigir esforço cognitivo. Padrões de navegação do sistema, materiais nativos, SF Pro e um azul de destaque do sistema sobre fundos totalmente nativos, tanto no modo claro quanto no escuro, fazem com que ele pareça um app de primeira-parte já na primeira abertura. A aparência acompanha o sistema perfeitamente, evitando aquela sensação de "tema pela metade" comum em outros apps.

Dentro dessa casca nativa, o design se justifica oferecendo o que falta nos concorrentes. Cada entrada pode carregar uma nota livre, para que um código de recuperação, um e-mail de backup ou um lembrete sobre qual número está vinculado à conta fique ao lado do próprio TOTP. Os códigos podem ser agrupados em pastas para quem precisa cuidar de dezenas de contas, e a cor de destaque da interface é configurável pelo usuário, o que ajuda o app a parecer pessoal em vez de ser apenas mais um utilitário cinza. O resultado é uma interface que se dissolve no iOS até você precisar dela, e que, calada, faz mais do que os apps ao redor.

credits

people

design · development
pedro wiezelluiz rosa