* This file is part of the openHiTLS project.
*
* openHiTLS is licensed under the Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
*
* http://license.coscl.org.cn/MulanPSL2
*
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PSL v2 for more details.
*/
#include <stdio.h>
#include <stdint.h>
#include <stdbool.h>
#include <string.h>
#include "crypt_modes_cfb.h"
static void dump_hex(const char *title, const uint8_t *buf, size_t len) {
printf("%s (len=%zu):\n", title, len);
for (size_t i = 0; i < len; ++i) {
printf("%02X", buf[i]);
if ((i + 1) % 16 == 0 || i + 1 == len) printf("\n");
else printf(" ");
}
}
static int stream_cfb(bool enc,
const uint8_t *key, uint32_t keyLen,
const uint8_t *iv, uint32_t ivLen,
const uint8_t *in, uint32_t inLen,
const uint32_t *chunks, size_t nChunks,
uint8_t *out )
{
MODES_CFB_Ctx m;
int32_t rc = SM4_CFB_InitCtx(&m, key, keyLen, iv, ivLen, enc);
if (rc != 0) {
fprintf(stderr, "SM4_CFB_InitCtx failed: %d\n", rc);
return rc;
}
uint32_t produced = 0, consumed = 0;
for (size_t i = 0; i < nChunks && consumed < inLen; ++i) {
uint32_t take = chunks[i];
if (consumed + take > inLen) take = inLen - consumed;
uint32_t outLen = 0;
rc = SM4_CFB_Update(&m, in + consumed, take, out + produced, &outLen);
if (rc != 0) {
fprintf(stderr, "SM4_CFB_Update failed at chunk #%zu: %d\n", i, rc);
return rc;
}
if (outLen != take) {
fprintf(stderr, "Unexpected outLen %u (expect %u)\n", outLen, take);
return -1;
}
consumed += take;
produced += outLen;
}
if (consumed < inLen) {
uint32_t tail = inLen - consumed, outLen = 0;
rc = SM4_CFB_Update(&m, in + consumed, tail, out + produced, &outLen);
if (rc != 0 || outLen != tail) {
fprintf(stderr, "SM4_CFB_Update tail failed: rc=%d, outLen=%u\n", rc, outLen);
return (rc != 0) ? rc : -1;
}
produced += outLen;
}
return (produced == inLen) ? 0 : -1;
}
int main(void) {
uint8_t key[16]; for (int i = 0; i < 16; ++i) key[i] = (uint8_t)(i + 1);
uint8_t iv[16]; for (int i = 0; i < 16; ++i) iv[i] = (uint8_t)i;
const uint8_t plaintext[] =
"The quick brown fox jumps over the lazy dog. CFB mode streaming test!";
const uint32_t pt_len = (uint32_t)strlen((const char*)plaintext);
uint8_t ct_stream[1024] = {0};
uint8_t ct_one[1024] = {0};
uint8_t pt_back[1024] = {0};
dump_hex("PLAINTEXT", plaintext, pt_len);
const uint32_t enc_chunks[] = {5, 7, 13, 1, 3};
if (stream_cfb(true, key, sizeof(key), iv, sizeof(iv),
plaintext, pt_len, enc_chunks, sizeof(enc_chunks)/sizeof(enc_chunks[0]),
ct_stream) != 0) {
return 2;
}
dump_hex("CIPHERTEXT (streamed)", ct_stream, pt_len);
{
MODES_CFB_Ctx m;
uint8_t iv2[16]; memcpy(iv2, iv, 16);
if (SM4_CFB_InitCtx(&m, key, sizeof(key), iv2, sizeof(iv2), true) != 0) return 3;
uint32_t outLen = 0;
if (SM4_CFB_Update(&m, plaintext, pt_len, ct_one, &outLen) != 0 || outLen != pt_len) return 3;
}
dump_hex("CIPHERTEXT (one-shot)", ct_one, pt_len);
if (memcmp(ct_stream, ct_one, pt_len) != 0) {
fprintf(stderr, "[X] Encrypt mismatch: streamed vs one-shot.\n");
return 4;
}
printf("[OK] Encrypt check passed.\n");
const uint32_t dec_chunks[] = {8, 2, 19, 4, 1};
if (stream_cfb(false, key, sizeof(key), iv, sizeof(iv),
ct_stream, pt_len, dec_chunks, sizeof(dec_chunks)/sizeof(dec_chunks[0]),
pt_back) != 0) {
return 5;
}
dump_hex("DECRYPTED", pt_back, pt_len);
if (memcmp(pt_back, plaintext, pt_len) != 0) {
fprintf(stderr, "[X] Decrypt mismatch: decrypted != plaintext.\n");
return 6;
}
printf("[OK] Decrypt check passed.\n");
puts("\nAll SM4-CFB streaming tests passed.");
return 0;
}