Article

Quantum Cybersecurity

Authors:

Dr. Marios Skevofylakas
Data Scientist Data Scientist
Jason Ramchandani
Lead Developer Advocate Lead Developer Advocate

In this article we are looking into Quantum Key Distribution a concept that allows two parties to securely exchange a secret key for further cryptographic processing.  Quantum secure transmission relies on Quantum mechanics principles rather than computational complexity. This means that when QKD is properly implemented, the laws of physics would have to be violated to break the Quantum protocol, something that is practically not possible.

Key concepts in Quantum

Superposition: In classical computing a bit can only have a single, out of two states at any time, 0 or 1, in Quantum computing a Qubit remains at a probabilistic state inside a Bloch sphere until measurement, when it collapses to a 0 or 1 state.

Uncertainty principle: The measurement of a Qubit collapses its superposed state into a certain state. This means man-in-the-middle, eavesdropping or tampering attempts during transmission can be detected on delivery.

No-cloning principle: No possible measurement can distinguish and clone a polarised sequence accurately given different random basis choices.

Quantum Key Distribution

Quantum Key Distribution (QKD) is the process of generating and transmitting a cryptographic key between parties, that can be used for secure communication. The main concept is based on a public transmission channel that can be eavesdropped with ease. The key property however that turns it to a fully secure communication protocol is that, based on Quantum properties, eavesdropped photons have consequently altered state, and we are therefore able to identify them. We can then use the rest of the photons, that have escaped eavesdropping, to generate a cryptographic key, which based on the concept of entanglement, need never be transmitted. Some of the most well-known QKD algorithms published are BB84 [1], a prepare and measure protocol, and BBM92[2] an entanglement-based protocol. BB84, published in 1984, consists of the following steps:

1.        Alice chooses a basis for every bit, rectilinear or diagonal, and sends a series of polarised photons to Bob. Polarisation results into four different states Vertical, Horizontal, Diagonal Right, Diagonal Left depending on basis.

2.        Bob selects a basis for every bit and measures the photons.

3.        Alice and Bob share their basis publicly, compare measurements and discard mismatches.

4.        The remaining measurements generate the secret key.

The important detail to understand here is that should there have been an eavesdropper on the Quantum channel intercepting the communication, photon measurement would have collapsed polarisation into the new measurement injecting errors during reconciliation of the secret key.

Quantum key distribution challenges

Quantum infrastructure: QKD requires specialised Quantum equipment such as encoders converting quantum bits to photons resulting in higher infrastructure costs.

Transmission distance: Photons interacting with atoms during transmission result in photon attenuation (photoelectric effect), which increases with distance, posing a distance cap. These challenges that can be overcome using Quantum repeaters increase costs and infrastructure complexity.

Recreating the concepts

Transmit a series of instrument prices using a Quantum exchanged cryptographic key & LSEG data libraries.

The first steps into this experiment would be to encode the classical candidate secret key to its Quantum Qubits equivalent that could then be transformed to polarised photons for transmission.

There are many strategies to encode classical data to Qubits including:

·      Basis encoding: The simplest one-to-one translation of a classical bit stream to a Qubit stream, for example 0101 would become 0101>.

·      Angle encoding: In angle encoding data is transformed into rotations that generate a quantum state.

·      Phase encoding: is very similar to angle encoding with the difference being that the Qubit’s phase is rotated in proportion to the encoded value.

·      Dense angle encoding: It is a combination of angle and phase encoding allowing for two features to be encoded in one Qubit.

These types of encoding encode one or maximum two features on each Qubit. There is however a different family of encodings that make use of entanglement like:

·      Amplitude encoding: Encodes data into quantum state amplitudes, for example: x = [2,2,1] 

Here, three features are encoded in a 2 Qubits state with zero padding to account for the absence of a fourth feature.

These types of encoding require on average less Qubits for the same number of features and, in theory, can make better use of Quantum characteristics to generate feature spaces. Other such feature maps include:

·      Z Feature map

·      ZZ feature map

·      Pauli feature map

Choosing the Quantum encoding feature map requires careful consideration of number of qubits, resulting circuit depth, degree of entanglement and applicability to the problem at hand. Let’s write an example on angle encoding, the following code encodes to a string to angles, while angle encoding is fast and interpretable, one of its downsides is that we need one qubit to encode every character:

_string = 'Hello Quantum!'

ascii_values = [ord(c) for c in _string]

thetas = [v / 127 * np.pi for v in ascii_values]

The thetas can now be easily applied to Ry qubit rotations.

Once Alice has the classical information encoded in Quantum she can transmit the photon stream to Bob. We will simulate such a scenario in python, following all the transmission specifications for encoding and decoding to photon polarisation. We will encode basis using characters ‘+’ and ‘x’ for orthogonal and diagonal and characters ‘\’, ’/’, ‘!’ and ‘–‘for photon polarisation states. Specifically, the bellow code simulates the following basis – polarisation schemes:

Quantum information exchange 

Let’s follow the whole process step by step, in the repository you can find all the structures needed to fully replicate these sessions from Quantum key exchange to classical secret key establishment, LSEG data instrument pricing ingestions and encrypted data transmission:

Instructions

Step 1 ==> Run Bob.py as the server

Step 2 ==> Execute Alice.ipynb notebook cell by cell

From Alice’s view:

Alice connects to Bob and sends a photon stream:

Alice(client)> Initial secret key ‘Hello Quantum!’ connected with Bob on Quantum channel!

Alice(client)> Sending photon stream to Bob: 

!\/!-!!/!\\!!\!\/--/-\/!!-\!\-///\\/-\--//-!!!///-!-/!!-/---/\/\!\\!/!!-!\\/\\-!!---!-///\--/\/\!--/-\!\/!\!/!/-

Bob calculates and sends back his own photon stream derived from the basis used:

Alice(client)> Received photon stream from Bob:

 !-!!-!\!!--!\-\-!-/!--!!\--!--!!!--!/---!!-!\!!!!-!-!\!-!///!-!-!--\!!\/!--!---\\---!-!!!-//!-!-!//!/-!-!!-!!!!-

Alice(client)> Received photon stream from Bob: !/-\

From Bob’s view:

Bob initialises the Quantum channel detects Alice connecting and reads her photon stream:

Bob(server)> initialising Quantum channel...

Bob(server)> Connected with Alice on Quantum Channel!

Bob(server)> Received photons from Alice: 

!\/!-!!/!\\!!\!\/--/-\/!!-\!\-///\\/-\--//-!!!///-!-/!!-/---/\/\!\\!/!!-!\\/\\-!!---!-///\--/\/\!--/-\!\/!\!/!/-

Bob calculates his own photon stream using his basis and Alice’s photon stream and transmits the stream:

Bob(server)> Sending measured photons to Alice: 

!-!!-!\!!--!\-\-!-/!--!!\--!--!!!--!/---!!-!\!!!!-!-!\!-!///!-!-!--\!!\/!--!---\\---!-!!!-//!-!-!//!/-!-!!-!!!!-

Bob(server)> Ending Quantum connection with Alice: !/-\

Classical information exchange – Establishing the secret key

The next step is establishing a classical channel and exchange basis used from both parties. Then both parties separately calculate the secret key without ever transmitting it using classical means:

From Alice’s view:

Alice sends the basis she is using and receives Bob’s basis:

Alice(client)> Connected with Bob on classical channel!

Alice(client)> Sending basis stream to Bob: 

+xx++++x+xx++x+xx++x+xx+++x+x+xxxxxx+x++xx++++xxx+++x+++x+++xxxx+xx+x++++xxxxx++++++++xxxx++xxxx+++x+x+xx+x+x+x+

Alice(client)> Received basis stream from Bob: 

++++++x++x++x+x+++x++x++x+++x++++xx+x+++xx++x+x+++++xx+++xxx+++x+++x++xx+x+x+x+xx+++++x+xxxxxxxx+xxxxx++x+x+++++

The photon stream and basis stream are used to generate the secret key:

Alice(client)> Received basis stream from Bob: END

Alice(client)> Establishing secret key.

Alice(client)> ESTABLISHED SECRET KEY: 0010001101011110010101000111101000001.

From Bob’s view:

Bob received the basis Alice is using and sends his own:

Bob(server)> initialising classical channel...

Bob(server)> Connected with Alice on classical Channel!

Bob(server)> Received basis stream from Alice: 

+xx++++x+xx++x+xx++x+xx+++x+x+xxxxxx+x++xx++++xxx+++x+++x+++xxxx+xx+x++++xxxxx++++++++xxxx++xxxx+++x+x+xx+x+x+x+

Bob(server)> Sending basis to Alice: 

++++++x++x++x+x+++x++x++x+++x++++xx+x+++xx++x+x+++++xx+++xxx+++x+++x++xx+x+x+x+xx+++++x+xxxxxxxx+xxxxx++x+x+++++

Bob(server)> Ending classical connection with Alice: END

The photon stream and basis stream are used to generate the secret key:

Bob(server)> Establishing secret key.

Bob(server)> ESTABLISHED SECRET KEY: 0010001101011110010101000111101000001.

We are now able to establish a secure channel between the two entities with a secret key that has never been transmitted through classical means.

Retrieving pricing data using LSEG data libraries

Here we will retrieve some data to send to another party though you could well apply the same principles to send transaction or order type data and be sure it has not been tampered with. We will use our LSEG Data Libraries with a Platform Session to retrieve some daily FX pricing data. This is very easy to do with a few lines of code:

    	
            

import lseg.data as ld

from lseg.data.content import historical_pricing

session = ld.session.platform.Definition(

    app_key = "YOUR_APPKEY_HERE",

    grant = ld.session.platform.GrantPassword(

        username = "YOUR_USERNAME",

        password = "YOUR_PASSWORD"

    ),

    signon_control=True

).get_session()

 

ld.session.set_default(session)

session.open()

 

response = historical_pricing.summaries.Definition(

    universe = ["GBP=","EUR=","CHF="],

    fields=["BID"],

    interval = "P1D"

    ).get_data(session)

df = response.data.df

df

    	
            

df_json = df.to_json()

df_json

'{"GBP=":{"1770940800000":1.3648,"1771200000000":1.3625,"1771286400000":1.3567,"1771372800000":1.3491,"1771459200000":1.3462,"1771545600000":1.3482,"1771804800000":1.3489,"1771891200000":1.3487,"1771977600000":1.3556,"1772064000000":1.3481,"1772150400000":1.3484,"1772409600000":1.3405,"1772496000000":1.3354,"1772582400000":1.3372,"1772668800000":1.3355,"1772755200000":1.3411,"1773014400000":1.3435,"1773100800000":1.3416,"1773187200000":1.3411,"1773273600000":1.3341},"EUR=":{"1770940800000":1.1867,"1771200000000":1.185,"1771286400000":1.1853,"1771372800000":1.1782,"1771459200000":1.1772,"1771545600000":1.178,"1771804800000":1.1784,"1771891200000":1.1771,"1771977600000":1.1809,"1772064000000":1.1797,"1772150400000":1.1813,"1772409600000":1.1687,"1772496000000":1.1613,"1772582400000":1.1633,"1772668800000":1.1607,"1772755200000":1.1618,"1773014400000":1.1636,"1773100800000":1.161,"1773187200000":1.1566,"1773273600000":1.151},"CHF=":{"1770940800000":0.7674,"1771200000000":0.7693,"1771286400000":0.7697,"1771372800000":0.7728,"1771459200000":0.775,"1771545600000":0.7758,"1771804800000":0.7746,"1771891200000":0.7736,"1771977600000":0.7723,"1772064000000":0.7738,"1772150400000":0.7687,"1772409600000":0.7789,"1772496000000":0.7815,"1772582400000":0.7789,"1772668800000":0.7806,"1772755200000":0.7757,"1773014400000":0.7771,"1773100800000":0.7782,"1773187200000":0.7802,"1773273600000":0.7858}}'

Encrypting information

Safe encryption relies on robust industry standards depending on the nature of data needs. For data at rest, AES-256 is the used for safety and for data in transit RSA-2048 or ECC are the protocols of choice. 

There are mainly three different types of encryptions:

·      Symmetric: One of the oldest methods using one key to encrypt and decrypt the data. Despite its simplicity and speed the strength of encryption relies on key secrecy making safe transmission paramount.

·      Asymmetric: This type of encryptions uses two keys, a private and a public one. The public one is used for encrypting messages and the private one for decrypting. Mathematical algorithms play a key role in generating two unique keys that can be used. In this scenario the public key can be communicated openly as only the owner of the private key is able to decrypt messages.

·      Hashing: We mention this approach here as it is a method of data transformation although is not considered an encryption method as hashing is a one-way process and while very useful for certain data processes the fact that data is not retrievable does not allow its use in communications settings. 

In this article we are simulating a symmetric encryption scenario using a unique key allowing for higher performance settings. In this setting, secure transmission of the key is of major importance. We have already seen how an encryption key can be exchanged using Quantum transmission making eavesdropping it impossible without tampering it and therefore making the attempt immediately detectable.

We will be using the python cryptography library and more specifically the Fernet encryption module that uses an AES algorithm at its core: The code to encrypt & decrypt a string using a secret key is the following:

    	
            

_secret_key = secret_key[:32]

ascii_key = _secret_key.encode('ascii')

b64_ascii_key = base64.urlsafe_b64encode(ascii_key)

f = Fernet(b64_ascii_key)

encrypted_data = f.encrypt(self.data.encode('utf-8'))

Notice that we use only the first 32 bytes of the Quantum exchanged key as is the constraint for Fernet. Furthermore, in a production environment it is advised to instantiate the Fernet key using PBKDF2HMAC structures:

    	
            

kdf = PBKDF2HMAC(algorithm=hashes.SHA256(), length=32, salt=salt, iterations=1_200_000)

f_key = base64.urlsafe_b64decode(kdf.derive(secret_key))

Now that we have all the elements in place Alice can re-establish the classical connection and transmit the encrypted json string of instrument prices:

From Alice’s view:

Alice(client)> Connected with Bob on classical channel!

Alice(client)> Sending encrypted data to Bob:

b'gAAAAABpqAVSZ9ruxCjVdgRmYWj0mci1-MKzrNgAnXi1KT3Xg1vHdGtqfO7EfGNlJSNUphSd3qod6wYO9eLw9NEoWYtkGnjgqin5_6TZclnXU5g7DjI3qxtjx091l3G-X0iA8AhKrBn7Pfb6I3s1vxqIvlncS-dCwLfAb-E2UPSfYft1W8IjPCbCWTUNGcEFxF0ql0RgQYeVl8uGlSYaeLyLhUzJI78yCIZcaZpLtorYtTFKmgSp5mrgo9OX0wPD3Y5tj_qf0tsBJ6jpLMpOEsYeEO4TOTaxB-4Ij8pNCcT1UNUJaycB77R9VifHoc-9aIpNmraRsBQ-n5uaWHBVMGTsk5a0QY8fLNnF-91eO7gRrC1Afwny9CF-KIUJDE9QbIlUS_9rQC6t2gLF_ngvwThFm0H2FsltJg5A9kglObcXCfZqDu6XDMvz6DULbN6prX4JebfDMPuIRO-U0sSbawj--83qwkflGA=='

Alice(client)> Received response from Bob: END

Alice(client)> ENCRYPTED DATA SENT.

Bob receives the encrypted data, and we can see that successfully de-crypts the message even though the secret key was never transmitted on classical channels:

From Bob’s view:

Bob(server)> Connected with Alice on classical channel for encrypted communications!

Bob(server)> Received encrypted data from Alice: 

gAAAAABpqAVSZ9ruxCjVdgRmYWj0mci1-MKzrNgAnXi1KT3Xg1vHdGtqfO7EfGNlJSNUphSd3qod6wYO9eLw9NEoWYtkGnjgqin5_6TZclnXU5g7DjI3qxtjx091l3G-X0iA8AhKrBn7Pfb6I3s1vxqIvlncS-dCwLfAb-E2UPSfYft1W8IjPCbCWTUNGcEFxF0ql0RgQYeVl8uGlSYaeLyLhUzJI78yCIZcaZpLtorYtTFKmgSp5mrgo9OX0wPD3Y5tj_qf0tsBJ6jpLMpOEsYeEO4TOTaxB-4Ij8pNCcT1UNUJaycB77R9VifHoc-9aIpNmraRsBQ-n5uaWHBVMGTsk5a0QY8fLNnF-91eO7gRrC1Afwny9CF-KIUJDE9QbIlUS_9rQC6t2gLF_ngvwThFm0H2FsltJg5A9kglObcXCfZqDu6XDMvz6DULbN6prX4JebfDMPuIRO-U0sSbawj--83qwkflGA==

Bob(server)> Ending classical connection with Alice: END

Bob(server)> Decrypted data with key calculated from QKD: 

'{"GBP=":{"1770940800000":1.3648,"1771200000000":1.3625,"1771286400000":1.3567,"1771372800000":1.3491,"1771459200000":1.3462,"1771545600000":1.3482,"1771804800000":1.3489,"1771891200000":1.3487,"1771977600000":1.3556,"1772064000000":1.3481,"1772150400000":1.3484,"1772409600000":1.3405,"1772496000000":1.3354,"1772582400000":1.3372,"1772668800000":1.3355,"1772755200000":1.3411,"1773014400000":1.3435,"1773100800000":1.3416,"1773187200000":1.3411,"1773273600000":1.3341},"EUR=":{"1770940800000":1.1867,"1771200000000":1.185,"1771286400000":1.1853,"1771372800000":1.1782,"1771459200000":1.1772,"1771545600000":1.178,"1771804800000":1.1784,"1771891200000":1.1771,"1771977600000":1.1809,"1772064000000":1.1797,"1772150400000":1.1813,"1772409600000":1.1687,"1772496000000":1.1613,"1772582400000":1.1633,"1772668800000":1.1607,"1772755200000":1.1618,"1773014400000":1.1636,"1773100800000":1.161,"1773187200000":1.1566,"1773273600000":1.151},"CHF=":{"1770940800000":0.7674,"1771200000000":0.7693,"1771286400000":0.7697,"1771372800000":0.7728,"1771459200000":0.775,"1771545600000":0.7758,"1771804800000":0.7746,"1771891200000":0.7736,"1771977600000":0.7723,"1772064000000":0.7738,"1772150400000":0.7687,"1772409600000":0.7789,"1772496000000":0.7815,"1772582400000":0.7789,"1772668800000":0.7806,"1772755200000":0.7757,"1773014400000":0.7771,"1773100800000":0.7782,"1773187200000":0.7802,"1773273600000":0.7858}}'

Conclusion

In this article we have simulated the process of Quantum Key Distribution, a secure Quantum transmission technique that ascertains security of transmission. Leveraging on Quantum mechanics physical concepts QKD ensures detection of eavesdropping and tampering attempts during secret key exchanges. We have looked at the process of encoding candidate secret key data to Qubits, simulated the process of exchanging Quantum information and establishing the secret key separately at the two ends and then LSEG data ingestion using LSEG data libraries and symmetrical encryption using Fernet. Finally, we looked at transmission and decryption of the data through a classical connection.

Request Free Trial

Help & Support

Already a customer?

Office locations

Contact LSEG near you