crypto.ss
#lang scheme/base

;; crypto file...
;; we want to pass in an encryption scheme... this does not control the path that is being
;; encrypted.
;; (encrypt-file path) => ;; write over the file?
;; (save-encrypted-file path data) => write the data into the path as encrypted file...
;;
;;
(require (planet bzlib/base) 
         (planet vyzo/crypto) 
         (planet vyzo/crypto/util)
         "filter.ss"
         "port.ss"
         file/gzip
         file/gunzip
         scheme/port
         )

(define (make-input-encrypted-pipe cipher key iv)
  (lambda (port)
    (decrypt cipher key iv)))

(define (make-output-encrypted-pipe cipher key iv)
  (lambda (port)
    (encrypt cipher key iv)))

;; crypto already provided its own pipe mechanism, which would make it hard to combine them together...
;; hmm...
;; how would this work?
;; what I want to do is to be able to supply my own version of the make-pipe function...
(define (open-input-encrypted-port in cipher key iv)
  (make-input-filter-port in #f (make-input-encrypted-pipe cipher key iv)))

(define call-with-input-encrypted-port
  (make-call-with-input-port open-input-encrypted-port in cipher key iv))

(define (open-input-encrypted-file path cipher key iv)
  (open-input-encrypted-port (open-input-file path) cipher key iv))

(define call-with-input-encrypted-file
  (make-call-with-input-port open-input-encrypted-file path cipher key iv))

(define (open-output-encrypted-port out cipher key iv)
  (make-output-filter-port out #f (make-output-encrypted-pipe cipher key iv)))

(define call-with-output-encrypted-port
  (make-call-with-output-port open-output-encrypted-port out cipher key iv))

(define (open-output-encrypted-file path cipher key iv #:exists (exists 'replace))
  (open-output-encrypted-port (open-output-file path #:exists exists) cipher key iv))

(define call-with-output-encrypted-file
  (make-call-with-output-port open-output-encrypted-file path cipher key iv #:exists (exists 'replace)))


(provide/contract 
 (make-input-encrypted-pipe (-> cipher? bytes? bytes? make-pipe/c))
 (make-output-encrypted-pipe (-> cipher? bytes? bytes? make-pipe/c))
 (open-input-encrypted-port (-> input-port? cipher? bytes? bytes? input-port?))
 (call-with-input-encrypted-port (-> input-port? cipher? bytes? bytes? (-> input-port? any) any))
 (open-input-encrypted-file (-> path-string? cipher? bytes? bytes? input-port?))
 (call-with-input-encrypted-file (-> path-string? cipher? bytes? bytes? (-> input-port? any) any))
 (open-output-encrypted-port (-> output-port? cipher? bytes? bytes? output-port?))
 (call-with-output-encrypted-port (-> output-port? cipher? bytes? bytes? (-> output-port? any) any))
 (open-output-encrypted-file (->* (path-string? cipher? bytes? bytes?)
                                  (#:exists (or/c 'replace 'error))
                                  output-port?))
 (call-with-output-encrypted-file (->* (path-string? cipher? bytes? bytes? (-> output-port? any))
                                       (#:exists (or/c 'replace 'error))
                                       any))
 )

;; maybe? (provide (all-from-out (planet vyzo/crypto) (planet vyzo/crypto/util)))

;;
#|
(require "gzip.ss" "base64.ss" net/base64 file/gzip file/gunzip)
(define cipher cipher:aes-128)
(define-values (key iv) (generate-key cipher))

(call-with-output-port 
 (make-output-filter-port (open-output-file "crypto.ss.gz.aes.b64" #:exists 'replace) 
                          output-gzip-filter ;; gzip 
                          #f
                          #f ;; encrypted 
                          (make-output-encrypted-pipe cipher key iv)
                          output-base64-filter ;; base64 
                          #f)
 (lambda (out)
   (call-with-input-file "crypto.ss"
     (lambda (in)
       (copy-port in out)))))

(call-with-input-port 
 (make-input-filter-port (open-input-file "crypto.ss.gz.aes.b64")
                         input-gzip-filter ;; gzip 
                         #f
                         #f ;; aes
                         (make-input-encrypted-pipe cipher key iv)
                         input-base64-filter ;; base64 
                         #f )
 (lambda (in)
   (read-bytes 20000 in)))

;;|#
#|(call-with-input-file "port.ss"
  (lambda (in)
    (call-with-output-file "port.ss.gz.enc.base64"
      (lambda (out)
        (call-with-output-base64-port
         out
         (lambda (out)
           (call-with-output-encrypted-port
            out
            cipher key iv 
            (lambda (out)
              (call-with-output-gzip-port
               out
               (lambda (out)
                 (copy-port in out))))))))
      #:exists 'replace)))

(call-with-input-file "port.ss.gz.enc.base64"
  (lambda (in)
    (call-with-input-base64-port
     in
     (lambda (in)
       (call-with-input-encrypted-port
        in cipher key iv
        (lambda (in) 
          (call-with-input-gzip-port
           in
           (lambda (in)
             (read-bytes 20000 in)))))))))
;;|#