Differences

This shows you the differences between two versions of the page.

Link to this comparison view

ac:laboratoare:11 [2025/11/06 10:05]
marios.choudary
ac:laboratoare:11 [2025/11/06 10:36] (current)
marios.choudary
Line 80: Line 80:
 ==== 3. PQC ready? (4p) ==== ==== 3. PQC ready? (4p) ====
  
-Now try to replace ​the key exchange ​used above with post-quantum cryptography. For this you can use different libraries.+Now let's update ​the key exchange ​to use post-quantum cryptography.
  
-One option is using [[https://​github.com/​open-quantum-safe/​liboqs |liboqs]]. To install it on Ubuntu, use the command below:+For this you can either modify the work you did above to use a post-quantum key exchange method such as ML-KEM in Python. 
 +To do this in Python you can use a library such as [[https://​pypi.org/​project/​mlkem/​|ml-kem]]. 
 +You can install this as follows: 
 +<​code>​ 
 +pip install ml-kem 
 +</​code>​ 
 + 
 +Below is an example of how to use this library in a simple client-server scenario. Note: this example is provided by Gemini AI, so use it with caution and double-check it: 
 +<​code>​ 
 +# Install the library first: pip install ml-kem 
 + 
 +from mlkem.ml_kem import ML_KEM 
 +from mlkem.parameter_set import ML_KEM_768 # Recommended security level 
 +import secrets 
 + 
 +# --- Server (Alice) Side --- 
 + 
 +def server_keygen():​ 
 +    """​Alice generates her ML-KEM key pair."""​ 
 +    # Initialize ML-KEM with the desired security level 
 +    ml_kem = ML_KEM(parameters=ML_KEM_768,​ randomness=secrets.token_bytes) 
 +     
 +    # Generate the encapsulation key (ek, public) and decapsulation key (dk, private) 
 +    ek, dk = ml_kem.key_gen() 
 +     
 +    print("​Alice:​ Generated Public Key (ek) and Private Key (dk)."​) 
 +    return ek, dk, ml_kem 
 + 
 +def server_decapsulate(dk,​ c, ml_kem): 
 +    """​Alice decapsulates the ciphertext to get the shared secret."""​ 
 +    try: 
 +        K_prime = ml_kem.decaps(dk,​ c) 
 +        print("​Alice:​ Successfully decapsulated the Shared Secret (K'​)."​) 
 +        return K_prime 
 +    except ValueError as e: 
 +        print(f"​Alice:​ Decapsulation failed! {e}"​) 
 +        return None 
 + 
 +# --- Client (Bob) Side --- 
 + 
 +def client_encapsulate(ek):​ 
 +    """​Bob encapsulates a shared secret using Alice'​s public key."""​ 
 +    ml_kem = ML_KEM(parameters=ML_KEM_768,​ randomness=secrets.token_bytes) 
 +     
 +    # Encapsulate to get the shared secret (K) and the ciphertext (c) 
 +    K, c = ml_kem.encaps(ek) 
 +     
 +    print("​Bob:​ Encapsulated a Shared Secret (K) and created Ciphertext (c)."​) 
 +    return K, c 
 + 
 +# --- Communication Flow Simulation --- 
 + 
 +# 1. Server (Alice) Key Generation 
 +ek_server, dk_server, ml_kem_instance = server_keygen() 
 + 
 +# 2. Public Key Transmission (ek_server is sent to the client) 
 +print("​\n--- Network Transmission:​ ek sent to Bob ---"​) 
 + 
 +# 3. Client (Bob) Encapsulation 
 +K_client, c_client = client_encapsulate(ek_server) 
 + 
 +# 4. Ciphertext Transmission (c_client is sent back to the server) 
 +print("​\n--- Network Transmission:​ c sent to Alice ---"​) 
 + 
 +# 5. Server (Alice) Decapsulation 
 +K_server = server_decapsulate(dk_server,​ c_client, ml_kem_instance) 
 + 
 +# 6. Verification 
 +print("​\n--- Verification ---"​) 
 +if K_client is not None and K_server is not None: 
 +    if K_client == K_server: 
 +        print("​Success! Alice'​s and Bob's shared secrets match."​) 
 +        # The shared secret can now be used as an AES key, e.g., K_client 
 +        # The shared secret is bytes: 
 +        # print(f"​Shared Secret: {K_client.hex()}"​) 
 +    else: 
 +        print("​Failure! Shared secrets do not match."​) 
 +else: 
 +    print("​Failure in key exchange process."​) 
 +</​code>​ 
 + 
 + 
 +Otherwise, you can start from the Diffie-Hellman key exchange lab we did in OpenSSL/C. You may start from {{:​ac:​laboratoare:​lab_dhe_solved.zip|this}} code, that provides a working solution for the Diffie-Hellman lab in OpenSSL. 
 + 
 +If you go for the C implementation in OpenSSL, one option ​to include post-quantum encryption ​is using [[https://​github.com/​open-quantum-safe/​liboqs |liboqs]]. To install it on Ubuntu, use the command below:
  
 <​code>​ <​code>​
Line 92: Line 176:
 Alternatively,​ you can also use OpenSSL directly (starting with version 3.5). You can find some documentation for ML-KEM [[https://​docs.openssl.org/​master/​man7/​EVP_KEM-ML-KEM/​ |here]] and [[https://​docs.openssl.org/​3.5/​man7/​EVP_PKEY-ML-KEM/​ |here]]. Alternatively,​ you can also use OpenSSL directly (starting with version 3.5). You can find some documentation for ML-KEM [[https://​docs.openssl.org/​master/​man7/​EVP_KEM-ML-KEM/​ |here]] and [[https://​docs.openssl.org/​3.5/​man7/​EVP_PKEY-ML-KEM/​ |here]].
  
-Below is an example code obtained through Gemini AI (not fully tested, but perhaps a good starting point -- you may do something similar to get a starting point for the server):+Below is an example code obtained through Gemini AI (not fully tested, but perhaps a good starting point):
 <​code>​ <​code>​
 #include <​stdio.h>​ #include <​stdio.h>​
Line 226: Line 310:
   * Extract the raw public key bytes to replace the placeholder in the C code. A common way to get the raw bytes is to convert the PEM file to a DER format and extract the key component. For ML-KEM, the raw key is often found within the ASN.1 structure.   * Extract the raw public key bytes to replace the placeholder in the C code. A common way to get the raw bytes is to convert the PEM file to a DER format and extract the key component. For ML-KEM, the raw key is often found within the ASN.1 structure.
 <​note>​ <​note>​
-See the DH lab for information about this process+See the DH lab for information about this process. But see also below more details for this process, as provided by Gemini AI.
 </​note>​ </​note>​
   * Compile the code (adjusting paths to your OpenSSL 3.5 installation),​ using a command like this (check again also the DH lab for more details):   * Compile the code (adjusting paths to your OpenSSL 3.5 installation),​ using a command like this (check again also the DH lab for more details):
Line 232: Line 316:
 gcc -o mlkem_client mlkem_client.c -I/​path/​to/​openssl/​include -L/​path/​to/​openssl/​lib -lssl -lcrypto gcc -o mlkem_client mlkem_client.c -I/​path/​to/​openssl/​include -L/​path/​to/​openssl/​lib -lssl -lcrypto
 </​code>​ </​code>​
 +
 +The following GeminiAI-generated scripts (might have some bugs, please double-check,​ they are only given as reference/​helper tools) generate an ML-KEM-768 key pair and, importantly,​ forces OpenSSL to save the private key in the FIPS 203 '​dk'​ format (the one the C code expects for decapsulation) rather than the default '​seed'​ format, which is not what the raw C code imports:
 +<​code>​
 +#!/bin/bash
 +KEY_ALG="​ML-KEM-768"​
 +PRIV_FILE="​server_private_dk.pem"​
 +PUB_FILE="​server_public_ek.pem"​
 +RAW_PRIV_FILE="​server_private_raw.bin"​
 +RAW_PUB_FILE="​server_public_raw.bin"​
 +
 +echo "--- 1. Generating $KEY_ALG Key Pair (forcing dk-only private key) ---"
 +
 +# Generate the private key, using '​-provparam ml-kem.retain_seed=no'​
 +# to ensure it saves the full FIPS 203 '​dk'​ decapsulation key,
 +# NOT just the seed.
 +openssl genpkey -algorithm "​$KEY_ALG"​ \
 +    -provparam ml-kem.retain_seed=no \
 +    -out "​$PRIV_FILE"​
 +
 +# Extract the public key from the private key file
 +openssl pkey -in "​$PRIV_FILE"​ -pubout -out "​$PUB_FILE"​
 +
 +echo "Keys generated: $PRIV_FILE and $PUB_FILE"​
 +echo "​----------------------------------------------------------------"​
 +</​code>​
 +
 +The ML-KEM public key is in the SubjectPublicKeyInfo structure in the PEM file. We use openssl pkey to output the key in DER format and then remove the ASN.1 header/​wrapper to get the raw bytes:
 +<​code>​
 +echo "--- 2. Extracting RAW Public Key (608 bytes) ---"
 +
 +# The ML-KEM public key is 608 bytes long.
 +# The '​pubout'​ option converts to DER, and '​tail'​ removes the ASN.1 wrapper.
 +# NOTE: The ASN.1 wrapper size may vary by OpenSSL version/​config. We must
 +# determine the exact offset to trim off the SubjectPublicKeyInfo header.
 +# For standard ML-KEM-768 PKCS#8 output, the header is typically 24 bytes.
 +HEADER_BYTES=24 # Common offset for ML-KEM-768 PKCS#8 SubjectPublicKeyInfo header
 +
 +openssl pkey -in "​$PUB_FILE"​ -pubin -outform DER -out "​$RAW_PUB_FILE"​
 +# Trim the ASN.1 header to get the raw 608-byte key
 +# (Skip first $HEADER_BYTES,​ save the next 608 bytes)
 +dd if="​$RAW_PUB_FILE"​ of="​client_public_key_raw_final.bin"​ bs=1 skip=$HEADER_BYTES count=608 status=none
 +
 +echo "Raw public key saved to client_public_key_raw_final.bin"​
 +# Print the hex array for C code
 +echo "​Public Key Hex Array:"​
 +xxd -p "​client_public_key_raw_final.bin"​ | tr -d '​\n'​ | sed '​s/​../&,​ 0x/g' | sed 's/^, 0x/​0x/'​ | sed 's/, $//'
 +echo
 +echo "​----------------------------------------------------------------"​
 +</​code>​
 +
 +Similarly, the private key (the FIPS 203 '​dk'​ component) is inside the PKCS#8 private key structure. We again convert to DER and trim the ASN.1 wrappers:
 +<​code>​
 +echo "--- 3. Extracting RAW Private Key (1184 bytes) ---"
 +
 +# The ML-KEM-768 private key (dk) is 1184 bytes long.
 +# We convert to DER and again skip the ASN.1 header bytes.
 +# For PKCS#8 '​dk'​ private key, the header is typically 50 bytes.
 +HEADER_BYTES=50 # Common offset for ML-KEM-768 PKCS#8 PrivateKeyInfo header
 +
 +openssl pkey -in "​$PRIV_FILE"​ -outform DER -out "​$RAW_PRIV_FILE"​
 +# Trim the ASN.1 header to get the raw 1184-byte key
 +# (Skip first $HEADER_BYTES,​ save the next 1184 bytes)
 +dd if="​$RAW_PRIV_FILE"​ of="​server_private_key_raw_final.bin"​ bs=1 skip=$HEADER_BYTES count=1184 status=none
 +
 +echo "Raw private key saved to server_private_key_raw_final.bin"​
 +# Print the hex array for C code
 +echo "​Private Key Hex Array:"​
 +xxd -p "​server_private_key_raw_final.bin"​ | tr -d '​\n'​ | sed '​s/​../&,​ 0x/g' | sed 's/^, 0x/​0x/'​ | sed 's/, $//'
 +echo
 +echo "​----------------------------------------------------------------"​
 +</​code>​
 +
 +You can now use the hex output from these scripts to reliably replace the placeholder arrays in your C client and server code.
 +See also [[https://​www.youtube.com/​watch?​v=FzLzH5W-mi8|this]] video about Post-Quantum Cryptography support in OpenSSL.
 +
  
 Below is also an example code from Gemini AI as starting point for the server, to pair with the code above for the client. Below is also an example code from Gemini AI as starting point for the server, to pair with the code above for the client.
ac/laboratoare/11.1762416341.txt.gz · Last modified: 2025/11/06 10:05 by marios.choudary
CC Attribution-Share Alike 3.0 Unported
www.chimeric.de Valid CSS Driven by DokuWiki do yourself a favour and use a real browser - get firefox!! Recent changes RSS feed Valid XHTML 1.0