View source with raw comments or as raw
    1/*  Part of SWI-Prolog
    2
    3    Author:        Markus Triska and Matt Lilley
    4    WWW:           http://www.swi-prolog.org
    5    Copyright (c)  2004-2017, SWI-Prolog Foundation
    6                              VU University Amsterdam
    7    All rights reserved.
    8
    9    Redistribution and use in source and binary forms, with or without
   10    modification, are permitted provided that the following conditions
   11    are met:
   12
   13    1. Redistributions of source code must retain the above copyright
   14       notice, this list of conditions and the following disclaimer.
   15
   16    2. Redistributions in binary form must reproduce the above copyright
   17       notice, this list of conditions and the following disclaimer in
   18       the documentation and/or other materials provided with the
   19       distribution.
   20
   21    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
   22    "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
   23    LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
   24    FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
   25    COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
   26    INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
   27    BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
   28    LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
   29    CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   30    LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
   31    ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   32    POSSIBILITY OF SUCH DAMAGE.
   33*/
   34
   35:- module(crypto,
   36          [ crypto_n_random_bytes/2,    % +N, -Bytes
   37            crypto_data_hash/3,         % +Data, -Hash, +Options
   38            crypto_file_hash/3,         % +File, -Hash, +Options
   39            crypto_context_new/2,       % -Context, +Options
   40            crypto_data_context/3,      % +Data, +C0, -C
   41            crypto_context_hash/2,      % +Context, -Hash
   42            crypto_open_hash_stream/3,  % +InStream, -HashStream, +Options
   43            crypto_stream_hash/2,       % +HashStream, -Hash
   44            crypto_password_hash/2,     % +Password, ?Hash
   45            crypto_password_hash/3,     % +Password, ?Hash, +Options
   46            crypto_data_hkdf/4,         % +Data, +Length, -Bytes, +Options
   47            ecdsa_sign/4,               % +Key, +Data, -Signature, +Options
   48            ecdsa_verify/4,             % +Key, +Data, +Signature, +Options
   49            ed25519_new_keypair/1,      % -KeyPair
   50            ed25519_seed_keypair/2,     % +Seed, -KeyPair
   51            ed25519_keypair_public_key/2,   % +KeyPair, -PublicKey
   52            ed25519_sign/4,             % +KeyPair, +Data, -Signature, +Options
   53            ed25519_verify/4,           % +PublicKey, +Data, +Signature, +Options
   54            curve25519_generator/1,     % -Generator
   55            curve25519_scalar_mult/3,   % +Scalar, +Point, -Result
   56            crypto_data_decrypt/6,      % +CipherText, +Algorithm, +Key, +IV, -PlainText, +Options
   57            crypto_data_encrypt/6,      % +PlainText, +Algorithm, +Key, +IV, -CipherText, +Options
   58            hex_bytes/2,                % ?Hex, ?List
   59            rsa_private_decrypt/4,      % +Key, +Ciphertext, -Plaintext, +Enc
   60            rsa_private_encrypt/4,      % +Key, +Plaintext, -Ciphertext, +Enc
   61            rsa_public_decrypt/4,       % +Key, +Ciphertext, -Plaintext, +Enc
   62            rsa_public_encrypt/4,       % +Key, +Plaintext, -Ciphertext, +Enc
   63            rsa_sign/4,                 % +Key, +Data, -Signature, +Options
   64            rsa_verify/4,               % +Key, +Data, +Signature, +Options
   65            crypto_modular_inverse/3,   % +X, +M, -Y
   66            crypto_generate_prime/3,    % +N, -P, +Options
   67            crypto_is_prime/2,          % +P, +Options
   68            crypto_name_curve/2,        % +Name, -Curve
   69            crypto_curve_order/2,       % +Curve, -Order
   70            crypto_curve_generator/2,   % +Curve, -Generator
   71            crypto_curve_scalar_mult/4  % +Curve, +Scalar, +Point, -Result
   72          ]).   73:- autoload(library(apply),[foldl/4,maplist/2,maplist/3]).   74:- autoload(library(base64),[base64_encoded/3]).   75:- autoload(library(error),[must_be/2,domain_error/2]).   76:- autoload(library(lists),[append/2,append/3,select/3,reverse/2]).   77:- autoload(library(option),[option/3,option/2]).   78
   79:- use_foreign_library(foreign(crypto4pl)).

Cryptography and authentication library

This library provides bindings to functionality of OpenSSL that is related to cryptography and authentication, not necessarily involving connections, sockets or streams.

The hash functionality of this library subsumes and extends that of library(sha), library(hash_stream) and library(md5) by providing a unified interface to all available digest algorithms.

The underlying OpenSSL library (libcrypto) is dynamically loaded if either library(crypto) or library(ssl) are loaded. Therefore, if your application uses library(ssl), you can use library(crypto) for hashing without increasing the memory footprint of your application. In other cases, the specialised hashing libraries are more lightweight but less general alternatives to library(crypto).

author
- Markus Triska
- Matt Lilley
 crypto_n_random_bytes(+N, -Bytes) is det
Bytes is unified with a list of N cryptographically secure pseudo-random bytes. Each byte is an integer between 0 and 255. If the internal pseudo-random number generator (PRNG) has not been seeded with enough entropy to ensure an unpredictable byte sequence, an exception is thrown.

One way to relate such a list of bytes to an integer is to use CLP(FD) constraints as follows:

:- use_module(library(clpfd)).

bytes_integer(Bs, N) :-
        foldl(pow, Bs, 0-0, N-_).

pow(B, N0-I0, N-I) :-
        B in 0..255,
        N #= N0 + B*256^I0,
        I #= I0 + 1.

With this definition, you can generate a random 256-bit integer from a list of 32 random bytes:

?- crypto_n_random_bytes(32, Bs),
   bytes_integer(Bs, I).
Bs = [98, 9, 35, 100, 126, 174, 48, 176, 246|...],
I = 109798276762338328820827...(53 digits omitted).

The above relation also works in the other direction, letting you translate an integer to a list of bytes. In addition, you can use hex_bytes/2 to convert bytes to tokens that can be easily exchanged in your applications. This also works if you have compiled SWI-Prolog without support for large integers.

  143/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  144   SHA256 is the current default for several hash-related predicates.
  145   It is deemed sufficiently secure for the foreseeable future.  Yet,
  146   application programmers must be aware that the default may change in
  147   future versions. The hash predicates all yield the algorithm they
  148   used if a Prolog variable is used for the pertaining option.
  149- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  150
  151default_hash(sha256).
  152
  153functor_hash_options(F, Hash, Options0, [Option|Options]) :-
  154        Option =.. [F,Hash],
  155        (   select(Option, Options0, Options) ->
  156            (   var(Hash) ->
  157                default_hash(Hash)
  158            ;   must_be(atom, Hash)
  159            )
  160        ;   Options = Options0,
  161            default_hash(Hash)
  162        ).
 crypto_data_hash(+Data, -Hash, +Options) is det
Hash is the hash of Data. The conversion is controlled by Options:
algorithm(+Algorithm)
One of md5 (insecure), sha1 (insecure), ripemd160, sha224, sha256, sha384, sha512, sha3_224, sha3_256, sha3_384, sha3_512, blake2s256 or blake2b512. The BLAKE digest algorithms require OpenSSL 1.1.0 or greater, and the SHA-3 algorithms require OpenSSL 1.1.1 or greater. The default is a cryptographically secure algorithm. If you specify a variable, then that variable is unified with the algorithm that was used.
encoding(+Encoding)
If Data is a sequence of character codes, this must be translated into a sequence of bytes, because that is what the hashing requires. The default encoding is utf8. The other meaningful value is octet, claiming that Data contains raw bytes.
hmac(+Key)
If this option is specified, a hash-based message authentication code (HMAC) is computed, using the specified Key which is either an atom, string or list of bytes. Any of the available digest algorithms can be used with this option. The cryptographic strength of the HMAC depends on that of the chosen algorithm and also on the key. This option requires OpenSSL 1.1.0 or greater.
Arguments:
Data- is either an atom, string or code-list
Hash- is an atom that represents the hash in hexadecimal encoding.
See also
- hex_bytes/2 for conversion between hexadecimal encoding and lists of bytes.
- crypto_password_hash/2 for the important use case of passwords.
  199crypto_data_hash(Data, Hash, Options) :-
  200    crypto_context_new(Context0, Options),
  201    crypto_data_context(Data, Context0, Context),
  202    crypto_context_hash(Context, Hash).
 crypto_file_hash(+File, -Hash, +Options) is det
True if Hash is the hash of the content of File. For Options, see crypto_data_hash/3.
  209crypto_file_hash(File, Hash, Options) :-
  210    setup_call_cleanup(open(File, read, In, [type(binary)]),
  211                       crypto_stream_hash(In, Hash, Options),
  212                       close(In)).
  213
  214crypto_stream_hash(Stream, Hash, Options) :-
  215    crypto_context_new(Context0, Options),
  216    update_hash(Stream, Context0, Context),
  217    crypto_context_hash(Context, Hash).
  218
  219update_hash(In, Context0, Context) :-
  220    (   at_end_of_stream(In)
  221    ->  Context = Context0
  222    ;   read_pending_codes(In, Data, []),
  223        crypto_data_context(Data, Context0, Context1),
  224        update_hash(In, Context1, Context)
  225    ).
 crypto_context_new(-Context, +Options) is det
Context is unified with the empty context, taking into account Options. The context can be used in crypto_data_context/3. For Options, see crypto_data_hash/3.
Arguments:
Context- is an opaque pure Prolog term that is subject to garbage collection.
  237crypto_context_new(Context, Options0) :-
  238    functor_hash_options(algorithm, _, Options0, Options),
  239    '_crypto_context_new'(Context, Options).
 crypto_data_context(+Data, +Context0, -Context) is det
Context0 is an existing computation context, and Context is the new context after hashing Data in addition to the previously hashed data. Context0 may be produced by a prior invocation of either crypto_context_new/2 or crypto_data_context/3 itself.

This predicate allows a hash to be computed in chunks, which may be important while working with Metalink (RFC 5854), BitTorrent or similar technologies, or simply with big files.

  253crypto_data_context(Data, Context0, Context) :-
  254    '_crypto_hash_context_copy'(Context0, Context),
  255    '_crypto_update_hash_context'(Data, Context).
 crypto_context_hash(+Context, -Hash)
Obtain the hash code of Context. Hash is an atom representing the hash code that is associated with the current state of the computation context Context.
  264crypto_context_hash(Context, Hash) :-
  265    '_crypto_hash_context_copy'(Context, Copy),
  266    '_crypto_hash_context_hash'(Copy, List),
  267    hex_bytes(Hash, List).
 crypto_open_hash_stream(+OrgStream, -HashStream, +Options) is det
Open a filter stream on OrgStream that maintains a hash. The hash can be retrieved at any time using crypto_stream_hash/2. Available Options in addition to those of crypto_data_hash/3 are:
close_parent(+Bool)
If true (default), closing the filter stream also closes the original (parent) stream.
  279crypto_open_hash_stream(OrgStream, HashStream, Options) :-
  280    crypto_context_new(Context, Options),
  281    '_crypto_open_hash_stream'(OrgStream, HashStream, Context).
 crypto_stream_hash(+HashStream, -Hash) is det
Unify Hash with a hash for the bytes sent to or read from HashStream. Note that the hash is computed on the stream buffers. If the stream is an output stream, it is first flushed and the Digest represents the hash at the current location. If the stream is an input stream the Digest represents the hash of the processed input including the already buffered data.
  293crypto_stream_hash(Stream, Hash) :-
  294    '_crypto_stream_hash_context'(Stream, Context),
  295    crypto_context_hash(Context, Hash).
  296
  297/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  298   The so-called modular crypt format (MCF) is a standard for encoding
  299   password hash strings. However, there's no official specification
  300   document describing it. Nor is there a central registry of
  301   identifiers or rules. This page describes what is known about it:
  302
  303   https://pythonhosted.org/passlib/modular_crypt_format.html
  304
  305   As of 2016, the MCF is deprecated in favor of the PHC String Format:
  306
  307   https://github.com/P-H-C/phc-string-format/blob/master/phc-sf-spec.md
  308
  309   This is what we are using below. For the time being, it is best to
  310   treat these hashes as opaque atoms in applications. Please let me
  311   know if you need to rely on any specifics of this format.
  312- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
 crypto_password_hash(+Password, ?Hash) is semidet
If Hash is instantiated, the predicate succeeds iff the hash matches the given password. Otherwise, the call is equivalent to crypto_password_hash(Password, Hash, []) and computes a password-based hash using the default options.
  321crypto_password_hash(Password, Hash) :-
  322    (   nonvar(Hash) ->
  323        must_be(atom, Hash),
  324        split_string(Hash, "$", "$", Parts),
  325        ( Parts = ["pbkdf2-sha512",Ps,SaltB64,HashB64] ->
  326          atom_to_term(Ps, t=Iterations, []),
  327          bytes_base64(SaltBytes, SaltB64),
  328          bytes_base64(HashBytes, HashB64),
  329          '_crypto_password_hash_pbkdf2'(Password, SaltBytes, Iterations, HashBytes)
  330        ; Parts = ["2a", _, _],
  331          sub_atom(Hash, 0, 29, 31, Setting),
  332          '_crypto_password_hash_bcrypt'(Password, Setting, Hash)
  333        )
  334    ;   crypto_password_hash(Password, Hash, [])
  335    ).
 crypto_password_hash(+Password, -Hash, +Options) is det
Derive Hash based on Password. This predicate is similar to crypto_data_hash/3 in that it derives a hash from given data. However, it is tailored for the specific use case of passwords. One essential distinction is that for this use case, the derivation of a hash should be as slow as possible to counteract brute-force attacks over possible passwords.

Another important distinction is that equal passwords must yield, with very high probability, different hashes. For this reason, cryptographically strong random numbers are automatically added to the password before a hash is derived.

Hash is unified with an atom that contains the computed hash and all parameters that were used, except for the password. Instead of storing passwords, store these hashes. Later, you can verify the validity of a password with crypto_password_hash/2, comparing the then entered password to the stored hash. If you need to export this atom, you should treat it as opaque ASCII data with up to 255 bytes of length. The maximal length may increase in the future.

Admissible options are:

algorithm(+Algorithm)
The algorithm to use. Currently, the only available algorithms are pbkdf2-sha512 (the default) and bcrypt.
cost(+C)
C is an integer, denoting the binary logarithm of the number of iterations used for the derivation of the hash. This means that the number of iterations is set to 2^C. Currently, the default is 17, and thus more than one hundred thousand iterations. You should set this option as high as your server and users can tolerate. The default is subject to change and will likely increase in the future or adapt to new algorithms.
salt(+Salt)
Use the given list of bytes as salt. By default, cryptographically secure random numbers are generated for this purpose. The default is intended to be secure, and constitutes the typical use case of this predicate.

Currently, PBKDF2 with SHA-512 is used as the hash derivation function, using 128 bits of salt. All default parameters, including the algorithm, are subject to change, and other algorithms will also become available in the future. Since computed hashes store all parameters that were used during their derivation, such changes will not affect the operation of existing deployments. Note though that new hashes will then be computed with the new default parameters.

See also
- crypto_data_hkdf/4 for generating keys from Hash.
  388crypto_password_hash(Password, Hash, Options) :-
  389    must_be(list, Options),
  390    option(cost(C), Options, 17),
  391    Iterations is 2^C,
  392    option(algorithm(Algorithm), Options, 'pbkdf2-sha512'),
  393    memberchk(Algorithm, ['pbkdf2-sha512', bcrypt]),
  394    (   option(salt(SaltBytes), Options) ->
  395        true
  396    ;   crypto_n_random_bytes(16, SaltBytes)
  397    ),
  398    (  Algorithm == 'pbkdf2-sha512'
  399    -> '_crypto_password_hash_pbkdf2'(Password, SaltBytes, Iterations, HashBytes),
  400       bytes_base64(HashBytes, HashB64),
  401       bytes_base64(SaltBytes, SaltB64),
  402       format(atom(Hash),
  403              "$pbkdf2-sha512$t=~d$~w$~w", [Iterations,SaltB64,HashB64])
  404    ;  bcrypt_bytes_base64(SaltBytes, SaltB64),
  405       option(cost(Cost), Options, 11),
  406       format(string(Setting), "$2a$~|~`0t~d~2+$~w", [Cost, SaltB64]),
  407       '_crypto_password_hash_bcrypt'(Password, Setting, Hash)
  408    ).
  409
  410
  411/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  412   Bidirectional Bytes <-> Base64 conversion as required by PHC format.
  413
  414   Note that *no padding* must be used, and that we must be able
  415   to encode the whole range of bytes, not only UTF-8 sequences!
  416- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  417
  418bytes_base64(Bytes, Base64) :-
  419    (   var(Bytes) ->
  420        base64_encoded(Atom, Base64, [padding(false), encoding(iso_latin_1)]),
  421        atom_codes(Atom, Bytes)
  422    ;   atom_codes(Atom, Bytes),
  423        base64_encoded(Atom, Base64, [padding(false), encoding(iso_latin_1)])
  424    ).
  425
  426% Bcrypt uses a different alphabeta for base64 encoding, annoyingly
  427bcrypt_bytes_base64(Bytes, Base64) :-
  428    (   var(Bytes) ->
  429        base64_encoded(Atom, Base64, [padding(false), encoding(utf8),
  430                                      charset(openbsd)]),
  431        atom_codes(Atom, Bytes)
  432    ;   atom_codes(Atom, Bytes),
  433        base64_encoded(Atom, Base64, [padding(false), encoding(utf8),
  434                                      charset(openbsd)])
  435    ).
 crypto_data_hkdf(+Data, +Length, -Bytes, +Options) is det
Concentrate possibly dispersed entropy of Data and then expand it to the desired length. Bytes is unified with a list of bytes of length Length, and is suitable as input keying material and initialization vectors to the symmetric encryption predicates.

Admissible options are:

algorithm(+Algorithm)
A hashing algorithm as specified to crypto_data_hash/3. The default is a cryptographically secure algorithm. If you specify a variable, then it is unified with the algorithm that was used.
info(+Info)
Optional context and application specific information, specified as an atom, string or list of bytes. The default is the zero length atom ''.
salt(+List)
Optionally, a list of bytes that are used as salt. The default is all zeroes.
encoding(+Atom)
Either utf8 (default) or octet, denoting the representation of Data as in crypto_data_hash/3.

The info/1 option can be used to generate multiple keys from a single master key, using for example values such as key and iv, or the name of a file that is to be encrypted.

This predicate requires OpenSSL 1.1.0 or greater.

See also
- crypto_n_random_bytes/2 to obtain a suitable salt.
- crypto_data_hash/3 to compute a HMAC signature.
  473crypto_data_hkdf(Data, L, Bytes, Options0) :-
  474        functor_hash_options(algorithm, Algorithm, Options0, Options),
  475        option(salt(SaltBytes), Options, []),
  476        option(info(Info), Options, ''),
  477        option(encoding(Enc), Options, utf8),
  478        '_crypto_data_hkdf'(Data, SaltBytes, Info, Algorithm, Enc, L, Bytes).
 ecdsa_sign(+Key, +Data, -Signature, +Options)
Create an ECDSA signature for Data with EC private key Key. Among the most common cases is signing a hash that was created with crypto_data_hash/3 or other predicates of this library. For this reason, the default encoding (hex) assumes that Data is an atom, string, character list or code list representing the data in hexadecimal notation. See rsa_sign/4 for an example.

Options:

encoding(+Encoding)
Encoding to use for Data. Default is hex. Alternatives are octet, utf8 and text.
  495ecdsa_sign(private_key(ec(Private,Public0,Curve)), Data0, Signature, Options) :-
  496    option(encoding(Enc0), Options, hex),
  497    hex_encoding(Enc0, Data0, Enc, Data),
  498    hex_bytes(Public0, Public),
  499    '_crypto_ecdsa_sign'(ec(Private,Public,Curve), Data, Enc, Signature).
  500
  501hex_encoding(hex, Data0, octet, Data) :- !,
  502    hex_bytes(Data0, Data).
  503hex_encoding(Enc, Data, Enc, Data).
 ecdsa_verify(+Key, +Data, +Signature, +Options) is semidet
True iff Signature can be verified as the ECDSA signature for Data, using the EC public key Key.

Options:

encoding(+Encoding)
Encoding to use for Data. Default is hex. Alternatives are octet, utf8 and text.
  516ecdsa_verify(public_key(ec(Private,Public0,Curve)), Data0, Signature0, Options) :-
  517    option(encoding(Enc0), Options, hex),
  518    hex_encoding(Enc0, Data0, Enc, Data),
  519    hex_bytes(Public0, Public),
  520    hex_bytes(Signature0, Signature),
  521    '_crypto_ecdsa_verify'(ec(Private,Public,Curve), Data, Enc, Signature).
  522
  523
  524                 /*******************************
  525                 *            ED25519           *
  526                 *******************************/
 ed25519_new_keypair(-KeyPair) is det
KeyPair is a new Ed25519 key pair, created from 32 random bytes obtained with crypto_n_random_bytes/2. It contains the private key and must be kept absolutely secret. See ed25519_seed_keypair/2.
  534ed25519_new_keypair(KeyPair) :-
  535    crypto_n_random_bytes(32, Seed),
  536    ed25519_seed_keypair(Seed, KeyPair).
 ed25519_seed_keypair(+Seed, -KeyPair) is det
Deterministically derive an Ed25519 key pair from Seed, 32 arbitrary bytes. Seed can be chosen at random using crypto_n_random_bytes/2 or derived from input keying material using crypto_data_hkdf/4.

KeyPair is a hexadecimal atom denoting the key pair in PKCS#8 v2 format (RFC 5958, RFC 8410), the format also used by openssl genpkey -algorithm ed25519. It contains the private key and must be kept absolutely secret. It can be used for signing with ed25519_sign/4, and its public key is obtained with ed25519_keypair_public_key/2.

  552ed25519_seed_keypair(Seed0, KeyPair) :-
  553    key_bytes(Seed0, 32, Seed),
  554    '_crypto_ed25519_seed_public_key'(Seed, PublicKey),
  555    append([[0x30,81,           % SEQUENCE of 81 bytes
  556             2,1,1,             % INTEGER 1: version v2, public key included
  557             0x30,5,            % privateKeyAlgorithm: SEQUENCE of 5 bytes
  558             6,3,43,101,112,    % OBJECT IDENTIFIER 1.3.101.112 (Ed25519)
  559             4,34,4,32],        % privateKey: OCTET STRING of an OCTET STRING
  560            Seed,
  561            [0x81,33,0],        % publicKey: [1] IMPLICIT BIT STRING, 0 unused
  562            PublicKey], Bytes),
  563    hex_bytes(KeyPair, Bytes).
 ed25519_keypair_public_key(+KeyPair, -PublicKey) is det
PublicKey is the public key of KeyPair, a hexadecimal atom. The public key is used for signature verification with ed25519_verify/4 and can be shared freely.
  571ed25519_keypair_public_key(KeyPair, PublicKey) :-
  572    keypair_bytes(KeyPair, Bytes),
  573    length(Prefix, 51),
  574    append(Prefix, Public, Bytes),
  575    hex_bytes(PublicKey, Public).
 ed25519_sign(+KeyPair, +Data, -Signature, +Options) is det
Create an Ed25519 (RFC 8032) signature for Data with the private key of KeyPair, as created by ed25519_new_keypair/1 or obtained with load_private_key/3. Signature is a hexadecimal atom.

Options:

encoding(+Encoding)
Encoding to use for Data. Default is utf8. Alternatives are octet, text and hex. Note that this differs from ecdsa_sign/4 and rsa_sign/4, which default to hex because they are typically applied to a hash of the data. Ed25519 signs the data itself.
  592ed25519_sign(KeyPair, Data0, Signature, Options) :-
  593    keypair_private_key(KeyPair, Seed),
  594    option(encoding(Enc0), Options, utf8),
  595    hex_encoding(Enc0, Data0, Enc, Data),
  596    '_crypto_ed25519_sign'(Seed, Data, Enc, Bytes),
  597    hex_bytes(Signature, Bytes).
 ed25519_verify(+PublicKey, +Data, +Signature, +Options) is semidet
True iff Signature can be verified as the Ed25519 signature for Data, using PublicKey.

Options are as for ed25519_sign/4.

  606ed25519_verify(Key, Data0, Signature0, Options) :-
  607    public_key_bytes(Key, PublicKey),
  608    option(encoding(Enc0), Options, utf8),
  609    hex_encoding(Enc0, Data0, Enc, Data),
  610    key_bytes(Signature0, 64, Signature),
  611    '_crypto_ed25519_verify'(PublicKey, Data, Enc, Signature).
  612
  613keypair_private_key(KeyPair, Seed) :-
  614    keypair_bytes(KeyPair, Bytes),
  615    length(Prefix, 16),
  616    append(Prefix, Rest, Bytes),
  617    length(Seed, 32),
  618    append(Seed, _, Rest).
  619
  620keypair_bytes(private_key(ed25519(KeyPair)), Bytes) :-
  621    !,
  622    key_bytes(KeyPair, 83, Bytes).
  623keypair_bytes(KeyPair, Bytes) :-
  624    key_bytes(KeyPair, 83, Bytes).
  625
  626public_key_bytes(public_key(ed25519(Key)), Bytes) :-
  627    !,
  628    key_bytes(Key, 32, Bytes).
  629public_key_bytes(Key, Bytes) :-
  630    key_bytes(Key, 32, Bytes).
 key_bytes(+Spec, +Length, -Bytes) is det
Bytes is the list of Length bytes denoted by Spec. A list of integers is a list of bytes, as produced by crypto_n_random_bytes/2. Anything else is a hexadecimal atom, string or list of characters, as produced by hex_bytes/2.
  639key_bytes(Spec, Length, Bytes) :-
  640    (   is_list(Spec),
  641        maplist(integer, Spec)
  642    ->  must_be(list(between(0,255)), Spec),
  643        Bytes = Spec
  644    ;   hex_bytes(Spec, Bytes)
  645    ),
  646    (   length(Bytes, Length)
  647    ->  true
  648    ;   domain_error(bytes(Length), Spec)
  649    ).
  650
  651
  652                 /*******************************
  653                 *            X25519            *
  654                 *******************************/
 curve25519_generator(-Generator) is det
Points on Curve25519 are hexadecimal atoms denoting the u-coordinate of the Montgomery curve. Generator is the generator point of Curve25519.
  662curve25519_generator(Generator) :-
  663    length(Zeroes, 31),
  664    maplist(=(0), Zeroes),
  665    hex_bytes(Generator, [9|Zeroes]).
 curve25519_scalar_mult(+Scalar, +Point, -Result) is semidet
Result is the point Scalar*Point on Curve25519, as mandated by X25519 (RFC 7748). Scalar is an integer between 0 and 2^256-1, or 32 bytes. Fails if Point has small order, i.e., if the result would be the point at infinity.

Alice and Bob can use this to establish a shared secret, where Generator is obtained with curve25519_generator/1:

  1. Alice creates a random integer a and sends As = a*Generator to Bob.
  2. Bob creates a random integer b and sends Bs = b*Generator to Alice.
  3. Alice computes Rs = a*Bs.
  4. Bob computes Rs = b*As.
  5. Alice and Bob use crypto_data_hkdf/4 on Rs with suitable (same) parameters to obtain keys and initialization vectors for symmetric encryption.

If a and b are kept secret, this method is considered very secure.

  690curve25519_scalar_mult(Scalar0, Point0, Result) :-
  691    (   integer(Scalar0)
  692    ->  integer_key_bytes(Scalar0, 32, Scalar)
  693    ;   key_bytes(Scalar0, 32, Scalar)
  694    ),
  695    key_bytes(Point0, 32, Point),
  696    '_crypto_curve25519_scalar_mult'(Scalar, Point, Bytes),
  697    hex_bytes(Result, Bytes).
 integer_key_bytes(+Integer, +Length, -Bytes) is det
Bytes is the little-endian representation of Integer using Length bytes, the byte order mandated by X25519.
  704integer_key_bytes(Integer, Length, Bytes) :-
  705    must_be(nonneg, Integer),
  706    (   Integer >> (8*Length) =:= 0
  707    ->  true
  708    ;   domain_error(bytes(Length), Integer)
  709    ),
  710    integer_bytes(Length, Integer, Bytes).
  711
  712integer_bytes(0, _, []) :-
  713    !.
  714integer_bytes(Length0, Integer, [Byte|Bytes]) :-
  715    Byte is Integer /\ 0xff,
  716    Integer1 is Integer>>8,
  717    Length is Length0-1,
  718    integer_bytes(Length, Integer1, Bytes).
 hex_bytes(?Hex, ?List) is det
Relation between a hexadecimal sequence and a list of bytes. Hex is an atom, string, list of characters or list of codes in hexadecimal encoding. This is the format that is used by crypto_data_hash/3 and related predicates to represent hashes. Bytes is a list of integers between 0 and 255 that represent the sequence as a list of bytes. At least one of the arguments must be instantiated. When converting List to Hex, an atom is used to represent the sequence of hexadecimal digits.

Example:

?- hex_bytes('501ACE', Bs).
Bs = [80, 26, 206].
See also
- base64_encoded/3 for Base64 encoding, which is often used to transfer or embed binary data in applications.
  742hex_bytes(Hs, Bytes) :-
  743    (   ground(Hs) ->
  744        string_chars(Hs, Chars),
  745        (   phrase(hex_bytes(Chars), Bytes)
  746        ->  true
  747        ;   domain_error(hex_encoding, Hs)
  748        )
  749    ;   must_be(list(between(0,255)), Bytes),
  750        phrase(bytes_hex(Bytes), Chars),
  751        atom_chars(Hs, Chars)
  752    ).
  753
  754hex_bytes([]) --> [].
  755hex_bytes([H1,H2|Hs]) --> [Byte],
  756    { char_type(H1, xdigit(High)),
  757      char_type(H2, xdigit(Low)),
  758      Byte is High*16 + Low },
  759    hex_bytes(Hs).
  760
  761bytes_hex([]) --> [].
  762bytes_hex([B|Bs]) -->
  763    { High is B>>4,
  764      Low is B /\ 0xf,
  765      char_type(C0, xdigit(High)),
  766      char_type(C1, xdigit(Low))
  767    },
  768    [C0,C1],
  769    bytes_hex(Bs).
 rsa_private_decrypt(+PrivateKey, +CipherText, -PlainText, +Options) is det
 rsa_private_encrypt(+PrivateKey, +PlainText, -CipherText, +Options) is det
 rsa_public_decrypt(+PublicKey, +CipherText, -PlainText, +Options) is det
 rsa_public_encrypt(+PublicKey, +PlainText, -CipherText, +Options) is det
RSA Public key encryption and decryption primitives. A string can be safely communicated by first encrypting it and have the peer decrypt it with the matching key and predicate. The length of the string is limited by the key length.

Options:

encoding(+Encoding)
Encoding to use for Data. Default is utf8. Alternatives are utf8 and octet.
padding(+PaddingScheme)
Padding scheme to use. Default is pkcs1. Alternatives are pkcs1_oaep, sslv23 and none. Note that none should only be used if you implement cryptographically sound padding modes in your application code as encrypting unpadded data with RSA is insecure
Errors
- ssl_error(Code, LibName, FuncName, Reason) is raised if there is an error, e.g., if the text is too long for the key.
See also
- load_private_key/3, load_public_key/2 can be use to load keys from a file. The predicate load_certificate/2 can be used to obtain the public key from a certificate.
 rsa_sign(+Key, +Data, -Signature, +Options) is det
Create an RSA signature for Data with private key Key. Options:
type(+Type)
SHA algorithm used to compute the digest. Values are sha1, sha224, sha256, sha384 or sha512. The default is a cryptographically secure algorithm. If you specify a variable, then it is unified with the algorithm that was used.
encoding(+Encoding)
Encoding to use for Data. Default is hex. Alternatives are octet, utf8 and text.

This predicate can be used to compute a sha256WithRSAEncryption signature as follows:

sha256_with_rsa(PemKeyFile, Password, Data, Signature) :-
    Algorithm = sha256,
    read_key(PemKeyFile, Password, Key),
    crypto_data_hash(Data, Hash, [algorithm(Algorithm),
                                  encoding(octet)]),
    rsa_sign(Key, Hash, Signature, [type(Algorithm)]).

read_key(File, Password, Key) :-
    setup_call_cleanup(
        open(File, read, In, [type(binary)]),
        load_private_key(In, Password, Key),
        close(In)).

Note that a hash that is computed by crypto_data_hash/3 can be directly used in rsa_sign/4 as well as ecdsa_sign/4.

  837rsa_sign(Key, Data0, Signature, Options0) :-
  838    functor_hash_options(type, Type, Options0, Options),
  839    option(encoding(Enc0), Options, hex),
  840    hex_encoding(Enc0, Data0, Enc, Data),
  841    rsa_sign(Key, Type, Enc, Data, Signature).
 rsa_verify(+Key, +Data, +Signature, +Options) is semidet
Verify an RSA signature for Data with public key Key.

Options:

type(+Type)
SHA algorithm used to compute the digest. Values are sha1, sha224, sha256, sha384 or sha512. The default is the same as for rsa_sign/4. This option must match the algorithm that was used for signing. When operating with different parties, the used algorithm must be communicated over an authenticated channel.
encoding(+Encoding)
Encoding to use for Data. Default is hex. Alternatives are octet, utf8 and text.
  862rsa_verify(Key, Data0, Signature0, Options0) :-
  863    functor_hash_options(type, Type, Options0, Options),
  864    option(encoding(Enc0), Options, hex),
  865    hex_encoding(Enc0, Data0, Enc, Data),
  866    hex_bytes(Signature0, Signature),
  867    rsa_verify(Key, Type, Enc, Data, Signature).
 crypto_data_decrypt(+CipherText, +Algorithm, +Key, +IV, -PlainText, +Options)
Decrypt the given CipherText, using the symmetric algorithm Algorithm, key Key, and initialization vector IV, to give PlainText. CipherText must be a string, atom or list of codes or characters, and PlainText is created as a string. Key and IV are typically lists of bytes, though atoms and strings are also permitted. Algorithm must be an algorithm which your copy of OpenSSL knows. See crypto_data_encrypt/6 for an example.
encoding(+Encoding)
Encoding to use for CipherText. Default is utf8. Alternatives are utf8 and octet.
padding(+PaddingScheme)
For block ciphers, the padding scheme to use. Default is block. You can disable padding by supplying none here.
tag(+Tag)
For authenticated encryption schemes, the tag must be specified as a list of bytes exactly as they were generated upon encryption. This option requires OpenSSL 1.1.0 or greater.
min_tag_length(+Length)
If the tag length is smaller than 16, this option must be used to permit such shorter tags. This is used as a safeguard against truncation attacks, where an attacker provides a short tag that is easier to guess.
  903crypto_data_decrypt(CipherText, Algorithm, Key, IV, PlainText, Options) :-
  904        (   option(tag(Tag), Options) ->
  905            option(min_tag_length(MinTagLength), Options, 16),
  906            length(Tag, TagLength),
  907            compare(C, TagLength, MinTagLength),
  908            tag_length_ok(C, Tag)
  909        ;   Tag = []
  910        ),
  911        '_crypto_data_decrypt'(CipherText, Algorithm, Key, IV,
  912                               Tag, PlainText, Options).
  913
  914% This test is important to prevent truncation attacks of the tag.
  915
  916tag_length_ok(=, _).
  917tag_length_ok(>, _).
  918tag_length_ok(<, Tag) :- domain_error(tag_is_too_short, Tag).
 crypto_data_encrypt(+PlainText, +Algorithm, +Key, +IV, -CipherText, +Options)
Encrypt the given PlainText, using the symmetric algorithm Algorithm, key Key, and initialization vector (or nonce) IV, to give CipherText.

PlainText must be a string, atom or list of codes or characters, and CipherText is created as a string. Key and IV are typically lists of bytes, though atoms and strings are also permitted. Algorithm must be an algorithm which your copy of OpenSSL knows about.

Keys and IVs can be chosen at random (using for example crypto_n_random_bytes/2) or derived from input keying material (IKM) using for example crypto_data_hkdf/4. This input is often a shared secret, such as a negotiated point on an elliptic curve, or the hash that was computed from a password via crypto_password_hash/3 with a freshly generated and specified salt.

Reusing the same combination of Key and IV typically leaks at least some information about the plaintext. For example, identical plaintexts will then correspond to identical ciphertexts. For some algorithms, reusing an IV with the same Key has disastrous results and can cause the loss of all properties that are otherwise guaranteed. Especially in such cases, an IV is also called a nonce (number used once). If an IV is not needed for your algorithm (such as 'aes-128-ecb') then any value can be provided as it will be ignored by the underlying implementation. Note that such algorithms do not provide semantic security and are thus insecure. You should use stronger algorithms instead.

It is safe to store and transfer the used initialization vector (or nonce) in plain text, but the key must be kept secret.

Commonly used algorithms include:

'chacha20-poly1305'
A powerful and efficient authenticated encryption scheme, providing secrecy and at the same time reliable protection against undetected modifications of the encrypted data. This is a very good choice for virtually all use cases. It is a stream cipher and can encrypt data of any length up to 256 GB. Further, the encrypted data has exactly the same length as the original, and no padding is used. It requires OpenSSL 1.1.0 or greater. See below for an example.
'aes-128-gcm'
Also an authenticated encryption scheme. It uses a 128-bit (i.e., 16 bytes) key and a 96-bit (i.e., 12 bytes) nonce. It requires OpenSSL 1.1.0 or greater.
'aes-128-cbc'
A block cipher that provides secrecy, but does not protect against unintended modifications of the cipher text. This algorithm uses 128-bit (16 bytes) keys and initialization vectors. It works with all supported versions of OpenSSL. If possible, consider using an authenticated encryption scheme instead.

Options:

encoding(+Encoding)
Encoding to use for PlainText. Default is utf8. Alternatives are utf8 and octet.
padding(+PaddingScheme)
For block ciphers, the padding scheme to use. Default is block. You can disable padding by supplying none here. If padding is disabled for block ciphers, then the length of the ciphertext must be a multiple of the block size.
tag(-List)
For authenticated encryption schemes, List is unified with a list of bytes holding the tag. This tag must be provided for decryption. Authenticated encryption requires OpenSSL 1.1.0 or greater.
tag_length(+Length)
For authenticated encryption schemes, the desired length of the tag, specified as the number of bytes. The default is 16. Smaller numbers are not recommended.

For example, with OpenSSL 1.1.0 and greater, we can use the ChaCha20 stream cipher with the Poly1305 authenticator. This cipher uses a 256-bit key and a 96-bit nonce, i.e., 32 and 12 bytes, respectively:

?- Algorithm = 'chacha20-poly1305',
   crypto_n_random_bytes(32, Key),
   crypto_n_random_bytes(12, IV),
   crypto_data_encrypt("this is some input", Algorithm,
               Key, IV, CipherText, [tag(Tag)]),
   crypto_data_decrypt(CipherText, Algorithm,
               Key, IV, RecoveredText, [tag(Tag)]).
Algorithm = 'chacha20-poly1305',
Key = [65, 147, 140, 197, 27, 60, 198, 50, 218|...],
IV = [253, 232, 174, 84, 168, 208, 218, 168, 228|...],
CipherText = <binary string>,
Tag = [248, 220, 46, 62, 255, 9, 178, 130, 250|...],
RecoveredText = "this is some input".

In this example, we use crypto_n_random_bytes/2 to generate a key and nonce from cryptographically secure random numbers. For repeated applications, you must ensure that a nonce is only used once together with the same key. Note that for authenticated encryption schemes, the tag that was computed during encryption is necessary for decryption. It is safe to store and transfer the tag in plain text.

See also
- crypto_data_decrypt/6.
- hex_bytes/2 for conversion between bytes and hex encoding.
 1040crypto_data_encrypt(PlainText, Algorithm, Key, IV, CipherText, Options) :-
 1041        (   option(tag(AuthTag), Options) ->
 1042            option(tag_length(AuthLength), Options, 16)
 1043        ;   AuthTag = _,
 1044            AuthLength = -1
 1045        ),
 1046        '_crypto_data_encrypt'(PlainText, Algorithm, Key, IV,
 1047                               AuthLength, AuthTag, CipherText, Options).
 crypto_modular_inverse(+X, +M, -Y) is det
Compute the modular multiplicative inverse of the integer X. Y is unified with an integer such that X*Y is congruent to 1 modulo M.
 1056crypto_modular_inverse(X, M, Y) :-
 1057    integer_serialized(X, XS),
 1058    integer_serialized(M, MS),
 1059    '_crypto_modular_inverse'(XS, MS, YHex),
 1060    hex_to_integer(YHex, Y).
 1061
 1062integer_serialized(I, serialized(S)) :-
 1063    must_be(integer, I),
 1064    integer_atomic_sign(I, Sign),
 1065    Abs is abs(I),
 1066    format(atom(A0), "~16r", [Abs]),
 1067    atom_length(A0, L),
 1068    Rem is L mod 2,
 1069    hex_pad(Rem, Sign, A0, S).
 1070
 1071integer_atomic_sign(I, S) :-
 1072    Sign is sign(I),
 1073    sign_atom(Sign, S).
 1074
 1075sign_atom(-1, '-').
 1076sign_atom( 0, '').
 1077sign_atom( 1, '').
 1078
 1079hex_pad(0, Sign, A0, A) :- atom_concat(Sign, A0, A).
 1080hex_pad(1, Sign, A0, A) :- atomic_list_concat([Sign,'0',A0], A).
 1081
 1082pow256(Byte, N0-I0, N-I) :-
 1083    N is N0 + Byte*256^I0,
 1084    I is I0 + 1.
 1085
 1086hex_to_integer(Hex, N) :-
 1087    hex_bytes(Hex, Bytes0),
 1088    reverse(Bytes0, Bytes),
 1089    foldl(pow256, Bytes, 0-0, N-_).
 crypto_generate_prime(+N, -P, +Options) is det
Generate a prime P with at least N bits. Options is a list of options. Currently, the only supported option is:
safe(Boolean)
If Boolean is true (default is false), then a safe prime is generated. This means that P is of the form 2*Q + 1 where Q is also prime.
 1101crypto_generate_prime(Bits, P, Options) :-
 1102        must_be(list, Options),
 1103        option(safe(Safe), Options, false),
 1104        '_crypto_generate_prime'(Bits, Hex, Safe, Options),
 1105        hex_to_integer(Hex, P).
 crypto_is_prime(+P, +Options) is semidet
True iff P passes a probabilistic primality test. Options is a list of options. Currently, the only supported option is:
iterations(N)
N is the number of iterations that are performed. If this option is not specified, a number of iterations is used such that the probability of a false positive is at most 2^(-80).
 1117crypto_is_prime(P0, Options) :-
 1118        must_be(integer, P0),
 1119        must_be(list, Options),
 1120        option(iterations(N), Options, -1),
 1121        integer_serialized(P0, P),
 1122        '_crypto_is_prime'(P, N).
 crypto_name_curve(+Name, -Curve) is det
Obtain a handle for a named elliptic curve. Name is an atom, and Curve is unified with an opaque object that represents the curve. Currently, only elliptic curves over prime fields are supported. Examples of such curves are prime256v1 and secp256k1.

If you have OpenSSL installed, you can get a list of supported curves via:

$ openssl ecparam -list_curves
 crypto_curve_order(+Curve, -Order) is det
Obtain the order of an elliptic curve. Order is an integer, denoting how many points on the curve can be reached by multiplying the curve's generator with a scalar.
 1145crypto_curve_order(Curve, Order) :-
 1146    '_crypto_curve_order'(Curve, Hex),
 1147    hex_to_integer(Hex, Order).
 crypto_curve_generator(+Curve, -Point) is det
Point is the generator of the elliptic curve Curve.
 1154crypto_curve_generator(Curve, point(X,Y)) :-
 1155    '_crypto_curve_generator'(Curve, X0, Y0),
 1156    hex_to_integer(X0, X),
 1157    hex_to_integer(Y0, Y).
 crypto_curve_scalar_mult(+Curve, +N, +Point, -R) is det
R is the result of N times Point on the elliptic curve Curve. N must be an integer, and Point must be a point on the curve.
 1164crypto_curve_scalar_mult(Curve, S0, point(X0,Y0), point(A,B)) :-
 1165    maplist(integer_serialized, [S0,X0,Y0], [S,X,Y]),
 1166    '_crypto_curve_scalar_mult'(Curve, S, X, Y, A0, B0),
 1167    hex_to_integer(A0, A),
 1168    hex_to_integer(B0, B).
 1169
 1170
 1171                 /*******************************
 1172                 *          Sandboxing          *
 1173                 *******************************/
 1174
 1175:- multifile sandbox:safe_primitive/1. 1176
 1177sandbox:safe_primitive(crypto:hex_bytes(_,_)).
 1178sandbox:safe_primitive(crypto:crypto_n_random_bytes(_,_)).
 1179
 1180sandbox:safe_primitive(crypto:crypto_data_hash(_,_,_)).
 1181sandbox:safe_primitive(crypto:crypto_data_context(_,_,_)).
 1182sandbox:safe_primitive(crypto:crypto_context_new(_,_)).
 1183sandbox:safe_primitive(crypto:crypto_context_hash(_,_)).
 1184
 1185sandbox:safe_primitive(crypto:crypto_password_hash(_,_)).
 1186sandbox:safe_primitive(crypto:crypto_password_hash(_,_,_)).
 1187sandbox:safe_primitive(crypto:crypto_data_hkdf(_,_,_,_)).
 1188
 1189sandbox:safe_primitive(crypto:ecdsa_sign(_,_,_,_)).
 1190sandbox:safe_primitive(crypto:ecdsa_verify(_,_,_,_)).
 1191
 1192sandbox:safe_primitive(crypto:ed25519_new_keypair(_)).
 1193sandbox:safe_primitive(crypto:ed25519_seed_keypair(_,_)).
 1194sandbox:safe_primitive(crypto:ed25519_keypair_public_key(_,_)).
 1195sandbox:safe_primitive(crypto:ed25519_sign(_,_,_,_)).
 1196sandbox:safe_primitive(crypto:ed25519_verify(_,_,_,_)).
 1197
 1198sandbox:safe_primitive(crypto:curve25519_generator(_)).
 1199sandbox:safe_primitive(crypto:curve25519_scalar_mult(_,_,_)).
 1200
 1201sandbox:safe_primitive(crypto:rsa_sign(_,_,_,_)).
 1202sandbox:safe_primitive(crypto:rsa_verify(_,_,_,_)).
 1203sandbox:safe_primitive(crypto:rsa_public_encrypt(_,_,_,_)).
 1204sandbox:safe_primitive(crypto:rsa_public_decrypt(_,_,_,_)).
 1205sandbox:safe_primitive(crypto:rsa_private_encrypt(_,_,_,_)).
 1206sandbox:safe_primitive(crypto:rsa_private_decrypt(_,_,_,_)).
 1207
 1208sandbox:safe_primitive(crypto:crypto_data_decrypt(_,_,_,_,_,_)).
 1209sandbox:safe_primitive(crypto:crypto_data_encrypt(_,_,_,_,_,_)).
 1210
 1211sandbox:safe_primitive(crypto:crypto_modular_inverse(_,_,_)).
 1212sandbox:safe_primitive(crypto:crypto_generate_prime(_,_,_)).
 1213sandbox:safe_primitive(crypto:crypto_is_prime(_,_)).
 1214
 1215sandbox:safe_primitive(crypto:crypto_name_curve(_,_)).
 1216sandbox:safe_primitive(crypto:crypto_curve_order(_,_)).
 1217sandbox:safe_primitive(crypto:crypto_curve_generator(_,_)).
 1218sandbox:safe_primitive(crypto:crypto_curve_scalar_mult(_,_,_,_)).
 1219
 1220                 /*******************************
 1221                 *           MESSAGES           *
 1222                 *******************************/
 1223
 1224:- multifile
 1225    prolog:error_message//1. 1226
 1227prolog:error_message(ssl_error(ID, _Library, Function, Reason)) -->
 1228    [ 'SSL(~w) ~w: ~w'-[ID, Function, Reason] ]