Application Programming Interface

CryptoLyzer is not only a command-line tool but also provides a Python API, making it possible to customize the analysis post-process its result or generate customized output by using a high-level, popular programming language. The main concept of the analysis requires two objects, namely an analyzer and an analyzable. A special kind of client represents the analyzable and implements the strictly necessary part of a certain protocol used by the analyzer to get the relevant in terms of a certain analysis. Different types of protocol – including opportunistic TLS protocols – are implemented by separate client types and different analysis types can also be run separately. However, a full analysis can also be run at once just like using the command-line interface.

TLS

The TLS protocol was used in two ways in the application layer protocol. One case is that the secure layer (TLS) initiated first and after it is successfully established the original application layer protocol (e.g. HTTP, IMAP, …), while in the second case, the application layer protocol (e.g.: SMTP, POP3, …) has an extension, which defines a command – usually called STARTTLS – that a client can use to initiate the secure channel. This second way of working is called opportunistic TLS and requires different client implementations for the different application layer protocols. CryptoLyzer supports all these protocols and also OpenVPN uses TLS to secure its command channel wrapping the original TLS protocol.

from cryptolyzer.tls.client import L7ClientTls, ClientIMAP
from cryptolyzer.tls.client import ClientOpenVpn, ClientOpenVpnTcp

client = L7ClientTls(host, port)
client = ClientIMAP(host, port)
client = ClientOpenVpn(host, port)
client = ClientOpenVpnTcp(host, port)

The TLS protocol always has some versions, meaning that just like in the command-line interface it is the parameter of the analysis in the case of the Python API, whenever the analysis itself version-dependent. As mentioned in the command-line interface there is some protocol version independent analysis. The most obvious one is the analysis of the protocol version supported by a server. In those cases, the protocol version is omitted by the analyzer

>>> from cryptolyzer.tls.client import L7ClientTls
>>> from cryptolyzer.tls.versions import AnalyzerVersions
>>>
>>> analyzer = AnalyzerVersions()
>>> client = L7ClientTls('dh1024.badssl.com', 443)
>>> result = analyzer.analyze(client, None)
>>>
>>> list(map(str, result.versions))
['TLS 1.0', 'TLS 1.1', 'TLS 1.2']
>>>
>>> from cryptolyzer.tls.dhparams import AnalyzerDHParams
>>> from cryptodatahub.tls.version import TlsVersion
>>> from cryptoparser.tls.version import TlsProtocolVersion
>>>
>>> analyzer = AnalyzerDHParams()
>>> protocol_version = TlsProtocolVersion(TlsVersion.TLS1_2)
>>> result = analyzer.analyze(client, protocol_version)
>>>
>>> result.dhparam.key_size
1024

Of course, the different types of analyzers have different types of results, however, the analysis can be performed in the same way as explained below assuming in the examples that a protocol version supported by the analyzable server is stored in the protocol_version variable.

Vulnerabilities

Code Snippet

>>> from cryptolyzer.tls.vulnerabilities import AnalyzerVulnerabilities
>>> from cryptolyzer.tls.client import L7ClientTls
>>>
>>> analyzer = AnalyzerVulnerabilities()
>>> client = L7ClientTls('dh1024.badssl.com', 443)
>>> result = analyzer.analyze(client, protocol_version)
>>>
>>> result.ciphers.lucky13
True
>>> result.versions.early_tls_version
True
>>> result.dhparams.logjam
True

Result Classes

class cryptolyzer.tls.vulnerabilities.AnalyzerResultVulnerabilities(target, ciphers, dhparams, versions)
Class:

Vulnerabilities relate to the server configuration.

Parameters:
  • cipher – Cipher suite related vulnerabilities.

  • dhparam – Diffie-Hellman parameter related vulnerabilities.

  • versions – Protocol version related vulnerabilities.

class cryptolyzer.tls.vulnerabilities.AnalyzerResultVulnerabilityCiphers(sweet32, anonymous_dh, rc4, non_forward_secret, null_encryption, lucky13, freak, export_grade)
Class:

Vulnerabilities relate to cipher suite algorithms. Any attribute represents an vulnerability, which value is true if any of the negotiable cipher suite uses an algorithm affected by the vulnerability.

Parameters:
class cryptolyzer.tls.vulnerabilities.AnalyzerResultVulnerabilityDHParams(dheat, weak_dh)
Class:

Vulnerabilities relate to the protocol versions. Any attribute represents a vulnerability, which value is true if any of the negotiable protocol versions uses an algorithm affected by the vulnerability.

Parameters:

weak_dhWeak DH vulnerability.

class cryptolyzer.tls.vulnerabilities.AnalyzerResultVulnerabilityVersions(inappropriate_version_fallback, drown, early_tls_version, ssl_version)
Class:

Vulnerabilities relate to the protocol versions. Any attribute represents a vulnerability, which value is true if any of the negotiable protocol versions uses an algorithm affected by the vulnerability.

Parameters:

Cipher Suites

Code Snippet

>>> from cryptolyzer.tls.ciphers import AnalyzerCipherSuites
>>> from cryptolyzer.tls.client import L7ClientTls
>>>
>>> analyzer = AnalyzerCipherSuites()
>>> client = L7ClientTls('rc4-md5.badssl.com', 443)
>>> result = analyzer.analyze(client, protocol_version)
>>>
>>> list(map(str, result.cipher_suites))
['TlsCipherSuite.TLS_RSA_WITH_RC4_128_MD5']

Result Classes

class cryptolyzer.tls.ciphers.AnalyzerResultCipherSuites(target, cipher_suites, cipher_suite_preference, long_cipher_suite_list_intolerance)
Class:

Analyzer result relates to the negotiable cipher suites.

Parameters:
  • cipher_suites – the supported cipher suites.

  • extension_supported – whether named group extension is supported.

Elliptic Curves

Code Snippet

>>> from cryptolyzer.tls.curves import AnalyzerCurves
>>> from cryptolyzer.tls.client import L7ClientTls
>>>
>>> analyzer = AnalyzerCurves()
>>> client = L7ClientTls('ecc256.badssl.com', 443)
>>> result = analyzer.analyze(client, protocol_version)
>>>
>>> list(map(str, result.curves))
['TlsNamedCurve.SECP256R1']

Result Classes

class cryptolyzer.tls.curves.AnalyzerResultCurves(target, curves, extension_supported)
Class:

Analyzer result relates to elliptic curve Diffie-Hellman (ECDH) key exchange

Parameters:
  • groups – supported ECDH named groups (can be negotiated using named group extensions)

  • extension_supported – whether named group extension supported

Diffie-Hellman Parameters

Code Snippet

>>> from cryptolyzer.tls.dhparams import AnalyzerDHParams
>>> from cryptolyzer.tls.client import L7ClientTls
>>>
>>> analyzer = AnalyzerDHParams()
>>> client = L7ClientTls('dh1024.badssl.com', 443)
>>> result = analyzer.analyze(client, protocol_version)
>>>
>>> result.dhparam.key_size
1024

Result Classes

class cryptolyzer.tls.dhparams.AnalyzerResultDHParams(target, groups, dhparam, key_reuse)
Class:

Analyzer result relates to Diffie-Hellman (DH) key exchange

Parameters:
  • groups – supported DH named groups (can be negotiated using TLS 1.3 or TLS 1.2 with extension defined in RFC 7919)

  • dhparam – DH paramater sent by the server using TLS versions up to 1.2

  • key_reuse – whether DH keys are shared between different connections (not ephemeral)

Certificate Chains

Code Snippet

>>> from cryptolyzer.tls.pubkeys import AnalyzerPublicKeys
>>> from cryptolyzer.tls.client import L7ClientTls
>>>
>>> analyzer = AnalyzerPublicKeys()
>>> client = L7ClientTls('rsa2048.badssl.com', 443)
>>> result = analyzer.analyze(client, protocol_version)
>>>
>>> certificate_chain = result.pubkeys[0].certificate_chain
>>> leaf_certificate = certificate_chain.items[0]
>>> leaf_certificate.key_type.name
'RSA'
>>>
>>> client = L7ClientTls('ecc256.badssl.com', 443)
>>> result = analyzer.analyze(client, protocol_version)
>>>
>>> certificate_chain = result.pubkeys[0].certificate_chain
>>> leaf_certificate = certificate_chain.items[0]
>>> leaf_certificate.key_type.name
'ECDSA'

Result Classes

class cryptolyzer.tls.pubkeys.AnalyzerResultPublicKeys(target, pubkeys)
Class:

Analyzer result relates to the signature algorithms.

Parameters:

pubkeys – list of the certificate chains sent by the server.

class cryptolyzer.tls.pubkeys.CertificateChainTls(sni_sent, subject_matches, certificate_chain, certificate_status=None, scts=None)
Class:

Analyzer result relates to a certificate chain

Parameters:
  • sni_sent – whether server name indication (SNI) extension is used by the client when the server sent the chain.

  • subject_matches – whether the subject (common name) of the leaf certificate in the chain mathes the analyzed server’s fully qualified domain name.

  • certificate_chain – the list of X.509 certificates sent in the chain.

  • certificate_status – certificate status (OCSP staple) relate to the leaf certificate in the chain.

  • scts – list of signed certificate timestamp (SCT) relate to the certificate in the chain.

Signature Algorithms

Code Snippet

>>> from cryptolyzer.tls.pubkeys import AnalyzerSigAlgos
>>> from cryptolyzer.tls.client import L7ClientTls
>>>
>>> analyzer = AnalyzerSigAlgos()
>>> client = L7ClientTls('rsa2048.badssl.com', 443)
>>> result = analyzer.analyze(client, protocol_version)
>>>
>>> set(map(
... lambda sig_algo: sig_algo.value.signature_algorithm.name,
... result.sig_algos
... ))
{'RSA'}
>>>
>>> client = L7ClientTls('ecc256.badssl.com', 443)
>>> result = analyzer.analyze(client, protocol_version)
>>>
>>> set(map(
... lambda sig_algo: sig_algo.value.signature_algorithm.name,
... result.sig_algos
... ))
{'ECDSA'}

Result Classes

class cryptolyzer.tls.sigalgos.AnalyzerResultSigAlgos(target, sig_algos)
Class:

Analyzer result relates to the signature algorithms

Parameters:

certificate_types – supported signature algorithms (can be negotiated using signature algorithms extension)

Simulations

Code Snippet

>>> from cryptolyzer.tls.simulations import AnalyzerSimulations
>>> from cryptolyzer.tls.client import L7ClientTls
>>>
>>> analyzer = AnalyzerSimulations()
>>> client = L7ClientTls('rc4-md5.badssl.com', 443)
>>> result = analyzer.analyze(client, protocol_version)
>>>
>>> set(map(
... lambda client: client.cipher_suite.name,
... result.succeeded_clients.values()
... ))
{'TLS_RSA_WITH_RC4_128_MD5'}

Result Classes

class cryptolyzer.tls.simulations.AnalyzerResultSimulations(target, succeeded_clients, failed_clients)
Class:

Analyzer result relates to the simulated client applications.

Parameters:
  • succeeded_clients – the list of client applications where the connection initiation was successful,

  • failed_clients – the list of client applications where the connection initiation was failed.

class cryptolyzer.tls.simulations.AnalyzerResultSimulationsSsl(cipher_kind)
Class:

Analyzer result relates to the parameters of the SSL connection initiated between the server and the simulated client application.

Parameters:

cipher_kind – cipher kind.

class cryptolyzer.tls.simulations.AnalyzerResultSimulationsTlsBase(version, cipher_suite, compression_method, encrypt_then_mac, application_layer_protocol)
Class:

Analyzer result relates to the parameters of the TLS connection initiated between the server and the simulated client application.

Parameters:
  • version – protocol version.

  • cipher_suite – cipher suite.

  • compression_method – compression method.

  • application_layer_protocol – application layer protocol.

class cryptolyzer.tls.simulations.AnalyzerResultSimulationsTlsPfs(version, cipher_suite, compression_method, encrypt_then_mac, application_layer_protocol, key_size)
Class:

Analyzer result relates to the parameters of a TLS connection – used a forward secret key-exchange – initiated between the server and the simulated client application.

Parameters:

key_size – Key size of used during the key exchange.

class cryptolyzer.tls.simulations.AnalyzerResultSimulationsTlsPfsDhWellKnown(version, cipher_suite, compression_method, encrypt_then_mac, application_layer_protocol, key_size, well_known)
Class:

Analyzer result relates to the parameters of a TLS connection – used a Diffie-Hellman parameter during the key exchange – initiated between the server and the simulated client application.

Parameters:

well_known – the well-known Diffie-Hellman parameter used during the key exchange.

class cryptolyzer.tls.simulations.AnalyzerResultSimulationsTlsPfsNamedGroup(version, cipher_suite, compression_method, encrypt_then_mac, application_layer_protocol, key_size, named_group)
Class:

Analyzer result relates to the parameters of a TLS connection – used a named group during the key exchange – initiated between the server and the simulated client application.

Parameters:

named_group – Named group used during the key exchange.

SSH

By now, almost exclusively the 2.0 version of the SSH protocol is used in practice, as the 1.5 versions have many security flaws. As a consequence CryptoLyzer supports only the 2.0 version of SSH, however, it can be recognized that a server supports both SSH protocol versions 1 and 2.

Software and Protocol Version

Code Snippet

>>> from cryptolyzer.ssh.versions import AnalyzerVersions
>>> from cryptolyzer.ssh.client import L7ClientSsh
>>>
>>> analyzer = AnalyzerVersions()
>>> client = L7ClientSsh('git.centos.org', 22)
>>> result = analyzer.analyze(client)
>>>
>>> list(map(str, result.protocol_versions))
['SSH 2.0']
>>>
>>> result.software_version.vendor
'OpenSSH'
>>> result.software_version.version
'8.0'

Result Classes

class cryptolyzer.ssh.versions.AnalyzerResultVersions(target, protocol_versions, software_version)
Class:

Analyzer result relates to protocol and software versions

Parameters:
  • protocol_versions – List of supported protocol versions.

  • software_version – Software versions (and vendor) of the server.

Cipher Suites

Code Snippet

>>> from cryptolyzer.ssh.pubkeys import AnalyzerCiphers
>>> from cryptolyzer.ssh.client import L7ClientSsh
>>>
>>> analyzer = AnalyzerCiphers()
>>> client = L7ClientSsh('github.com', 22)
>>> result = analyzer.analyze(client)
>>>
>>> list(map(
... lambda public_key: public_key.host_key_algorithm.value.code,
... result.public_keys
... ))
['ecdsa-sha2-nistp256', 'ssh-ed25519', 'ssh-rsa']

Result Classes

class cryptolyzer.ssh.ciphers.AnalyzerResultCiphers(target, kex_algorithms, host_key_algorithms, encryption_algorithms_client_to_server, encryption_algorithms_server_to_client, mac_algorithms_client_to_server, mac_algorithms_server_to_client, compression_algorithms_client_to_server, compression_algorithms_server_to_client, hassh_fingerprint)
Class:

Analyzer result relates to the negotiable cryptographic algorithms.

Parameters:
  • kex_algorithms – List of the negotiable key exchange algorithms.

  • host_key_algorithms – List of the negotiable host key algorithms.

  • encryption_algorithms_client_to_server – List of the negotiable encryption algorithms in client-to-server direction.

  • encryption_algorithms_server_to_client – List of the negotiable encryption algorithms in server-to-client direction.

  • mac_algorithms_client_to_server – List of the negotiable message authentication code algorithms in client-to-server direction.

  • mac_algorithms_server_to_client – List of the negotiable message authentication code algorithms in server-to-client direction.

  • compression_algorithms_client_to_server – List of the negotiable compression algorithms in client-to-server direction.

  • compression_algorithms_server_to_client – List of the negotiable compression algorithms in server-to-client direction.

  • hassh_fingerprintHASSH fingerprint of the negotiable algorithms.

Diffie-Hellman Parameters

Code Snippet

>>> from cryptolyzer.ssh.dhparams import AnalyzerDHParams
>>> from cryptolyzer.ssh.client import L7ClientSsh
>>>
>>> analyzer = AnalyzerDHParams()
>>> client = L7ClientSsh('git.launchpad.net', 22)
>>> result = analyzer.analyze(client, protocol_version)
>>>
>>> list(map(
... lambda key_exchange: key_exchange.value.key_size,
... result.key_exchange.kex_algorithms
... ))
[2048]
>>>
>>> result.group_exchange.key_sizes
[2048, 3072, 4096, 6144, 7680, 8192]

Result Classes

class cryptolyzer.ssh.dhparams.AnalyzerResultDHParams(target, key_exchange, group_exchange)
Class:

Analyzer result relates to Diffie-Hellman (DH) key exchange

Parameters:
  • key_exchange – Key exchange related analyzer result, when supported.

  • group_exchange – Group exchange related analyzer result, when supported.

class cryptolyzer.ssh.dhparams.AnalyzerResultGroupExchange(gex_algorithms=<deep_iterable validator for iterables of <instance_of validator for type <enum 'SshKexAlgorithm'>>>, key_sizes=<deep_iterable validator for iterables of <instance_of validator for type <class 'cryptodatahub.common.key.PublicKeySize'>>>, bounds_tolerated=<instance_of validator for type <class 'bool'>>)
Class:

Analyzer result relates to DH group exchange

Parameters:
  • gex_algorithms – List of the negotiable group exchange algorithms.

  • key_sizes – List of the negotiable key size during the group exchange.

  • bounds_tolerated – Whether server tolerate the range of the supported key sizes by the client.

class cryptolyzer.ssh.dhparams.AnalyzerResultKeyExchange(kex_algorithms=<deep_iterable validator for iterables of <instance_of validator for type <enum 'SshKexAlgorithm'>>>)
Class:

Analyzer result relates to DH key exchange

Parameters:

kex_algorithms – List of the negotiable key exchange algorithms.

Host Keys and Certificates

Code Snippet

>>> from cryptolyzer.ssh.pubkeys import AnalyzerPublicKeys
>>> from cryptolyzer.ssh.client import L7ClientSsh
>>>
>>> analyzer = AnalyzerPublicKeys()
>>> client = L7ClientSsh('git.launchpad.net', 22)
>>> result = analyzer.analyze(client)
>>>
>>> list(map(
... lambda public_key: public_key.host_key_algorithm.value.code,
... result.public_keys
... ))
['ssh-rsa']
>>>
>>> print(result.public_keys[0].public_key.pem)
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxBURMAQ9sntl63NklXFJ
pieODBdQQgd1tdTU2oqs1Y+12Z0JoFmZPVGnR1WNsAV73pXAzudTDzeaMyYxQJJ8
NPaz+1zESTJQDi0iFaFOg0RdbtY/JCVWPnX4gx4Xku/rIgA565m/Bxp9sUEOhCQ4
wF68NcefMeXmY0NDxVnSPqUU3WBr1pKR3VyhTumvf5Q8eLqPTAp3jxBov0J5Apiq
iwgVJWDWWEYgfJ1XntrTBdJo1fMZNayfv1D/vPe/hVxUfcPwdRD0Y4kN+WTUGSjz
+IrMT7cjLgkJGWO3JFq+WLMpTX7zXMhg5ztV2s2YSe9a8w6YtUZpxVwVuYvtnZts
uwIDAQAB
-----END PUBLIC KEY-----

Result Classes

class cryptolyzer.ssh.pubkeys.AnalyzerResultPublicKeys(target, public_keys)
Class:

Analyzer result relates to a host keys/certificates.

Parameters:

public_keys – List of host keys/certificates.

HTTP(S)

By now, exclusively the 1.1 version of the HTTP protocol is used in practice, so CryptoLyzer supports only the 1.1 version of the HTTP protocol. The analyses work both with the plain text version of the protocol (HTTP) and the TLS-secured version (HTTPS).

Headers

Code Snippet

>>> from cryptolyzer.httpx.headers import AnalyzerHeaders
>>> from cryptolyzer.httpx.client import L7ClientHttp
>>>
>>> analyzer = AnalyzerHeaders()
>>> client = L7ClientHttp('https://hstspreload.org/')
>>> result = analyzer.analyze(client, None)
>>>
>>> header = next(filter(
... lambda header: isinstance(header, HttpHeaderFieldSTS),
... result.headers
... ))
>>>
>>> header.value.preload.value
True
>>> header.value.max_age.value
datetime.timedelta(days=365)

Result Classes

class cryptolyzer.httpx.headers.AnalyzerResultHeaders(target, headers)
Class:

Analyzer result relates to the response headers.

Parameters:

versions – List of the response headers.

DNSSEC

Code Snippet

>>> from cryptolyzer.dnsrec.dnssec import AnalyzerDnsSec
>>> from cryptolyzer.dnsrec.client import L7ClientDns
>>>
>>> analyzer = AnalyzerDnsSec()
>>> client = L7ClientDns('cloudflare.com')
>>>
>>> result = analyzer.analyze(client)
>>>
>>> list(map(
... lambda dns_key: set(map(lambda flag: flag.name, dns_key.flags)),
... result.dns_keys
... ))
[{'DNS_ZONE_KEY'}, {'DNS_ZONE_KEY'}, {'SECURE_ENTRY_POINT', 'DNS_ZONE_KEY'}]
>>>
>>> list(map(
... lambda dns_key: dns_key.key_tag,
... result.dns_keys
... ))
[43038, 32553, 57355]
>>>
>>> list(map(
... lambda digital_signature: digital_signature.key_tag,
... result.digital_signatures
... ))
[57355]

Result Classes

class cryptolyzer.dnsrec.dnssec.AnalyzerResultDnsSec(target, dns_keys, delegation_signer, resource_record_signatures)
Class:

Analyzer result relates to DNSSEC keys end signatures.

Parameters:
  • dns_keys – List of the public keys that can be used to verify digital signatures (DNSKEY).

  • delegation_signer – List of the signatures relate to delegation signer (DS).

  • resource_record_signatures – List of the digital signatures for the record set (RRSIG).