Zuc128

 avatar
BaHieu
c_cpp
5 months ago
13 kB
2
Indexable
// zuc128_model.c

#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
// Define constants
#define MASK 0x7FFFFFFF
#define KEYSIZE 16
#define IVSIZE 16
#define BYTE unsigned char
typedef long DWORD;
// S-boxes
const uint8_t S0[256] = {
    0x3e, 0x72, 0x5b, 0x47, 0xca, 0xe0, 0x00, 0x33, 0x04, 0xd1, 0x54, 0x98, 0x09, 0xb9, 0x6d, 0xcb,
    0x7b, 0x1b, 0xf9, 0x32, 0xaf, 0x9d, 0x6a, 0xa5, 0xb8, 0x2d, 0xfc, 0x1d, 0x08, 0x53, 0x03, 0x90,
    0x4d, 0x4e, 0x84, 0x99, 0xe4, 0xce, 0xd9, 0x91, 0xdd, 0xb6, 0x85, 0x48, 0x8b, 0x29, 0x6e, 0xac,
    0xcd, 0xc1, 0xf8, 0x1e, 0x73, 0x43, 0x69, 0xc6, 0xb5, 0xbd, 0xfd, 0x39, 0x63, 0x20, 0xd4, 0x38,
    0x76, 0x7d, 0xb2, 0xa7, 0xcf, 0xed, 0x57, 0xc5, 0xf3, 0x2c, 0xbb, 0x14, 0x21, 0x06, 0x55, 0x9b,
    0xe3, 0xef, 0x5e, 0x31, 0x4f, 0x7f, 0x5a, 0xa4, 0x0d, 0x82, 0x51, 0x49, 0x5f, 0xba, 0x58, 0x1c,
    0x4a, 0x16, 0xd5, 0x17, 0xa8, 0x92, 0x24, 0x1f, 0x8c, 0xff, 0xd8, 0xae, 0x2e, 0x01, 0xd3, 0xad,
    0x3b, 0x4b, 0xda, 0x46, 0xeb, 0xc9, 0xde, 0x9a, 0x8f, 0x87, 0xd7, 0x3a, 0x80, 0x6f, 0x2f, 0xc8,
    0xb1, 0xb4, 0x37, 0xf7, 0x0a, 0x22, 0x13, 0x28, 0x7c, 0xcc, 0x3c, 0x89, 0xc7, 0xc3, 0x96, 0x56,
    0x07, 0xbf, 0x7e, 0xf0, 0x0b, 0x2b, 0x97, 0x52, 0x35, 0x41, 0x79, 0x61, 0xa6, 0x4c, 0x10, 0xfe,
    0xbc, 0x26, 0x95, 0x88, 0x8a, 0xb0, 0xa3, 0xfb, 0xc0, 0x18, 0x94, 0xf2, 0xe1, 0xe5, 0xe9, 0x5d,
    0xd0, 0xdc, 0x11, 0x66, 0x64, 0x5c, 0xec, 0x59, 0x42, 0x75, 0x12, 0xf5, 0x74, 0x9c, 0xaa, 0x23,
    0x0e, 0x86, 0xab, 0xbe, 0x2a, 0x02, 0xe7, 0x67, 0xe6, 0x44, 0xa2, 0x6c, 0xc2, 0x93, 0x9f, 0xf1,
    0xf6, 0xfa, 0x36, 0xd2, 0x50, 0x68, 0x9e, 0x62, 0x71, 0x15, 0x3d, 0xd6, 0x40, 0xc4, 0xe2, 0x0f,
    0x8e, 0x83, 0x77, 0x6b, 0x25, 0x05, 0x3f, 0x0c, 0x30, 0xea, 0x70, 0xb7, 0xa1, 0xe8, 0xa9, 0x65,
    0x8d, 0x27, 0x1a, 0xdb, 0x81, 0xb3, 0xa0, 0xf4, 0x45, 0x7a, 0x19, 0xdf, 0xee, 0x78, 0x34, 0x60
};

const uint8_t S1[256] = {
    0x55, 0xc2, 0x63, 0x71, 0x3b, 0xc8, 0x47, 0x86, 0x9f, 0x3c, 0xda, 0x5b, 0x29, 0xaa, 0xfd, 0x77,
    0x8c, 0xc5, 0x94, 0x0c, 0xa6, 0x1a, 0x13, 0x00, 0xe3, 0xa8, 0x16, 0x72, 0x40, 0xf9, 0xf8, 0x42,
    0x44, 0x26, 0x68, 0x96, 0x81, 0xd9, 0x45, 0x3e, 0x10, 0x76, 0xc6, 0xa7, 0x8b, 0x39, 0x43, 0xe1,
    0x3a, 0xb5, 0x56, 0x2a, 0xc0, 0x6d, 0xb3, 0x05, 0x22, 0x66, 0xbf, 0xdc, 0x0b, 0xfa, 0x62, 0x48,
    0xdd, 0x20, 0x11, 0x06, 0x36, 0xc9, 0xc1, 0xcf, 0xf6, 0x27, 0x52, 0xbb, 0x69, 0xf5, 0xd4, 0x87,
    0x7f, 0x84, 0x4c, 0xd2, 0x9c, 0x57, 0xa4, 0xbc, 0x4f, 0x9a, 0xdf, 0xfe, 0xd6, 0x8d, 0x7a, 0xeb,
    0x2b, 0x53, 0xd8, 0x5c, 0xa1, 0x14, 0x17, 0xfb, 0x23, 0xd5, 0x7d, 0x30, 0x67, 0x73, 0x08, 0x09,
    0xee, 0xb7, 0x70, 0x3f, 0x61, 0xb2, 0x19, 0x8e, 0x4e, 0xe5, 0x4b, 0x93, 0x8f, 0x5d, 0xdb, 0xa9,
    0xad, 0xf1, 0xae, 0x2e, 0xcb, 0x0d, 0xfc, 0xf4, 0x2d, 0x46, 0x6e, 0x1d, 0x97, 0xe8, 0xd1, 0xe9,
    0x4d, 0x37, 0xa5, 0x75, 0x5e, 0x83, 0x9e, 0xab, 0x82, 0x9d, 0xb9, 0x1c, 0xe0, 0xcd, 0x49, 0x89,
    0x01, 0xb6, 0xbd, 0x58, 0x24, 0xa2, 0x5f, 0x38, 0x78, 0x99, 0x15, 0x90, 0x50, 0xb8, 0x95, 0xe4,
    0xd0, 0x91, 0xc7, 0xce, 0xed, 0x0f, 0xb4, 0x6f, 0xa0, 0xcc, 0xf0, 0x02, 0x4a, 0x79, 0xc3, 0xde,
    0xa3, 0xef, 0xea, 0x51, 0xe6, 0x6b, 0x18, 0xec, 0x1b, 0x2c, 0x80, 0xf7, 0x74, 0xe7, 0xff, 0x21,
    0x5a, 0x6a, 0x54, 0x1e, 0x41, 0x31, 0x92, 0x35, 0xc4, 0x33, 0x07, 0x0a, 0xba, 0x7e, 0x0e, 0x34,
    0x88, 0xb1, 0x98, 0x7c, 0xf3, 0x3d, 0x60, 0x6c, 0x7b, 0xca, 0xd3, 0x1f, 0x32, 0x65, 0x04, 0x28,
    0x64, 0xbe, 0x85, 0x9b, 0x2f, 0x59, 0x8a, 0xd7, 0xb0, 0x25, 0xac, 0xaf, 0x12, 0x03, 0xe2, 0xf2
};
const uint32_t EK_d[16] = {
    0x44D7, 0x26BC, 0x626B, 0x135E, 0x5789, 0x35E2, 0x7135, 0x09AF,
    0x4D78, 0x2F13, 0x6BC4, 0x1AF1, 0x5E26, 0x3C4D, 0x789A, 0x47AC
};
uint32_t LFSR_S[16] = {0};
uint32_t F_R[2] = {0};
uint32_t BRC_X[4] = {0};
int w = 0;



uint32_t* string_to_uint32_array(const char* input, int* out_len) {

    int len = strlen(input);

    int num_uint32 = (len + 3) / 4;

    uint32_t* uint32_array = (uint32_t*)malloc(num_uint32 * sizeof(uint32_t));

    for (int i = 0; i < num_uint32; i++) {
        uint32_array[i] = 0;
    }

    for (int i = 0; i < len; i++) {
        uint32_array[i / 4] |= (uint32_t)(uint8_t)input[i] << (8 * (3 - (i % 4)));
    }

    *out_len = num_uint32;

    return uint32_array;
}
void hex_to_uint32(const char *hex, uint32_t* array) {
    for(int i=0;i<strlen(hex)/8;i++)
        array[i]=0;
    for (int i = 0; i < strlen(hex)/2; i++) {
        uint32_t value;
        if(hex[2*i]<='9')
            value=hex[i*2]-'0';
        else if(hex[2*i]>='a')
            value=hex[i*2]-'a'+10;
        else value=hex[i*2]-'A'+10;
        if(hex[2*i+1]<='9')
            value= value*16 + hex[i*2+1]-'0';
        else if(hex[2*i+1]>='a')
            value=value*16 + hex[i*2+1]-'a'+10;
        else value=value*16 + hex[i*2+1]-'A'+10;
        array[i/4] = (array[i/4]<<8) | value;
    }

}
void generateIV(uint8_t* iv, int length) {
    srand(time(NULL));
    for (int i = 0;i < length;i++)
        iv[i] = rand() % 256;
}
void bytes_to_arr_uint32(BYTE* bytes, int bytes_len, uint32_t* output){
    for(int i=0;i<bytes_len/4;i++)
        output[i]=0;
    for(int i=0;i<bytes_len;i++)
        output[i/4]= (output[i/4]<<8) | (uint32_t)bytes[i];
}
char* uint32_array_to_string(uint32_t* input, int inp_len) {
    char* output = (char*)malloc(inp_len * 4 + 1);
    output[inp_len * 4] = 0;
    for (int i = 0; i < inp_len * 4;i++) {
        output[i] = (char)((input[i / 4] >> (24 - (i % 4) * 8)) & 0XFF);
    }
    return output;
}
void hex_to_bytes(char* hex, BYTE* output){
  for(int i=0;hex[i]!=0;i++){
    if(hex[i]<='9')
      output[i/2]=hex[i]-'0';
    else if(hex[i]>='a')
      output[i/2]=hex[i]-'a'+10;
    else
      output[i/2]=hex[i]-'A'+10;
    i++;
    if(hex[i]<='9')
      output[i/2]=output[i/2]*16+hex[i]-'0';
    else if(hex[i]>='a')
      output[i/2]=output[i/2]*16+hex[i]-'a'+10;
    else
      output[i/2]=output[i/2]*16+hex[i]-'A'+10;
  }
}
void uint32_arr_to_hex(uint32_t* arr, int inpLen, char* hex){
    hex[inpLen*8]=0;
    for (int i = 0; i < inpLen * 4;i++) {
        BYTE value = (BYTE)((arr[i / 4] >> (24 - (i % 4) * 8)) & 0XFF);
        sprintf_s(hex + i*2, 3, "%02x", value);
    }
}
void bytes_to_hex(const BYTE* bytes, DWORD bytes_len, char* hex_output) {
    for (DWORD i = 0; i < bytes_len; i++) {
        sprintf_s(hex_output + (i * 2), 3, "%02x", bytes[i]);
    }
    hex_output[bytes_len * 2] = '\0';
}
/** c = a + b mod (2^31 – 1) */
uint32_t AddM(uint32_t a, uint32_t b) {
    uint32_t c = a + b;
    c = (c & MASK) + (c >> 31);
    return c;
}

/** Rotate left by k bits */
uint32_t ROT(uint32_t a, int k) {
    return (a << k) | (a >> (32 - k));
}

/** Multiply by 2^k with rotation and mask */
uint32_t MulByPow2(uint32_t x, int k) {
    return ((x << k) | (x >> (31 - k))) & MASK;
}

/** LFSR with initialization mode */
void LFSRWithInitialisationMode(uint32_t u) {
    uint32_t f = 0;
    uint32_t v = 0;

    f = LFSR_S[0];
    v = MulByPow2(LFSR_S[0], 8);
    f = AddM(f, v);

    v = MulByPow2(LFSR_S[4], 20);
    f = AddM(f, v);

    v = MulByPow2(LFSR_S[10], 21);
    f = AddM(f, v);

    v = MulByPow2(LFSR_S[13], 17);
    f = AddM(f, v);

    v = MulByPow2(LFSR_S[15], 15);
    f = AddM(f, v);

    f = AddM(f, u);

    // Update the state
    for (int i = 0; i < 15; i++) {
        LFSR_S[i] = LFSR_S[i + 1];
    }
    LFSR_S[15] = f;
}

/** LFSR with work mode */
void LFSRWithWorkMode() {
    uint32_t f = 0;
    uint32_t v = 0;

    f = LFSR_S[0];
    v = MulByPow2(LFSR_S[0], 8);
    f = AddM(f, v);

    v = MulByPow2(LFSR_S[4], 20);
    f = AddM(f, v);

    v = MulByPow2(LFSR_S[10], 21);
    f = AddM(f, v);

    v = MulByPow2(LFSR_S[13], 17);
    f = AddM(f, v);

    v = MulByPow2(LFSR_S[15], 15);
    f = AddM(f, v);

    // Update the state
    for (int i = 0; i < 15; i++) {
        LFSR_S[i] = LFSR_S[i + 1];
    }
    LFSR_S[15] = f;
}

/** Bit Reorganization
 * It extracts 128 bits from the cells of the LFSR and forms 4 of 32-bit words,
 * where the first three words will be used by the nonlinear function F in the bottom layer,
 * and the last word will be involved in producing the keystream.
 */
void BitReorganization() {
    BRC_X[0] = (((LFSR_S[15] & 0x7FFF8000) << 1) | (LFSR_S[14] & 0xFFFF));
    BRC_X[1] = (((LFSR_S[11] & 0xFFFF) << 16) | (LFSR_S[9] >> 15));
    BRC_X[2] = (((LFSR_S[7] & 0xFFFF) << 16) | (LFSR_S[5] >> 15));
    BRC_X[3] = (((LFSR_S[2] & 0xFFFF) << 16) | (LFSR_S[0] >> 15));
}

/** Both L1 and L2 are linear transforms from 32-bit words to 32-bit words */
uint32_t L1(uint32_t x) {
    return x ^ ROT(x, 2) ^ ROT(x, 10) ^ ROT(x, 18) ^ ROT(x, 24);
}

uint32_t L2(uint32_t X) {
    return X ^ ROT(X, 8) ^ ROT(X, 14) ^ ROT(X, 22) ^ ROT(X, 30);
}

/** Function to make a 32-bit word from four 8-bit values */
uint32_t MAKEU32(uint8_t a, uint8_t b, uint8_t c, uint8_t d) {
    return ((uint32_t)a << 24) | ((uint32_t)b << 16) | ((uint32_t)c << 8) | ((uint32_t)d);
}

/** The nonlinear function F has 2 of 32-bit memory cells R1 and R2 */
uint32_t F_func() {
    uint32_t W, W1, W2;
    uint32_t u, v;
    const uint32_t MASK1 = 0xFF;

    W = (BRC_X[0] ^ F_R[0]) + F_R[1];
    W1 = F_R[0] + BRC_X[1];
    W2 = F_R[1] ^ BRC_X[2];

    u = L1(((W1 << 16) | (W2 >> 16)));
    v = L2(((W2 << 16) | (W1 >> 16)));

    F_R[0] = MAKEU32(S0[(u >> 24) & 0xFF],
                    S1[(u >> 16) & MASK1],
                    S0[(u >> 8) & MASK1],
                    S1[u & MASK1]);

    F_R[1] = MAKEU32(S0[(v >> 24) & 0xFF],
                    S1[(v >> 16) & MASK1],
                    S0[(v >> 8) & MASK1],
                    S1[v & MASK1]);

    return W;
}

/** Function to make a 31-bit LFSR value from a, b, c */
uint32_t MAKEU31(uint8_t a, uint16_t b, uint8_t c) {
    return ((uint32_t)a << 23) | ((uint32_t)b << 8) | ((uint32_t)c);
}

/** Initialize LFSR with Key and IV */
void init_LFSR_key_exp(const uint8_t k[16], const uint8_t iv[16]) {
    for (int i = 0; i < 16; i++) {
        LFSR_S[i] = MAKEU31(k[i], EK_d[i], iv[i]) & MASK;
    }
}

/** Initialization stage */
void Initialization(const uint8_t k[16], const uint8_t iv[16]) {
    init_LFSR_key_exp(k, iv);

    // Set F_R1 and F_R2 to zero
    F_R[0] = 0;
    F_R[1] = 0;

    int nCount = 32;

    while (nCount > 0) {
        BitReorganization();
        w = F_func();
        LFSRWithInitialisationMode(w >> 1);
        nCount--;
    }
}

/** Generate Keystream */
uint32_t* GenerateKeystream(int KeystreamLen) {
    uint32_t* pKeystream = (uint32_t*)calloc(KeystreamLen, sizeof(uint32_t));
    if (pKeystream == NULL) {
        printf("Memory allocation failed.\n");
        exit(1);
    }

    // Initial step
    BitReorganization();
    F_func(); // Discard the output of F
    LFSRWithWorkMode();

    for (int i = 0; i < KeystreamLen; i++) {
        BitReorganization();
        pKeystream[i] = F_func() ^ BRC_X[3];
        LFSRWithWorkMode();
    }

    return pKeystream;
}
void generateKey256(char* key, int length) {
    srand(time(NULL));
    for (int i = 0;i < length*2;i++){
      int r = rand() % 256;
      if(r/16<=9)
        key[i]=r/16+'0';
      else
        key[i]=r/16+'A'-10;
      i++;
      if(r%16<=9)
        key[i]=r%16+'0';
      else
        key[i]=r%16+'A'-10;
    }
    key[length*2]=0;
}
char* encryptZuc128(char* keyHex, char plaintext[500]){
    uint8_t* key=(uint8_t*)malloc(16);
    uint8_t* iv=(uint8_t*)malloc(16);
    hex_to_bytes(keyHex, key);
    generateIV(iv,16);
    Initialization(key, iv);
    uint32_t* data;
    int length;
    data = string_to_uint32_array(plaintext, &length);
    uint32_t* keystream = GenerateKeystream(length);
    for(int i =0;i<length;i++)
      data[i] ^= keystream[i];
    
    char* ivHex=(char*)malloc(33);
    bytes_to_hex(iv, 16, ivHex);
    char* ciphertext = (char*) malloc(length*8+33);
    memcpy(ciphertext, ivHex, 32);
    uint32_arr_to_hex(data, length, ciphertext+32);
    return ciphertext;

}
char* decryptZuc128(char* keyHex, char* ciphertext) {
    uint8_t* key=(uint8_t*)malloc(16);
    uint8_t* iv =(uint8_t*)malloc(16);
    char* ivHex=(char*)malloc(33);
    memcpy(ivHex, ciphertext, 32);
    ivHex[32]=0;
    ciphertext+=32;
    hex_to_bytes(ivHex, iv);
    hex_to_bytes(keyHex, key);
    Initialization(key, iv);

    int length=strlen(ciphertext)/4;
    uint32_t* data=(uint32_t*)malloc(length*4+1);
    hex_to_uint32(ciphertext, data);
    uint32_t* keystream = GenerateKeystream(length);
    for (int i = 0; i < length; i++) {
        data[i] ^= keystream[i];
    }

    char* result = uint32_array_to_string(data,length);
    return result;
}
int main() {
    char* key = (char*) malloc (33);
    generateKey256(key,16);
    char plaintext[100]="hellooooooaaaaaawwwwwwwwwwwwwwweeeeeeeawwwqd";
    char *ciphertext;
    ciphertext=encryptZuc128(key,plaintext);
    char *plaintext2 = decryptZuc128(key,ciphertext);
    printf("%s\n%s",ciphertext,plaintext2);
    return 0;
}
Editor is loading...
Leave a Comment