#lang scheme
(require (planet soegaard/digest:1:2/digest))
(provide scramble-411
make-retro-password-bytes)
(define (scramble-411 password-bytes seed-bytes)
(let* ((stage1 (bytes-digest password-bytes 'sha1))
(stage2 (bytes-digest stage1 'sha1))
(raw (bytes-digest (bytes-append seed-bytes stage2) 'sha1)))
(list->bytes (map bitwise-xor (bytes->list raw) (bytes->list stage1)))))
(define (make-retro-password-bytes buf salt)
(define ring-size (expt 2 64))
(define (mod+ x y) (modulo (+ x y) ring-size))
(define (mod* x y) (modulo (* x y) ring-size))
(define (mod-shift x y) (modulo (arithmetic-shift x y) ring-size))
(define (hash buf)
(let ((len (bytes-length buf)))
(let loop ((n1 1345345333) (n2 305419889) (add 7) (i 0))
(if (= i len)
(values (bitwise-and #x7fffffff n1) (bitwise-and #x7fffffff n2))
(let ((c (bytes-ref buf i)))
(if (or (= c 32) (= c 9))
(loop n1 n2 add (+ i 1))
(let* ((nr-shift (mod-shift n1 8))
(nr-mask (bitwise-and 63 n1))
(nr (mod+ nr-shift (mod* c (mod+ add nr-mask))))
(nr2-shift (mod-shift n2 8))
(new-n1 (bitwise-xor nr n1)))
(loop new-n1 (mod+ n2 (bitwise-xor nr2-shift new-n1)) (mod+ add c) (+ i 1)))))))))
(define (rnd val offset)
(let ((d (/ val (- (expt 2 30) 1))))
(bitwise-and #xff (inexact->exact (floor (+ (* d 31) offset))))))
(let ((len (bytes-length salt)))
(if (zero? (bytes-length buf))
buf
(let-values (((pw1 pw2) (hash salt))
((msg1 msg2) (hash buf))
((new-buf) (make-bytes (+ len 1) 0))
((m) (- (expt 2 30) 1)))
(let loop ((seed1 (remainder (bitwise-xor pw1 msg1) m)) (seed2 (remainder (bitwise-xor pw2 msg2) m)) (i 0))
(if (= i len)
(let* ((seed1 (remainder (mod+ seed2 (mod* seed1 3)) m))
(seed2 (remainder (mod+ seed1 (mod+ seed2 33)) m))
(b (rnd seed1 0)))
(let loop2 ((j 0))
(if (= j len)
new-buf
(begin (bytes-set! new-buf j (bitwise-xor (bytes-ref new-buf j) b))
(loop2 (+ j 1))))))
(let* ((seed1 (remainder (mod+ seed2 (mod* seed1 3)) m))
(seed2 (remainder (mod+ seed1 (mod+ seed2 33)) m))
(b (rnd seed1 64)))
(bytes-set! new-buf i b)
(loop seed1 seed2 (+ i 1)))))))))