sexta-feira, 24 de abril de 2009

Criptografia simples (ingênua)

A seguir está um esquema simples de criptografia para autenticação em páginas web. Não é um esquema seguro e não envolve chaves públicas (criptografia de chaves assimétricas).

O esquema consiste em apresentar para o usuário uma matriz de números aleatórios (puzzle) para que ele possa dali extrair o texto a ser enviado para ser validado. A cada acesso à pagina uma matriz aleatória nova é exibida. Somente o usuário e o software para valição de senha sabem o segredo (chave) para determinar se a senha está ou não correta.

Na implementação mostrada a seguir (em Chicken Scheme), o código para valição de senha verifica se:

  • a senha possui quatro caracteres

  • o primeiro caractere da senha é igual ao caractere do canto superior esquerdo da matriz de números

  • o segundo caractere da senha é igual ao caractere do canto superior direito da matriz de números

  • o terceiro caractere da senha é igual ao caractere do canto inferior esquerdo da matriz de números

  • o quarto caractere da senha é igual ao caractere do canto inferior direito da matriz de números





Ou seja, o validador verifica se a senha corresponde aos números dos quatro cantos da matriz números concatenados no sentido horário, começando pelo canto superior esquerdo.

Obviamente o validador de senha é dos mais simples, mas poderia usar técnicas mais elaboradas como, por exemplo, o código de Beale. Neste caso, o validador teria um texto padrão, o qual seria de conhecimento do usuário, e os números da matriz indicariam a posição das letras no texto. Assim, o usuário digitaria as letras correspondentes às posições do texto indicadas em lugares pré-determinados da matriz (o uso da matriz é uma otimização sobre o código de Beale -- originalmente seriam apresentados apenas os números indicando a posição das letras no texto).

O código de servidor web (extensão spiffy de Chicken) está abaixo (web-server.scm):

#!/usr/bin/csi -script

(use spiffy spiffy-utils web-scheme web-scheme-handler (srfi 1 13))

(spiffy-file-ext-handlers `(("ws" . ,web-scheme-handler)))
(spiffy-tcp-port 8080)
(spiffy-root-path "./")

(start-server)


A implementação do esquema de autenticação está a seguir (index.ws):

(define (make-puzzle)
;; Retorna uma lista de listas de numeros aleatorios entre 0 e 9
;; (inclusive 0 e 9).
(let* ((line-length 40)
(num-columns 10)
(random-line
(lambda ()
(map (lambda (_) (random 10))
(iota line-length)))))
(map (lambda (_)
(random-line))
(iota num-columns))))

(define (valid-passwd? passwd puzzle)
;; Chave (ingenua): a senha corresponde aos numeros dos cantos da
;; tabela de numeros concatenados no sentido horario, comecando pelo
;; canto superior esquerdo.

(define ($ pos)
;; Retorna o caractere da posicao POS em PASSWD, ou #f se POS nao
;; existir em PASSWD.
(handle-exceptions exn #f (->string (string-ref passwd pos))))

(define (check pw-pos key-pos)
(equal? ($ pw-pos) (number->string key-pos)))

(and passwd
(= (string-length passwd) 4)
(check 0 (caar puzzle))
(check 1 (last (car puzzle)))
(check 2 (car (last puzzle)))
(check 3 (last (last puzzle)))))

(define (auth-page #!optional preamble)
;; Pagina de autenticacao.
(ws:page
(let ((puzzle (make-puzzle)))
(center
(if preamble (p preamble) "")
(ws:make-table puzzle)
(form 'method "post"
(input 'type "hidden" 'name "puzzle"
'value (with-output-to-string (cut pp puzzle)))
(input 'type "password" 'name "passwd")
(input 'type "submit"))))))

(let ((passwd (post-var "passwd"))
(puzzle (post-var "puzzle")))
(if (and puzzle passwd)
(if (valid-passwd? passwd (with-input-from-string puzzle read))
(ws:page "Senha correta")
(auth-page "Senha errada!"))
(auth-page)))

Nenhum comentário: