Using both QKD and PQC
FortiOS supports configuring Quantum Key Distribution (QKD) and Post-Quantum Cryptography (PQC). This allows you to mix keys from QKD, PQC, and traditional Diffie-Hellman (DH) key exchange, ensuring robust security. By combining different types of keys, users can achieve maximum resilience against potential threats.
This feature can be used in environments handling highly sensitive data, necessitating the highest level of security. For example, a financial institution might use this feature in its network infrastructure to secure communications between different system components. This ensures that even if one key exchange method is compromised, the other methods will still provide secure communication.
In such a scenario, the financial institution could enable QKD for advanced quantum security, PQC for resilience against quantum threats, and DH for traditional key exchange. By combining these methods, they can tailor their security approach to meet specific needs and maximize resilience against potential threats.
Example
To configure IPsec key retrieval with a QKD and PQC keys together by CLI:
-
Configure FGT-A
-
Configure the QKD profile:
config vpn qkd edit "qkd_1" set server "10.1.100.9" set port 8989 set id "123456" set peer "qkdtest" next end -
Configure the IPsec phase1 interface:
config vpn ipsec phase1-interface edit "test_qkd" set interface "port9" set peertype any set net-device disable set proposal aes128-sha256 aes256-sha256 aes128gcm-prfsha256 aes256gcm-prfsha384 chacha20poly1305-prfsha256 set dhgrp 21 set addke1 1080 set qkd require set qkd-hybrid require set qkd-profile "qkdtest" set remote-gw 173.1.1.1 set psksecret ********** next end -
Configure the IPsec phase2 interface :
config vpn ipsec phase2-interface edit "test_qkd" set phase1name "test_qkd" set proposal aes128-sha1 aes256-sha1 aes128-sha256 aes256-sha256 aes128gcm aes256gcm chacha20poly1305 set dhgrp 20 21 set addke1 35 next end
-
-
Configure FGT-D
-
Configure the QKD profile:
config vpn qkd edit "qkdtest" set server "10.1.100.9" set port 8989 set id "123456" set peer "qkdtest" next end -
Configure the IPsec phase1 interface:
config vpn ipsec phase1-interface edit "test_qkd" set interface "test_qkd" set peertype any set net-device disable set proposal aes128-sha256 aes256-sha256 aes128gcm-prfsha256 aes256gcm-prfsha384 chacha20poly1305-prfsha256 set dhgrp 21 set addke1 1080 set qkd require set qkd-hybrid require set qkd-profile "qkdtest" set remote-gw 11.101.1.1 set psksecret ********** next end -
Configure the IPsec phase2 interface :
config vpn ipsec phase2-interface edit "test_qkd" set phase1name "test_qkd" set proposal aes128-sha1 aes256-sha1 aes128-sha256 aes256-sha256 aes128gcm aes256gcm chacha20poly1305 set dhgrp 20 21 set addke1 35 next end
-
To verify the configuration on FGT-A:
-
Generate traffic between PC1 and PC4.
-
Verify the IPsec phase1 interface status:
# diagnose vpn ike gateway list vd: root/0 name: test_qkd version: 2 interface: port9 15 addr: 11.101.1.1:500 -> 173.1.1.1:500 tun_id: 173.1.1.1/::173.1.1.1 remote_location: 0.0.0.0 network-id: 0 transport: UDP created: 1557s ago peer-id: 173.1.1.1 peer-id-auth: no pending-queue: 0 PPK: no IKE SA: created 1/18 established 1/18 time 0/2/10 ms IPsec SA: created 1/33 established 1/18 time 0/16/20 ms id/spi: 67 bc882e536cbc7f1d/ede854f1e0dc71bb direction: responder status: established 17-17s ago = 0ms proposal: aes128-sha256 child: yes SK_ei: 4e415c84e086e980-059f1be89239ec30 SK_er: fb14db5b3718dad4-e7f5158308ba00c0 SK_ai: 8894937bd4e66304-a5c64941dc08d544-c7d725408247cfc4-489a292a3fb44b51 SK_ar: 0bbf85dcd9daaa1b-1f1e04318b69aaae-befc871e40f9ab4c-0d005f0f980a3d60 message-id sent/recv: 0/1 QKD: yes PQC-KEM (IKE): yes PQC-KEM (all IPsec): yes lifetime/rekey: 86400/86112 DPD sent/recv: 00000000/00000000 peer-id: 173.1.1.1
-
Verify the IPsec phase2 interface status:
# diagnose vpn tunnel list list all ipsec tunnel in vd 0 ------------------------------------------------------ name=test_qkd ver=2 serial=1 11.101.1.1:0->173.1.1.1:0 nexthop=11.101.1.2 tun_id=173.1.1.1 tun_id6=::173.1.1.1 status=up dst_mtu=1500 weight=1 bound_if=15 real_if=15 lgwy=static/1 tun=intf mode=auto/1 encap=none/552 options[0228]=npu frag-rfc run_state=0 role=primary accept_traffic=1 overlay_id=0 proxyid_num=1 child_num=0 refcnt=3 ilast=1270 olast=1270 ad=/0 stat: rxp=69 txp=70 rxb=10420 txb=5880 dpd: mode=off natt: mode=none draft=0 interval=0 remote_port=0 fec: egress=0 ingress=0 proxyid=test_qkd proto=0 sa=1 ref=2 serial=2 auto-negotiate src: 0:0.0.0.0-255.255.255.255:0 dst: 0:0.0.0.0-255.255.255.255:0 SA: ref=6 options=18227 type=00 soft=0 mtu=1438 expire=3297/0B replaywin=2048 seqno=1 esn=0 replaywin_lastseq=00000000 qat=0 rekey=0 hash_search_len=1 life: type=01 bytes=0/0 timeout=3329/3600 dec: spi=450287b6 esp=aes key=16 42551cf97c77fb110f44574e0b33b36a ah=sha1 key=20 640b627fb80f4342a488349bdd35437db381640c enc: spi=a8a6afc3 esp=aes key=16 238c43ac7ee569c20ba5861fb8336c9a ah=sha1 key=20 d1226a16bfecb186148aafbce42a5da34e246afb dec:pkts/bytes=0/0, enc:pkts/bytes=0/0 npu_flag=03 npu_rgwy=173.1.1.1 npu_lgwy=11.101.1.1 npu_selid=1 dec_npuid=1 enc_npuid=1 -
Verify IKE debug messages on:
# diagnose debug application ike -1 ... ike V=root:0:64555dc0381b820e/0000000000000000:70: received notify type USE_QKD ike V=root:0:64555dc0381b820e/0000000000000000:70: received notify type INTERMEDIATE_EXCHANGE_SUPPORTED ike V=root:0:64555dc0381b820e/0000000000000000:70: incoming proposal: ike V=root:0:64555dc0381b820e/0000000000000000:70: proposal id = 1: ike V=root:0:64555dc0381b820e/0000000000000000:70: protocol = IKEv2: ike V=root:0:64555dc0381b820e/0000000000000000:70: encapsulation = IKEv2/none ike V=root:0:64555dc0381b820e/0000000000000000:70: type=ENCR, val=AES_CBC (key_len = 128) ike V=root:0:64555dc0381b820e/0000000000000000:70: type=INTEGR, val=AUTH_HMAC_SHA2_256_128 ike V=root:0:64555dc0381b820e/0000000000000000:70: type=PRF, val=PRF_HMAC_SHA2_256 ike V=root:0:64555dc0381b820e/0000000000000000:70: type=DH_GROUP, val=ECP521. ike V=root:0:64555dc0381b820e/0000000000000000:70: type=ADDKE1, val=KYBER512. ... ike V=root:0:test_qkd:70: process NAT-D ike V=root:0:test_qkd:70: processing notify type FRAGMENTATION_SUPPORTED ike V=root:0:test_qkd:70: processing notify type USE_QKD ike V=root:0:test_qkd:70: responder preparing SA_INIT msg ... ike V=root:0:test_qkd:70: responder received INTEREMDIATE msg ike V=root:0:test_qkd:70: processing KE group 1080 ike V=root:0:test_qkd:70: KEM encapsulate okay ike V=root:0:test_qkd:70: responder INTERMEDIATE send ike V=root:0:test_qkd:70: construct KE (1080) payload ... ike V=root:0:test_qkd:73: received followup-ke request ike V=root:0:test_qkd:73: responder received FOLLOWUP_KE msg ike V=root:0:test_qkd:73: processing notify type ADDITIONAL_KEY_EXCHANGE ike V=root:0:test_qkd:73: received ADDKE notify link data size (len=4) ike V=root:0:test_qkd:73: FOLLOWUP_KE continuation for IKE SA 1d5770c3f3044565/b2cb648b2f8e064d ike V=root:0:test_qkd:74: KEM encapsulate okay ike V=root:0:test_qkd:74: responder preparing IKE SA FOLLOWUP_KE message ike V=root:0:test_qkd:74: construct KE grp (1080) payload ... ike V=root:0:test_qkd:74::80: QKD responder request '49d2bff4-0e61-11f0-8e8b-6bdf091987ab' ike V=root:0:test_qkd:74::80: QKD responder key-id '49d2bff4-0e61-11f0-8e8b-6bdf091987ab' ike V=root:0:test_qkd:74:80: peer proposal: ike V=root:0:test_qkd:74:80: TSi_0 0:0.0.0.0-255.255.255.255:0 ike V=root:0:test_qkd:74:80: TSr_0 0:0.0.0.0-255.255.255.255:0 ike V=root:0:test_qkd:74:test_qkd:80: comparing selectors ike V=root:0:test_qkd:74:test_qkd:80: matched by rfc-rule-2 ike V=root:0:test_qkd:74:test_qkd:80: phase2 matched by subset ike V=root:0:test_qkd:74:test_qkd:80: accepted proposal: ike V=root:0:test_qkd:74:test_qkd:80: TSi_0 0:0.0.0.0-255.255.255.255:0 ike V=root:0:test_qkd:74:test_qkd:80: TSr_0 0:0.0.0.0-255.255.255.255:0 ike V=root:0:test_qkd:74:test_qkd:80: autokey ike V=root:0:test_qkd:74:test_qkd:80: incoming child SA proposal: ike V=root:0:test_qkd:74:test_qkd:80: proposal id = 1: ike V=root:0:test_qkd:74:test_qkd:80: protocol = ESP: ike V=root:0:test_qkd:74:test_qkd:80: encapsulation = TUNNEL ike V=root:0:test_qkd:74:test_qkd:80: type=ENCR, val=AES_CBC (key_len = 128) ike V=root:0:test_qkd:74:test_qkd:80: type=INTEGR, val=SHA ike V=root:0:test_qkd:74:test_qkd:80: type=DH_GROUP, val=ECP384 ike V=root:0:test_qkd:74:test_qkd:80: type=DH_GROUP, val=ECP521 ike V=root:0:test_qkd:74:test_qkd:80: type=ESN, val=NO ike V=root:0:test_qkd:74:test_qkd:80: type=ADDKE1, val=ML-KEM-512. ... ike V=root:0:test_qkd:74:test_qkd:80: ADDKE negotiated ... ike V=root:0:test_qkd:74: responder received FOLLOWUP_KE msg ike V=root:0:test_qkd:74: processing notify type ADDITIONAL_KEY_EXCHANGE ike V=root:0:test_qkd:74: received ADDKE notify link data size (len=4) ike V=root:0:test_qkd:74: FOLLOWUP_KE continuation for IPsec SA bc870245/c9afa6a8 ike V=root:0:test_qkd:80: KEM encapsulate okay ike V=root:0:test_qkd:80: responder preparing CHILD SA FOLLOWUP_KE message ike V=root:0:test_qkd:80: construct KE grp (35) payload
-
Verify the statistics of QKD profile:
# diagnose vpn ike qkd qkdtest ike.qkd.server.dns.addrs: ike.qkd.server.curl.initiator.error.request.send.count: 10 ike.qkd.server.curl.initiator.error.request.send.last.ticks: 4295033761 ike.qkd.server.curl.initiator.error.request.send.last.ago: 1986 ike.qkd.server.curl.initiator.error.request.send.last.local: 2025-04-01 06:12:40 +1200 ike.qkd.server.curl.initiator.error.request.send.last.utc: 2025-03-31 18:12:40 ike.qkd.server.curl.initiator.error.request.send.value: 7 ike.qkd.server.curl.inflight: now 0 max 2 total 48 ike.qkd.server.curl.ssl.verify.count: 3952 ike.qkd.server.curl.ssl.verify.last.ticks: 4295231030 ike.qkd.server.curl.ssl.verify.last.ago: 13 ike.qkd.server.curl.ssl.verify.last.local: 2025-04-01 06:45:33 +1200 ike.qkd.server.curl.ssl.verify.last.utc: 2025-03-31 18:45:33