Cryptography with Prolog: How do I begin?

Skip to first unread message

Markus Triska

Sep 15, 2017, 10:37:46 AM9/15/17
to SWI-Prolog
Hi all,

the upcoming stable release, SWI-Prolog 7.6, will provide cryptographic functionality that has never before been available in any Prolog system.

To encourage the use of these features, I have uploaded a document that explains how you can call and combine the new predicates in typical cases:

The examples include: securely storing user passwords, verifying digital signatures, and encrypting data with a password.

You can try all included queries and code samples already today, using the current SWI-Prolog development release (7.5.15) and OpenSSL 1.1.0.

I hope that the newly available features help you to implement Prolog applications that achieve very high security standards.

If you need any additional features, or if you have any questions or comments, please let me know any time!

Thank you and all the best,

Jan Burse

Sep 17, 2017, 1:31:39 PM9/17/17
to SWI-Prolog
If you want to make crypo transparent, you should extend the support
for URLs in SWI-Prolog. This is like the end-user view of crypto, and
not the developer view of crypto.

So it would address the need for those who for example just want
to establish a connection to a HTTPS web site without much husse.
I doubt that we need an extra open/[3,4] for that.

I have aready promoted extending ISO core Prolog streams to also
support all kind of connections for a while. I remember discussions
with Logtalk, why we would then drop the requirement that

stream_property really keeps a table of all connections. But maybe
different design considerations are possible. Last week I figured out,
that absolute_file_name/[2,3] can be used to let a web site normalize
paths, and make visible when a HTTPS connection is requested.

This does not (yet?) work in SWI-Prolog I only get:

?- absolute_file_name('', X).
X = 'c:/users/jan burse/documents/prolog/http:/'.

On the other hand for the upcoming release of Jekejeke Prolog I have:

?- absolute_file_name('', X).
X = ''

Note the magic that happend (by virtue of the HTTP 301 code):
    - The host was automatically prefixed by 'www.'
    - The protocol was automatically changed from 'http:' to 'https:'

This is a very nice canonization without the use of an other infrastructure
from the internet, namely the domain name server infrastructure. Because
this infrastructure usually yields nonsense for a web server:

I guess the nonsense happens because of modern CDN technique,
a fact that I had to learn last weak also.

?- use_module(library(system/domain)).
% 1 consults and 0 unloads in 16 ms.
?- host_lookup('', X).
X = ''
?- host_lookup(X, '').
X = ''
?- host_lookup('', X).
X = ''
?- host_lookup(X, '').
X = ''

For the end-user, extending the absolute_file_name to URLs
is very comfortabke. For example then reading a HTTPS web
site works as easily as:

?- open('', read, X, [alias(test)]).
X = 0r4bc68116
?- read_line(test, X).
X = 'User-agent: * '
?- close(test).

See also my blog post here:

Disclaimer: This realization wasn't planned. I was first
researching into Puny code. But this web server based to
find normal URLs is very welcome.

By the approach of just using the ISO core Prolog API, I
spare additional predicates such as for example http_open/3.
I could add all the http_open/3 options to open/[3,4] as well.

I did the following test here (providing a HTTP URL which
will be redirected to a HTTPS URL):

Welcome to SWI-Prolog (threaded, 64 bits, version 7.6.0-rc1)
SWI-Prolog comes with ABSOLUTELY NO WARRANTY. This is free software.

?- use_module(library(http/http_open)).

ᄀ?- use_module(library(http/http_ssl_plugin)).
ERROR: c:/program files/swipl/library/
        c:/program files/swipl/library/ Initialization goal raised exception:
        '$open_shared_object'/3: Das angegebene Modul wurde nicht gefunden.

?- http_open('', X, []).
ERROR: Undefined procedure: ssl:'_ssl_context'/4
ERROR:   However, there are definitions for:
ERROR:         ssl:ssl_context/3

But after the first error it probably didn't make any sense to
continue testing. Is the SSL plugin not supported on Windows?
Or is this a smal problem of the release  version 7.6.0-rc1 I was using?

I was using this recommendation here:

But I don't know whether there is a recommendation to
get the redirected URL before actually establishing the connection.
Is this possible?

Markus Triska

Sep 18, 2017, 2:03:41 PM9/18/17
to SWI-Prolog
Hi Jan,

On Sunday, September 17, 2017 at 7:31:39 PM UTC+2, Jan Burse wrote:

But after the first error it probably didn't make any sense to
continue testing. Is the SSL plugin not supported on Windows?
Or is this a smal problem of the release  version 7.6.0-rc1 I was using?

It is a small problem with 7.6.0-rc1 and Jan pushed a fix so that as of tomorrow's daily build (and then with 7.6.0-rc2), it should work!

Once it works, you get for example:

?- http_open('', Stream, [final_url(Final)]).
Stream = <stream>(0x7fc6ed020c00),

This shows that the HTTP --> HTTPS redirect does indeed happen, and a TLS session is created.

Thank you for trying this, and I hope it works for you with tomorrow's build!

It is an interesting idea to use open/3 for this: I frequently need to open HTTP and HTTPS streams, and I always wondered why http_open/3 is not at least autoloaded:

All the best,

Jan Burse

Sep 18, 2017, 3:11:24 PM9/18/17
to SWI-Prolog

Didn't pay attention to this fine detail, the final_url/1 option.

BTW do you support puny code (under the hood)?
This one gives also a nice test case (German city with umlaut):


Markus Triska

Sep 19, 2017, 2:47:24 PM9/19/17
to SWI-Prolog
Hi Jan,

On Monday, September 18, 2017 at 9:11:24 PM UTC+2, Jan Burse wrote:

Didn't pay attention to this fine detail, the final_url/1 option.

In this context, the option redirect/1 (or, more generally, max_redirect/1) is also extremely useful: Together with the status_code/1 option, it can be used to prevent redirects. It is sometimes important to rewrite redirects, for example in (reverse) proxy servers, and in such cases we want to perform the redirect ourselves instead of relying on the HTTP framework. This feature is used for example in Proloxy to rewrite redirects so that the correct target service is used even though the service itself is not aware of the proxy.

BTW do you support puny code (under the hood)?
This one gives also a nice test case (German city with umlaut):


With SWI, I get:

?- http_open('http://nü', Stream, [redirect(false)]).
ERROR: Socket error: Unknown error 0
ERROR:   [16] throw(error(socket_error('Unknown error 0'),_8894))

This arises already at the HTTP layer, so the SSL bindings are not (yet) involved in this error.

It is, however, also a security issue to support such URLs, because they give rise to a certain class of attacks:

Therefore, this should definitely also be considered in connection with HTTPS.

Are you considering ways to mitigate such attacks?

All the best!

Jan Burse

Sep 19, 2017, 6:22:56 PM9/19/17
to SWI-Prolog
Try any web browser, type in http://nü , it
will do the redirect for you. No warnings no nothing:

Chrome: http://nü  -->
Edge: http://nü ->
Seamonkey: http://nü -->

DNS does only understand ASCII, so you have to ACE the URL first.

?- uri_puny('http://nü', X).
X = ''

I am using puny coding during all connections, because in Java there
is no other way (so far my testing shows), to access Unicode domain

names. The libary I am using is this:

You need to puny code the authority part of an URL. The library, through
open/[3,4] also allows to open homographic similar domain names.
There is no restriction what ever built-in. Maye you want to contact
the server and ask for further credentials, an imposter might not

give you the correct information, so its necessary that you can
connect to homographic similar domain names, you might anyway
have further validation steps in the application layer. Since puny code
works, it seems that nowhere in the stack any such checks based
on the domain name are done. And for example browsers, agains
the usual myth, done use puny code when something is not ASCII.
They do the contrary, they convert puny code back to Unicode.
Try this, and error in the nü web site URL,

I changed the country form "de" to "com":

Here is what the browsers do with this beast (Some
browsers try the prefix www. on their own, but all
browser do a Un-Puny code):

Chrome: -->
http://nü and Error Page

Edge: -->
http://nü and Error Page

Seamonkey: -->
http://www.nü and Error Page

In my opinion this is fine. You could do more as
described here, but maybe the whole domain name
system needs a different approach:

Like some lexical backend in the domain servers,
with world wide application. Most likely domain servers
will look different in 2525. But today is only 2017.

Jan Burse

Sep 19, 2017, 6:26:50 PM9/19/17
to SWI-Prolog
The recommendation goes to the domain owner:

"If you are buying a domain in a registry which does not have proper
anti-spoofing protections (like .com), it is sadly the responsibility of
domain owners to check for whole-script homographs and register them."

From the same article:

Jan Burse

Sep 19, 2017, 7:35:12 PM9/19/17
to SWI-Prolog
I guess I am mocking Paul V. Mockapetris.

Jan Burse

Sep 20, 2017, 6:35:44 AM9/20/17
to SWI-Prolog
The following paper sums up the current DNS:

Development of the Domain Name System
Paul V. Mockapetris, Kevin J. Dunlap - 1988

You find some fundamental decisions here: 

2.2 The name space
Labels are variable-length strings of octets, and each
octet in a label can be any 8-bit value. The zero length
label is reserved for the root. Name space searching
operations (for operations defined at present) are done
in a case-insensitive manner (assuming ASCII). Thus
the labels “Paul”, “paul”, and “PAUL”, would match
each other.

And why it might be important to either access the
DNS even for strange domain names. The DNS itself
could give further hints:

2.2 The name space
"but the default assumption is that
the only way to tell definitely what a name represents
is to look at the data associated with the name."

But if the DNS is corrupted, either through the end zones or
intermediary zoones, because they cannot be trusted.

I guess this doesn't help either...

Jan Burse

Sep 20, 2017, 6:42:28 AM9/20/17
to SWI-Prolog
There was also the idea to use the DNS to censor the internet:

Jan Burse

Sep 22, 2017, 11:07:50 AM9/22/17
to SWI-Prolog
We might begin with data types. In Java, most of crypto is done
with byte[] (array of primitive byte), and since in Java byte is fixed

as octet its kind of internet compatible... Same in ISO core Prolog
byte is fixed as octet. And this already looks good:

library(crypto): Cryptography and authentication library

Bytes, bytes, bytes, etc... Cool!

And this probably due to Markus Triska:

:- 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.

What happens if Bs is just a variable:

Welcome to SWI-Prolog (threaded, 64 bits, version 7.5.8)
SWI-Prolog comes with ABSOLUTELY NO WARRANTY. This is free software.

?- bytes_integer(L,X).

L = [],
X = 0

L = [X],
X in 0..255

L = [_3136, _3142],
_3136 in 0..255,
_3204 in 0..65280,
_3142 in 0..255,X in 0..65535 .

And then you need:

crypto_data_encrypt(+PlainText, +Algorithm, +Key, +IV, -CipherText, +Options)
Encoding to use for PlainText. Default is utf8. Alternatives are utf8 and octet.


Am Freitag, 15. September 2017 16:37:46 UTC+2 schrieb Markus Triska:
Reply all
Reply to author
0 new messages