user45698746
user45698746

Reputation: 325

How to cast a char array into a structure?

I'm trying to read RSA private keys from a file into a structure. I'm using mpi_read_string() to load these keys into RSA context. Therefore, each individual keys has to be null-terminated. To achieve this upon reading each keys from the file, I concatenate \0 at the end of each keys.

In summary, I read all the content of a file into an unsigned char * buffer, tokenize each line, concatenate \0 at the end of each line, and store it into unsigned char no_label_key_array[]. I also have a structure struct RSA_KEY. I'm trying to assign this unsigned char no_label_key_array[] into the structure.

rsa_priv.txt contains the following,

N = D0C2ACDCF780B1E4846054BDA700F18D567247FE8BC5BA4FBCAB814E619DA63A20F65A58EE89FC0824DC9367C5725BDDC596065F1C8868E99C896F3A0CF7D7F0A785E668F2568F19BAFB8FF3BA5CDF487544EFE71010BEDB4EE16EDC3AF0A71391AD3194B42D3FD40B4E0DE12A22D8188AF03FF4E36D37BA1DA1F3C57188E60DA38C25329E48805FC7FF524761A6F010E737B927D8F67383274F8E600167A52A042E1DCA3335150C090803F9D96F6E63BEBFB153516E863F5B4CB02104077834FC5EC31A47451783931D643CE736DD1BAB40C5523858BB067FB9E490DCB5FDBBB03B9D68A8998C1347E237C477AA14B0997A84708CED05A9E24C7072B838F753
E = 010001
D = 21AFE07431CE47269083F8F8B7ABCBCEDA6DCB975457BE6662942C64091586FEE755C9A3832EAA0868665DB507A41A15F1EDF12E44ECF03D0E61111D457D730FA700D0FB0B6C13607C0F5F1DDDEB61AE9019E53A9C998F2AD5924430EEA3E9DA1B0E5F2B575DDBE86C4096B5C87661F7A7E7F7F21D0701509BBA881B4AE463F6F18C7F04AB742319E2D7319EECA136EEB0CF7B2BFA87E3A0E69FBC0E5FDC7EE6271EB2CA09DDBF7C8B57D951762708D76890E62858C1D5FC5B7E40D50913CE7797BD80F6A398FB92703FBDD33FBCB129B86E54F13EC14DA68BE139634DD1E9C01F01751C427B029AF629EED23C99726F0A0C3CEA1229E4099B588CE676975D25
P = FD1120F3E183DF72779B9B4A29FF9157C89FF8204988B6FB1211642B4D59B6A1BB306E81C040F0F822B41765FC4435A46B5090700E72B9720481EACF3624885D7A263CAC0CA559954E9382FCC7D57221CD9394C64585653664976174CAE2E7DC6A7B03DE09599B5D9501927ACC4EED5F5CBC5870E31A051AF9842945A0168E35
Q = D32E15E032B256C7DE0BDB585379EB897343ABFB8C7A86A3D798C13AE3E3F048A50DA9D7C31EB65A588CF6B9911F7B41D6F154F99B4F64839E110C30BA4B79286A4A3A3F7F0169A1D3A21F0D084CFA423E04C90C5966AC391A47F10E823C71B9716856B05BC12160DF0BA96300F8ADDC0D59E54E9CBDC7AC0EA6747DBA46C067
DP = 2004DECA7CAA16C780E2AB4F42E91716A847B53940948FB24CA2EEAD9BE7D1F7BC9B701FF29744E5E05E30E7B2775EE222C1DAC492CF692F47EAB82EE786CFCA23FE5A86DA42C186E69E3B608858354C999A26A4BF7F1543408EF6C1B439E9643604C2848162590A0A245CC834B977C72D10979010EBE5E177D884F04E450C51
DQ = 9A035E48E8305041EB9AD21994A7B233C8306E59429689632C7567573FA4993521CAD93756422BD3B008FE574F939A1CE659931387455B94F1CE950964946E841F208B628B89C83411588734C5FCFDF719ABFBC459DF1B7379CB45EEC2E4BA3BF88D93CB82DF532C86FEC646420B1B21054BAE84AAA36DDFF9BF43EDFDD063B9
QP = E7A5BC150E6A20E52920C6F24FC872B1893ED9268AA506D86EC3AA6E3B377E5F6AE0D686751CE40F684435C6F64F31888861389CE430FB271EE81D0067ED8A1BD8096FB3E4AF5839383F26F99916EED4D80CFA9B5901350A9C0AAD4E348EBCC559F92434C71DA864C13371626D9F29998748BB3C47BED31471B73ABF2E27B983

I have the following code,

#include<stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#define KEY_LEN 256

typedef struct RSA_KEY{
    unsigned char N[KEY_LEN];
    unsigned char E[KEY_LEN];
    unsigned char D[KEY_LEN];
    unsigned char P[KEY_LEN];
    unsigned char Q[KEY_LEN];
    unsigned char DP[KEY_LEN];
    unsigned char DQ[KEY_LEN];
    unsigned char QP[KEY_LEN];
}RSA_, *RSA_PTR;


int main(){

    int j;
    unsigned char * buffer = 0;
    long length;
    FILE * fp = fopen ("rsa_priv.txt", "rb");

    if (fp){
        fseek (fp, 0, SEEK_END);
        length = ftell (fp);
        fseek (fp, 0, SEEK_SET);
        buffer = calloc (1,length+1);
        if (buffer){
            fread (buffer, 1, length, fp);
        }
        fclose (fp);
    }


    // removing label from the keys
    // tokenize key and read into rsa context
    const char s[3] = "= ";
    char *token;
    int k=0, size_tok;

    char n='\0';

    // following buffer will hold the private key without any level
    unsigned char *final_token= calloc(1, length+1);

    // get the first token
    token = strtok(buffer, s);

    // walk through other tokens
    while( token != NULL ) {
        size_tok = strlen(token);

        switch (k) {
            case 1: 
                strncat(token, &n,1);
                strcat(final_token,token);
                break;

            case 3:
                strncat(token, &n,1);
                strcat(final_token,token);
                break;

            case 5:
                strncat(token, &n,1);
                strcat(final_token,token);
                break;

            case 7:
                strncat(token, &n,1);
                strcat(final_token,token);
                break;

            case 9:
                strncat(token, &n,1);
                strcat(final_token,token);
                break;

            case 11:
                strncat(token, &n,1);
                strcat(final_token,token);
                break;

            case 13:
                strncat(token, &n,1);
                strcat(final_token,token);
                break;

            case 15:
                strncat(token, &n,1);
                strcat(final_token,token);
                break;
        }
        k=k+1;
        token = strtok(NULL, "= \n");
    }

    //printf("RSA keys without label \n %s",final_token);


    // coping final token to a char array,
    unsigned char no_label_key_array[strlen(final_token)];
    memcpy(no_label_key_array,final_token,sizeof(no_label_key_array));
    //printf("no_label_key_array \n %s",no_label_key_array);


    // assigning char array to a structure
    RSA_PTR rsa_ptr;
    rsa_ptr = (RSA_PTR)no_label_key_array;

    printf("rsa_ptr.N--> %s\n",rsa_ptr->N);
    printf("\n");
    printf("rsa_ptr.E--> %s\n",rsa_ptr->E);
    printf("\n");
    printf("rsa_ptr.DQ--> %s\n",rsa_ptr->DQ);
    printf("\n");
    printf("rsa_ptr.QP--> %s\n",rsa_ptr->QP);

    return 0;
}

This code generates the following output:

rsa_ptr.N--> D0C2ACDCF780B1E4846054BDA700F18D567247FE8BC5BA4FBCAB814E619DA63A20F65A58EE89FC0824DC9367C5725BDDC596065F1C8868E99C896F3A0CF7D7F0A785E668F2568F19BAFB8FF3BA5CDF487544EFE71010BEDB4EE16EDC3AF0A71391AD3194B42D3FD40B4E0DE12A22D8188AF03FF4E36D37BA1DA1F3C57188E60DA38C25329E48805FC7FF524761A6F010E737B927D8F67383274F8E600167A52A042E1DCA3335150C090803F9D96F6E63BEBFB153516E863F5B4CB02104077834FC5EC31A47451783931D643CE736DD1BAB40C5523858BB067FB9E490DCB5FD21AFE07431CE47269083F8F8B7ABCBCEDA6DCB975457BE6662942C64091586FEE755C9A3832EAA0868665DB507A41A15F1EDF12E44ECF03D0E61111D457D730FA700D0FB0B6C13607C0F5F1DDDEB61AE9019E53A9C998F2AD5924430EEA3E9DA1B0E5F2B575DDBE86C4096B5C87661F7A7E7F7F21D0701509BBA881B4AE463F6F18C7F04AB742319E2D7319EECA136EEB0CF7B2BFA87E3A0E69FBC0E5FDC7EE6271EB2CA09DDBF7C8B57D951762708D76890E62858C1D5FC5B7E40D50913CE7797BD80F6A398FB92703FBDD33FBCB129B86E54F13EC14DA68BE139634DD1E9C01F01751C427FD1120F3E183DF72779B9B4A29FF9157C89FF8204988B6FB1211642B4D59B6A1BB306E81C040F0F822B41765FC4435A46B5090700E72B9720481EACF3624885D7A263CAC0CA559954E9382FCCD32E15E032B256C7DE0BDB585379EB897343ABFB8C7A86A3D798C13AE3E3F048A50DA9D7C31EB65A588CF6B9911F7B41D6F154F99B4F64839E110C30BA4B79286A4A3A3F7F0169A1D3A21F0D02004DECA7CAA16C780E2AB4F42E91716A847B53940948FB24CA2EEAD9BE7D1F7BC9B701FF29744E5E05E30E7B2775EE222C1DAC492CF692F47EAB82EE786CFCA23FE5A86DA42C186E69E3B6089A035E48E8305041EB9AD21994A7B233C8306E59429689632C7567573FA4993521CAD93756422BD3B008FE574F939A1CE659931387455B94F1CE950964946E841F208B628B89C83411588734CE7A5BC150E6A20E52920C6F24FC872B1893ED9268AA506D86EC3AA6E3B377E5F6AE0D686751CE40F684435C6F64F31888861389CE430FB271EE81D0067ED8A1BD8096FB3E4AF5839383F26F99916EED4D80CFA9B5901350A9C0AAD4E348EBCC559F92434C71DA864C13371626D9F29998748BB3C47BED31471B73ABF2E27B983

rsa_ptr.E--> A38C25329E48805FC7FF524761A6F010E737B927D8F67383274F8E600167A52A042E1DCA3335150C090803F9D96F6E63BEBFB153516E863F5B4CB02104077834FC5EC31A474521AFE07431CE47269083F8F8B7ABCBCEDA6DCB975457BE6662942C64091586FEE755C9A3832EAA0868665DB507A41A15F1EDF12E44ECF03D0E61111D457D730FA700D0FB0B6C13607C0F5F1DDDEB61AE9019E53A9C998F2AD5924430EEA3E9DA1B0E5F2B575DDBE86C4096B5C87661F7A7E7F7F21D0701509BBA881B4AE463F6F18C7F04AB742319E2D7319EECA136EEB0CF7B2BFA87E3A0E69FBC0E5FDC7EE6271EB2CA09DDBF7C8B57D951762708D76890E62858C1D5FC5B7E40D50913CE7797BD80F6A398FB92703FBDD33FBCB129B86E54F13EC14DA68BE139634DD1E9C01F01751C427FD1120F3E183DF72779B9B4A29FF9157C89FF8204988B6FB1211642B4D59B6A1BB306E81C040F0F822B41765FC4435A46B5090700E72B9720481EACF3624885D7A263CAC0CA559954E9382FCCD32E15E032B256C7DE0BDB585379EB897343ABFB8C7A86A3D798C13AE3E3F048A50DA9D7C31EB65A588CF6B9911F7B41D6F154F99B4F64839E110C30BA4B79286A4A3A3F7F0169A1D3A21F0D02004DECA7CAA16C780E2AB4F42E91716A847B53940948FB24CA2EEAD9BE7D1F7BC9B701FF29744E5E05E30E7B2775EE222C1DAC492CF692F47EAB82EE786CFCA23FE5A86DA42C186E69E3B6089A035E48E8305041EB9AD21994A7B233C8306E59429689632C7567573FA4993521CAD93756422BD3B008FE574F939A1CE659931387455B94F1CE950964946E841F208B628B89C83411588734CE7A5BC150E6A20E52920C6F24FC872B1893ED9268AA506D86EC3AA6E3B377E5F6AE0D686751CE40F684435C6F64F31888861389CE430FB271EE81D0067ED8A1BD8096FB3E4AF5839383F26F99916EED4D80CFA9B5901350A9C0AAD4E348EBCC559F92434C71DA864C13371626D9F29998748BB3C47BED31471B73ABF2E27B983

2004DECA7CAA16C780E2AB4F42E91716A847B53940948FB24CA2EEAD9BE7D1F7BC9B701FF29744E5E05E30E7B2775EE222C1DAC492CF692F47EAB82EE786CFCA23FE5A86DA42C186E69E3B6089A035E48E8305041EB9AD21994A7B233C8306E59429689632C7567573FA4993521CAD93756422BD3B008FE574F939A1CE659931387455B94F1CE950964946E841F208B628B89C83411588734CE7A5BC150E6A20E52920C6F24FC872B1893ED9268AA506D86EC3AA6E3B377E5F6AE0D686751CE40F684435C6F64F31888861389CE430FB271EE81D0067ED8A1BD8096FB3E4AF5839383F26F99916EED4D80CFA9B5901350A9C0AAD4E348EBCC559F92434C71DA864C13371626D9F29998748BB3C47BED31471B73ABF2E27B983

9A035E48E8305041EB9AD21994A7B233C8306E59429689632C7567573FA4993521CAD93756422BD3B008FE574F939A1CE659931387455B94F1CE950964946E841F208B628B89C83411588734CE7A5BC150E6A20E52920C6F24FC872B1893ED9268AA506D86EC3AA6E3B377E5F6AE0D686751CE40F684435C6F64F31888861389CE430FB271EE81D0067ED8A1BD8096FB3E4AF5839383F26F99916EED4D80CFA9B5901350A9C0AAD4E348EBCC559F92434C71DA864C13371626D9F29998748BB3C47BED31471B73ABF2E27B983

Sorry, that I could not format the output into a single block.

From the output, I can see that even after concatenating \0 my outputs are not right?

So my question is, am I concatenating correctly? and Can I cast an unsigned char array to a structure like the way I did? If not, how can I do that?

Upvotes: 0

Views: 239

Answers (1)

Lundin
Lundin

Reputation: 213513

You have several bugs:

  • You aren't using strings correctly here: unsigned char no_label_key_array[strlen(final_token)]; This is a very common FAQ that we get almost every day. Please read How should character arrays be used as strings?
  • rsa_ptr = (RSA_PTR)no_label_key_array is a strict aliasing violation. You can't convert wildly between types like this. What is the strict aliasing rule? The solution is to put your struct in a union together with a raw unsigned char array of the same size as the struct.

Other issues:

  • It is very bad practice to hide pointers behind typedef. It achieves absolutely nothing but turns your code harder to read. RSA* is ideal C code, a typedef RSA_PTR will only make it worse.

  • The switch can be replaced with a look-up table, for reduced code repetition, increased readability and performance, like this:

      unsigned int k; // needs to be unsigned
      const bool accepted [16] =
      {
        [ 1] = true, [ 3] = true, [ 5] = true,  [ 7] = true,
        [ 9] = true, [11] = true, [13] = true,  [15] = true,
      };
      ... // assign something to k   
    
      if(k<16 && accepted[k]) // replace the whole switch with this
      {
        strncat(token, &n,1);
        strcat(final_token,token);
      }
    

Upvotes: 2

Related Questions