Update QUIC/SM9/ZUC

This commit is contained in:
Zhi Guan
2026-06-24 18:21:27 +08:00
parent e5d318d1a7
commit 09c96fa2e0
21 changed files with 7702 additions and 45 deletions

View File

@@ -221,7 +221,7 @@ set(src
set(tools
tools/gmssl.c
tools/version.c
tools/sm4.c
# tools/sm4.c
tools/sm4_cbc.c
tools/sm4_ctr.c
tools/sm4_gcm.c
@@ -233,6 +233,7 @@ set(tools
tools/sm2verify.c
tools/sm2encrypt.c
tools/sm2decrypt.c
tools/sm2exch.c
tools/rand.c
tools/certgen.c
tools/certparse.c
@@ -507,7 +508,8 @@ if (ENABLE_SM9)
tools/sm9sign.c
tools/sm9verify.c
tools/sm9encrypt.c
tools/sm9decrypt.c)
tools/sm9decrypt.c
tools/sm9exch.c)
list(APPEND tests sm9)
endif()
@@ -657,7 +659,11 @@ if (ENABLE_ZUC)
message(STATUS "ENABLE_ZUC is ON")
add_definitions(-DENABLE_ZUC)
list(APPEND src src/zuc.c src/zuc_modes.c)
list(APPEND tools tools/zuc.c)
list(APPEND tools
tools/zuc.c
tools/zuc256.c
tools/zuc_128_eea3.c
tools/zuc_128_eia3.c)
list(APPEND tests zuc)
endif()
@@ -1010,7 +1016,7 @@ endif()
#
set(CPACK_PACKAGE_NAME "GmSSL")
set(CPACK_PACKAGE_VENDOR "GmSSL develop team")
set(CPACK_PACKAGE_VERSION "3.3.0-dev.1168")
set(CPACK_PACKAGE_VERSION "3.3.0-dev.1169")
set(CPACK_PACKAGE_DESCRIPTION_FILE ${PROJECT_SOURCE_DIR}/README.md)
set(CPACK_NSIS_MODIFY_PATH ON)
include(CPack)

View File

@@ -64,6 +64,216 @@ if(NOT "${TEST_STDOUT}" STREQUAL "${SECRET_MESSAGE}")
message(FATAL_ERROR "stdout: ${TEST_STDOUT}")
endif()
execute_process(
COMMAND bin/gmssl sm2keygen -pass P@ssw0rd -out sm2_peer.pem -pubout sm2_peer_pub.pem
RESULT_VARIABLE TEST_RESULT
ERROR_VARIABLE TEST_STDERR
)
if(NOT ${TEST_RESULT} EQUAL 0)
message(FATAL_ERROR "stderr: ${TEST_STDERR}")
endif()
execute_process(
COMMAND bin/gmssl sm2exch -stage init
-exch_keyout sm2exch_alice_ra.pem -exch_pass P@ssw0rd
-out sm2exch_ra.bin
RESULT_VARIABLE TEST_RESULT
ERROR_VARIABLE TEST_STDERR
)
if(NOT ${TEST_RESULT} EQUAL 0)
message(FATAL_ERROR "stderr: ${TEST_STDERR}")
endif()
execute_process(
COMMAND bin/gmssl sm2exch -stage respond
-key sm2_peer.pem -pass P@ssw0rd -id Bob
-peer_pubkey sm2pub.pem -peer_id Alice -in sm2exch_ra.bin
-exch_keyout sm2exch_bob_rb.pem -exch_pass P@ssw0rd
-secret_state_out sm2exch_bob_secret_state.bin
-out sm2exch_rb_sb.bin
RESULT_VARIABLE TEST_RESULT
ERROR_VARIABLE TEST_STDERR
)
if(NOT ${TEST_RESULT} EQUAL 0)
message(FATAL_ERROR "stderr: ${TEST_STDERR}")
endif()
execute_process(
COMMAND bin/gmssl sm2exch -stage confirm
-key sm2.pem -pass P@ssw0rd -id Alice
-peer_pubkey sm2_peer_pub.pem -peer_id Bob
-exch_key sm2exch_alice_ra.pem -exch_pass P@ssw0rd
-in sm2exch_rb_sb.bin
-keylen 48 -keyout sm2exch_alice_key.bin
-secret_state_out sm2exch_alice_secret_state.bin
-out sm2exch_sa.bin
RESULT_VARIABLE TEST_RESULT
ERROR_VARIABLE TEST_STDERR
)
if(NOT ${TEST_RESULT} EQUAL 0)
message(FATAL_ERROR "stderr: ${TEST_STDERR}")
endif()
execute_process(
COMMAND bin/gmssl sm2exch -stage finish
-key sm2_peer.pem -pass P@ssw0rd -id Bob
-peer_pubkey sm2pub.pem -peer_id Alice
-exch_key sm2exch_bob_rb.pem -exch_pass P@ssw0rd
-secret_state sm2exch_bob_secret_state.bin
-in sm2exch_sa.bin
-keylen 48 -keyout sm2exch_bob_key.bin
RESULT_VARIABLE TEST_RESULT
ERROR_VARIABLE TEST_STDERR
)
if(NOT ${TEST_RESULT} EQUAL 0)
message(FATAL_ERROR "stderr: ${TEST_STDERR}")
endif()
execute_process(
COMMAND ${CMAKE_COMMAND} -E compare_files sm2exch_alice_key.bin sm2exch_bob_key.bin
RESULT_VARIABLE TEST_RESULT
)
if(NOT ${TEST_RESULT} EQUAL 0)
message(FATAL_ERROR "SM2 key exchange output mismatch")
endif()
execute_process(
COMMAND ${CMAKE_COMMAND} -E compare_files sm2exch_alice_secret_state.bin sm2exch_bob_secret_state.bin
RESULT_VARIABLE TEST_RESULT
)
if(NOT ${TEST_RESULT} EQUAL 0)
message(FATAL_ERROR "SM2 key exchange secret_state mismatch")
endif()
execute_process(
COMMAND bin/gmssl sm2exch -stage init -bin
-exch_keyout sm2exch_bin_alice_ra.pem -exch_pass P@ssw0rd
-out sm2exch_bin_ra.bin
RESULT_VARIABLE TEST_RESULT
ERROR_VARIABLE TEST_STDERR
)
if(NOT ${TEST_RESULT} EQUAL 0)
message(FATAL_ERROR "stderr: ${TEST_STDERR}")
endif()
execute_process(
COMMAND bin/gmssl sm2exch -stage respond -bin
-key sm2_peer.pem -pass P@ssw0rd -id Bob
-peer_pubkey sm2pub.pem -peer_id Alice -in sm2exch_bin_ra.bin
-exch_keyout sm2exch_bin_bob_rb.pem -exch_pass P@ssw0rd
-secret_state_out sm2exch_bin_bob_secret_state.bin
-out sm2exch_bin_rb_sb.bin
RESULT_VARIABLE TEST_RESULT
ERROR_VARIABLE TEST_STDERR
)
if(NOT ${TEST_RESULT} EQUAL 0)
message(FATAL_ERROR "stderr: ${TEST_STDERR}")
endif()
execute_process(
COMMAND bin/gmssl sm2exch -stage confirm -bin
-key sm2.pem -pass P@ssw0rd -id Alice
-peer_pubkey sm2_peer_pub.pem -peer_id Bob
-exch_key sm2exch_bin_alice_ra.pem -exch_pass P@ssw0rd
-in sm2exch_bin_rb_sb.bin
-keylen 48 -keyout sm2exch_bin_alice_key.bin
-secret_state_out sm2exch_bin_alice_secret_state.bin
-out sm2exch_bin_sa.bin
RESULT_VARIABLE TEST_RESULT
ERROR_VARIABLE TEST_STDERR
)
if(NOT ${TEST_RESULT} EQUAL 0)
message(FATAL_ERROR "stderr: ${TEST_STDERR}")
endif()
execute_process(
COMMAND bin/gmssl sm2exch -stage finish -bin
-key sm2_peer.pem -pass P@ssw0rd -id Bob
-peer_pubkey sm2pub.pem -peer_id Alice
-exch_key sm2exch_bin_bob_rb.pem -exch_pass P@ssw0rd
-secret_state sm2exch_bin_bob_secret_state.bin
-in sm2exch_bin_sa.bin
-keylen 48 -keyout sm2exch_bin_bob_key.bin
RESULT_VARIABLE TEST_RESULT
ERROR_VARIABLE TEST_STDERR
)
if(NOT ${TEST_RESULT} EQUAL 0)
message(FATAL_ERROR "stderr: ${TEST_STDERR}")
endif()
execute_process(
COMMAND ${CMAKE_COMMAND} -E compare_files sm2exch_bin_alice_key.bin sm2exch_bin_bob_key.bin
RESULT_VARIABLE TEST_RESULT
)
if(NOT ${TEST_RESULT} EQUAL 0)
message(FATAL_ERROR "SM2 binary key exchange output mismatch")
endif()
execute_process(
COMMAND bin/gmssl sm2exch -stage init
-exch_keyout sm2exch_stdio_alice_ra.pem -exch_pass P@ssw0rd
OUTPUT_FILE sm2exch_stdio_ra.hex
RESULT_VARIABLE TEST_RESULT
ERROR_VARIABLE TEST_STDERR
)
if(NOT ${TEST_RESULT} EQUAL 0)
message(FATAL_ERROR "stderr: ${TEST_STDERR}")
endif()
execute_process(
COMMAND bin/gmssl sm2exch -stage respond
-key sm2_peer.pem -pass P@ssw0rd -id Bob
-peer_pubkey sm2pub.pem -peer_id Alice
-exch_keyout sm2exch_stdio_bob_rb.pem -exch_pass P@ssw0rd
-secret_state_out sm2exch_stdio_bob_secret_state.hex
INPUT_FILE sm2exch_stdio_ra.hex
OUTPUT_FILE sm2exch_stdio_rb_sb.hex
RESULT_VARIABLE TEST_RESULT
ERROR_VARIABLE TEST_STDERR
)
if(NOT ${TEST_RESULT} EQUAL 0)
message(FATAL_ERROR "stderr: ${TEST_STDERR}")
endif()
execute_process(
COMMAND bin/gmssl sm2exch -stage confirm
-key sm2.pem -pass P@ssw0rd -id Alice
-peer_pubkey sm2_peer_pub.pem -peer_id Bob
-exch_key sm2exch_stdio_alice_ra.pem -exch_pass P@ssw0rd
-keylen 48 -keyout sm2exch_stdio_alice_key.hex
-secret_state_out sm2exch_stdio_alice_secret_state.hex
INPUT_FILE sm2exch_stdio_rb_sb.hex
OUTPUT_FILE sm2exch_stdio_sa.hex
RESULT_VARIABLE TEST_RESULT
ERROR_VARIABLE TEST_STDERR
)
if(NOT ${TEST_RESULT} EQUAL 0)
message(FATAL_ERROR "stderr: ${TEST_STDERR}")
endif()
execute_process(
COMMAND bin/gmssl sm2exch -stage finish
-key sm2_peer.pem -pass P@ssw0rd -id Bob
-peer_pubkey sm2pub.pem -peer_id Alice
-exch_key sm2exch_stdio_bob_rb.pem -exch_pass P@ssw0rd
-secret_state sm2exch_stdio_bob_secret_state.hex
-keylen 48 -keyout sm2exch_stdio_bob_key.hex
INPUT_FILE sm2exch_stdio_sa.hex
RESULT_VARIABLE TEST_RESULT
ERROR_VARIABLE TEST_STDERR
)
if(NOT ${TEST_RESULT} EQUAL 0)
message(FATAL_ERROR "stderr: ${TEST_STDERR}")
endif()
execute_process(
COMMAND ${CMAKE_COMMAND} -E compare_files sm2exch_stdio_alice_key.hex sm2exch_stdio_bob_key.hex
RESULT_VARIABLE TEST_RESULT
)
if(NOT ${TEST_RESULT} EQUAL 0)
message(FATAL_ERROR "SM2 stdio key exchange output mismatch")
endif()
execute_process(
COMMAND bin/gmssl sm2sign -key sm2.pem -pass P@ssw0rd -id Alice -in message.txt -out sm2_id.sig
RESULT_VARIABLE TEST_RESULT

View File

@@ -2,7 +2,6 @@ include("${CMAKE_CURRENT_LIST_DIR}/tool_helpers.cmake")
set(SM4_KEY 0123456789abcdeffedcba9876543210)
set(SM4_IV 00000000000000000000000000000000)
set(SM4_HMAC_KEY 0123456789abcdeffedcba98765432100123456789abcdeffedcba98765432100123456789abcdeffedcba9876543210)
set(SM4_XTS_KEY 0123456789abcdeffedcba987654321000112233445566778899aabbccddeeff)
set(SM4_FF1_KEY 2b7e151628aed2a6abf7158809cf4f3c)
set(SM4_TEXT "0123456789abcdef0123456789abcdef")
@@ -23,23 +22,39 @@ gmssl_run(sm4_cbc -decrypt -key ${SM4_KEY} -iv ${SM4_IV}
-in tool_sm4_cbc_kat.cipher -out tool_sm4_cbc_kat.decrypt)
gmssl_files_equal(tool_sm4_cbc_kat.plain tool_sm4_cbc_kat.decrypt)
file(WRITE tool_sm4_unified_cbc_kat.plain "0123456789abcdef")
gmssl_run(sm4 -cbc -encrypt -key ${SM4_KEY} -iv ${SM4_IV}
-in tool_sm4_unified_cbc_kat.plain -out tool_sm4_unified_cbc_kat.cipher)
gmssl_expect_file_hex(tool_sm4_unified_cbc_kat.cipher
"e6887b77dbabb572ffa07fed7548b192ceaace11f2b90b94c2b7a4d9382e471e")
gmssl_run(sm4 -cbc -decrypt -key ${SM4_KEY} -iv ${SM4_IV}
-in tool_sm4_unified_cbc_kat.cipher -out tool_sm4_unified_cbc_kat.decrypt)
gmssl_files_equal(tool_sm4_unified_cbc_kat.plain tool_sm4_unified_cbc_kat.decrypt)
gmssl_symmetric_roundtrip(tool_sm4_cbc sm4_cbc -key ${SM4_KEY} -iv ${SM4_IV})
gmssl_symmetric_roundtrip(tool_sm4_ctr sm4_ctr -key ${SM4_KEY} -iv ${SM4_IV})
gmssl_symmetric_roundtrip(tool_sm4_gcm sm4_gcm -key ${SM4_KEY} -iv 000000000000000000000000 -aad_hex 001122 -taglen 16)
gmssl_symmetric_roundtrip(tool_sm4_cbc_sm3_hmac sm4_cbc_sm3_hmac -key ${SM4_HMAC_KEY} -iv ${SM4_IV} -aad_hex 001122)
gmssl_symmetric_roundtrip(tool_sm4_ctr_sm3_hmac sm4_ctr_sm3_hmac -key ${SM4_HMAC_KEY} -iv ${SM4_IV} -aad_hex 001122)
gmssl_symmetric_roundtrip(tool_sm4_unified_cbc sm4 -cbc -key ${SM4_KEY} -iv ${SM4_IV})
gmssl_symmetric_roundtrip(tool_sm4_unified_ctr sm4 -ctr -key ${SM4_KEY} -iv ${SM4_IV})
gmssl_symmetric_roundtrip(tool_sm4_unified_gcm sm4 -gcm -key ${SM4_KEY} -iv 000000000000000000000000 -aad_hex 001122 -taglen 16)
if(ENABLE_SM4_ECB)
gmssl_symmetric_roundtrip(tool_sm4_ecb sm4_ecb -key ${SM4_KEY})
gmssl_symmetric_roundtrip(tool_sm4_unified_ecb sm4 -ecb -key ${SM4_KEY})
endif()
if(ENABLE_SM4_CFB)
gmssl_symmetric_roundtrip(tool_sm4_cfb sm4_cfb -sbytes 16 -key ${SM4_KEY} -iv ${SM4_IV})
gmssl_symmetric_roundtrip(tool_sm4_unified_cfb sm4 -cfb -sbytes 16 -key ${SM4_KEY} -iv ${SM4_IV})
gmssl_symmetric_roundtrip(tool_sm4_unified_cfb8 sm4 -cfb -sbytes 1 -key ${SM4_KEY} -iv ${SM4_IV})
endif()
if(ENABLE_SM4_OFB)
gmssl_symmetric_roundtrip(tool_sm4_ofb sm4_ofb -key ${SM4_KEY} -iv ${SM4_IV})
gmssl_symmetric_roundtrip(tool_sm4_unified_ofb sm4 -ofb -key ${SM4_KEY} -iv ${SM4_IV})
endif()
if(ENABLE_SM4_CCM)
gmssl_symmetric_roundtrip(tool_sm4_ccm sm4_ccm -key ${SM4_KEY} -iv 000000000000000000000000 -aad_hex 001122 -taglen 16)
gmssl_symmetric_roundtrip(tool_sm4_unified_ccm sm4 -ccm -key ${SM4_KEY} -iv 000000000000000000000000 -aad_hex 001122 -taglen 16)
endif()
if(ENABLE_SM4_XTS)
file(WRITE tool_sm4_xts.plain "0123456789abcdef0123456789abcdef")
@@ -48,6 +63,12 @@ if(ENABLE_SM4_XTS)
gmssl_run(sm4_xts -decrypt -key ${SM4_XTS_KEY} -iv ${SM4_IV} -data_unit_size 32
-in tool_sm4_xts.cipher -out tool_sm4_xts.decrypt)
gmssl_files_equal(tool_sm4_xts.plain tool_sm4_xts.decrypt)
file(WRITE tool_sm4_unified_xts.plain "0123456789abcdef0123456789abcdef")
gmssl_run(sm4 -xts -encrypt -key ${SM4_XTS_KEY} -iv ${SM4_IV} -data_unit_size 32
-in tool_sm4_unified_xts.plain -out tool_sm4_unified_xts.cipher)
gmssl_run(sm4 -xts -decrypt -key ${SM4_XTS_KEY} -iv ${SM4_IV} -data_unit_size 32
-in tool_sm4_unified_xts.cipher -out tool_sm4_unified_xts.decrypt)
gmssl_files_equal(tool_sm4_unified_xts.plain tool_sm4_unified_xts.decrypt)
endif()
if(ENABLE_SM4_FF1)
gmssl_expect_stdout("2326982895499381\n"

View File

@@ -24,8 +24,119 @@ gmssl_run(sm9keygen -alg sm9encrypt
-in tool_sm9_enc_msk.pem -inpass ${SM9_PASS}
-id ${SM9_ID}
-out tool_sm9_enc_key.pem -outpass ${SM9_USER_PASS})
gmssl_run(sm9keygen -alg sm9keyagreement
-in tool_sm9_enc_msk.pem -inpass ${SM9_PASS}
-id Bob
-out tool_sm9_bob_exch_key.pem -outpass ${SM9_USER_PASS})
gmssl_run(sm9encrypt -pubmaster tool_sm9_enc_mpk.pem -id ${SM9_ID}
-in tool_sm9_message.txt -out tool_sm9_cipher.der)
gmssl_run(sm9decrypt -key tool_sm9_enc_key.pem -pass ${SM9_USER_PASS} -id ${SM9_ID}
-in tool_sm9_cipher.der -out tool_sm9_plain.txt)
gmssl_expect_file_text(tool_sm9_plain.txt "${SM9_TEXT}")
gmssl_run(sm9keygen -alg sm9keyagreement
-in tool_sm9_enc_msk.pem -inpass ${SM9_PASS}
-id ${SM9_ID}
-out tool_sm9_alice_exch_key.pem -outpass ${SM9_USER_PASS})
gmssl_run(sm9exch -stage init
-pubmaster tool_sm9_enc_mpk.pem -peer_id Bob
-exch_keyout tool_sm9_alice_ra.pem -out tool_sm9_ra.bin)
gmssl_run(sm9exch -stage respond
-pubmaster tool_sm9_enc_mpk.pem
-key tool_sm9_bob_exch_key.pem -pass ${SM9_USER_PASS} -id Bob
-peer_id ${SM9_ID} -in tool_sm9_ra.bin
-exch_keyout tool_sm9_bob_rb.pem -out tool_sm9_rb_sb.bin)
gmssl_run(sm9exch -stage confirm
-pubmaster tool_sm9_enc_mpk.pem
-key tool_sm9_alice_exch_key.pem -pass ${SM9_USER_PASS} -id ${SM9_ID}
-peer_id Bob -exch_key tool_sm9_alice_ra.pem
-in tool_sm9_rb_sb.bin
-keylen 48 -keyout tool_sm9_alice_shared_key.bin
-out tool_sm9_sa.bin)
gmssl_run(sm9exch -stage finish
-pubmaster tool_sm9_enc_mpk.pem
-key tool_sm9_bob_exch_key.pem -pass ${SM9_USER_PASS} -id Bob
-peer_id ${SM9_ID}
-exch_key tool_sm9_bob_rb.pem
-in tool_sm9_sa.bin
-keylen 48 -keyout tool_sm9_bob_shared_key.bin)
gmssl_files_equal(tool_sm9_alice_shared_key.bin tool_sm9_bob_shared_key.bin)
gmssl_run(sm9exch -stage init -bin
-pubmaster tool_sm9_enc_mpk.pem -peer_id Bob
-exch_keyout tool_sm9_bin_alice_ra.pem -out tool_sm9_bin_ra.bin)
gmssl_run(sm9exch -stage respond -bin
-pubmaster tool_sm9_enc_mpk.pem
-key tool_sm9_bob_exch_key.pem -pass ${SM9_USER_PASS} -id Bob
-peer_id ${SM9_ID} -in tool_sm9_bin_ra.bin
-exch_keyout tool_sm9_bin_bob_rb.pem -out tool_sm9_bin_rb_sb.bin)
gmssl_run(sm9exch -stage confirm -bin
-pubmaster tool_sm9_enc_mpk.pem
-key tool_sm9_alice_exch_key.pem -pass ${SM9_USER_PASS} -id ${SM9_ID}
-peer_id Bob -exch_key tool_sm9_bin_alice_ra.pem
-in tool_sm9_bin_rb_sb.bin
-keylen 48 -keyout tool_sm9_bin_alice_shared_key.bin
-out tool_sm9_bin_sa.bin)
gmssl_run(sm9exch -stage finish -bin
-pubmaster tool_sm9_enc_mpk.pem
-key tool_sm9_bob_exch_key.pem -pass ${SM9_USER_PASS} -id Bob
-peer_id ${SM9_ID}
-exch_key tool_sm9_bin_bob_rb.pem
-in tool_sm9_bin_sa.bin
-keylen 48 -keyout tool_sm9_bin_bob_shared_key.bin)
gmssl_files_equal(tool_sm9_bin_alice_shared_key.bin tool_sm9_bin_bob_shared_key.bin)
execute_process(
COMMAND ${GMSSL_BIN} sm9exch -stage init
-pubmaster tool_sm9_enc_mpk.pem -peer_id Bob
-exch_keyout tool_sm9_stdio_alice_ra.pem
OUTPUT_FILE tool_sm9_stdio_ra.hex
RESULT_VARIABLE TEST_RESULT
ERROR_VARIABLE TEST_STDERR
)
if(NOT TEST_RESULT EQUAL 0)
message(FATAL_ERROR "command failed: ${GMSSL_BIN} sm9exch -stage init\nstderr: ${TEST_STDERR}")
endif()
execute_process(
COMMAND ${GMSSL_BIN} sm9exch -stage respond
-pubmaster tool_sm9_enc_mpk.pem
-key tool_sm9_bob_exch_key.pem -pass ${SM9_USER_PASS} -id Bob
-peer_id ${SM9_ID}
-exch_keyout tool_sm9_stdio_bob_rb.pem
INPUT_FILE tool_sm9_stdio_ra.hex
OUTPUT_FILE tool_sm9_stdio_rb_sb.hex
RESULT_VARIABLE TEST_RESULT
ERROR_VARIABLE TEST_STDERR
)
if(NOT TEST_RESULT EQUAL 0)
message(FATAL_ERROR "command failed: ${GMSSL_BIN} sm9exch -stage respond\nstderr: ${TEST_STDERR}")
endif()
execute_process(
COMMAND ${GMSSL_BIN} sm9exch -stage confirm
-pubmaster tool_sm9_enc_mpk.pem
-key tool_sm9_alice_exch_key.pem -pass ${SM9_USER_PASS} -id ${SM9_ID}
-peer_id Bob -exch_key tool_sm9_stdio_alice_ra.pem
-keylen 48 -keyout tool_sm9_stdio_alice_shared_key.hex
INPUT_FILE tool_sm9_stdio_rb_sb.hex
OUTPUT_FILE tool_sm9_stdio_sa.hex
RESULT_VARIABLE TEST_RESULT
ERROR_VARIABLE TEST_STDERR
)
if(NOT TEST_RESULT EQUAL 0)
message(FATAL_ERROR "command failed: ${GMSSL_BIN} sm9exch -stage confirm\nstderr: ${TEST_STDERR}")
endif()
execute_process(
COMMAND ${GMSSL_BIN} sm9exch -stage finish
-pubmaster tool_sm9_enc_mpk.pem
-key tool_sm9_bob_exch_key.pem -pass ${SM9_USER_PASS} -id Bob
-peer_id ${SM9_ID}
-exch_key tool_sm9_stdio_bob_rb.pem
-keylen 48 -keyout tool_sm9_stdio_bob_shared_key.hex
INPUT_FILE tool_sm9_stdio_sa.hex
RESULT_VARIABLE TEST_RESULT
ERROR_VARIABLE TEST_STDERR
)
if(NOT TEST_RESULT EQUAL 0)
message(FATAL_ERROR "command failed: ${GMSSL_BIN} sm9exch -stage finish\nstderr: ${TEST_STDERR}")
endif()
gmssl_files_equal(tool_sm9_stdio_alice_shared_key.hex tool_sm9_stdio_bob_shared_key.hex)

View File

@@ -8,3 +8,25 @@ gmssl_run(zuc -key ${ZUC_KEY} -iv ${ZUC_IV} -in tool_zuc.plain -out tool_zuc.cip
gmssl_expect_file_hex(tool_zuc.cipher "178fec4735b5b4edbfed84d4fc7cda00")
gmssl_run(zuc -key ${ZUC_KEY} -iv ${ZUC_IV} -in tool_zuc.cipher -out tool_zuc.decrypt)
gmssl_files_equal(tool_zuc.plain tool_zuc.decrypt)
gmssl_run(zuc_128_eea3
-key 173d14ba5003731d7a60049470f00a29
-count 0x66035492 -bearer 15 -direction 0
-in_hex 6cf65340735552ab0c9752fa6f9025fe0bd675d9005875b2
-out tool_zuc_128_eea3.cipher)
gmssl_expect_file_hex(tool_zuc_128_eea3.cipher
"a6c85fc66afb8533aafc2518dfe784940ee1e4b030238cc8")
gmssl_expect_stdout("390a91b7\n" zuc_128_eia3
-key 00000000000000000000000000000000
-count 0 -bearer 0 -direction 0 -in_hex 00)
gmssl_run(zuc256
-key 0000000000000000000000000000000000000000000000000000000000000000
-iv 0000000000000000000000000000000000000000000000
-in tool_zuc.plain -out tool_zuc256.cipher)
gmssl_expect_file_hex(tool_zuc256.cipher "68e108e51a361ad5e2c509585ad9ae65")
gmssl_run(zuc256
-key 0000000000000000000000000000000000000000000000000000000000000000
-iv 0000000000000000000000000000000000000000000000
-in tool_zuc256.cipher -out tool_zuc256.decrypt)
gmssl_files_equal(tool_zuc.plain tool_zuc256.decrypt)

View File

@@ -13,6 +13,9 @@
#include <stdint.h>
#include <stdlib.h>
#include <stdio.h>
#include <gmssl/digest.h>
#include <gmssl/tls.h>
#ifdef __cplusplus
@@ -31,6 +34,40 @@ extern "C" {
#define QUIC_TRANSPORT_PARAM_MAX_SIZE 512
typedef enum {
QUIC_packet_initial = 0,
QUIC_packet_0_rtt = 1,
QUIC_packet_handshake = 2,
QUIC_packet_retry = 3,
} QUIC_PACKET_TYPE;
typedef enum {
QUIC_frame_padding = 0x00,
QUIC_frame_ping = 0x01,
QUIC_frame_ack = 0x02,
QUIC_frame_ack_ecn = 0x03,
QUIC_frame_reset_stream = 0x04,
QUIC_frame_stop_sending = 0x05,
QUIC_frame_crypto = 0x06,
QUIC_frame_new_token = 0x07,
QUIC_frame_stream_base = 0x08,
QUIC_frame_max_data = 0x10,
QUIC_frame_max_stream_data = 0x11,
QUIC_frame_max_streams_bidi = 0x12,
QUIC_frame_max_streams_uni = 0x13,
QUIC_frame_data_blocked = 0x14,
QUIC_frame_stream_data_blocked = 0x15,
QUIC_frame_streams_blocked_bidi = 0x16,
QUIC_frame_streams_blocked_uni = 0x17,
QUIC_frame_new_connection_id = 0x18,
QUIC_frame_retire_connection_id = 0x19,
QUIC_frame_path_challenge = 0x1a,
QUIC_frame_path_response = 0x1b,
QUIC_frame_connection_close = 0x1c,
QUIC_frame_connection_close_app = 0x1d,
QUIC_frame_handshake_done = 0x1e,
} QUIC_FRAME_TYPE;
typedef enum {
QUIC_transport_param_original_destination_connection_id = 0x00,
QUIC_transport_param_max_idle_timeout = 0x01,
@@ -70,6 +107,25 @@ typedef struct {
uint8_t hp[QUIC_INITIAL_HP_KEY_SIZE]; // hp = header protection key
} QUIC_INITIAL_KEYS;
typedef struct {
int cipher_suite;
uint8_t key[QUIC_INITIAL_KEY_SIZE];
uint8_t iv[QUIC_INITIAL_IV_SIZE];
uint8_t hp[QUIC_INITIAL_HP_KEY_SIZE]; /* hp is Header Protection. QUIC protects packet number bytes and selected header bits separately from payload AEAD. */
} QUIC_PACKET_KEYS;
typedef struct {
int type;
uint64_t packet_number;
size_t packet_len;
uint8_t dcid[20];
size_t dcid_len;
uint8_t scid[20];
size_t scid_len;
uint8_t plaintext[4096];
size_t plaintext_len;
} QUIC_DECRYPTED_PACKET;
typedef struct {
uint64_t id;
uint8_t data[QUIC_TRANSPORT_PARAM_MAX_SIZE];
@@ -104,6 +160,30 @@ int quic_derive_initial_secrets(const uint8_t *dcid, size_t dcid_len, QUIC_INITI
int quic_derive_initial_client_keys(const QUIC_INITIAL_SECRETS *secrets, QUIC_INITIAL_KEYS *keys);
int quic_derive_initial_server_keys(const QUIC_INITIAL_SECRETS *secrets, QUIC_INITIAL_KEYS *keys);
int quic_derive_initial_keys(const uint8_t secret[QUIC_INITIAL_SECRET_SIZE], QUIC_INITIAL_KEYS *keys);
int quic_packet_keys_derive(const DIGEST *digest, const uint8_t secret[32], int cipher_suite, QUIC_PACKET_KEYS *keys);
int quic_packet_keys_from_initial(const QUIC_INITIAL_KEYS *initial_keys, QUIC_PACKET_KEYS *keys);
int quic_packet_total_length(const uint8_t *packet, size_t packet_len, size_t *total_len);
int quic_long_packet_decrypt(const QUIC_PACKET_KEYS *keys, const uint8_t *packet, size_t packet_len, int expected_type, QUIC_DECRYPTED_PACKET *out);
int quic_long_packet_encrypt(const QUIC_PACKET_KEYS *keys, int type, const uint8_t *dcid, size_t dcid_len,
const uint8_t *scid, size_t scid_len, uint64_t packet_number, const uint8_t *frames, size_t frames_len,
uint8_t *packet, size_t *packet_len);
int quic_short_packet_decrypt(const QUIC_PACKET_KEYS *keys, const uint8_t *packet, size_t packet_len,
const uint8_t *dcid, size_t dcid_len, QUIC_DECRYPTED_PACKET *out);
int quic_short_packet_encrypt(const QUIC_PACKET_KEYS *keys, const uint8_t *dcid, size_t dcid_len,
uint64_t packet_number, const uint8_t *frames, size_t frames_len, uint8_t *packet, size_t *packet_len);
int quic_client_hello_to_bytes_ex(TLS_CONNECT *conn, const QUIC_TRANSPORT_PARAMS *params, uint8_t **out, size_t *outlen);
int quic_client_hello_to_bytes(TLS_CONNECT *conn, uint8_t **out, size_t *outlen);
int quic_server_hello_to_bytes(TLS_CONNECT *conn, uint8_t **out, size_t *outlen);
const char *quic_packet_type_name(int type);
const char *quic_frame_type_name(uint64_t type);
const char *quic_encryption_level_name(int level);
int quic_packet_print(FILE *fp, int fmt, int ind, const uint8_t *packet, size_t packetlen);
int quic_frames_print(FILE *fp, int fmt, int ind, int level, const uint8_t *frames, size_t frameslen);
int quic_frame_print(FILE *fp, int fmt, int ind, int level, const uint8_t **in, size_t *inlen);
int quic_crypto_data_print(FILE *fp, int fmt, int ind, int level, const uint8_t *data, size_t datalen);
#ifdef __cplusplus

View File

@@ -18,7 +18,7 @@ extern "C" {
#define GMSSL_VERSION_NUM 30300
#define GMSSL_VERSION_STR "GmSSL 3.3.0-dev.1168"
#define GMSSL_VERSION_STR "GmSSL 3.3.0-dev.1169"
int gmssl_version_num(void);
const char *gmssl_version_str(void);

1222
src/quic.c

File diff suppressed because it is too large Load Diff

897
src/sm9_cms.c Normal file
View File

@@ -0,0 +1,897 @@
/*
GM/T 0081-2020 ASN.1 definitions
IdentifierRevocationLists ::= SET OF IdentifierRevocationList
ContentEncryptionAlgorithmIdentifier ::= AlgorithmIdentifier
DigestAlgorithmIdentifier ::= AlgorithmIdentifier
DigestEncryptionAlgorithmIdentifier ::= AlgorithmIdentifier
KeyEncryptionAlgorithmIdentifier ::= AlgorithmIdentifier
Version ::= INTEGER(1)
ContentInfo ::= SEQUENCE {
contentType ContentType,
content [0] EXPLICIT contentType OPTIONAL
}
ContentType ::= OBJECT IDENTIFIER
Identifier ::= SEQUENCE {
version EXPLICIT VERSION DEFAULT v1,
ibcType OBJECT IDENTIFIER,
ibcTypeAlias [0] OCTET STRING OPTIONAL,
identityData OCTET STRING,
validStart UTCTIME,
validEnd [1] UTCTIME OPTIONAL,
extensions [2] Extensions OPTIONAL
}
Extensions ::= SEQUENCE SIZE (1..MAX) OF Extension
Extension ::= SEQUENCE {
extnID OBJECT IDENTIFIER,
critical BOOLEAN DEFAULT FALSE,
extnValue OCTET STRING
}
DistricInfo ::= SEQUENCE {
district IA5String,
districtNo INTEGER,
}
Validity ::= SEQUENCE {
notBefore Time,
notAfter Time,
Time ::= CHOICE {
utcTime UTCTime,
generalTime GeneralizedTime
}
}
IBCSysParamsPublishInfo ::= SEQUENCE {
ibcSysParams IBCSysParams,
signatureAlgorithm OBJECT IDENTIFIER,
signatureValue BIT STRING
}
AlgorithmIdentifier ::= SEQUENCE {
Algorithm OBJECT IDENTIFIER,
Parameters ANY DEFINED BY algorithm OPTIONAL
}
BeSignParamsPubInfo ::= SEQUENCE {
ibcSysParams IBCSysParams,
signatureAlgorithm OBJECT IDENTIFIER
}
IDAppAttr ::= SEQUENCE {
versoin Version DEFAULT v1,
serialNumber IdentifierSerialNumber,
subjectId Identifier,
sysParamsPublishInfo IBCSysParamsPublishInfo,
extensions [0] EXPLICIT Externsions OPTIONAL
}
version ::= INTEGER { v1(0) }
IdentifierSerialNumber ::= INTEGER
Externsions ::= SEQUENCE SIZE (1..MAX) OF Extension
Data ::= OCTET STRING
SignedData ::= SEQUENCE {
version Version,
digestAlgorithms DigestAlgorithmIdentifiers,
contentInfo ContentInfo,
ibcSysParamsPublishInfos [0] IMPLICIT IBCSysParamsPublishInfos OPTIONAL,
irls [1] IMPLICIT IdentifierRevocationLists OPTIONAL,
signerInfos SignerInfos
}
IBCSysParamsPublishInfos ::= SET OF IBCSysParamsPublishInfo
DigestAlgorithmIdentifiers ::= SET OF DigestAlgorithmIdentifier
SignerInfos ::= SET OF SignerInfo
SignerInfo ::= SEQUENCE {
version Version,
issuerIdentifier Identifier,
digestAlgorithm DigestAlgorithmIdentifier,
authenticatedAttributes [0] IMPLICIT Attributes OPTIONAL,
digestEncryptionAlgorithm DigestEncryptionAlgorithmIdentifier,
encryptedDigest SM9Signature,
unauthenticatedAttributes [1] IMPLICIT Attributes OPTIONAL
}
EnvelopedData ::= SEQUENCE {
version Version,
recipientInfos RecipientInfos,
encryptedContentInfo EncryptedContentInfo
}
RecipientInfos ::= SET OF RecipientInfo
EncryptedContentInfo ::= SEQUENCE {
contentType ContentType,
contentEncryptionAlgorithm ContentEncryptionAlgorithmIdentifier,
sharedInfo [0] OCTET STRING OPTIONAL,
sharedInfo2 [1] OCTET STRING OPTIONAL,
encryptedContent [2] IMPLICIT EncryptedContent OPTIONAL
}
EncryptedContent ::= OCTET STRING
RecipientInfo ::= SEQUENCE {
Version Version,
issuerIdentifier Identifier,
keyEncryptionAlgorithm KeyEncryptionAlgorithmIdentifier,
encryptedKey SM9cipher
}
SignedAndEnvelopedData ::= SEQUENCE {
version Version,
recipientInfos RecipientInfos,
digestAlgorithms DigestAlgorithmIdentifiers,
encryptedContentInfo EncryptedContentInfo,
idAppAttrInfos [0] IMPLICIT IDAppAttrInfos OPTIONAL,
irls [1] IMPLICIT IdentifierRevocationLists OPTIONAL,
signerInfos SignerInfos
}
EncryptedData ::= SEQUENCE {
Version Version,
encryptedContentInfo EncryptedContentInfo
}
//-- 这之后的类型都需要实现
KeyAgreementInfo ::= SEQUENCE {
version Version(1),
tempKey SM9MastEncryptPublicKey,
userIDA OCTET STRING
userIDB OCTET STRING
hid OCTET STRING
}
IdentifierRevocationList ::= SEQUENCE {
tbsIdList TBSIdList,
signInfos SignerInfos
}
TBSIdList ::= SEQUENCE {
Version(1) Version,
signatureOID AlgorithmIdentifier,
issuerIdentifier Identifier,
thisUpdate GeneralizedTime,
nextUpdate [0] GeneralizedTime OPTIONAL,
revokedIds RevokedIds,
irlExtensions [1] EXPLICIT Extensions OPTIONAL
}
Version ::= INTEGER(1)
RevokedIds ::= SEQUENCE OF RevokedId
RevokedId ::= SEQUENCE {
id OCTET STRING,
revocationDate GeneralizedTime,
IrlEntryExtensions [0] Extensions OPTIONAL
}
IBCSysParams ::= SEQUENCE {
version INTEGER { v2(2) },
districtName IA5String,
districtSerial INTEGER,
validity ValidityPeriod,
ibcPublicParameters IBCPublicParameters,
ibcIdentityType OBJECT IDENTIFIER,
issuerID Identifier,
ibcParamExtensions IBCParamExtensions OPTIONAL
}
IBCPublicParameters ::= SEQUENCE (1..MAX) OF IBCPublicParameter
IBCPublicParameter ::= SEQUENCE {
ibcAlgorithm OBJECT IDENTIFIER,
publicParameterData OCTET STRING
}
SM9PublicParameterData ::= SEQUENCE {
pkgID OCTET STRING,
encMastPublicKey SM9EncryptMasterPublicKey,
signMastPublicKey SM9SignMasterPublicKey
}
IBCParamExtensions ::= SEQUENCE OF IBCParamExtension
IBCParamExtension ::= SEQUENCE {
ibcParamExtensionOID OBJECT IDENTIFIER,
ibcParamExtensionValue OCTET STRING
}
IbcParamExt OBJECT IDENTIFIER ::= {
ibcs ibcs3(3) parameter-extensions(2)
}
*/
#include <time.h>
#include <stdint.h>
#include <stdio.h>
#include <gmssl/asn1.h>
#include <gmssl/sm9.h>
#include <gmssl/x509.h>
#include <gmssl/error.h>
int sm9_cms_algorithm_identifier_to_der(
const uint32_t *algorithm, size_t algorithm_cnt,
const uint8_t *parameters, size_t parameters_len,
uint8_t **out, size_t *outlen)
{
size_t len = 0;
if (asn1_object_identifier_to_der(algorithm, algorithm_cnt, NULL, &len) != 1
|| asn1_any_to_der(parameters, parameters_len, NULL, &len) < 0
|| asn1_sequence_header_to_der(len, out, outlen) != 1
|| asn1_object_identifier_to_der(algorithm, algorithm_cnt, out, outlen) != 1
|| asn1_any_to_der(parameters, parameters_len, out, outlen) < 0) {
error_print();
return -1;
}
return 1;
}
int sm9_cms_algorithm_identifier_from_der(
uint32_t *algorithm, size_t *algorithm_cnt,
const uint8_t **parameters, size_t *parameters_len,
const uint8_t **in, size_t *inlen)
{
int ret;
const uint8_t *d;
size_t dlen;
*parameters = NULL;
*parameters_len = 0;
if ((ret = asn1_sequence_from_der(&d, &dlen, in, inlen)) != 1) {
if (ret < 0) error_print();
return ret;
}
if (asn1_object_identifier_from_der(algorithm, algorithm_cnt, &d, &dlen) != 1
|| asn1_any_from_der(parameters, parameters_len, &d, &dlen) < 0
|| asn1_length_is_zero(dlen) != 1) {
error_print();
return -1;
}
return 1;
}
int sm9_cms_extensions_to_der(const uint8_t *extensions, size_t extensions_len,
uint8_t **out, size_t *outlen)
{
if (asn1_sequence_of_to_der(extensions, extensions_len, out, outlen) != 1) {
error_print();
return -1;
}
return 1;
}
int sm9_cms_extensions_from_der(const uint8_t **extensions, size_t *extensions_len,
const uint8_t **in, size_t *inlen)
{
int ret;
if ((ret = asn1_sequence_of_from_der(extensions, extensions_len, in, inlen)) != 1) {
if (ret < 0) error_print();
return ret;
}
return 1;
}
int sm9_cms_explicit_extensions_to_der(int index,
const uint8_t *extensions, size_t extensions_len,
uint8_t **out, size_t *outlen)
{
size_t len = 0;
if (!extensions) {
return 0;
}
if (sm9_cms_extensions_to_der(extensions, extensions_len, NULL, &len) != 1
|| asn1_explicit_header_to_der(index, len, out, outlen) != 1
|| sm9_cms_extensions_to_der(extensions, extensions_len, out, outlen) != 1) {
error_print();
return -1;
}
return 1;
}
int sm9_cms_explicit_extensions_from_der(int index,
const uint8_t **extensions, size_t *extensions_len,
const uint8_t **in, size_t *inlen)
{
int ret;
const uint8_t *d;
size_t dlen;
if ((ret = asn1_explicit_from_der(index, &d, &dlen, in, inlen)) != 1) {
if (ret < 0) error_print();
else {
*extensions = NULL;
*extensions_len = 0;
}
return ret;
}
if (sm9_cms_extensions_from_der(extensions, extensions_len, &d, &dlen) != 1
|| asn1_length_is_zero(dlen) != 1) {
error_print();
return -1;
}
return 1;
}
int sm9_cms_implicit_extensions_to_der(int index,
const uint8_t *extensions, size_t extensions_len,
uint8_t **out, size_t *outlen)
{
if (!extensions) {
return 0;
}
if (asn1_implicit_sequence_to_der(index, extensions, extensions_len, out, outlen) != 1) {
error_print();
return -1;
}
return 1;
}
int sm9_cms_implicit_extensions_from_der(int index,
const uint8_t **extensions, size_t *extensions_len,
const uint8_t **in, size_t *inlen)
{
int ret;
if ((ret = asn1_implicit_sequence_from_der(index, extensions, extensions_len, in, inlen)) < 0) {
error_print();
return -1;
}
return ret;
}
int sm9_cms_key_agreement_info_to_der(
int version,
const SM9_ENC_MASTER_KEY *temp_key,
const uint8_t *user_id_a, size_t user_id_a_len,
const uint8_t *user_id_b, size_t user_id_b_len,
const uint8_t *hid, size_t hid_len,
uint8_t **out, size_t *outlen)
{
size_t len = 0;
if (version != 1) {
error_print();
return -1;
}
if (asn1_int_to_der(version, NULL, &len) != 1
|| sm9_enc_master_public_key_to_der(temp_key, NULL, &len) != 1
|| asn1_octet_string_to_der(user_id_a, user_id_a_len, NULL, &len) != 1
|| asn1_octet_string_to_der(user_id_b, user_id_b_len, NULL, &len) != 1
|| asn1_octet_string_to_der(hid, hid_len, NULL, &len) != 1
|| asn1_sequence_header_to_der(len, out, outlen) != 1
|| asn1_int_to_der(version, out, outlen) != 1
|| sm9_enc_master_public_key_to_der(temp_key, out, outlen) != 1
|| asn1_octet_string_to_der(user_id_a, user_id_a_len, out, outlen) != 1
|| asn1_octet_string_to_der(user_id_b, user_id_b_len, out, outlen) != 1
|| asn1_octet_string_to_der(hid, hid_len, out, outlen) != 1) {
error_print();
return -1;
}
return 1;
}
int sm9_cms_key_agreement_info_from_der(
int *version,
SM9_ENC_MASTER_KEY *temp_key,
const uint8_t **user_id_a, size_t *user_id_a_len,
const uint8_t **user_id_b, size_t *user_id_b_len,
const uint8_t **hid, size_t *hid_len,
const uint8_t **in, size_t *inlen)
{
int ret;
const uint8_t *d;
size_t dlen;
if ((ret = asn1_sequence_from_der(&d, &dlen, in, inlen)) != 1) {
if (ret < 0) error_print();
return ret;
}
if (asn1_int_from_der(version, &d, &dlen) != 1
|| sm9_enc_master_public_key_from_der(temp_key, &d, &dlen) != 1
|| asn1_octet_string_from_der(user_id_a, user_id_a_len, &d, &dlen) != 1
|| asn1_octet_string_from_der(user_id_b, user_id_b_len, &d, &dlen) != 1
|| asn1_octet_string_from_der(hid, hid_len, &d, &dlen) != 1
|| asn1_length_is_zero(dlen) != 1) {
error_print();
return -1;
}
if (*version != 1) {
error_print();
return -1;
}
return 1;
}
int sm9_cms_revoked_id_to_der(
const uint8_t *id, size_t id_len,
time_t revocation_date,
const uint8_t *irl_entry_extensions, size_t irl_entry_extensions_len,
uint8_t **out, size_t *outlen)
{
size_t len = 0;
if (asn1_octet_string_to_der(id, id_len, NULL, &len) != 1
|| asn1_generalized_time_to_der(revocation_date, NULL, &len) != 1
|| sm9_cms_implicit_extensions_to_der(0, irl_entry_extensions, irl_entry_extensions_len, NULL, &len) < 0
|| asn1_sequence_header_to_der(len, out, outlen) != 1
|| asn1_octet_string_to_der(id, id_len, out, outlen) != 1
|| asn1_generalized_time_to_der(revocation_date, out, outlen) != 1
|| sm9_cms_implicit_extensions_to_der(0, irl_entry_extensions, irl_entry_extensions_len, out, outlen) < 0) {
error_print();
return -1;
}
return 1;
}
int sm9_cms_revoked_id_from_der(
const uint8_t **id, size_t *id_len,
time_t *revocation_date,
const uint8_t **irl_entry_extensions, size_t *irl_entry_extensions_len,
const uint8_t **in, size_t *inlen)
{
int ret;
const uint8_t *d;
size_t dlen;
if ((ret = asn1_sequence_from_der(&d, &dlen, in, inlen)) != 1) {
if (ret < 0) error_print();
return ret;
}
if (asn1_octet_string_from_der(id, id_len, &d, &dlen) != 1
|| asn1_generalized_time_from_der(revocation_date, &d, &dlen) != 1
|| sm9_cms_implicit_extensions_from_der(0, irl_entry_extensions, irl_entry_extensions_len, &d, &dlen) < 0
|| asn1_length_is_zero(dlen) != 1) {
error_print();
return -1;
}
return 1;
}
int sm9_cms_revoked_ids_to_der(const uint8_t *revoked_ids, size_t revoked_ids_len,
uint8_t **out, size_t *outlen)
{
if (asn1_sequence_of_to_der(revoked_ids, revoked_ids_len, out, outlen) != 1) {
error_print();
return -1;
}
return 1;
}
int sm9_cms_revoked_ids_from_der(const uint8_t **revoked_ids, size_t *revoked_ids_len,
const uint8_t **in, size_t *inlen)
{
int ret;
if ((ret = asn1_sequence_of_from_der(revoked_ids, revoked_ids_len, in, inlen)) != 1) {
if (ret < 0) error_print();
return ret;
}
return 1;
}
int sm9_cms_tbs_id_list_to_der(
int version,
const uint32_t *signature_oid, size_t signature_oid_cnt,
const uint8_t *signature_params, size_t signature_params_len,
const uint8_t *issuer_identifier, size_t issuer_identifier_len,
time_t this_update, time_t next_update,
const uint8_t *revoked_ids, size_t revoked_ids_len,
const uint8_t *irl_extensions, size_t irl_extensions_len,
uint8_t **out, size_t *outlen)
{
size_t len = 0;
if (version != 1) {
error_print();
return -1;
}
if (asn1_int_to_der(version, NULL, &len) != 1
|| sm9_cms_algorithm_identifier_to_der(signature_oid, signature_oid_cnt,
signature_params, signature_params_len, NULL, &len) != 1
|| asn1_any_to_der(issuer_identifier, issuer_identifier_len, NULL, &len) != 1
|| asn1_generalized_time_to_der(this_update, NULL, &len) != 1
|| asn1_implicit_generalized_time_to_der(0, next_update, NULL, &len) < 0
|| sm9_cms_revoked_ids_to_der(revoked_ids, revoked_ids_len, NULL, &len) != 1
|| sm9_cms_explicit_extensions_to_der(1, irl_extensions, irl_extensions_len, NULL, &len) < 0
|| asn1_sequence_header_to_der(len, out, outlen) != 1
|| asn1_int_to_der(version, out, outlen) != 1
|| sm9_cms_algorithm_identifier_to_der(signature_oid, signature_oid_cnt,
signature_params, signature_params_len, out, outlen) != 1
|| asn1_any_to_der(issuer_identifier, issuer_identifier_len, out, outlen) != 1
|| asn1_generalized_time_to_der(this_update, out, outlen) != 1
|| asn1_implicit_generalized_time_to_der(0, next_update, out, outlen) < 0
|| sm9_cms_revoked_ids_to_der(revoked_ids, revoked_ids_len, out, outlen) != 1
|| sm9_cms_explicit_extensions_to_der(1, irl_extensions, irl_extensions_len, out, outlen) < 0) {
error_print();
return -1;
}
return 1;
}
int sm9_cms_tbs_id_list_from_der(
int *version,
uint32_t *signature_oid, size_t *signature_oid_cnt,
const uint8_t **signature_params, size_t *signature_params_len,
const uint8_t **issuer_identifier, size_t *issuer_identifier_len,
time_t *this_update, time_t *next_update,
const uint8_t **revoked_ids, size_t *revoked_ids_len,
const uint8_t **irl_extensions, size_t *irl_extensions_len,
const uint8_t **in, size_t *inlen)
{
int ret;
const uint8_t *d;
size_t dlen;
if ((ret = asn1_sequence_from_der(&d, &dlen, in, inlen)) != 1) {
if (ret < 0) error_print();
return ret;
}
if (asn1_int_from_der(version, &d, &dlen) != 1
|| sm9_cms_algorithm_identifier_from_der(signature_oid, signature_oid_cnt,
signature_params, signature_params_len, &d, &dlen) != 1
|| asn1_any_from_der(issuer_identifier, issuer_identifier_len, &d, &dlen) != 1
|| asn1_generalized_time_from_der(this_update, &d, &dlen) != 1
|| asn1_implicit_generalized_time_from_der(0, next_update, &d, &dlen) < 0
|| sm9_cms_revoked_ids_from_der(revoked_ids, revoked_ids_len, &d, &dlen) != 1
|| sm9_cms_explicit_extensions_from_der(1, irl_extensions, irl_extensions_len, &d, &dlen) < 0
|| asn1_length_is_zero(dlen) != 1) {
error_print();
return -1;
}
if (*version != 1) {
error_print();
return -1;
}
return 1;
}
int sm9_cms_signer_infos_to_der(const uint8_t *signer_infos, size_t signer_infos_len,
uint8_t **out, size_t *outlen)
{
if (asn1_set_of_to_der(signer_infos, signer_infos_len, out, outlen) != 1) {
error_print();
return -1;
}
return 1;
}
int sm9_cms_signer_infos_from_der(const uint8_t **signer_infos, size_t *signer_infos_len,
const uint8_t **in, size_t *inlen)
{
int ret;
if ((ret = asn1_set_of_from_der(signer_infos, signer_infos_len, in, inlen)) != 1) {
if (ret < 0) error_print();
return ret;
}
return 1;
}
int sm9_cms_identifier_revocation_list_to_der(
const uint8_t *tbs_id_list, size_t tbs_id_list_len,
const uint8_t *signer_infos, size_t signer_infos_len,
uint8_t **out, size_t *outlen)
{
size_t len = 0;
if (asn1_any_to_der(tbs_id_list, tbs_id_list_len, NULL, &len) != 1
|| sm9_cms_signer_infos_to_der(signer_infos, signer_infos_len, NULL, &len) != 1
|| asn1_sequence_header_to_der(len, out, outlen) != 1
|| asn1_any_to_der(tbs_id_list, tbs_id_list_len, out, outlen) != 1
|| sm9_cms_signer_infos_to_der(signer_infos, signer_infos_len, out, outlen) != 1) {
error_print();
return -1;
}
return 1;
}
int sm9_cms_identifier_revocation_list_from_der(
const uint8_t **tbs_id_list, size_t *tbs_id_list_len,
const uint8_t **signer_infos, size_t *signer_infos_len,
const uint8_t **in, size_t *inlen)
{
int ret;
const uint8_t *d;
size_t dlen;
if ((ret = asn1_sequence_from_der(&d, &dlen, in, inlen)) != 1) {
if (ret < 0) error_print();
return ret;
}
if (asn1_any_from_der(tbs_id_list, tbs_id_list_len, &d, &dlen) != 1
|| sm9_cms_signer_infos_from_der(signer_infos, signer_infos_len, &d, &dlen) != 1
|| asn1_length_is_zero(dlen) != 1) {
error_print();
return -1;
}
return 1;
}
int sm9_cms_validity_period_to_der(time_t not_before, time_t not_after,
uint8_t **out, size_t *outlen)
{
return x509_validity_to_der(not_before, not_after, out, outlen);
}
int sm9_cms_validity_period_from_der(time_t *not_before, time_t *not_after,
const uint8_t **in, size_t *inlen)
{
return x509_validity_from_der(not_before, not_after, in, inlen);
}
int sm9_cms_ibc_public_parameter_to_der(
const uint32_t *ibc_algorithm, size_t ibc_algorithm_cnt,
const uint8_t *public_parameter_data, size_t public_parameter_data_len,
uint8_t **out, size_t *outlen)
{
size_t len = 0;
if (asn1_object_identifier_to_der(ibc_algorithm, ibc_algorithm_cnt, NULL, &len) != 1
|| asn1_octet_string_to_der(public_parameter_data, public_parameter_data_len, NULL, &len) != 1
|| asn1_sequence_header_to_der(len, out, outlen) != 1
|| asn1_object_identifier_to_der(ibc_algorithm, ibc_algorithm_cnt, out, outlen) != 1
|| asn1_octet_string_to_der(public_parameter_data, public_parameter_data_len, out, outlen) != 1) {
error_print();
return -1;
}
return 1;
}
int sm9_cms_ibc_public_parameter_from_der(
uint32_t *ibc_algorithm, size_t *ibc_algorithm_cnt,
const uint8_t **public_parameter_data, size_t *public_parameter_data_len,
const uint8_t **in, size_t *inlen)
{
int ret;
const uint8_t *d;
size_t dlen;
if ((ret = asn1_sequence_from_der(&d, &dlen, in, inlen)) != 1) {
if (ret < 0) error_print();
return ret;
}
if (asn1_object_identifier_from_der(ibc_algorithm, ibc_algorithm_cnt, &d, &dlen) != 1
|| asn1_octet_string_from_der(public_parameter_data, public_parameter_data_len, &d, &dlen) != 1
|| asn1_length_is_zero(dlen) != 1) {
error_print();
return -1;
}
return 1;
}
int sm9_cms_ibc_public_parameters_to_der(
const uint8_t *ibc_public_parameters, size_t ibc_public_parameters_len,
uint8_t **out, size_t *outlen)
{
if (asn1_sequence_of_to_der(ibc_public_parameters, ibc_public_parameters_len, out, outlen) != 1) {
error_print();
return -1;
}
return 1;
}
int sm9_cms_ibc_public_parameters_from_der(
const uint8_t **ibc_public_parameters, size_t *ibc_public_parameters_len,
const uint8_t **in, size_t *inlen)
{
int ret;
if ((ret = asn1_sequence_of_from_der(ibc_public_parameters, ibc_public_parameters_len, in, inlen)) != 1) {
if (ret < 0) error_print();
return ret;
}
return 1;
}
int sm9_cms_sm9_public_parameter_data_to_der(
const uint8_t *pkg_id, size_t pkg_id_len,
const SM9_ENC_MASTER_KEY *enc_mast_public_key,
const SM9_SIGN_MASTER_KEY *sign_mast_public_key,
uint8_t **out, size_t *outlen)
{
size_t len = 0;
if (asn1_octet_string_to_der(pkg_id, pkg_id_len, NULL, &len) != 1
|| sm9_enc_master_public_key_to_der(enc_mast_public_key, NULL, &len) != 1
|| sm9_sign_master_public_key_to_der(sign_mast_public_key, NULL, &len) != 1
|| asn1_sequence_header_to_der(len, out, outlen) != 1
|| asn1_octet_string_to_der(pkg_id, pkg_id_len, out, outlen) != 1
|| sm9_enc_master_public_key_to_der(enc_mast_public_key, out, outlen) != 1
|| sm9_sign_master_public_key_to_der(sign_mast_public_key, out, outlen) != 1) {
error_print();
return -1;
}
return 1;
}
int sm9_cms_sm9_public_parameter_data_from_der(
const uint8_t **pkg_id, size_t *pkg_id_len,
SM9_ENC_MASTER_KEY *enc_mast_public_key,
SM9_SIGN_MASTER_KEY *sign_mast_public_key,
const uint8_t **in, size_t *inlen)
{
int ret;
const uint8_t *d;
size_t dlen;
if ((ret = asn1_sequence_from_der(&d, &dlen, in, inlen)) != 1) {
if (ret < 0) error_print();
return ret;
}
if (asn1_octet_string_from_der(pkg_id, pkg_id_len, &d, &dlen) != 1
|| sm9_enc_master_public_key_from_der(enc_mast_public_key, &d, &dlen) != 1
|| sm9_sign_master_public_key_from_der(sign_mast_public_key, &d, &dlen) != 1
|| asn1_length_is_zero(dlen) != 1) {
error_print();
return -1;
}
return 1;
}
int sm9_cms_ibc_param_extension_to_der(
const uint32_t *ibc_param_extension_oid, size_t ibc_param_extension_oid_cnt,
const uint8_t *ibc_param_extension_value, size_t ibc_param_extension_value_len,
uint8_t **out, size_t *outlen)
{
size_t len = 0;
if (asn1_object_identifier_to_der(ibc_param_extension_oid, ibc_param_extension_oid_cnt, NULL, &len) != 1
|| asn1_octet_string_to_der(ibc_param_extension_value, ibc_param_extension_value_len, NULL, &len) != 1
|| asn1_sequence_header_to_der(len, out, outlen) != 1
|| asn1_object_identifier_to_der(ibc_param_extension_oid, ibc_param_extension_oid_cnt, out, outlen) != 1
|| asn1_octet_string_to_der(ibc_param_extension_value, ibc_param_extension_value_len, out, outlen) != 1) {
error_print();
return -1;
}
return 1;
}
int sm9_cms_ibc_param_extension_from_der(
uint32_t *ibc_param_extension_oid, size_t *ibc_param_extension_oid_cnt,
const uint8_t **ibc_param_extension_value, size_t *ibc_param_extension_value_len,
const uint8_t **in, size_t *inlen)
{
int ret;
const uint8_t *d;
size_t dlen;
if ((ret = asn1_sequence_from_der(&d, &dlen, in, inlen)) != 1) {
if (ret < 0) error_print();
return ret;
}
if (asn1_object_identifier_from_der(ibc_param_extension_oid, ibc_param_extension_oid_cnt, &d, &dlen) != 1
|| asn1_octet_string_from_der(ibc_param_extension_value, ibc_param_extension_value_len, &d, &dlen) != 1
|| asn1_length_is_zero(dlen) != 1) {
error_print();
return -1;
}
return 1;
}
int sm9_cms_ibc_param_extensions_to_der(
const uint8_t *ibc_param_extensions, size_t ibc_param_extensions_len,
uint8_t **out, size_t *outlen)
{
if (!ibc_param_extensions) {
return 0;
}
if (asn1_sequence_of_to_der(ibc_param_extensions, ibc_param_extensions_len, out, outlen) != 1) {
error_print();
return -1;
}
return 1;
}
int sm9_cms_ibc_param_extensions_from_der(
const uint8_t **ibc_param_extensions, size_t *ibc_param_extensions_len,
const uint8_t **in, size_t *inlen)
{
int ret;
if ((ret = asn1_sequence_of_from_der(ibc_param_extensions, ibc_param_extensions_len, in, inlen)) < 0) {
error_print();
return -1;
}
return ret;
}
int sm9_cms_ibc_sys_params_to_der(
int version,
const char *district_name, size_t district_name_len,
int district_serial,
time_t not_before, time_t not_after,
const uint8_t *ibc_public_parameters, size_t ibc_public_parameters_len,
const uint32_t *ibc_identity_type, size_t ibc_identity_type_cnt,
const uint8_t *issuer_id, size_t issuer_id_len,
const uint8_t *ibc_param_extensions, size_t ibc_param_extensions_len,
uint8_t **out, size_t *outlen)
{
size_t len = 0;
if (version != 2) {
error_print();
return -1;
}
if (asn1_int_to_der(version, NULL, &len) != 1
|| asn1_ia5_string_to_der(district_name, district_name_len, NULL, &len) != 1
|| asn1_int_to_der(district_serial, NULL, &len) != 1
|| sm9_cms_validity_period_to_der(not_before, not_after, NULL, &len) != 1
|| sm9_cms_ibc_public_parameters_to_der(ibc_public_parameters, ibc_public_parameters_len, NULL, &len) != 1
|| asn1_object_identifier_to_der(ibc_identity_type, ibc_identity_type_cnt, NULL, &len) != 1
|| asn1_any_to_der(issuer_id, issuer_id_len, NULL, &len) != 1
|| sm9_cms_ibc_param_extensions_to_der(ibc_param_extensions, ibc_param_extensions_len, NULL, &len) < 0
|| asn1_sequence_header_to_der(len, out, outlen) != 1
|| asn1_int_to_der(version, out, outlen) != 1
|| asn1_ia5_string_to_der(district_name, district_name_len, out, outlen) != 1
|| asn1_int_to_der(district_serial, out, outlen) != 1
|| sm9_cms_validity_period_to_der(not_before, not_after, out, outlen) != 1
|| sm9_cms_ibc_public_parameters_to_der(ibc_public_parameters, ibc_public_parameters_len, out, outlen) != 1
|| asn1_object_identifier_to_der(ibc_identity_type, ibc_identity_type_cnt, out, outlen) != 1
|| asn1_any_to_der(issuer_id, issuer_id_len, out, outlen) != 1
|| sm9_cms_ibc_param_extensions_to_der(ibc_param_extensions, ibc_param_extensions_len, out, outlen) < 0) {
error_print();
return -1;
}
return 1;
}
int sm9_cms_ibc_sys_params_from_der(
int *version,
const char **district_name, size_t *district_name_len,
int *district_serial,
time_t *not_before, time_t *not_after,
const uint8_t **ibc_public_parameters, size_t *ibc_public_parameters_len,
uint32_t *ibc_identity_type, size_t *ibc_identity_type_cnt,
const uint8_t **issuer_id, size_t *issuer_id_len,
const uint8_t **ibc_param_extensions, size_t *ibc_param_extensions_len,
const uint8_t **in, size_t *inlen)
{
int ret;
const uint8_t *d;
size_t dlen;
if ((ret = asn1_sequence_from_der(&d, &dlen, in, inlen)) != 1) {
if (ret < 0) error_print();
return ret;
}
if (asn1_int_from_der(version, &d, &dlen) != 1
|| asn1_ia5_string_from_der(district_name, district_name_len, &d, &dlen) != 1
|| asn1_int_from_der(district_serial, &d, &dlen) != 1
|| sm9_cms_validity_period_from_der(not_before, not_after, &d, &dlen) != 1
|| sm9_cms_ibc_public_parameters_from_der(ibc_public_parameters, ibc_public_parameters_len, &d, &dlen) != 1
|| asn1_object_identifier_from_der(ibc_identity_type, ibc_identity_type_cnt, &d, &dlen) != 1
|| asn1_any_from_der(issuer_id, issuer_id_len, &d, &dlen) != 1
|| sm9_cms_ibc_param_extensions_from_der(ibc_param_extensions, ibc_param_extensions_len, &d, &dlen) < 0
|| asn1_length_is_zero(dlen) != 1) {
error_print();
return -1;
}
if (*version != 2) {
error_print();
return -1;
}
return 1;
}

View File

@@ -182,11 +182,310 @@ static int quic_test_initial_keys(void)
return 1;
}
static int quic_test_aes_128_gcm_sha256_packet_protection(void)
{
#ifdef ENABLE_SHA2
const uint8_t secret[32] = {
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
};
const uint8_t dcid[] = { 0x83, 0x94, 0xc8, 0xf0, 0x3e, 0x51, 0x57, 0x08 };
const uint8_t scid[] = { 0x08, 0x75, 0x6d, 0x35, 0x14, 0xf0, 0x9a, 0x1b };
const uint8_t frames[] = { QUIC_frame_ping, QUIC_frame_padding, QUIC_frame_padding };
QUIC_PACKET_KEYS keys;
QUIC_DECRYPTED_PACKET decrypted;
uint8_t packet[256];
size_t packet_len = 0;
memset(&keys, 0, sizeof(keys));
memset(&decrypted, 0, sizeof(decrypted));
if (quic_packet_keys_derive(DIGEST_sha256(), secret, TLS_cipher_aes_128_gcm_sha256, &keys) != 1
|| quic_long_packet_encrypt(&keys, QUIC_packet_initial, dcid, sizeof(dcid), scid, sizeof(scid),
1, frames, sizeof(frames), packet, &packet_len) != 1
|| quic_long_packet_decrypt(&keys, packet, packet_len, QUIC_packet_initial, &decrypted) != 1) {
error_print();
return -1;
}
if (decrypted.packet_number != 1
|| decrypted.plaintext_len != sizeof(frames)
|| memcmp(decrypted.plaintext, frames, sizeof(frames)) != 0) {
error_print();
return -1;
}
memset(packet, 0, sizeof(packet));
memset(&decrypted, 0, sizeof(decrypted));
if (quic_short_packet_encrypt(&keys, dcid, sizeof(dcid), 2, frames, sizeof(frames), packet, &packet_len) != 1
|| quic_short_packet_decrypt(&keys, packet, packet_len, dcid, sizeof(dcid), &decrypted) != 1) {
error_print();
return -1;
}
if (decrypted.packet_number != 2
|| decrypted.plaintext_len != sizeof(frames)
|| memcmp(decrypted.plaintext, frames, sizeof(frames)) != 0) {
error_print();
return -1;
}
#endif
printf("%s() ok\n", __FUNCTION__);
return 1;
}
static int quic_test_sm4_gcm_sm3_packet_protection(void)
{
const uint8_t secret[32] = {
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
};
const uint8_t dcid[] = { 0x83, 0x94, 0xc8, 0xf0, 0x3e, 0x51, 0x57, 0x08 };
const uint8_t scid[] = { 0x08, 0x75, 0x6d, 0x35, 0x14, 0xf0, 0x9a, 0x1b };
const uint8_t frames[] = { QUIC_frame_ping, QUIC_frame_padding, QUIC_frame_padding };
QUIC_PACKET_KEYS keys;
QUIC_DECRYPTED_PACKET decrypted;
uint8_t packet[256];
size_t packet_len = 0;
memset(&keys, 0, sizeof(keys));
memset(&decrypted, 0, sizeof(decrypted));
if (quic_packet_keys_derive(DIGEST_sm3(), secret, TLS_cipher_sm4_gcm_sm3, &keys) != 1
|| quic_long_packet_encrypt(&keys, QUIC_packet_handshake, dcid, sizeof(dcid), scid, sizeof(scid),
3, frames, sizeof(frames), packet, &packet_len) != 1
|| quic_long_packet_decrypt(&keys, packet, packet_len, QUIC_packet_handshake, &decrypted) != 1) {
error_print();
return -1;
}
if (decrypted.packet_number != 3
|| decrypted.plaintext_len != sizeof(frames)
|| memcmp(decrypted.plaintext, frames, sizeof(frames)) != 0) {
error_print();
return -1;
}
memset(packet, 0, sizeof(packet));
memset(&decrypted, 0, sizeof(decrypted));
if (quic_short_packet_encrypt(&keys, dcid, sizeof(dcid), 4, frames, sizeof(frames), packet, &packet_len) != 1
|| quic_short_packet_decrypt(&keys, packet, packet_len, dcid, sizeof(dcid), &decrypted) != 1) {
error_print();
return -1;
}
if (decrypted.packet_number != 4
|| decrypted.plaintext_len != sizeof(frames)
|| memcmp(decrypted.plaintext, frames, sizeof(frames)) != 0) {
error_print();
return -1;
}
printf("%s() ok\n", __FUNCTION__);
return 1;
}
static int quic_test_sm4_ccm_sm3_packet_protection(void)
{
#ifdef ENABLE_SM4_CCM
const uint8_t secret[32] = {
0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
};
const uint8_t dcid[] = { 0x83, 0x94, 0xc8, 0xf0, 0x3e, 0x51, 0x57, 0x08 };
const uint8_t scid[] = { 0x08, 0x75, 0x6d, 0x35, 0x14, 0xf0, 0x9a, 0x1b };
const uint8_t frames[] = { QUIC_frame_ping, QUIC_frame_padding, QUIC_frame_padding };
QUIC_PACKET_KEYS keys;
QUIC_DECRYPTED_PACKET decrypted;
uint8_t packet[256];
size_t packet_len = 0;
memset(&keys, 0, sizeof(keys));
memset(&decrypted, 0, sizeof(decrypted));
if (quic_packet_keys_derive(DIGEST_sm3(), secret, TLS_cipher_sm4_ccm_sm3, &keys) != 1
|| quic_long_packet_encrypt(&keys, QUIC_packet_handshake, dcid, sizeof(dcid), scid, sizeof(scid),
5, frames, sizeof(frames), packet, &packet_len) != 1
|| quic_long_packet_decrypt(&keys, packet, packet_len, QUIC_packet_handshake, &decrypted) != 1) {
error_print();
return -1;
}
if (decrypted.packet_number != 5
|| decrypted.plaintext_len != sizeof(frames)
|| memcmp(decrypted.plaintext, frames, sizeof(frames)) != 0) {
error_print();
return -1;
}
memset(packet, 0, sizeof(packet));
memset(&decrypted, 0, sizeof(decrypted));
if (quic_short_packet_encrypt(&keys, dcid, sizeof(dcid), 6, frames, sizeof(frames), packet, &packet_len) != 1
|| quic_short_packet_decrypt(&keys, packet, packet_len, dcid, sizeof(dcid), &decrypted) != 1) {
error_print();
return -1;
}
if (decrypted.packet_number != 6
|| decrypted.plaintext_len != sizeof(frames)
|| memcmp(decrypted.plaintext, frames, sizeof(frames)) != 0) {
error_print();
return -1;
}
#endif
printf("%s() ok\n", __FUNCTION__);
return 1;
}
static int quic_test_client_hello_to_bytes(void)
{
TLS_CTX ctx;
TLS_CONNECT conn;
int cipher_suites[] = { TLS_cipher_sm4_gcm_sm3 };
int supported_groups[] = { TLS_curve_sm2p256v1 };
int signature_algorithms[] = { TLS_sig_sm2sig_sm3 };
uint8_t buf[TLS_MAX_RECORD_SIZE];
uint8_t *p = buf;
size_t len = 0;
size_t handshake_len;
if (tls_ctx_init(&ctx, TLS_protocol_tls13, TLS_client_mode) != 1
|| tls_ctx_set_cipher_suites(&ctx, cipher_suites, sizeof(cipher_suites)/sizeof(cipher_suites[0])) != 1
|| tls_ctx_set_supported_groups(&ctx, supported_groups, sizeof(supported_groups)/sizeof(supported_groups[0])) != 1
|| tls_ctx_set_signature_algorithms(&ctx, signature_algorithms, sizeof(signature_algorithms)/sizeof(signature_algorithms[0])) != 1
|| tls_init(&conn, &ctx) != 1) {
error_print();
return -1;
}
if (quic_client_hello_to_bytes(&conn, &p, &len) != 1) {
error_print();
tls_ctx_cleanup(&ctx);
return -1;
}
if (len < TLS_HANDSHAKE_HEADER_SIZE || p != buf + len) {
error_print();
tls_ctx_cleanup(&ctx);
return -1;
}
if (buf[0] != TLS_handshake_client_hello || buf[0] == TLS_record_handshake) {
error_print();
tls_ctx_cleanup(&ctx);
return -1;
}
handshake_len = ((size_t)buf[1] << 16) | ((size_t)buf[2] << 8) | buf[3];
if (handshake_len + TLS_HANDSHAKE_HEADER_SIZE != len) {
error_print();
tls_ctx_cleanup(&ctx);
return -1;
}
if (conn.plain_recordlen != len || memcmp(conn.plain_record, buf, len) != 0) {
error_print();
tls_ctx_cleanup(&ctx);
return -1;
}
tls_ctx_cleanup(&ctx);
printf("%s() ok\n", __FUNCTION__);
return 1;
}
static int quic_test_verbose_print(void)
{
TLS_CTX ctx;
TLS_CONNECT conn;
int cipher_suites[] = { TLS_cipher_sm4_gcm_sm3 };
int supported_groups[] = { TLS_curve_sm2p256v1 };
int signature_algorithms[] = { TLS_sig_sm2sig_sm3 };
uint8_t handshake[TLS_MAX_RECORD_SIZE];
uint8_t frames[TLS_MAX_RECORD_SIZE];
uint8_t packet[64];
uint8_t *p = handshake;
uint8_t *q = frames;
uint8_t *r = packet;
size_t handshake_len = 0;
size_t frames_len = 0;
size_t packet_len = 0;
FILE *fp;
fp = tmpfile();
if (!fp) {
error_print();
return -1;
}
if (tls_ctx_init(&ctx, TLS_protocol_tls13, TLS_client_mode) != 1
|| tls_ctx_set_cipher_suites(&ctx, cipher_suites, sizeof(cipher_suites)/sizeof(cipher_suites[0])) != 1
|| tls_ctx_set_supported_groups(&ctx, supported_groups, sizeof(supported_groups)/sizeof(supported_groups[0])) != 1
|| tls_ctx_set_signature_algorithms(&ctx, signature_algorithms, sizeof(signature_algorithms)/sizeof(signature_algorithms[0])) != 1
|| tls_init(&conn, &ctx) != 1) {
error_print();
fclose(fp);
return -1;
}
if (quic_client_hello_to_bytes(&conn, &p, &handshake_len) != 1
|| quic_crypto_data_print(fp, 0, 0, QUIC_encryption_initial, handshake, handshake_len) != 1) {
error_print();
tls_ctx_cleanup(&ctx);
fclose(fp);
return -1;
}
if (quic_varint_to_bytes(QUIC_frame_ping, &q, &frames_len) != 1
|| quic_varint_to_bytes(QUIC_frame_crypto, &q, &frames_len) != 1
|| quic_varint_to_bytes(0, &q, &frames_len) != 1
|| quic_varint_to_bytes(handshake_len, &q, &frames_len) != 1) {
error_print();
tls_ctx_cleanup(&ctx);
fclose(fp);
return -1;
}
memcpy(q, handshake, handshake_len);
q += handshake_len;
frames_len += handshake_len;
if (quic_frames_print(fp, 0, 0, QUIC_encryption_initial, frames, frames_len) != 1) {
error_print();
tls_ctx_cleanup(&ctx);
fclose(fp);
return -1;
}
*r++ = 0xc0;
*r++ = 0x00; *r++ = 0x00; *r++ = 0x00; *r++ = 0x01;
*r++ = 0x08;
memcpy(r, "12345678", 8); r += 8;
*r++ = 0x08;
memcpy(r, "87654321", 8); r += 8;
*r++ = 0x00;
*r++ = 0x01;
*r++ = 0x00;
packet_len = (size_t)(r - packet);
if (quic_packet_print(fp, 0, 0, packet, packet_len) != 1) {
error_print();
tls_ctx_cleanup(&ctx);
fclose(fp);
return -1;
}
tls_ctx_cleanup(&ctx);
fclose(fp);
printf("%s() ok\n", __FUNCTION__);
return 1;
}
int main(void)
{
if (quic_test_varint() != 1
|| quic_test_transport_params() != 1
|| quic_test_initial_keys() != 1) {
|| quic_test_initial_keys() != 1
|| quic_test_aes_128_gcm_sha256_packet_protection() != 1
|| quic_test_sm4_gcm_sm3_packet_protection() != 1
|| quic_test_sm4_ccm_sm3_packet_protection() != 1
|| quic_test_client_hello_to_bytes() != 1
|| quic_test_verbose_print() != 1) {
error_print();
return 1;
}

View File

@@ -35,6 +35,7 @@ extern int sm2sign_main(int argc, char **argv);
extern int sm2verify_main(int argc, char **argv);
extern int sm2encrypt_main(int argc, char **argv);
extern int sm2decrypt_main(int argc, char **argv);
extern int sm2exch_main(int argc, char **argv);
extern int sm3_main(int argc, char **argv);
extern int sm3hmac_main(int argc, char **argv);
extern int sm3_pbkdf2_main(int argc, char **argv);
@@ -64,6 +65,9 @@ extern int sm4_cbc_mac_main(int argc, char **argv);
#endif
#ifdef ENABLE_ZUC
extern int zuc_main(int argc, char **argv);
extern int zuc256_main(int argc, char **argv);
extern int zuc_128_eea3_main(int argc, char **argv);
extern int zuc_128_eia3_main(int argc, char **argv);
#endif
#ifdef ENABLE_GHASH
extern int ghash_main(int argc, char **argv);
@@ -75,6 +79,7 @@ extern int sm9sign_main(int argc, char **argv);
extern int sm9verify_main(int argc, char **argv);
extern int sm9encrypt_main(int argc, char **argv);
extern int sm9decrypt_main(int argc, char **argv);
extern int sm9exch_main(int argc, char **argv);
#endif
#ifdef ENABLE_CMS
extern int cmsparse_main(int argc, char **argv);
@@ -92,6 +97,10 @@ extern int tls13_client_main(int argc, char **argv);
extern int tls13_server_main(int argc, char **argv);
extern int sctverify_main(int argc, char **argv);
#endif
#ifdef ENABLE_QUIC
extern int quic_client_main(int argc, char **argv);
extern int quic_server_main(int argc, char **argv);
#endif
#ifdef ENABLE_SECP256R1
extern int p256keygen_main(int argc, char **argv);
#endif
@@ -147,9 +156,11 @@ static const char *options =
" sm2verify Verify SM2 signature\n"
" sm2encrypt Encrypt with SM2 public key\n"
" sm2decrypt Decrypt with SM2 private key\n"
" sm2exch SM2 key exchange\n"
" sm3 Generate SM3 hash\n"
" sm3hmac Generate SM3 HMAC tag\n"
" sm3_pbkdf2 Hash password into key using PBKDF2 algoritm\n"
" sm4 Encrypt or decrypt with SM4\n"
" sm4_gcm Encrypt or decrypt with SM4 GCM\n"
" sm4_cbc Encrypt or decrypt with SM4 CBC\n"
" sm4_ctr Encrypt or decrypt with SM4 CTR\n"
@@ -179,6 +190,9 @@ static const char *options =
#endif
#ifdef ENABLE_ZUC
" zuc Encrypt or decrypt with ZUC\n"
" zuc256 Encrypt or decrypt with ZUC-256\n"
" zuc_128_eea3 Encrypt or decrypt with ZUC 128-EEA3\n"
" zuc_128_eia3 Generate ZUC 128-EIA3 MAC\n"
#endif
#ifdef ENABLE_SM9
" sm9setup Generate SM9 master secret\n"
@@ -187,6 +201,7 @@ static const char *options =
" sm9verify Verify SM9 signature\n"
" sm9encrypt SM9 public key encryption\n"
" sm9decrypt SM9 decryption\n"
" sm9exch SM9 key exchange\n"
#endif
" reqgen Generate certificate signing request (CSR)\n"
" reqsign Generate certificate from CSR\n"
@@ -259,6 +274,10 @@ static const char *options =
" tls12_server TLS 1.2 server\n"
" tls13_client TLS 1.3 client\n"
" tls13_server TLS 1.3 server\n"
#endif
#ifdef ENABLE_QUIC
" quic_client QUIC client\n"
" quic_server QUIC server\n"
#endif
"\n"
"run `gmssl <command> -help` to print help of the given command\n"
@@ -326,6 +345,8 @@ int main(int argc, char **argv)
return sm2encrypt_main(argc, argv);
} else if (!strcmp(*argv, "sm2decrypt")) {
return sm2decrypt_main(argc, argv);
} else if (!strcmp(*argv, "sm2exch")) {
return sm2exch_main(argc, argv);
} else if (!strcmp(*argv, "sm3")) {
return sm3_main(argc, argv);
} else if (!strcmp(*argv, "sm3hmac")) {
@@ -373,6 +394,12 @@ int main(int argc, char **argv)
#ifdef ENABLE_ZUC
} else if (!strcmp(*argv, "zuc")) {
return zuc_main(argc, argv);
} else if (!strcmp(*argv, "zuc256")) {
return zuc256_main(argc, argv);
} else if (!strcmp(*argv, "zuc_128_eea3")) {
return zuc_128_eea3_main(argc, argv);
} else if (!strcmp(*argv, "zuc_128_eia3")) {
return zuc_128_eia3_main(argc, argv);
#endif
#ifdef ENABLE_SM9
} else if (!strcmp(*argv, "sm9setup")) {
@@ -387,6 +414,8 @@ int main(int argc, char **argv)
return sm9encrypt_main(argc, argv);
} else if (!strcmp(*argv, "sm9decrypt")) {
return sm9decrypt_main(argc, argv);
} else if (!strcmp(*argv, "sm9exch")) {
return sm9exch_main(argc, argv);
#endif
#ifdef ENABLE_CMS
} else if (!strcmp(*argv, "cmsparse")) {
@@ -416,6 +445,12 @@ int main(int argc, char **argv)
} else if (!strcmp(*argv, "sctverify")) {
return sctverify_main(argc, argv);
#endif
#ifdef ENABLE_QUIC
} else if (!strcmp(*argv, "quic_client")) {
return quic_client_main(argc, argv);
} else if (!strcmp(*argv, "quic_server")) {
return quic_server_main(argc, argv);
#endif
#ifdef ENABLE_SECP256R1
} else if (!strcmp(*argv, "p256keygen")) {
return p256keygen_main(argc, argv);

1270
tools/quic_client.c Normal file

File diff suppressed because it is too large Load Diff

35
tools/quic_help.h Normal file
View File

@@ -0,0 +1,35 @@
"\n"
"Supported cipher suites:\n"
#if defined(ENABLE_AES) && defined(ENABLE_SHA2)
" TLS_AES_128_GCM_SHA256\n"
#ifdef ENABLE_AES_CCM
" TLS_AES_128_CCM_SHA256\n"
#endif
#endif
" TLS_SM4_GCM_SM3\n"
#ifdef ENABLE_SM4_CCM
" TLS_SM4_CCM_SM3\n"
#endif
"\n"
"Examples\n"
"\n"
" gmssl quic_server -port 4433 -cert p256_tls_server_certs.pem -key p256_tls_server_key.pem \\\n"
" -pass P@ssw0rd -cipher_suite TLS_AES_128_GCM_SHA256 -supported_group prime256v1 \\\n"
" -sig_alg ecdsa_secp256r1_sha256 -verbose\n"
" gmssl quic_client -host 127.0.0.1 -port 4433 -server_name localhost \\\n"
" -cipher_suite TLS_AES_128_GCM_SHA256 -supported_group prime256v1 \\\n"
" -sig_alg ecdsa_secp256r1_sha256 -get / -verbose\n"
"\n"
" gmssl quic_server -port 4434 -cert sm2_tls_server_certs.pem -key sm2_tls_server_key.pem \\\n"
" -pass P@ssw0rd -cipher_suite TLS_SM4_GCM_SM3 -supported_group sm2p256v1 \\\n"
" -sig_alg sm2sig_sm3 -verbose\n"
" gmssl quic_client -host 127.0.0.1 -port 4434 -server_name localhost \\\n"
" -cipher_suite TLS_SM4_GCM_SM3 -supported_group sm2p256v1 -sig_alg sm2sig_sm3 \\\n"
" -get / -verbose\n"
"\n"
" ngtcp2/examples/osslserver --groups=P-256 --ciphers=TLS_AES_128_GCM_SHA256 \\\n"
" -d htdocs 127.0.0.1 4435 p256-key.pem p256-cert.pem\n"
" gmssl quic_client -host 127.0.0.1 -port 4435 -server_name localhost \\\n"
" -cipher_suite TLS_AES_128_GCM_SHA256 -supported_group prime256v1 \\\n"
" -sig_alg ecdsa_secp256r1_sha256 -get / -verbose\n"
"\n"

1010
tools/quic_server.c Normal file

File diff suppressed because it is too large Load Diff

929
tools/sm2exch.c Normal file
View File

@@ -0,0 +1,929 @@
/*
* Copyright 2014-2026 The GmSSL Project. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the License); you may
* not use this file except in compliance with the License.
*
* http://www.apache.org/licenses/LICENSE-2.0
*/
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>
#include <stdint.h>
#include <gmssl/mem.h>
#include <gmssl/hex.h>
#include <gmssl/pem.h>
#include <gmssl/sm2.h>
#include <gmssl/x509.h>
#include <gmssl/x509_ext.h>
#define SM2EXCH_RA_SIZE 65
#define SM2EXCH_RB_SIZE 65
#define SM2EXCH_CONFIRM_SIZE 32
#define SM2EXCH_RB_SB_SIZE (SM2EXCH_RB_SIZE + SM2EXCH_CONFIRM_SIZE)
#define SM2EXCH_SECRET_STATE_SIZE 65
#define SM2EXCH_MAX_SHARED_KEY_SIZE 1024
#define PEM_SM2_EXCH_PEER_RA "SM2 EXCHANGE PEER RA"
enum {
SM2EXCH_FMT_BIN = 0,
SM2EXCH_FMT_HEX = 1,
};
static const char *usage =
"-stage init|respond|confirm|finish [options]";
static const char *options =
"\n"
"Options\n"
"\n"
" -stage init|respond|confirm|finish\n"
" SM2 key exchange stage\n"
" -cert pem Optional local SM2 certificate for checking against -key\n"
" -pubkey pem Optional local SM2 public key for checking against -key\n"
" -key pem Local SM2 private key in PEM format\n"
" -pass str Password to open local private key\n"
" -peer_cert pem Peer SM2 key exchange/encryption certificate in PEM format\n"
" -peer_pubkey pem Peer SM2 public key in PEM format\n"
" -id str Local SM2 identity, '1234567812345678' by default\n"
" -id_hex hex Local SM2 identity in hex\n"
" -peer_id str Peer SM2 identity, '1234567812345678' by default\n"
" -peer_id_hex hex Peer SM2 identity in hex\n"
" -in file | stdin Input data for this stage\n"
" respond: RA, 65 bytes\n"
" confirm: RB || SB, 97 bytes\n"
" finish: SA, 32 bytes\n"
" -out file | stdout Output data to send to peer\n"
" init: RA, 65 bytes\n"
" respond: RB || SB, 97 bytes\n"
" confirm: SA, 32 bytes\n"
" -exch_keyout pem Output local ephemeral private key\n"
" -exch_key pem Input local ephemeral private key\n"
" -exch_pass str Password for local ephemeral private key\n"
" -secret_state_out file\n"
" Output 65-byte secret_state point\n"
" -secret_state file Input 65-byte secret_state point\n"
" -keylen num Shared key length in bytes, 32 by default\n"
" -keyout file Output shared key\n"
" -hex Encode input/output data in hex, default\n"
" -bin Encode input/output data in binary\n"
"\n"
"Examples\n"
"\n"
"Public-key file workflow:\n"
"\n"
" gmssl sm2keygen -pass P@ssw0rd -out alice.pem -pubout alicepub.pem\n"
" gmssl sm2keygen -pass P@ssw0rd -out bob.pem -pubout bobpub.pem\n"
" gmssl sm2exch -stage init \\\n"
" -exch_keyout alice_ra.pem -exch_pass P@ssw0rd -out ra.hex\n"
" gmssl sm2exch -stage respond \\\n"
" -key bob.pem -pass P@ssw0rd -id Bob \\\n"
" -peer_pubkey alicepub.pem -peer_id Alice -in ra.hex \\\n"
" -exch_keyout bob_rb.pem -exch_pass P@ssw0rd \\\n"
" -secret_state_out bob_secret_state.hex -out rb_sb.hex\n"
" gmssl sm2exch -stage confirm \\\n"
" -key alice.pem -pass P@ssw0rd -id Alice \\\n"
" -peer_pubkey bobpub.pem -peer_id Bob \\\n"
" -exch_key alice_ra.pem -exch_pass P@ssw0rd -in rb_sb.hex \\\n"
" -keylen 48 -keyout alice_shared_key.hex -out sa.hex\n"
" gmssl sm2exch -stage finish \\\n"
" -key bob.pem -pass P@ssw0rd -id Bob \\\n"
" -peer_pubkey alicepub.pem -peer_id Alice \\\n"
" -exch_key bob_rb.pem -exch_pass P@ssw0rd \\\n"
" -secret_state bob_secret_state.hex -in sa.hex \\\n"
" -keylen 48 -keyout bob_shared_key.hex\n"
"\n"
"Certificate workflow:\n"
"\n"
" gmssl sm2exch -stage respond \\\n"
" -key bob_enc_key.pem -pass P@ssw0rd -id Bob \\\n"
" -peer_cert alice_enc_cert.pem -peer_id Alice -in ra.hex \\\n"
" -exch_keyout bob_rb.pem -exch_pass P@ssw0rd \\\n"
" -secret_state_out bob_secret_state.hex -out rb_sb.hex\n"
" gmssl sm2exch -stage confirm \\\n"
" -key alice_enc_key.pem -pass P@ssw0rd -id Alice \\\n"
" -peer_cert bob_enc_cert.pem -peer_id Bob \\\n"
" -exch_key alice_ra.pem -exch_pass P@ssw0rd -in rb_sb.hex \\\n"
" -keyout alice_shared_key.hex -out sa.hex\n"
"\n"
"Notes\n"
"\n"
" -cert and -peer_cert read only the first certificate from the PEM file.\n"
" If KeyUsage is present, the certificate must allow keyEncipherment or keyAgreement.\n"
" RA, RB and secret_state are fixed 65-byte uncompressed SM2 points.\n"
" The respond output is RB || SB, fixed 97 bytes.\n"
" -hex and -bin affect RA, RB||SB, SA, secret_state and shared key files.\n"
"\n";
static int read_file(const char *file, uint8_t *buf, size_t *len, size_t maxlen)
{
FILE *fp = stdin;
size_t n;
if (!buf || !len) {
return -1;
}
if (file && !(fp = fopen(file, "rb"))) {
return -1;
}
n = fread(buf, 1, maxlen + 1, fp);
if (ferror(fp)) {
if (file) fclose(fp);
return -1;
}
if (file) fclose(fp);
if (n > maxlen) {
return -1;
}
*len = n;
return 1;
}
static int write_file(const char *file, const uint8_t *buf, size_t len)
{
FILE *fp = stdout;
int ret = -1;
if (!buf || !len) {
return -1;
}
if (file && !(fp = fopen(file, "wb"))) {
return -1;
}
if (fwrite(buf, 1, len, fp) == len) {
ret = 1;
}
if (file) fclose(fp);
return ret;
}
static int sm2exch_read_exact(const char *file, uint8_t *buf, size_t len);
static int sm2exch_write_data(const char *file, const uint8_t *buf, size_t len, int format)
{
uint8_t *hexbuf = NULL;
size_t i;
int ret;
if (format == SM2EXCH_FMT_BIN) {
return write_file(file, buf, len);
}
if (!(hexbuf = malloc(len * 2))) {
return -1;
}
for (i = 0; i < len; i++) {
static const char *hex = "0123456789abcdef";
hexbuf[i * 2] = (uint8_t)hex[buf[i] >> 4];
hexbuf[i * 2 + 1] = (uint8_t)hex[buf[i] & 0x0f];
}
ret = write_file(file, hexbuf, len * 2);
gmssl_secure_clear(hexbuf, len * 2);
free(hexbuf);
return ret;
}
static int sm2exch_read_data(const char *file, uint8_t *buf, size_t len, int format)
{
uint8_t *in = NULL;
uint8_t *hex = NULL;
size_t inlen;
size_t hexlen = 0;
size_t outlen;
size_t i;
int ret = -1;
if (format == SM2EXCH_FMT_BIN) {
return sm2exch_read_exact(file, buf, len);
}
if (!(in = malloc(len * 2 + 64)) || !(hex = malloc(len * 2))) {
goto end;
}
if (read_file(file, in, &inlen, len * 2 + 63) != 1) {
goto end;
}
for (i = 0; i < inlen; i++) {
if (in[i] == ' ' || in[i] == '\t' || in[i] == '\r' || in[i] == '\n') {
continue;
}
if (hexlen >= len * 2) {
goto end;
}
hex[hexlen++] = in[i];
}
if (hexlen != len * 2
|| hex_to_bytes((char *)hex, hexlen, buf, &outlen) != 1
|| outlen != len) {
goto end;
}
ret = 1;
end:
if (in) {
gmssl_secure_clear(in, len * 2 + 64);
free(in);
}
if (hex) {
gmssl_secure_clear(hex, len * 2);
free(hex);
}
return ret;
}
static int sm2exch_read_point(const char *file, uint8_t point[65], int format)
{
if (sm2exch_read_data(file, point, 65, format) != 1) {
return -1;
}
if (point[0] != 0x04) {
return -1;
}
return 1;
}
static int sm2exch_read_exact(const char *file, uint8_t *buf, size_t len)
{
size_t inlen;
if (read_file(file, buf, &inlen, len) != 1 || inlen != len) {
return -1;
}
return 1;
}
static int sm2exch_cert_check_key_usage(const uint8_t *cert, size_t certlen)
{
int ret;
int critical;
const uint8_t *exts;
size_t extslen;
const uint8_t *val;
size_t vlen;
int bits;
if (!cert || !certlen) {
return -1;
}
if ((ret = x509_cert_get_exts(cert, certlen, &exts, &extslen)) < 0) {
return -1;
}
if (ret == 0) {
return 1;
}
if ((ret = x509_exts_get_ext_by_oid(exts, extslen, OID_ce_key_usage,
&critical, &val, &vlen)) < 0) {
return -1;
}
if (ret == 0) {
return 1;
}
if (x509_key_usage_from_der(&bits, &val, &vlen) != 1
|| asn1_length_is_zero(vlen) != 1) {
return -1;
}
if ((bits & (X509_KU_KEY_ENCIPHERMENT | X509_KU_KEY_AGREEMENT)) == 0) {
return 0;
}
return 1;
}
static int sm2exch_load_public_key(SM2_KEY *pub_key, const char *pubkeyfile,
const char *certfile, const char *prog, const char *label)
{
FILE *fp = NULL;
uint8_t cert[4096];
size_t certlen;
X509_KEY x509_key;
int ret;
if (!pub_key || !prog || !label) {
return -1;
}
if (pubkeyfile && certfile) {
if (label[0]) {
fprintf(stderr, "gmssl %s: options '-%s_pubkey' and '-%s_cert' conflict\n",
prog, label, label);
} else {
fprintf(stderr, "gmssl %s: options '-pubkey' and '-cert' conflict\n", prog);
}
return -1;
}
if (pubkeyfile) {
if (!(fp = fopen(pubkeyfile, "rb"))) {
fprintf(stderr, "gmssl %s: open '%s' failure : %s\n", prog, pubkeyfile, strerror(errno));
return -1;
}
ret = sm2_public_key_info_from_pem(pub_key, fp);
fclose(fp);
if (ret != 1) {
fprintf(stderr, "gmssl %s: parse public key failed\n", prog);
return -1;
}
return 1;
}
if (certfile) {
if (!(fp = fopen(certfile, "rb"))) {
fprintf(stderr, "gmssl %s: open '%s' failure : %s\n", prog, certfile, strerror(errno));
return -1;
}
ret = x509_cert_from_pem(cert, &certlen, sizeof(cert), fp);
fclose(fp);
if (ret != 1
|| x509_cert_get_subject_public_key(cert, certlen, &x509_key) != 1) {
fprintf(stderr, "gmssl %s: parse certificate failed\n", prog);
return -1;
}
if (x509_key.algor != OID_ec_public_key || x509_key.algor_param != OID_sm2) {
fprintf(stderr, "gmssl %s: certificate public key is not SM2\n", prog);
return -1;
}
ret = sm2exch_cert_check_key_usage(cert, certlen);
if (ret < 0) {
fprintf(stderr, "gmssl %s: certificate KeyUsage parse failure\n", prog);
return -1;
}
if (ret == 0) {
fprintf(stderr, "gmssl %s: certificate KeyUsage does not allow key exchange/encryption\n", prog);
return -1;
}
*pub_key = x509_key.u.sm2_key;
return 1;
}
if (label[0]) {
fprintf(stderr, "gmssl %s: '-%s_pubkey' or '-%s_cert' option required\n",
prog, label, label);
} else {
fprintf(stderr, "gmssl %s: '-pubkey' or '-cert' option required\n", prog);
}
return -1;
}
static int sm2exch_load_private_key(SM2_KEY *key, const char *keyfile,
const char *pass, const char *prog)
{
FILE *fp;
int ret;
if (!keyfile) {
fprintf(stderr, "gmssl %s: '-key' option required\n", prog);
return -1;
}
if (!pass) {
fprintf(stderr, "gmssl %s: '-pass' option required\n", prog);
return -1;
}
if (!(fp = fopen(keyfile, "rb"))) {
fprintf(stderr, "gmssl %s: open '%s' failure : %s\n", prog, keyfile, strerror(errno));
return -1;
}
ret = sm2_private_key_info_decrypt_from_pem(key, pass, fp);
fclose(fp);
if (ret != 1) {
fprintf(stderr, "gmssl %s: private key decryption failure\n", prog);
return -1;
}
return 1;
}
static int sm2exch_load_exch_key(SM2_KEY *key, uint8_t peer_ra[65],
const char *keyfile, const char *pass, const char *prog)
{
FILE *fp;
int ret;
size_t len;
if (!keyfile) {
fprintf(stderr, "gmssl %s: '-exch_key' option required\n", prog);
return -1;
}
if (!pass) {
fprintf(stderr, "gmssl %s: '-exch_pass' option required\n", prog);
return -1;
}
if (!(fp = fopen(keyfile, "rb"))) {
fprintf(stderr, "gmssl %s: open '%s' failure : %s\n", prog, keyfile, strerror(errno));
return -1;
}
ret = sm2_private_key_info_decrypt_from_pem(key, pass, fp);
if (ret != 1) {
fprintf(stderr, "gmssl %s: ephemeral private key decryption failure\n", prog);
goto end;
}
if (peer_ra) {
if (pem_read(fp, PEM_SM2_EXCH_PEER_RA, peer_ra, &len, 65) != 1
|| len != 65 || peer_ra[0] != 0x04) {
fprintf(stderr, "gmssl %s: peer RA not found in exchange key\n", prog);
ret = -1;
goto end;
}
}
ret = 1;
end:
fclose(fp);
return ret;
}
static int sm2exch_save_exch_key(const SM2_KEY *key, const char *keyfile,
const char *pass, const uint8_t peer_ra[65], const char *prog)
{
FILE *fp;
int ret;
if (!keyfile) {
fprintf(stderr, "gmssl %s: '-exch_keyout' option required\n", prog);
return -1;
}
if (!pass) {
fprintf(stderr, "gmssl %s: '-exch_pass' option required\n", prog);
return -1;
}
if (!(fp = fopen(keyfile, "wb"))) {
fprintf(stderr, "gmssl %s: open '%s' failure : %s\n", prog, keyfile, strerror(errno));
return -1;
}
ret = sm2_private_key_info_encrypt_to_pem(key, pass, fp);
if (ret == 1 && peer_ra) {
ret = pem_write(fp, PEM_SM2_EXCH_PEER_RA, peer_ra, 65);
}
fclose(fp);
if (ret != 1) {
fprintf(stderr, "gmssl %s: output ephemeral private key failed\n", prog);
return -1;
}
return 1;
}
static int sm2exch_load_local_keys(SM2_KEY *key, const char *keyfile, const char *pass,
const char *pubkeyfile, const char *certfile, const char *prog)
{
SM2_KEY pub_key;
if (sm2exch_load_private_key(key, keyfile, pass, prog) != 1) {
return -1;
}
if (pubkeyfile || certfile) {
if (sm2exch_load_public_key(&pub_key, pubkeyfile, certfile, prog, "") != 1) {
return -1;
}
if (sm2_public_key_equ(key, &pub_key) != 1) {
fprintf(stderr, "gmssl %s: private key does not match local public key/certificate\n", prog);
return -1;
}
}
return 1;
}
static int sm2exch_derive_key_from_secret_state(int is_initiator,
const SM2_KEY *key, const char *id, size_t idlen,
const SM2_KEY *peer_public_key, const char *peer_id, size_t peer_idlen,
const uint8_t secret_state[65], uint8_t *shared_key, size_t shared_key_len)
{
SM2_Z256_POINT point;
uint8_t za[32];
uint8_t zb[32];
uint8_t kdf_input[128];
int ret = -1;
if (!key || !id || !peer_public_key || !peer_id
|| !secret_state || !shared_key || !shared_key_len) {
return -1;
}
if (sm2_z256_point_from_octets(&point, secret_state, 65) != 1) {
return -1;
}
if (is_initiator) {
if (sm2_compute_z(za, &key->public_key, id, idlen) != 1
|| sm2_compute_z(zb, &peer_public_key->public_key, peer_id, peer_idlen) != 1) {
goto end;
}
} else {
if (sm2_compute_z(za, &peer_public_key->public_key, peer_id, peer_idlen) != 1
|| sm2_compute_z(zb, &key->public_key, id, idlen) != 1) {
goto end;
}
}
sm2_z256_point_to_bytes(&point, kdf_input);
memcpy(kdf_input + 64, za, sizeof(za));
memcpy(kdf_input + 96, zb, sizeof(zb));
if (sm2_kdf(kdf_input, sizeof(kdf_input), shared_key_len, shared_key) != 1
|| mem_is_zero(shared_key, shared_key_len)) {
goto end;
}
ret = 1;
end:
gmssl_secure_clear(&point, sizeof(point));
gmssl_secure_clear(za, sizeof(za));
gmssl_secure_clear(zb, sizeof(zb));
gmssl_secure_clear(kdf_input, sizeof(kdf_input));
return ret;
}
static int sm2exch_stage_init(const char *exch_keyoutfile, const char *exch_pass,
const char *outfile, int format, const char *prog)
{
SM2_KEY exch_key;
uint8_t ra[65];
int ret = -1;
if (sm2_key_generate(&exch_key) != 1
|| sm2_z256_point_to_uncompressed_octets(&exch_key.public_key, ra) != 1
|| sm2exch_save_exch_key(&exch_key, exch_keyoutfile, exch_pass, NULL, prog) != 1
|| sm2exch_write_data(outfile, ra, sizeof(ra), format) != 1) {
fprintf(stderr, "gmssl %s: init stage failure\n", prog);
goto end;
}
ret = 0;
end:
gmssl_secure_clear(&exch_key, sizeof(exch_key));
return ret;
}
static int sm2exch_stage_respond(const char *keyfile, const char *pass,
const char *pubkeyfile, const char *certfile,
const char *peer_pubkeyfile, const char *peer_certfile,
const char *id, size_t idlen, const char *peer_id, size_t peer_idlen,
const char *infile, const char *exch_keyoutfile, const char *exch_pass,
const char *secret_stateoutfile, const char *outfile, size_t keylen,
int format, const char *prog)
{
SM2_KEY key;
SM2_KEY peer_public_key;
SM2_KEY exch_key;
uint8_t ra[65];
uint8_t rb[65];
uint8_t secret_state[65];
uint8_t shared_key[SM2EXCH_MAX_SHARED_KEY_SIZE];
uint8_t sb[32];
uint8_t rb_sb[97];
int ret = -1;
if (!secret_stateoutfile) {
fprintf(stderr, "gmssl %s: '-secret_state_out' option required\n", prog);
return -1;
}
if (sm2exch_load_local_keys(&key, keyfile, pass, pubkeyfile, certfile, prog) != 1
|| sm2exch_load_public_key(&peer_public_key, peer_pubkeyfile, peer_certfile, prog, "peer") != 1
|| sm2exch_read_point(infile, ra, format) != 1
|| sm2_key_generate(&exch_key) != 1
|| sm2_z256_point_to_uncompressed_octets(&exch_key.public_key, rb) != 1) {
fprintf(stderr, "gmssl %s: respond stage input failure\n", prog);
goto end;
}
if (sm2_key_exchange(0, &key, id, idlen, &peer_public_key, peer_id, peer_idlen,
&exch_key, ra, secret_state, keylen, shared_key) != 1
|| sm2_key_exchange_compute_confirm(0, &key, id, idlen,
&peer_public_key, peer_id, peer_idlen,
&exch_key, ra, secret_state, sb) != 1
|| sm2exch_save_exch_key(&exch_key, exch_keyoutfile, exch_pass, ra, prog) != 1
|| sm2exch_write_data(secret_stateoutfile, secret_state, sizeof(secret_state), format) != 1) {
fprintf(stderr, "gmssl %s: respond stage failure\n", prog);
goto end;
}
memcpy(rb_sb, rb, sizeof(rb));
memcpy(rb_sb + sizeof(rb), sb, sizeof(sb));
if (sm2exch_write_data(outfile, rb_sb, sizeof(rb_sb), format) != 1) {
fprintf(stderr, "gmssl %s: output RB||SB failed : %s\n", prog, strerror(errno));
goto end;
}
ret = 0;
end:
gmssl_secure_clear(&key, sizeof(key));
gmssl_secure_clear(&peer_public_key, sizeof(peer_public_key));
gmssl_secure_clear(&exch_key, sizeof(exch_key));
gmssl_secure_clear(secret_state, sizeof(secret_state));
gmssl_secure_clear(shared_key, sizeof(shared_key));
gmssl_secure_clear(sb, sizeof(sb));
return ret;
}
static int sm2exch_stage_confirm(const char *keyfile, const char *pass,
const char *pubkeyfile, const char *certfile,
const char *peer_pubkeyfile, const char *peer_certfile,
const char *id, size_t idlen, const char *peer_id, size_t peer_idlen,
const char *exch_keyfile, const char *exch_pass, const char *infile,
const char *secret_stateoutfile, const char *keyoutfile, const char *outfile,
size_t keylen, int format, const char *prog)
{
SM2_KEY key;
SM2_KEY peer_public_key;
SM2_KEY exch_key;
uint8_t rb_sb[97];
uint8_t secret_state[65];
uint8_t shared_key[SM2EXCH_MAX_SHARED_KEY_SIZE];
uint8_t sa[32];
int vr;
int ret = -1;
if (!keyoutfile) {
fprintf(stderr, "gmssl %s: '-keyout' option required\n", prog);
return -1;
}
if (sm2exch_load_local_keys(&key, keyfile, pass, pubkeyfile, certfile, prog) != 1
|| sm2exch_load_public_key(&peer_public_key, peer_pubkeyfile, peer_certfile, prog, "peer") != 1
|| sm2exch_load_exch_key(&exch_key, NULL, exch_keyfile, exch_pass, prog) != 1
|| sm2exch_read_data(infile, rb_sb, sizeof(rb_sb), format) != 1) {
fprintf(stderr, "gmssl %s: confirm stage input failure\n", prog);
goto end;
}
if (sm2_key_exchange(1, &key, id, idlen, &peer_public_key, peer_id, peer_idlen,
&exch_key, rb_sb, secret_state, keylen, shared_key) != 1) {
fprintf(stderr, "gmssl %s: key exchange failure\n", prog);
goto end;
}
if ((vr = sm2_key_exchange_verify_confirm(1, &key, id, idlen,
&peer_public_key, peer_id, peer_idlen, &exch_key,
rb_sb, secret_state, rb_sb + SM2EXCH_RB_SIZE)) != 1) {
fprintf(stderr, "gmssl %s: SB verification %s\n", prog, vr < 0 ? "failure" : "failed");
goto end;
}
if (sm2_key_exchange_compute_confirm(1, &key, id, idlen,
&peer_public_key, peer_id, peer_idlen, &exch_key,
rb_sb, secret_state, sa) != 1
|| sm2exch_write_data(keyoutfile, shared_key, keylen, format) != 1
|| sm2exch_write_data(outfile, sa, sizeof(sa), format) != 1) {
fprintf(stderr, "gmssl %s: confirm stage failure\n", prog);
goto end;
}
if (secret_stateoutfile
&& sm2exch_write_data(secret_stateoutfile, secret_state, sizeof(secret_state), format) != 1) {
fprintf(stderr, "gmssl %s: output secret_state failed : %s\n", prog, strerror(errno));
goto end;
}
ret = 0;
end:
gmssl_secure_clear(&key, sizeof(key));
gmssl_secure_clear(&peer_public_key, sizeof(peer_public_key));
gmssl_secure_clear(&exch_key, sizeof(exch_key));
gmssl_secure_clear(secret_state, sizeof(secret_state));
gmssl_secure_clear(shared_key, sizeof(shared_key));
gmssl_secure_clear(sa, sizeof(sa));
return ret;
}
static int sm2exch_stage_finish(const char *keyfile, const char *pass,
const char *pubkeyfile, const char *certfile,
const char *peer_pubkeyfile, const char *peer_certfile,
const char *id, size_t idlen, const char *peer_id, size_t peer_idlen,
const char *exch_keyfile, const char *exch_pass, const char *secret_statefile,
const char *infile, const char *keyoutfile, size_t keylen, int format,
const char *prog)
{
SM2_KEY key;
SM2_KEY peer_public_key;
SM2_KEY exch_key;
uint8_t ra[65];
uint8_t secret_state[65];
uint8_t sa[32];
uint8_t shared_key[SM2EXCH_MAX_SHARED_KEY_SIZE];
int vr;
int ret = -1;
if (!secret_statefile) {
fprintf(stderr, "gmssl %s: '-secret_state' option required\n", prog);
return -1;
}
if (!keyoutfile) {
fprintf(stderr, "gmssl %s: '-keyout' option required\n", prog);
return -1;
}
if (sm2exch_load_local_keys(&key, keyfile, pass, pubkeyfile, certfile, prog) != 1
|| sm2exch_load_public_key(&peer_public_key, peer_pubkeyfile, peer_certfile, prog, "peer") != 1
|| sm2exch_load_exch_key(&exch_key, ra, exch_keyfile, exch_pass, prog) != 1
|| sm2exch_read_point(secret_statefile, secret_state, format) != 1
|| sm2exch_read_data(infile, sa, sizeof(sa), format) != 1) {
fprintf(stderr, "gmssl %s: finish stage input failure\n", prog);
goto end;
}
if ((vr = sm2_key_exchange_verify_confirm(0, &key, id, idlen,
&peer_public_key, peer_id, peer_idlen, &exch_key,
ra, secret_state, sa)) != 1) {
fprintf(stderr, "gmssl %s: SA verification %s\n", prog, vr < 0 ? "failure" : "failed");
goto end;
}
if (sm2exch_derive_key_from_secret_state(0, &key, id, idlen,
&peer_public_key, peer_id, peer_idlen,
secret_state, shared_key, keylen) != 1
|| sm2exch_write_data(keyoutfile, shared_key, keylen, format) != 1) {
fprintf(stderr, "gmssl %s: finish stage failure\n", prog);
goto end;
}
ret = 0;
end:
gmssl_secure_clear(&key, sizeof(key));
gmssl_secure_clear(&peer_public_key, sizeof(peer_public_key));
gmssl_secure_clear(&exch_key, sizeof(exch_key));
gmssl_secure_clear(secret_state, sizeof(secret_state));
gmssl_secure_clear(shared_key, sizeof(shared_key));
return ret;
}
int sm2exch_main(int argc, char **argv)
{
int ret = 1;
char *prog = argv[0];
char *stage = NULL;
char *certfile = NULL;
char *pubkeyfile = NULL;
char *keyfile = NULL;
char *pass = NULL;
char *peer_certfile = NULL;
char *peer_pubkeyfile = NULL;
char *id = NULL;
char *peer_id = NULL;
char *id_hex = NULL;
char *peer_id_hex = NULL;
char id_buf[SM2_MAX_ID_LENGTH];
size_t id_len = 0;
char peer_id_buf[SM2_MAX_ID_LENGTH];
size_t peer_id_len = 0;
char *infile = NULL;
char *outfile = NULL;
char *exch_keyfile = NULL;
char *exch_keyoutfile = NULL;
char *exch_pass = NULL;
char *secret_statefile = NULL;
char *secret_stateoutfile = NULL;
char *keyoutfile = NULL;
size_t keylen = 32;
int format = SM2EXCH_FMT_HEX;
argc--;
argv++;
if (argc < 1) {
fprintf(stderr, "usage: gmssl %s %s\n", prog, usage);
return 1;
}
while (argc > 0) {
if (!strcmp(*argv, "-help")) {
printf("usage: gmssl %s %s\n", prog, usage);
printf("%s\n", options);
return 0;
} else if (!strcmp(*argv, "-stage")) {
if (--argc < 1) goto bad;
stage = *(++argv);
} else if (!strcmp(*argv, "-cert")) {
if (pubkeyfile) {
fprintf(stderr, "gmssl %s: options '-cert' and '-pubkey' conflict\n", prog);
goto end;
}
if (--argc < 1) goto bad;
certfile = *(++argv);
} else if (!strcmp(*argv, "-pubkey")) {
if (certfile) {
fprintf(stderr, "gmssl %s: options '-cert' and '-pubkey' conflict\n", prog);
goto end;
}
if (--argc < 1) goto bad;
pubkeyfile = *(++argv);
} else if (!strcmp(*argv, "-key")) {
if (--argc < 1) goto bad;
keyfile = *(++argv);
} else if (!strcmp(*argv, "-pass")) {
if (--argc < 1) goto bad;
pass = *(++argv);
} else if (!strcmp(*argv, "-peer_cert")) {
if (peer_pubkeyfile) {
fprintf(stderr, "gmssl %s: options '-peer_cert' and '-peer_pubkey' conflict\n", prog);
goto end;
}
if (--argc < 1) goto bad;
peer_certfile = *(++argv);
} else if (!strcmp(*argv, "-peer_pubkey")) {
if (peer_certfile) {
fprintf(stderr, "gmssl %s: options '-peer_cert' and '-peer_pubkey' conflict\n", prog);
goto end;
}
if (--argc < 1) goto bad;
peer_pubkeyfile = *(++argv);
} else if (!strcmp(*argv, "-id")) {
if (id_hex) {
fprintf(stderr, "gmssl %s: '-id' and '-id_hex' should not be used together\n", prog);
goto end;
}
if (--argc < 1) goto bad;
id = *(++argv);
id_len = strlen(id);
} else if (!strcmp(*argv, "-id_hex")) {
if (id) {
fprintf(stderr, "gmssl %s: '-id' and '-id_hex' should not be used together\n", prog);
goto end;
}
if (--argc < 1) goto bad;
id_hex = *(++argv);
if (strlen(id_hex) > sizeof(id_buf) * 2
|| hex_to_bytes(id_hex, strlen(id_hex), (uint8_t *)id_buf, &id_len) != 1) {
fprintf(stderr, "gmssl %s: invalid '-id_hex' value\n", prog);
goto end;
}
id = id_buf;
} else if (!strcmp(*argv, "-peer_id")) {
if (peer_id_hex) {
fprintf(stderr, "gmssl %s: '-peer_id' and '-peer_id_hex' should not be used together\n", prog);
goto end;
}
if (--argc < 1) goto bad;
peer_id = *(++argv);
peer_id_len = strlen(peer_id);
} else if (!strcmp(*argv, "-peer_id_hex")) {
if (peer_id) {
fprintf(stderr, "gmssl %s: '-peer_id' and '-peer_id_hex' should not be used together\n", prog);
goto end;
}
if (--argc < 1) goto bad;
peer_id_hex = *(++argv);
if (strlen(peer_id_hex) > sizeof(peer_id_buf) * 2
|| hex_to_bytes(peer_id_hex, strlen(peer_id_hex), (uint8_t *)peer_id_buf, &peer_id_len) != 1) {
fprintf(stderr, "gmssl %s: invalid '-peer_id_hex' value\n", prog);
goto end;
}
peer_id = peer_id_buf;
} else if (!strcmp(*argv, "-in")) {
if (--argc < 1) goto bad;
infile = *(++argv);
} else if (!strcmp(*argv, "-out")) {
if (--argc < 1) goto bad;
outfile = *(++argv);
} else if (!strcmp(*argv, "-exch_keyout")) {
if (--argc < 1) goto bad;
exch_keyoutfile = *(++argv);
} else if (!strcmp(*argv, "-exch_key")) {
if (--argc < 1) goto bad;
exch_keyfile = *(++argv);
} else if (!strcmp(*argv, "-exch_pass")) {
if (--argc < 1) goto bad;
exch_pass = *(++argv);
} else if (!strcmp(*argv, "-secret_state_out")) {
if (--argc < 1) goto bad;
secret_stateoutfile = *(++argv);
} else if (!strcmp(*argv, "-secret_state")) {
if (--argc < 1) goto bad;
secret_statefile = *(++argv);
} else if (!strcmp(*argv, "-keylen")) {
if (--argc < 1) goto bad;
keylen = (size_t)atoi(*(++argv));
if (keylen < 1 || keylen > SM2EXCH_MAX_SHARED_KEY_SIZE) {
fprintf(stderr, "gmssl %s: invalid '-keylen' value\n", prog);
goto end;
}
} else if (!strcmp(*argv, "-keyout")) {
if (--argc < 1) goto bad;
keyoutfile = *(++argv);
} else if (!strcmp(*argv, "-hex")) {
format = SM2EXCH_FMT_HEX;
} else if (!strcmp(*argv, "-bin")) {
format = SM2EXCH_FMT_BIN;
} else {
fprintf(stderr, "gmssl %s: illegal option '%s'\n", prog, *argv);
goto end;
bad:
fprintf(stderr, "gmssl %s: '%s' option value missing\n", prog, *argv);
goto end;
}
argc--;
argv++;
}
if (!stage) {
fprintf(stderr, "gmssl %s: '-stage' option required\n", prog);
goto end;
}
if (!id) {
id = SM2_DEFAULT_ID;
id_len = SM2_DEFAULT_ID_LENGTH;
}
if (!peer_id) {
peer_id = SM2_DEFAULT_ID;
peer_id_len = SM2_DEFAULT_ID_LENGTH;
}
if (!strcmp(stage, "init")) {
ret = sm2exch_stage_init(exch_keyoutfile, exch_pass, outfile, format, prog);
} else if (!strcmp(stage, "respond")) {
ret = sm2exch_stage_respond(keyfile, pass, pubkeyfile, certfile,
peer_pubkeyfile, peer_certfile, id, id_len, peer_id, peer_id_len,
infile, exch_keyoutfile, exch_pass, secret_stateoutfile,
outfile, keylen, format, prog);
} else if (!strcmp(stage, "confirm")) {
ret = sm2exch_stage_confirm(keyfile, pass, pubkeyfile, certfile,
peer_pubkeyfile, peer_certfile, id, id_len, peer_id, peer_id_len,
exch_keyfile, exch_pass, infile, secret_stateoutfile,
keyoutfile, outfile, keylen, format, prog);
} else if (!strcmp(stage, "finish")) {
ret = sm2exch_stage_finish(keyfile, pass, pubkeyfile, certfile,
peer_pubkeyfile, peer_certfile, id, id_len, peer_id, peer_id_len,
exch_keyfile, exch_pass, secret_statefile, infile,
keyoutfile, keylen, format, prog);
} else {
fprintf(stderr, "gmssl %s: invalid '-stage' value\n", prog);
goto end;
}
end:
return ret == 0 ? 0 : 1;
}

View File

@@ -27,8 +27,6 @@ enum {
SM4_MODE_XTS,
SM4_MODE_CCM,
SM4_MODE_GCM,
SM4_MODE_CBC_SM3_HMAC,
SM4_MODE_CTR_SM3_HMAC,
};
static uint8_t *read_content(FILE *infp, size_t *outlen, const char *prog)
@@ -188,8 +186,6 @@ static const char *options =
" -ctr CTR mode, need 16-byte key and 16-byte iv\n"
" -ccm CCM mode, need 16-byte key and any iv length\n"
" -gcm GCM mode, need 16-byte key and any iv length\n"
" -cbc_sm3_hmac CBC mode with padding and HMAC-SM3 (encrypt-then-mac), need 48-byte key and 16-byte iv\n"
" -ctr_sm3_hmac CTR mode with HMAC-SM3 (entrypt-then-mac), need 48-byte key and 16-byte iv\n"
" -xts XTS mode\n"
"\n"
" -encrypt Encrypt\n"
@@ -205,13 +201,6 @@ static const char *options =
"\n"
" echo \"hello\" | gmssl sm4 -gcm -encrypt -key 11223344556677881122334455667788 -iv 112233445566778811223344 -out ciphertext.bin\n"
" gmssl sm4 -gcm -decrypt -key 11223344556677881122334455667788 -iv 112233445566778811223344 -in ciphertext.bin\n"
"\n"
" echo \"hello\" | gmssl sm4 -cbc_sm3_hmac -encrypt \\\n"
" -key 112233445566778811223344556677881122334455667788112233445566778811223344556677881122334455667788 \\\n"
" -iv 11223344556677881122334455667788 -out ciphertext.bin\n"
" gmssl sm4 -cbc_sm3_hmac -decrypt \\\n"
" -key 112233445566778811223344556677881122334455667788112233445566778811223344556677881122334455667788 \\\n"
" -iv 11223344556677881122334455667788 -in ciphertext.bin\n"
"\n";
int sm4_main(int argc, char **argv)
@@ -322,12 +311,6 @@ int sm4_main(int argc, char **argv)
} else if (!strcmp(*argv, "-ctr")) {
if (mode) goto bad;
mode = SM4_MODE_CTR;
} else if (!strcmp(*argv, "-cbc_sm3_hmac")) {
if (mode) goto bad;
mode = SM4_MODE_CBC_SM3_HMAC;
} else if (!strcmp(*argv, "-ctr_sm3_hmac")) {
if (mode) goto bad;
mode = SM4_MODE_CTR_SM3_HMAC;
} else if (!strcmp(*argv, "-gcm")) {
if (mode) goto bad;
mode = SM4_MODE_GCM;
@@ -449,9 +432,6 @@ bad:
#ifdef ENABLE_SM4_XTS
case SM4_MODE_XTS:
#endif
case SM4_MODE_CBC_SM3_HMAC:
case SM4_MODE_CTR_SM3_HMAC:
break;
default:
fprintf(stderr, "%s: mode is not supported\n", prog);
goto end;
@@ -477,13 +457,6 @@ bad:
goto end;
}
break;
case SM4_MODE_CBC_SM3_HMAC:
case SM4_MODE_CTR_SM3_HMAC:
if (keylen != 48) {
fprintf(stderr, "%s: invalid key length, should be 96 hex digits\n", prog);
goto end;
}
break;
}
// check iv length
@@ -498,8 +471,6 @@ bad:
case SM4_MODE_CFB:
case SM4_MODE_OFB:
case SM4_MODE_CTR:
case SM4_MODE_CBC_SM3_HMAC:
case SM4_MODE_CTR_SM3_HMAC:
if (ivlen != 16) {
fprintf(stderr, "%s: invalid IV length, should be 32 hex digits\n", prog);
goto end;
@@ -613,7 +584,6 @@ bad:
goto end;
}
}
switch (mode) {
#ifdef ENABLE_SM4_ECB
case SM4_MODE_ECB: rv = sm4_ecb_encrypt_finish(&sm4_ctx.ecb, outbuf, &outlen); break;
@@ -688,7 +658,6 @@ bad:
goto end;
}
}
switch (mode) {
#ifdef ENABLE_SM4_ECB
case SM4_MODE_ECB: rv = sm4_ecb_decrypt_finish(&sm4_ctx.ecb, outbuf, &outlen); break;

771
tools/sm9exch.c Normal file
View File

@@ -0,0 +1,771 @@
/*
* Copyright 2014-2026 The GmSSL Project. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the License); you may
* not use this file except in compliance with the License.
*
* http://www.apache.org/licenses/LICENSE-2.0
*/
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>
#include <stdint.h>
#include <gmssl/mem.h>
#include <gmssl/hex.h>
#include <gmssl/pem.h>
#include <gmssl/sm9.h>
#define SM9EXCH_R_SIZE 32
#define SM9EXCH_RA_SIZE 65
#define SM9EXCH_RB_SIZE 65
#define SM9EXCH_CONFIRM_SIZE 32
#define SM9EXCH_RB_SB_SIZE (SM9EXCH_RB_SIZE + SM9EXCH_CONFIRM_SIZE)
#define SM9EXCH_EXCH_KEY_SIZE (SM9EXCH_R_SIZE + SM9EXCH_RB_SIZE)
#define SM9EXCH_EXCH_KEY_WITH_PEER_R_SIZE (SM9EXCH_EXCH_KEY_SIZE + SM9EXCH_RA_SIZE)
#define SM9EXCH_MAX_SHARED_KEY_SIZE 1024
#define PEM_SM9_EXCH_KEY "SM9 EXCHANGE PRIVATE KEY"
enum {
SM9EXCH_FMT_BIN = 0,
SM9EXCH_FMT_HEX = 1,
};
static const char *usage =
"-stage init|respond|confirm|finish [options]";
static const char *options =
"\n"
"Options\n"
"\n"
" -stage init|respond|confirm|finish\n"
" SM9 key exchange stage\n"
" -pubmaster pem SM9 exchange master public key in PEM format\n"
" -key pem Local SM9 exchange private key in PEM format\n"
" -pass str Password to open local private key\n"
" -id str Local SM9 identity\n"
" -id_hex hex Local SM9 identity in hex\n"
" -peer_id str Peer SM9 identity\n"
" -peer_id_hex hex Peer SM9 identity in hex\n"
" -in file | stdin Input data for this stage\n"
" respond: RA, 65 bytes\n"
" confirm: RB || SB, 97 bytes\n"
" finish: SA, 32 bytes\n"
" -out file | stdout Output data to send to peer\n"
" init: RA, 65 bytes\n"
" respond: RB || SB, 97 bytes\n"
" confirm: SA, 32 bytes\n"
" -exch_keyout pem Output local ephemeral exchange state r||R in PEM format\n"
" -exch_key pem Input local ephemeral exchange state r||R in PEM format\n"
" -keylen num Shared key length in bytes, 32 by default\n"
" -keyout file Output shared key\n"
" -hex Encode input/output data in hex, default\n"
" -bin Encode input/output data in binary\n"
"\n"
"Examples\n"
"\n"
" gmssl sm9setup -alg sm9encrypt -pass P@ssw0rd \\\n"
" -out sm9_msk.pem -pubout sm9_mpk.pem\n"
" gmssl sm9keygen -alg sm9keyagreement -in sm9_msk.pem -inpass P@ssw0rd \\\n"
" -id Alice -out alice.pem -outpass 123456\n"
" gmssl sm9keygen -alg sm9keyagreement -in sm9_msk.pem -inpass P@ssw0rd \\\n"
" -id Bob -out bob.pem -outpass 123456\n"
" gmssl sm9exch -stage init \\\n"
" -pubmaster sm9_mpk.pem -peer_id Bob \\\n"
" -exch_keyout alice_ra.pem -out ra.hex\n"
" gmssl sm9exch -stage respond \\\n"
" -pubmaster sm9_mpk.pem -key bob.pem -pass 123456 -id Bob \\\n"
" -peer_id Alice -in ra.hex \\\n"
" -exch_keyout bob_rb.pem -out rb_sb.hex\n"
" gmssl sm9exch -stage confirm \\\n"
" -pubmaster sm9_mpk.pem -key alice.pem -pass 123456 -id Alice \\\n"
" -peer_id Bob -exch_key alice_ra.pem -in rb_sb.hex \\\n"
" -keylen 48 -keyout alice_shared_key.hex -out sa.hex\n"
" gmssl sm9exch -stage finish \\\n"
" -pubmaster sm9_mpk.pem -key bob.pem -pass 123456 -id Bob \\\n"
" -peer_id Alice -exch_key bob_rb.pem \\\n"
" -in sa.hex -keylen 48 -keyout bob_shared_key.hex\n"
"\n"
"Notes\n"
"\n"
" RA and RB are fixed 65-byte uncompressed SM9 curve points.\n"
" The respond output is RB || SB, fixed 97 bytes.\n"
" The ephemeral exchange state contains secret scalar r, public point R and optional peer point.\n"
" -hex and -bin affect RA, RB||SB, SA and shared key files.\n"
"\n";
static int read_file(const char *file, uint8_t *buf, size_t *len, size_t maxlen)
{
FILE *fp = stdin;
size_t n;
if (!buf || !len) {
return -1;
}
if (file && !(fp = fopen(file, "rb"))) {
return -1;
}
n = fread(buf, 1, maxlen + 1, fp);
if (ferror(fp)) {
if (file) fclose(fp);
return -1;
}
if (file) fclose(fp);
if (n > maxlen) {
return -1;
}
*len = n;
return 1;
}
static int write_file(const char *file, const uint8_t *buf, size_t len)
{
FILE *fp = stdout;
int ret = -1;
if (!buf || !len) {
return -1;
}
if (file && !(fp = fopen(file, "wb"))) {
return -1;
}
if (fwrite(buf, 1, len, fp) == len) {
ret = 1;
}
if (file) fclose(fp);
return ret;
}
static int sm9exch_read_exact(const char *file, uint8_t *buf, size_t len);
static int sm9exch_write_data(const char *file, const uint8_t *buf, size_t len, int format)
{
uint8_t *hexbuf = NULL;
size_t i;
int ret;
if (format == SM9EXCH_FMT_BIN) {
return write_file(file, buf, len);
}
if (!(hexbuf = malloc(len * 2))) {
return -1;
}
for (i = 0; i < len; i++) {
static const char *hex = "0123456789abcdef";
hexbuf[i * 2] = (uint8_t)hex[buf[i] >> 4];
hexbuf[i * 2 + 1] = (uint8_t)hex[buf[i] & 0x0f];
}
ret = write_file(file, hexbuf, len * 2);
gmssl_secure_clear(hexbuf, len * 2);
free(hexbuf);
return ret;
}
static int sm9exch_read_data(const char *file, uint8_t *buf, size_t len, int format)
{
uint8_t *in = NULL;
uint8_t *hex = NULL;
size_t inlen;
size_t hexlen = 0;
size_t outlen;
size_t i;
int ret = -1;
if (format == SM9EXCH_FMT_BIN) {
return sm9exch_read_exact(file, buf, len);
}
if (!(in = malloc(len * 2 + 64)) || !(hex = malloc(len * 2))) {
goto end;
}
if (read_file(file, in, &inlen, len * 2 + 63) != 1) {
goto end;
}
for (i = 0; i < inlen; i++) {
if (in[i] == ' ' || in[i] == '\t' || in[i] == '\r' || in[i] == '\n') {
continue;
}
if (hexlen >= len * 2) {
goto end;
}
hex[hexlen++] = in[i];
}
if (hexlen != len * 2
|| hex_to_bytes((char *)hex, hexlen, buf, &outlen) != 1
|| outlen != len) {
goto end;
}
ret = 1;
end:
if (in) {
gmssl_secure_clear(in, len * 2 + 64);
free(in);
}
if (hex) {
gmssl_secure_clear(hex, len * 2);
free(hex);
}
return ret;
}
static int sm9exch_read_exact(const char *file, uint8_t *buf, size_t len)
{
size_t inlen;
if (read_file(file, buf, &inlen, len) != 1 || inlen != len) {
return -1;
}
return 1;
}
static int sm9exch_read_point_file(const char *file, SM9_Z256_POINT *point, int format)
{
uint8_t buf[65];
if (sm9exch_read_data(file, buf, sizeof(buf), format) != 1
|| sm9_z256_point_from_uncompressed_octets(point, buf) != 1
|| !sm9_z256_point_is_on_curve(point)) {
return -1;
}
return 1;
}
static int sm9exch_load_master_public_key(SM9_EXCH_MASTER_KEY *mpk,
const char *mpkfile, const char *prog)
{
FILE *fp = NULL;
int ret = -1;
if (!mpkfile) {
fprintf(stderr, "gmssl %s: '-pubmaster' option required\n", prog);
return -1;
}
if (!(fp = fopen(mpkfile, "rb"))) {
fprintf(stderr, "gmssl %s: open master public key failed : %s\n", prog, strerror(errno));
goto end;
}
if (sm9_enc_master_public_key_from_pem(mpk, fp) != 1) {
fprintf(stderr, "gmssl %s: parse master public key failed\n", prog);
goto end;
}
ret = 1;
end:
if (fp) fclose(fp);
return ret;
}
static int sm9exch_load_private_key(SM9_EXCH_KEY *key, const char *keyfile,
const char *pass, const SM9_EXCH_MASTER_KEY *mpk, const char *prog)
{
FILE *fp = NULL;
int ret = -1;
if (!keyfile) {
fprintf(stderr, "gmssl %s: '-key' option required\n", prog);
return -1;
}
if (!pass) {
fprintf(stderr, "gmssl %s: '-pass' option required\n", prog);
return -1;
}
if (!(fp = fopen(keyfile, "rb"))) {
fprintf(stderr, "gmssl %s: open private key failed : %s\n", prog, strerror(errno));
goto end;
}
if (sm9_enc_key_info_decrypt_from_pem(key, pass, fp) != 1) {
fprintf(stderr, "gmssl %s: parse private key failed\n", prog);
goto end;
}
if (mpk && sm9_z256_point_equ(&key->Ppube, &mpk->Ppube) != 1) {
fprintf(stderr, "gmssl %s: private key does not match master public key\n", prog);
goto end;
}
ret = 1;
end:
if (fp) fclose(fp);
return ret;
}
static int sm9exch_generate_R(const SM9_EXCH_MASTER_KEY *mpk,
const char *peer_id, size_t peer_idlen, sm9_z256_t r, SM9_Z256_POINT *R)
{
if (!mpk || !peer_id || !peer_idlen || !r || !R) {
return -1;
}
if (peer_idlen > SM9_MAX_ID_SIZE) {
return -1;
}
sm9_z256_hash1(r, peer_id, peer_idlen, SM9_HID_EXCH);
sm9_z256_point_mul(R, r, sm9_z256_generator());
sm9_z256_point_add(R, R, &mpk->Ppube);
do {
if (sm9_z256_rand_range(r, sm9_z256_order()) != 1) {
return -1;
}
} while (sm9_z256_is_zero(r));
sm9_z256_point_mul(R, r, R);
return 1;
}
static int sm9exch_save_exch_key(const sm9_z256_t r, const SM9_Z256_POINT *R,
const SM9_Z256_POINT *peer_R, const char *keyfile, const char *prog)
{
FILE *fp = NULL;
uint8_t buf[SM9EXCH_EXCH_KEY_WITH_PEER_R_SIZE];
size_t len = SM9EXCH_EXCH_KEY_SIZE;
int ret = -1;
if (!keyfile) {
fprintf(stderr, "gmssl %s: '-exch_keyout' option required\n", prog);
return -1;
}
sm9_z256_to_bytes(r, buf);
if (sm9_z256_point_to_uncompressed_octets(R, buf + SM9EXCH_R_SIZE) != 1) {
goto end;
}
if (peer_R) {
if (sm9_z256_point_to_uncompressed_octets(peer_R, buf + SM9EXCH_EXCH_KEY_SIZE) != 1) {
goto end;
}
len = SM9EXCH_EXCH_KEY_WITH_PEER_R_SIZE;
}
if (!(fp = fopen(keyfile, "wb"))) {
fprintf(stderr, "gmssl %s: open output exchange key failed : %s\n", prog, strerror(errno));
goto end;
}
if (pem_write(fp, PEM_SM9_EXCH_KEY, buf, len) != 1) {
fprintf(stderr, "gmssl %s: output exchange key failed\n", prog);
goto end;
}
ret = 1;
end:
gmssl_secure_clear(buf, sizeof(buf));
if (fp) fclose(fp);
return ret;
}
static int sm9exch_load_exch_key(sm9_z256_t r, SM9_Z256_POINT *R,
SM9_Z256_POINT *peer_R, const char *keyfile, const char *prog)
{
FILE *fp = NULL;
uint8_t buf[SM9EXCH_EXCH_KEY_WITH_PEER_R_SIZE];
size_t len;
int ret = -1;
if (!keyfile) {
fprintf(stderr, "gmssl %s: '-exch_key' option required\n", prog);
return -1;
}
if (!(fp = fopen(keyfile, "rb"))) {
fprintf(stderr, "gmssl %s: open exchange key failed : %s\n", prog, strerror(errno));
goto end;
}
if (pem_read(fp, PEM_SM9_EXCH_KEY, buf, &len, sizeof(buf)) != 1
|| (len != SM9EXCH_EXCH_KEY_SIZE && len != SM9EXCH_EXCH_KEY_WITH_PEER_R_SIZE)) {
fprintf(stderr, "gmssl %s: parse exchange key failed\n", prog);
goto end;
}
sm9_z256_from_bytes(r, buf);
if (sm9_z256_is_zero(r)
|| sm9_z256_point_from_uncompressed_octets(R, buf + SM9EXCH_R_SIZE) != 1
|| !sm9_z256_point_is_on_curve(R)) {
fprintf(stderr, "gmssl %s: invalid exchange key\n", prog);
goto end;
}
if (peer_R) {
if (len != SM9EXCH_EXCH_KEY_WITH_PEER_R_SIZE
|| sm9_z256_point_from_uncompressed_octets(peer_R, buf + SM9EXCH_EXCH_KEY_SIZE) != 1
|| !sm9_z256_point_is_on_curve(peer_R)) {
fprintf(stderr, "gmssl %s: peer exchange point not found in exchange key\n", prog);
goto end;
}
}
ret = 1;
end:
gmssl_secure_clear(buf, sizeof(buf));
if (fp) fclose(fp);
return ret;
}
static int sm9exch_stage_init(const char *mpkfile, const char *peer_id,
size_t peer_idlen, const char *exch_keyoutfile, const char *outfile,
int format, const char *prog)
{
SM9_EXCH_MASTER_KEY mpk;
SM9_Z256_POINT R;
sm9_z256_t r;
uint8_t ra[65];
int ret = -1;
if (!peer_id) {
fprintf(stderr, "gmssl %s: '-peer_id' option required\n", prog);
return -1;
}
if (sm9exch_load_master_public_key(&mpk, mpkfile, prog) != 1
|| sm9exch_generate_R(&mpk, peer_id, peer_idlen, r, &R) != 1
|| sm9_z256_point_to_uncompressed_octets(&R, ra) != 1
|| sm9exch_save_exch_key(r, &R, NULL, exch_keyoutfile, prog) != 1
|| sm9exch_write_data(outfile, ra, sizeof(ra), format) != 1) {
fprintf(stderr, "gmssl %s: init stage failure\n", prog);
goto end;
}
ret = 0;
end:
gmssl_secure_clear(&mpk, sizeof(mpk));
gmssl_secure_clear(&R, sizeof(R));
gmssl_secure_clear(r, sizeof(r));
return ret;
}
static int sm9exch_stage_respond(const char *mpkfile, const char *keyfile,
const char *pass, const char *id, size_t idlen,
const char *peer_id, size_t peer_idlen, const char *infile,
const char *exch_keyoutfile, const char *outfile, size_t keylen,
int format, const char *prog)
{
SM9_EXCH_MASTER_KEY mpk;
SM9_EXCH_KEY key;
SM9_Z256_POINT ra;
SM9_Z256_POINT rb;
sm9_z256_t r;
uint8_t rb_octets[65];
uint8_t shared_key[SM9EXCH_MAX_SHARED_KEY_SIZE];
uint8_t sb[32];
uint8_t rb_sb[97];
int ret = -1;
if (!id) {
fprintf(stderr, "gmssl %s: '-id' option required\n", prog);
return -1;
}
if (!peer_id) {
fprintf(stderr, "gmssl %s: '-peer_id' option required\n", prog);
return -1;
}
if (sm9exch_load_master_public_key(&mpk, mpkfile, prog) != 1
|| sm9exch_load_private_key(&key, keyfile, pass, &mpk, prog) != 1
|| sm9exch_read_point_file(infile, &ra, format) != 1
|| sm9exch_generate_R(&mpk, peer_id, peer_idlen, r, &rb) != 1
|| sm9_z256_point_to_uncompressed_octets(&rb, rb_octets) != 1) {
fprintf(stderr, "gmssl %s: respond stage input failure\n", prog);
goto end;
}
if (sm9_key_exchange(0, &mpk, &key, id, idlen, peer_id, peer_idlen,
r, &rb, &ra, keylen, shared_key) != 1
|| sm9_key_exchange_compute_confirm(0, &mpk, &key, id, idlen,
peer_id, peer_idlen, r, &rb, &ra, sb) != 1
|| sm9exch_save_exch_key(r, &rb, &ra, exch_keyoutfile, prog) != 1) {
fprintf(stderr, "gmssl %s: respond stage failure\n", prog);
goto end;
}
memcpy(rb_sb, rb_octets, sizeof(rb_octets));
memcpy(rb_sb + sizeof(rb_octets), sb, sizeof(sb));
if (sm9exch_write_data(outfile, rb_sb, sizeof(rb_sb), format) != 1) {
fprintf(stderr, "gmssl %s: output RB||SB failed : %s\n", prog, strerror(errno));
goto end;
}
ret = 0;
end:
gmssl_secure_clear(&mpk, sizeof(mpk));
gmssl_secure_clear(&key, sizeof(key));
gmssl_secure_clear(&ra, sizeof(ra));
gmssl_secure_clear(&rb, sizeof(rb));
gmssl_secure_clear(r, sizeof(r));
gmssl_secure_clear(shared_key, sizeof(shared_key));
gmssl_secure_clear(sb, sizeof(sb));
return ret;
}
static int sm9exch_stage_confirm(const char *mpkfile, const char *keyfile,
const char *pass, const char *id, size_t idlen,
const char *peer_id, size_t peer_idlen, const char *exch_keyfile,
const char *infile, const char *keyoutfile, const char *outfile,
size_t keylen, int format, const char *prog)
{
SM9_EXCH_MASTER_KEY mpk;
SM9_EXCH_KEY key;
SM9_Z256_POINT ra;
SM9_Z256_POINT rb;
sm9_z256_t r;
uint8_t rb_sb[97];
uint8_t shared_key[SM9EXCH_MAX_SHARED_KEY_SIZE];
uint8_t sa[32];
int vr;
int ret = -1;
if (!id) {
fprintf(stderr, "gmssl %s: '-id' option required\n", prog);
return -1;
}
if (!peer_id) {
fprintf(stderr, "gmssl %s: '-peer_id' option required\n", prog);
return -1;
}
if (!keyoutfile) {
fprintf(stderr, "gmssl %s: '-keyout' option required\n", prog);
return -1;
}
if (sm9exch_load_master_public_key(&mpk, mpkfile, prog) != 1
|| sm9exch_load_private_key(&key, keyfile, pass, &mpk, prog) != 1
|| sm9exch_load_exch_key(r, &ra, NULL, exch_keyfile, prog) != 1
|| sm9exch_read_data(infile, rb_sb, sizeof(rb_sb), format) != 1
|| sm9_z256_point_from_uncompressed_octets(&rb, rb_sb) != 1
|| !sm9_z256_point_is_on_curve(&rb)) {
fprintf(stderr, "gmssl %s: confirm stage input failure\n", prog);
goto end;
}
if (sm9_key_exchange(1, &mpk, &key, id, idlen, peer_id, peer_idlen,
r, &ra, &rb, keylen, shared_key) != 1) {
fprintf(stderr, "gmssl %s: key exchange failure\n", prog);
goto end;
}
if ((vr = sm9_key_exchange_verify_confirm(1, &mpk, &key, id, idlen,
peer_id, peer_idlen, r, &ra, &rb, rb_sb + SM9EXCH_RB_SIZE)) != 1) {
fprintf(stderr, "gmssl %s: SB verification %s\n", prog, vr < 0 ? "failure" : "failed");
goto end;
}
if (sm9_key_exchange_compute_confirm(1, &mpk, &key, id, idlen,
peer_id, peer_idlen, r, &ra, &rb, sa) != 1
|| sm9exch_write_data(keyoutfile, shared_key, keylen, format) != 1
|| sm9exch_write_data(outfile, sa, sizeof(sa), format) != 1) {
fprintf(stderr, "gmssl %s: confirm stage failure\n", prog);
goto end;
}
ret = 0;
end:
gmssl_secure_clear(&mpk, sizeof(mpk));
gmssl_secure_clear(&key, sizeof(key));
gmssl_secure_clear(&ra, sizeof(ra));
gmssl_secure_clear(&rb, sizeof(rb));
gmssl_secure_clear(r, sizeof(r));
gmssl_secure_clear(shared_key, sizeof(shared_key));
gmssl_secure_clear(sa, sizeof(sa));
return ret;
}
static int sm9exch_stage_finish(const char *mpkfile, const char *keyfile,
const char *pass, const char *id, size_t idlen,
const char *peer_id, size_t peer_idlen, const char *exch_keyfile,
const char *infile, const char *keyoutfile, size_t keylen, int format,
const char *prog)
{
SM9_EXCH_MASTER_KEY mpk;
SM9_EXCH_KEY key;
SM9_Z256_POINT ra;
SM9_Z256_POINT rb;
sm9_z256_t r;
uint8_t sa[32];
uint8_t shared_key[SM9EXCH_MAX_SHARED_KEY_SIZE];
int vr;
int ret = -1;
if (!id) {
fprintf(stderr, "gmssl %s: '-id' option required\n", prog);
return -1;
}
if (!peer_id) {
fprintf(stderr, "gmssl %s: '-peer_id' option required\n", prog);
return -1;
}
if (!keyoutfile) {
fprintf(stderr, "gmssl %s: '-keyout' option required\n", prog);
return -1;
}
if (sm9exch_load_master_public_key(&mpk, mpkfile, prog) != 1
|| sm9exch_load_private_key(&key, keyfile, pass, &mpk, prog) != 1
|| sm9exch_load_exch_key(r, &rb, &ra, exch_keyfile, prog) != 1
|| sm9exch_read_data(infile, sa, sizeof(sa), format) != 1) {
fprintf(stderr, "gmssl %s: finish stage input failure\n", prog);
goto end;
}
if ((vr = sm9_key_exchange_verify_confirm(0, &mpk, &key, id, idlen,
peer_id, peer_idlen, r, &rb, &ra, sa)) != 1) {
fprintf(stderr, "gmssl %s: SA verification %s\n", prog, vr < 0 ? "failure" : "failed");
goto end;
}
if (sm9_key_exchange(0, &mpk, &key, id, idlen, peer_id, peer_idlen,
r, &rb, &ra, keylen, shared_key) != 1
|| sm9exch_write_data(keyoutfile, shared_key, keylen, format) != 1) {
fprintf(stderr, "gmssl %s: finish stage failure\n", prog);
goto end;
}
ret = 0;
end:
gmssl_secure_clear(&mpk, sizeof(mpk));
gmssl_secure_clear(&key, sizeof(key));
gmssl_secure_clear(&ra, sizeof(ra));
gmssl_secure_clear(&rb, sizeof(rb));
gmssl_secure_clear(r, sizeof(r));
gmssl_secure_clear(shared_key, sizeof(shared_key));
return ret;
}
int sm9exch_main(int argc, char **argv)
{
int ret = 1;
char *prog = argv[0];
char *stage = NULL;
char *mpkfile = NULL;
char *keyfile = NULL;
char *pass = NULL;
char *id = NULL;
char *peer_id = NULL;
char *id_hex = NULL;
char *peer_id_hex = NULL;
char id_buf[SM9_MAX_ID_SIZE];
size_t id_len = 0;
char peer_id_buf[SM9_MAX_ID_SIZE];
size_t peer_id_len = 0;
char *infile = NULL;
char *outfile = NULL;
char *exch_keyfile = NULL;
char *exch_keyoutfile = NULL;
char *keyoutfile = NULL;
size_t keylen = 32;
int format = SM9EXCH_FMT_HEX;
argc--;
argv++;
if (argc < 1) {
fprintf(stderr, "usage: gmssl %s %s\n", prog, usage);
return 1;
}
while (argc > 0) {
if (!strcmp(*argv, "-help")) {
printf("usage: gmssl %s %s\n", prog, usage);
printf("%s\n", options);
return 0;
} else if (!strcmp(*argv, "-stage")) {
if (--argc < 1) goto bad;
stage = *(++argv);
} else if (!strcmp(*argv, "-pubmaster")) {
if (--argc < 1) goto bad;
mpkfile = *(++argv);
} else if (!strcmp(*argv, "-key")) {
if (--argc < 1) goto bad;
keyfile = *(++argv);
} else if (!strcmp(*argv, "-pass")) {
if (--argc < 1) goto bad;
pass = *(++argv);
} else if (!strcmp(*argv, "-id")) {
if (id_hex) {
fprintf(stderr, "gmssl %s: '-id' and '-id_hex' should not be used together\n", prog);
goto end;
}
if (--argc < 1) goto bad;
id = *(++argv);
id_len = strlen(id);
} else if (!strcmp(*argv, "-id_hex")) {
if (id) {
fprintf(stderr, "gmssl %s: '-id' and '-id_hex' should not be used together\n", prog);
goto end;
}
if (--argc < 1) goto bad;
id_hex = *(++argv);
if (strlen(id_hex) > sizeof(id_buf) * 2
|| hex_to_bytes(id_hex, strlen(id_hex), (uint8_t *)id_buf, &id_len) != 1) {
fprintf(stderr, "gmssl %s: invalid '-id_hex' value\n", prog);
goto end;
}
id = id_buf;
} else if (!strcmp(*argv, "-peer_id")) {
if (peer_id_hex) {
fprintf(stderr, "gmssl %s: '-peer_id' and '-peer_id_hex' should not be used together\n", prog);
goto end;
}
if (--argc < 1) goto bad;
peer_id = *(++argv);
peer_id_len = strlen(peer_id);
} else if (!strcmp(*argv, "-peer_id_hex")) {
if (peer_id) {
fprintf(stderr, "gmssl %s: '-peer_id' and '-peer_id_hex' should not be used together\n", prog);
goto end;
}
if (--argc < 1) goto bad;
peer_id_hex = *(++argv);
if (strlen(peer_id_hex) > sizeof(peer_id_buf) * 2
|| hex_to_bytes(peer_id_hex, strlen(peer_id_hex), (uint8_t *)peer_id_buf, &peer_id_len) != 1) {
fprintf(stderr, "gmssl %s: invalid '-peer_id_hex' value\n", prog);
goto end;
}
peer_id = peer_id_buf;
} else if (!strcmp(*argv, "-in")) {
if (--argc < 1) goto bad;
infile = *(++argv);
} else if (!strcmp(*argv, "-out")) {
if (--argc < 1) goto bad;
outfile = *(++argv);
} else if (!strcmp(*argv, "-exch_keyout")) {
if (--argc < 1) goto bad;
exch_keyoutfile = *(++argv);
} else if (!strcmp(*argv, "-exch_key")) {
if (--argc < 1) goto bad;
exch_keyfile = *(++argv);
} else if (!strcmp(*argv, "-keylen")) {
if (--argc < 1) goto bad;
keylen = (size_t)atoi(*(++argv));
if (keylen < 1 || keylen > SM9EXCH_MAX_SHARED_KEY_SIZE) {
fprintf(stderr, "gmssl %s: invalid '-keylen' value\n", prog);
goto end;
}
} else if (!strcmp(*argv, "-keyout")) {
if (--argc < 1) goto bad;
keyoutfile = *(++argv);
} else if (!strcmp(*argv, "-hex")) {
format = SM9EXCH_FMT_HEX;
} else if (!strcmp(*argv, "-bin")) {
format = SM9EXCH_FMT_BIN;
} else {
fprintf(stderr, "gmssl %s: illegal option '%s'\n", prog, *argv);
goto end;
bad:
fprintf(stderr, "gmssl %s: '%s' option value missing\n", prog, *argv);
goto end;
}
argc--;
argv++;
}
if (!stage) {
fprintf(stderr, "gmssl %s: '-stage' option required\n", prog);
goto end;
}
if (id && id_len > SM9_MAX_ID_SIZE) {
fprintf(stderr, "gmssl %s: local identity too long\n", prog);
goto end;
}
if (peer_id && peer_id_len > SM9_MAX_ID_SIZE) {
fprintf(stderr, "gmssl %s: peer identity too long\n", prog);
goto end;
}
if (!strcmp(stage, "init")) {
ret = sm9exch_stage_init(mpkfile, peer_id, peer_id_len,
exch_keyoutfile, outfile, format, prog);
} else if (!strcmp(stage, "respond")) {
ret = sm9exch_stage_respond(mpkfile, keyfile, pass, id, id_len,
peer_id, peer_id_len, infile, exch_keyoutfile,
outfile, keylen, format, prog);
} else if (!strcmp(stage, "confirm")) {
ret = sm9exch_stage_confirm(mpkfile, keyfile, pass, id, id_len,
peer_id, peer_id_len, exch_keyfile, infile,
keyoutfile, outfile, keylen, format, prog);
} else if (!strcmp(stage, "finish")) {
ret = sm9exch_stage_finish(mpkfile, keyfile, pass, id, id_len,
peer_id, peer_id_len, exch_keyfile, infile,
keyoutfile, keylen, format, prog);
} else {
fprintf(stderr, "gmssl %s: invalid '-stage' value\n", prog);
goto end;
}
end:
return ret == 0 ? 0 : 1;
}

View File

@@ -17,12 +17,13 @@
#include <gmssl/error.h>
static const char *usage = "-alg (sm9sign|sm9encrypt) -in master_key.pem -inpass str -id str [-out pem] -outpass str";
static const char *usage = "-alg (sm9sign|sm9encrypt|sm9keyagreement) -in master_key.pem -inpass str -id str [-out pem] -outpass str";
static const char *options =
"Options\n"
"\n"
" -alg sm9sign|sm9encrypt Generate maeter key for sm9sign or sm9encrypt\n"
" -alg sm9sign|sm9encrypt|sm9keyagreement\n"
" Generate user's private key for sm9sign, sm9encrypt or sm9keyagreement\n"
" -in pem SM9 master private key in PEM format\n"
" -inpass pass Password to decrypt the master private key\n"
" -id str User's identity\n"
@@ -36,6 +37,7 @@ static const char *options =
"\n"
" $ gmssl sm9setup -alg sm9encrypt -pass P@ssw0rd -out sm9enc_msk.pem\n"
" $ gmssl sm9keygen -alg sm9encrypt -in sm9enc_msk.pem -inpass P@ssw0rd -id Alice -out sm9enc.pem -outpass 123456\n"
" $ gmssl sm9keygen -alg sm9keyagreement -in sm9enc_msk.pem -inpass P@ssw0rd -id Alice -out sm9exch.pem -outpass 123456\n"
"\n";
int sm9keygen_main(int argc, char **argv)
@@ -60,19 +62,20 @@ int sm9keygen_main(int argc, char **argv)
argv++;
if (argc < 1) {
fprintf(stderr, "usage: %s %s\n", prog, options);
fprintf(stderr, "usage: gmssl %s %s\n", prog, usage);
return 1;
}
while (argc > 0) {
if (!strcmp(*argv, "-help")) {
fprintf(stdout, "usage: %s %s\n", prog, options);
fprintf(stdout, "usage: gmssl %s %s\n", prog, usage);
fprintf(stdout, "%s\n", options);
return 0;
} else if (!strcmp(*argv, "-alg")) {
if (--argc < 1) goto bad;
alg = *(++argv);
if ((oid = sm9_oid_from_name(alg)) < 1) {
fprintf(stdout, "%s: invalid alg '%s', should be sm9sign or sm9encrypt\n", prog, alg);
fprintf(stdout, "%s: invalid alg '%s', should be sm9sign, sm9encrypt or sm9keyagreement\n", prog, alg);
goto end;
}
} else if (!strcmp(*argv, "-in")) {
@@ -135,6 +138,14 @@ bad:
goto end;
}
break;
case OID_sm9keyagreement:
if (sm9_enc_master_key_info_decrypt_from_pem(&enc_msk, inpass, infp) != 1
|| sm9_exch_master_key_extract_key(&enc_msk, id, strlen(id), &enc_key) != 1
|| sm9_enc_key_info_encrypt_to_pem(&enc_key, outpass, outfp) != 1) {
error_print();
goto end;
}
break;
default:
error_print();
goto end;

150
tools/zuc256.c Normal file
View File

@@ -0,0 +1,150 @@
/*
* Copyright 2014-2026 The GmSSL Project. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the License); you may
* not use this file except in compliance with the License.
*
* http://www.apache.org/licenses/LICENSE-2.0
*/
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>
#include <gmssl/mem.h>
#include <gmssl/zuc.h>
#include <gmssl/hex.h>
static const char *usage = "-key hex -iv hex [-in file] [-out file]";
static const char *help =
"Options\n"
"\n"
" -key hex ZUC-256 key in HEX format, 32 bytes\n"
" -iv hex ZUC-256 IV in HEX format, 23 bytes\n"
" -in file | stdin Input data\n"
" -out file | stdout Output data\n"
"\n"
"Examples\n"
"\n"
" gmssl zuc256 -key 0000000000000000000000000000000000000000000000000000000000000000 \\\n"
" -iv 0000000000000000000000000000000000000000000000 -in plaintext.bin -out ciphertext.bin\n"
"\n";
int zuc256_main(int argc, char **argv)
{
int ret = 1;
char *prog = argv[0];
char *keyhex = NULL;
char *ivhex = NULL;
char *infile = NULL;
char *outfile = NULL;
uint8_t key[ZUC256_KEY_SIZE];
uint8_t iv[ZUC256_IV_SIZE];
size_t keylen;
size_t ivlen;
FILE *infp = stdin;
FILE *outfp = stdout;
ZUC_STATE zuc_state;
uint8_t inbuf[4096];
uint8_t outbuf[4096];
size_t inlen;
argc--;
argv++;
if (argc < 1) {
fprintf(stderr, "usage: gmssl %s %s\n", prog, usage);
return 1;
}
while (argc > 0) {
if (!strcmp(*argv, "-help")) {
printf("usage: gmssl %s %s\n", prog, usage);
printf("%s\n", help);
ret = 0;
goto end;
} else if (!strcmp(*argv, "-key")) {
if (--argc < 1) goto bad;
keyhex = *(++argv);
if (strlen(keyhex) != sizeof(key) * 2) {
fprintf(stderr, "gmssl %s: key should be 32 bytes\n", prog);
goto end;
}
if (hex_to_bytes(keyhex, strlen(keyhex), key, &keylen) != 1) {
fprintf(stderr, "gmssl %s: invalid key hex digits\n", prog);
goto end;
}
} else if (!strcmp(*argv, "-iv")) {
if (--argc < 1) goto bad;
ivhex = *(++argv);
if (strlen(ivhex) != sizeof(iv) * 2) {
fprintf(stderr, "gmssl %s: IV should be 23 bytes\n", prog);
goto end;
}
if (hex_to_bytes(ivhex, strlen(ivhex), iv, &ivlen) != 1) {
fprintf(stderr, "gmssl %s: invalid IV hex digits\n", prog);
goto end;
}
} else if (!strcmp(*argv, "-in")) {
if (--argc < 1) goto bad;
infile = *(++argv);
if (!(infp = fopen(infile, "rb"))) {
fprintf(stderr, "gmssl %s: open '%s' failure : %s\n", prog, infile, strerror(errno));
goto end;
}
} else if (!strcmp(*argv, "-out")) {
if (--argc < 1) goto bad;
outfile = *(++argv);
if (!(outfp = fopen(outfile, "wb"))) {
fprintf(stderr, "gmssl %s: open '%s' failure : %s\n", prog, outfile, strerror(errno));
goto end;
}
} else {
fprintf(stderr, "gmssl %s: illegal option '%s'\n", prog, *argv);
goto end;
bad:
fprintf(stderr, "gmssl %s: '%s' option value missing\n", prog, *argv);
goto end;
}
argc--;
argv++;
}
if (!keyhex) {
fprintf(stderr, "gmssl %s: option '-key' required\n", prog);
goto end;
}
if (!ivhex) {
fprintf(stderr, "gmssl %s: option '-iv' required\n", prog);
goto end;
}
zuc256_init(&zuc_state, key, iv);
while ((inlen = fread(inbuf, 1, sizeof(inbuf), infp)) > 0) {
zuc_encrypt(&zuc_state, inbuf, inlen, outbuf);
if (fwrite(outbuf, 1, inlen, outfp) != inlen) {
fprintf(stderr, "gmssl %s: output failure : %s\n", prog, strerror(errno));
goto end;
}
}
if (ferror(infp)) {
fprintf(stderr, "gmssl %s: read failure : %s\n", prog, strerror(errno));
goto end;
}
ret = 0;
end:
gmssl_secure_clear(&zuc_state, sizeof(zuc_state));
gmssl_secure_clear(key, sizeof(key));
gmssl_secure_clear(iv, sizeof(iv));
gmssl_secure_clear(inbuf, sizeof(inbuf));
gmssl_secure_clear(outbuf, sizeof(outbuf));
if (infile && infp) fclose(infp);
if (outfile && outfp) fclose(outfp);
return ret;
}

310
tools/zuc_128_eea3.c Normal file
View File

@@ -0,0 +1,310 @@
/*
* Copyright 2014-2026 The GmSSL Project. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the License); you may
* not use this file except in compliance with the License.
*
* http://www.apache.org/licenses/LICENSE-2.0
*/
#include <stdio.h>
#include <errno.h>
#include <limits.h>
#include <stdint.h>
#include <string.h>
#include <stdlib.h>
#include <gmssl/mem.h>
#include <gmssl/zuc.h>
#include <gmssl/hex.h>
#include <gmssl/endian.h>
static const char *usage =
"-key hex -count num -bearer num -direction num [-in file|-in_hex hex] [-out file]";
static const char *help =
"Options\n"
"\n"
" -key hex 128-EEA3 confidentiality key, 16 bytes\n"
" -count num COUNT parameter, 32-bit integer, decimal or 0x-prefixed hex\n"
" -bearer num BEARER parameter, 5-bit integer in [0, 31]\n"
" -direction num DIRECTION parameter, 0 or 1\n"
" -in_hex hex Input bytes in HEX format\n"
" -in file | stdin Input file path\n"
" `-in_hex` and `-in` should not be used together\n"
" If neither `-in_hex` nor `-in` specified, read from stdin\n"
" -out file | stdout Output ciphertext bytes. If not specified, output to stdout\n"
"\n"
"Examples\n"
"\n"
" gmssl zuc_128_eea3 -key 173d14ba5003731d7a60049470f00a29 \\\n"
" -count 0x66035492 -bearer 15 -direction 0 \\\n"
" -in_hex 6cf65340735552ab0c9752fa6f9025fe0bd675d9005875b2 -out ciphertext.bin\n"
"\n";
static int parse_uint64(const char *s, uint64_t max, uint64_t *out)
{
char *end = NULL;
unsigned long long v;
if (!s || !*s) {
return -1;
}
errno = 0;
v = strtoull(s, &end, 0);
if (errno || *end || v > max) {
return -1;
}
*out = (uint64_t)v;
return 1;
}
static uint8_t *read_content(FILE *infp, size_t *outlen, const char *prog)
{
const size_t initial_size = 4096;
const size_t max_size = 512 * 1024 * 1024;
uint8_t *buf = NULL;
size_t bufsiz = initial_size;
size_t len = 0;
if (!(buf = (uint8_t *)malloc(bufsiz))) {
fprintf(stderr, "gmssl %s: malloc failure\n", prog);
return NULL;
}
for (;;) {
size_t n;
if (len == bufsiz) {
uint8_t *tmp;
if (bufsiz >= max_size) {
fprintf(stderr, "gmssl %s: input too long, should be less than %zu\n", prog, max_size);
free(buf);
return NULL;
}
bufsiz *= 2;
if (bufsiz > max_size) {
bufsiz = max_size;
}
if (!(tmp = (uint8_t *)realloc(buf, bufsiz))) {
fprintf(stderr, "gmssl %s: realloc failure\n", prog);
free(buf);
return NULL;
}
buf = tmp;
}
n = fread(buf + len, 1, bufsiz - len, infp);
len += n;
if (feof(infp)) {
break;
}
if (ferror(infp)) {
fprintf(stderr, "gmssl %s: read failure : %s\n", prog, strerror(errno));
free(buf);
return NULL;
}
}
*outlen = len;
return buf;
}
int zuc_128_eea3_main(int argc, char **argv)
{
int ret = 1;
char *prog = argv[0];
char *keyhex = NULL;
char *inhex = NULL;
char *infile = NULL;
char *outfile = NULL;
uint8_t key[ZUC_KEY_SIZE];
size_t keylen;
uint8_t *in = NULL;
size_t inlen = 0;
uint8_t *padded = NULL;
ZUC_UINT32 *inwords = NULL;
ZUC_UINT32 *outwords = NULL;
uint8_t *out = NULL;
size_t nbits;
size_t nbytes = 0;
size_t nwords = 0;
size_t i;
uint64_t v;
ZUC_UINT32 count = 0;
ZUC_UINT5 bearer = 0;
ZUC_BIT direction = 0;
int count_set = 0;
int bearer_set = 0;
int direction_set = 0;
FILE *infp = stdin;
FILE *outfp = stdout;
argc--;
argv++;
if (argc < 1) {
fprintf(stderr, "usage: gmssl %s %s\n", prog, usage);
return 1;
}
while (argc > 0) {
if (!strcmp(*argv, "-help")) {
printf("usage: gmssl %s %s\n", prog, usage);
printf("%s\n", help);
ret = 0;
goto end;
} else if (!strcmp(*argv, "-key")) {
if (--argc < 1) goto bad;
keyhex = *(++argv);
if (strlen(keyhex) != sizeof(key) * 2) {
fprintf(stderr, "gmssl %s: key should be 16 bytes\n", prog);
goto end;
}
if (hex_to_bytes(keyhex, strlen(keyhex), key, &keylen) != 1) {
fprintf(stderr, "gmssl %s: invalid key hex digits\n", prog);
goto end;
}
} else if (!strcmp(*argv, "-count")) {
if (--argc < 1) goto bad;
if (parse_uint64(*(++argv), UINT32_MAX, &v) != 1) {
fprintf(stderr, "gmssl %s: invalid COUNT value\n", prog);
goto end;
}
count = (ZUC_UINT32)v;
count_set = 1;
} else if (!strcmp(*argv, "-bearer")) {
if (--argc < 1) goto bad;
if (parse_uint64(*(++argv), 31, &v) != 1) {
fprintf(stderr, "gmssl %s: invalid BEARER value\n", prog);
goto end;
}
bearer = (ZUC_UINT5)v;
bearer_set = 1;
} else if (!strcmp(*argv, "-direction")) {
if (--argc < 1) goto bad;
if (parse_uint64(*(++argv), 1, &v) != 1) {
fprintf(stderr, "gmssl %s: invalid DIRECTION value\n", prog);
goto end;
}
direction = (ZUC_BIT)v;
direction_set = 1;
} else if (!strcmp(*argv, "-in_hex")) {
if (infile) {
fprintf(stderr, "gmssl %s: `-in` and `-in_hex` should not be used together\n", prog);
goto end;
}
if (--argc < 1) goto bad;
inhex = *(++argv);
} else if (!strcmp(*argv, "-in")) {
if (inhex) {
fprintf(stderr, "gmssl %s: `-in` and `-in_hex` should not be used together\n", prog);
goto end;
}
if (--argc < 1) goto bad;
infile = *(++argv);
if (!(infp = fopen(infile, "rb"))) {
fprintf(stderr, "gmssl %s: open '%s' failure : %s\n", prog, infile, strerror(errno));
goto end;
}
} else if (!strcmp(*argv, "-out")) {
if (--argc < 1) goto bad;
outfile = *(++argv);
if (!(outfp = fopen(outfile, "wb"))) {
fprintf(stderr, "gmssl %s: open '%s' failure : %s\n", prog, outfile, strerror(errno));
goto end;
}
} else {
fprintf(stderr, "gmssl %s: illegal option '%s'\n", prog, *argv);
goto end;
bad:
fprintf(stderr, "gmssl %s: '%s' option value missing\n", prog, *argv);
goto end;
}
argc--;
argv++;
}
if (!keyhex) {
fprintf(stderr, "gmssl %s: option '-key' required\n", prog);
goto end;
}
if (!count_set || !bearer_set || !direction_set) {
fprintf(stderr, "gmssl %s: options '-count', '-bearer' and '-direction' are required\n", prog);
goto end;
}
if (inhex) {
if (strlen(inhex) % 2) {
fprintf(stderr, "gmssl %s: invalid input hex length\n", prog);
goto end;
}
nbytes = strlen(inhex) / 2;
if (!(in = (uint8_t *)malloc(nbytes ? nbytes : 1))) {
fprintf(stderr, "gmssl %s: malloc failure\n", prog);
goto end;
}
if (hex_to_bytes(inhex, strlen(inhex), in, &inlen) != 1) {
fprintf(stderr, "gmssl %s: invalid input hex digits\n", prog);
goto end;
}
} else if (!(in = read_content(infp, &inlen, prog))) {
goto end;
}
nbytes = inlen;
nbits = inlen * 8;
nwords = (nbits + 31) / 32;
if (!(padded = (uint8_t *)calloc(nwords ? nwords : 1, sizeof(uint32_t)))
|| !(inwords = (ZUC_UINT32 *)calloc(nwords ? nwords : 1, sizeof(uint32_t)))
|| !(outwords = (ZUC_UINT32 *)calloc(nwords ? nwords : 1, sizeof(uint32_t)))
|| !(out = (uint8_t *)calloc(nwords ? nwords : 1, sizeof(uint32_t)))) {
fprintf(stderr, "gmssl %s: malloc failure\n", prog);
goto end;
}
memcpy(padded, in, inlen);
for (i = 0; i < nwords; i++) {
inwords[i] = GETU32(padded + i * 4);
}
zuc_eea_encrypt(inwords, outwords, nbits, key, count, bearer, direction);
for (i = 0; i < nwords; i++) {
PUTU32(out + i * 4, outwords[i]);
}
if (nbytes && fwrite(out, 1, nbytes, outfp) != nbytes) {
fprintf(stderr, "gmssl %s: output failure : %s\n", prog, strerror(errno));
goto end;
}
ret = 0;
end:
gmssl_secure_clear(key, sizeof(key));
if (in) {
gmssl_secure_clear(in, inlen);
free(in);
}
if (padded) {
gmssl_secure_clear(padded, (nwords ? nwords : 1) * sizeof(uint32_t));
free(padded);
}
if (inwords) {
gmssl_secure_clear(inwords, (nwords ? nwords : 1) * sizeof(uint32_t));
free(inwords);
}
if (outwords) {
gmssl_secure_clear(outwords, (nwords ? nwords : 1) * sizeof(uint32_t));
free(outwords);
}
if (out) {
gmssl_secure_clear(out, (nwords ? nwords : 1) * sizeof(uint32_t));
free(out);
}
if (infile && infp) fclose(infp);
if (outfile && outfp) fclose(outfp);
return ret;
}

299
tools/zuc_128_eia3.c Normal file
View File

@@ -0,0 +1,299 @@
/*
* Copyright 2014-2026 The GmSSL Project. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the License); you may
* not use this file except in compliance with the License.
*
* http://www.apache.org/licenses/LICENSE-2.0
*/
#include <stdio.h>
#include <errno.h>
#include <limits.h>
#include <stdint.h>
#include <string.h>
#include <stdlib.h>
#include <gmssl/mem.h>
#include <gmssl/zuc.h>
#include <gmssl/hex.h>
#include <gmssl/endian.h>
static const char *usage =
"-key hex -count num -bearer num -direction num [-in file|-in_hex hex] [-hex|-bin] [-out file]";
static const char *help =
"Options\n"
"\n"
" -key hex 128-EIA3 integrity key, 16 bytes\n"
" -count num COUNT parameter, 32-bit integer, decimal or 0x-prefixed hex\n"
" -bearer num BEARER parameter, 5-bit integer in [0, 31]\n"
" -direction num DIRECTION parameter, 0 or 1\n"
" -in_hex hex Input message bytes in HEX format\n"
" -in file | stdin Input file path\n"
" `-in_hex` and `-in` should not be used together\n"
" If neither `-in_hex` nor `-in` specified, read from stdin\n"
" -hex Output MAC as hex string (by default)\n"
" -bin Output MAC as binary\n"
" `-hex` and `-bin` should not be used together\n"
" -out file | stdout Output file path. If not specified, output to stdout\n"
"\n"
"Examples\n"
"\n"
" gmssl zuc_128_eia3 -key 00000000000000000000000000000000 \\\n"
" -count 0 -bearer 0 -direction 0 -in_hex 00\n"
"\n";
static int parse_uint64(const char *s, uint64_t max, uint64_t *out)
{
char *end = NULL;
unsigned long long v;
if (!s || !*s) {
return -1;
}
errno = 0;
v = strtoull(s, &end, 0);
if (errno || *end || v > max) {
return -1;
}
*out = (uint64_t)v;
return 1;
}
static uint8_t *read_content(FILE *infp, size_t *outlen, const char *prog)
{
const size_t initial_size = 4096;
const size_t max_size = 512 * 1024 * 1024;
uint8_t *buf = NULL;
size_t bufsiz = initial_size;
size_t len = 0;
if (!(buf = (uint8_t *)malloc(bufsiz))) {
fprintf(stderr, "gmssl %s: malloc failure\n", prog);
return NULL;
}
for (;;) {
size_t n;
if (len == bufsiz) {
uint8_t *tmp;
if (bufsiz >= max_size) {
fprintf(stderr, "gmssl %s: input too long, should be less than %zu\n", prog, max_size);
free(buf);
return NULL;
}
bufsiz *= 2;
if (bufsiz > max_size) {
bufsiz = max_size;
}
if (!(tmp = (uint8_t *)realloc(buf, bufsiz))) {
fprintf(stderr, "gmssl %s: realloc failure\n", prog);
free(buf);
return NULL;
}
buf = tmp;
}
n = fread(buf + len, 1, bufsiz - len, infp);
len += n;
if (feof(infp)) {
break;
}
if (ferror(infp)) {
fprintf(stderr, "gmssl %s: read failure : %s\n", prog, strerror(errno));
free(buf);
return NULL;
}
}
*outlen = len;
return buf;
}
int zuc_128_eia3_main(int argc, char **argv)
{
int ret = 1;
char *prog = argv[0];
char *keyhex = NULL;
char *inhex = NULL;
char *infile = NULL;
char *outfile = NULL;
int outformat = 0;
uint8_t key[ZUC_KEY_SIZE];
size_t keylen;
uint8_t *in = NULL;
size_t inlen = 0;
size_t nbits;
size_t nbytes = 0;
uint64_t v;
ZUC_UINT32 count = 0;
ZUC_UINT5 bearer = 0;
ZUC_BIT direction = 0;
ZUC_UINT32 macword;
uint8_t mac[ZUC_MAC_SIZE];
int count_set = 0;
int bearer_set = 0;
int direction_set = 0;
FILE *infp = stdin;
FILE *outfp = stdout;
size_t i;
argc--;
argv++;
if (argc < 1) {
fprintf(stderr, "usage: gmssl %s %s\n", prog, usage);
return 1;
}
while (argc > 0) {
if (!strcmp(*argv, "-help")) {
printf("usage: gmssl %s %s\n", prog, usage);
printf("%s\n", help);
ret = 0;
goto end;
} else if (!strcmp(*argv, "-key")) {
if (--argc < 1) goto bad;
keyhex = *(++argv);
if (strlen(keyhex) != sizeof(key) * 2) {
fprintf(stderr, "gmssl %s: key should be 16 bytes\n", prog);
goto end;
}
if (hex_to_bytes(keyhex, strlen(keyhex), key, &keylen) != 1) {
fprintf(stderr, "gmssl %s: invalid key hex digits\n", prog);
goto end;
}
} else if (!strcmp(*argv, "-count")) {
if (--argc < 1) goto bad;
if (parse_uint64(*(++argv), UINT32_MAX, &v) != 1) {
fprintf(stderr, "gmssl %s: invalid COUNT value\n", prog);
goto end;
}
count = (ZUC_UINT32)v;
count_set = 1;
} else if (!strcmp(*argv, "-bearer")) {
if (--argc < 1) goto bad;
if (parse_uint64(*(++argv), 31, &v) != 1) {
fprintf(stderr, "gmssl %s: invalid BEARER value\n", prog);
goto end;
}
bearer = (ZUC_UINT5)v;
bearer_set = 1;
} else if (!strcmp(*argv, "-direction")) {
if (--argc < 1) goto bad;
if (parse_uint64(*(++argv), 1, &v) != 1) {
fprintf(stderr, "gmssl %s: invalid DIRECTION value\n", prog);
goto end;
}
direction = (ZUC_BIT)v;
direction_set = 1;
} else if (!strcmp(*argv, "-in_hex")) {
if (infile) {
fprintf(stderr, "gmssl %s: `-in` and `-in_hex` should not be used together\n", prog);
goto end;
}
if (--argc < 1) goto bad;
inhex = *(++argv);
} else if (!strcmp(*argv, "-in")) {
if (inhex) {
fprintf(stderr, "gmssl %s: `-in` and `-in_hex` should not be used together\n", prog);
goto end;
}
if (--argc < 1) goto bad;
infile = *(++argv);
if (!(infp = fopen(infile, "rb"))) {
fprintf(stderr, "gmssl %s: open '%s' failure : %s\n", prog, infile, strerror(errno));
goto end;
}
} else if (!strcmp(*argv, "-hex")) {
if (outformat == 2) {
fprintf(stderr, "gmssl %s: `-hex` and `-bin` should not be used together\n", prog);
goto end;
}
outformat = 1;
} else if (!strcmp(*argv, "-bin")) {
if (outformat == 1) {
fprintf(stderr, "gmssl %s: `-hex` and `-bin` should not be used together\n", prog);
goto end;
}
outformat = 2;
} else if (!strcmp(*argv, "-out")) {
if (--argc < 1) goto bad;
outfile = *(++argv);
if (!(outfp = fopen(outfile, "wb"))) {
fprintf(stderr, "gmssl %s: open '%s' failure : %s\n", prog, outfile, strerror(errno));
goto end;
}
} else {
fprintf(stderr, "gmssl %s: illegal option '%s'\n", prog, *argv);
goto end;
bad:
fprintf(stderr, "gmssl %s: '%s' option value missing\n", prog, *argv);
goto end;
}
argc--;
argv++;
}
if (!keyhex) {
fprintf(stderr, "gmssl %s: option '-key' required\n", prog);
goto end;
}
if (!count_set || !bearer_set || !direction_set) {
fprintf(stderr, "gmssl %s: options '-count', '-bearer' and '-direction' are required\n", prog);
goto end;
}
if (inhex) {
if (strlen(inhex) % 2) {
fprintf(stderr, "gmssl %s: invalid input hex length\n", prog);
goto end;
}
nbytes = strlen(inhex) / 2;
if (!(in = (uint8_t *)malloc(nbytes ? nbytes : 1))) {
fprintf(stderr, "gmssl %s: malloc failure\n", prog);
goto end;
}
if (hex_to_bytes(inhex, strlen(inhex), in, &inlen) != 1) {
fprintf(stderr, "gmssl %s: invalid input hex digits\n", prog);
goto end;
}
} else if (!(in = read_content(infp, &inlen, prog))) {
goto end;
}
nbytes = inlen;
nbits = inlen * 8;
macword = zuc_eia_generate_mac((ZUC_UINT32 *)in, nbits, key, count, bearer, direction);
PUTU32(mac, macword);
if (outformat == 2) {
if (fwrite(mac, 1, sizeof(mac), outfp) != sizeof(mac)) {
fprintf(stderr, "gmssl %s: output failure : %s\n", prog, strerror(errno));
goto end;
}
} else {
for (i = 0; i < sizeof(mac); i++) {
fprintf(outfp, "%02x", mac[i]);
}
fprintf(outfp, "\n");
}
ret = 0;
end:
gmssl_secure_clear(key, sizeof(key));
gmssl_secure_clear(mac, sizeof(mac));
if (in) {
gmssl_secure_clear(in, inlen);
free(in);
}
if (infile && infp) fclose(infp);
if (outfile && outfp) fclose(outfp);
return ret;
}