Add SM4-FF1, update socket API

This commit is contained in:
Zhi Guan
2026-06-22 22:52:39 +08:00
parent 3a3f632b46
commit 6c2b35b96d
15 changed files with 1058 additions and 44 deletions

308
src/ff1.c Normal file
View File

@@ -0,0 +1,308 @@
/*
* 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 <gmssl/ff1.h>
#include <string.h>
#include <gmssl/endian.h>
#include <gmssl/error.h>
static const uint32_t ff1_radix10_mod[] = {
1,
10,
100,
1000,
10000,
100000,
1000000,
10000000,
100000000,
1000000000,
};
static const size_t ff1_radix10_b[] = {
0, 1, 1, 2, 2, 3, 3, 3, 4, 4,
};
int ff1_init(BLOCK_CIPHER_KEY *key, const BLOCK_CIPHER *cipher, const uint8_t *raw_key)
{
if (!key || !cipher || !raw_key) {
error_print();
return -1;
}
if (cipher->block_size != BLOCK_CIPHER_BLOCK_SIZE) {
error_print();
return -1;
}
if (block_cipher_set_encrypt_key(key, cipher, raw_key) != 1) {
error_print();
return -1;
}
return 1;
}
static int ff1_digits_to_num(const char *digits, size_t ndigits, uint32_t *num)
{
uint32_t value = 0;
size_t i;
if (!digits || !num || ndigits > FF1_MAX_DIGITS/2) {
error_print();
return -1;
}
for (i = 0; i < ndigits; i++) {
if (digits[i] < '0' || digits[i] > '9') {
error_print();
return -1;
}
value = value * 10 + (uint32_t)(digits[i] - '0');
}
*num = value;
return 1;
}
static int ff1_num_to_digits(uint32_t num, size_t ndigits, char *digits)
{
if (!digits || ndigits > FF1_MAX_DIGITS/2 || num >= ff1_radix10_mod[ndigits]) {
error_print();
return -1;
}
while (ndigits) {
digits[--ndigits] = (char)('0' + num % 10);
num /= 10;
}
return 1;
}
static int ff1_check_args(const BLOCK_CIPHER_KEY *key, const char *in, size_t inlen,
const uint8_t *tweak, size_t tweaklen, char *out)
{
size_t i;
if (!key || !key->cipher || !in || !out || (!tweak && tweaklen)) {
error_print();
return -1;
}
if (key->cipher->block_size != BLOCK_CIPHER_BLOCK_SIZE) {
error_print();
return -1;
}
if (inlen < FF1_MIN_DIGITS || inlen > FF1_MAX_DIGITS) {
error_print();
return -1;
}
if (tweaklen < FF1_MIN_TWEAK_SIZE || tweaklen > FF1_MAX_TWEAK_SIZE) {
error_print();
return -1;
}
for (i = 0; i < inlen; i++) {
if (in[i] < '0' || in[i] > '9') {
error_print();
return -1;
}
}
return 1;
}
static int ff1_init_pblock(const BLOCK_CIPHER_KEY *key, uint8_t pblock[16],
size_t u, size_t n, size_t tweaklen)
{
static const uint8_t ff1_radix10_pblock[16] = {
0x01, 0x02, 0x01, 0x00, 0x00, 0x0a, 0x0a, 0xff,
0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff,
};
memcpy(pblock, ff1_radix10_pblock, 16);
pblock[7] = (uint8_t)u;
PUTU32(pblock + 8, (uint32_t)n);
PUTU32(pblock + 12, (uint32_t)tweaklen);
if (block_cipher_encrypt(key, pblock, pblock) != 1) {
error_print();
return -1;
}
return 1;
}
static int ff1_round(const BLOCK_CIPHER_KEY *key, const uint8_t pblock[16],
const uint8_t *tweak, size_t tweaklen, size_t bsize, int round, uint32_t num, uint64_t *y)
{
uint8_t qblock[32] = {0};
uint8_t block[16];
size_t padlen;
size_t offset;
size_t qlen;
size_t i;
if (!key || !pblock || (!tweak && tweaklen) || !bsize || bsize > sizeof(uint32_t)
|| !y || round < 0 || round > 0xff) {
error_print();
return -1;
}
/* Keep a full zero padding block when tweak || round || NUM(B) is block-aligned. */
padlen = 16 - (tweaklen + 1 + bsize) % 16;
qlen = tweaklen + padlen + 1 + bsize;
if (!qlen || qlen > sizeof(qblock) || qlen % 16) {
error_print();
return -1;
}
if (tweaklen) {
memcpy(qblock, tweak, tweaklen);
}
offset = tweaklen + padlen;
qblock[offset++] = (uint8_t)round;
for (i = 0; i < bsize; i++) {
qblock[offset + bsize - 1 - i] = (uint8_t)(num >> (8 * i));
}
for (i = 0; i < sizeof(block); i++) {
block[i] = pblock[i] ^ qblock[i];
}
if (block_cipher_encrypt(key, block, block) != 1) {
error_print();
return -1;
}
for (offset = 16; offset < qlen; offset += 16) {
for (i = 0; i < sizeof(block); i++) {
block[i] ^= qblock[offset + i];
}
if (block_cipher_encrypt(key, block, block) != 1) {
error_print();
return -1;
}
}
*y = GETU64(block);
return 1;
}
int ff1_encrypt(const BLOCK_CIPHER_KEY *key, const char *in, size_t inlen,
const uint8_t *tweak, size_t tweaklen, char *out)
{
size_t u;
size_t v;
uint32_t a;
uint32_t b;
size_t alen;
size_t blen;
uint64_t y;
uint32_t ymod;
uint32_t c;
uint8_t pblock[16];
size_t bsize;
int i;
if (ff1_check_args(key, in, inlen, tweak, tweaklen, out) != 1) {
error_print();
return -1;
}
u = inlen / 2;
v = inlen - u;
if (ff1_digits_to_num(in, u, &a) != 1
|| ff1_digits_to_num(in + u, v, &b) != 1
|| ff1_init_pblock(key, pblock, u, inlen, tweaklen) != 1) {
error_print();
return -1;
}
alen = u;
blen = v;
bsize = ff1_radix10_b[v];
for (i = 0; i < FF1_NUM_ROUNDS; i++) {
size_t m = (i & 1) ? v : u;
if (ff1_round(key, pblock, tweak, tweaklen, bsize, i, b, &y) != 1) {
error_print();
return -1;
}
ymod = (uint32_t)(y % ff1_radix10_mod[m]);
c = (a + ymod) % ff1_radix10_mod[m];
a = b;
alen = blen;
b = c;
blen = m;
}
if (alen != u || blen != v) {
error_print();
return -1;
}
if (ff1_num_to_digits(a, alen, out) != 1
|| ff1_num_to_digits(b, blen, out + alen) != 1) {
error_print();
return -1;
}
return 1;
}
int ff1_decrypt(const BLOCK_CIPHER_KEY *key, const char *in, size_t inlen,
const uint8_t *tweak, size_t tweaklen, char *out)
{
size_t u;
size_t v;
uint32_t a;
uint32_t b;
size_t alen;
size_t blen;
uint64_t y;
uint32_t ymod;
uint32_t c;
uint8_t pblock[16];
size_t bsize;
int i;
if (ff1_check_args(key, in, inlen, tweak, tweaklen, out) != 1) {
error_print();
return -1;
}
u = inlen / 2;
v = inlen - u;
if (ff1_digits_to_num(in, u, &a) != 1
|| ff1_digits_to_num(in + u, v, &b) != 1
|| ff1_init_pblock(key, pblock, u, inlen, tweaklen) != 1) {
error_print();
return -1;
}
alen = u;
blen = v;
bsize = ff1_radix10_b[v];
for (i = FF1_NUM_ROUNDS - 1; i >= 0; i--) {
size_t m = (i & 1) ? v : u;
c = b;
b = a;
blen = alen;
if (ff1_round(key, pblock, tweak, tweaklen, bsize, i, b, &y) != 1) {
error_print();
return -1;
}
ymod = (uint32_t)(y % ff1_radix10_mod[m]);
a = c;
a = (a >= ymod) ? a - ymod : a + ff1_radix10_mod[m] - ymod;
alen = m;
}
if (alen != u || blen != v) {
error_print();
return -1;
}
if (ff1_num_to_digits(a, alen, out) != 1
|| ff1_num_to_digits(b, blen, out + alen) != 1) {
error_print();
return -1;
}
return 1;
}

View File

@@ -120,7 +120,6 @@ int http_get(const char *uri, uint8_t *buf, size_t *contentlen, size_t buflen)
char host[128];
int port;
char path[256];
struct hostent *hp;
struct sockaddr_in server;
tls_socket_t sock = tls_socket_invalid();
char get[sizeof(HTTP_GET_TEMPLATE) + sizeof(host) + sizeof(path)];
@@ -141,13 +140,10 @@ int http_get(const char *uri, uint8_t *buf, size_t *contentlen, size_t buflen)
}
// connect and send request
if (!(hp = gethostbyname(host))) {
if (tls_socket_get_addr(host, port, &server) != 1) {
error_print();
return -1;
}
server.sin_addr = *((struct in_addr *)hp->h_addr_list[0]);
server.sin_family = AF_INET;
server.sin_port = htons(port);
if (tls_socket_create(&sock, AF_INET, SOCK_STREAM, 0) != 1) {
error_print();
@@ -198,7 +194,6 @@ int http_post(const char *uri, const char *content_type,
char host[128];
int port;
char path[256];
struct hostent *hp;
struct sockaddr_in server;
tls_socket_t sock = tls_socket_invalid();
char post[1024];
@@ -223,13 +218,10 @@ int http_post(const char *uri, const char *content_type,
return -1;
}
if (!(hp = gethostbyname(host))) {
if (tls_socket_get_addr(host, port, &server) != 1) {
error_print();
return -1;
}
server.sin_addr = *((struct in_addr *)hp->h_addr_list[0]);
server.sin_family = AF_INET;
server.sin_port = htons(port);
if (tls_socket_create(&sock, AF_INET, SOCK_STREAM, 0) != 1) {
error_print();

View File

@@ -120,7 +120,6 @@ int http_get(const char *uri, uint8_t *buf, size_t *contentlen, size_t buflen)
char host[128];
int port;
char path[256];
struct hostent *hp;
struct sockaddr_in server;
tls_socket_t sock = tls_socket_invalid();
char get[sizeof(HTTP_GET_TEMPLATE) + sizeof(host) + sizeof(path)];
@@ -148,13 +147,10 @@ int http_get(const char *uri, uint8_t *buf, size_t *contentlen, size_t buflen)
socket_lib_inited = 1;
// connect and send request
if (!(hp = gethostbyname(host))) {
if (tls_socket_get_addr(host, port, &server) != 1) {
error_print();
goto end;
}
server.sin_addr = *((struct in_addr *)hp->h_addr_list[0]);
server.sin_family = AF_INET;
server.sin_port = htons(port);
if (tls_socket_create(&sock, AF_INET, SOCK_STREAM, 0) != 1) {
error_print();
@@ -207,7 +203,6 @@ int http_post(const char *uri, const char *content_type,
char host[128];
int port;
char path[256];
struct hostent *hp;
struct sockaddr_in server;
tls_socket_t sock = tls_socket_invalid();
char post[1024];
@@ -239,13 +234,10 @@ int http_post(const char *uri, const char *content_type,
}
socket_lib_inited = 1;
if (!(hp = gethostbyname(host))) {
if (tls_socket_get_addr(host, port, &server) != 1) {
error_print();
goto end;
}
server.sin_addr = *((struct in_addr *)hp->h_addr_list[0]);
server.sin_family = AF_INET;
server.sin_port = htons(port);
if (tls_socket_create(&sock, AF_INET, SOCK_STREAM, 0) != 1) {
error_print();

View File

@@ -18,6 +18,7 @@
#ifdef WIN32
#include <windows.h>
#include <ws2tcpip.h>
#endif
@@ -29,6 +30,47 @@ static int tls_socket_should_print_error(int err, int is_read)
&& type != TLS_SOCKET_ERR_INTERRUPTED;
}
int tls_socket_get_addr(const char *host, int port, struct sockaddr_in *addr)
{
char service[16];
struct addrinfo hints;
struct addrinfo *res = NULL;
int err;
if (!host || !addr || port <= 0 || port > 65535) {
error_print();
return -1;
}
if (snprintf(service, sizeof(service), "%d", port) <= 0) {
error_print();
return -1;
}
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
if ((err = getaddrinfo(host, service, &hints, &res)) != 0) {
#ifdef WIN32
error_print_msg("getaddrinfo error: %d (%s)\n", err, gai_strerrorA(err));
#else
error_print_msg("getaddrinfo error: %d (%s)\n", err, gai_strerror(err));
#endif
return -1;
}
if (!res || res->ai_addrlen < sizeof(struct sockaddr_in)) {
error_print();
if (res) {
freeaddrinfo(res);
}
return -1;
}
memcpy(addr, res->ai_addr, sizeof(struct sockaddr_in));
freeaddrinfo(res);
return 1;
}
#ifdef WIN32
int tls_socket_get_error(void)