void encode(char *msg, char *img, char *out_filename) { unsigned char *data, *enc_data, *final_data; char *filename = 0; int len, plen, final_len; FILE *fp = fopen(msg, "rb"); // Not saving the last null byte (in legal C strings) in either case // because all the chars are going into the image if (!fp) { len = strlen(msg); data = malloc(len); memcpy(data, msg, len); } else { filename = basename(msg); int fplen = strlen(filename)+1; // 1 for the colon char fprefix[fplen]; sprintf(fprefix, "%s:", filename); // Read the file to data fseek(fp, 0, SEEK_END); int file_len = ftell(fp); len = fplen + file_len; rewind(fp); data = malloc(len); // all chars are 1 byte int read_size = fread(data, 1, file_len, fp); if (file_len != read_size) Error("Error reading file"); // Prepend filename with colons (filenames can't have colons) // Filename gets encrypted too memmove(data+fplen, data, file_len); memcpy(data, fprefix, fplen); } fclose(fp); // Encrypt the data enc_data = aes_encrypt(&en, data, &len); // len gets updated here ^ to the new len of the encrypted data free(data); // Don't need this anymore plen = digits(len)+1; char prefix[plen]; sprintf(prefix, filename ? "%d>" : "%d<", len); // The different symbols are to differentiate between file data and plaintext final_len = plen + len; int padding = 3 - (final_len % 3); // Data needs to be divisible by 3 before being put // into the image int padded_len = final_len + padding; final_data = malloc(padded_len); memcpy(final_data, enc_data, len); free(enc_data); // All we need now is the final data // Prepend the encrypted data with the prefix of how long // it is so we know where to stop when decoding memmove(final_data+plen, final_data, len); memcpy(final_data, prefix, plen); // Last, add the padding of null bytes to make it divisible by 3 // Note: this will get removed in the end because // we keep the size not including the padding. We need to have it divisibile by 3 because // if we have 2 bits left of data, we need to store it in 1 whole pixel, which holds // 6 possible bits of information for (int i = final_len; i < padded_len; i++) final_data[i] = '\0'; // Checking if possible read_png_file(img); int space = (width * height) * (3.0f / 4.0f); if (padded_len > space) { // Make sure there is enough space in the image for the data puts("Not enough space in image."); char *rspace; rspace = byteconvert(padded_len); printf("Data size: %s\n", rspace); free(rspace); rspace = byteconvert(space); printf("Space available: %s\n", rspace); free(rspace); exit(1); } // Loop through all the data, 3 bytes at a time, // putting every 3 bytes into groups of 4 pixels // (8 bits for 3 bytes is 24 total bits, 6 bits for each of // 4 pixels (matching of total 24)) int pixel_loc = 0; int x, y; png_byte* pixel; for (int i = 0; i < padded_len; i += 3, pixel_loc += 4) { // next group of pixels every loop, so add 4 each time // Loop for each color component and for each byte of data // (3 of each) // Each byte has 8 bits, 2 of each go into each of the 4 pixels for (int j = 0; j < 3; j++, pixel_loc -= 4) { // reset to continue looping through the same pixels every time by doing -= 4 // Loop for each of 4 pixels to put the data into for (int p = 0; p < 4; p++, pixel_loc++) { x = pixel_loc % width, y = pixel_loc / width; pixel = &(row_pointers[y][x*3]); // j for color component // Replace last 2 bits with zeros pixel[j] &= ~3; int sh = p * 2; // Add 2 bits of data at a time pixel[j] |= ((int)final_data[i + j] & (3 << sh)) >> sh; // & 3 gets only the last 2 bits of the data (1 byte) because // 3 is 00000011 in binary, // 3 << 2 is 00001100, 3 << 4 is 00110000, etc } } } // Save the image with the data inside it // (use output filename if specified, otherwsie just "new-image.png") if (out_filename) write_png_file(out_filename); else write_png_file("new-image.png"); free(final_data); // Done with this }
int main(int argc, char **argv) { // Argument parsing char usage[256]; char *pgrm = argv[0]; sprintf(usage, "\ Usage: %s -e [message/file] [image]\n\ %s -d [image]\n\ %s -s [image(s)]\ ", pgrm, pgrm, pgrm); if (argc == 1) Error(usage); char *options = "\n\ Options:\n\ -h Show this help message and exit\n\ -e Encode data into image\n\ -d Decode data from image\n\ -s Space available in image(s) (the higher the\n\ resolution, the more space available)\n\ -o When encoding, use this filename for the\n\ new image\ "; char *e_arg = 0, *d_arg = 0, *s_arg = 0, *o_arg = 0; int c; opterr = 0; while ((c = getopt(argc, argv, "hd:e:s:o:")) != -1) { switch(c) { case 'h': puts(usage); puts(options); return 0; break; case 'e': e_arg = optarg; break; case 'd': d_arg = optarg; break; case 's': s_arg = optarg; break; case 'o': o_arg = optarg; break; case '?': break; default: Error(usage); } } char (*last_args)[256] = malloc(256 * sizeof(*last_args)); int index = s_arg ? 1 : 0; if (optind < argc) { while (optind < argc) sprintf(last_args[index++], "%s", argv[optind++]); } if (s_arg) sprintf(last_args[0], "%s", s_arg); if (e_arg || d_arg) { if (e_arg && !index) Error(usage); // Prompt for password char *pass = getpass("Password for encoding:"); if (strcmp(pass, "") == 0) Error("No password entered."); // Prepare encryption and decryption: // The salt paramter is used as a salt in the derivation: // it should point to an 8 byte buffer or NULL if no salt is used. unsigned char salt[] = {1, 2, 3, 4, 5, 6, 7, 8}; unsigned char *key_data = (unsigned char *) pass; int key_data_len = strlen(pass); // Gen key and iv. init the cipher ctx object if (aes_init(key_data, key_data_len, salt, &en, &de)) Error("Error initializing AES cipher"); } // Encode if (e_arg) encode(e_arg, last_args[0], o_arg); // Decode else if (d_arg) decode(d_arg); // Print space in image(s) else if (s_arg) { puts("Space available in image(s):"); for (int i = 0; i < index; i++) { read_png_file(last_args[i]); int space = (width * height) * (3.0f / 4.0f); space -= 256+ AES_BLOCK_SIZE +12; // 256 for filename char *rspace = byteconvert(space); printf("%s: %s\n", basename(last_args[i]), rspace); free(rspace); } } else Error(usage); if (opterr) return 1; // Cleanup free(last_args); aes_clean(); png_clean(); return 0; }
/* Perform interpolation, if necessary, to derive the final output value for this obsmode from the appropriate row. */ double ComputeValue(PhtRow *tabrow, PhotPar *obs) { /* Parameters: PhtRow *tabrow: values read from matching row of table char *obsmode: full obsmode string from header obsmode string needs to contain values of parameterized values appropriate for this observation. */ double value; int parnum; int n,p, nx, ndim; double *out; double *obsindx; /* index of each obsmode par value in tabrow->parvals */ double *obsvals; /* value for each obsmode par in the same order as tabrow */ int *ndpos; int **bounds; /* [ndim,2] array for bounds around obsvals values */ double resvals[2]; /* Values from tabrow->results for interpolation */ double resindx[2]; /* 1-D indices into tabrow->results for bounding positions*/ int posindx; /* N dimensional array of indices for a position */ int indx,pdim,ppos,xdim,xpos; int tabparlen; /* intermediate products used in iterating over dims */ int iter, x; int dimpow,iterpow; double *ndposd; int b0,b1,pindx; int deltadim; /* index of varying dimension */ double bindx[2],bvals[2]; /* indices into results array for bounding values */ double rinterp; /* placeholder for interpolated result */ BoundingPoint **points; /* array of bounding points defining the area of interpolation */ /* Define functions called in this functions */ double linterp(double *, int, double *, double); void byteconvert(int, int *, int); int computedeltadim(BoundingPoint *, BoundingPoint *); long computeindex(int *, double *, int); void computebounds(double *, int, double, int *, int*); int strneq_ic(char *, char*, int); BoundingPoint **InitBoundingPointArray(int, int); void FreeBoundingPointArray(BoundingPoint **, int); /* Initialize variables and allocate memory */ value = 0.0; ndim = tabrow->parnum; if (ndim == 0) { /* No parameterized values, so simply return value stored in 1-element array results */ return(tabrow->results[0]); } dimpow = pow(2,ndim); obsindx = (double *)calloc(ndim, sizeof(double)); obsvals = (double *)calloc(ndim, sizeof(double)); /* Final answer */ ndpos = (int *)calloc(ndim, sizeof(int)); ndposd = (double *)calloc(ndim, sizeof(double)); bounds = (int **) calloc(ndim, sizeof(int *)); for (p=0;p<ndim;p++) bounds[p] = (int *) calloc(2, sizeof(int)); /* We have parameterized values, so linear interpolation will be needed in all dimensions to get correct value. Start by getting the floating-point indices for each parameterized value */ /* Start by matching up the obsmode parameters with those in the table row These are the values along each dimension of the interpolation */ for (p=0;p<ndim;p++){ tabparlen = strlen(tabrow->parnames[p]); for(n=0;n<obs->npar;n++){ if (strneq_ic(tabrow->parnames[p],obs->parnames[n],tabparlen)){ obsvals[p] = obs->parvalues[n]; break; } } if (obsvals[p] == 0.0) { printf("ERROR: No obsmode value found for %s\n",tabrow->parnames[p]); free(obsindx); free(obsvals); free(ndpos); free(ndposd); for (p=0;p<ndim;p++) free(bounds[p]); free(bounds); return ('\0'); } /* check whether we're going beyond the data in the table (extrapolation) */ /* if we are, return -9999 */ nx = tabrow->nelem[p+1]; if ((obsvals[p] < tabrow->parvals[p][0]) || (obsvals[p] > tabrow->parvals[p][nx-1])) { printf("WARNING: Parameter value %s%f is outside table data bounds.\n", tabrow->parnames[p],obsvals[p]); free(obsindx); free(obsvals); free(ndpos); free(ndposd); for (p=0;p<ndim;p++) free(bounds[p]); free(bounds); return -9999.0; } } /* Set up array of BoundingPoint objects to keep track of information needed for the interpolation */ points = InitBoundingPointArray(dimpow,ndim); /* Now find the index of the obsmode parameterized value into each parameterized value array Equivalent to getting positions in each dimension (x,y,...). */ for (p=0;p<ndim;p++){ nx = tabrow->nelem[p+1]; out = (double *) calloc(nx, sizeof(double)); for (n=0; n<nx;n++) out[n] = n; value = linterp(tabrow->parvals[p], nx, out, obsvals[p]); if (value == -99) { free(obsindx); free(obsvals); free(ndpos); free(ndposd); for (p=0;p<ndim;p++) free(bounds[p]); free(bounds); free(out); return('\0'); } obsindx[p] = value; /* Index into dimension p */ computebounds(out, nx, (double)floor(value), &b0, &b1); bounds[p][0] = b0; bounds[p][1] = b1; /* Free memory so we can use this array for the next variable*/ free(out); } /* End loop over each parameterized value */ /* Loop over each axis and perform interpolation to find final result For each axis, interpolate between all pairs of positions along the same axis An example with 3 parameters/dimensions for a point with array index (2.2, 4.7, 1.3): Iteration 1: for all z and y positions , interpolate between pairs in x (2,4,1)vs(3,4,1), (2,5,1)vs(3,5,1), (2,4,2)vs(3,4,2), and (2,5,2)vs(3,5,2) Iteration 2: for all z positions, interpolate between pairs from iteration 1 in y (2.2, 4,1)vs(2.2, 5, 1) and (2.2, 4, 2)vs(2.2, 5, 2) Iteration 3: interpolate between pairs from iteration 2 in z (2.2, 4.7, 1) vs (2.2, 4.7, 2) ==> final answer */ for (iter=ndim; iter >0; iter--) { iterpow = pow(2,iter); for (p=0;p < iterpow;p++){ pdim = floor(p/2); ppos = p%2; if (iter == ndim) { /* Initialize all intermediate products and perform first set of interpolations over the first dimension */ /* Create a bitmask for each dimension for each position */ byteconvert(p,ndpos,ndim); for (n=0;n<ndim;n++) { pindx = bounds[n][ndpos[n]]; points[pdim][ppos].index[n] = (double)pindx; points[pdim][ppos].pos[n] = tabrow->parvals[n][pindx]; } /* Determine values from tables which correspond to bounding positions to be interpolated */ indx = computeindex(tabrow->nelem, points[pdim][ppos].index, ndim); points[pdim][ppos].value = tabrow->results[indx]; } /* End if(iter==ndim) */ if (ppos == 1) { /* Determine which axis is varying, so we know which input value from the obsmode string we need to use for the interpolation */ deltadim = computedeltadim(&points[pdim][0],&points[pdim][1]); if (deltadim < 0 || deltadim >= ndim) { printf("ERROR: Deltadim out of range: %i\n",deltadim); free(obsindx); free(obsvals); free (ndpos); free (ndposd); for (p=0;p<ndim;p++)free(bounds[p]); free(bounds); return('\0'); } bindx[0] = points[pdim][0].pos[deltadim]; bindx[1] = points[pdim][1].pos[deltadim]; bvals[0] = points[pdim][0].value; bvals[1] = points[pdim][1].value; /*Perform interpolation now and record the results */ rinterp = linterp(bindx, 2, bvals,obsvals[deltadim]); /* Update intermediate arrays with results in preparation for the next iteration */ if (rinterp == -99) return('\0'); /* Determine where the result of this interpolation should go */ x = floor((p-1)/2); xdim = floor(x/2); xpos = x%2; /* update bpos and bindx for iteration over next dimension */ points[xdim][xpos].value = rinterp; for (n=0;n<ndim;n++) { points[xdim][xpos].index[n] = points[pdim][0].index[n]; points[xdim][xpos].pos[n] = points[pdim][0].pos[n]; } points[xdim][xpos].index[deltadim] = obsindx[deltadim]; points[xdim][xpos].pos[deltadim] = obsvals[deltadim]; } /* Finished with this pair of positions (end if(ppos==1)) */ } /* End loop over p, data stored for interpolation in changing dimension */ } /* End loop over axes(iterations), iter, for interpolation */ /* Record result */ value = points[0][0].value; /* clean up memory allocated within this function */ free(obsindx); free(obsvals); free (ndpos); free (ndposd); for (p=0;p<tabrow->parnum;p++)free(bounds[p]); free(bounds); FreeBoundingPointArray(points,dimpow); return (value); }