diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 98de99f4..c955d266 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -18,9 +18,26 @@ jobs: - name: Update run: sudo apt-get update - name: Install Dependencies - run: sudo apt-get install -y lcov libcurl4-openssl-dev libmariadb-dev libmariadb-dev-compat libgcrypt20-dev python3 + run: sudo apt-get install -y lcov libcurl4-openssl-dev libmariadb-dev libmariadb-dev-compat python3 - name: Install Python Libraries run: sudo pip install pycryptodome + - name: Install Libgcrypt + run: > + curl + -LS https://www.gnupg.org/ftp/gcrypt/libgpg-error/libgpg-error-1.50.tar.bz2 + -o /tmp/libgpg-error-1.50.tar.bz2 + && tar -xjf /tmp/libgpg-error-1.50.tar.bz2 -C /tmp/ + && cd /tmp/libgpg-error-1.50 + && sudo ./configure + && sudo make install + && curl + -LS https://www.gnupg.org/ftp/gcrypt/libgcrypt/libgcrypt-1.11.0.tar.bz2 + -o /tmp/libgcrypt-1.11.0.tar.bz2 + && tar -xjf /tmp/libgcrypt-1.11.0.tar.bz2 -C /tmp/ + && cd /tmp/libgcrypt-1.11.0 + && sudo ./configure + && sudo make install + && sudo ldconfig # End Container Setup - name: Minimal Build Script @@ -38,9 +55,26 @@ jobs: - name: Update run: sudo apt-get update - name: Install Dependencies - run: sudo apt-get install -y lcov libcurl4-openssl-dev libmariadb-dev libmariadb-dev-compat libgcrypt20-dev python3 + run: sudo apt-get install -y lcov libcurl4-openssl-dev libmariadb-dev libmariadb-dev-compat python3 - name: Install Python Libraries run: sudo pip install pycryptodome + - name: Install Libgcrypt + run: > + curl + -LS https://www.gnupg.org/ftp/gcrypt/libgpg-error/libgpg-error-1.50.tar.bz2 + -o /tmp/libgpg-error-1.50.tar.bz2 + && tar -xjf /tmp/libgpg-error-1.50.tar.bz2 -C /tmp/ + && cd /tmp/libgpg-error-1.50 + && sudo ./configure + && sudo make install + && curl + -LS https://www.gnupg.org/ftp/gcrypt/libgcrypt/libgcrypt-1.11.0.tar.bz2 + -o /tmp/libgcrypt-1.11.0.tar.bz2 + && tar -xjf /tmp/libgcrypt-1.11.0.tar.bz2 -C /tmp/ + && cd /tmp/libgcrypt-1.11.0 + && sudo ./configure + && sudo make install + && sudo ldconfig # End Container Setup - name: Internal Build Script @@ -70,9 +104,26 @@ jobs: - name: Update run: sudo apt-get update - name: Install Dependencies - run: sudo apt-get install -y lcov libcurl4-openssl-dev libmariadb-dev libmariadb-dev-compat libgcrypt20-dev python3 + run: sudo apt-get install -y lcov libcurl4-openssl-dev libmariadb-dev libmariadb-dev-compat python3 - name: Install Python Libraries run: sudo pip install pycryptodome + - name: Install Libgcrypt + run: > + curl + -LS https://www.gnupg.org/ftp/gcrypt/libgpg-error/libgpg-error-1.50.tar.bz2 + -o /tmp/libgpg-error-1.50.tar.bz2 + && tar -xjf /tmp/libgpg-error-1.50.tar.bz2 -C /tmp/ + && cd /tmp/libgpg-error-1.50 + && sudo ./configure + && sudo make install + && curl + -LS https://www.gnupg.org/ftp/gcrypt/libgcrypt/libgcrypt-1.11.0.tar.bz2 + -o /tmp/libgcrypt-1.11.0.tar.bz2 + && tar -xjf /tmp/libgcrypt-1.11.0.tar.bz2 -C /tmp/ + && cd /tmp/libgcrypt-1.11.0 + && sudo ./configure + && sudo make install + && sudo ldconfig # End Container Setup - name: KMC Build Script @@ -102,9 +153,26 @@ jobs: - name: Update run: sudo apt-get update - name: Install Dependencies - run: sudo apt-get install -y lcov libcurl4-openssl-dev libmariadb-dev libmariadb-dev-compat libgcrypt20-dev python3 autoconf libtool + run: sudo apt-get install -y lcov libcurl4-openssl-dev libmariadb-dev libmariadb-dev-compat python3 autoconf libtool - name: Install Python Libraries run: sudo pip install pycryptodome + - name: Install Libgcrypt + run: > + curl + -LS https://www.gnupg.org/ftp/gcrypt/libgpg-error/libgpg-error-1.50.tar.bz2 + -o /tmp/libgpg-error-1.50.tar.bz2 + && tar -xjf /tmp/libgpg-error-1.50.tar.bz2 -C /tmp/ + && cd /tmp/libgpg-error-1.50 + && sudo ./configure + && sudo make install + && curl + -LS https://www.gnupg.org/ftp/gcrypt/libgcrypt/libgcrypt-1.11.0.tar.bz2 + -o /tmp/libgcrypt-1.11.0.tar.bz2 + && tar -xjf /tmp/libgcrypt-1.11.0.tar.bz2 -C /tmp/ + && cd /tmp/libgcrypt-1.11.0 + && sudo ./configure + && sudo make install + && sudo ldconfig - name: Clone WolfSSL run: git clone --depth 1 --branch v5.6.0-stable https://github.com/wolfSSL/wolfssl.git /tmp/wolfssl @@ -114,7 +182,7 @@ jobs: #run: cd /tmp/wolfssl/; # sudo chown -R runner /usr/local; # ./autogen.sh; - # ./configure --enable-aesccm --enable-aessiv --enable-cmac; + # sudo ./configure --enable-aesccm --enable-aessiv --enable-cmac; # make; # make install; #sudo chown -R runner /usr/local; @@ -155,21 +223,40 @@ jobs: - name: Update run: yum update -y - name: Install Dependencies - run: yum install -y epel-release python38-devel libcurl-devel libgpg-error-devel libgcrypt-devel git cmake gcc java-11-openjdk-devel openssl wget mariadb-devel mariadb-common mariadb-connector-c mariadb-connector-c-config mariadb-errmsg mariadb-gssapi-server + run: yum install -y epel-release python38-devel libcurl-devel git cmake gcc java-11-openjdk-devel openssl wget bzip2 ldconfig mariadb-devel mariadb-common mariadb-connector-c mariadb-connector-c-config mariadb-errmsg mariadb-gssapi-server # Might want to trim this down, but these dependencies should work for KMC - name: install lcov run: yum install -y --enablerepo=epel lcov - name: Install Python Dependencies run: pip3 install pycryptodome + - name: Install Libgcrypt + run: > + curl + -LS https://www.gnupg.org/ftp/gcrypt/libgpg-error/libgpg-error-1.50.tar.bz2 + -o /tmp/libgpg-error-1.50.tar.bz2 + && tar -xjf /tmp/libgpg-error-1.50.tar.bz2 -C /tmp/ + && cd /tmp/libgpg-error-1.50 + && ./configure + && make install + && curl + -LS https://www.gnupg.org/ftp/gcrypt/libgcrypt/libgcrypt-1.11.0.tar.bz2 + -o /tmp/libgcrypt-1.11.0.tar.bz2 + && tar -xjf /tmp/libgcrypt-1.11.0.tar.bz2 -C /tmp/ + && cd /tmp/libgcrypt-1.11.0 + && ./configure + && make install + && echo "export LD_LIBRARY_PATH=/usr/local/lib/:/usr/local/include:$LD_LIBRARY_PATH" >> ~/.bashrc + && source ~/.bashrc + && ldconfig # End Container Setup - name: RHEL Build Script working-directory: ${{github.workspace}} - run: bash ${GITHUB_WORKSPACE}/support/scripts/build_rhel.sh + run: source ~/.bashrc && ${GITHUB_WORKSPACE}/support/scripts/build_rhel.sh - name: Code-Coverage working-directory: ${{github.workspace}} - run: make gcov + run: source ~/.bashrc && make gcov - name: Upload uses: codecov/codecov-action@v4 diff --git a/CMakeLists.txt b/CMakeLists.txt index 8e32bcfa..0936d717 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -24,6 +24,7 @@ project(crypto C) set(SA_CUSTOM_PATH_DEFAULT "../../sa/custom") set(KEY_CUSTOM_PATH_DEFAULT "../../key/custom") set(MC_CUSTOM_PATH_DEFAULT "../../mc/custom") +set(MC_LOG_PATH_DEFAULT "log.txt") set(CRYPTO_CUSTOM_PATH_DEFAULT "../../crypto/custom") @@ -57,6 +58,7 @@ option(SYSTEM_INSTALL "SystemInstall" OFF) option(TEST "Test" OFF) option(TEST_ENC "Tests - Encryption" OFF) option(SA_FILE "Save Security Association to File" OFF) +option(KEY_VALIDATION "Validate existance of key duplication" OFF) OPTION(KMC_MDB_RH "KMC-MDB-RedHat-Integration-Testing" OFF) #Disabled by default, enable with: -DKMC_MDB_RH=ON OPTION(KMC_MDB_DB "KMC-MDB-Debian-Integration-Testing" OFF) #Disabled by default, enable with: -DKMC_MDB_DB=ON @@ -110,11 +112,22 @@ if(SA_FILE) add_definitions(-DSA_FILE) endif() +if(KEY_VALIDATION) + add_definitions(-DKEY_VALIDATION) +endif() + if(DEBUG) add_definitions(-DDEBUG -DOCF_DEBUG -DFECF_DEBUG -DSA_DEBUG -DPDU_DEBUG -DCCSDS_DEBUG -DTC_DEBUG -DMAC_DEBUG -DTM_DEBUG -DAOS_DEBUG) add_compile_options(-ggdb) endif() +if(DEFINED MC_LOG_CUSTOM_PATH) + message(STATUS "MC_LOG_CUSTOM_PATH set to: ${MC_LOG_CUSTOM_PATH}") + add_compile_definitions(MC_LOG_PATH="${MC_LOG_CUSTOM_PATH}") +else() + add_compile_definitions(MC_LOG_PATH="${MC_LOG_PATH_DEFAULT}") +endif() + IF(KMC_MDB_RH) ADD_DEFINITIONS(-DKMC_MDB_RH) ADD_DEFINITIONS(-DKMC_CFFI_EXCLUDE) diff --git a/README.md b/README.md index 6e7da057..c2609f29 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,8 @@ ![Build](https://github.com/nasa/CryptoLib/actions/workflows/build.yml/badge.svg) [![CodeCov](https://codecov.io/gh/nasa/CryptoLib/branch/main/graph/badge.svg?token=KCOMCQO0ZU)](https://codecov.io/gh/nasa/CryptoLib) +![CryptoLib logo Final All orange](https://github.com/user-attachments/assets/fc02870b-e2d2-4577-83c2-78985d5fbdd6) + # CryptoLib Provide a software-only solution using the CCSDS Space Data Link Security Protocol - Extended Procedures (SDLS-EP) to secure communications between a spacecraft running the core Flight System (cFS) and a ground station. diff --git a/doc/requirements.md b/doc/requirements.md new file mode 100644 index 00000000..f9a2b04c --- /dev/null +++ b/doc/requirements.md @@ -0,0 +1,83 @@ +# CryptoLib Requirements + +Note this is in draft form and is not yet traceable to the unit tests. + +# General +* CryptoLib shall provide initialization function(s) for the setup of the library. +* CryptoLib shall provide apply security functions for each supported frame type. +* CryptoLib shall provide process security functions for each supported frame type. +* CryptoLib shall provide teardown function(s) for the cleanup of the library. +* CryptoLib shall maintain separation of modules for cryptography, key management, monitoring and control, and security associations that can be configured at build time for use. +* CryptoLib shall maintain a custom option for each module type for users to develop specific implementations. +* CryptoLib shall adhere to the CCSDS Space Data Link Security standard (CCSDS 355.0-B-2) Protocl Implementation Conformance Statements (PICS). +* CryptoLib shall adhere to the CCSDS Space Data Link Security Extended Procedures standard (CCSDS 355.1-B-1) Protocol Implementation Conformance Statements (PICS). + +# CCSDS SDLS PICS +* A4/1 - CryptoLib shall support the TM Space Data Link Protocol. +* A4/2 - CryptoLib shall support the TC Space Data Link Protocol. +* A4/3 - CryptoLib shall support the AOS Space Data Link Protocol. +* A5/1 - The CryptoLib cryptography module shall support encryption. +* A5/2 - The CryptoLib cryptography module shall support authentication. +* A5/3 - The CryptoLib cryptography module shall support authenticated encryption. +* A6/1 - CryptoLib shall maintain the global virtual channel ID (GVCID) as part of the security association management data. +* A6/2 - CryptoLib shall maintain the global multiplexer access point identifier (GMAP_ID) as part of the security association management data. +* A6/3 - CryptoLib shall maintain the security parameter index (SPI) identifying the security association (SA) applicable to a frame as part of the SA management data. +* A6/4 - CryptoLib shall maintain the security association service type (SA_service_type) indicating the cryptographic function(s) specified for the SA as part of the security association management data. +* A6/5 - CryptoLib shall maintain the security association sequence number length (SA_length_SN) indicating the length of the sequence number field in the security header as part of the security association management data. +* A6/6 - CryptoLib shall maintain the security association initialization vector length (SA_length_IV) indicating the length of the initialization vector field in the security header as part of the security association management data. +* A6/7 - CryptoLib shall maintain the security association pad length (SA_length_PL) indicating the length of the pad length field in the security header as part of the security association management data. +* A6/8 - CryptoLib shall maintain the security association message authentication code length (SA_length_MAC) indicating the length of the MAC field in the security trailer as part of the security association management data. +* A6/9 - CryptoLib shall maintain the security association authentication algorithm and mode of operation as part of the security association management data. +* A6/10 - CryptoLib shall maintain the security association authentication key or index that refers to the actual key as part of the security association management data. +* A6/11 - CryptoLib shall maintain the security association authentication mask parameter indicating the value of a provided bit mask that is applied against the Transfer Frame in a bitwise-AND operation to generate an Authentication Payload as part of the security association management data. +* A6/12 - CryptoLib shall maintain the security association sequence number indicating the present value of a managed anti-replay sequence counter as part of the security association management data. +* A6/13 - CryptoLib shall maintain the security association sequence window indicating the amount of deviation the receiving end will accept between the expected anti-replay sequence number in a received frame as part of the security association management data. +* A6/14 - CryptoLib shall maintain the security association encryption algorithm and mode of operation as part of the security association management data. +* A6/15 - CryptoLib shall maintain the security association encryption key or index that refers to the actual key as part of the security association management data. +* A6/16 - CryptoLib shall maintain the security association initialization vector indicating the present value of a managed initialization vector field as part of the security association management data. +* A7/1 - CryptoLib shall have apply security functions for each transfer frame type supported that contains input parameters of a payload containing the partially formatted frame and the identifiers of the Virtual Channel and the MAP channel (for TC only). +* A7/2 - CryptoLib shall have process security functions for each transfer frame type supported that contains input parameters of a payload containing the frame and the identifiers of the Virtual Channel and the MAP channel (for TC only). +* A7.1.1/1 - CryptoLib's TM apply security payload shall consist of the first octet of the transfer frame primary header to the last octet of the fixed-length protocol data unit of the TM frame. +* A7.1.1/2 - CryptoLib's TC apply security payload shall consist of the first octet of the transfer frame primary header to the last octet of the transfer frame data field. +* A7.1.1/3 - CryptoLib's AOS apply security payload shall consist of the first octet of the transfer frame primary header to the last octet of the transfer frame data field. +* A7.1.1/5 - CryptoLib's apply security functions shall confirm the managed security association data matches the global virtual channel identifier (GVCID) parameter in the partially formatted transfer frame contained in the apply security payload. +* A7.1.1/6 - CryptoLib's TC apply security function shall confirm the global multiplexer access point identifier (GMAP_ID) parameter determined by the GVCID in the partially formatted transfer frame in the TC apply security payload is valid if the virtual channel specified is using segment headers. +* A7.1.1/7 - CryptoLib's TC apply security function transfer frame data field shall be plaintext if the cryptographic algorithm is authenticated encryption. +* A7.1.1/8 - CryptoLib's TC apply security function additional authenticated data (AAD) shall be the portion from the first octet of the Authentication Payload to the octet immediately preceding the Transfer Frame Data Field. +* A7.1.1/9 - CryptoLib's TC apply security function shall encrypt the Transfer Frame Data Field if encryption is selected for the security association in use. +* A7.1.1/10 - CryptoLib's TC apply security function shall place the number of fill bytes used into the Pad Length field of the Security Header if the algorithm and mode selected for the security association in use require. +* A7.1.1/11 - CryptoLib's TC apply security function shall increment the SA's managed sequence number by one if authentication is selected for the security association in use. +* A7.1.1/12 - CryptoLib's TC apply security function shall expect the managed sequence number in the Sequence Number field of the Security header, unless the security association (SA) specified use of the Initialization Vector field of the Security header instead if authentication is selected for an SA. +* A7.1.1/13 - CryptoLib's TC apply security function shall complete the Security Header for each transfer frame if authentication is selected for the security association in use. +* A7.1.1/14 - CryptoLib's TC apply security function shall apply the security association's (SA) authentication bit mask in a bitwise-AND operation against the partial frame if authentication is selected for the SA in use. +* A7.1.1/15 - CryptoLib's TC apply security function shall compute a MAC over the authentication payload if authentication is selected for the security association in use. +* A7.1.1/16 - CryptoLib's TC apply security function shall truncate the least-significant bits of the computed MAC, if necessary, if authentication is selected for the security association in use. +* A7.1.1/18 - CryptoLib's TC apply security function shall return a unique status to the caller per error type. +* A7.1.2/1 - CryptoLib's TM process security payload shall consist of the first octet of the transfer frame primary header to the last octet of the security trailer, if present, or the last octet of the Transfer Frame Data Field. +* A7.1.2/2 - CryptoLib's TC process security payload shall consist of the first octet of the transfer frame primary header to the last octet of the security trailer, if present, or the last octet of the Transfer Frame Data Field. +* A7.1.2/3 - CryptoLib's AOS process security payload shall consist of the first octet of the transfer frame primary header to the last octet of the security trailer, if present, or the last octet of the Transfer Frame Data Field. +* A7.1.2/5 - CryptoLib's process security functions shall confirm the managed security association data matches the global virtual channel identifier (GVCID) parameter in the partially formatted transfer frame contained in the apply security payload. +* A7.1.2/6 - CryptoLib's TC process security function shall confirm the global multiplexer access point identifier (GMAP_ID) parameter determined by the GVCID in the partially formatted transfer frame in the TC process security payload is valid if the virtual channel specified is using segment headers. +* A7.1.2/7 - CryptoLib's process security functions shall discard frames with wrong security associations and report exceptions. +* A7.1.2/8 - CryptoLib's process security function transfer frame data field shall be plaintext if the cryptographic algorithm is authenticated encryption. +* A7.1.2/9 - CryptoLib's process security function additional authenticated data (AAD) shall be the portion from the first octet of the Authentication Payload to the octet immediately preceding the Transfer Frame Data Field. +* A7.1.2/10 - CryptoLib's process security function shall apply the security association's (SA) authentication bit mask in a bitwise-AND operation against the partial frame if authentication is selected for the SA in use. +* A7.1.2/12 - CryptoLib's process security function shall compute a MAC over the authentication payload if authentication is selected for the security association in use. +* A7.1.2/13 - CryptoLib's process security function shall truncate the least-significant bits of the computed MAC, if necessary, if authentication is selected for the security association in use. +* A7.1.2/14 - CryptoLib's process security function shall verify that the computed MAC matches the MAC received in the Security Trailer if authentication is selected for the security association in use. +* A7.1.2/15 - CryptoLib's process security function shall report an exception to the service user for frames in which the received frame fails MAC verification and discard those frame if authentication is selected for the SA in use. +* A7.1.2/18 - CryptoLib's process security function shall extract the received sequence number from either the Sequence Number field of the Initialization Vector field of the Security Header according to the options specified for that SA if authentication is selected for the SA in use. +* A7.1.2/19 - CryptoLib's process security function shall compare the received sequence number to the managed sequence number if authentication is selected for the SA in use. +* A7.1.2/20 - CryptoLib's process security function shall report an exception to the service user for frames in which the received sequence number is larger than the managed sequence number by a value greater than teh window defined for that SA and discard those frames if authentication is selected for the SA in use. +* A7.1.2/23 - CryptoLib's process security function shall replace the managed sequence number with the received sequence number if the frame passes verification operations and if authentication is selected for the SA in use. +* A7.1.2/25 - CryptoLib's process security function shall decrypt the Transfer Frame Data Field if encryption is selected for the SA in use. +* A7.1.2/26 - CryptoLib's process security function shall extract the count of fill bytes used from the Pad Length field of the Security Header, and remove those fill bytes from the Frame Data field to be returned if encryption is selected for the SA in use. +* A7.1.2/27 - CryptoLib's process security function shall return a unique status to the caller per error type. +* A8.1/1 - CryptoLib's security header shall consist of one mandatory security parameter index in bits 0-15. +* A8.1/2 - CryptoLib's security header may contain an option field of the initialization vector following the SPI. +* A8.1/3 - CryptoLib's security header may contain an option field of the sequence number following the initialization vector. +* A8.1/4 - CryptoLib's security header may contain an option field of the pad length following the sequence number. +* A8.2/1 - CryptoLib's security trailer shall define the presence or absence of the MAC based on a virtual channel or MAP in the security association parameters. + +# CCSDS SDLS-EP PICS +* ... diff --git a/include/crypto_config_structs.h b/include/crypto_config_structs.h index 3ad48826..4d24a048 100644 --- a/include/crypto_config_structs.h +++ b/include/crypto_config_structs.h @@ -190,6 +190,7 @@ typedef enum { CRYPTO_CIPHER_NONE, CRYPTO_CIPHER_AES256_GCM, + CRYPTO_CIPHER_AES256_GCM_SIV, CRYPTO_CIPHER_AES256_CBC, CRYPTO_CIPHER_AES256_CBC_MAC, CRYPTO_CIPHER_AES256_CCM diff --git a/include/crypto_error.h b/include/crypto_error.h index 2f7e213f..ff2f3439 100644 --- a/include/crypto_error.h +++ b/include/crypto_error.h @@ -123,6 +123,7 @@ #define CRYPTO_LIB_ERR_INVALID_SA_SERVICE_TYPE (-51) #define CRYPTO_LIB_ERR_FAIL_SA_SAVE (-52) #define CRYPTO_LIB_ERR_FAIL_SA_LOAD (-53) +#define CRYPTO_LIB_ERR_KEY_VALIDATION (-54) extern char *crypto_enum_errlist_core[]; extern char *crypto_enum_errlist_config[]; diff --git a/src/core/crypto.c b/src/core/crypto.c index 975aa1fc..43991951 100644 --- a/src/core/crypto.c +++ b/src/core/crypto.c @@ -100,7 +100,7 @@ uint8_t Crypto_Is_AEAD_Algorithm(uint32_t cipher_suite_id) // CryptoLib only supports AES-GCM, which is an AEAD (Authenticated Encryption with Associated Data) algorithm, so // return true/1. // TODO - Add cipher suite mapping to which algorithms are AEAD and which are not. - if ((cipher_suite_id == CRYPTO_CIPHER_AES256_GCM) || (cipher_suite_id == CRYPTO_CIPHER_AES256_CBC_MAC)) + if ((cipher_suite_id == CRYPTO_CIPHER_AES256_GCM) || (cipher_suite_id == CRYPTO_CIPHER_AES256_CBC_MAC) || (cipher_suite_id == CRYPTO_CIPHER_AES256_GCM_SIV)) { #ifdef DEBUG printf(KYEL "CRYPTO IS AEAD? : TRUE\n" RESET); @@ -982,7 +982,7 @@ int32_t Crypto_Check_Anti_Replay(SecurityAssociation_t* sa_ptr, uint8_t* arsn, u } // For GCM specifically, if have a valid IV... - if ((sa_ptr->ecs == CRYPTO_CIPHER_AES256_GCM) && (iv_valid == CRYPTO_TRUE)) + if ((sa_ptr->ecs == CRYPTO_CIPHER_AES256_GCM || sa_ptr->ecs == CRYPTO_CIPHER_AES256_GCM_SIV) && (iv_valid == CRYPTO_TRUE)) { // Using ARSN? Need to be valid to increment both if (sa_ptr->arsn_len > 0 && arsn_valid == CRYPTO_TRUE) @@ -998,7 +998,7 @@ int32_t Crypto_Check_Anti_Replay(SecurityAssociation_t* sa_ptr, uint8_t* arsn, u } // If not GCM, and ARSN is valid - can incrmeent it - if (sa_ptr->ecs != CRYPTO_CIPHER_AES256_GCM && arsn_valid == CRYPTO_TRUE) + if ((sa_ptr->ecs != CRYPTO_CIPHER_AES256_GCM && sa_ptr->ecs != CRYPTO_CIPHER_AES256_GCM_SIV) && arsn_valid == CRYPTO_TRUE) { memcpy(sa_ptr->arsn, arsn, sa_ptr->arsn_len); } @@ -1026,6 +1026,9 @@ int32_t Crypto_Get_ECS_Algo_Keylen(uint8_t algo) case CRYPTO_CIPHER_AES256_GCM: retval = 32; break; + case CRYPTO_CIPHER_AES256_GCM_SIV: + retval = 32; + break; case CRYPTO_CIPHER_AES256_CBC: retval = 32; break; diff --git a/src/core/crypto_config.c b/src/core/crypto_config.c index c163cbdc..1afecca8 100644 --- a/src/core/crypto_config.c +++ b/src/core/crypto_config.c @@ -176,62 +176,68 @@ int32_t Crypto_Init(void) // #endif /* Key Interface */ - if (crypto_config.key_type == KEY_TYPE_CUSTOM) - { - key_if = get_key_interface_custom(); - } - else if (crypto_config.key_type == KEY_TYPE_INTERNAL) - { - key_if = get_key_interface_internal(); - } - else // KEY_TYPE_KMC - { - key_if = get_key_interface_kmc(); + if (key_if == NULL) { + if (crypto_config.key_type == KEY_TYPE_CUSTOM) + { + key_if = get_key_interface_custom(); + } + else if (crypto_config.key_type == KEY_TYPE_INTERNAL) + { + key_if = get_key_interface_internal(); + } + else // KEY_TYPE_KMC + { + key_if = get_key_interface_kmc(); + } } key_if->key_init(); // TODO: Check and return status on error /* MC Interface */ - if (crypto_config.mc_type == MC_TYPE_CUSTOM) - { - mc_if = get_mc_interface_custom(); - } - else if (crypto_config.mc_type == MC_TYPE_DISABLED) - { - mc_if = get_mc_interface_disabled(); - } - else // MC_TYPE_INTERNAL - { - mc_if = get_mc_interface_internal(); + if (mc_if == NULL) { + if (crypto_config.mc_type == MC_TYPE_CUSTOM) + { + mc_if = get_mc_interface_custom(); + } + else if (crypto_config.mc_type == MC_TYPE_DISABLED) + { + mc_if = get_mc_interface_disabled(); + } + else // MC_TYPE_INTERNAL + { + mc_if = get_mc_interface_internal(); + } } mc_if->mc_initialize(); // TODO: Check and return status on error /* SA Interface */ - // Prepare SA type from config - if (crypto_config.sa_type == SA_TYPE_CUSTOM) - { - sa_if = get_sa_interface_custom(); - } - else if (crypto_config.sa_type == SA_TYPE_INMEMORY) - { - sa_if = get_sa_interface_inmemory(); - } - else if (crypto_config.sa_type == SA_TYPE_MARIADB) - { - if (sa_mariadb_config == NULL) + if (sa_if == NULL) { + // Prepare SA type from config + if (crypto_config.sa_type == SA_TYPE_CUSTOM) + { + sa_if = get_sa_interface_custom(); + } + else if (crypto_config.sa_type == SA_TYPE_INMEMORY) + { + sa_if = get_sa_interface_inmemory(); + } + else if (crypto_config.sa_type == SA_TYPE_MARIADB) { - status = CRYPTO_MARIADB_CONFIGURATION_NOT_COMPLETE; - printf(KRED "ERROR: CryptoLib MariaDB must be configured before intializing!\n" RESET); - return status; // MariaDB connection specified but no configuration exists, return! + if (sa_mariadb_config == NULL) + { + status = CRYPTO_MARIADB_CONFIGURATION_NOT_COMPLETE; + printf(KRED "ERROR: CryptoLib MariaDB must be configured before intializing!\n" RESET); + return status; // MariaDB connection specified but no configuration exists, return! + } + sa_if = get_sa_interface_mariadb(); } - sa_if = get_sa_interface_mariadb(); + else + { + status = SADB_INVALID_SADB_TYPE; + return status; + } // TODO: Error stack } - else - { - status = SADB_INVALID_SADB_TYPE; - return status; - } // TODO: Error stack /* Crypto Interface */ // Determine which cryptographic module is in use diff --git a/src/core/crypto_error.c b/src/core/crypto_error.c index 6894eac1..3725768b 100644 --- a/src/core/crypto_error.c +++ b/src/core/crypto_error.c @@ -74,7 +74,8 @@ char *crypto_enum_errlist_core[] = (char*) "CRYPTO_LIB_ERR_TC_ENUM_USED_FOR_AOS_CONFIG", (char*) "CRYPTO_LIB_ERR_INVALID_SA_SERVICE_TYPE", (char*) "CRYPTO_LIB_ERR_FAIL_SA_SAVE", - (char*) "CRYPTO_LIB_ERR_FAIL_SA_LOAD", + (char*) "CRYPTO_LIB_ERR_FAIL_SA_LOAD", + (char*) "CRYPTO_LIB_ERR_KEY_VALIDATION", }; char *crypto_enum_errlist_config[] = diff --git a/src/crypto/kmc/cryptography_interface_kmc_crypto_service.template.c b/src/crypto/kmc/cryptography_interface_kmc_crypto_service.template.c index 3edaebd0..330ae3ec 100644 --- a/src/crypto/kmc/cryptography_interface_kmc_crypto_service.template.c +++ b/src/crypto/kmc/cryptography_interface_kmc_crypto_service.template.c @@ -2291,6 +2291,8 @@ int32_t cryptography_get_ecs_algo(int8_t algo_enum) return CRYPTO_CIPHER_AES256_GCM; case CRYPTO_CIPHER_AES256_CCM: return CRYPTO_CIPHER_AES256_CCM; + case CRYPTO_CIPHER_AES256_GCM_SIV: + return CRYPTO_CIPHER_AES256_GCM_SIV; default: #ifdef DEBUG diff --git a/src/crypto/libgcrypt/cryptography_interface_libgcrypt.template.c b/src/crypto/libgcrypt/cryptography_interface_libgcrypt.template.c index 90b467d6..e6655096 100644 --- a/src/crypto/libgcrypt/cryptography_interface_libgcrypt.template.c +++ b/src/crypto/libgcrypt/cryptography_interface_libgcrypt.template.c @@ -837,6 +837,7 @@ static int32_t cryptography_aead_decrypt(uint8_t* data_out, size_t len_data_out, // Select correct libgcrypt ecs enum int32_t algo = -1; + int32_t mode = -1; if (ecs != NULL) { algo = cryptography_get_ecs_algo(*ecs); @@ -844,6 +845,11 @@ static int32_t cryptography_aead_decrypt(uint8_t* data_out, size_t len_data_out, { return CRYPTO_LIB_ERR_UNSUPPORTED_ECS; } + mode = cryptography_get_ecs_mode(*ecs); + if (mode == CRYPTO_LIB_ERR_UNSUPPORTED_ECS) + { + return CRYPTO_LIB_ERR_UNSUPPORTED_ECS; + } } else { @@ -858,7 +864,7 @@ static int32_t cryptography_aead_decrypt(uint8_t* data_out, size_t len_data_out, return status; } - gcry_error = gcry_cipher_open(&(tmp_hd), GCRY_CIPHER_AES256, GCRY_CIPHER_MODE_GCM, GCRY_CIPHER_NONE); + gcry_error = gcry_cipher_open(&(tmp_hd), GCRY_CIPHER_AES256, mode, GCRY_CIPHER_NONE); if ((gcry_error & GPG_ERR_CODE_MASK) != GPG_ERR_NO_ERROR) { printf(KRED "ERROR: gcry_cipher_open error code %d\n" RESET, gcry_error & GPG_ERR_CODE_MASK); @@ -903,6 +909,10 @@ static int32_t cryptography_aead_decrypt(uint8_t* data_out, size_t len_data_out, if (decrypt_bool == CRYPTO_TRUE) { + if (mode == GCRY_CIPHER_MODE_GCM_SIV || mode == GCRY_CIPHER_MODE_SIV) + { + gcry_cipher_set_decryption_tag(tmp_hd, mac, mac_size); + } gcry_error = gcry_cipher_decrypt(tmp_hd, data_out, // plaintext output len_data_out, // length of data @@ -912,6 +922,7 @@ static int32_t cryptography_aead_decrypt(uint8_t* data_out, size_t len_data_out, if ((gcry_error & GPG_ERR_CODE_MASK) != GPG_ERR_NO_ERROR) { printf(KRED "ERROR: gcry_cipher_decrypt error code %d\n" RESET, gcry_error & GPG_ERR_CODE_MASK); + printf(KRED "Failure: %s/%s\n", gcry_strsource(gcry_error), gcry_strerror(gcry_error)); gcry_cipher_close(tmp_hd); status = CRYPTO_LIB_ERR_DECRYPT_ERROR; return status; @@ -927,6 +938,7 @@ static int32_t cryptography_aead_decrypt(uint8_t* data_out, size_t len_data_out, if ((gcry_error & GPG_ERR_CODE_MASK) != GPG_ERR_NO_ERROR) { printf(KRED "ERROR: gcry_cipher_decrypt error code %d\n" RESET, gcry_error & GPG_ERR_CODE_MASK); + printf(KRED "Failure: %s/%s\n", gcry_strsource(gcry_error), gcry_strerror(gcry_error)); gcry_cipher_close(tmp_hd); status = CRYPTO_LIB_ERR_DECRYPT_ERROR; return status; @@ -969,7 +981,7 @@ static int32_t cryptography_aead_decrypt(uint8_t* data_out, size_t len_data_out, if ((gcry_error & GPG_ERR_CODE_MASK) != GPG_ERR_NO_ERROR) { printf(KRED "ERROR: gcry_cipher_checktag error code %d\n" RESET, gcry_error & GPG_ERR_CODE_MASK); - fprintf(stderr, "gcry_cipher_decrypt failed: %s\n", gpg_strerror(gcry_error)); + printf(KRED "Failure: %s/%s\n", gcry_strsource(gcry_error), gcry_strerror(gcry_error)); gcry_cipher_close(tmp_hd); status = CRYPTO_LIB_ERR_MAC_VALIDATION_ERROR; return status; @@ -1023,6 +1035,9 @@ int32_t cryptography_get_ecs_algo(int8_t algo_enum) case CRYPTO_CIPHER_AES256_GCM: algo = GCRY_CIPHER_AES256; break; + case CRYPTO_CIPHER_AES256_GCM_SIV: + algo = GCRY_CIPHER_AES256; + break; case CRYPTO_CIPHER_AES256_CBC: algo = GCRY_CIPHER_AES256; break; @@ -1053,6 +1068,9 @@ int32_t cryptography_get_ecs_mode(int8_t algo_enum) case CRYPTO_CIPHER_AES256_GCM: mode = GCRY_CIPHER_MODE_GCM; break; + case CRYPTO_CIPHER_AES256_GCM_SIV: + mode = GCRY_CIPHER_MODE_GCM_SIV; + break; case CRYPTO_CIPHER_AES256_CBC: mode = GCRY_CIPHER_MODE_CBC; break; diff --git a/src/crypto/wolfssl/cryptography_interface_wolfssl.template.c b/src/crypto/wolfssl/cryptography_interface_wolfssl.template.c index b668381d..238f1e4b 100644 --- a/src/crypto/wolfssl/cryptography_interface_wolfssl.template.c +++ b/src/crypto/wolfssl/cryptography_interface_wolfssl.template.c @@ -422,6 +422,7 @@ static int32_t cryptography_encrypt(uint8_t* data_out, size_t len_data_out, } break; + case CRYPTO_CIPHER_AES256_CBC: status = wc_AesSetKey(&enc, key, len_key, iv, AES_ENCRYPTION); if (status == 0) diff --git a/src/mc/internal/mc_interface_internal.template.c b/src/mc/internal/mc_interface_internal.template.c index 170c9e6f..974fd567 100644 --- a/src/mc/internal/mc_interface_internal.template.c +++ b/src/mc/internal/mc_interface_internal.template.c @@ -53,11 +53,11 @@ static int32_t mc_initialize(void) int32_t status = CRYPTO_LIB_SUCCESS; /* Open log */ - mc_file_ptr = fopen("log.txt", "a"); + mc_file_ptr = fopen(MC_LOG_PATH, "a"); if (mc_file_ptr == NULL) { status = CRYPTO_LIB_ERR_MC_INIT; - printf(KRED "ERROR: Monitoring andcontrol initialization - internal failed\n" RESET); + printf(KRED "ERROR: Monitoring and control initialization - internal failed\n" RESET); } return status; diff --git a/src/sa/internal/sa_interface_inmemory.template.c b/src/sa/internal/sa_interface_inmemory.template.c index a7bda4c1..a045c1d1 100644 --- a/src/sa/internal/sa_interface_inmemory.template.c +++ b/src/sa/internal/sa_interface_inmemory.template.c @@ -544,6 +544,51 @@ void sa_populate(void) sa_perform_save(&sa[0]); } +/** + * @brief Function Key_Validation() + * Validates the use of a single key per encryption type per SA + * At most an SA can contain 2 unique Keys. These my not be utilized in another SA + */ +int32_t key_validation(void) +{ + int32_t status = CRYPTO_LIB_SUCCESS; + int i = 0; + int j = 0; + for(i = 0; i < NUM_SA; i++) + { + uint16_t i_ekid = sa[i].ekid; + uint16_t i_akid = sa[i].akid; + + if(i_ekid == i_akid) + { + status = CRYPTO_LIB_ERR_KEY_VALIDATION; +#ifdef DEBUG + printf(KRED "SA Key Validation FAILURE!\n"); + printf("Key Duplication: SA #%d, EKID: %d, AKID: %d\n", i, i_ekid, i_akid); + printf("\n"RESET); +#endif + break; + } + + for(j = i+1; j < NUM_SA; j++) + { + uint16_t j_ekid = sa[j].ekid; + uint16_t j_akid = sa[j].akid; + + if((i_ekid == j_ekid) || (i_ekid == j_akid) || (i_akid == j_ekid) || (i_akid == j_akid) || (j_ekid == j_akid)) + { + status = CRYPTO_LIB_ERR_KEY_VALIDATION; +#ifdef DEBUG + printf(KRED "SA Key Validation FAILURE!\n"); + printf("Key Duplication SA: %d, EKID: %d, AKID: %d\n\tSA: %d, EKID: %d, AKID: %d\n", i, i_ekid, i_akid, j, j_ekid, j_akid); + printf("\n"RESET); +#endif + break; + } + } + } + return status; +} /** * @brief Function; sa_config @@ -561,6 +606,9 @@ int32_t sa_config(void) if(use_internal) { sa_populate(); +#ifdef KEY_VALIDATION + status = key_validation(); +#endif } return status; @@ -627,6 +675,9 @@ int32_t sa_init(void) } sa_populate(); +#ifdef KEY_VALIDATION + status = key_validation(); +#endif } return status; } diff --git a/support/Dockerfile b/support/Dockerfile index b92f2856..08b55592 100644 --- a/support/Dockerfile +++ b/support/Dockerfile @@ -5,13 +5,11 @@ # ARG WOLFSSL_VERSION=5.6.0-stable -FROM ubuntu +FROM ubuntu:jammy-20240212 AS CL0 -ARG WOLFSSL_VERSION - -RUN set -eux \ - # install deps - && buildDeps=' \ +ARG DEBIAN_FRONTEND=noninteractive +RUN apt-get update -y \ + && apt-get install -y \ autoconf \ automake \ ca-certificates \ @@ -26,25 +24,39 @@ RUN set -eux \ libcurl4-openssl-dev \ libmariadb-dev \ libmariadb-dev-compat \ - libgcrypt20-dev \ libtool \ make \ python3-dev \ python3-pip \ unzip \ - ' \ - && apt-get update \ - && apt-get install -y --no-install-recommends $buildDeps \ - && rm -r /var/lib/apt/lists/* \ + && rm -rf /var/lib/apt/lists/* \ + && pip3 install pycryptodome + +FROM CL0 AS CL1 +ARG GPG_ERROR_VERSION=1.50 +ARG GCRYPT_VERSION=1.11.0 +RUN curl \ + -LS https://www.gnupg.org/ftp/gcrypt/libgpg-error/libgpg-error-${GPG_ERROR_VERSION}.tar.bz2 \ + -o /tmp/libgpg-error-${GPG_ERROR_VERSION}.tar.bz2 \ + && tar -xjf /tmp/libgpg-error-${GPG_ERROR_VERSION}.tar.bz2 -C /tmp/ \ + && cd /tmp/libgpg-error-${GPG_ERROR_VERSION} \ + && ./configure \ + && make install \ + && curl \ + -LS https://www.gnupg.org/ftp/gcrypt/libgcrypt/libgcrypt-${GCRYPT_VERSION}.tar.bz2 \ + -o /tmp/libgcrypt-${GCRYPT_VERSION}.tar.bz2 \ + && tar -xjf /tmp/libgcrypt-${GCRYPT_VERSION}.tar.bz2 -C /tmp/ \ + && cd /tmp/libgcrypt-${GCRYPT_VERSION} \ + && ./configure \ + && make install - # download source files - && curl \ +FROM CL1 AS CL2 +ARG WOLFSSL_VERSION=5.6.0-stable +RUN curl \ -LS https://github.com/wolfSSL/wolfssl/archive/v${WOLFSSL_VERSION}.zip \ -o v${WOLFSSL_VERSION}.zip \ && unzip v${WOLFSSL_VERSION}.zip \ && rm v${WOLFSSL_VERSION}.zip \ - - # build and install wolfssl && cd wolfssl-${WOLFSSL_VERSION} \ && mkdir -p build \ && cd build \ @@ -52,10 +64,3 @@ RUN set -eux \ && cmake --build . \ && make install \ && ldconfig - - # cleanup - #&& cd .. \ - #&& rm -r wolfssl-${WOLFSSL_VERSION} - #&& apt-get purge -y --auto-remove $buildDeps - -RUN pip3 install pycryptodome diff --git a/support/scripts/build_internal.sh b/support/scripts/build_internal.sh index c6e326f2..c41dd2c3 100755 --- a/support/scripts/build_internal.sh +++ b/support/scripts/build_internal.sh @@ -9,4 +9,6 @@ SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd ) source $SCRIPT_DIR/env.sh -cmake $BASE_DIR -DCODECOV=1 -DDEBUG=1 -DMC_INTERNAL=1 -DTEST=1 -DTEST_ENC=1 -DSA_FILE=1 && make && make test +rm $BASE_DIR/CMakeCache.txt + +cmake $BASE_DIR -DCODECOV=1 -DDEBUG=1 -DMC_INTERNAL=1 -DTEST=1 -DTEST_ENC=1 -DSA_FILE=1 -DKEY_VALIDATION=0 && make && make test diff --git a/support/scripts/build_kmc.sh b/support/scripts/build_kmc.sh index 95c1489f..2c18bd7a 100755 --- a/support/scripts/build_kmc.sh +++ b/support/scripts/build_kmc.sh @@ -9,4 +9,6 @@ SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd ) source $SCRIPT_DIR/env.sh +rm $BASE_DIR/CMakeCache.txt + cmake $BASE_DIR -DCODECOV=1 -DDEBUG=1 -DCRYPTO_KMC=1 -DKEY_KMC=1 -DMC_DISABLED=1 -DSA_MARIADB=1 -DTEST=1 -DTEST_ENC=1 -DKMC_CFFI_EXCLUDE=1 -DSA_FILE=1 && make && make test diff --git a/support/scripts/build_minimal.sh b/support/scripts/build_minimal.sh index c07c09a3..f9781ae7 100755 --- a/support/scripts/build_minimal.sh +++ b/support/scripts/build_minimal.sh @@ -9,4 +9,6 @@ SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd ) source $SCRIPT_DIR/env.sh +rm $BASE_DIR/CMakeCache.txt + cmake $BASE_DIR && make && make test diff --git a/support/scripts/build_rhel.sh b/support/scripts/build_rhel.sh index 94053036..644fa9b3 100755 --- a/support/scripts/build_rhel.sh +++ b/support/scripts/build_rhel.sh @@ -9,4 +9,7 @@ SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd ) source $SCRIPT_DIR/env.sh +rm $BASE_DIR/CMakeCache.txt + cmake $BASE_DIR -DCODECOV=1 -DDEBUG=1 -DMC_INTERNAL=1 -DTEST=1 -DTEST_ENC=1 -DSA_FILE=1 && make && make test + diff --git a/support/scripts/build_support.sh b/support/scripts/build_support.sh index 4e92ea6c..0392bd8f 100755 --- a/support/scripts/build_support.sh +++ b/support/scripts/build_support.sh @@ -9,4 +9,6 @@ SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd ) source $SCRIPT_DIR/env.sh +rm $BASE_DIR/CMakeCache.txt + cmake $BASE_DIR -DCODECOV=1 -DDEBUG=1 -DSUPPORT=1 -DTEST=1 -DTEST_ENC=1 && make && make test diff --git a/support/scripts/build_wolf.sh b/support/scripts/build_wolf.sh index 0cae1611..a646e932 100755 --- a/support/scripts/build_wolf.sh +++ b/support/scripts/build_wolf.sh @@ -9,4 +9,6 @@ SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd ) source $SCRIPT_DIR/env.sh +rm $BASE_DIR/CMakeCache.txt + cmake $BASE_DIR -DCODECOV=1 -DDEBUG=1 -DCRYPTO_LIBGCRYPT=0 -DCRYPTO_WOLFSSL=1 -DTEST=1 -DTEST_ENC=1 -DSA_FILE=1 && make && make test diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index ac9352a8..4973346f 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -57,6 +57,12 @@ add_test(NAME UT_TM_PROCESS COMMAND ${PROJECT_BINARY_DIR}/bin/ut_tm_process WORKING_DIRECTORY ${PROJECT_TEST_DIR}) +if(NOT ${CRYPTO_WOLFSSL}) + add_test(NAME UT_AES_GCM_SIV + COMMAND ${PROJECT_BINARY_DIR}/bin/ut_aes_gcm_siv + WORKING_DIRECTORY ${PROJECT_TEST_DIR}) +endif() + if(SA_FILE) add_test(NAME UT_SA_SAVE COMMAND ${PROJECT_BINARY_DIR}/bin/ut_sa_save diff --git a/test/include/ut_aes_gcm_siv.h b/test/include/ut_aes_gcm_siv.h new file mode 100644 index 00000000..99fb7572 --- /dev/null +++ b/test/include/ut_aes_gcm_siv.h @@ -0,0 +1,18 @@ +#ifndef CRYPTOLIB_UT_AES_GCM_SIV_H +#define CRYPTOLIB_UT_AES_GCM_SIV_H + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include "crypto.h" +#include "shared_util.h" +#include +#include "cryptography_interface.h" + +#ifdef __cplusplus +} /* Close scope of 'extern "C"' declaration which encloses file. */ +#endif + +#endif //CRYPTOLIB_UT_AES_GCM_SIV_H \ No newline at end of file diff --git a/test/unit/ut_aes_gcm_siv.c b/test/unit/ut_aes_gcm_siv.c new file mode 100644 index 00000000..8610ffdd --- /dev/null +++ b/test/unit/ut_aes_gcm_siv.c @@ -0,0 +1,474 @@ +// /* Copyright (C) 2009 - 2022 National Aeronautics and Space Admirfcration. +// All Foreign Rights are Reserved to the U.S. Government. + +// This software is provided "as is" without any warranty of any kind, either expressed, implied, or statutory, +// including, but not limited to, any warranty that the software will conform to specifications, any implied warranties +// of merchantability, fitness for a particular purpose, and freedom from infringement, and any warranty that the +// documentation will conform to the program, or any warranty that the software will be error free. + +// In no event shall NASA be liable for any damages, including, but not limited to direct, indirect, special or +// consequential damages, arising out of, resulting from, or in any way connected with the software or its +// documentation, whether or not based upon warranty, contract, tort or otherwise, and whether or not loss was sustained +// from, or arose out of the results of, or use of, the software, documentation or services provided hereunder. + +// ITC Team +// NASA IV&V +// jstar-development-team@mail.nasa.gov +// */ + +#include "ut_aes_gcm_siv.h" +#include "crypto.h" +#include "crypto_error.h" +#include "sa_interface.h" +#include "utest.h" + +/** + * @brief Unit Test: Crypto ECS Get Algorithm key length response for AES-GCM-SIV + **/ +UTEST(AES_GCM_SIV, GET_ECS_ALGO_KEY_LEN_SIV) +{ + remove("sa_save_file.bin"); + int32_t algo_keylen = -1; + uint8_t crypto_algo = CRYPTO_CIPHER_AES256_GCM_SIV; + algo_keylen = Crypto_Get_ACS_Algo_Keylen(crypto_algo); + ASSERT_EQ(algo_keylen, 32); + Crypto_Shutdown(); +} + +/** + * @brief Unit Test: Crypto ECS Get Algorithm response for AES-GCM-SIV + **/ +UTEST(AES_GCM_SIV, GET_ECS_ALGO_SIV) +{ + remove("sa_save_file.bin"); + Crypto_Init_TC_Unit_Test(); + int32_t libgcrypt_algo = -1; + int8_t crypto_algo = CRYPTO_CIPHER_AES256_GCM_SIV; + + libgcrypt_algo = cryptography_if->cryptography_get_ecs_algo(crypto_algo); + ASSERT_EQ(libgcrypt_algo, 9); + Crypto_Shutdown(); +} + +/** + * @brief Validation Test: AEAD_AES_256_GCM_SIV Test Vectors + * Reference: + * https://datatracker.ietf.org/doc/rfc8452/?include_text=1 C.2. Second Example + * Recreated test vectors with https://github.com/line/aes-gcm-siv/tree/master, then input CryptoLib test vectors to generate truth data. + **/ +UTEST(AES_GCM_SIV, AES_GCM_SIV_256_KEY_32_PT_8_ENC_TEST_1) +{ + remove("sa_save_file.bin"); + uint8_t* ptr_enc_frame = NULL; + uint16_t enc_frame_len = 0; + // Setup & Initialize CryptoLib + Crypto_Config_CryptoLib(KEY_TYPE_INTERNAL, MC_TYPE_INTERNAL, SA_TYPE_INMEMORY, CRYPTOGRAPHY_TYPE_LIBGCRYPT, + IV_INTERNAL, CRYPTO_TC_CREATE_FECF_TRUE, TC_PROCESS_SDLS_PDUS_TRUE, TC_HAS_PUS_HDR, + TC_IGNORE_SA_STATE_FALSE, TC_IGNORE_ANTI_REPLAY_FALSE, TC_UNIQUE_SA_PER_MAP_ID_FALSE, + TC_CHECK_FECF_TRUE, 0x3F, SA_INCREMENT_NONTRANSMITTED_IV_TRUE); + Crypto_Config_Add_Gvcid_Managed_Parameter(0, 0x0003, 0, TC_NO_FECF, TC_NO_SEGMENT_HDRS, TC_OCF_NA, 1024, AOS_FHEC_NA, AOS_IZ_NA, 0); + Crypto_Config_Add_Gvcid_Managed_Parameter(0, 0x0003, 1, TC_NO_FECF, TC_NO_SEGMENT_HDRS, TC_OCF_NA, 1024, AOS_FHEC_NA, AOS_IZ_NA, 0); + Crypto_Init(); + SaInterface sa_if = get_sa_interface_inmemory(); + crypto_key_t* ekp = NULL; + + // RFC supplied vectors + // NOTE: Added Transfer Frame header to the plaintext + char* buffer_rfc_pt_h = "2003000c000100000000000000"; + char* buffer_rfc_aad_h = ""; + char* buffer_rfc_key_h = "0100000000000000000000000000000000000000000000000000000000000000"; + char* buffer_rfc_nonce_h = "030000000000000000000000"; + char* buffer_rfc_ct_h = "4fa7a4cb7d3434f8a2855b40016daccb62a454551878fc26"; + uint8_t* buffer_rfc_pt_b, *buffer_rfc_aad_b, *buffer_rfc_key_b, *buffer_rfc_nonce_b, *buffer_rfc_ct_b = NULL; + int buffer_rfc_pt_len, buffer_rfc_aad_len, buffer_rfc_key_len, buffer_rfc_nonce_len, buffer_rfc_ct_len = 0; + + // Expose/setup SAs for testing + SecurityAssociation_t* test_association = NULL; + test_association = malloc(sizeof(SecurityAssociation_t) * sizeof(uint8_t)); + // Deactivate SA 1 + sa_if->sa_get_from_spi(1, &test_association); + test_association->sa_state = SA_NONE; + // Activate SA 9 + sa_if->sa_get_from_spi(9, &test_association); + test_association->arsn_len = 0; + test_association->sa_state = SA_OPERATIONAL; + test_association->ast = 1; + test_association->est = 1; + test_association->ecs_len = 1; + test_association->ecs = CRYPTO_CIPHER_AES256_GCM_SIV; + test_association->acs_len = 1; + test_association->acs = CRYPTO_MAC_CMAC_AES256; + test_association->stmacf_len = 16; + + // Insert key into keyring of SA 9 + hex_conversion(buffer_rfc_key_h, (char**) &buffer_rfc_key_b, &buffer_rfc_key_len); + ekp = key_if->get_key(test_association->ekid); + memcpy(ekp->value, buffer_rfc_key_b, buffer_rfc_key_len); + + // Convert input plaintext + // TODO: Account for length of header and FECF (5+2) + hex_conversion(buffer_rfc_pt_h, (char**) &buffer_rfc_pt_b, &buffer_rfc_pt_len); + // Convert/Set input AAD + hex_conversion(buffer_rfc_aad_h, (char**) &buffer_rfc_aad_b, &buffer_rfc_aad_len); + memcpy(test_association->abm, buffer_rfc_aad_b + 5, buffer_rfc_aad_len); + hex_conversion(buffer_rfc_nonce_h, (char**) &buffer_rfc_nonce_b, &buffer_rfc_nonce_len); + memcpy(test_association->iv, buffer_rfc_nonce_b, buffer_rfc_nonce_len); + // Convert input ciphertext + hex_conversion(buffer_rfc_ct_h, (char**) &buffer_rfc_ct_b, &buffer_rfc_ct_len); + + Crypto_TC_ApplySecurity(buffer_rfc_pt_b, buffer_rfc_pt_len, &ptr_enc_frame, &enc_frame_len); + // Note: For comparison, interested in the TF payload (exclude headers and FECF if present) + // Calc payload index: total length - pt length + uint16_t enc_data_idx = enc_frame_len - buffer_rfc_ct_len; + Crypto_Shutdown(); + for (int i = 0; i < buffer_rfc_pt_len - 7; i++) + { + printf("[%d]: %02x -> %02x \n", i, *(ptr_enc_frame + enc_data_idx), buffer_rfc_ct_b[i]); + ASSERT_EQ(*(ptr_enc_frame + enc_data_idx), buffer_rfc_ct_b[i]); + enc_data_idx++; + } + //ASSERT_EQ(1,0); + free(ptr_enc_frame); + free(buffer_rfc_pt_b); + free(buffer_rfc_aad_b); + free(buffer_rfc_nonce_b); + free(buffer_rfc_ct_b); + free(buffer_rfc_key_b); +} + +/** + * @brief Validation Test: AEAD_AES_256_GCM_SIV Test Vectors + * Reference: + * https://datatracker.ietf.org/doc/rfc8452/?include_text=1 C.2. Second Example + * Recreated test vectors with https://github.com/line/aes-gcm-siv/tree/master, then input CryptoLib test vectors to generate truth data. + **/ +UTEST(AES_GCM_SIV, AES_GCM_SIV_256_KEY_32_PT_8_DEC_TEST_1) +{ + remove("sa_save_file.bin"); + uint8_t* ptr_enc_frame = NULL; + + // Setup & Initialize CryptoLib + Crypto_Config_CryptoLib(KEY_TYPE_INTERNAL, MC_TYPE_INTERNAL, SA_TYPE_INMEMORY, CRYPTOGRAPHY_TYPE_LIBGCRYPT, + IV_INTERNAL, CRYPTO_TC_CREATE_FECF_TRUE, TC_PROCESS_SDLS_PDUS_TRUE, TC_HAS_PUS_HDR, + TC_IGNORE_SA_STATE_FALSE, TC_IGNORE_ANTI_REPLAY_FALSE, TC_UNIQUE_SA_PER_MAP_ID_FALSE, + TC_CHECK_FECF_TRUE, 0x3F, SA_INCREMENT_NONTRANSMITTED_IV_FALSE); + Crypto_Config_Add_Gvcid_Managed_Parameter(0, 0x0003, 0, TC_NO_FECF, TC_NO_SEGMENT_HDRS, TC_OCF_NA, 1024, AOS_FHEC_NA, AOS_IZ_NA, 0); + Crypto_Config_Add_Gvcid_Managed_Parameter(0, 0x0003, 1, TC_NO_FECF, TC_NO_SEGMENT_HDRS, TC_OCF_NA, 1024, AOS_FHEC_NA, AOS_IZ_NA, 0); + Crypto_Init(); + SaInterface sa_if = get_sa_interface_inmemory(); + crypto_key_t* ekp = NULL; + + // rfc supplied vectors + // NOTE: Added Transfer Frame header to the plaintext + char* buffer_rfc_key_h = "0100000000000000000000000000000000000000000000000000000000000000"; + char* buffer_rfc_pt_h = "2003000c000100000000000000"; + char* buffer_rfc_aad_h = ""; + char* buffer_rfc_nonce_h = "030000000000000000000000"; + char* buffer_rfc_et_h = "2003002a0000090300000000000000000000004fa7a4cb7d3434f8a2855b40016daccb62a454551878fc26"; + uint8_t* buffer_rfc_pt_b, *buffer_rfc_nonce_b, *buffer_rfc_et_b, *buffer_rfc_key_b, *buffer_rfc_aad_b = NULL; + int buffer_rfc_pt_len, buffer_rfc_nonce_len, buffer_rfc_et_len, buffer_rfc_key_len, buffer_rfc_aad_len = 0; + + // Setup Processed Frame For Decryption + TC_t* tc_rfc_processed_frame; + tc_rfc_processed_frame = malloc(sizeof(uint8_t) * TC_SIZE); + + // Expose/setup SAs for testing + SecurityAssociation_t* test_association = NULL; + test_association = malloc(sizeof(SecurityAssociation_t) * sizeof(uint8_t)); + // Deactivate SA 1 + sa_if->sa_get_from_spi(1, &test_association); + test_association->sa_state = SA_NONE; + // Activate SA 9 + sa_if->sa_get_from_spi(9, &test_association); + test_association->arsn_len = 0; + test_association->sa_state = SA_OPERATIONAL; + test_association->ast = 1; + test_association->est = 1; + test_association->ecs_len = 1; + test_association->ecs = CRYPTO_CIPHER_AES256_GCM_SIV; + test_association->stmacf_len = 16; + + // Insert key into keyring of SA 9 + hex_conversion(buffer_rfc_key_h, (char**) &buffer_rfc_key_b, &buffer_rfc_key_len); + ekp = key_if->get_key(test_association->ekid); + memcpy(ekp->value, buffer_rfc_key_b, buffer_rfc_key_len); + + // Convert input plaintext + // TODO: Account for length of header and FECF (5+2) + hex_conversion(buffer_rfc_pt_h, (char**) &buffer_rfc_pt_b, &buffer_rfc_pt_len); + // Convert/Set input nonce + hex_conversion(buffer_rfc_nonce_h, (char**) &buffer_rfc_nonce_b, &buffer_rfc_nonce_len); + memcpy(test_association->iv, buffer_rfc_nonce_b, buffer_rfc_nonce_len); + hex_conversion(buffer_rfc_aad_h, (char**) &buffer_rfc_aad_b, &buffer_rfc_aad_len); + // Convert input encryptedtext + hex_conversion(buffer_rfc_et_h, (char**) &buffer_rfc_et_b, &buffer_rfc_et_len); + + Crypto_TC_ProcessSecurity(buffer_rfc_et_b, &buffer_rfc_et_len, tc_rfc_processed_frame); + + for (int i = 0; i < tc_rfc_processed_frame->tc_pdu_len; i++) + { + + if (buffer_rfc_pt_b[i + 5] != tc_rfc_processed_frame->tc_pdu[i]) + { + printf("[%d]: %02x -> %02x \n", i, buffer_rfc_pt_b[i + 5], tc_rfc_processed_frame->tc_pdu[i]); + } + ASSERT_EQ(buffer_rfc_pt_b[i + 5], tc_rfc_processed_frame->tc_pdu[i]); + } + Crypto_Shutdown(); + free(ptr_enc_frame); + free(buffer_rfc_pt_b); + free(buffer_rfc_nonce_b); + free(buffer_rfc_aad_b); + free(buffer_rfc_et_b); + free(buffer_rfc_key_b); +} + +/** + * @brief Validation Test: AEAD_AES_256_GCM_SIV Test Vectors + * Reference: + * https://datatracker.ietf.org/doc/rfc8452/?include_text=1 C.2. + * Recreated test vectors with https://github.com/line/aes-gcm-siv/tree/master, then input CryptoLib test vectors to generate truth data. + **/ +UTEST(AES_GCM_SIV, AES_GCM_SIV_256_KEY_32_PT_8_ENC_TEST_2) +{ + remove("sa_save_file.bin"); + uint8_t* ptr_enc_frame = NULL; + uint16_t enc_frame_len = 0; + // Setup & Initialize CryptoLib + Crypto_Config_CryptoLib(KEY_TYPE_INTERNAL, MC_TYPE_INTERNAL, SA_TYPE_INMEMORY, CRYPTOGRAPHY_TYPE_LIBGCRYPT, + IV_INTERNAL, CRYPTO_TC_CREATE_FECF_TRUE, TC_PROCESS_SDLS_PDUS_TRUE, TC_NO_PUS_HDR, + TC_IGNORE_SA_STATE_FALSE, TC_IGNORE_ANTI_REPLAY_FALSE, TC_UNIQUE_SA_PER_MAP_ID_FALSE, + TC_CHECK_FECF_TRUE, 0x3F, SA_INCREMENT_NONTRANSMITTED_IV_TRUE); + Crypto_Config_Add_Gvcid_Managed_Parameter(0, 0x0003, 0, TC_NO_FECF, TC_NO_SEGMENT_HDRS, TC_OCF_NA, 1024, AOS_FHEC_NA, AOS_IZ_NA, 0); + Crypto_Config_Add_Gvcid_Managed_Parameter(0, 0x0003, 1, TC_NO_FECF, TC_NO_SEGMENT_HDRS, TC_OCF_NA, 1024, AOS_FHEC_NA, AOS_IZ_NA, 0); + Crypto_Init(); + SaInterface sa_if = get_sa_interface_inmemory(); + crypto_key_t* ekp = NULL; + + // RFC supplied vectors + // NOTE: Added Transfer Frame header to the plaintext + char* buffer_rfc_pt_h = "2003001000010000000000000000000000"; + char* buffer_rfc_aad_h = ""; + char* buffer_rfc_key_h = "0100000000000000000000000000000000000000000000000000000000000000"; + char* buffer_rfc_nonce_h = "030000000000000000000000"; + char *buffer_rfc_ct_h = "08fbd140589f067e2772b4a1480eefe49f5ec5c2e65c135e1ad51c58"; + uint8_t* buffer_rfc_pt_b, *buffer_rfc_aad_b, *buffer_rfc_key_b, *buffer_rfc_nonce_b, *buffer_rfc_ct_b = NULL; + int buffer_rfc_pt_len, buffer_rfc_aad_len, buffer_rfc_key_len, buffer_rfc_nonce_len, buffer_rfc_ct_len = 0; + + // Expose/setup SAs for testing + SecurityAssociation_t* test_association = NULL; + test_association = malloc(sizeof(SecurityAssociation_t) * sizeof(uint8_t)); + // Deactivate SA 1 + sa_if->sa_get_from_spi(1, &test_association); + test_association->sa_state = SA_NONE; + // Activate SA 9 + sa_if->sa_get_from_spi(9, &test_association); + test_association->arsn_len = 0; + test_association->sa_state = SA_OPERATIONAL; + test_association->ast = 1; + test_association->est = 1; + test_association->ecs_len = 1; + test_association->ecs = CRYPTO_CIPHER_AES256_GCM_SIV; + test_association->acs_len = 1; + test_association->acs = CRYPTO_MAC_CMAC_AES256; + test_association->stmacf_len = 16; + + // Insert key into keyring of SA 9 + hex_conversion(buffer_rfc_key_h, (char**) &buffer_rfc_key_b, &buffer_rfc_key_len); + ekp = key_if->get_key(test_association->ekid); + memcpy(ekp->value, buffer_rfc_key_b, buffer_rfc_key_len); + + // Convert input plaintext + // TODO: Account for length of header and FECF (5+2) + hex_conversion(buffer_rfc_pt_h, (char**) &buffer_rfc_pt_b, &buffer_rfc_pt_len); + // Convert/Set input AAD + hex_conversion(buffer_rfc_aad_h, (char**) &buffer_rfc_aad_b, &buffer_rfc_aad_len); + memcpy(test_association->abm, buffer_rfc_aad_b + 5, buffer_rfc_aad_len); + hex_conversion(buffer_rfc_nonce_h, (char**) &buffer_rfc_nonce_b, &buffer_rfc_nonce_len); + memcpy(test_association->iv, buffer_rfc_nonce_b, buffer_rfc_nonce_len); + // Convert input ciphertext + hex_conversion(buffer_rfc_ct_h, (char**) &buffer_rfc_ct_b, &buffer_rfc_ct_len); + + Crypto_TC_ApplySecurity(buffer_rfc_pt_b, buffer_rfc_pt_len, &ptr_enc_frame, &enc_frame_len); + // Note: For comparison, interested in the TF payload (exclude headers and FECF if present) + // Calc payload index: total length - pt length + uint16_t enc_data_idx = enc_frame_len - buffer_rfc_ct_len; + Crypto_Shutdown(); + for (int i = 0; i < buffer_rfc_pt_len - 7; i++) + { + printf("[%d]: %02x -> %02x \n", i, *(ptr_enc_frame + enc_data_idx), buffer_rfc_ct_b[i]); + ASSERT_EQ(*(ptr_enc_frame + enc_data_idx), buffer_rfc_ct_b[i]); + enc_data_idx++; + } + free(ptr_enc_frame); + free(buffer_rfc_pt_b); + free(buffer_rfc_aad_b); + free(buffer_rfc_nonce_b); + free(buffer_rfc_ct_b); + free(buffer_rfc_key_b); +} + +/** + * @brief Validation Test: AEAD_AES_256_GCM_SIV Test Vectors + * Reference: + * https://datatracker.ietf.org/doc/rfc8452/?include_text=1 C.2. + * Recreated test vectors with https://github.com/line/aes-gcm-siv/tree/master, then input CryptoLib test vectors to generate truth data. + **/ +UTEST(AES_GCM_SIV, AES_GCM_SIV_256_KEY_32_PT_20_WITH_AAD_ENC_TEST_1) +{ + remove("sa_save_file.bin"); + uint8_t* ptr_enc_frame = NULL; + uint16_t enc_frame_len = 0; + // Setup & Initialize CryptoLib + // Crypto_Init_TC_Unit_Test(); + Crypto_Config_CryptoLib(KEY_TYPE_INTERNAL, MC_TYPE_INTERNAL, SA_TYPE_INMEMORY, CRYPTOGRAPHY_TYPE_LIBGCRYPT, + IV_INTERNAL, CRYPTO_TC_CREATE_FECF_FALSE, TC_PROCESS_SDLS_PDUS_TRUE, TC_HAS_PUS_HDR, + TC_IGNORE_SA_STATE_FALSE, TC_IGNORE_ANTI_REPLAY_FALSE, TC_UNIQUE_SA_PER_MAP_ID_FALSE, + TC_CHECK_FECF_FALSE, 0x3F, SA_INCREMENT_NONTRANSMITTED_IV_TRUE); + Crypto_Config_Add_Gvcid_Managed_Parameter(0, 0x0003, 0, TC_NO_FECF, TC_NO_SEGMENT_HDRS, TC_OCF_NA, 1024, AOS_FHEC_NA, AOS_IZ_NA, 0); + Crypto_Config_Add_Gvcid_Managed_Parameter(0, 0x0003, 1, TC_NO_FECF, TC_NO_SEGMENT_HDRS, TC_OCF_NA, 1024, AOS_FHEC_NA, AOS_IZ_NA, 0); + Crypto_Init(); + SaInterface sa_if = get_sa_interface_inmemory(); + crypto_key_t* ekp = NULL; + + // RFC8452 supplied vectors + // NOTE: Added Transfer Frame header to the plaintext + char* buffer_rfc_pt_h = "20030018000300000000000000000000000000000004000000"; + char* buffer_rfc_aad_h = "010000000000000000000000000000000200"; + char* buffer_rfc_key_h = "0100000000000000000000000000000000000000000000000000000000000000"; + char* buffer_rfc_nonce_h = "030000000000000000000000"; + char* buffer_rfc_ct_h = "e6e883db43a9ef98fa6271cb7d4834139acf479e3b910775e769286f3f59d2e588f69b06"; + uint8_t* buffer_rfc_pt_b, *buffer_rfc_aad_b, *buffer_rfc_key_b, *buffer_rfc_nonce_b, *buffer_rfc_ct_b = NULL; + int buffer_rfc_pt_len, buffer_rfc_aad_len, buffer_rfc_key_len, buffer_rfc_nonce_len, buffer_rfc_ct_len = 0; + + // Expose/setup SAs for testing + SecurityAssociation_t* test_association = NULL; + test_association = malloc(sizeof(SecurityAssociation_t) * sizeof(uint8_t)); + // Deactivate SA 1 + sa_if->sa_get_from_spi(1, &test_association); + test_association->sa_state = SA_NONE; + // Activate SA 9 + sa_if->sa_get_from_spi(9, &test_association); + test_association->arsn_len = 0; + test_association->sa_state = SA_OPERATIONAL; + test_association->ast = 1; + test_association->est = 1; + test_association->ecs_len = 1; + test_association->ecs = CRYPTO_CIPHER_AES256_GCM_SIV; + test_association->acs_len = 1; + test_association->acs = CRYPTO_MAC_CMAC_AES256; + test_association->stmacf_len = 16; + + // Insert key into keyring of SA 9 + hex_conversion(buffer_rfc_key_h, (char**) &buffer_rfc_key_b, &buffer_rfc_key_len); + ekp = key_if->get_key(test_association->ekid); + memcpy(ekp->value, buffer_rfc_key_b, buffer_rfc_key_len); + + // Convert input plaintext + // TODO: Account for length of header and FECF (5+2) + hex_conversion(buffer_rfc_pt_h, (char**) &buffer_rfc_pt_b, &buffer_rfc_pt_len); + // Convert/Set input AAD + hex_conversion(buffer_rfc_aad_h, (char**) &buffer_rfc_aad_b, &buffer_rfc_aad_len); + memcpy(test_association->abm, buffer_rfc_aad_b, buffer_rfc_aad_len); + hex_conversion(buffer_rfc_nonce_h, (char**) &buffer_rfc_nonce_b, &buffer_rfc_nonce_len); + memcpy(test_association->iv, buffer_rfc_nonce_b, buffer_rfc_nonce_len); + // Convert input ciphertext + hex_conversion(buffer_rfc_ct_h, (char**) &buffer_rfc_ct_b, &buffer_rfc_ct_len); + + Crypto_TC_ApplySecurity(buffer_rfc_pt_b, buffer_rfc_pt_len, &ptr_enc_frame, &enc_frame_len); + // Note: For comparison, interested in the TF payload (exclude headers and FECF if present) + // Calc payload index: total length - pt length + uint16_t enc_data_idx = enc_frame_len - buffer_rfc_ct_len; + Crypto_Shutdown(); + for (int i = 0; i < buffer_rfc_pt_len - 7; i++) + { + printf("[%d]: %02x -> %02x \n", i, *(ptr_enc_frame + enc_data_idx), buffer_rfc_ct_b[i]); + ASSERT_EQ(*(ptr_enc_frame + enc_data_idx), buffer_rfc_ct_b[i]); + enc_data_idx++; + } + free(ptr_enc_frame); + free(buffer_rfc_pt_b); + free(buffer_rfc_aad_b); + free(buffer_rfc_nonce_b); + free(buffer_rfc_ct_b); + free(buffer_rfc_key_b); +} + +/** + * @brief Validation Test: AEAD_AES_256_GCM_SIV Test Vectors + * Reference: + * https://datatracker.ietf.org/doc/rfc8452/?include_text=1 C.2. Second Example + * Recreated test vectors with https://github.com/line/aes-gcm-siv/tree/master, then input CryptoLib test vectors to generate truth data. + **/ +UTEST(AES_GCM_SIV, AES_GCM_SIV_256_KEY_32_PT_20_WITH_AAD_DEC_TEST_1) +{ + remove("sa_save_file.bin"); + uint8_t* ptr_enc_frame = NULL; + + // Setup & Initialize CryptoLib + Crypto_Config_CryptoLib(KEY_TYPE_INTERNAL, MC_TYPE_INTERNAL, SA_TYPE_INMEMORY, CRYPTOGRAPHY_TYPE_LIBGCRYPT, + IV_INTERNAL, CRYPTO_TC_CREATE_FECF_TRUE, TC_PROCESS_SDLS_PDUS_TRUE, TC_HAS_PUS_HDR, + TC_IGNORE_SA_STATE_FALSE, TC_IGNORE_ANTI_REPLAY_FALSE, TC_UNIQUE_SA_PER_MAP_ID_FALSE, + TC_CHECK_FECF_TRUE, 0x3F, SA_INCREMENT_NONTRANSMITTED_IV_FALSE); + Crypto_Config_Add_Gvcid_Managed_Parameter(0, 0x0003, 0, TC_NO_FECF, TC_NO_SEGMENT_HDRS, TC_OCF_NA, 1024, AOS_FHEC_NA, AOS_IZ_NA, 0); + Crypto_Config_Add_Gvcid_Managed_Parameter(0, 0x0003, 1, TC_NO_FECF, TC_NO_SEGMENT_HDRS, TC_OCF_NA, 1024, AOS_FHEC_NA, AOS_IZ_NA, 0); + Crypto_Init(); + SaInterface sa_if = get_sa_interface_inmemory(); + crypto_key_t* ekp = NULL; + + // rfc supplied vectors + // NOTE: Added Transfer Frame header to the plaintext + char* buffer_rfc_pt_h = "20030018000300000000000000000000000000000004000000"; + char* buffer_rfc_key_h = "0100000000000000000000000000000000000000000000000000000000000000"; + char* buffer_rfc_et_h = "20030036000009030000000000000000000000e6e883db43a9ef98fa6271cb7d4834139acf479e3b910775e769286f3f59d2e588f69b06"; + uint8_t* buffer_rfc_pt_b, *buffer_rfc_et_b, *buffer_rfc_key_b = NULL; + int buffer_rfc_pt_len, buffer_rfc_et_len, buffer_rfc_key_len = 0; + + // Setup Processed Frame For Decryption + TC_t* tc_rfc_processed_frame; + tc_rfc_processed_frame = malloc(sizeof(uint8_t) * TC_SIZE); + + // Expose/setup SAs for testing + SecurityAssociation_t* test_association = NULL; + test_association = malloc(sizeof(SecurityAssociation_t) * sizeof(uint8_t)); + // Deactivate SA 1 + sa_if->sa_get_from_spi(1, &test_association); + test_association->sa_state = SA_NONE; + // Activate SA 9 + sa_if->sa_get_from_spi(9, &test_association); + test_association->arsn_len = 0; + test_association->sa_state = SA_OPERATIONAL; + test_association->ast = 1; + test_association->est = 1; + test_association->ecs_len = 1; + test_association->ecs = CRYPTO_CIPHER_AES256_GCM_SIV; + test_association->stmacf_len = 16; + // Insert key into keyring of SA 9 + hex_conversion(buffer_rfc_key_h, (char**) &buffer_rfc_key_b, &buffer_rfc_key_len); + ekp = key_if->get_key(test_association->ekid); + memcpy(ekp->value, buffer_rfc_key_b, buffer_rfc_key_len); + + // Convert input plaintext + hex_conversion(buffer_rfc_pt_h, (char**) &buffer_rfc_pt_b, &buffer_rfc_pt_len); + // Convert input encryptedtext + hex_conversion(buffer_rfc_et_h, (char**) &buffer_rfc_et_b, &buffer_rfc_et_len); + + Crypto_TC_ProcessSecurity(buffer_rfc_et_b, &buffer_rfc_et_len, tc_rfc_processed_frame); + + for (int i = 0; i < tc_rfc_processed_frame->tc_pdu_len; i++) + { + if (buffer_rfc_pt_b[i + 5] != tc_rfc_processed_frame->tc_pdu[i]) + { + printf("[%d]: %02x -> %02x \n", i, buffer_rfc_pt_b[i + 5], tc_rfc_processed_frame->tc_pdu[i]); + } + ASSERT_EQ(buffer_rfc_pt_b[i + 5], tc_rfc_processed_frame->tc_pdu[i]); + } + + Crypto_Shutdown(); + free(ptr_enc_frame); + free(buffer_rfc_pt_b); + free(buffer_rfc_et_b); + free(buffer_rfc_key_b); +} + +UTEST_MAIN(); \ No newline at end of file diff --git a/test/unit/ut_crypto.c b/test/unit/ut_crypto.c index e4ab24f8..1f1dfe60 100644 --- a/test/unit/ut_crypto.c +++ b/test/unit/ut_crypto.c @@ -274,6 +274,7 @@ UTEST(CRYPTO_C, EXT_PROC_PDU) UTEST(CRYPTO_C, GET_ACS_ALGO) { remove("sa_save_file.bin"); + Crypto_Init_TC_Unit_Test(); int32_t libgcrypt_algo = -1; uint8_t crypto_algo = CRYPTO_MAC_CMAC_AES256; @@ -312,6 +313,7 @@ UTEST(CRYPTO_C, GET_ACS_ALGO_KEY_LEN) UTEST(CRYPTO_C, GET_ECS_ALGO) { remove("sa_save_file.bin"); + Crypto_Init_TC_Unit_Test(); int32_t libgcrypt_algo = -1; int8_t crypto_algo = CRYPTO_CIPHER_AES256_GCM;