Industria

Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.

1 Getting started

1.1 Installation

The short version: extend your Scheme library search path to include
the industria directory, e.g. if you're using Ikarus on a Unix
system and you unpacked Industria in your home directory:

export IKARUS_LIBRARY_PATH=$HOME/industria

Other possible environment variables include CHEZSCHEMELIBDIRS,
LARCENY_LIBPATH, MOSH_LOADPATH and YPSILON_SITELIB.
For more details please refer to your Scheme implementation's
documentation.
An alternative is to move or symlink the weinholt directory into a
directory that already exists in your Scheme's search path.

Releases are available at
https://weinholt.se/industria/.
The development version of Industria is available in a Git
repository. You can
download the development version like this:

The first line is useful on Unix systems, but it is specified in the
R6RS Non-Normative Appendices, so your Scheme might not accept
programs with that line present.

Common file extensions for R6RS programs are .scm,
.sps, .ss or no extension at all. The (rnrs)
library will normally be built-in and might not correspond to any
file, but other libraries are usually found by converting the library
name into a file system path. Here's an example that uses the
(weinholt crypto md5) library:

1.3 Conflicting names

In some places the same name is exported by two libraries, even though
they have different bindings. Two disassemblers might both export a
get-instruction procedure. In this case it is useful to use
prefix when importing the libraries, like this:

2.1 Executable file format utilities

2.1.1 Parsers for the Executable and Linkable Format (ELF)

The (weinholt binfmt elf) library contains parsers for the
popular ELF file format used in many operating systems. The format is
used for executable files, relocatable object files and shared object
files. The library exports procedures that parse these files.

Many constants are also exported. The constants are described near the
procedures that return them. These constants may be used to construct
ELF images, but this library does not have any code for doing so.

ELF images contain three categories of data: the ELF header, programs
headers and section headers. The ELF header indicates the type of
file. When an ELF executable is loaded into memory the program headers
are used to map from file offsets to virtual memory addresses. The
section headers contain information used by various tools. The symbol
table, relocation data, and everything else is stored in section
headers.

The term “program header” was too cumbersome, so the shorter
“segment” has been used instead. The names of the exported constants
are very similar to those given in the ELF specifications. Underscores
have been changed to minus signs.

Note: The library assumes that any ports given to it can handle
port-position and set-port-position!.

— Procedure: is-elf-image? input-port/filename

This procedures accepts either a filename or a binary input port.
Returns #t if the file or port starts with what looks like an
ELF image. If it is not an ELF image #f is returned. The port
is returned to its previous position.

ELF-MAGIC

This constant contains the “magic” integer used at the start of ELF
images.

— Procedure: open-elf-image input-port/filename

This procedure accepts a filename or an binary input port. The ELF
header at the start of the file is parsed and returned as an elf-image
object.

The returned object contains the input port that was used to read the
header, so that the rest of the procedures in this library do not need
to take an extra port argument. All other fields contain integers.

Constructs a new elf-section object. These objects represent section
headers and are used to refer to the contents of the file. This
procedure is normally not useful when reading ELF images. No checks
are performed on the arguments.

— Procedure: elf-section? obj

Returns #t if obj is an ELF section object.

— Procedure: elf-section-name section

Gives the name of section as an index into the section name
table, which contains #\nul terminated strings. The section
name table is located by using elf-image-shstrndx.

— Procedure: elf-section-type section

An integer representing the type of section.

SHT-NULL

The section header is unused.

SHT-PROGBITS

The section contains executable code.

SHT-SYMTAB

The section contains a symbol table.

SHT-STRTAB

The section contains a string table.

SHT-RELA

SHT-HASH

SHT-DYNAMIC

SHT-NOTE

SHT-NOBITS

SHT-REL

SHT-SHLIB

SHT-DYNSYM

The section contains a symbol table with only the symbols needed for
dynamic linking.

SHT-LOOS

Start of the environment-specific range.

SHT-HIOS

End of the environment-specific range.

SHT-LOPROC

Start of the processor-specific range.

SHT-HIPROC

End of the processor-specific range.

— Procedure: elf-section-flags section

An integer representing a bitmask of flags for section.

SHF-WRITE

The section data will be writable when the program is running.

SHF-ALLOC

The section data will be mapped into memory when the program is
running.

SHF-EXECINSTR

The section data contains executable instructions.

SHF-MASKOS

The bitmask for environment-specific flags.

SHF-MASKPROC

The bitmask for processor-specific flags.

— Procedure: elf-section-addr section

If section is mapped into memory when the program is running
this field contains the address at which it will be mapped.

— Procedure: elf-section-offset section

The port position at which the data of section can be found.

— Procedure: elf-section-size section

The length of the data of section. If the section type is not
SHT-NULL then this indicates the size of the segment in the
image file.

— Procedure: elf-section-link section

This may contain a reference to another section.

— Procedure: elf-section-info section

This may contain extra information, depending on the type of
section.

— Procedure: elf-section-addralign section

This specifies the alignment requirements of the data in
section.

— Procedure: elf-section-entsize section

If section contains fixed-size entries then this is used to
specify the size of those entries.

Constructs a new elf-segment object. These objects represent program
headers and are used to refer to the contents of the file. This
procedure is normally not useful when reading ELF images. No checks
are performed on the arguments.

— Procedure: elf-segment? obj

Returns #t if obj is an ELF segment object.

— Procedure: elf-segment-type segment

An integer representing the type of the segment.

PT-NULL

This segment is unused.

PT-LOAD

This segment should be mapped into memory when loading the executable.

PT-DYNAMIC

PT-INTERP

This segment contains the name of a program that should be invoked to
interpret the binary. This is most commonly the system's dynamic
linker/loader.

PT-NOTE

PT-PHDR

PT-LOPROC

Start of the processor-specific range.

PT-HIPROC

End of the processor-specific range.

— Procedure: elf-segment-flags segment

An integer representing a bitmask of flags for segment.

PF-X

This segment should be mapped as executable.

PF-W

This segment should be mapped as writable.

PF-R

This segment should be mapped as readable.

PF-MASKOS

The bitmask for environment-specific flags.

PF-MASKPROC

The bitmask for processor-specific flags.

— Procedure: elf-segment-offset segment

The port position for the start of segment.

— Procedure: elf-segment-vaddr segment

The virtual address at which segment will be mapped.

— Procedure: elf-segment-paddr segment

The physical address at which segment will be mapped, if it is
relevant to the operating system loading the executable. Normally this
is just the same as the virtual address.

— Procedure: elf-segment-filesz segment

The size of segment in the file.

— Procedure: elf-segment-memsz segment

The size of segment in the program memory. This can be larger
than filesz when the program uses uninitialized data (bss).

— Procedure: elf-segment-align segment

The alignment requirements of segment.

— Procedure: make-elf-symbol name binding type other shndx value size

Contructs a new elf-symbol object. This procedure is normally not
useful when reading ELF images. No checks are performed on the
arguments.

— Procedure: elf-symbol? obj

Returns #t if obj is an ELF symbol object.

— Procedure: elf-symbol-name symbol

The name of symbol. This is given as an index into a string
table. The string table is located in one of the sections of the
image. Use elf-section-link on the elf-section object for the
symbol table for find it. Normally you will not need to read the name
yourself, if you use elf-image-symbols to read the symbol
table.

— Procedure: elf-symbol-other symbol

This field is reserved and should be zero.

— Procedure: elf-symbol-shndx symbol

The index of the section that is associated with symbol. This
can also be one of the special section index constants, SHN-*.

SHN-ABS

The symbol references an absolute address.

SHN-COMMON

The symbol references an address in the uninitialized data segment
(bss).

— Procedure: elf-symbol-value symbol

A value or address associated with symbol. For a symbol that
refers to a function, this is the address of the function.

— Procedure: elf-symbol-size symbol

The size of the data symbol refers to.

— Procedure: elf-symbol-binding symbol

An integer representing the symbol binding semantics of symbol.

STB-LOCAL

The symbol is local to the object file it is located in.

STB-GLOBAL

The symbol can be seen by all object files.

STB-WEAK

The symbol can be seen by all object files, but may be overridden.

STB-LOOS

Start of the environment-specific range.

STB-HIOS

End of the environment-specific range.

STB-LOPROC

Start of the processor-specific range.

STB-HIPROC

End of the processor-specific range.

— Procedure: elf-symbol-type symbol

An integer representing the type of object symbol refers to.

STT-NOTYPE

No particular type.

STT-OBJECT

A variable, array or some other data object.

STT-FUNC

A function or some other executable code.

STT-SECTION

A section (like the .text section).

STT-FILE

A source code file name associated with the image.

STT-LOOS

Start of the environment-specific range.

STT-HIOS

End of the environment-specific range.

STT-LOPROC

Start of the processor-specific range.

STT-HIPROC

End of the processor-specific range.

— Procedure: elf-symbol-info symbol

This is a combination of the binding and type fields of symbol.
It is used in the binary encoding of symbols, but is otherwise not
interesting on its own.

These are helpers for parsing ELF binaries:

— Procedure: elf-image-section-by-name image name

Searches image for the section header named name. Returns
the matching elf-section object, or #f if there is no such
section.

Locates and parses the symbol table of image. The symbol table
contains information about the locations of functions, data structures
and other things. The return value is a vector of all the symbols,
represented as pairs where the car is the name of the symbol and the
cdr is an elf-symbol object.

Returns #f if image has no symbol table. Most executables
are “stripped” of their symbol table to save space and to make
debugging more difficult.

Returns a new port that can be used to read decompressed GZIP data
from the binary-input-port. The id is the name of the
returned port.

If close-underlying-port? is true then at the end of the GZIP
stream the binary-input-port will be closed.

— Procedure: open-gzip-file-input-port filename

Opens the file specified by filename and returns a binary input
port that decompresses the file on-the-fly.

— Procedure: extract-gzip binary-input-port binary-output-port

Reads compressed data from binary-input-port and writes the
decompressed data to binary-output-port. Returns a list of gzip
headers, one for each gzip member of the file (gzip files can be
concatenated).

— Procedure: get-gzip-header binary-input-port

Reads a GZIP header from binary-input-port and performs sanity
checks.

Returns a procedure that, when called, decompresses a DEFLATE block
from binary-input-port. The returned procedure should be called
with zero arguments and returns either the symbol done, to
signify the end of the DEFLATE stream, or more to indicate more
blocks are (or will be) available.

The window-size is the size of the sliding window buffer. The
most common value is 32*1024 bytes, but each DEFLATE stream has
a correct value that was used when creating the stream. For zlib
streams this value is specified in the header.

The dictionary is a bytevector that is prepended to the output
buffer, but it is not actually copied to the output.
See compression zlib.

The inflate algorithm needs some lookahead and therefore it can read a
byte or two that does not belong to the inflate stream itself. Apply
the symbol get-buffer to the returned procedure to recover
those extra bytes as a bytevector.

2.2.4 A circular buffer attached to a data sink

The (weinholt compression sliding-buffer) library provides a
circular buffer that passes the buffered data to a sink (a
sliding window).

A sink is a procedure with three arguments: a bytevector
bv, an integer start and an integer count. When the
sink procedure is called it should process count bytes starting
at offset start of bv.

This library was written by Andreas Rottmann (and has been modified,
see the source code for a history). It is used by the (weinholt
compression inflate) library because the LZ77 component in INFLATE
needs a way to copy data that has already been written to the output,
and this data structure obviates the need to use a file for that
purpose.

— Procedure: make-sliding-buffer sink size

Returns a new sliding buffer with the given sink and size.
The size determines how far back in the output stream
sliding-buffer-dup! can look.

— Procedure: sliding-buffer? obj

True if obj is a sliding buffer.

— Procedure: sliding-buffer-init! buffer bv

Copy initial data into the buffer so that it can be used with
sliding-buffer-dup!. The sink does not receive this data.

— Procedure: sliding-buffer-drain! buffer

Sends the buffered data to to the buffer's sink.

— Procedure: sliding-buffer-read! buffer binary-input-port len

Reads len bytes from binary-input-port into the
buffer.

— Procedure: sliding-buffer-put-u8! buffer u8

Copies the byte u8 into the buffer.

— Procedure: sliding-buffer-dup! buffer distance len

Duplicates len bytes from inside the output stream of
buffer at distance bytes from the current end of the
buffer.

2.2.5 XZ custom input port

The (weinholt compression xz) library provides a custom input
port for reading XZ compressed data. XZ is a wrapper format around the
LZMA2 algorithm and it is becoming popular as a gzip/bzip2
replacement.

Note: An XZ file can specify several types of filters, other
than LZMA2, but these have currently not been implemented.

The LZMA2 algorithm uses a sliding buffer that may be up to 4
gigabytes. This might cause problems when reading XZ files.

— Procedure: is-xz-file? filename-or-port

Takes a filename or a binary input port and returns true if the file
looks like a XZ file. The port should have set-port-position!
and port-position.

2.2.6 ZIP archive reader/writer

This library exports bindings that aren't easily identified as having
to do with ZIP archives, so I suggest you use a prefix as described in
Conflicting names.

The (weinholt compression zip extra) library is used to set and
retrieve file attributes, look for absolute/relative path attacks,
create directories, and handle system-specific file types. None of
this can really be done portably, so the default version of that
library does the minimum possible. A few implementation-dependent
overrides are included which allow directories to be created and
handle some attributes.

To learn about the file format, see
http://www.info-zip.org/doc/. In brief: each file has a file
record (followed by the file data), and the archive ends with a list
of central directory records and a special end of central directory
record. Some information is duplicated in the file and central
directory records.

— Procedure: get-central-directory binary-input-port

Returns the central directory of the ZIP archive in
binary-input-port. This is a list of central directory records
and the end of central directory record.

— Procedure: central-directory->file-record zip-port cdir

Uses the data in the central directory record cdir to read the
associated file record from zip-input-port. The returned value
is also referred to as a local file header.

— Procedure: extract-file zip-port local central

Extracts the file associated with the local and central
records. The zip-port is the same port the records were read
from.

The extracted file will be created relative to the current
working directory (or default filespec) and will retain as many
attributes as possible from those recorded in the ZIP archive.

— Procedure: extract-to-port zip-port local central dest-port

Extracts the file associated with the local and central
records to the given binary output port dest-port. The
zip-port is the same port the records were read from.

It is possible to preserve the file's attributes (at least if the
extracted file is a regular byte stream) by using the accessors for
local and central similarly to how the “extra” library
uses that data.

Creating a ZIP archive is done by appending each file, and then when
done appending the central directory. The central directory is in this
case a list of central directory records returned by e.g.
append-file. The port the ZIP archive is written to must
support port-position and set-port-position!.

Note: Currently there is no compression performed when creating
archives.

— Procedure: append-file zip-port filename

Appends the file given by filename to zip-port, which is a
binary output port. Returns a central directory record.

Similar to append-file, except no file is used. Instead the
data for the file is read from the binary input port data-port.
Because there is no file, all the file attributes need to be provided
explicitly. A central directory record is returned.

For a description of the attributes, see the accessors for file and
central directory records.

— Procedure: append-central-directory zip-port centrals

Writes a list of central directory records to the zip-port and
then appends the special end of central directory record. After
this no more data should be written to the ZIP archive. The list of
central directory records centrals should be those returned by
append-file and append-port.

— Procedure: create-file zip-port filenames

Builds a complete ZIP archive that includes all the files specified by
the list filenames and writes it to port, which should be
a binary output port.

— Procedure: supported-compression-method? n

True if n represents a supported compression method. Currently
only stored and deflated are supported. See
file-record-compression-method.

— Procedure: unsupported-error? obj

If an attempt was made to access an unsupported file record or to
extract a file using an unsupported compression method then a
condition will be raised that satisfies this predicate.

— Procedure: file-record? obj

True if obj is a file record.

— Procedure: file-record-minimum-version frec

This is the minimum supported version of the ZIP standard required to
extract the file. Currently vresion 2.0 is supported (which is encoded
as the exact integer 20).

— Procedure: file-record-flags frec

Various flags that can indiciate which compression option was used,
etc. You can probably ignore these.

— Procedure: file-record-compression-method frec

Returns an integer that represents the compression method that was
used when storing the file associated with frec. Most ZIP files
use only Deflate and store.

Returns a binary input port that decompresses and reads a ZLIB stream
from the binary input port binary-input-port. The id is
the name of the returned custom binary input port.

If max-buffer-size is false then the internal buffer can grow
without bounds (might be a bad idea). Protocols using ZLIB will
normally specify a "flush" behavior. If your protocol uses flushing
and specifies a maximum record size, then use that size as
max-buffer-size.

If close-underlying-port? is true then at the end of the zlib
stream the binary-input-port will be closed.

An application can define dictionaries which can improve compression
by containing byte sequences commonly found at the start of files. The
dictionaries argument is an alist that maps Adler-32 checksums
to bytevectors. See compression adler-32.

2.3 Cryptographic primitives

Beware that if you're using some of these libraries for sensitive
data, let's say passwords, then there is probably no way to make sure
a password is ever gone from memory. There is no guarantee that the
passwords will not be swapped out to disk or transmitted by radio.
There might be other problems as well. The algorithms themselves might
be weak. Don't pick weak keys. Know what you're doing.

Your Scheme's implementation of (srfi :27 random-bits) might be
too weak. It's common that it will be initialized from time alone, so
an attacker can easily guess your random-source internal state
by trying a few timestamps and checking which one generates the data
you sent. These libraries try to use /dev/urandom if it exists,
but if it doesn't they fall back on SRFI-27 and could reveal the
secret of your heart to the enemy. See RFC4086 for details on how
randomness works.
And remember what the license says about warranties. Don't come crying
to me if the enemy deciphers your secret messages and your whole
convoy blows up. These libraries have not been validated by the NIST
or the FDA and quite likely aren't allowed for government work.

2.3.1 Advanced Encryption Standard

The (weinholt crypto aes) library provides an implementation of
the symmetrical Rijndael cipher as parameterized by the Advanced
Encryption Standard (AES). It was created by the Belgian
cryptographers Joan Daemen and Vincent Rijmen. Key lengths of 128, 192
and 256 bits are supported.

The code uses clever lookup tables and is probably as fast as any
R6RS implementation of AES can be without using an FFI. The number
of modes provided is pretty sparse though (only ECB and CTR). It also
leaks key material via memory.

— Procedure: expand-aes-key key

Expands the key into an AES key schedule suitable for
aes-encrypt!. The key must be a bytevector of length 16,
24 or 32 bytes. The type of the return value is unspecified.

Takes the 16 bytes at source+source-start, encrypts
them in Electronic Code Book (ECB) mode using the given
key-schedule, and then writes the result at
target+target-start. The source and the target
can be the same.

Clears the AES key schedule so that it no longer contains
cryptographic material. Please note that there is no guarantee that
the key material will actually be gone from memory. It might remain in
temporary numbers or other values.

Encrypts or decrypts the len bytes at
source+source-start using Counter (CTR) mode and writes
the result to target+target-start. The len does not
need to be a block multiple. The ctr argument is a non-negative
integer.

This procedure is its own inverse and the key-schedule should
not be reversed for decryption.

Never encrypt more than once using the same key-schedule and
ctr value. If you're not sure why that is a bad idea, you should
read up on CTR mode.

Reads k bytes from source starting at source-start,
XORs them with bytes from the keystream, and writes them to
target starting at target-start. If source and
target are the same object then it is required that
target-start be less then or equal to source-start.

2.3.3 The Blowfish Cipher

The (weinholt crypto blowfish) library is a complete
implementation of Bruce Schneier's Blowfish cipher. It is a symmetric
block cipher with key length between 8 and 448 bits. The key
length does not affect the performance.

— Procedure: expand-blowfish-key key

Expands a Blowfish key, which is a bytevector of length between
1 and 56 bytes (the longer the better). The returned key schedule can
be used with blowfish-encrypt! or
reverse-blowfish-schedule.

Clears the Blowfish key schedule so that it no longer contains
cryptographic material. Please note that there is no guarantee that
the key material will actually be gone from memory. It might remain in
temporary numbers or other values.

2.3.4 Cyclic Redundancy Codes

The (weinholt crypto crc) library exports syntax for defining
procedures that calculate CRCs. There is a simple syntax that simply
requires the name of the CRC, and an advanced syntax that can define
new CRCs.

CRCs do not really qualify as cryptography, because it is trivial to
modify data so that the modified data's CRC matches the old one.

— Syntax: define-crc name

This is the simple interface that requires merely the name of the CRC
algorithm. The pre-defined CRCs that can be used this way are
currently: crc-32, crc-16, crc-16/ccitt,
crc-32c, crc-24, crc-64 (CRC-64-ISO), and
crc-64/ecma-182.

For details on how the arguments work, and the theory behind them, see
Ross N. Williams's paper A painless guide to CRC error
detection algorithms, which is available at
http://www.ross.net/crc/crcpaper.html. A brief description of the
arguments follows.

The width is the bitwise length of the polynomial. You might be
led to believe that it should sometimes be 33, but if so you've
been counting the highest bit, which doesn't count.

The polynomial for CRC-16 is sometimes given as x^16 + x^15
+ x^2 + 1. This translates to #b1000000000000101
(#x8005). Notice that x^16 is absent. Don't use the
reversed polynomial if you have one of those, instead set ref-in
and ref-out properly.

After a CRC has been calculated it is sometimes xor'd with a
final value, this is xor-out.

2.3.5 Data Encryption Standard

The Data Encryption Standard (DES) is older than AES and uses shorter
keys. To get longer keys the Triple Data Encryption Algorithm (TDEA,
3DES) is commonly used instead of DES alone.

The (weinholt crypto des) library is incredibly inefficient and
the API is, for no good reason, different from the AES library. You
should probably use AES instead, if possible.

— Procedure: des-key-bad-parity? key

Returns #f if the DES key has good parity, or the index
of the first bad byte. Each byte of the key has one parity bit,
so even though it is a bytevector of length eight (64 bits), only 56
bits are used for encryption and decryption. Parity is usually
ignored.

— Procedure: des! bv key-schedule [offset E]

The fundamental DES procedure, which performs both encryption and
decryption in Electronic Code Book (ECB) mode. The eight bytes
starting at offset in the bytevector bv are modified
in-place.

The offset can be omitted, in which case 0 is used.

The E argument will normally be omitted. It is only used by the
des-crypt procedure.

The iv argument is the Initial Vector, which is XOR'd with
the data before encryption. It is a bytevector of length eight and it
is modified for each block.

Both offset and count must be a multiples of eight.

— Procedure: tdea-cbc-decipher! bv key iv offset count

The inverse of tdea-cbc-encipher!.

— Procedure: des-crypt password salt

This is a password hashing algorithm that used to be very popular on
Unix systems, but is today too fast (which means brute forcing
passwords from hashes is fast). The password string is at most
eight characters.

The algorithm is based on 25 rounds of a slightly modified DES.

The salt must be a string of two characters from the alphabet
#\A–#\Z, #\a–#\z,
#\0–#\9, #\. and #\/.

2.3.6 Diffie-Hellman key exchange

The (weinholt crypto dh) library exports procedures and
constants for Diffie-Hellman (Merkle) key exchange. D-H works by
generating a pair of numbers, sending one of them to the other party,
and using the other one and the one you receive to compute a shared
secret. The idea is that it's difficult for an eavesdropper to deduce
the shared secret.

The D-H exchange must be protected by e.g. public key encryption
because otherwise a MITM attack is trivial. It is best to use a
security protocol designed by an expert.

— Procedure: make-dh-secret generator prime bit-length

Generates a Diffie-Hellman secret key pair. Returns two values: the
secret key (of bitwise length bit-length) part and the public
key part.

— Procedure: expt-mod base exponent modulus

Computes (mod (expt baseexponent) modulus).
This is modular exponentiation, so all the parameters must be
integers.

The exponent can also be negative (set it to -1 to calculate the
multiplicative inverse of base).

This library also exports a few well known modular exponential (MODP)
Diffie-Hellman groups (generators and primes) that have been defined
by Internet RFCs. They are named modp-groupN-g (generator) and
modp-groupN-p (prime) where N is the number of the group. Groups 1, 2,
5, 14, 15, 16, 17 and 18 are currently exported. They all have
different lengths and longer primes are more secure but also slower.
See RFC 3526 for more on this.
Version history:

2.3.7 Digital Signature Algorithm

The (weinholt crypto dsa) library provides procedures for
creating and verifying DSA signatures. DSA is a public key signature
algorithm, which means that it uses private and public key pairs. With
a private key you can create a signature that can then be verified by
someone using the corresponding public key. The idea is that it's very
difficult to create a correct signature without having access to the
private key, so if the signature can be verified it must have been
made by someone who has access to the private key.

Returns a DSA public key value. See the FIPS standard for a
description of the parameters.

To access the fields use dsa-public-key-p,
dsa-public-key-q, dsa-public-key-g and
dsa-public-key-y.

— Procedure: dsa-public-key? obj

True if obj is a DSA public key value.

— Procedure: dsa-public-key-length key

Returns the number of bits in the p value of key. This is
often considered to be the length of the key. The bitwise-length of
q is also important, it corresponds with the length of the
hashes used for signatures.

— Procedure: make-dsa-private-key p q g y x

Returns a DSA private key value. See the FIPS standard for a
description of the parameters.

To access the fields use dsa-private-key-p,
dsa-private-key-q, dsa-private-key-g,
dsa-private-key-y and dsa-private-key-x.

— Procedure: dsa-private-key? obj

Returns #t if obj is a DSA private key.

— Procedure: dsa-private->public private-key

Converts a private DSA key into a public DSA key by removing the
private fields.

— Procedure: dsa-private-key-from-bytevector bv

Parses bv as an ASN.1 DER encoded private DSA key.

— Procedure: dsa-private-key-from-pem-file filename

Opens the file and reads a private DSA key. The file should be in
Privacy Enhanced Mail (PEM) format and contain an ASN.1 DER encoded
private DSA key.

Encrypted keys are currently not supported.

— Procedure: dsa-signature-from-bytevector bv

Parses the bytevector bv as an ASN.1 DER encoded DSA signature.
The return value is a list with the r and s values that
make up a DSA signature.

— Procedure: dsa-create-signature hash private-key

The hash is the message digest (as a bytevector) of the data you
want to sign. The hash and the private-key are used to
create a signature which is returned as two values: r and
s.

The hash can e.g. be an SHA-1 message digest. Such a digest is
160 bits and the q parameter should then be 160 bits.

— Procedure: dsa-verify-signature hash public-key r s

The hash is the message digest (as a bytevector) of the data
which the signature is signing.

2.3.9 Elliptic Curve Digital Signature Algorithm (ECDSA)

The (weinholt crypto ec dsa) library builds on the
(weinholt crypto ec) library and provides an interface similar
to (weinholt crypto dsa). The keys and the operations are
defined to work with elliptic curves instead of modular
exponentiation.

— Procedure: make-ecdsa-public-key elliptic-curve Q

Constructs an ECDSA public key object. Q is a point on
elliptic-curve. Q is only checked to be on the curve if it
is in bytevector format.

— Procedure: ecdsa-public-key? obj

Returns #t if obj is an ECDSA public key object.

— Procedure: ecdsa-public-key-curve ecdsa-public-key

Returns the curve that ecdsa-public-key uses.

— Procedure: ecdsa-public-key-Q ecdsa-public-key

The point on the curve that defines ecdsa-public-key.

— Procedure: ecdsa-public-key-length ecdsa-public-key

The bitwise length of the ECDSA public key ecdsa-public-key.

— Procedure: make-ecdsa-private-key elliptic-curve [d Q]

Constructs an ECDSA private key object. d is a secret
multiplier, which gives a public point Q on
elliptic-curve.

If Q is omitted it is recomputed based on d and the curve.
If d is omitted a random multiplier is chosen. Please note the
warning about entropy at the start of this section. See crypto.

— Procedure: ecdsa-private-key? obj

Returns #t if obj is an ECDSA private key object.

— Procedure: ecdsa-private-key-d ecdsa-private-key

The secret multiplier of ecdsa-private-key.

— Procedure: ecdsa-private-key-Q ecdsa-private-key

The public point of ecdsa-private-key.

— Procedure: ecdsa-private->public ecdsa-private-key

Strips ecdsa-private-key of the secret multiplier and returns an
ECDSA public key object.

— Procedure: ecdsa-private-key-from-bytevector bytevector

Parses bytevector as an ECDSA private key encoded in RFC 5915
format. A curve identifier is encoded along with the key. Currently
only the curves secp256r1, secp384r1 and secp521r1 are supported.

— Procedure: ecdsa-verify-signature hash ecdsa-public-key r s

Returns #t if the signature (r,s) was made by the
private key corresponding to ecdsa-public-key. The bytevector
hash is the message digest that was signed.

— Procedure: ecdsa-create-signature hash ecdsa-private-key

Creates a signature of the bytevector hash using
ecdsa-private-key. Returns the values r and s.

ECDSA keys are normally defined to work together with some particular
message digest algorithm. RFC 5656 defines ECDSA with SHA-2 and this
library provides the record types ecdsa-sha-2-public-key and
ecdsa-sha-2-private-key so that keys defined to work with SHA-2
can be distinguished from other keys. Keys of this type are still
usable for operations that expect the normal ECDSA key types.

— Procedure: make-ecdsa-sha-2-public-key elliptic-curve Q

Performs the same function as make-ecdsa-public-key, but the
returned key is marked to be used with SHA-2.

— Procedure: ecdsa-sha-2-public-key? obj

Returns #t if obj is an ECDSA public key marked to be
used with SHA-2.

— Procedure: make-ecdsa-sha-2-private-key

Performs the same function as make-ecdsa-private-key, but the
returned key is marked to be used with SHA-2.

— Procedure: ecdsa-sha-2-private-key?

Returns #t if obj is an ECDSA private key marked to be
used with SHA-2.

The bytevector message is hashed with the appropriate message
digest algorithm (see RFC 5656) and the signature (r,s) is
then verified. Returns #t if the signature was made with the
private key corresponding to ecdsa-sha2-public-key.

2.3.11 Message-Digest algorithm 5

The (weinholt crypto md5) library is an implementation of the
cryptographic hash function MD5. It takes bytes as input and returns a
message digest, which is like a one-way summary of the data. The
idea is that even the smallest change in the data should produce a
completely different digest, and it should be difficult to find
different data that has the same digest. An MD5 digest is 16 bytes.

MD5 has a maximum message size of 2^64-1 bits.

The MD5 algorithm is considered broken and you will likely want to use
SHA-2 instead, if possible.

— Procedure: md5 bv ...

The complete all-in-one procedure to calculate the MD5 message digest
of all the given bytevectors in order. Returns an md5 state, which
should be used with md5->bytevector or md5->string.

Returns a new MD5 state for use with the procedures below. The type of
the return value is unspecified.

— Procedure: md5-update! md5state bv [start end]

Updates the md5state to include the specified range of data from
bv.

— Procedure: md5-finish! md5state

Finalizes the md5state. This must be used after the last call to
md5-update!.

— Procedure: md5-clear! md5state

Clear the md5state so that it does not contain any part of the
input data or the message digest.

— Procedure: md5-copy md5state

Make a copy of the md5state.

— Procedure: md5-finish md5state

Performs md5-finish! on a copy of md5state and then
returns the new state.

— Procedure: md5-copy-hash! md5state bv offset

Copies the message digest (a.k.a. hash) in the finalized
md5state into bv at the given offset.

— Procedure: md5-96-copy-hash! md5state bv offset

Like md5-copy-hash!, but only copies the leftmost 96 bits.

— Procedure: md5->bytevector md5state

Returns a new bytevector which contains a binary representation of the
finalized md5state.

— Procedure: md5->string md5state

Returns a new string which contains a textual representation of the
finalized md5state. The conventional hexadecimal representation
is used.

— Procedure: md5-hash=? md5state bv

Compares the finalized md5state with the leading bytes of
bv. The comparison is designed to take the same amount of time
regardless of where any differences may be. This may be important for
networked programs that would otherwise be vulnerable to timing
attacks.

— Procedure: md5-96-hash=? md5state bv

Like md5-hash=? except it only compares the leftmost 96 bits.

— Procedure: hmac-md5 secret bytevector ...

An HMAC is a Hash-based Message Authentication Code. This procedure uses
MD5 to generate such a code. The return value is an MD5 state.

2.3.12 OpenPGP signature verification

The (weinholt crypto openpgp) library provides procedures for
reading OpenPGP keyrings and verifying signatures. OpenPGP signatures
can be created with e.g. GNU Private Guard (GnuPG) and are often
used to verify the integrity of software releases.

Version 4 keys and version 3/4 signatures are supported. The
implemented public key algorithms are RSA and DSA, and it verifies
signatures made using the message digest algorithms MD5, SHA-1,
SHA-224, SHA-256, SHA-384 and SHA-512 (all the standard algorithms
except RIPE-MD160).

An OpenPGP key is actually a list of OpenPGP packets with a certain
structure: first is the primary key (e.g. an RSA or DSA key), next
possibly a revocation, then a number of user IDs, attributes,
signatures and also subkeys (which are just like primary keys, except
marked as subkeys). See RFC 4880 section 11 for the exact composition.
This library represents keyrings as hashtables indexed by key ID and
where the entries are lists of packets in the order they appeared in
the keyring file.

Please note that this library assumes the program that wrote the
keyring did due diligence when importing keys, and made sure that
e.g. subkey binding signatures are verified, and that the order of
packets is correct.

— Procedure: port-ascii-armored? port

Returns false if the data at the beginning of port doesn't look
like a valid binary OpenPGP packet. The port must be a binary input
port. The port position is not changed.

— Procedure: get-openpgp-packet port

Reads an OpenPGP packet from port, which must be a binary input
port. An error is raised if the packet type is unimplemented.

— Procedure: get-openpgp-keyring p

Reads a keyring from the binary input port p. Returns a
hashtable where all primary keys and subkeys are indexed by their key
ID (an integer). The values in the hashtable are lists that contain
all OpenPGP packets associated with each key. No effort at all is made
to verify that keys have valid signatures.

Warning: this can take a while if the keyring is very big.

— Procedure: get-openpgp-keyring/keyid p keyid

Searches the binary input port p for the public key with the
given keyid. Returns a hashtable similar to
get-openpgp-keyring, except it will only contain the primary
and subkeys associated with the keyid.

The keyid can be either a 64 or 32 bit exact integer.

Warning: this is faster than get-openpgp-keyring, but is still rather
slow with big keyrings. The speed depends on the SHA-1 implementation.

— Procedure: get-openpgp-detached-signature/ascii p

Reads a detached OpenPGP signature from the textual input port
p. Returns either an OpenPGP signature object or the end of file
object.

These signatures can be created with e.g. gpg -a --detach-sign filename.

— Procedure: verify-openpgp-signature sig keyring p

Verifies the signature data in sig. The keyring hashtable
is used to find the public key of the signature issuer. The signed
data is read from the binary input port p.

This procedure returns two values. These are the possible
combinations:

good-signature key-data – The signature matches
the data. The key-data contains the public key list that was
used to verify the signature.

bad-signature key-data – The signature does not
match the data. The key-data is the same as above.

missing-key key-id – The issuer public key for the
signature was not found in the keyring. The key-id is the
64-bit key ID of the issuer.

— Procedure: openpgp-signature? obj

True if obj is an OpenPGP signature object. Such objects are
read with get-openpgp-detached-signature/ascii and are also
contained in keyring entries.

— Procedure: openpgp-signature-issuer sig

The 64-bit key ID of the OpenPGP public key that issued the
signature sig.

— Procedure: openpgp-signature-public-key-algorithm sig

Returns the name of the public key algorithm used to create the
signature sig. This is currently the symbol dsa or
rsa.

— Procedure: openpgp-signature-hash-algorithm sig

The name of the message digest algorithm used to create the
signature sig. This is currently one of md5,
sha-1, ripe-md160 (unsupported), sha-224,
sha-256, sha-384 or sha-512.

— Procedure: openpgp-signature-creation-time sig

An SRFI-19 date object representing the time at which the signature
sig was created.

— Procedure: openpgp-signature-expiration-time sig

An SRFI-19 date object representing the time at which the signature
sig expires. Returns #f if there's no expiration time.

— Procedure: openpgp-user-id? obj

True if obj is an OpenPGP user id.

— Procedure: openpgp-user-id-value user-id

The string value of the user-id. This is often the name of the
person who owns the key.

— Procedure: openpgp-user-attribute? obj

True if obj is an OpenPGP user attribute. Attributes are used to
encode JPEG images. There's currently no way to access the image.

— Procedure: openpgp-public-key? obj

True if obj is an OpenPGP primary key or subkey.

— Procedure: openpgp-public-key-subkey? key

True if obj is a subkey.

— Procedure: openpgp-public-key-value key

The DSA or RSA public key contained in the OpenPGP public key.
The value returned has the same type as the (crypto weinholt
dsa) or (crypto weinholt rsa).

— Procedure: openpgp-public-key-fingerprint key

The fingerprint of the OpenPGP public key as a bytevector. This
is an SHA-1 digest based on the public key values.

— Procedure: openpgp-format-fingerprint bv

Formats the bytevector bv, which was presumably created by
openpgp-public-key-fingerprint, as a string in the format
preferred for PGP public key fingerprints.

2.3.13 Password hashing

The procedure provided by (weinholt crypto password) is the
same type of procedure that is called crypt in the standard C
library. It is used for password hashing, i.e. it scrambles
passwords. This is a method often used when passwords need to be
stored in databases.

The scrambling algorithms are based on cryptographic primitives but
have been modified so that they take more time to compute. They also
happen to be quite annoying to implement.

Only DES and MD5 based hashes are currently supported.

— Procedure: crypt password salt

Scrambles a password using the given salt. The salt
can also be a hash. The returned hash will be prefixed by the salt.

A fresh random salt should be used when hashing a new password. The
purpose of the salt is to make it infeasible to reverse the hash
using lookup tables.

To verify that a password matches a hash, you can do something like
(string=? hash (crypt password hash)).

This performs the same function as rsa-decrypt, but it uses RSA
blinding. It has been shown that the private key can be recovered by
measuring the time it takes to run the RSA decryption function. Use
RSA blinding to protect against these timing attacks.

It is often not enough to just use the plain encryption and decryption
procedures; a protocol for what to put in the plaintext should also be
used. PKCS #1 (RFC 3447) is a standard for how to perform RSA
encryption and signing with padding. New protocols should use one of
the other protocols from the RFC.

— Procedure: rsa-pkcs1-encrypt plaintext public-key

Pads and encrypts the plaintext bytevector using
public-key, a public RSA key. The return value is an integer.

The plaintext can't be longer than the length of the key modulus, in
bytes, minus 11.

— Procedure: rsa-pkcs1-decrypt ciphertext private-key

The inverse of rsa-pkcs1-encrypt. Decrypts the ciphertext
integer using private-key, a private RSA key. The padding is
then checked for correctness and removed.

Decrypts the signature (a bytevector) contained in the signature
integer by using the public-key. The signature initially
contains PKCS #1 padding, but this is removed.

— Procedure: rsa-pkcs1-decrypt-digest signature public-key

This performs the same operation as
rsa-pkcs1-decrypt-signature, except it then treats the
decrypted signature as a DER encoded DigestInfo. The return value is a
list containing a digest algorithm specifier and a digest.

2.3.16 Secure Hash Algorithm 2

The interface provided by (weinholt crypto sha-2) is identical
to the one provided by the MD5 library, but instead of md5,
every procedure is prefixed by sha-224, sha-256,
sha-384 or sha-512. In addition the procedures that
operate on the leftmost 96 bits are instead defined for the leftmost
128 bits (e.g. sha-512-128-hash=?). See crypto md5.

SHA-224 and SHA-256 have a maximum message size of 2^64-1
bits. For SHA-384 and SHA-512 the maximum is 2^128-1 bits.
The message digests produced by SHA-224 are 224 bits, and so on.
Version history:

(0 0) – Initial version.

(1 1) – Added sha-224-length, sha-256-length,
sha-384-length, sha-512-length that return the length of
a digest in bytes. Added the comparison predicates
sha-224-hash=?, sha-256-hash=?, sha-384-hash=?sha-512-hash=? that run in constant time. Added procedures for
truncated digests: sha-224-128-hash=?,
sha-256-128-hash=?, sha-384-128-hash=?sha-512-128-hash=?, sha-224-128-copy-hash!,
sha-256-128-copy-hash!, sha-384-128-copy-hash! and
sha-512-128-copy-hash!. Now uses the correct definition of
HMAC-SHA-384 and HMAC-SHA-512. The HMACs now also handle key lengths
larger than the block size.

2.3.17 SSH public key format conversion

Use (weinholt crypto ssh-public-key) to convert public RSA,
DSA, and ECDSA keys from records to the binary SSH public key format,
and the other way around. SSH is the name of a network protocol for
secure terminal connections defined by RFCs 4250-4254. The key format
is specified by RFC 4716. ECDSA keys are specified by RFC 5656.

The types used for RSA, DSA and ECDSA keys in this library are the
same types used elsewhere. The ECDSA keys must have the record type
ecdsa-sha-2-public-key.

Future work would be to implement parsing of the various textual
formats that contain Base64 public SSH keys.

— Procedure: get-ssh-public-key p

Reads a public RSA/DSA/ECDSA key encoded in the SSH public key format
from the binary input port p.

— Procedure: ssh-public-key->bytevector key

Converts the public RSA/DSA/ECDSA key to the SSH public key
format.

— Procedure: ssh-public-key-algorithm key

Returns the SSH algorithm identifier of key. For RSA keys this
is "ssh-rsa", for DSA keys it is "ssh-dss", and for
ECDSA keys it is "ecdsa-sha2-[identifier]" where
[identifier] identifies the curve.

— Procedure: ssh-public-key-fingerprint key

The MD5 based fingerprint of the RSA/DSA/ECDSA key in the same
format used by common SSH software and specified by RFC 4716.

— Procedure: ssh-public-key-random-art key

The random art of the RSA/DSA/ECDSA key. This is a visual
representation of the key can is easier for humans to distinguish than
fingerprints. This is the same art that OpenSSH's VisualHostKey
feature displays.

2.3.18 X.509 Public-Key Infrastructure

An X.509 certificate is a data structure that contains a public RSA or
DSA key and some identifying information. There is a subject
and an issuer (and lots of details). The subject specifies who
the certificate belongs to, and the issuer specifies who signed it.
Certificate path validation is used to get from a trusted issuer to
the subject, often via several intermediates.
X.509 certificates are used in many places, e.g. TLS, S/MIME email
and IPsec.

— Procedure: certificate? obj

True if obj is an X.509 certificate.

— Procedure: certificate-from-bytevector bv [start end]

Reads an X.509 certificate from the bytevector bv. The
certificate is in the ASN.1 DER format customarily used for X.509
certificates. For certificates in PEM format, first read them with
get-delimited-base64. See text base64.

— Procedure: certificate-public-key certificate

Returns the public key contained in the certificate. The return
value's type is either an RSA or a DSA public key. See crypto dsa.
See crypto rsa.

Returns ok if the certificates in the path list form a
valid certificate path. A valid certificate path begins with a trusted
CA certificate and ends with an end entity's certificate. Each
certificate in the chain signs the next certificate. This is intended
to form a chain of trust from a certificate you already trust (the CA
certificate) to a new certificate, the end entity's certificate.

Optionally a common-name string can be given. This is normally a
good idea. If you've tried to connect to a service at the domain name
example.com, you might like to know that the certificate it presents
actually belongs to example.com. Both the common name and
subjectAltName fields of the certificate are checked. Currently only
tested with domain names.

An SRFI-19 time can also optionally be given, in which case it
is used instead of the system's current time.

If the optional CA-cert argument is given it is a trusted
certificate that will be used to validate the start of the path. If
this argument is given then no other trusted certificates will be
tried.

— Parameter: CA-path

— Parameter: CA-file

— Parameter: CA-procedure

These SRFI-39 parameters can be used to provide the
validate-certificate-path procedure with trusted Certificate
Authority (CA) certificates, also known as root certificates. It is
beyond the scope of this library collection to provide you with
trusted certificates. Many operating systems have such collections,
e.g. Debian's ca-certificates package. Technically, a CA certificate
is a self-issued certificate with correctly set “basic constraints”
and “key usage” attributes.
The CA-path parameter should be the name (ending in the path
separator character, if any) of a directory containing files named by
OpenSSL's c_rehash program. The files contain PEM encoded CA
certificates. The filenames are partially a hash which also can be
retrieved from the name-hash value in the issuer/subject
alists. Default: "/etc/ssl/certs/".

The CA-file parameter is not yet implemented. In the future
this will be the name of a file which contains trusted certificates.
Default: "/etc/ssl/certs/ca-certificates.crt".

The CA-procedure parameter is a procedure which takes a single
argument: an issuer alist. If you have the requested certificate,
return it. Otherwise return #f. For forward compatibility the
procedure should accept any number of arguments.
Default: (lambda (issuer . _) #f)

The following part of the library is for more advanced uses.

— Procedure: certificate-key-usage certificate

Returns the keyUsage extension data from certificate. If the
extension is absent then the return value is #f. Otherwise it
is a list in which the possible entries are: digitalSignature,
nonRepudiation, keyEncipherment,
dataEncipherment, keyAgreement, keyCertSign,
cRLSign, encipherOnly, and decipherOnly. See
RFC 5280 for an explanation of their meaning. If you are
implementing a protocol where keyUsage is important, the specification
will probably mention it.

— Procedure: certificate-tbs-data certificate

Returns the To Be Signed (TBS) part of certificate as a DER
encoded bytevector. Except for the certificate's signature, the whole
certificate is contained in the TBS data.

— Procedure: decipher-certificate-signature subject-cert issuer-cert

Uses the public key of issuer-cert to decipher the signature on
subject-cert.

2.4 Machine code disassemblers

All disassemblers provided here use the same method of signalling
undefined/invalid opcodes. The following procedure can be used to
guard against such errors:

— Procedure: invalid-opcode? obj

When an invalid opcode is encountered an exception with the
&invalid-opcode condition is raised. Use invalid-opcode?
to guard against it.

The disassemblers take an argument that is called a collector.
It is either #f or a procedure of the following form:
(lambda (tag . bytes) body). The tag is specific to the
architecture, but the bytes are the bytes forming the instruction.
The procedure is used to tell the caller what function each byte of
an instruction performs. This works best for architectures that use
variable-length instructions. For most instructions there will be
multiple calls to the collector.

2.4.1 Intel 8080/8085 disassembler

The (weinholt disassembler i8080) library provides a
disassembler for the Intel 8080 architecture. It was an 8-bit
architecture used in many micros and even the DEC VT100. It was also
the predecessor of the Intel 8086.

— Procedure: get-instruction binary-input-port collector

Reads one instruction from the binary-input-port and returns it
in symbolic form. For a description of the collector,
see disassembler.

2.4.2 Freescale 68HC12 disassembler

The (weinholt disassembler m68hc12) library provides a
disassembler for the Freescale 68HC12 architecture (formerly Motorola
68HC12 and sometimes called 68HCS12, HC12 or CPU12). It is a 16-bit
architecture used in microcontrollers.

— Procedure: get-instruction binary-input-port collector

Reads one instruction from the binary-input-port and returns it
in symbolic form. For a description of the collector,
see disassembler.

2.4.3 MIPS II disassembler

The (weinholt disassembler mips) library provides a
disassembler for most 32-bit MIPS II instructions. MIPS is a RISC
architecture and all instructions have the same length.

— Procedure: get-instruction binary-input-port endianness collector

Disassembles one instruction from the binary-input-port and
returns it in symbolic form. The endianness specifies if
instructions are read in big or little endianness. For a description
of the collector, see disassembler.

2.4.4 Intel x86-16/32/64 disassembler

The (weinholt disassembler x86) library is a disassembler for
the Intel x86 architecture. It supports 16-bit, 32-bit and 64-bit
modes as well as most modern instruction encodings, including the VEX
prefix used by Intel AVX.

The disassembler does not keep track of the instruction pointer, so
relative offsets are returned as they appear in the instruction
encoding. If you wish to show the destination for branches, or the
actual offset for AMD64's RIP-relative addressing, you will need to
compute the offset yourself.

— Procedure: get-instruction binary-input-port mode collector

Reads a single instruction from the given binary-input-port. The
mode is one of 16, 32 or 64 (which roughly correspond to real,
protected and long mode).

The collector is either #f or a procedure that takes a
symbolic tag and a variable number of bytes. The tag is one of the
symbols modr/m, sib, disp, immediate,
/is4, prefix and opcode. The x86 instruction set
uses variable length instructions (of up to 15 bytes) and the
collector procedure can be used to find out the type of data
each byte of an instruction contains.

The returned instructions have the same operand order as Intel's
documentation uses, i.e. the left operand is the destination.

2.5.1 Internet Relay Chat

The (weinholt net irc) library provides low-level procedures
for parsing and formatting IRC protocol commands. It makes it easy to
split incoming commands into parts and to format outgoing commands.
There are also helpers for various other parsing needs.

The IRC protocol is standardized by RFCs 2810-2813, but servers very
often (always?) disregard the RFCs. They do provide good guidelines
for what should work.

— Procedure: parse-message message [remote-server]

This procedure splits an IRC message into three parts: prefix,
command and a list of arguments. The command is either a symbol or a
number. If the message does not have a prefix the remote-server
argument will be used instead, because it is implied by the protocol.

This procedure does the same thing parse-message does, except
it works on bytevectors. This is useful because the IRC protocol does
not have a standard character encoding. Different channels on IRC
often use different encodings.

— Procedure: format-message-raw port codec prefix cmd parameters ...

Formats and outputs an IRC message to the given port, which must
be in binary mode.

The codec is a codec, meaning the value returned by e.g.
utf-8-codec or latin-1-codec. The codec is used to
transcode the parameters.

The prefix is the name of the server or client that originated
the message. IRC clients should use #f as prefix when sending
to a server.

The cmd is a symbol or string representing an IRC command, but
it can also be an integer (which must be be between 000 and 999). Only
servers send numerical commands.

The rest of the arguments are the parameters for the given
command, which can be either numbers, strings or bytevectors. Only the
last of the parameters may contain whitespace. The maximum number of
parameters allowed by the protocol is 15. Each IRC protocol command
takes a pre-defined number of parameters, so e.g. if cmd is
PRIVMSG then you must only pass two parameters.

This procedure works just like format-message-raw, except before
writing the message it parses the formatted message and compares it
with the input to make sure it is the same. This prevents some attacks
against IRC bots.

This example shows what happens when a parameter contains a newline,
which is a common attack against bots. The command after the newline
would be sent to the server, and the bot would exit all channels.
Instead an exception is raised:

Compares str1 and str2 for equality. The comparison is
case-insensitive and uses the specified mapping to compare
characters. This procedure is useful for comparing nicknames.

The mapping should be one of rfc1459, ascii or
strict-rfc1459. Servers indicate in the CASEMAPPING
ISUPPORT parameter which mapping they use.

The first IRC servers used Swedish ASCII for nicknames, so the
nicknames sm|rg}s and SM\RG]S are equivalent on some servers.

— Procedure: string-upcase-irc str mapping

Upcases str using the given case mapping.

— Procedure: string-downcase-irc str mapping

Downcases str using the given case mapping.

— Procedure: ctcp-message? str

Returns #t if the str represents a CTCP message. This is
currently the extent of this library's CTCP support. CTCP is used for
sending files, opening direct connections between clients, checking
client versions, asking for the time, pinging clients, doing
“action” style messages, and some other stuff.

— Procedure: irc-match? pattern input

Returns #t if the pattern, which can contain wildcards,
matches the input. Otherwise returns #f. Strings
containing wildcards are called masks, and they are used in
e.g. channel ban lists.

The pattern follows the syntax specified in section 2.5 of RFC2812. A
#\* matches zero or more characters and #\? matches any
single character. The comparison is case-insensitive. Wildcard
characters can be escaped with #\\.

Uses the ISUPPORT data in prefix and chanmodes to
parse a MODE command for a channel. The target is not included
in the mode-list. To keep track of changes to who is op'd and
voice'd (and half-op'd) you can use this procedure together with the
server's ISUPPORT PREFIX data.

2.5.2 Blowcrypt/FiSH encryption for IRC

The (weinholt net irc fish) library provides procedures for
interacting with IRC clients that use Blowcrypt/FiSH encryption.
Messages are encrypted with Blowfish in ECB mode and then encoded with
a peculiar base64 encoding. Keys can be exchanged with Diffie-Hellman
(vulnerable to middleman attacks) or they can be pre-shared. FiSH is
useful if you want to draw attention to your communications.

There is currently no way to initialize key-exchange.

Blowcrypt/FiSH supports both private messages and public channels. If
you only need private messages then OTR provides a much better
protocol. See net otr.

— Procedure: fish-message? str

Returns #f is the string is not a FiSH message.

— Procedure: fish-decrypt-message msg key

Decrypts a FiSH message. The msg is the line that the remote
client sent to you.

— Procedure: fish-encrypt-message msg key

Encrypts the string msg with FiSH encryption. Returns a string
containing the plaintext. There is no verification that the key was
correct and the returned string might be garbage.

— Procedure: fish-key-init? str

Returns #f is str is not a FiSH key-exchange
initialization request.

— Procedure: fish-generate-key init-msg

Finishes the DH1080 key-exchange request contained in init-msg.
Returns two values: the newly generated key and a response for the
remote client. There is no protection against middleman attacks.

— Procedure: make-fish-key str

The str is expanded and can then be used with
fish-decrypt-message and fish-encrypt-message.

2.5.3 Off-the-Record Messaging

The (weinholt net otr) library provides Off-the-Record
Messaging (OTR), which is a security protocol for private chat. It can
be tunneled over any protocol that guarantees in-order delivery
(e.g. IRC or XMPP). It provides encryption, authentication,
deniability and perfect forward secrecy.

This library does not manage user identities, which is something the
OTR Development Team's C library does. This choice was made to keep
the implementation simple and focused on the protocol only.

Returns #t if str, which is a message from a remote
party, contains an OTR message. If it is an OTR message you should
look up the OTR state that corresponds to the remote party (possibly
make a new state) and call otr-update!.

— Procedure: make-otr-state dsa-key mss [instance-tag [versions]]

Creates an OTR state value given the private DSA key dsa-key and
a maximum segment size mss. The state is used to keep track of
session keys and incoming message fragments.

The dsa-key must have a 160-bit q-parameter because of details
in the protocol and limitations of other implementations. A 1024-bit
DSA key will work. See crypto dsa.

The maximum segment size mss is used to split long OTR messages
into smaller parts when OTR is used over a protocol with a maximum
message size, e.g. IRC.

If an instance-tag is specified it must be a 32-bit integer not
less than #x100. If it is omitted or #f an instance tag
will be randomly generated. OTR version 3 uses the instance tags to
identify which OTR state messages belongs to. Be sure to read the
documentation for otr-state-our-instance-tag. New for Industria
1.5.

If versions is not omitted it must be a list of acceptable OTR
protocol versions. The default is (2 3). New for Industria 1.5.

— Procedure: otr-update! state str

Processes the str message, which came from the remote party,
and updates the state. Use otr-empty-queue! to retrieve
scheduled events.

— Procedure: otr-send-encrypted! state msg

This is used to send a message to the remote party. It encrypts and
enqueues the msg bytevector and updates the state.
Use otr-empty-queue! to retrieve the encrypted and formatted
messages that should be sent to the remote party.

The msg must not contain a NUL (0) byte.

— Procedure: otr-authenticate! state secret [question]

Initiate or respond to an authentication request.
After calling this procedure you should use otr-empty-queue!,
just like with otr-send-encrypted!.

The authentication protocol can be used to verify that both partyies
know the secret bytevector. The secret is never revealed over
the network and is not even transmitted in an encrypted form. The
protocol used is the Socialist Millionaires' Protocol (SMP), which is
based on a series of zero-knowledge proofs.

— Procedure: otr-empty-queue! state

Returns and clears the event queue. The queue is a list of pairs where
the symbol in the car of the pair determines its meaning. These
are the possible types:

(outgoing . line) – The cdr is a string
that should be sent to the remote party.

(encrypted . msg) – The cdr is a string
that contains a decrypted message that was sent by the remote party.

(unencrypted . msg) – The cdr is a string that
was sent unencrypted by the remote party. This happens when a
whitespace-tagged message is received.

(session-established . whence) – A session has been
established with the remote party. It is now safe to call
otr-state-their-dsa-key, otr-state-secure-session-id,
otr-send-encrypted! and otr-authenticate!. The
cdr is the symbol from-there if the session was
initiated by the remote party. Otherwise it is from-here.

(session-finished . whom) – The session is now
finished and no new messages can be sent over it. The cdr is
either the symbol by-them or by-us. Note: there
is currently no way to finish the session from the local side, so
by-us is not used yet.

(authentication . expecting-secret) – The remote party has
started the authentication protocol and now expects you to
call otr-authenticate!.

(authentication . #t) – The authentication protocol has
succeeded and both parties had the same secret.

(authentication . #f) – The authentication protocol has
failed. The secrets were not identical.

(authentication . aborted-by-them) – The remote party
has aborted the authentication protocol.

(authentication . aborted-by-us) – The local party has
encountered an error and therefore aborted the authentication
protocol.

(they-revealed . k) – The remote party revealed an old
signing key. This is a normal part of the protocol and the key is sent
unencrypted to ensure the deniability property. You might like to
reveal the key somehow yourself in case you're tunneling OTR over an
encrypted protocol.

(we-revealed . k) – The local party has revealed an
old signing key. Note: currently not used.

(undecipherable-message . #f) – An encrypted message was
received, but it was not possible to decrypt it. This might mean
e.g. that the remote and local parties have different sessions or
that a message was sent out of order.

(remote-error . msg) – The remote party encountered a
protocol error and sent a plaintext error message (probably in
English).

(local-error . con) – There was an exception raised
during processing of a message. The cdr is the condition object.

(symmetric-key-request . (protocol . data))
– The remote party has requested that the extra symmetric
key be used to communicate in some out-of-band protocol. See
otr-send-symmetric-key-request!. New for Industria 1.5.

For forward-compatibility you should ignore any pair with an unknown
car. Most messages are quite safe to ignore if you don't want
to handle them.

— Procedure: otr-state-their-dsa-key state

Returns the remote party's public DSA key. This should be used to
verify the remote party's identity. If the SMP authentication protocol
succeeds you can remember the hash of the key for the next session.
The user could also verify the key's hash by cell phone telephone or
something.

— Procedure: otr-state-our-dsa-key state

Returns the local party's private DSA key. This is useful when the
user is on the phone with the remote party. First convert it to a
public key with dsa-private->public and then hash it with
otr-hash-public-key.

— Procedure: otr-hash-public-key public-dsa-key

Hashes a public DSA key and formats it so that it can be shown to the
OTR user.

— Procedure: otr-state-secure-session-id state

Returns the secure session ID associated with the OTR state.

— Procedure: otr-format-session-id id

Formats a secure session ID in the format that is recommended when
the ID should be shown to the OTR user.

The first part of the ID should be shown in bold if the session was
initiated by the local party. Otherwise the second part should be bold.

— Procedure: otr-state-version state

The OTR protocol version used by the state. This is either the integer
2 or the integer 3. New for Industria 1.5.

— Procedure: otr-state-mss state

Returns the current maximum segment size of the OTR state.

— Procedure: otr-state-mss-set! state int

Sets int as the maximum segment size of the OTR state.

OTR protocol version 3 defines an extra symmetric key.

— Procedure: otr-send-symmetric-key-request! state protocol data

This sends a message to the remote party that requests that it uses
the extra symmetric key for some out-of-band protocol.

The remote party may ignore this request if the OTR protocol version
(as returned by otr-state-version) is not at least 3.

The protocol parameter is an unsigned 32-bit integer that
indicates what the key should be used for. At the time this manual is
written there are no defined uses. One might expect a list of uses to
appear in the protocol documentation at
http://www.cypherpunks.ca/otr/.

The data parameter is a bytevector containing protocol-dependent
data.

— Procedure: otr-state-symmetric-key state

This returns the extra symmetric key in the form of a 256-bit bytevector.

— Procedure: otr-tag whitespace? versions

Constructs a string that may be sent to a remote party as a request to
start an OTR session. New for Industria 1.5.

If whitespace? is true then a whitespace tag will be made. This
tag may be appended to a normal message sent by the user. If the
recipient's client supports OTR it may start a session, but if it does
not support OTR then hopefully it will not show the whitespaces.

The versions argument specifies which OTR protocol versions
should be present in the tag. This can either be a list of version
numbers or the symbol all.

— Procedure: otr-state-our-instance-tag state

This returns the local instance tag. It is new for Industria 1.5.

It is intended for instance tags to be persistent across client
restarts. If the local party crashes then the remote party may still
have an OTR session established. If the local client were then to
change its instance tag on restart it would not receive any messages
from the remote party and would not send error messages. To the remote
party it would look like they were being ignored.

Isn't this the most boring manual you've ever read?

Version history:

Industria 1.5 introduced support for protocol version 3. This new
version of the protocol uses instance tags, which are used to
distinguish between different OTR sessions. This fixes a problem with
chat networks that allow multiple logins. The new version also defines
an extra symmetrical key that can be used by out-of-band protocols.

2.5.4 Secure Shell (SSH)

The (weinholt net ssh) library hierarchy deals with the Secure
Shell protocol. Both SSH servers and clients can be written with these
libraries. Some convenient abstractions are currently missing though,
e.g. a channel abstraction. These libraries hide the details of the
wire protocol and the cryptographic algorithms. The protocol is
standardized by a series of RFCs: 4250, 4251, 4252, 4253, 4254, etc.

No TCP server abstraction is provided by Industria. To make a server
you will probably need to use your implementation's network
abstractions.

It remains to be seen if this interface can be used for interactive
applications. One problem is get-ssh, which reads a whole SSH
packet. This procedure is blocking. R6RS doesn't provide any
procedures for event-driven programming, so the author has made no
effort to make this library work in an event-driven setting.

This SRFI-39 parameter controls debug output. It is a bit field with
three bits currently defined. Bit 0 enables general trace messages,
bit 1 enables packet traces and bit 2 enables packet hexdumps.

Default: #b000

— Parameter: ssh-debugging-port

This SRFI-39 parameter controls where debug output is written to. It
defaults to the error port that was current when the library top-level
was run.

— Parameter: identification-protocol-version

This SRFI-39 parameter is used when constructing the local
identification string. It specifies which SSH protocol version number
is supported.

Default: "2.0"

— Parameter: identification-software-version

This SRFI-39 parameter is used when constructing the local
identification string. It specifies the name and version of the client
or server.

Default: "Industria_1"

— Parameter: identification-comments

This SRFI-39 parameter is used when constructing the local
identification string. It is #f or optionally a string of
comments. This field is sometimes used to identify a vendor.

Default: #f

The following parameters are when constructing the local kex exchange
packet. It lists the preferred algorithms. You may remove and reorder
the algorithms, but you can't introduce new ones without first adding
them to (weinholt net ssh algorithms). The defaults may change
in the future.

— Parameter: preferred-kex-algorithms

This is a list of key exchange algorithm names in the order they are
preferred.

Starts an SSH server connection over the two given ports, which should
be connected to a client via TCP (or some other similar means).

keys is a list of host keys. The currently supported key types
are dsa-private-key and ecdsa-sha-2-private-key.

If everything goes right an ssh-conn object is returned.
The peer identification and kexinit fields are valid.

— Procedure: ssh-key-exchange ssh-conn

This runs the negotiated key exchange algorithm on ssh-conn.
After this is done the client will have received one of the server's
public keys. The negotiated encryption and MAC algorithms will have
been activated.

— Procedure: ssh-conn-peer-identification ssh-conn

The identification string the peer sent. This is a string that
contains the peer's protocol version, software version and optionally
some comments.

— Procedure: ssh-conn-peer-kexinit ssh-conn

This is the peer's key exchange initialization (kexinit) packet. It
lists the peer's supported algorithms. See net ssh transport.

— Procedure: ssh-conn-host-key ssh-conn

The server's public key. This has unspecified contents before the
ssh-key-exchange procedure returns.

— Procedure: ssh-conn-session-id ssh-conn

The session ID of ssh-conn. This has unspecified contents before
the ssh-key-exchange procedure returns.

— Procedure: ssh-conn-registrar ssh-conn

Returns a procedure that can be used to register parsers and
formatters for SSH packet types. The returned procedure should be
given as an argument to register-connection and
register-userauth.

— Procedure: ssh-error ssh-conn who message code irritants ...

Sends a disconnect packet to the peer. The packet contains the
message and the code. The connection is then closed and an error is
raised.

Reads an SSH packet object from the peer of ssh-conn. The
end-of-file object will be returned if the peer has closed the
connection. The procedure blocks until a message has been received.
Any messages of the type ignore are ignored.

Packet types must be registered before they can be received. Initially
only the transport layer types are registered. If an unregistered type
is received this procedure returns a list of two items: the symbol
unimplemented and the unparsed contents of the packet. A packet
of type unimplemented is sent to the peer.

— Procedure: close-ssh ssh-conn

Flushes the output port of ssh-conn, and then closes both the
input and output ports.

— Procedure: flush-ssh-output ssh-conn

Flushes any pending output on ssh-conn.

The procedures below are used in the implementation of key
re-exchange. After the initial key exchange either party can initiate
a key re-exchange. RFC 4253 has the following to say on the subject:

It is RECOMMENDED that the keys be changed after each gigabyte of
transmitted data or after each hour of connection time, whichever
comes sooner. However, since the re-exchange is a public key
operation, it requires a fair amount of processing power and should
not be performed too often.

The demonstration program secsh-client contains an example of
how to initiate key re-exchange. The server demonstration program
honingsburk also handles key re-exchange, but does not initiate
it. See honingsburk.

— Procedure: build-kexinit-packet ssh-conn

Constructs and returns a key exchange packet for use by the local
side.

— Procedure: key-exchange-packet? pkt

Returns #t if pkt should be given to
process-key-exchange-packet for handling by the key exchange
logic.

— Procedure: ssh-key-re-exchange ssh-conn peer-kex local-kex

Initiates key re-exchange on ssh-conn. This requires the peer's
key exchange packet peer-kex, and the local key exchange packet
local-kex. The procedure returns before the key re-exchange is
finished. Both sides of the algorithm will need to communicate to
complete the exchange.

— Procedure: process-key-exchange-packet ssh-conn pkt

Updates the key exchange logic on ssh-conn with the contents of
pkt. If the packet is a kexinit packet and ssh-conn
is a server, then this will automatically initiate the key re-exchange
algorithm.

The procedure may return the symbol finished to indicate that
the key exchange algorithm has finished and the new algorithms are
used for packets sent to the peer.

Note: This interface is currently balanced in favor of servers.
More experience in using the library is needed to determine how to
make the key re-exchange interface better for clients. Suggestions are
welcome.

2.5.4.1 Secure Shell Connection Protocol

The (weinholt net ssh connection) library implements record
types, parsers and formatters for the connection protocol packets in
SSH.

The connection protocol handles two types of communication: global
requests and channels. The global requests can be used to setup TCP/IP
port forwarding. Most communication over SSH passes through channels.
Channels are opened with the channel-open requests. The client
and the server each assign an ID number to a channel: one ID is sent
in the channel-open packet, the other ID in the
channel-open-confirmation packet. In Industria all packets that
are directed to a specific channel inherit from the
channel-packet record type and the ID can be found with the
channel-packet-recipient procedure.

Strings and bytevectors may be used interchangeably when constructing
packets. Strings will automatically be converted with
string->utf8. When these packets are received the parser will
either parse those fields either as a string or a bytevector. A
bytevector will be used when the field can contain more or less
arbitrary data, e.g. filenames.

The text of this section uses the words “packet”, “message” and
“request” interchangeably.

See RFC 4254 for a more detailed description of this protocol.

— Procedure: register-connection registrar

Registers the packet types for the connection protocol so that they
may be received and sent. A registrar may be obtained from an ssh-conn
object using ssh-conn-registrar.

— Procedure: make-global-request type want-reply?

Constructs a global request: a connection request not related to any
channel. Some global requests contain additional fields. These
requests are represented by the global-request/* packets.

— Procedure: global-request? obj

Returns true if obj is a global-request? packet.

— Procedure: global-request-type pkt

This field contains a string identifying the type of the request,
e.g. "no-more-sessions@openssh.com".

— Procedure: global-request-want-reply? pkt

This field is true if the sender expects a request-success or
request-failure record in response.

Constructs a request that instructs the server to bind a TCP server port
and forward connections to the client.

— Procedure: global-request/tcpip-forward? obj

Returns true if obj is a global-request/tcpip-forward packet.

— Procedure: global-request/tcpip-forward-address req

This field is a string that represents the address to which the server
should bind the TCP server port. Some addresses are given special meaning:

""

The server should listen to all its addresses on all supported protocols
(IPv4, IPV6, etc).

"0.0.0.0"

The server should listen to all its IPv4 addresses.

"::"

The server should listen to all its IPv6 addresses.

"localhost"

The server should listen to its loopback addresses on all supported
protocols.

"127.0.0.1"

The server should listen to its IPv4 loopback address.

"::1"

The server should listen to its IPv6 loopback address.

— Procedure: global-request/tcpip-forward-port req

This field is an integer representing the port number to which the
server should bind the TCP server port. If the number is 0 and
want-reply? is true, the server will pick a port number and send
it to the client in a request-success packet (the port number
can be recovered with (unpack "!L" (request-success-data
response))).

Constructs a message that undoes the effect of a
global-request/tcpip-forward request.

— Procedure: global-request/cancel-tcpip-forward? obj

Returns true if obj is a global-request/cancel-tcpip-forward packet.

— Procedure: global-request/cancel-tcpip-forward-address req

See global-request/tcpip-forward-address.

— Procedure: global-request/cancel-tcpip-forward-port req

See global-request/tcpip-forward-port.

— Procedure: make-request-success data

Constructs a packet which indicates that the previous
global-request was successful.

— Procedure: request-success? obj

Returns true if obj is a request-success packet.

— Procedure: request-success-data pkt

This field contains a request-specific bytevector which is mostly
empty.

— Procedure: make-request-failure

Returns an object which indicates that a global request failed.

— Procedure: request-failure? obj

Returns true if obj is a request-failure packet.

All requests to open a channel are represented by
channel-open/* packets.

— Procedure: channel-open? obj

Returns true if obj is a channel-open packet.

— Procedure: channel-open-type pkt

A string representing the type of the channel-open request,
e.g. "session".

— Procedure: channel-open-sender pkt

This is the ID for the sender side of the channel.

— Procedure: channel-open-initial-window-size pkt

This is the window size of the channel. The window size is used for
flow-control and it decreases when data is sent over the channel and
increases when a channel-window-adjust packet is sent. Each
side of a channel has a window size.

— Procedure: channel-open-maximum-packet-size pkt

This is the maximum allowed packet size for data sent to a channel. It
basically limits the size of channel-data and
channel-extended-data packets.

Construct a request to open a session channel. This type of channel is
used for interactive logins, remote command execution, etc. After the
channel has been established the client will send e.g. a
channel-request/shell or a channel-request/exec request.

Constructs a message that indicates a channel was successfully opened
(identified by recipient). The party that sends this message
will include its own channel ID (sender).

— Procedure: channel-open-confirmation? obj

Returns true if obj is a channel-open-confirmation packet.

— Procedure: channel-open-confirmation-sender pkt

This field contains the sender's ID for this channel.

— Procedure: channel-open-confirmation-initial-window-size pkt

This is the sender's initial window size. Analogous to the initial
window size in a channel-open/* request.

— Procedure: channel-open-confirmation-maximum-packet-size pkt

This is the sender's maximum packet size. Analogous to the maximum
packet size in a channel-open/* request.

— Procedure: make-channel-window-adjust recipient amount

This constructs a packet that is used to increment the window size of
channel recipient by amount octets. It tells the remote
part that the channel may receive additional data. If the client has
assigned to a channel a receive buffer of 4096 bytes and the server
sends 4096 bytes, the server will not be able to successfully send
more data until the client has processed some of the buffer. When
there is more room in the buffer the client can send a message of this
type.

— Procedure: channel-window-adjust? obj

Returns true if obj is a channel-window-adjust packet.

— Procedure: channel-window-adjust-amount pkt

This field contains the number of bytes that will be added to the
window size.

— Procedure: make-channel-data recipient value

This constructs a request that sends data over a channel.

— Procedure: channel-data? obj

Returns true if obj is a channel-data packet.

— Procedure: channel-data-value pkt

This field contains a bytevector with data being sent over the
channel.

— Procedure: make-channel-extended-data recipient type value

This constructs a message that works just like channel-data,
except it contains an additional type field (explained below).

— Procedure: channel-extended-data? obj

Returns true if obj is a channel-extended-data packet.

— Procedure: channel-extended-data-type pkt

Data sent by a channel-data packet will normally be sent to a
port connected with standard output. A channel-extended-data
field is used when the data destination is a different port.

SSH-EXTENDED-DATA-STDERR

This constant specifies that the destination is the standard error
port.

— Procedure: channel-extended-data-value pkt

This field contains a bytevector with the data sent over the channel,
e.g. an error message printed on the standard error port.

— Procedure: make-channel-eof recipient

This constructs a packet that signals the end-of-file condition on the
channel identified by the recipient ID.

— Procedure: channel-eof? obj

Returns true if obj is a channel-eof packet.

— Procedure: make-channel-close recipient

This constructs a message that is used when a channel is closed.

— Procedure: channel-close? obj

Returns true if obj is a channel-close packet.

— Procedure: make-channel-success recipient

This constructs a packet that indicates that the previous request was
successful. These packets are sent in response to requests where
want-reply? is true.

— Procedure: channel-success? obj

Returns true if obj is a channel-success packet.

— Procedure: make-channel-failure recipient

This constructs a packet that indicates that the previous request was
not successful. These packets are sent in response to requests where
want-reply? is true.

— Procedure: channel-failure? obj

Returns true if obj is a channel-failure packet.

— Procedure: channel-request? obj

Returns true if obj is a channel-request packet.

— Procedure: channel-request-type req

This field is a string that identifies the type of the request, e.g.
"break" or "shell".

— Procedure: channel-request-want-reply? req

When this field is true the peer will respond with
channel-success or channel-failure. This field is not
valid for all requests. Where it is not valid the constructor will not
include it as an argument.

— Procedure: make-channel-request/break recipient want-reply? length

This constructs a request that relays a “BREAK” signal on the
channel. A “BREAK” is a signalling mechanism used with serial
consoles. This request is standardized by RFC 4335.

This constructs a packet which indicates that the program connected
to the channel identified by recipient has exited due to an
operating system signal.

— Procedure: channel-request/exit-signal? obj

Returns true if obj is a channel-request/exit-signal packet.

— Procedure: channel-request/exit-signal-name req

This is a string that identifies the signal by name. For posix
systems it is one of the following: "ABRT", "ALRM",
"FPE", "HUP", "ILL", "INT", "KILL",
"PIPE", "QUIT", "SEGV", "TERM",
"USR1", "USR2". Other signal names may be used by
following the guidelines in section 6.10 of RFC 4254.

— Procedure: channel-request/exit-signal-core-dumped? req

This field is true when the operating system saved a process image
(“core dump”) when it sent the signal.

— Procedure: channel-request/exit-signal-message req

This may be a string that explains the signal.

— Procedure: channel-request/exit-signal-language req

This string may identify the language used in
channel-request/exit-signal-message.

— Procedure: make-channel-request/exit-status recipient value

This constructs a packet which indicates that the program connected
to the channel identified by recipient has exited voluntarily.

— Procedure: channel-request/exit-status? obj

Returns true if obj is a channel-request/exit-status packet.

— Procedure: channel-request/exit-status-value req

This is an integer that identifies the exit status of the program. It
is the same kind of number used by the the Scheme procedure
exit.

Constructs a request that instructs the server to allocate a
pseudo-terminal (PTY) for the channel identified by recipient.
A PTY is needed for interactive programs, such as shells and Emacs.

— Procedure: channel-request/pty-req? obj

Returns true if obj is a channel-request/pty-req packet.

— Procedure: channel-request/pty-req-term req

This is a string that identifies the type of terminal that this PTY
will be connected to. If the terminal is compatible with the DEC VT100
the value would be "vt100". This value is also the environment
variable TERM. The set of supported terminal types depends on
the server. Typically the software running on an SSH server uses the
“terminfo” database.

— Procedure: channel-request/pty-req-columns req

This field contains the number of columns the terminal supports, e.g.
80. The channel-request/window-change request can be
used to update this value if the terminal supports resizing.

— Procedure: channel-request/pty-req-rows req

This field contains the number of rows the terminal supports, e.g.
24.

— Procedure: channel-request/pty-req-width req

This field specifies the width of the terminal in pixels.

— Procedure: channel-request/pty-req-height req

This field specifies the height of the terminal in pixels.

— Procedure: channel-request/pty-req-modes req

This is a bytevector that encodes POSIX terminal modes. Unlike the
size of the terminal, it is not possible to change the modes after the
PTY has been created. The client should emulate a terminal set to
“raw” mode and send a correct list of terminal modes. The server
will then cooperate to handle the rest. This means that, unlike with
telnet, the client will generally not do local “canonical” terminal
processing.

— Procedure: bytevector->terminal-modes bv

Decodes the modes from a channel-request/pty-req. The return
value is an association list.

— Procedure: terminal-modes->bytevector modes

The inverse of bytevector->terminal-modes. All modes specified
by RFC 4254 can be encoded.

If this field is true when only one X11 connection should be
forwarded.

— Procedure: channel-request/x11-req-protocol req

This field identifies an X11 authentication protocol. The most common
value is "MIT-MAGIC-COOKIE-1".

— Procedure: channel-request/x11-req-cookie req

This is a “magic cookie” encoded as a hexadecimal string. It is used
with "MIT-MAGIC-COOKIE-1". It is recommended by RFC 4254 that
this cookie should be different from the actual cookie used by the X11
server. When receiving a channel-open/x11 request the cookie
can be intercepted, verified and replaced with the real one.

— Procedure: channel-request/x11-req-screen req

An X11 display can have, in X jargon, multiple screens. Normally this
field would be 0.

— Procedure: make-channel-request/xon-xoff recipient client-can-do?

Constructs a message that tells the client when it can do local
processing of terminal flow control (C-s and C-q).

— Procedure: channel-request/xon-xoff? obj

Returns true if obj is a channel-request/xon-xoff packet.

— Procedure: channel-request/xon-xoff-client-can-do? req

This flag is true if the client is allowed to do local processing of
terminal flow control. If the flag is false then flow control is done
on the server.

2.5.4.2 Secure Shell Transport Layer Protocol

The (weinholt net ssh transport) library implements record
types, parsers and formatters for the transport layer packets in SSH.

See RFC 4253 for a description of this protocol.

— Procedure: register-transport registrar

Registers the packet types for the transport layer so that they may be
received and sent. A registrar may be obtained using
ssh-conn-registrar.

— Procedure: make-disconnect code message language

Constructs a packet that closes the SSH connection. After sending or
receiving this message the connection should be closed with
close-ssh. The ssh-error procedure may be more
convenient than manually constructing and sending a disconnect
packet.

— Procedure: disconnect? obj

Returns #t if obj is a disconnect packet.

— Procedure: disconnect-code pkt

This field is an integer that represents the cause of the disconnect.
The reason could be one of these (exported) constants:

SSH-DISCONNECT-HOST-NOT-ALLOWED-TO-CONNECT

SSH-DISCONNECT-PROTOCOL-ERROR

SSH-DISCONNECT-KEY-EXCHANGE-FAILED

SSH-DISCONNECT-RESERVED

SSH-DISCONNECT-MAC-ERROR

SSH-DISCONNECT-COMPRESSION-ERROR

SSH-DISCONNECT-SERVICE-NOT-AVAILABLE

SSH-DISCONNECT-PROTOCOL-VERSION-NOT-SUPPORTED

SSH-DISCONNECT-HOST-KEY-NOT-VERIFIABLE

SSH-DISCONNECT-CONNECTION-LOST

SSH-DISCONNECT-BY-APPLICATION

SSH-DISCONNECT-TOO-MANY-CONNECTIONS

SSH-DISCONNECT-AUTH-CANCELLED-BY-USER

SSH-DISCONNECT-NO-MORE-AUTH-METHODS-AVAILABLE

SSH-DISCONNECT-ILLEGAL-USER-NAME

— Procedure: disconnect-message pkt

This is a human-readable explanation for the disconnect.

— Procedure: disconnect-language pkt

Most commonly unused, "".

— Procedure: make-ignore data

Construct a new ignore packet using the bytevector data
as the payload. These packets are ignored by receivers but can be used
to make traffic analysis more difficult.

— Procedure: ignore? obj

Returns #t if obj is an ignore packet.

— Procedure: make-unimplemented sequence-number

This constructs a message that should be sent when a received packet
type is not implemented.

— Procedure: unimplemented? obj

Returns #t if obj is an unimplemented packet.

— Procedure: unimplemented-sequence-number pkt

Each packet sent over an SSH connection is given an implicit sequence
number. This field exactly identifies one SSH packet.

— Procedure: make-debug always-display? message language

Constructs a debug packet. It contains a message that a client or
server may optionally display to the user.

— Procedure: debug? obj

Returns #t if obj is a debug packet.

— Procedure: debug-always-display? pkt

If this field is true then the message should be displayed.

— Procedure: debug-message pkt

This is a string containing the debugging message. If it is displayed
to the user it should first be filtered.

— Procedure: debug-language pkt

Most commonly unused, "".

— Procedure: make-service-request name

This constructs a service request packet. The first service requested
is normally "ssh-userauth". See net ssh userauth.

— Procedure: service-request? obj

Returns #t if obj is a service-request packet.

— Procedure: service-request-name pkt

This is the name of the service being requested, e.g.
"ssh-userauth".

— Procedure: make-service-accept name

Constructs a request which indicates that access to a requested
service was granted.

— Procedure: service-accept? obj

Returns #t if obj is a service-accept packet.

— Procedure: service-accept-name pkt

This field contains the name of the service to which access was
granted.

Constructs a kexinit packet, which is used as part of the key
exchange algorithm. The arguments are explained below. You probably
want to use build-kexinit-packet instead of this procedure.

— Procedure: kexinit? obj

Returns #t if obj is a kexinit packet.

— Procedure: kexinit-cookie pkt

This field is a random bytevector. It is used in the key exchange to
make things more difficult for an attacker.

— Procedure: kexinit-kex-algorithms pkt

A list of the supported key exchange algorithms (mostly variations on
Diffie-Hellman).

— Procedure: kexinit-server-host-key-algorithms pkt

A list of the supported host key algorithms.

— Procedure: kexinit-encryption-algorithms-client-to-server pkt

A list of the supported encryption algorithms for packets sent from
the client to the server.

— Procedure: kexinit-encryption-algorithms-server-to-client pkt

A list of the supported encryption algorithms for packets sent from
the server to the client.

— Procedure: kexinit-mac-algorithms-client-to-server pkt

A list of the supported Message Authentication Code (MAC) algorithms
for packets sent from the client to the server.

— Procedure: kexinit-mac-algorithms-server-to-client pkt

A list of the supported Message Authentication Code (MAC) algorithms
for packets sent from the server to the client.

— Procedure: kexinit-compression-algorithms-client-to-server pkt

A list of the supported compression algorithms for packets sent from
the client to the server. The algorithm "none" is currently the
only implemented compression algorithm.

— Procedure: kexinit-compression-algorithms-server-to-client pkt

A list of the supported compression algorithms for packets sent from
the server to the client. The algorithm "none" is currently the
only implemented compression algorithm.

— Procedure: kexinit-languages-client-to-server pkt

Normally never used. Set to the empty list.

— Procedure: kexinit-languages-server-to-client pkt

Normally never used. Set to the empty list.

— Procedure: kexinit-first-kex-packet-follows? pkt

If this field is true then the server and client will try to cooperate
in order to make the key exchange run faster over connections with
high latency. This optimization only works when the server and client
both prefer the same algorithms.

— Procedure: kexinit-reserved pkt

This field must be zero.

— Procedure: make-newkeys

Constructs a new newkeys packet. This message is used as part
of key exchange to notify the remote side that new encryption keys are
being used.

2.5.4.3 Secure Shell Authentication Protocol

The (weinholt net ssh userauth) library implements record
types, parsers and formatters for the authentication protocol packets
in SSH.

See RFC 4252 for a more detailed description of this protocol. In this
protocol the client sends packets of type userauth-request. The
type names that start with userauth-request/ are sub-types that
contain user credentials. All other packet types documented here are
sent by the server.

All user authentication requests contain a user name, a service name
and a method name. The service name most commonly used is
"ssh-connection", which requests access to the connection
protocol. See net ssh connection.

— Procedure: register-userauth registrar

Registers the packet types for the authentication protocol so that
they may be received and sent. A registrar may be obtained using
ssh-conn-registrar.

— Procedure: register-userauth-password registrar

Registers the packet types for the password authentication protocol.
This is a supplement to register-userauth.

— Procedure: register-userauth-public-key registrar

Registers the packet types for the public key authentication protocol.
This is a supplement to register-userauth.

— Procedure: deregister-userauth registrar

Deregisters all authentication protocol packet types.

— Procedure: make-userauth-request username service method

Constructs a new user authentication request. This particular
procedure is only good for constructing requests that use the
"none" method. When such a request is sent to the server it
will respond with a list of available authentication methods. To make
a proper request use one of the make-userauth-request/*
procedures below. Those procedures automatically include the correct
method in the request. The service is normally
"ssh-connection". See net ssh connection.

— Procedure: userauth-request? obj

Returns true if obj is a userauth-request packet. This
includes userauth-request/password packets, and so on.

— Procedure: userauth-request-username request

This returns the user name field of request.

— Procedure: userauth-request-service request

This returns the service name field of request.

— Procedure: userauth-request-method request

This returns the method name field of request. Examples include
"none", "password" and "publickey".

If the server does not like the credentials provided in a
userauth-request it will send a userauth-failure packet.

— Procedure: make-userauth-failure can-continue partial?

Constructs a message that indicates to the client that the user
authentication request was not successful.

— Procedure: userauth-failure? obj

Returns true if obj is a userauth-failure packet. These
packets indicate the the client was denied access to the requested
service. The credentials might be incorrect or the server might be
requesting additional authentication requests (see below).

— Procedure: userauth-failure-can-continue failure

This returns a list of authentication methods that “can continue”,
i.e. methods that might be successful given that correct credentials
are provided.

Constructs a packet that indicates to the client that the user
authentication was successful. The client can now use the requested
service (e.g. the connection protocol). This message has no fields.

— Procedure: userauth-success? obj

Returns true if obj is a userauth-success packet.

The server can send a banner before the user authenticates. The banner
might often contain a warning about unauthorized access.

— Procedure: make-userauth-banner message language

This constructs a textual message that the server can send to the
client. The client software can then display it to the user. This
happens before user authentication is attempted and often contains a
warning about unauthorized accesss.

— Procedure: userauth-banner? obj

Returns true if obj is a userauth-banner packet.

— Procedure: userauth-banner-message banner

This field is a message that the client can show to the user.

— Procedure: userauth-banner-language banner

This field might indicate the language of the text in the banner, but
is most commonly empty and not used.

The client can try to authenticate with a password. Note that the
unencrypted password is seen by the server. It's important to check
hosts keys to make sure you're connecting to the right server.

— Procedure: make-userauth-request/password username service password

Constructs a user authentication request. This is a normal attempt to
login with a user name and password. There is an alternative protocol
for these types of login requests: the "keyboard-interactive"
method (support is planned).

— Procedure: userauth-request/password? obj

Returns true if obj is a userauth-request/password
packet.

— Procedure: userauth-request/password-value request

Returns the password field for this user authentication request.

The server can request that the client should change its password.

— Procedure: make-userauth-password-changereq prompt language

This constructs a password change request. Some servers might send
this packet if e.g. they use a password expiry system.

— Procedure: userauth-password-changereq? obj

Returns true if obj is a userauth-request/changereq
packet.

— Procedure: userauth-password-changereq-prompt changereq

This is the message to show the user when prompting for the new
password.

— Procedure: userauth-password-changereq-language changereq

This is the language used in the password change request prompt.

After having received a request to change its password a client may
send a userauth-request/password-change packet.

— Procedure: make-userauth-request/password-change username service old new

Constructs a request to authenticate the user and at the same time
change the user's password. This message may be sent without having
received a userauth-request/changereq packet. Please see
section 8 of RFC 4252 for the meaning of the packet that the server
will send in response to this packet.

This procedure creates an unsigned request to authenticate with
public key cryptography. The client may try to authenticate itself by
sending a signed request to the server. The server will have a copy of
the public key on file, e.g. stored in the user's
authorized_keys file. By using the public key it can confirm
that the client is possession of the corresponding private key. The
packet returned by this procedure may be signed with
sign-userauth-request/public-key.

— Procedure: userauth-request/public-key? obj

Returns true if obj is a userauth-request/public-key
packet.

— Procedure: userauth-request/public-key-algorithm request

This field indicates the public key algorithm name of the public key
in the request. It is automatically filled in when the request is
constructed.

This generates a signed userauth-request/public-key packet. It
needs an unsigned request, which may be created with
make-userauth-request/public-key. The session-id can be
recovered with ssh-conn-session-id. The private-key must
be a private DSA or ECDSA key (support for RSA signing is planned).
The signed request uses the SSH connection's session ID and can
therefore not be used with any other connection.

2.5.5 Basic TCP client connections

The (weinholt net tcp) provides a simple TCP client. This
library needs implementation-specific code, so the author is not eager
to provide more than the bare minimum.

This library should work with Ikarus Scheme, GNU Guile, Larceny (not
tested with Petit Larceny and Common Larceny), Mosh Scheme, Petite
Chez Scheme (as long as the nc command is installed), Vicare Scheme,
and Ypsilon Scheme. Once upon a time it also worked with PLT Scheme,
but it has not been tested with Racket.

— Procedure: tcp-connect hostname portname

Initiates a TCP connection to the given hostname and
portname (both of which are strings).

Returns an input-port and an output-port. They are not guaranteed to
be distinct.

2.5.6 Transport Layer Security (simple interface)

The (weinholt net tls simple) library provides custom binary
ports that implement the Transport Layer Security (TLS) protocol used
by e.g. https. After starting TLS you can use the new ports as
easily as if they were unencrypted. TLS encrypts the traffic and
lets you verify the remote server's identity.
This library currently only provides a TLS client. Both TLS 1.0 and
TLS 1.1 are supported. The RSA, DHE-RSA (Ephemeral Diffie-Hellman) and
DHE-DSA key exchange algorithms are supported, as well as AES, ARCFOUR
and 3DES ciphers.

This whole thing is kind of experimental and I'd appreciate feedback.

— Procedure: tls-connect hostname portname [client-certificates]

Initiates a TCP connection to the given hostname and
portname (which are strings) and negotiates a TLS connection.
Can hang forever.

Pay no attention to the optional client-certificates argument.
It is not yet implemented.

This procedure returns three values: a binary input port, a binary
output port, and a TLS connection object. The last value comes from
the not-yet-documented (weinholt net tls) library. It is
intended to be used to access the server's certificate chain, which
can be verified using the not-yet-documented (weinholt crypto
x509) library.

Negotiates TLS on two already opened ports. Same return values as
tls-connect. This procedure can be used for protocols where the
communication at first is in plaintext and then switches over to
encrypted (i.e. STARTTLS). Some such protocols are SMTP, LDAP and
XMPP.

2.6 Binary structure utilities

2.6.1 Binary structure packing and unpacking

With (weinholt struct pack) you can easily access fields in a
bytevector and make new bytevectors from fields. The library defines
syntax that is similar to Python's struct module or Perl's pack/unpack
functions.

The exported bindings are actually syntax, but they can be used as
normal procedures, thanks to the use of
make-variable-transformer. The syntax transformers basically
perform inlining.

This library uses format strings which specify binary fields.
The format strings are read left-to-right and their syntax is:

c – s8, a signed byte.

C – u8, an unsigned byte.

s – s16, a signed 16-bit word.

S – u16, an unsigned 16-bit word.

l – s32, a signed 32-bit word.

L – u32, an unsigned 32-bit word.

q – s64, a signed 64-bit word.

Q – u64, an unsigned 64-bit word.

f – an IEEE-754 single-precision number.

d – an IEEE-754 double-precision number.

x – one byte of padding (zero).

a – enable automatic natural alignment (default).
Padding is inserted to align fields to their natural alignment,
i.e. a 32-bit field is aligned to a 4 byte offset.

u – disable automatic natural alignment.

! and > – the following fields will have big-endian
(network) byte order.

< – the following fields will have little-endian byte order.

= – the following fields will have native endianness.

whitespace – ignored.

decimals – repeat the following format character N times.

— Procedure: unpack fmt bytevector [offset]

Returns as many values as there are fields in the fmt string.
The values are fetched from the bytevector starting at the
offset (by default 0). For example, if the format string is
"C", this translates into a bytevector-u8-ref call.

2.7 Textual structure utilities

2.7.1 Base64 encoding and decoding

The (weinholt text base64) library provides procedures for
dealing with the standard Base64 encoding from RFC 4648 and some
variations thereof. The Base64 encoding can be used to represent
arbitrary bytevectors purely in printable ASCII.

One variation of Base64 is in the alphabet used. The standard encoding
uses an alphabet that ends with #\+ and #\/, but these
characters are reserved in some applications. One such application is
HTTP URLs, so there is a special encoding called base64url that simply
uses a different alphabet.

The line length can also vary. Some applications will need Base64
encoded strings that have no line endings at all, while other
applications have 64 or 76 characters per line. For these uses the
line length must be a multiple of four characters. Sometimes there is
not enough input to get a multiple of four, but then the padding
character #\= is used. Some applications don't use padding.

Some applications have their own “Base64” encodings that encode bits
in a different order. Such will be deemed magic and shall not work
with this library.

Encodes the bytevector bv in Base64 encoding. Optionally a range
of bytes can be specified with start and end.

If a maximum line length is required, set line-length to an
integer multiple of four (the default is #f). To omit padding
at the end of the data, set no-padding or a non-false value. The
alphabet is a string of length 64 (by default
base64-alphabet).

The port is either a textual output port or #f, in which
case this procedure returns a string.

— Procedure: base64-decode str [alphabet port]

Decodes the Base64 data in str. The string has to contain pure
Base64 data, including padding, and no whitespace or other extra
characters. The output is written to the binary output port.
Returns a bytevector if port is #f.

— Procedure: put-delimited-base64 port type bv [line-length]

Write the Base64 encoding of bv to the port. The output is
delimited by BEGIN/END lines that include the type.

Reads a delimited Base64 encoded bytevector and returns two values:
type (a string) and data (a bytevector). The data
value is the end-of-file object if port-eof? would return
#t.

Note: This procedure ignores MIME headers. Some delimited
Base64 formats have headers on the line after BEGIN, followed by an
empty line.

Note: This procedure ignores the Radix-64 checksum. The
Radix-64 format (RFC 4880) is based on Base64, but appends a CRC-24
(prefixed by #\=) at the end of the data.

The rationale for ignoring headers and checksums is that it follows
the Principle of Robustness: “Be conservative in what you send; be
liberal in what you accept from others.” Lines before the BEGIN line
are also ignored, because some applications (like OpenSSL) like to
prepend a human readable version of the data.

You should probably use special parsers if you are reading data with
headers or checksums. For some applications, e.g. MIME, you might
need a Base64 decoder that also ignores characters outside the
alphabet.

2.7.2 Internet address parsing and formatting

The (weinholt text internet) library helps you correctly parse
and format IPv4 and IPv6 addresses. This was a relatively trivial task
when the Internet used the 32-bit IPv4 addresses. But when the newer
128-bit IPv6 addresses are represented as strings they can be
compressed (meaning that sequences of zeroes may be omitted). An IPv6
address can actually be written in a great number of ways, and this
has resulted in a recommended textual representation (RFC 5952).

The IPv6 code does not yet handle embedded IPv4 addresses.

— Procedure: ipv4->string bytevector

The IPv4 address in bytevector is converted to the canonical
string representation.

— Procedure: string->ipv4 string

The textually represented IPv4 address in string is converted to
its bytevector representation.

If the string does not represent an IPv4 address, #f is
returned.

Note that this only handles the normal dotted-decimal notation. Some
libraries, e.g. the standard C library, provide a function that
parses addresses in octal, hex, and even handles some octets being
missing. This library does none of that. Up to two leading zeroes may
be used, though:

True if bytevector1 and bytevector2 are of equal length
and have the same contents.

This is a drop-in replacement for bytevector=? that does not
leak information about the outcome of the comparison by how much time
the comparison takes to perform. It works by accumulating the
differences between the bytevectors. This kind of operation is most
often needed when comparing fixed-length message digests, so the
length comparison is done in the obvious (fast) way.

3.1 checksig – verifies OpenPGP signature files

This program takes a detached ascii armored OpenPGP signature, a file
to check against, and a GPG keyring. It then verifies the signature.
As a curiosity it also prints OpenSSH-style random art for the key
that made the signature.

3.4 honingsburk – simple Secure Shell honey pot

This demonstrates the server part of the SSH library. It starts up a
dummy SSH server that accepts logins with the username root and the
password toor. The server does not create a real PTY and the client
does not gain access to the computer running the server. It presents a
command line where all commands return an error. It uses a few
non-standard procedures from Ikarus.

3.5 meircbot – the minimum-effort irc bot

The program file contains the configuration. It doesn't do anything
other than joining channels and being rude in private messages. Shows
how the (weinholt net irc) library can be used. It requires
the (xitomatl AS-match) library.

It also uses demonstrates how to use FiSH, OTR and the simple TLS
library.

3.6 secsh-client – manually operated Secure Shell client

Most SSH clients try to provide a nice user experience. This one is
instead a command-line based manually operated client. After
establishing the initial connection you can use a few simplistic
commands to login, establish a session channel, read and write channel
data. You can also enable debugging if you'd like to see a packet
trace. This session log shows how to connect to a honingsburk
running on TCP port 2222: