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: AnalyzerTargetBase | L7TransferBase, 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, logjam, 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: AnalyzerTargetBase | L7TransferBase, 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: AnalyzerTargetBase | L7TransferBase, 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: AnalyzerTargetBase | L7TransferBase, 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: AnalyzerTargetBase | L7TransferBase, 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: AnalyzerTargetBase | L7TransferBase, 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: ~cryptolyzer.common.result.AnalyzerTargetBase | ~cryptolyzer.common.transfer.L7TransferBase, succeeded_clients=<optional validator for <deep_mapping validator for objects mapping <instance_of validator for type <class 'cryptodatahub.common.client.ClientVersionedParamsBase'>> to <instance_of validator for type (<class 'cryptolyzer.tls.simulations.AnalyzerResultSimulationsTlsBase'>, <class 'cryptolyzer.tls.simulations.AnalyzerResultSimulationsSsl'>)>> or None>, failed_clients=<optional validator for <deep_mapping validator for objects mapping <instance_of validator for type <class 'cryptodatahub.common.client.ClientVersionedParamsBase'>> to <instance_of validator for type <class 'cryptolyzer.common.exception.ErrorParams'>>> or None>)
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: AnalyzerTargetBase | L7TransferBase, 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: AnalyzerTargetBase | L7TransferBase, 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: AnalyzerTargetBase | L7TransferBase, 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: AnalyzerTargetBase | L7TransferBase, public_keys)
Class:

Analyzer result relates to a host keys/certificates.

Parameters:

public_keys – List of host keys/certificates, each paired with its SSHFP DNS verification status.

class cryptolyzer.ssh.pubkeys.SshFpVerificationStatus(value)

An enumeration.

IKE

Versions

The IKE protocol has two different versions, meaning that just like in the command-line interface it is the parameter of the analysis in the case of the Python API, so before running the analysis the protocol version must be determined.

>>> from cryptolyzer.ike.client import L7ClientIPsecBase
>>> from cryptolyzer.ike.versions import AnalyzerVersions
>>>
>>> analyzer = AnalyzerVersions()
>>> client = L7ClientIPsecBase('moon.strongswan.org', 500)
>>> result = analyzer.analyze(client, None)
>>>
>>> [str(version) for version in result.versions]
['IKEv1 (0)', 'IKEv2 (0)']

Extensions

Code Snippet

>>> from cryptodatahub.ike.version import IkeVersion
>>>
>>> from cryptolyzer.ike.client import L7ClientIPsecBase
>>> from cryptolyzer.ike.extensions import AnalyzerExtensions
>>>
>>> analyzer = AnalyzerExtensions()
>>> client = L7ClientIPsecBase('moon.strongswan.org', 500)
>>> result = analyzer.analyze(client, IkeVersion.V2)
>>>
>>> result.ikev2_fragmentation_supported
True

Result Classes

class cryptolyzer.ike.extensions.AnalyzerResultIkev1Extensions(target: AnalyzerTargetBase | L7TransferBase, nat_traversal_supported, dead_peer_detection_supported, vendor_ids)

IKEv1 extensions advertised by the responder during Phase 1.

class cryptolyzer.ike.extensions.AnalyzerResultIkev2Extensions(target: AnalyzerTargetBase | L7TransferBase, ikev2_fragmentation_supported, signature_hash_algorithms_supported, intermediate_exchange_supported, use_ppk_supported, redirect_supported, childless_ikev2_supported, multiple_auth_supported, nat_detection_source_ip_supported, nat_detection_destination_ip_supported, nat_traversal_supported, vendor_ids)

IKEv2 extensions advertised by the responder during IKE_SA_INIT.

Public Keys

Code Snippet

>>> from cryptodatahub.ike.version import IkeVersion
>>>
>>> from cryptolyzer.ike.client import L7ClientIPsecBase
>>> from cryptolyzer.ike.pubkeys import AnalyzerPublicKeys
>>>
>>> analyzer = AnalyzerPublicKeys()
>>> client = L7ClientIPsecBase('moon.strongswan.org', 500)
>>> result = analyzer.analyze(client, IkeVersion.V1)

Result Classes

class cryptolyzer.ike.pubkeys.AnalyzerPublicKeys
class cryptolyzer.ike.pubkeys.AnalyzerResultPublicKeys(target: AnalyzerTargetBase | L7TransferBase, public_keys: list[CertificateChainIke])
Parameters:

public_keys – List of certificate-bearing rows the responder offered (one per cert_encoding).

class cryptolyzer.ike.pubkeys.CertificateChainIke(cert_encoding, identification, auth_method_used, signature_length, transport, certificate_chain=None, raw_bytes=None, auth_envelope=None)

One certificate-bearing result row from an IKE pubkeys probe.

There is one row per certificate encoding the responder offered. Only one of certificate_chain / raw_bytes is populated, picked by the encoding:

  • X.509 signature certificate / PKCS#7-wrapped X.509 certificate → certificate_chain populated with the parsed X.509 chain.

  • Certificate revocation list / authority revocation list → raw_bytes populated with the raw payload.

  • Other encodings (PGP, DNS-signed key, Kerberos token, SPKI, X.509 attribute) are out of scope per RFC 4945 §3.2.1 and currently rejected by the analyzer.

Parameters:
  • identification – Responder’s identification payload.

  • auth_method_used – Authentication method the responder offered (RSA signature, ECDSA over P-256 / P-384 / P-521 — selected on the analyzer side).

  • signature_length – Octet length of the responder’s signature payload (analytics; tells RSA modulus size or ECDSA curve from r||s).

  • transport – How the certificate reached the analyzer — see Transport.

  • auth_envelope – IKEv2-only — populated when the responder’s authentication payload uses the RFC 7427 digital signature envelope. Carries the algorithm-identifier OID + raw signature bytes extracted from the payload’s authentication data field. None for IKEv1 and for the IKEv2 legacy authentication methods.

fingerprint() bytes

Stable dedup key for one probe outcome. When an X.509 chain is present, hashes the leaf certificate’s DER so probes returning the same end-entity certificate collapse to one row regardless of the authentication method that selected them. When only raw payload bytes are present (raw public key or other non-X.509 encoding), those bytes are the identifier. When neither is present (authentication succeeded without a certificate payload), falls back to the responder’s identification + authentication method so two distinct identity-only rows do not collide.

classmethod from_ikev1_aggressive_response(response: IsakmpMessage, auth_method: Ikev1AuthenticationMethod) CertificateChainIke | None

Return None if IDir or SIG_R missing (RFC 2409 §5.1). SIG_R present but CERT absent yields a cert-less row (cert_encoding=None / certificate_chain=None / raw_bytes=None) — distinguishes send_cert=never from probe failure.

classmethod from_ikev2_eap_inner_payloads(inner_payloads: list[Any]) CertificateChainIke | None

Return None if IDr or AUTH missing (responder refused EAP-mode or SK envelope decrypted to something unexpected). Payload chain per RFC 7296 §2.16: IDr, [CERT,] AUTH, [EAP].

class cryptolyzer.ike.pubkeys.IkeIdentification(id_type: IdType, protocol_id: IpProtocolNumber, port: int, id_data: bytes | bytearray)

One IKEv1 IDENTIFICATION payload (RFC 2408 §3.8, RFC 2407 §4.6.2) captured from a peer.

classmethod ikev1_id_type_from_ikev2(id_type: IdType) IdType

IPv4/IPv6 address, FQDN, and DER-encoded distinguished/general name pass through unchanged; the IKEv2-only e-mail address falls back to user FQDN; every other IKEv2-only identity (Fibre Channel name, NULL identity, …) falls back to the opaque key ID.

static wire_bytes(id_payload: Any) bytes

Mirror per-type _encode_identifier logic on cryptoparser IkeIdentification*Mixin mixins via public identifier to avoid poking cryptoparser’s protected methods.

class cryptolyzer.ike.pubkeys.Transport(value)

An enumeration.

Public Key Requests

Code Snippet

>>> from cryptodatahub.ike.version import IkeVersion
>>>
>>> from cryptolyzer.ike.client import L7ClientIPsecBase
>>> from cryptolyzer.ike.pubkeyreq import AnalyzerPublicKeyRequest
>>>
>>> analyzer = AnalyzerPublicKeyRequest()
>>> client = L7ClientIPsecBase('moon.strongswan.org', 500)
>>> result = analyzer.analyze(client, IkeVersion.V2)

Result Classes

IKE public-key-request analyzer.

class cryptolyzer.ike.pubkeyreq.AnalyzerPublicKeyRequest

Enumerate which trust anchors the responder requests from the initiator via CERTREQ payloads (RFC 2408 §3.10 for IKEv1, RFC 7296 §3.7 for IKEv2). Runs the shared pubkey probe grid and walks each response’s CERTREQ payloads for the responder’s trusted-CA hint list.

class cryptolyzer.ike.pubkeyreq.AnalyzerResultIkev1PublicKeyRequest(target: AnalyzerTargetBase | L7TransferBase, certificate_types, distinguished_names)
Class:

Analyzer result for IKEv1 CERTREQ payloads (RFC 2408 §3.10).

Parameters:
  • certificate_types – Certificate Encodings the responder advertised (deduplicated, first-seen order).

  • distinguished_names – Parsed X.501 subject-DN dicts extracted from each X.509 CERTREQ (deduplicated, first-seen order). None when the responder sent no CERTREQ payloads.

class cryptolyzer.ike.pubkeyreq.AnalyzerResultIkev2PublicKeyRequest(target: AnalyzerTargetBase | L7TransferBase, certificate_types, trusted_ca_hashes)
Class:

Analyzer result for IKEv2 CERTREQ payloads (RFC 7296 §3.7).

Parameters:
  • certificate_types – Certificate Encodings the responder advertised (deduplicated, first-seen order).

  • trusted_ca_hashes – 20-octet SHA-1(SPKI) hashes extracted from every X.509 CERTREQ’s concatenated authority field (deduplicated, first-seen order). None when the responder sent no CERTREQ payloads.

Simulations

The proposal set to be offered is given by the axis arguments of the command-line interface, so the analyzer takes them from a parsed argument namespace instead of a constructor parameter. The axis tokens can be written in the dialect of strongswan, libreswan, openswan, or in iana registry names.

Code Snippet

>>> from cryptodatahub.ike.version import IkeVersion
>>>
>>> from cryptolyzer.__main__ import get_argument_parser
>>> from cryptolyzer.ike.client import L7ClientIPsecBase
>>> from cryptolyzer.ike.simulations import AnalyzerIkev1Simulations
>>>
>>> parser = get_argument_parser()
>>> arguments = parser.parse_args([
...     'ikev1', 'simulations',
...     '--encryption-algorithm', 'aes128',
...     '--hash-algorithm', 'sha256',
...     '--authentication-method', 'psk',
...     '--diffie-hellman-group', 'modp1536',
...     'ipsec://moon.strongswan.org',
... ])
>>>
>>> analyzer = AnalyzerIkev1Simulations()
>>> analyzer.parse_arguments(parser, arguments)
>>> client = L7ClientIPsecBase('moon.strongswan.org', 500)
>>> result = analyzer.analyze(client, IkeVersion.V1)

Result Classes

class cryptolyzer.ike.simulations.AnalyzerResultIkev1Simulations(target: AnalyzerTargetBase | L7TransferBase, succeeded_clients: dict[str, Ikev1ProposalProbeResult], failed_clients: dict[str, Ikev1ProposalProbeResult])
class cryptolyzer.ike.simulations.AnalyzerResultIkev2Simulations(target: AnalyzerTargetBase | L7TransferBase, succeeded_clients: dict[str, Ikev2ProposalProbeResult], failed_clients: dict[str, Ikev2ProposalProbeResult])
Class:

Analyzer result relates to the simulated IKEv2 proposal sets.

Parameters:
  • succeeded_clients – the clients whose offered proposal set the responder accepted, keyed by client name.

  • failed_clients – the clients whose offered proposal set the responder rejected, keyed by client name.

class cryptolyzer.ike.simulations.Ikev2ProposalProbeResult(offered: Ikev2TransformAxes, negotiated: Ikev2CipherSuite | None = None, notify: NotifyType | None = None)

Outcome of offering one user-supplied IKEv2 proposal set to a responder.

Parameters:
  • offered – the per-axis algorithm set that was offered.

  • negotiated – the transform combination the responder selected, when it answered with a full SA.

  • notify – the notify the responder replied with, when it did not answer with a selected SA.

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: AnalyzerTargetBase | L7TransferBase, 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: AnalyzerTargetBase | L7TransferBase, 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).