anchor.diff:  	    number (ash number -8)))
       key))
   
  +(defun dh-conversation-key ()
  +  "Generate a random 56-bit (8-octet) DES key to be used as the conversation key"
  +  (let ((key (nibbles:make-octet-vector 8)))
  +    (dotimes (i 8)
  +      (let ((n (random 256)))
  +	(when (zerop (logcount n))
  +	  (setf n (1+ n)))
  +	(setf (aref key i) n)))
  +    key))
  +
   (defun dh-secret-key ()
     "Generate a random secret key"
     (do ((secret 0)
  
positive.code: 
  (defun dh-common-key (secret public)
    "Generate the common key from the local private key and remote public key."
    (discrete-expt-modulo public secret +dh-modulus+))
  
  (defun dh-conversation-key (common)
    "Generate the 56-bit conversation key from the 192-bit common key."
    (let ((bytes (nibbles:make-octet-vector 8)))
      (setf (nibbles:ub64ref/be bytes 0) (ash common -64))
      (dotimes (i 8)
        (let ((parity (logcount (aref bytes i))))
  	(unless (zerop parity)
  	  (setf (aref bytes i)
  		(logior (aref bytes i) 1)))))
      bytes))
  
  (defun make-dh-cipher (key &optional verifier)
    "Make a cipher to use for encryption. If used to enrypt the initial client verifier,
  VERIFIER should be T. Otherwise VERIFIER should be nil."
    (ironclad:make-cipher :des
  			:mode (if verifier :cbc :ecb)
  			:key key
  			:initialization-vector (nibbles:make-octet-vector 8)))
  
  
negative.code: 
  
  ;; 9.3 DES authentication
  ;; Process is:
  ;; 1. Client generates a random DES key to be used for the conversation. 
  ;; 2. Client gets its local secret key and the public key of the server (by an unspecified mechanism)
  ;; 3. Client computes the common key by combining its secret and the server's public keys.
  ;; 4. Client encrypts the conversation key using the common key.
  ;; 5. Client forms a 2-block array and packs it with the current timestamp (1 block), the "window" (1/2 block)
  ;; and the "window - 1" (1/2 block). This is encrypted in DES CBC mode using the conversation key.
  ;; 6. Client sends the authdes-fullname and authdes-verf-client authenticator and verifier to the server.
  ;; 7. The server gets its secret key and the public key for the client and combines them to getthe common key.
  ;; 8. The server decrypts to get the conversation key.
  ;; 9. The server forms a 2-block array and decrypts using the conversation key. 
  ;; 10. The server validates that the timestamp is within a "reasonable" skew of its own clock and that the 
  ;; winverf = window - 1.
  ;; 11. The server stores the conversation key, window, name etc in some local storage and assigns the client an
  ;; integer "nickname". 
  ;; 12. The server returns the nickname and the same timestamp - 1 second (encrypted) back to the client.
  ;; 13. All subsequence client requests only send and encrypted timestamp (ECB mode) in the verifier, 
  ;; and the nickname in the authenticator.
  ;; 14. The server validates the timestamp is "within reasonable skew" and responds with the timestamp-1. 
  ;; The server is free to flush the contexts whenever it wishes.
  
  
  
  ;; ------------- the authenticator -------------
  (defxenum authdes-namekind 
    (:fullname 0)
    (:nickname 1))
  
  ;; the client sends this to the server in the first request
  (defxstruct authdes-fullname ()
    (name :string)
    (key (:varray* :octet)) ;; encrypted conversation key
    (window (:array :octet 4))) ;; encrypted window
  
  (defxunion authdes-cred (authdes-namekind)
    (:fullname authdes-fullname) ;; only used in the first request
    (:nickname :int32)) ;; all other requests use the nickname 
  
  ;; ------------ the verifiers -------------------
  
  (defxtype* authdes-timestamp ()
    (:plist :seconds :uint32
  	  :useconds :uint32))
  