@c -*-texinfo-*-
@c This file is part of Guile-SSH Reference Manual.
@c Copyright (C) 2014-2023, 2026 Artyom V. Poptsov
@c Copyright (C) 2026 Nicolas Graves
@c See the file guile-ssh.texi for copying conditions.

@node Keys
@section Keys

@cindex public keys
@cindex private keys
@tindex key

The @code{(ssh key)} module provides procedures for handling of
Guile-SSH keys.

@strong{Note} that Guile-SSH does not support @abbr{ECDSA, Elliptic Curve
Digital Signature Algorithm} keys if libssh is compiled with GCrypt instead of
OpenSSL.

@deffn {Scheme Procedure} make-keypair type length
Generate a keypair of specified @var{type} and @var{length} (in bits).  This
may take some time.

Possible key types are: @code{dss}, @code{rsa}, @code{rsa1}, @code{ecdsa}
and @code{ed25519}.  If libssh version is greater than 0.9, the @var{type} can
also be among @code{ecdsa-p256}, @code{ecdsa-p384}, @code{ecdsa-p521},
@code{ecdsa-p256-cert01}, @code{ecdsa-p384-cert01}, @code{ecdsa-p521-cert01}.

Return newly generated private key.  Throw @code{guile-ssh-error} on error.
@end deffn

@deffn {Scheme Procedure} key? x
Return @code{#t} if @var{x} is a Guile-SSH key, @code{#f} otherwise.
@end deffn

@deffn {Scheme Procedure} public-key? x
Return @code{#t} if @var{x} is a Guile-SSH key and it @strong{contains} a
public key, @code{#f} otherwise.  What it means is that the procedure will
return @code{#t} for a private key too (because the private key contains a
public key in some sense).
@end deffn

@deffn {Scheme Procedure} private-key? x
Return @code{#t} if @var{x} is a Guile-SSH private key, @code{#f}
otherwise.
@end deffn

@deffn {Scheme Procedure} public-key->string public-key
Convert @var{public-key} to a string.
@end deffn

@deffn {Scheme Procedure} string->public-key string type
Convert a public key of @var{type} represented as Base64 @var{string}
to a Guile-SSH key.  Throw @code{guile-ssh-error} on error.

The @var{type} must be one of the following symbols: @code{dss},
@code{rsa}, @code{rsa1}, @code{ed25519}, @code{ecdsa}.  If libssh version is
greater than 0.9, the @var{type} can also be among @code{ecdsa-p256},
@code{ecdsa-p384}, @code{ecdsa-p521}, @code{ecdsa-p256-cert01},
@code{ecdsa-p384-cert01}, @code{ecdsa-p521-cert01}.
@end deffn

@deffn {Scheme Procedure} private-key-from-file @
               file @
               [#:auth-callback=#f] @
               [#:user-data=#f]

Read private key from a @var{file}.  If the the key is encrypted the user will
be asked using @var{auth-callback} for passphrase to decrypt the key.  When
@var{auth-callback} is called, @var{user-data} is passed to it as an argument.
If no @var{auth-callback} is provided then the procedure denies access to an
encrypted key.

Return a new Guile-SSH key or @code{#f} on error.

The procedure performs @var{auth-callback} call as follows:

@lisp
(auth-callback prompt maximum-password-length echo? verify? user-data)
@end lisp

Where @code{prompt} is a string that specifies the password prompt to use.
The callback must return either a password as a string or @code{#f} if access
must be denied.

Usage example:
@lisp
(use-modules (ssh key))

(define (callback prompt max-len echo? verify? user-data)
  (getpass (format #f "~a: " prompt)))

(define key (private-key-from-file (string-append (getenv "HOME")
                                                  "/.ssh/id_rsa")
                                   #:auth-callback callback))
@end lisp

@end deffn

@deffn {Scheme Procedure} private-key-to-file private-key file-name
Export @var{private-key} to a PAM file @var{file-name} on a disk.  Throw
@code{guile-ssh-error} on error.  Return value is undefined.

@strong{Note} that this procedure won't work if libssh is compiled with
GCrypt cryptographic library.
@end deffn

@deffn {Scheme Procedure} private-key->public-key private-key
Get a public key from the @var{private-key}.
@end deffn

@deffn {Scheme Procedure} public-key-from-file session file
Read public key from a @var{file}.  Return a public key or @code{#f}
on error.
@end deffn

@deffn {Scheme Procedure} get-key-type key
Get a symbol that represents the type of the Guile-SSH @var{key}.
Possible types are: @code{dss}, @code{rsa}, @code{rsa1}, @code{unknown}.
@end deffn

@deffn {Scheme Procedure} get-public-key-fingerprint public-key type
@cindex fingerprint
@tindex fingerprint
Get a @var{public-key} fingerprint of @var{type} as a string.  Return the
string on success, @code{#f} on error.

See also @code{get-server-public-key} in @pxref{Sessions}.

The @var{type} can be one of the following symbols: @code{md5},
@code{sha1}, @code{sha256}.

Example:

@lisp
(get-public-key-fingerprint *rsa-pub-key* 'sha1)
@result{} "SHA1:FEE4m3ctVKMyGjtc15+LBeWuVFA"
@end lisp

@end deffn

@deffn {Scheme Procedure} get-public-key-hash public-key type
@cindex fingerprint
@tindex fingerprint
Get a @var{public-key} hash of @var{type} as a bytevector.  Return the
bytevector on success, @code{#f} on error.

See also @code{get-server-public-key} in @pxref{Sessions}.

The @var{type} can be one of the following symbols: @code{md5},
@code{sha1}.

Example:

@lisp
(let ((pubkey (get-server-public-key session)))
  (get-public-key-hash pubkey 'md5))
@result{} #vu8(15 142 110 203 162 228 250 211 20 212 26 217 118 57 217 66)
@end lisp

@end deffn

@deffn {Scheme Procedure} bytevector->hex-string bv
@cindex fingerprint
@tindex fingerprint
Convert the given bytevector @var{bv} to a colon separated string.

Example:

@lisp
(let ((hash (get-public-key-hash pubkey 'md5)))
  (bytevector->hex-string hash))
@result{} "0f:8e:6e:cb:a2:e4:fa:d3:14:d4:1a:d9:76:39:d9:42"
@end lisp

@end deffn

@deffn {Scheme Procedure} sign data key
               [#:namespace=''file''] @
               [#:hash='sha512]

@cindex signature
@tindex signature
Sign @var{data} using a private @var{key} with specified @var{namespace} and
@var{hash}.  @var{data} can be a binary bytevector or a string.  @var{hash}
should be 'sha256 or 'sha512.  Return the armored signature string on success,
@code{#f} on error.

See also @code{verify}.

Example:

@lisp
(let ((rsakey (private-key-from-file "tests/keys/rsakey"))
      (test-string "Test input\0string"))
  (call-with-output-file "/tmp/message.sig"
    (lambda (port)
      (format port (sign test-string rsakey)))))
@result{} #t
@end lisp

@end deffn

@deffn {Scheme Procedure} verify data signature
               [#:namespace=''file'']

@cindex signature
@tindex signature
Verify a @var{signature} for @var{data} with @var{namespace}. @var{data} can
be a binary bytevector or a string. Return the signing key on success,
@code{#f} on error.

See also @code{sign}.

Example:

@lisp
(verify "Test input\0string"
        (call-with-input-file "/tmp/message.sig"
          (@ (ice-9 textual-ports) get-string-all)))
@result{} #<key rsa (public) ...>
@end lisp

@end deffn

@c Local Variables:
@c TeX-master: "guile-ssh.texi"
@c End:
