forked from syndicate-lang/marketplace-ssh-2014
First steps toward modernization and port to syndicate-rkt.
Switch from (planet vyzo/crypto) to crypto. Comment out most of the upper layers of the protocol. Switch to new syndicate/rkt. Unfortunately since I last ran this, the set of MUST-implement kex methods has changed and there's no overlap with my default SSH client :-)
This commit is contained in:
parent
5381a0b8d3
commit
3c07c96307
|
@ -1,66 +0,0 @@
|
|||
#lang racket/base
|
||||
;;; SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
;;; SPDX-FileCopyrightText: Copyright © 2011-2021 Tony Garnock-Jones <tonyg@leastfixedpoint.com>
|
||||
|
||||
;;; Provide AES CTR mode, since OpenSSL's EVP support for AES CTR mode
|
||||
;;; is still ifdef'd out.
|
||||
|
||||
(provide start-aes-ctr
|
||||
aes-ctr-process!)
|
||||
|
||||
(require ffi/unsafe)
|
||||
(require ffi/unsafe/define)
|
||||
(require openssl/libcrypto)
|
||||
|
||||
(define _AES_KEY-pointer _pointer)
|
||||
|
||||
(define AES_BLOCK_SIZE 16)
|
||||
(define sizeof-AES_KEY 244) ;; TODO: figure out a good way to get this
|
||||
;; from the header file or the library
|
||||
;; itself
|
||||
|
||||
(define-ffi-definer define-crypto libcrypto
|
||||
#:default-make-fail make-not-available)
|
||||
|
||||
(define-crypto AES_set_encrypt_key (_fun _pointer _int _AES_KEY-pointer -> _int))
|
||||
;;(define-crypto AES_set_decrypt_key (_fun _pointer _int _AES_KEY-pointer -> _int))
|
||||
|
||||
(define-crypto AES_ctr128_encrypt
|
||||
(_fun _pointer ;; in
|
||||
_pointer ;; out
|
||||
_long ;; length
|
||||
_AES_KEY-pointer ;; key
|
||||
_pointer ;; ivec, AES_BLOCK_SIZE bytes
|
||||
_pointer ;; ecount_buf, AES_BLOCK_SIZE bytes
|
||||
_pointer ;; int pointer, the "num" field of the ongoing state (??)
|
||||
-> _void))
|
||||
|
||||
(struct aes-ctr-state (key ivec ecount num) #:transparent)
|
||||
|
||||
(define (start-aes-ctr key initialization-vector)
|
||||
(let ((key-buffer (malloc sizeof-AES_KEY))
|
||||
(ivec (make-bytes AES_BLOCK_SIZE))
|
||||
(ecount (make-bytes AES_BLOCK_SIZE))
|
||||
(num (make-bytes (ctype-sizeof _int))))
|
||||
(AES_set_encrypt_key key
|
||||
(* 8 (bytes-length key)) ;; measured in bits
|
||||
key-buffer)
|
||||
(bytes-copy! ivec 0 initialization-vector 0 AES_BLOCK_SIZE)
|
||||
(bytes-fill! ecount 0)
|
||||
(bytes-fill! num 0)
|
||||
(aes-ctr-state key-buffer
|
||||
ivec
|
||||
ecount
|
||||
num)))
|
||||
|
||||
(define (aes-ctr-process! state input-block)
|
||||
(define block-length (bytes-length input-block))
|
||||
(define output-block (make-bytes block-length))
|
||||
(AES_ctr128_encrypt input-block
|
||||
output-block
|
||||
block-length
|
||||
(aes-ctr-state-key state)
|
||||
(aes-ctr-state-ivec state)
|
||||
(aes-ctr-state-ecount state)
|
||||
(aes-ctr-state-num state))
|
||||
output-block)
|
|
@ -0,0 +1,9 @@
|
|||
#lang racket/base
|
||||
;;; SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
;;; SPDX-FileCopyrightText: Copyright © 2011-2021 Tony Garnock-Jones <tonyg@leastfixedpoint.com>
|
||||
|
||||
(provide (all-from-out crypto))
|
||||
|
||||
(require crypto)
|
||||
(require crypto/all)
|
||||
(use-all-factories!)
|
|
@ -1,77 +0,0 @@
|
|||
#lang racket/base
|
||||
;;; SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
;;; SPDX-FileCopyrightText: Copyright © 2011-2021 Tony Garnock-Jones <tonyg@leastfixedpoint.com>
|
||||
|
||||
(provide make-queue
|
||||
queue?
|
||||
enqueue
|
||||
enqueue-all
|
||||
dequeue
|
||||
list->queue
|
||||
queue->list
|
||||
queue-length
|
||||
queue-empty?
|
||||
queue-append
|
||||
queue-extract)
|
||||
|
||||
(struct queue (head tail) #:transparent)
|
||||
|
||||
(define (make-queue)
|
||||
(queue '() '()))
|
||||
|
||||
(define (enqueue q v)
|
||||
(queue (queue-head q)
|
||||
(cons v (queue-tail q))))
|
||||
|
||||
(define (enqueue-all q v)
|
||||
(queue (queue-head q)
|
||||
(append (reverse v) (queue-tail q))))
|
||||
|
||||
(define (shuffle q)
|
||||
(if (null? (queue-head q))
|
||||
(queue (reverse (queue-tail q)) '())
|
||||
q))
|
||||
|
||||
(define (dequeue q)
|
||||
(let ((q1 (shuffle q)))
|
||||
(values (car (queue-head q1))
|
||||
(queue (cdr (queue-head q1)) (queue-tail q1)))))
|
||||
|
||||
(define (list->queue xs)
|
||||
(queue xs '()))
|
||||
|
||||
(define (queue->list q)
|
||||
(append (queue-head q) (reverse (queue-tail q))))
|
||||
|
||||
(define (queue-length q)
|
||||
(+ (length (queue-head q))
|
||||
(length (queue-tail q))))
|
||||
|
||||
(define (queue-empty? q)
|
||||
(and (null? (queue-head q))
|
||||
(null? (queue-tail q))))
|
||||
|
||||
(define (queue-append q1 q2)
|
||||
(queue (append (queue-head q1)
|
||||
(reverse (queue-tail q1))
|
||||
(queue-head q2))
|
||||
(queue-tail q2)))
|
||||
|
||||
(define (queue-extract q predicate [default-value #f])
|
||||
(let search-head ((head (queue-head q))
|
||||
(rejected-head-rev '()))
|
||||
(cond
|
||||
((null? head) (let search-tail ((tail (reverse (queue-tail q)))
|
||||
(rejected-tail-rev '()))
|
||||
(cond
|
||||
((null? tail) (values default-value q))
|
||||
((predicate (car tail)) (values (car tail)
|
||||
(queue (queue-head q)
|
||||
(append (reverse (cdr tail))
|
||||
rejected-tail-rev))))
|
||||
(else (search-tail (cdr tail) (cons (car tail) rejected-tail-rev))))))
|
||||
((predicate (car head)) (values (car head)
|
||||
(queue (append (reverse rejected-head-rev)
|
||||
(cdr head))
|
||||
(queue-tail q))))
|
||||
(else (search-head (cdr head) (cons (car head) rejected-head-rev))))))
|
|
@ -9,11 +9,12 @@
|
|||
"base"
|
||||
|
||||
"bitsyntax"
|
||||
"syndicate"
|
||||
"crypto"
|
||||
"preserves"
|
||||
"syndicate"
|
||||
|
||||
))
|
||||
|
||||
;; (define build-deps '("rackunit-lib"))
|
||||
(define build-deps '("rackunit-lib"))
|
||||
|
||||
(define pre-install-collection "private/install.rkt")
|
||||
|
|
|
@ -1,15 +0,0 @@
|
|||
#lang racket/base
|
||||
;;; SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
;;; SPDX-FileCopyrightText: Copyright © 2013-2021 Tony Garnock-Jones <tonyg@leastfixedpoint.com>
|
||||
|
||||
;;; Reexport racket-matrix module contents.
|
||||
|
||||
(require marketplace/sugar)
|
||||
(require marketplace/drivers/tcp)
|
||||
(require marketplace/drivers/timer)
|
||||
(require marketplace/drivers/event-relay)
|
||||
|
||||
(provide (all-from-out marketplace/sugar))
|
||||
(provide (all-from-out marketplace/drivers/tcp))
|
||||
(provide (all-from-out marketplace/drivers/timer))
|
||||
(provide (all-from-out marketplace/drivers/event-relay))
|
|
@ -1,12 +1,13 @@
|
|||
#lang racket/base
|
||||
#lang syndicate
|
||||
;;; SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
;;; SPDX-FileCopyrightText: Copyright © 2012-2021 Tony Garnock-Jones <tonyg@leastfixedpoint.com>
|
||||
|
||||
;;; (Temporary) example client and server
|
||||
|
||||
(require racket/set)
|
||||
(require racket/match)
|
||||
(require racket/contract)
|
||||
(require syndicate/drivers/timer)
|
||||
(require syndicate/drivers/tcp)
|
||||
(require syndicate/dataspace)
|
||||
|
||||
(require (only-in racket/port peek-bytes-avail!-evt))
|
||||
(require "cook-port.rkt")
|
||||
(require "sandboxes.rkt")
|
||||
|
@ -17,19 +18,16 @@
|
|||
(require "ssh-channel.rkt")
|
||||
(require "ssh-message-types.rkt")
|
||||
(require "ssh-exceptions.rkt")
|
||||
(require "marketplace-support.rkt")
|
||||
|
||||
(define (main)
|
||||
(ground-vm (timer-driver)
|
||||
(tcp-driver)
|
||||
(tcp-spy)
|
||||
(name-process 'ssh-tcp-listener (spawn listener))))
|
||||
|
||||
(define listener
|
||||
(transition/no-state
|
||||
(observe-publishers (tcp-channel ? (tcp-listener 2322) ?)
|
||||
(match-conversation r
|
||||
(on-presence (session-vm r))))))
|
||||
(module+ main
|
||||
(actor-system/dataspace (ds)
|
||||
(spawn-timer-driver ds)
|
||||
(spawn-tcp-driver ds)
|
||||
(spawn #:name 'ssh-tcp-listener
|
||||
(at ds
|
||||
(during/spawn (Connection $conn (TcpInbound "0.0.0.0" 2322))
|
||||
#:name (list 'ssh conn)
|
||||
(session ds conn))))))
|
||||
|
||||
;;---------------------------------------------------------------------------
|
||||
|
||||
|
@ -44,242 +42,164 @@
|
|||
"Invalid peer identification string ~v"
|
||||
peer-identification-string)))
|
||||
|
||||
(define (spy marker)
|
||||
(define (dump what message)
|
||||
(write `(,marker ,what ,message))
|
||||
(newline)
|
||||
(flush-output)
|
||||
(void))
|
||||
(list
|
||||
(observe-publishers/everything (wild)
|
||||
(match-interest-type i
|
||||
(match-conversation c
|
||||
(on-presence (dump 'arrived (role 'publisher c i)))
|
||||
(on-absence (dump 'departed (role 'publisher c i)))
|
||||
(on-message [message (dump 'message message)]))))
|
||||
(observe-subscribers/everything (wild)
|
||||
(match-interest-type i
|
||||
(match-conversation c
|
||||
(on-presence (dump 'arrived (role 'subscriber c i)))
|
||||
(on-absence (dump 'departed (role 'subscriber c i)))
|
||||
(on-message [message (dump 'feedback message)]))))))
|
||||
(define (session ground-ds conn)
|
||||
(define root-facet this-facet)
|
||||
|
||||
(define-syntax-rule (wait-as my-orientation topic action ...)
|
||||
(let-fresh (endpoint-name)
|
||||
(build-endpoint endpoint-name
|
||||
(role my-orientation topic 'observer)
|
||||
(match-state state
|
||||
(on-presence (sequence-actions (transition state
|
||||
(delete-endpoint endpoint-name)
|
||||
action ...)))))))
|
||||
(define update-input-handler
|
||||
(accept-connection conn
|
||||
#:initial-credit #f
|
||||
#:on-data (lambda (input mode) (error 'session "Unexpected input"))))
|
||||
|
||||
(define (session-vm new-conversation)
|
||||
(match-define (tcp-channel remote-addr local-addr _) new-conversation)
|
||||
(define local-identification #"SSH-2.0-RacketSSH_0.0")
|
||||
(define local-identification "SSH-2.0-RacketSSH_0.0")
|
||||
(send-line conn local-identification)
|
||||
|
||||
(define (issue-identification-string)
|
||||
(at-meta-level
|
||||
(send-message (tcp-channel local-addr remote-addr
|
||||
(bytes-append local-identification #"\r\n")))))
|
||||
(send-lines-credit conn 1 (LineMode-crlf))
|
||||
(update-input-handler
|
||||
#:on-data (lambda (remote-identification _mode)
|
||||
(check-remote-identification! remote-identification)
|
||||
|
||||
(define (read-handshake-and-become-reader)
|
||||
(transition 'handshake-is-stateless ;; but, crucially, the ssh-reader proper isn't!
|
||||
(at-meta-level
|
||||
(name-endpoint 'socket-reader
|
||||
(subscriber (tcp-channel remote-addr local-addr ?)
|
||||
(match-state state
|
||||
(on-message
|
||||
[(tcp-channel _ _ (? eof-object?))
|
||||
(transition state (quit))]
|
||||
[(tcp-channel _ _ (? bytes? remote-identification))
|
||||
(begin
|
||||
(check-remote-identification! remote-identification)
|
||||
(sequence-actions (transition state)
|
||||
;; First, set the incoming mode to bytes.
|
||||
(at-meta-level
|
||||
(send-feedback (tcp-channel remote-addr local-addr (tcp-mode 'bytes))))
|
||||
;; Then initialise the reader, switching to packet-reading mode.
|
||||
(lambda (ignored-state) (ssh-reader new-conversation))
|
||||
;; Finally, spawn the remaining processes and issue
|
||||
;; the initial credit to the reader.
|
||||
(name-process 'ssh-writer
|
||||
;; TODO: canary: #:exit-signal? #t
|
||||
(spawn (ssh-writer new-conversation)))
|
||||
;; Wait for the reader and writer get started, then tell
|
||||
;; the reader we are ready for a single packet and spawn
|
||||
;; the session manager.
|
||||
(wait-as 'subscriber (inbound-packet (wild) (wild) (wild) (wild))
|
||||
(wait-as 'publisher (outbound-packet (wild))
|
||||
(send-message (inbound-credit 1))
|
||||
(name-process 'ssh-session
|
||||
(spawn #:pid session-pid
|
||||
;; TODO: canary: #:exit-signal? #t
|
||||
(ssh-session session-pid
|
||||
local-identification
|
||||
remote-identification
|
||||
repl-boot
|
||||
'server)))))))])))))))
|
||||
(define session-vm
|
||||
(actor-group [(on-stop
|
||||
(stop-facet root-facet)
|
||||
(log-info "Session VM for ~a closed" conn))]
|
||||
(define conn-ds (dataspace #:name (gensym 'conn-ds)))
|
||||
|
||||
(define (exn->outbound-packet reason)
|
||||
(outbound-packet (ssh-msg-disconnect (exn:fail:contract:protocol-reason-code reason)
|
||||
(string->bytes/utf-8 (exn-message reason))
|
||||
#"")))
|
||||
(spawn/link #:name 'reader
|
||||
(ssh-reader conn-ds conn update-input-handler))
|
||||
(spawn/link #:name 'writer
|
||||
(ssh-writer conn-ds conn))
|
||||
|
||||
(define (disconnect-message-required? reason)
|
||||
(and (exn:fail:contract:protocol? reason)
|
||||
(not (exn:fail:contract:protocol-originated-at-peer? reason))))
|
||||
;; Wait for the reader and writer get started, then tell the reader
|
||||
;; we are ready for a single packet and spawn the session manager.
|
||||
(react
|
||||
(at conn-ds
|
||||
(stop-when (asserted (Observe (:pattern (inbound-credit ,_)) _))
|
||||
(send! conn-ds (inbound-credit 1))
|
||||
|
||||
(define (active-exception-handler reason)
|
||||
;; This is kind of gross: because the absence handler gets invoked
|
||||
;; several times in a row because of multiple flows intersecting
|
||||
;; this role, we have to be careful to make the transmission of
|
||||
;; the disconnection packet idempotent.
|
||||
;; TODO: this is likely no longer true now we're using exit-signals %%%
|
||||
(define interesting? (disconnect-message-required? reason))
|
||||
(transition inert-exception-handler
|
||||
(when interesting? (send-message (exn->outbound-packet reason)))
|
||||
(yield state ;; gross
|
||||
(transition state (at-meta-level (quit #f (and interesting? reason)))))))
|
||||
(spawn/link
|
||||
#:name 'session
|
||||
(ssh-session conn-ds
|
||||
ground-ds
|
||||
local-identification
|
||||
remote-identification
|
||||
(lambda (user-name)
|
||||
(error 'repl-boot "Would start session with ~a" user-name))
|
||||
'server)))))
|
||||
|
||||
(define (inert-exception-handler reason)
|
||||
inert-exception-handler)
|
||||
(at conn-ds
|
||||
(during $m
|
||||
(on-start (log-info "++ ~v" m))
|
||||
(on-stop (log-info "-- ~v" m)))
|
||||
(when (message $m)
|
||||
(log-info ">> ~v" m)))
|
||||
|
||||
(spawn-vm #:debug-name (list 'ssh-session-vm new-conversation)
|
||||
(event-relay 'ssh-event-relay)
|
||||
(timer-relay 'ssh-timer-relay)
|
||||
(spy 'SSH)
|
||||
(at conn-ds
|
||||
(when (asserted (protocol-error $reason-code $message _ $originated-at-peer?))
|
||||
(when (not originated-at-peer?)
|
||||
(send! conn-ds
|
||||
(outbound-packet (ssh-msg-disconnect reason-code
|
||||
(string->bytes/utf-8 message)
|
||||
#""))))
|
||||
(actor-system-shutdown! session-vm)))))
|
||||
|
||||
(issue-identification-string)
|
||||
|
||||
;; Expect identification string, then update (!) our inbound
|
||||
;; subscription handler to switch to packet mode.
|
||||
(at-meta-level
|
||||
(send-feedback (tcp-channel remote-addr local-addr (tcp-mode 'lines)))
|
||||
(send-feedback (tcp-channel remote-addr local-addr (tcp-credit 1))))
|
||||
|
||||
(name-process 'ssh-reader
|
||||
;; TODO: canary: #:exit-signal? #t
|
||||
(spawn (read-handshake-and-become-reader)))
|
||||
|
||||
;; TODO: canary:
|
||||
;; (spawn #:child
|
||||
;; (transition active-exception-handler
|
||||
;; (role (topic-subscriber (exit-signal (wild) (wild)))
|
||||
;; #:state current-handler
|
||||
;; #:reason reason
|
||||
;; #:on-absence (current-handler reason))))
|
||||
))
|
||||
(void))))
|
||||
|
||||
;;---------------------------------------------------------------------------
|
||||
|
||||
(define (repl-boot user-name)
|
||||
(list
|
||||
(event-relay 'app-event-relay)
|
||||
(spy 'APP)
|
||||
(at-meta-level
|
||||
(subscriber (channel-message (channel-stream-name #t (wild)) (wild))
|
||||
(match-conversation (channel-message (channel-stream-name _ cname) _)
|
||||
(on-presence (name-process cname (spawn (repl-instance user-name cname)))))))))
|
||||
;; ;; (repl-instance InputPort OutputPort InputPort OutputPort)
|
||||
;; (struct repl-instance-state (c2s-in ;; used by thread to read input from relay
|
||||
;; c2s-out ;; used by relay to feed input from remote to the thread
|
||||
;; s2c-in ;; used by relay to feed output from thread to remote
|
||||
;; s2c-out ;; used by thread to write output to relay
|
||||
;; ) #:prefab)
|
||||
|
||||
;; (repl-instance InputPort OutputPort InputPort OutputPort)
|
||||
(struct repl-instance-state (c2s-in ;; used by thread to read input from relay
|
||||
c2s-out ;; used by relay to feed input from remote to the thread
|
||||
s2c-in ;; used by relay to feed output from thread to remote
|
||||
s2c-out ;; used by thread to write output to relay
|
||||
) #:prefab)
|
||||
|
||||
(define (repl-instance user-name cname)
|
||||
(define inbound-stream (channel-stream-name #t cname))
|
||||
(define outbound-stream (channel-stream-name #f cname))
|
||||
(define (ch-do action-ctor stream body)
|
||||
(at-meta-level (action-ctor (channel-message stream body))))
|
||||
(define (handle-channel-message state body)
|
||||
(match body
|
||||
[(channel-stream-request #"pty-req" _)
|
||||
(match-define (repl-instance-state old-in _ _ old-out) state)
|
||||
(define-values (cooked-in cooked-out) (cook-io old-in old-out "> "))
|
||||
(transition (struct-copy repl-instance-state state
|
||||
[c2s-in cooked-in]
|
||||
[s2c-out cooked-out])
|
||||
(ch-do send-feedback inbound-stream (channel-stream-ok)))]
|
||||
[(channel-stream-notify #"env" _)
|
||||
;; Don't care
|
||||
(transition state)]
|
||||
[(channel-stream-request #"shell" _)
|
||||
(match-define (repl-instance-state c2s-in _ s2c-in s2c-out) state)
|
||||
(define buffer-size 1024)
|
||||
(define dummy-buffer (make-bytes buffer-size))
|
||||
(define repl-thread (thread (lambda () (repl-shell user-name c2s-in s2c-out))))
|
||||
(transition state
|
||||
(ch-do send-feedback inbound-stream (channel-stream-ok))
|
||||
(subscriber (cons (thread-dead-evt repl-thread) (wild))
|
||||
(on-message [_ (quit #f "REPL thread exited")]))
|
||||
(subscriber (cons (peek-bytes-avail!-evt dummy-buffer 0 #f s2c-in) (wild))
|
||||
;; We're using peek-bytes-avail!-evt rather than
|
||||
;; read-bytes-avail!-evt because of potential overwriting
|
||||
;; of the buffer. The overwriting can happen when there's
|
||||
;; any latency between handling the event and the next
|
||||
;; firing of the event, since the peek-bytes-avail!-evt
|
||||
;; will overwrite its buffer next time it's synced on.
|
||||
(match-state state
|
||||
(on-message
|
||||
[(cons _ (? eof-object?))
|
||||
(let ()
|
||||
(match-define (repl-instance-state c2s-in c2s-out s2c-in s2c-out) state)
|
||||
(close-input-port c2s-in)
|
||||
(close-output-port c2s-out)
|
||||
(close-input-port s2c-in)
|
||||
(close-output-port s2c-out)
|
||||
(transition state (quit)))]
|
||||
[(cons _ (? number? count))
|
||||
(transition state
|
||||
(ch-do send-message outbound-stream (channel-stream-data
|
||||
(read-bytes count s2c-in))))]))))]
|
||||
[(or (channel-stream-data #"\4") ;; C-d a.k.a EOT
|
||||
(channel-stream-eof))
|
||||
(let ()
|
||||
(close-output-port (repl-instance-state-c2s-out state))
|
||||
;; ^ this signals the repl thread to exit.
|
||||
;; Now, wait for it to do so.
|
||||
(transition state))]
|
||||
[(channel-stream-data bs)
|
||||
(write-bytes bs (repl-instance-state-c2s-out state))
|
||||
(flush-output (repl-instance-state-c2s-out state))
|
||||
(transition state
|
||||
(ch-do send-feedback inbound-stream (channel-stream-credit (bytes-length bs))))]
|
||||
[m
|
||||
(write `(channel inbound ,m)) (newline)
|
||||
(transition state)]))
|
||||
(match (channel-name-type cname)
|
||||
[#"session"
|
||||
(define-values (c2s-in c2s-out) (make-pipe))
|
||||
(define-values (s2c-in s2c-out) (make-pipe))
|
||||
(transition (repl-instance-state c2s-in c2s-out s2c-in s2c-out)
|
||||
(at-meta-level
|
||||
(subscriber (channel-message inbound-stream (wild))
|
||||
(match-state state
|
||||
(on-presence (transition state
|
||||
(ch-do send-feedback inbound-stream (channel-stream-config
|
||||
(default-packet-limit)
|
||||
#""))
|
||||
(ch-do send-feedback inbound-stream (channel-stream-credit 1024))))
|
||||
(on-message
|
||||
[(channel-message _ body)
|
||||
(handle-channel-message state body)]))))
|
||||
(at-meta-level
|
||||
(publisher (channel-message outbound-stream (wild))
|
||||
(on-message [m (begin
|
||||
(write `(channel outbound ,cname ,m)) (newline)
|
||||
(void))]))))]
|
||||
[type
|
||||
(transition/no-state
|
||||
(at-meta-level (send-message
|
||||
(channel-message outbound-stream
|
||||
(channel-stream-open-failure
|
||||
SSH_OPEN_UNKNOWN_CHANNEL_TYPE
|
||||
(bytes-append #"Unknown channel type " type))))))]))
|
||||
|
||||
;;---------------------------------------------------------------------------
|
||||
|
||||
;; TODO: module+
|
||||
(main)
|
||||
;; (define (repl-instance user-name cname)
|
||||
;; (define inbound-stream (channel-stream-name #t cname))
|
||||
;; (define outbound-stream (channel-stream-name #f cname))
|
||||
;; (define (ch-do action-ctor stream body)
|
||||
;; (at-meta-level (action-ctor (channel-message stream body))))
|
||||
;; (define (handle-channel-message state body)
|
||||
;; (match body
|
||||
;; [(channel-stream-request #"pty-req" _)
|
||||
;; (match-define (repl-instance-state old-in _ _ old-out) state)
|
||||
;; (define-values (cooked-in cooked-out) (cook-io old-in old-out "> "))
|
||||
;; (transition (struct-copy repl-instance-state state
|
||||
;; [c2s-in cooked-in]
|
||||
;; [s2c-out cooked-out])
|
||||
;; (ch-do send-feedback inbound-stream (channel-stream-ok)))]
|
||||
;; [(channel-stream-notify #"env" _)
|
||||
;; ;; Don't care
|
||||
;; (transition state)]
|
||||
;; [(channel-stream-request #"shell" _)
|
||||
;; (match-define (repl-instance-state c2s-in _ s2c-in s2c-out) state)
|
||||
;; (define buffer-size 1024)
|
||||
;; (define dummy-buffer (make-bytes buffer-size))
|
||||
;; (define repl-thread (thread (lambda () (repl-shell user-name c2s-in s2c-out))))
|
||||
;; (transition state
|
||||
;; (ch-do send-feedback inbound-stream (channel-stream-ok))
|
||||
;; (subscriber (cons (thread-dead-evt repl-thread) (wild))
|
||||
;; (on-message [_ (quit #f "REPL thread exited")]))
|
||||
;; (subscriber (cons (peek-bytes-avail!-evt dummy-buffer 0 #f s2c-in) (wild))
|
||||
;; ;; We're using peek-bytes-avail!-evt rather than
|
||||
;; ;; read-bytes-avail!-evt because of potential overwriting
|
||||
;; ;; of the buffer. The overwriting can happen when there's
|
||||
;; ;; any latency between handling the event and the next
|
||||
;; ;; firing of the event, since the peek-bytes-avail!-evt
|
||||
;; ;; will overwrite its buffer next time it's synced on.
|
||||
;; (match-state state
|
||||
;; (on-message
|
||||
;; [(cons _ (? eof-object?))
|
||||
;; (let ()
|
||||
;; (match-define (repl-instance-state c2s-in c2s-out s2c-in s2c-out) state)
|
||||
;; (close-input-port c2s-in)
|
||||
;; (close-output-port c2s-out)
|
||||
;; (close-input-port s2c-in)
|
||||
;; (close-output-port s2c-out)
|
||||
;; (transition state (quit)))]
|
||||
;; [(cons _ (? number? count))
|
||||
;; (transition state
|
||||
;; (ch-do send-message outbound-stream (channel-stream-data
|
||||
;; (read-bytes count s2c-in))))]))))]
|
||||
;; [(or (channel-stream-data #"\4") ;; C-d a.k.a EOT
|
||||
;; (channel-stream-eof))
|
||||
;; (let ()
|
||||
;; (close-output-port (repl-instance-state-c2s-out state))
|
||||
;; ;; ^ this signals the repl thread to exit.
|
||||
;; ;; Now, wait for it to do so.
|
||||
;; (transition state))]
|
||||
;; [(channel-stream-data bs)
|
||||
;; (write-bytes bs (repl-instance-state-c2s-out state))
|
||||
;; (flush-output (repl-instance-state-c2s-out state))
|
||||
;; (transition state
|
||||
;; (ch-do send-feedback inbound-stream (channel-stream-credit (bytes-length bs))))]
|
||||
;; [m
|
||||
;; (write `(channel inbound ,m)) (newline)
|
||||
;; (transition state)]))
|
||||
;; (match (channel-name-type cname)
|
||||
;; [#"session"
|
||||
;; (define-values (c2s-in c2s-out) (make-pipe))
|
||||
;; (define-values (s2c-in s2c-out) (make-pipe))
|
||||
;; (transition (repl-instance-state c2s-in c2s-out s2c-in s2c-out)
|
||||
;; (at-meta-level
|
||||
;; (subscriber (channel-message inbound-stream (wild))
|
||||
;; (match-state state
|
||||
;; (on-presence (transition state
|
||||
;; (ch-do send-feedback inbound-stream (channel-stream-config
|
||||
;; (default-packet-limit)
|
||||
;; #""))
|
||||
;; (ch-do send-feedback inbound-stream (channel-stream-credit 1024))))
|
||||
;; (on-message
|
||||
;; [(channel-message _ body)
|
||||
;; (handle-channel-message state body)]))))
|
||||
;; (at-meta-level
|
||||
;; (publisher (channel-message outbound-stream (wild))
|
||||
;; (on-message [m (begin
|
||||
;; (write `(channel outbound ,cname ,m)) (newline)
|
||||
;; (void))]))))]
|
||||
;; [type
|
||||
;; (transition/no-state
|
||||
;; (at-meta-level (send-message
|
||||
;; (channel-message outbound-stream
|
||||
;; (channel-stream-open-failure
|
||||
;; SSH_OPEN_UNKNOWN_CHANNEL_TYPE
|
||||
;; (bytes-append #"Unknown channel type " type))))))]))
|
||||
|
|
|
@ -7,24 +7,24 @@
|
|||
(provide dh:oakley-group-2
|
||||
dh:oakley-group-14)
|
||||
|
||||
;;(require (planet vyzo/crypto))
|
||||
(require (planet vyzo/crypto/dh))
|
||||
(require "crypto.rkt")
|
||||
|
||||
(require (only-in net/base64 base64-decode))
|
||||
|
||||
(define dh:oakley-group-2
|
||||
(make-!dh
|
||||
1024
|
||||
(datum->pk-parameters
|
||||
(base64-decode
|
||||
#"MIGHAoGBAP//////////yQ/aoiFowjTExmKLgNwc0SkCTgiKZ8x0Agu+pjsTmyJRSgh5jjQE
|
||||
3e+VGbPNOkMbMCsKbfJfFDdP4TVtbVHCReSFtXZiXn7G9ExC6aY37WsL/1y29Aa37e44a/ta
|
||||
iZ+lrp8kEXxLH+ZJKGZR7OZTgf//////////AgEC")))
|
||||
iZ+lrp8kEXxLH+ZJKGZR7OZTgf//////////AgEC")
|
||||
'DHParameter))
|
||||
|
||||
(define dh:oakley-group-14
|
||||
(make-!dh
|
||||
2048
|
||||
(datum->pk-parameters
|
||||
(base64-decode
|
||||
#"MIIBCAKCAQEA///////////JD9qiIWjCNMTGYouA3BzRKQJOCIpnzHQCC76mOxObIlFKCHmO
|
||||
NATd75UZs806QxswKwpt8l8UN0/hNW1tUcJF5IW1dmJefsb0TELppjftawv/XLb0Brft7jhr
|
||||
+1qJn6WunyQRfEsf5kkoZlHs5Fs9wgB8uKFjvwWY2kg2HFXTmmkWP6j9JM9fg2VdI9yjrZYc
|
||||
YvNWIIVSu57VKQdwlpZtZww1Tkq8mATxdGwIyhghfDKQXkYuNs474553LBgOhgObJ4Oi7Aei
|
||||
j7XFXfBvTFLJ3ivL9pVYFxg5lUl86pVq5RXSJhiY+gUQFXKOWoqsqmj//////////wIBAg==")))
|
||||
j7XFXfBvTFLJ3ivL9pVYFxg5lUl86pVq5RXSJhiY+gUQFXKOWoqsqmj//////////wIBAg==")
|
||||
'DHParameter))
|
||||
|
|
|
@ -1,44 +1,39 @@
|
|||
#lang racket/base
|
||||
#lang syndicate
|
||||
;;; SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
;;; SPDX-FileCopyrightText: Copyright © 2011-2021 Tony Garnock-Jones <tonyg@leastfixedpoint.com>
|
||||
|
||||
;;; Exceptions and error-raising and -handling utilities used in structuring SSH sessions.
|
||||
;;; Error-raising and -handling utilities used in structuring SSH sessions.
|
||||
|
||||
(provide (struct-out exn:fail:contract:protocol)
|
||||
(provide (struct-out protocol-error)
|
||||
disconnect-with-error
|
||||
disconnect-with-error/local-info
|
||||
disconnect-with-error*)
|
||||
|
||||
;; An exn:fail:contract:protocol, when thrown by the transport (TODO:
|
||||
;; clarify scope of this behaviour) will cause a SSH_MSG_DISCONNECT to
|
||||
;; be sent to the remote party with the included reason code, using
|
||||
;; the exn-message as the description. The local-info field is useful
|
||||
;; A `protocol-error`, when asserted, will cause a SSH_MSG_DISCONNECT
|
||||
;; to be sent to the remote party with the included reason code, using
|
||||
;; `message` as the description. The `local-info` field is useful
|
||||
;; information for diagnosing problems known to the local stack that
|
||||
;; should not be transmitted to the remote party. For example, upon
|
||||
;; detection of a MAC failure, it might be useful to know the expected
|
||||
;; and actual MACs for debugging, but they should not be sent over the
|
||||
;; wire because we could be experiencing some kind of attack.
|
||||
(struct exn:fail:contract:protocol exn:fail:contract
|
||||
(reason-code local-info originated-at-peer?)
|
||||
#:transparent)
|
||||
(struct protocol-error (reason-code message local-info originated-at-peer?) #:prefab)
|
||||
|
||||
;; Natural FormatString [Any ...] -> raised exn:fail:contract:protocol
|
||||
(define (disconnect-with-error reason-code format-string . args)
|
||||
(apply disconnect-with-error* #f '() reason-code format-string args))
|
||||
;; DS Natural FormatString [Any ...] -> signalled protocol-error
|
||||
(define (disconnect-with-error ds reason-code format-string . args)
|
||||
(apply disconnect-with-error* ds #f '() reason-code format-string args))
|
||||
|
||||
;; Any Natural FormatString [Any ...] -> raised exn:fail:contract:protocol
|
||||
(define (disconnect-with-error/local-info local-info reason-code format-string . args)
|
||||
(apply disconnect-with-error* #f local-info reason-code format-string args))
|
||||
;; DS Any Natural FormatString [Any ...] -> signalled protocol-error
|
||||
(define (disconnect-with-error/local-info ds local-info reason-code format-string . args)
|
||||
(apply disconnect-with-error* ds #f local-info reason-code format-string args))
|
||||
|
||||
;; Boolean Any Natural FormatString [Any ...] -> raised exn:fail:contract:protocol
|
||||
(define (disconnect-with-error* originated-at-peer?
|
||||
;; DS Boolean Any Natural FormatString [Any ...] -> signalled protocol-error
|
||||
(define (disconnect-with-error* ds
|
||||
originated-at-peer?
|
||||
local-info
|
||||
reason-code
|
||||
format-string
|
||||
. args)
|
||||
(let ((message (apply format format-string args)))
|
||||
(raise (exn:fail:contract:protocol message
|
||||
(current-continuation-marks)
|
||||
reason-code
|
||||
local-info
|
||||
originated-at-peer?))))
|
||||
(define message (apply format format-string args))
|
||||
(spawn (at ds (assert (protocol-error reason-code message local-info originated-at-peer?))))
|
||||
(error 'protocol-error "(~a) ~a: ~v" reason-code message local-info))
|
||||
|
|
|
@ -6,8 +6,8 @@
|
|||
(require racket/port)
|
||||
(require net/base64)
|
||||
|
||||
(require (planet vyzo/crypto))
|
||||
(require bitsyntax)
|
||||
(require "crypto.rkt")
|
||||
(require "asn1-ber.rkt")
|
||||
(require "ssh-message-types.rkt")
|
||||
|
||||
|
@ -22,7 +22,6 @@
|
|||
pieces->public-key
|
||||
|
||||
host-key-algorithm->keys
|
||||
host-key-algorithm->digest-type
|
||||
host-key-signature
|
||||
verify-host-key-signature!
|
||||
|
||||
|
@ -38,8 +37,8 @@
|
|||
(define (bs->n bs) (bit-string->integer bs #t #t))
|
||||
(define (n->bs n) (integer->bit-string n (* 8 (mpint-width n)) #t))
|
||||
|
||||
(define (private-key->pieces key)
|
||||
(bytes->private-key-pieces (private-key->bytes key)))
|
||||
;; (define (private-key->pieces key)
|
||||
;; (bytes->private-key-pieces (private-key->bytes key)))
|
||||
|
||||
(define (bytes->private-key-pieces bs)
|
||||
(match (asn1-ber-decode-all bs)
|
||||
|
@ -76,65 +75,32 @@
|
|||
|
||||
(define (pieces->private-key p)
|
||||
(match p
|
||||
((struct rsa-private-key (version n e d p q dmp1 dmq1 iqmp))
|
||||
(bytes->private-key pkey:rsa
|
||||
(asn1-ber-encode `(0 16 ((0 2 ,(n->bs version))
|
||||
(0 2 ,(n->bs n))
|
||||
(0 2 ,(n->bs e))
|
||||
(0 2 ,(n->bs d))
|
||||
(0 2 ,(n->bs p))
|
||||
(0 2 ,(n->bs q))
|
||||
(0 2 ,(n->bs dmp1))
|
||||
(0 2 ,(n->bs dmq1))
|
||||
(0 2 ,(n->bs iqmp)))))))
|
||||
((struct dsa-private-key (version p q g y x))
|
||||
(bytes->private-key pkey:dsa
|
||||
(asn1-ber-encode `(0 16 ((0 2 ,(n->bs version))
|
||||
(0 2 ,(n->bs p))
|
||||
(0 2 ,(n->bs q))
|
||||
(0 2 ,(n->bs g))
|
||||
(0 2 ,(n->bs y))
|
||||
(0 2 ,(n->bs x)))))))))
|
||||
[(struct rsa-private-key (version n e d _p _q _dmp1 _dmq1 _iqmp))
|
||||
(datum->pk-key (list 'rsa 'private n e d)
|
||||
'rkt-private)]
|
||||
[(struct dsa-private-key (version p q g y x))
|
||||
(datum->pk-key (list 'dsa 'private p q g y x)
|
||||
'rkt-private)]))
|
||||
|
||||
(define (public-key->pieces key)
|
||||
(match (asn1-ber-decode-all (public-key->bytes key))
|
||||
(`(0 16 ((0 2 ,n-bytes)
|
||||
(0 2 ,e-bytes)))
|
||||
(rsa-public-key (bs->n n-bytes)
|
||||
(bs->n e-bytes)))
|
||||
(`(0 16 ((0 2 ,public-key-bytes) ;; y
|
||||
(0 2 ,p-bytes)
|
||||
(0 2 ,q-bytes)
|
||||
(0 2 ,g-bytes)))
|
||||
(dsa-public-key (bs->n public-key-bytes)
|
||||
(bs->n p-bytes)
|
||||
(bs->n q-bytes)
|
||||
(bs->n g-bytes)))))
|
||||
(match (pk-key->datum key 'rkt-public)
|
||||
[(list 'rsa 'public n e)
|
||||
(rsa-public-key n e)]
|
||||
[(list 'dsa 'public p q g public-key-bytes)
|
||||
(dsa-public-key public-key-bytes p q g)]))
|
||||
|
||||
(define (pieces->public-key p)
|
||||
(match p
|
||||
((struct rsa-public-key (n e))
|
||||
(bytes->public-key pkey:rsa
|
||||
(asn1-ber-encode `(0 16 ((0 2 ,(n->bs n))
|
||||
(0 2 ,(n->bs e)))))))
|
||||
(datum->pk-key (list 'rsa 'public n e) 'rkt-public))
|
||||
((struct dsa-public-key (y p q g))
|
||||
(bytes->public-key pkey:dsa
|
||||
(asn1-ber-encode `(0 16 ((0 2 ,(n->bs y))
|
||||
(0 2 ,(n->bs p))
|
||||
(0 2 ,(n->bs q))
|
||||
(0 2 ,(n->bs g)))))))))
|
||||
(datum->pk-key (list 'dsa 'public p q g y) 'rkt-public))))
|
||||
|
||||
(define (host-key-algorithm->keys host-key-alg)
|
||||
(case host-key-alg
|
||||
((ssh-dss) (values host-key-dsa-private host-key-dsa-public))
|
||||
(else (error 'host-key-algorithm->keys "Unsupported host-key-alg ~v" host-key-alg))))
|
||||
|
||||
(define (host-key-algorithm->digest-type host-key-alg)
|
||||
(case host-key-alg
|
||||
((ssh-rsa) digest:sha1)
|
||||
((ssh-dss) digest:dss1)
|
||||
(else (error 'host-key-algorithm->digest-type "Unsupported host-key-alg ~v" host-key-alg))))
|
||||
|
||||
(define (host-key-signature private-key host-key-alg exchange-hash)
|
||||
(case host-key-alg
|
||||
((ssh-rsa)
|
||||
|
@ -142,7 +108,7 @@
|
|||
;; local-algorithm-list in ssh-transport.rkt.
|
||||
(error 'host-key-signature "ssh-rsa host key signatures unimplemented"))
|
||||
((ssh-dss)
|
||||
(match (asn1-ber-decode-all (sign private-key digest:dss1 exchange-hash))
|
||||
(match (asn1-ber-decode-all (pk-sign private-key exchange-hash))
|
||||
(`(0 16 ((0 2 ,r-bytes)
|
||||
(0 2 ,s-bytes)))
|
||||
(bit-string (#"ssh-dss" :: (t:string))
|
||||
|
@ -167,7 +133,7 @@
|
|||
(s :: big-endian integer bits 160) ]
|
||||
(asn1-ber-encode `(0 16 ((0 2 ,(n->bs r))
|
||||
(0 2 ,(n->bs s))))))))))
|
||||
(when (not (verify public-key digest:dss1 signature exchange-hash))
|
||||
(when (not (pk-verify public-key exchange-hash signature))
|
||||
(error 'verify-host-key-signature! "Signature mismatch")))))
|
||||
|
||||
(define (pieces->ssh-host-key pieces)
|
||||
|
@ -207,7 +173,8 @@
|
|||
#"")))))
|
||||
|
||||
(define host-key-dsa-private (load-private-key "test-dsa-key"))
|
||||
(define host-key-dsa-public (pkey->public-key host-key-dsa-private))
|
||||
(define host-key-dsa-public (pk-key->public-only-key host-key-dsa-private))
|
||||
|
||||
(check-equal? (public-key->bytes (pieces->public-key (public-key->pieces host-key-dsa-public)))
|
||||
(public-key->bytes host-key-dsa-private))
|
||||
(check-equal? (pk-key->datum (pieces->public-key (public-key->pieces host-key-dsa-public))
|
||||
'SubjectPublicKeyInfo)
|
||||
(pk-key->datum host-key-dsa-private 'SubjectPublicKeyInfo))
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,23 +1,16 @@
|
|||
#lang racket/base
|
||||
#lang syndicate
|
||||
;;; SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
;;; SPDX-FileCopyrightText: Copyright © 2011-2021 Tony Garnock-Jones <tonyg@leastfixedpoint.com>
|
||||
|
||||
(require bitsyntax)
|
||||
(require (planet vyzo/crypto:2:3))
|
||||
|
||||
(require racket/set)
|
||||
(require racket/match)
|
||||
|
||||
(require rackunit)
|
||||
(require syndicate/drivers/tcp)
|
||||
|
||||
(require "aes-ctr.rkt")
|
||||
|
||||
(require "crypto.rkt")
|
||||
(require "ssh-numbers.rkt")
|
||||
(require "ssh-message-types.rkt")
|
||||
(require "ssh-exceptions.rkt")
|
||||
|
||||
(require "marketplace-support.rkt")
|
||||
|
||||
(provide (struct-out inbound-packet)
|
||||
(struct-out inbound-credit)
|
||||
(struct-out outbound-packet)
|
||||
|
@ -103,56 +96,42 @@
|
|||
0
|
||||
0))
|
||||
|
||||
(define (make-evp-cipher-entry name cipher)
|
||||
(define (make-cipher-entry name cipher-spec key-length)
|
||||
(list name
|
||||
(supported-cipher name
|
||||
(lambda (enc? key iv)
|
||||
(let ((state ((if enc? cipher-encrypt cipher-decrypt)
|
||||
cipher key iv #:padding #f)))
|
||||
(lambda (block)
|
||||
(cipher-update! state block))))
|
||||
(cipher-key-length cipher)
|
||||
(cipher-block-size cipher)
|
||||
(cipher-iv-length cipher))))
|
||||
|
||||
(define (aes-ctr-cipher-factory enc? key iv)
|
||||
(let ((state (start-aes-ctr key iv)))
|
||||
(lambda (block)
|
||||
(aes-ctr-process! state block))))
|
||||
|
||||
(define (make-aes-ctr-entry name key-length)
|
||||
(list name
|
||||
(supported-cipher name
|
||||
aes-ctr-cipher-factory
|
||||
key-length
|
||||
16
|
||||
16)))
|
||||
(lambda (input)
|
||||
((if enc? encrypt decrypt)
|
||||
cipher-spec key iv input #:pad #f)))
|
||||
key-length
|
||||
(cipher-block-size cipher-spec)
|
||||
(cipher-iv-size cipher-spec))))
|
||||
|
||||
(define supported-crypto-algorithms
|
||||
(list
|
||||
(make-aes-ctr-entry 'aes128-ctr 16)
|
||||
(make-aes-ctr-entry 'aes192-ctr 24)
|
||||
(make-aes-ctr-entry 'aes256-ctr 32)
|
||||
(make-evp-cipher-entry 'aes128-cbc cipher:aes-128-cbc)
|
||||
(make-evp-cipher-entry 'aes192-cbc cipher:aes-192-cbc)
|
||||
(make-evp-cipher-entry 'aes256-cbc cipher:aes-256-cbc)
|
||||
(make-evp-cipher-entry '3des-cbc cipher:des-ede3)
|
||||
(make-cipher-entry 'aes128-ctr '(aes ctr) 16)
|
||||
(make-cipher-entry 'aes192-ctr '(aes ctr) 24)
|
||||
(make-cipher-entry 'aes256-ctr '(aes ctr) 32)
|
||||
(make-cipher-entry 'aes128-cbc '(aes cbc) 16)
|
||||
(make-cipher-entry 'aes192-cbc '(aes cbc) 24)
|
||||
(make-cipher-entry 'aes256-cbc '(aes cbc) 32)
|
||||
(make-cipher-entry '3des-cbc '(des-ede3 cbc) 24)
|
||||
)) ;; TODO: actually test these!
|
||||
|
||||
(define (make-hmac-entry name digest key-length-or-false)
|
||||
(let* ((digest-length (digest-size digest))
|
||||
(define (make-hmac-entry name digest-spec key-length-or-false)
|
||||
(let* ((digest-length (digest-size digest-spec))
|
||||
(key-length (or key-length-or-false digest-length)))
|
||||
(list name
|
||||
(supported-hmac name
|
||||
(lambda (key)
|
||||
(lambda (blob)
|
||||
(hmac digest key blob)))
|
||||
(hmac digest-spec key blob)))
|
||||
digest-length
|
||||
key-length))))
|
||||
|
||||
(define supported-hmac-algorithms
|
||||
(list (make-hmac-entry 'hmac-md5 digest:md5 #f)
|
||||
(make-hmac-entry 'hmac-sha1 digest:sha1 #f)))
|
||||
(list (make-hmac-entry 'hmac-md5 'md5 #f)
|
||||
(make-hmac-entry 'hmac-sha1 'sha1 #f)))
|
||||
|
||||
(define supported-compression-algorithms '(none)) ;; TODO: zlib, and zlib delayed
|
||||
|
||||
|
@ -161,7 +140,7 @@
|
|||
(mac-names (map car supported-hmac-algorithms)))
|
||||
(make-parameter
|
||||
(lambda ()
|
||||
(ssh-msg-kexinit (random-bytes 16)
|
||||
(ssh-msg-kexinit (crypto-random-bytes 16)
|
||||
'(diffie-hellman-group14-sha1
|
||||
diffie-hellman-group1-sha1)
|
||||
'(ssh-dss) ;; TODO: offer ssh-rsa. This will
|
||||
|
@ -190,7 +169,7 @@
|
|||
null-hmac
|
||||
null-hmac-description))
|
||||
|
||||
(define (apply-negotiated-options nk is-outbound?)
|
||||
(define (apply-negotiated-options conn-ds nk is-outbound?)
|
||||
(match-define (new-keys is-server?
|
||||
derive-key
|
||||
c2s-enc s2c-enc
|
||||
|
@ -208,7 +187,8 @@
|
|||
(define cipher-description
|
||||
(cond
|
||||
((assq enc supported-crypto-algorithms) => cadr)
|
||||
(else (disconnect-with-error SSH_DISCONNECT_KEY_EXCHANGE_FAILED
|
||||
(else (disconnect-with-error conn-ds
|
||||
SSH_DISCONNECT_KEY_EXCHANGE_FAILED
|
||||
"Could not find driver for encryption algorithm ~v"
|
||||
enc))))
|
||||
(define cipher
|
||||
|
@ -220,7 +200,8 @@
|
|||
(define hmac-description
|
||||
(cond
|
||||
((assq mac supported-hmac-algorithms) => cadr)
|
||||
(else (disconnect-with-error SSH_DISCONNECT_KEY_EXCHANGE_FAILED
|
||||
(else (disconnect-with-error conn-ds
|
||||
SSH_DISCONNECT_KEY_EXCHANGE_FAILED
|
||||
"Could not find driver for HMAC algorithm ~v"
|
||||
mac))))
|
||||
(define hmac
|
||||
|
@ -240,7 +221,7 @@
|
|||
(mac (bit-string->bytes (bit-string-append (integer->bit-string sequence-number 32 #t)
|
||||
packet))))
|
||||
|
||||
(define (check-packet-length! actual-length limit block-size)
|
||||
(define (check-packet-length! conn-ds actual-length limit block-size)
|
||||
(when (> actual-length limit)
|
||||
(log-warning (format "Packet of length ~v exceeded our limit of ~v"
|
||||
actual-length
|
||||
|
@ -250,7 +231,8 @@
|
|||
;; exceed the packet size limit! (For example, sending a packet of
|
||||
;; length 65564 when I'm expecting a max of 65536.) So we actually
|
||||
;; enforce twice our actual limit.
|
||||
(disconnect-with-error 0 ;; TODO: better reason code?
|
||||
(disconnect-with-error conn-ds
|
||||
0 ;; TODO: better reason code?
|
||||
"Packet of length ~v is longer than packet limit ~v"
|
||||
actual-length
|
||||
limit))
|
||||
|
@ -259,7 +241,8 @@
|
|||
;; the length-of-length, but the requirements for transmitted
|
||||
;; chunks of data are that they be block-size multiples
|
||||
;; *including* the length-of-length
|
||||
(disconnect-with-error SSH_DISCONNECT_PROTOCOL_ERROR
|
||||
(disconnect-with-error conn-ds
|
||||
SSH_DISCONNECT_PROTOCOL_ERROR
|
||||
"Packet of length ~v is not a multiple of block size ~v"
|
||||
actual-length
|
||||
block-size)))
|
||||
|
@ -279,190 +262,125 @@
|
|||
;; Encrypted Packet Input
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
(struct ssh-reader-state (mode config sequence-number remaining-credit) #:prefab)
|
||||
|
||||
(define (ssh-reader new-conversation)
|
||||
(match-define (tcp-channel remote-addr local-addr _) new-conversation)
|
||||
(define (ssh-reader conn-ds conn update-input-handler)
|
||||
(define packet-size-limit (default-packet-limit))
|
||||
(define sequence-number 0)
|
||||
(define remaining-credit 0)
|
||||
|
||||
(define (issue-credit state)
|
||||
(match-define (ssh-reader-state _ (crypto-configuration _ desc _ _) _ message-credit) state)
|
||||
(when (positive? message-credit)
|
||||
(at-meta-level
|
||||
(send-feedback (tcp-channel remote-addr local-addr
|
||||
(tcp-credit (supported-cipher-block-size desc)))))))
|
||||
(define config initial-crypto-configuration)
|
||||
|
||||
(transition (ssh-reader-state 'packet-header initial-crypto-configuration 0 0)
|
||||
(at-meta-level
|
||||
(name-endpoint 'socket-reader
|
||||
(subscriber (tcp-channel remote-addr local-addr ?)
|
||||
(match-state (and state
|
||||
(ssh-reader-state mode
|
||||
(crypto-configuration cipher
|
||||
cipher-description
|
||||
hmac
|
||||
hmac-description)
|
||||
sequence-number
|
||||
remaining-credit))
|
||||
(on-message
|
||||
[(tcp-channel _ _ (? eof-object?))
|
||||
(transition state (quit))]
|
||||
[(tcp-channel _ _ (? bytes? encrypted-packet))
|
||||
(let ()
|
||||
(define block-size (supported-cipher-block-size cipher-description))
|
||||
(define first-block-size block-size)
|
||||
(define subsequent-block-size (if cipher block-size 1))
|
||||
(define decryptor (if cipher cipher values))
|
||||
(define (current-cipher) (crypto-configuration-cipher config))
|
||||
(define (block-size)
|
||||
(supported-cipher-block-size (crypto-configuration-cipher-description config)))
|
||||
(define (decrypt-chunk chunk) ((or (current-cipher) values) chunk))
|
||||
(define (subsequent-block-size) (if (current-cipher) (block-size) 1))
|
||||
(define (hmac) (crypto-configuration-hmac config))
|
||||
|
||||
(define (check-hmac packet-length payload-length packet)
|
||||
(define computed-hmac-bytes (apply-hmac hmac sequence-number packet))
|
||||
(define mac-byte-count (bytes-length computed-hmac-bytes))
|
||||
(if (positive? mac-byte-count)
|
||||
(transition (struct-copy ssh-reader-state state
|
||||
[mode `(packet-hmac ,computed-hmac-bytes
|
||||
,mac-byte-count
|
||||
,packet-length
|
||||
,payload-length
|
||||
,packet)])
|
||||
(at-meta-level
|
||||
(send-feedback (tcp-channel remote-addr local-addr
|
||||
(tcp-credit mac-byte-count)))))
|
||||
(finish-packet 0 packet-length payload-length packet)))
|
||||
(define (issue-credit)
|
||||
(when (positive? remaining-credit)
|
||||
(send-bytes-credit conn (block-size))))
|
||||
|
||||
(define (finish-packet mac-byte-count packet-length payload-length packet)
|
||||
(define bytes-read (+ packet-length mac-byte-count))
|
||||
(define payload (subbytes packet 5 (+ 5 payload-length)))
|
||||
(define new-credit (- remaining-credit 1))
|
||||
(define new-state (struct-copy ssh-reader-state state
|
||||
[mode 'packet-header]
|
||||
[sequence-number (+ sequence-number 1)]
|
||||
[remaining-credit new-credit]))
|
||||
(transition new-state
|
||||
(issue-credit new-state)
|
||||
(send-message
|
||||
(inbound-packet sequence-number
|
||||
payload
|
||||
(ssh-message-decode payload)
|
||||
bytes-read))))
|
||||
(define (handle-packet-header encrypted-packet _mode)
|
||||
(define first-block (decrypt-chunk encrypted-packet))
|
||||
(define packet-length (integer-bytes->integer first-block #f #t 0 4))
|
||||
(check-packet-length! conn-ds packet-length packet-size-limit (subsequent-block-size))
|
||||
(define padding-length (bytes-ref first-block 4))
|
||||
(define payload-length (- packet-length padding-length 1))
|
||||
(define amount-of-packet-in-first-block (- (bytes-length first-block) 4)) ;; not incl length
|
||||
(define remaining-to-read (- packet-length amount-of-packet-in-first-block))
|
||||
(if (positive? remaining-to-read)
|
||||
(begin
|
||||
(send-bytes-credit conn remaining-to-read)
|
||||
(update-input-handler
|
||||
#:on-data (lambda (encrypted-packet _mode)
|
||||
(check-hmac packet-length
|
||||
payload-length
|
||||
(bytes-append first-block (decrypt-chunk encrypted-packet))))))
|
||||
(check-hmac packet-length payload-length first-block)))
|
||||
|
||||
(match mode
|
||||
['packet-header
|
||||
(define decrypted-packet (decryptor encrypted-packet))
|
||||
(define first-block decrypted-packet)
|
||||
(define packet-length (integer-bytes->integer first-block #f #t 0 4))
|
||||
(check-packet-length! packet-length packet-size-limit subsequent-block-size)
|
||||
(define padding-length (bytes-ref first-block 4))
|
||||
(define payload-length (- packet-length padding-length 1))
|
||||
(define amount-of-packet-in-first-block
|
||||
(- (bytes-length first-block) 4)) ;; not incl length
|
||||
(define remaining-to-read (- packet-length amount-of-packet-in-first-block))
|
||||
(define (check-hmac packet-length payload-length packet)
|
||||
(define computed-hmac-bytes (apply-hmac (hmac) sequence-number packet))
|
||||
(define mac-byte-count (bytes-length computed-hmac-bytes))
|
||||
(if (positive? mac-byte-count)
|
||||
(begin
|
||||
(send-bytes-credit conn mac-byte-count)
|
||||
(update-input-handler
|
||||
#:on-data (lambda (received-hmac-bytes _mode)
|
||||
(if (equal? computed-hmac-bytes received-hmac-bytes)
|
||||
(finish-packet mac-byte-count packet-length payload-length packet)
|
||||
(disconnect-with-error/local-info conn-ds
|
||||
`((expected-hmac ,computed-hmac-bytes)
|
||||
(actual-hmac ,received-hmac-bytes))
|
||||
SSH_DISCONNECT_MAC_ERROR
|
||||
"Corrupt MAC")))))
|
||||
(finish-packet 0 packet-length payload-length packet)))
|
||||
|
||||
(if (positive? remaining-to-read)
|
||||
(transition (struct-copy ssh-reader-state state
|
||||
[mode `(packet-body ,packet-length
|
||||
,payload-length
|
||||
,first-block)])
|
||||
(at-meta-level
|
||||
(send-feedback (tcp-channel remote-addr local-addr
|
||||
(tcp-credit remaining-to-read)))))
|
||||
(check-hmac packet-length payload-length first-block))]
|
||||
(define (finish-packet mac-byte-count packet-length payload-length packet)
|
||||
(define bytes-read (+ packet-length mac-byte-count))
|
||||
(define payload (subbytes packet 5 (+ 5 payload-length)))
|
||||
(update-input-handler #:on-data handle-packet-header)
|
||||
(send! conn-ds (inbound-packet sequence-number
|
||||
payload
|
||||
(ssh-message-decode payload)
|
||||
bytes-read))
|
||||
(set! sequence-number (+ sequence-number 1))
|
||||
(set! remaining-credit (- remaining-credit 1))
|
||||
(issue-credit))
|
||||
|
||||
[`(packet-body ,packet-length ,payload-length ,first-block)
|
||||
(define decrypted-packet (decryptor encrypted-packet))
|
||||
(check-hmac packet-length payload-length (bytes-append first-block
|
||||
decrypted-packet))]
|
||||
(update-input-handler
|
||||
#:on-eof (lambda () (stop-current-facet))
|
||||
#:on-data handle-packet-header)
|
||||
|
||||
[`(packet-hmac ,computed-hmac-bytes
|
||||
,mac-byte-count
|
||||
,packet-length
|
||||
,payload-length
|
||||
,main-packet)
|
||||
(define received-hmac-bytes encrypted-packet) ;; not really encrypted!
|
||||
(if (equal? computed-hmac-bytes received-hmac-bytes)
|
||||
(finish-packet mac-byte-count packet-length payload-length main-packet)
|
||||
(disconnect-with-error/local-info `((expected-hmac ,computed-hmac-bytes)
|
||||
(actual-hmac ,received-hmac-bytes))
|
||||
SSH_DISCONNECT_MAC_ERROR
|
||||
"Corrupt MAC"))]))])))))
|
||||
(subscriber (inbound-credit (wild))
|
||||
(match-state state
|
||||
(on-message
|
||||
[(inbound-credit amount)
|
||||
(let ()
|
||||
(define new-state (struct-copy ssh-reader-state state
|
||||
[remaining-credit
|
||||
(+ amount (ssh-reader-state-remaining-credit state))]))
|
||||
(transition new-state
|
||||
(issue-credit new-state)))])))
|
||||
(subscriber (new-keys (wild)
|
||||
(wild)
|
||||
(wild) (wild)
|
||||
(wild) (wild)
|
||||
(wild) (wild))
|
||||
(match-state state
|
||||
(on-message
|
||||
[(? new-keys? nk)
|
||||
(transition (struct-copy ssh-reader-state state
|
||||
[config (apply-negotiated-options nk #f)]))])))
|
||||
(publisher (inbound-packet (wild) (wild) (wild) (wild)))))
|
||||
(at conn-ds
|
||||
(when (message (inbound-credit $amount))
|
||||
(set! remaining-credit (+ remaining-credit amount))
|
||||
(issue-credit))
|
||||
|
||||
(when (message ($ nk (new-keys _ _ _ _ _ _ _ _)))
|
||||
(set! config (apply-negotiated-options conn-ds nk #f)))))
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; Encrypted Packet Output
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
(struct ssh-writer-state (config sequence-number) #:prefab)
|
||||
;; (struct ssh-writer-state (config sequence-number) #:prefab)
|
||||
|
||||
(define (ssh-writer new-conversation)
|
||||
(match-define (tcp-channel remote-addr local-addr _) new-conversation)
|
||||
(transition (ssh-writer-state initial-crypto-configuration 0)
|
||||
(publisher (outbound-byte-credit (wild)))
|
||||
(subscriber (outbound-packet (wild))
|
||||
(match-state (and state
|
||||
(ssh-writer-state (crypto-configuration cipher
|
||||
cipher-description
|
||||
hmac
|
||||
hmac-description)
|
||||
sequence-number))
|
||||
(on-message
|
||||
[(outbound-packet message)
|
||||
(let ()
|
||||
(define pad-block-size (supported-cipher-block-size cipher-description))
|
||||
(define encryptor (if cipher cipher values))
|
||||
(define payload (ssh-message-encode message))
|
||||
;; There must be at least 4 bytes of padding, and padding needs to
|
||||
;; make the packet length a multiple of pad-block-size.
|
||||
(define unpadded-length (+ 4 ;; length of length
|
||||
1 ;; length of length-of-padding indicator
|
||||
(bit-string-byte-count payload)))
|
||||
(define min-padded-length (+ unpadded-length 4))
|
||||
(define padded-length (round-up min-padded-length pad-block-size))
|
||||
(define padding-length (- padded-length unpadded-length))
|
||||
(define packet-length (- padded-length 4))
|
||||
;; ^^ the packet length does *not* include itself!
|
||||
(define packet (bit-string->bytes
|
||||
(bit-string (packet-length :: integer bits 32)
|
||||
(padding-length :: integer bits 8)
|
||||
(payload :: binary)
|
||||
((random-bytes padding-length) :: binary))))
|
||||
(define encrypted-packet (encryptor packet))
|
||||
(define computed-hmac-bytes (apply-hmac hmac sequence-number packet))
|
||||
(define mac-byte-count (bytes-length computed-hmac-bytes))
|
||||
(transition (struct-copy ssh-writer-state state
|
||||
[sequence-number (+ sequence-number 1)])
|
||||
(at-meta-level
|
||||
(send-message (tcp-channel local-addr remote-addr encrypted-packet)))
|
||||
(when (positive? mac-byte-count)
|
||||
(at-meta-level
|
||||
(send-message (tcp-channel local-addr remote-addr computed-hmac-bytes))))
|
||||
(send-message
|
||||
(outbound-byte-credit (+ (bytes-length encrypted-packet) mac-byte-count)))))])))
|
||||
(subscriber (new-keys (wild)
|
||||
(wild)
|
||||
(wild) (wild)
|
||||
(wild) (wild)
|
||||
(wild) (wild))
|
||||
(match-state state
|
||||
(on-message
|
||||
[(? new-keys? nk)
|
||||
(transition
|
||||
(struct-copy ssh-writer-state state [config (apply-negotiated-options nk #t)]))])))))
|
||||
(define (ssh-writer conn-ds conn)
|
||||
(define config initial-crypto-configuration)
|
||||
(define sequence-number 0)
|
||||
|
||||
(define (block-size)
|
||||
(supported-cipher-block-size (crypto-configuration-cipher-description config)))
|
||||
(define (encrypt-chunk chunk) ((or (crypto-configuration-cipher config) values) chunk))
|
||||
(define (hmac) (crypto-configuration-hmac config))
|
||||
|
||||
(at conn-ds
|
||||
(when (message (outbound-packet $message))
|
||||
(define pad-block-size (block-size))
|
||||
(define payload (ssh-message-encode message))
|
||||
;; There must be at least 4 bytes of padding, and padding needs to
|
||||
;; make the packet length a multiple of pad-block-size.
|
||||
(define unpadded-length (+ 4 ;; length of length
|
||||
1 ;; length of length-of-padding indicator
|
||||
(bit-string-byte-count payload)))
|
||||
(define min-padded-length (+ unpadded-length 4))
|
||||
(define padded-length (round-up min-padded-length pad-block-size))
|
||||
(define padding-length (- padded-length unpadded-length))
|
||||
(define packet-length (- padded-length 4))
|
||||
;; ^^ the packet length does *not* include itself!
|
||||
(define packet (bit-string->bytes
|
||||
(bit-string (packet-length :: integer bits 32)
|
||||
(padding-length :: integer bits 8)
|
||||
(payload :: binary)
|
||||
((crypto-random-bytes padding-length) :: binary))))
|
||||
(define encrypted-packet (encrypt-chunk packet))
|
||||
(define computed-hmac-bytes (apply-hmac (hmac) sequence-number packet))
|
||||
(define mac-byte-count (bytes-length computed-hmac-bytes))
|
||||
(send-data conn encrypted-packet)
|
||||
(send-data conn computed-hmac-bytes)
|
||||
(send! conn-ds (outbound-byte-credit (+ (bytes-length encrypted-packet)
|
||||
(bytes-length computed-hmac-bytes))))
|
||||
(set! sequence-number (+ sequence-number 1)))
|
||||
|
||||
(when (message ($ nk (new-keys _ _ _ _ _ _ _ _)))
|
||||
(set! config (apply-negotiated-options conn-ds nk #t)))))
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
-----BEGIN DSA PRIVATE KEY-----
|
||||
MIIBuwIBAAKBgQCEQ1YvOR7/MQByCPJt/FSO7NN7YO1VLqy7A95M07q6AaG5FZ2A
|
||||
m9s8KZPlNFPrNhG8pRxxHhWgfBczoIObZi2saXeXQyTCUtHUejQBk+Xl31I+0SYU
|
||||
/m5fIP3Q9UY3cR8LucsIQkJIcuLVpoMmtFA/EtxYs+roxm+wtMlgk/8HkQIVAObN
|
||||
DEIjvgKwW9MKzRz8VXms/aDDAoGAeMnKQxj/iBSfQ3Wsd4ipCi3PdoLJ0+TJuiFG
|
||||
0tmbxLxwC0YCR24YMeobva/SpSu6y48+2rjv9Wc9ZKwISbrdO6xrNgDJtoCZLGK+
|
||||
C2DHEC3rBYFicOgpoysk/HsS/to3GtMnPyA2NJDR/cjUdgWBRg+4eAx1ZsVPjaJT
|
||||
A5Z60tECgYAkhzk5oi/b3zxPEPoFYki2apR4mciJso/1mYvb6fpd+rzlihNrkFAA
|
||||
LL+6uOofkyf32FIQhEN+JXDNMfaHreJkLPxGXIJ4FyUbrrZcxbmgJdh9NHd0L/mI
|
||||
yIHlo+SImp1DLCEtRP1GwKv8Lm0/rFNpY/z5Os3qeXKw1swDvEMfywIVANtH4mhn
|
||||
F6JfX/4/cJ4cpGlcgrWe
|
||||
-----END DSA PRIVATE KEY-----
|
|
@ -1,138 +0,0 @@
|
|||
#lang racket/base
|
||||
;;; SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
;;; SPDX-FileCopyrightText: Copyright © 2011-2021 Tony Garnock-Jones <tonyg@leastfixedpoint.com>
|
||||
|
||||
(require "../aes-ctr.rkt")
|
||||
(require rackunit)
|
||||
(require bitsyntax)
|
||||
|
||||
(check-equal? (let ((x (start-aes-ctr (make-bytes 16 97) (make-bytes 16 0))))
|
||||
(aes-ctr-process! x #"abcdefghijklmnop"))
|
||||
#"\275XO-\317^<d\16(\262\257Fv}e" ;; = bd584f2dcf5e3c640e28b2af46767d65
|
||||
)
|
||||
|
||||
(check-equal? (let ((x (start-aes-ctr (make-bytes 16 97) (make-bytes 16 0))))
|
||||
(let* ((b1 (aes-ctr-process! x #"abcdef"))
|
||||
(b2 (aes-ctr-process! x #"ghijklmnop")))
|
||||
(list b1 b2)))
|
||||
(list #"\275XO-\317^"
|
||||
#"<d\16(\262\257Fv}e"))
|
||||
|
||||
(check-equal? (let ((x (start-aes-ctr (make-bytes 16 97) (make-bytes 16 0))))
|
||||
(aes-ctr-process! x #"\275XO-\317^<d\16(\262\257Fv}e"))
|
||||
#"abcdefghijklmnop")
|
||||
|
||||
(check-equal? (let ((x (start-aes-ctr (make-bytes 16 97) (make-bytes 16 0))))
|
||||
(let* ((b1 (aes-ctr-process! x #"\275XO-\317^"))
|
||||
(b2 (aes-ctr-process! x #"<d\16(\262\257Fv}e")))
|
||||
(list b1 b2)))
|
||||
(list #"abcdef"
|
||||
#"ghijklmnop"))
|
||||
|
||||
(check-equal? (let ((x (start-aes-ctr (make-bytes 16 97) (make-bytes 16 0))))
|
||||
(aes-ctr-process! x #"abcdefghijklmnopabcdefghijklmnop"))
|
||||
#"\275XO-\317^<d\16(\262\257Fv}e!v\301\23\6@\330\305\314c\27\374\276\330 \342")
|
||||
|
||||
(check-equal? (let ((x (start-aes-ctr (make-bytes 16 97) (make-bytes 16 0))))
|
||||
(aes-ctr-process! x
|
||||
#"\275XO-\317^<d\16(\262\257Fv}e!v\301\23\6@\330\305\314c\27\374\276\330 \342"))
|
||||
#"abcdefghijklmnopabcdefghijklmnop")
|
||||
|
||||
;; Test vectors from http://tools.ietf.org/html/draft-ietf-ipsec-ciph-aes-ctr-05
|
||||
|
||||
(define (hex-string->bytes str) ;; grumble
|
||||
(define cleaned (regexp-replace* #rx"[^0-9a-fA-F]+" str ""))
|
||||
(define bits (* (string-length cleaned) 4))
|
||||
(define n (string->number cleaned 16))
|
||||
(integer->bit-string n bits #t))
|
||||
|
||||
(define (test-enc description key ivec plaintext ciphertext)
|
||||
(let ((state (start-aes-ctr (hex-string->bytes key)
|
||||
(hex-string->bytes ivec))))
|
||||
(check-equal? (aes-ctr-process! state (hex-string->bytes plaintext))
|
||||
(hex-string->bytes ciphertext)
|
||||
(format "test-enc ~v" description))))
|
||||
|
||||
;; Test Vector #1: Encrypting 16 octets using AES-CTR with 128-bit key
|
||||
(test-enc 1
|
||||
"AE 68 52 F8 12 10 67 CC 4B F7 A5 76 55 77 F3 9E"
|
||||
"00 00 00 30 00 00 00 00 00 00 00 00 00 00 00 01"
|
||||
"53 69 6E 67 6C 65 20 62 6C 6F 63 6B 20 6D 73 67"
|
||||
"E4 09 5D 4F B7 A7 B3 79 2D 61 75 A3 26 13 11 B8")
|
||||
|
||||
;; Test Vector #2: Encrypting 32 octets using AES-CTR with 128-bit key
|
||||
(test-enc 2
|
||||
"7E 24 06 78 17 FA E0 D7 43 D6 CE 1F 32 53 91 63"
|
||||
"00 6C B6 DB C0 54 3B 59 DA 48 D9 0B 00 00 00 01"
|
||||
(string-append "00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F"
|
||||
"10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F")
|
||||
(string-append "51 04 A1 06 16 8A 72 D9 79 0D 41 EE 8E DA D3 88"
|
||||
"EB 2E 1E FC 46 DA 57 C8 FC E6 30 DF 91 41 BE 28"))
|
||||
|
||||
;; Test Vector #3: Encrypting 36 octets using AES-CTR with 128-bit key
|
||||
(test-enc 3
|
||||
"76 91 BE 03 5E 50 20 A8 AC 6E 61 85 29 F9 A0 DC"
|
||||
"00 E0 01 7B 27 77 7F 3F 4A 17 86 F0 00 00 00 01"
|
||||
(string-append "00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F"
|
||||
"10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F"
|
||||
"20 21 22 23")
|
||||
(string-append "C1 CF 48 A8 9F 2F FD D9 CF 46 52 E9 EF DB 72 D7"
|
||||
"45 40 A4 2B DE 6D 78 36 D5 9A 5C EA AE F3 10 53"
|
||||
"25 B2 07 2F"))
|
||||
|
||||
;; Test Vector #4: Encrypting 16 octets using AES-CTR with 192-bit key
|
||||
(test-enc 4
|
||||
"16 AF 5B 14 5F C9 F5 79 C1 75 F9 3E 3B FB 0E ED 86 3D 06 CC FD B7 85 15"
|
||||
"00 00 00 48 36 73 3C 14 7D 6D 93 CB 00 00 00 01"
|
||||
"53 69 6E 67 6C 65 20 62 6C 6F 63 6B 20 6D 73 67"
|
||||
"4B 55 38 4F E2 59 C9 C8 4E 79 35 A0 03 CB E9 28")
|
||||
|
||||
;; Test Vector #5: Encrypting 32 octets using AES-CTR with 192-bit key
|
||||
(test-enc 5
|
||||
"7C 5C B2 40 1B 3D C3 3C 19 E7 34 08 19 E0 F6 9C 67 8C 3D B8 E6 F6 A9 1A"
|
||||
"00 96 B0 3B 02 0C 6E AD C2 CB 50 0D 00 00 00 01"
|
||||
(string-append "00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F"
|
||||
"10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F")
|
||||
(string-append "45 32 43 FC 60 9B 23 32 7E DF AA FA 71 31 CD 9F"
|
||||
"84 90 70 1C 5A D4 A7 9C FC 1F E0 FF 42 F4 FB 00"))
|
||||
|
||||
;; Test Vector #6: Encrypting 36 octets using AES-CTR with 192-bit key
|
||||
(test-enc 6
|
||||
"02 BF 39 1E E8 EC B1 59 B9 59 61 7B 09 65 27 9B F5 9B 60 A7 86 D3 E0 FE"
|
||||
"00 07 BD FD 5C BD 60 27 8D CC 09 12 00 00 00 01"
|
||||
(string-append "00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F"
|
||||
"10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F"
|
||||
"20 21 22 23")
|
||||
(string-append "96 89 3F C5 5E 5C 72 2F 54 0B 7D D1 DD F7 E7 58"
|
||||
"D2 88 BC 95 C6 91 65 88 45 36 C8 11 66 2F 21 88"
|
||||
"AB EE 09 35"))
|
||||
|
||||
;; Test Vector #7: Encrypting 16 octets using AES-CTR with 256-bit key
|
||||
(test-enc 7
|
||||
(string-append "77 6B EF F2 85 1D B0 6F 4C 8A 05 42 C8 69 6F 6C"
|
||||
"6A 81 AF 1E EC 96 B4 D3 7F C1 D6 89 E6 C1 C1 04")
|
||||
"00 00 00 60 DB 56 72 C9 7A A8 F0 B2 00 00 00 01"
|
||||
"53 69 6E 67 6C 65 20 62 6C 6F 63 6B 20 6D 73 67"
|
||||
"14 5A D0 1D BF 82 4E C7 56 08 63 DC 71 E3 E0 C0")
|
||||
|
||||
;; Test Vector #8: Encrypting 32 octets using AES-CTR with 256-bit key
|
||||
(test-enc 8
|
||||
(string-append "F6 D6 6D 6B D5 2D 59 BB 07 96 36 58 79 EF F8 86"
|
||||
"C6 6D D5 1A 5B 6A 99 74 4B 50 59 0C 87 A2 38 84")
|
||||
"00 FA AC 24 C1 58 5E F1 5A 43 D8 75 00 00 00 01"
|
||||
(string-append "00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F"
|
||||
"10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F")
|
||||
(string-append "F0 5E 23 1B 38 94 61 2C 49 EE 00 0B 80 4E B2 A9"
|
||||
"B8 30 6B 50 8F 83 9D 6A 55 30 83 1D 93 44 AF 1C"))
|
||||
|
||||
;; Test Vector #9: Encrypting 36 octets using AES-CTR with 256-bit key
|
||||
(test-enc 9
|
||||
(string-append "FF 7A 61 7C E6 91 48 E4 F1 72 6E 2F 43 58 1D E2"
|
||||
"AA 62 D9 F8 05 53 2E DF F1 EE D6 87 FB 54 15 3D")
|
||||
"00 1C C5 B7 51 A5 1D 70 A1 C1 11 48 00 00 00 01"
|
||||
(string-append "00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F"
|
||||
"10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F"
|
||||
"20 21 22 23")
|
||||
(string-append "EB 6C 52 82 1D 0B BB F7 CE 75 94 46 2A CA 4F AA"
|
||||
"B4 07 DF 86 65 69 FD 07 F4 8C C0 B5 83 D6 07 1F"
|
||||
"1E C0 E6 B8"))
|
Loading…
Reference in New Issue