#include /* standard I/O stuff */ #include /* standard library stuff */ #include /* had to have this */ #include /* for optarg stuff */ #include /* just for error codes */ #include /* open and read stuff */ #include /* open and read stuff */ #include /* open and read stuff */ #define LINE_SIZE 80 #define NUM_ASCII 256 #define KAPPA_R .00391 #define DELTA_SCALE 20.00 static double KAPPA_P = .06721; static double ALPHA = 85.00; static double DELTA = 45.00; static double DELTA_DATA[NUM_ASCII] = { 0.000000000000000, 0.000000000000000, 0.000000000000000, 0.000000000000000, 0.000000000000000, 0.000000000000000, 0.000000000000000, 0.000000000000000, 0.000000000000000, 0.02159470613142943, 0.6285374239022192, 0.000000000000000, 0.005185663688211039, 0.6133133535749141, 0.000000000000000, 0.000000000000000, 0.000000000000000, 0.000000000000000, 0.000000000000000, 0.000000000000000, 0.000000000000000, 0.000000000000000, 0.000000000000000, 0.000000000000000, 0.000000000000000, 0.000000000000000, 0.000000000000000, 0.000000000000000, 0.000000000000000, 0.000000000000000, 0.00003949907053044318, 0.000000000000000, 18.22847120088911, 0.04859514220116809, 0.5461592909487992, 0.003402562789979605, 0.002234518847150785, 0.001303469327504625, 0.006477847566992680, 0.3059033730851979, 0.08960646286049109, 0.09127106654713120, 0.007922385003534602, 0.09826240203101963, 1.053056505790338, 0.4302746607368405, 1.376283042665316, 0.09522661632453701, 0.1386530230105785, 0.1799069808174457, 0.1202633843164765, 0.07334413125067149, 0.07575357455302852, 0.06504368371491692, 0.09012559350174834, 0.04630419611040239, 0.05494320710784645, 0.08418380474909740, 0.09928937786481117, 0.03923386248545305, 0.01657832417406315, 0.01697895760372907, 0.01933197366247119, 0.07915049461864664, 0.003537988174655410, 0.2914128569248868, 0.1257424696714851, 0.1951649074909197, 0.1386417375618555, 0.1284566200893627, 0.1055302310086212, 0.06836724836383565, 0.2390822311964111, 0.3479924540975659, 0.03624886129822385, 0.03771032690785025, 0.09399085968937028, 0.1463158426934845, 0.1507735949390631, 0.1007395580257146, 0.1932125248618435, 0.01100895522927066, 0.1581881347500634, 0.2934780940411928, 0.3444883222690794, 0.05642724361491882, 0.02919545584635900, 0.1236151625872027, 0.01430430625638192, 0.05275947277994910, 0.004976882886835840, 0.03121555116777309, 0.001004404936345555, 0.03118733754596563, 0.0005642724361491883, 0.03387891706639726, 0.0006037715066796314, 5.687533235646489, 1.065707493808803, 2.069813365763199, 2.943182956986189, 9.018512424376208, 1.488669183773150, 1.553803151077851, 3.836166658089726, 4.859497291943724, 0.07046634182631062, 0.7000476697354059, 2.918490395180301, 1.663824990678219, 5.016218318359800, 5.537707618400157, 1.403289121459416, 0.06597473323456308, 4.474065361707660, 4.668818350320191, 6.601158022464363, 2.045137732130395, 0.6983887087731273, 1.398317881296942, 0.1526864784976088, 1.483483520084939, 0.06741927067110501, 0.002584367757563282, 0.02536404600490601, 0.002584367757563282, 0.0006489133015715664, 0.000000000000000, 0.000000000000000, 0.000000000000000, 0.000000000000000, 0.000000000000000, 0.000000000000000, 0.000000000000000, 0.000000000000000, 0.000000000000000, 0.000000000000000, 0.000000000000000, 0.000000000000000, 0.000000000000000, 0.000000000000000, 0.000000000000000, 0.000000000000000, 0.000000000000000, 0.000000000000000, 0.000000000000000, 0.000000000000000, 0.000000000000000, 0.000000000000000, 0.000000000000000, 0.000000000000000, 0.000000000000000, 0.000000000000000, 0.000000000000000, 0.000000000000000, 0.000000000000000, 0.000000000000000, 0.000000000000000, 0.000000000000000, 0.000000000000000, 0.000000000000000, 0.000000000000000, 0.000000000000000, 0.000000000000000, 0.000000000000000, 0.000000000000000, 0.000000000000000, 0.000000000000000, 0.000000000000000, 0.000000000000000, 0.000000000000000, 0.000000000000000, 0.000000000000000, 0.000000000000000, 0.000000000000000, 0.000000000000000, 0.000000000000000, 0.000000000000000, 0.000000000000000, 0.000000000000000, 0.000000000000000, 0.000000000000000, 0.000000000000000, 0.000000000000000, 0.000000000000000, 0.000000000000000, 0.000000000000000, 0.000000000000000, 0.000000000000000, 0.000000000000000, 0.000000000000000, 0.000000000000000, 0.000000000000000, 0.000000000000000, 0.000000000000000, 0.000000000000000, 0.000000000000000, 0.000000000000000, 0.000000000000000, 0.000000000000000, 0.000000000000000, 0.000000000000000, 0.000000000000000, 0.000000000000000, 0.000000000000000, 0.000000000000000, 0.000000000000000, 0.000000000000000, 0.000000000000000, 0.000000000000000, 0.000000000000000, 0.000000000000000, 0.000000000000000, 0.000000000000000, 0.000000000000000, 0.000000000000000, 0.000000000000000, 0.000000000000000, 0.000000000000000, 0.000000000000000, 0.000000000000000, 0.000000000000000, 0.000000000000000, 0.000000000000000, 0.000000000000000, 0.000000000000000, 0.000000000000000, 0.000000000000000, 0.000000000000000, 0.000000000000000, 0.000000000000000, 0.000000000000000, 0.000000000000000, 0.000000000000000, 0.000000000000000, 0.000000000000000, 0.000000000000000, 0.000000000000000, 0.000000000000000, 0.000000000000000, 0.000000000000000, 0.000000000000000, 0.000000000000000, 0.000000000000000, 0.000000000000000, 0.000000000000000, 0.000000000000000, 0.000000000000000, 0.000000000000000, 0.000000000000000, 0.000000000000000, 0.000000000000000, 0.000000000000000, 0.000000000000000, 0.000000000000000, 0.000000000000000 }; /* function prototypes */ void Usage(char *progName); void Xor(int fo, char *key, char *data, int dataSize); void GetKappa(int od, char *data, int dataSize); void BreakXor(int od, int fo, char *cyphertext, int cSize, int kLength); void SetDeltaData(char *data, int dSize); int PhiTest(int print, char *cyphertext, int cSize); double *GetDeltaData(char *data, int dSize); int main(int argc, char *argv[]) { int e_flag = 0, d_flag = 0, k_flag = 0, i_flag = 0, f_flag = 0, l_flag = 0, F_flag = 0, p_flag = 0, s_flag = 0, a_flag = 0, b_flag = 0, g_flag = 0, z_flag = 0, o_flag = 0; int opt; /* used for getopt */ int dSize = 0; /* the data size */ int deltaSize = 0; /* the delta data size */ int di; /* FD for delta file */ int fi; /* in file stream */ int fo; /* out file stream */ int od; /* data output file stream */ int kLength = 0; /* length of key */ char progName[256]; /* the name of our program */ char key[256]; /* key */ char *data = NULL; /* the data */ char *dData = NULL; /* the delta data */ struct stat file_info; /* for info on file */ /* copy in case we need usage function */ strncpy(progName, argv[0], sizeof(progName)); if(argc <= 1) { Usage(progName); return(1); } /* loop until end of arg list */ while((opt = getopt(argc, argv, "hedipbg:l:a:s:k:f:F:z:o:")) != EOF) { switch(opt) { case 'b': b_flag++; break; case 'e': e_flag++; break; case 'd': d_flag++; break; case 'k': strncpy(key, optarg, sizeof(key)); k_flag++; break; case 'i': i_flag++; break; case 'p': p_flag++; break; case 's': KAPPA_P = atof(optarg); s_flag++; break; case 'l': kLength = atoi(optarg); l_flag++; break; case 'a': ALPHA = atof(optarg); a_flag++; break; case 'z': DELTA = atof(optarg); z_flag++; break; case 'g': if((di = open(optarg, O_RDONLY)) == -1) { fprintf(stderr, "open(): %s\n", strerror(errno)); return(1); } fstat(di, &file_info); dData = (char *)malloc(file_info.st_size); deltaSize = read(di, dData, file_info.st_size); SetDeltaData(dData, deltaSize); free(dData); close(di); g_flag++; break; case 'f': if((fi = open(optarg, O_RDONLY)) == -1) { fprintf(stderr, "open(): %s\n", strerror(errno)); return(1); } fstat(fi, &file_info); data = (char *)malloc(file_info.st_size); dSize = read(fi, data, file_info.st_size); f_flag++; break; case 'F': if((fo = open(optarg, O_CREAT|O_WRONLY|O_TRUNC, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH)) == -1) { fprintf(stderr, "open(): %s\n", strerror(errno)); return(1); } F_flag++; break; case 'o': if((od = open(optarg, O_CREAT|O_WRONLY|O_TRUNC, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH)) == -1) { fprintf(stderr, "open(): %s\n", strerror(errno)); return(1); } o_flag++; break; default: Usage(progName); return(0); break; } } if((d_flag || e_flag) && f_flag && F_flag) { Xor(fo, key, data, dSize); close(fo); } else if(p_flag && f_flag && o_flag) { GetKappa(od, data, dSize); close(od); } else if(i_flag && f_flag && o_flag) { PhiTest(od, data, dSize); free(data); close(od); return(0); } else if(b_flag && f_flag && F_flag && o_flag) { if(!(l_flag)) kLength = PhiTest(od, data, dSize); BreakXor(od, fo, data, dSize, kLength); } free(data); close(fi); return(0); } void Usage(char *progName) { fprintf(stderr, "\nUsage: %s\n" "[-ihedpb] [-k ] [-f ] [-F ]\n" "[-s ] [-a ] [-l ] [-g ]\n" "[-z ] [-o ]\n", progName); fprintf(stderr, "\n" "-h\tprint this usage message\n" "-e\tXOR encipher data\n" "-d\tXOR decipher data\n" "-b\tbreak xor cipher\n" "-l\tspecify the key length manually\n" "-i\tjust print index of coincidence information\n" "-k\tthe key used to encipher/decipher data\n" "-p\tget KAPPA_P value for some input file\n" "-s\tset the KAPPA_P value (default: .06721)\n" "-a\tset the ALPHA point for key length match (default: 85.00)\n" "-z\tset DELTA value probable plaintext match (default: 45.00)\n" "-g\tset delta data information\n" "-o\toutput data file name\n" "-f\tinput file name\n" "-F\toutput file name\n\n"); } void Xor(int fo, char *key, char *data, int dataSize) { int i; char c; char *startKey = key; if(*key != '\0') { for(i = 0; i < dataSize; i++) { if(!(*key)) key = startKey; c = data[i] ^ *(key++); write(fo, &c, 1); } } } int PhiTest(int print, char *cyphertext, int cSize) { int i; int keyLength; int *candKey = (int *)malloc(cSize * sizeof(int)); double frequency[NUM_ASCII]; double phi_r = 0.0; double phi_p = 0.0; double *match = (double *)malloc(cSize * sizeof(double)); char line[LINE_SIZE]; union idx_t { int i; char c; } idx; for(i = 0; i < cSize; i++) candKey[i] = 0; for(i = 0; i < NUM_ASCII; i++) frequency[i] = 0; for(keyLength = 1; keyLength < cSize/2; keyLength++) { for(i = 0; i < cSize; i += keyLength) { memset(&idx, 0, sizeof(idx)); idx.c = cyphertext[i]; frequency[idx.i]++; } match[keyLength] = 0; for(i = 0; i < NUM_ASCII; i++) { match[keyLength] += (frequency[i] * (frequency[i] - 1)); frequency[i] = 0; } } snprintf(line, LINE_SIZE, "-------------------------------------------------------------\n"); write(print, line, strlen(line)); snprintf(line, LINE_SIZE, "%10s\t%10s\t%10s\t%10s\n", "Key Length", "PHI_R", "PHI_P", "Observed PHI"); write(print, line, strlen(line)); snprintf(line, LINE_SIZE, "-------------------------------------------------------------\n"); write(print, line, strlen(line)); for(keyLength = 1; keyLength < cSize/2; keyLength++) { phi_r = KAPPA_R*(double)(cSize/keyLength)*((cSize/keyLength)-1); phi_p = KAPPA_P*(double)(cSize/keyLength)*((cSize/keyLength)-1); if((match[keyLength] > phi_p) || ((match[keyLength] > phi_r) && ((match[keyLength] - phi_r) > (phi_p - match[keyLength])) && ((100*(match[keyLength]/phi_p)) > ALPHA))) { snprintf(line, LINE_SIZE, "%10d\t%10.6g\t%10.6g\t%10.6g <=== Candidate\n", keyLength, phi_r, phi_p, match[keyLength]); write(print, line, strlen(line)); candKey[keyLength]++; } else { snprintf(line, LINE_SIZE, "%10d\t%10.6g\t%10.6g\t%10.6g\n", keyLength, phi_r, phi_p, match[keyLength]); write(print, line, strlen(line)); } } for(i = 0; i < cSize/2; i++) { if(candKey[i] >= 1) { keyLength = i; break; } } snprintf(line, LINE_SIZE, "-------------------------------------------------------------\n"); write(print, line, strlen(line)); snprintf(line, LINE_SIZE, "Shortest Key Length is: %d\n", keyLength); write(print, line, strlen(line)); snprintf(line, LINE_SIZE, "-------------------------------------------------------------\n"); write(print, line, strlen(line)); fsync(print); return(keyLength); } void GetKappa(int od, char *data, int dataSize) { int i; double kappa_p = 0.0; double frequency[NUM_ASCII]; char line[LINE_SIZE]; for(i = 0; i < NUM_ASCII; i++) frequency[i] = 0.0; for(i = 0; i < dataSize; i++) frequency[(int)data[i]]++; for(i = 0; i < NUM_ASCII; i++) { kappa_p += (frequency[i]/dataSize) * (frequency[i]/dataSize); } snprintf(line, LINE_SIZE, "KAPPA_P for %d bytes is: %6.10g\n", dataSize, kappa_p); write(od, line, strlen(line)); fsync(od); } void BreakXor(int od, int fo, char *cyphertext, int cSize, int kLength) { int i; int j; int k; int x; int totalClose; int dataSize = (cSize/kLength) + 1; double (*candKey)[NUM_ASCII] = malloc(kLength * sizeof(*candKey)); double *deltaInfo; double bestKey; char line[LINE_SIZE]; char *data = (char *)malloc(dataSize); char *key = (char *)malloc(kLength + 1); memset(key, 0, (kLength + 1)); for(i = 0; i < kLength; i++) { for(k = 0; k < NUM_ASCII; k++) candKey[i][k] = 0.0; } for(i = 0; i < kLength; i++) { for(k = 0; k < NUM_ASCII; k++) { x = 0; for(j = i; j < cSize; j += kLength) { data[x] = cyphertext[j] ^ k; x++; } deltaInfo = GetDeltaData(data, dataSize); totalClose = 0; for(j = 0; j < NUM_ASCII; j++) { if(DELTA_DATA[j] != deltaInfo[j]) { if(DELTA_DATA[j] < deltaInfo[j]) { if((100 * (DELTA_DATA[j]/deltaInfo[j])) >= DELTA) totalClose++; } else { if((100 * (deltaInfo[j]/DELTA_DATA[j])) >= DELTA) totalClose++; } } else totalClose++; } if((((double)totalClose/NUM_ASCII) * 100) >= (DELTA + DELTA_SCALE)) candKey[i][k] = (((double)totalClose/NUM_ASCII) * 100); free(deltaInfo); } } snprintf(line, LINE_SIZE, "-------------------------------------------------------------\n"); write(od, line, strlen(line)); snprintf(line, LINE_SIZE, "Possible values for each key position are:\n"); write(od, line, strlen(line)); snprintf(line, LINE_SIZE, "-------------------------------------------------------------\n"); write(od, line, strlen(line)); for(i = 0; i < kLength; i++) { snprintf(line, LINE_SIZE, "%d: ", i + 1); write(od, line, strlen(line)); bestKey = 0.0; for(j = 0; j < NUM_ASCII; j++) { if(candKey[i][j] > bestKey) { if(j >= 32 && j < 127) { snprintf(line, LINE_SIZE, "%c ", j); write(od, line, strlen(line)); } else { snprintf(line, LINE_SIZE, "0x%hhx ", j); write(od, line, strlen(line)); } bestKey = candKey[i][j]; } } for(j = 0; j < NUM_ASCII; j++) { if(candKey[i][j] == bestKey) key[i] = (char)j; } snprintf(line, LINE_SIZE, "\n"); write(od, line, strlen(line)); } snprintf(line, LINE_SIZE, "-------------------------------------------------------------\n"); write(od, line, strlen(line)); snprintf(line, LINE_SIZE, "Most probable key is: "); write(od, line, strlen(line)); for(i = 0; i < kLength; i++) { if(key[i] >= 32 && key[i] < 127) { snprintf(line, LINE_SIZE, "%c", key[i]); write(od, line, strlen(line)); } else { snprintf(line, LINE_SIZE, " 0x%hhx ", key[i]); write(od, line, strlen(line)); } } snprintf(line, LINE_SIZE, "\n-------------------------------------------------------------\n"); write(od, line, strlen(line)); fsync(od); Xor(fo, key, cyphertext, cSize); free(candKey); free(data); free(key); } double *GetDeltaData(char *data, int dSize) { int i; int *frequency = (int *)malloc(NUM_ASCII * sizeof(int)); double *deltaInfo = (double *)malloc(NUM_ASCII * sizeof(double)); union idx_t { int i; char c; } idx; for(i = 0; i < NUM_ASCII; i++) frequency[i] = 0; for(i = 0; i < dSize; i++) { memset(&idx, 0, sizeof(idx)); idx.c = data[i]; frequency[idx.i]++; } for(i = 0; i < NUM_ASCII; i++) deltaInfo[i] = (double)frequency[i]/dSize * 100; free(frequency); return(deltaInfo); } void SetDeltaData(char *data, int dSize) { int i; int *frequency = (int *)malloc(NUM_ASCII * sizeof(int)); union idx_t { int i; char c; } idx; for(i = 0; i < NUM_ASCII; i++) frequency[i] = 0; for(i = 0; i < dSize; i++) { memset(&idx, 0, sizeof(idx)); idx.c = data[i]; frequency[idx.i]++; } for(i = 0; i < NUM_ASCII; i++) DELTA_DATA[i] = (double)frequency[i]/dSize * 100; free(frequency); }