Created
August 22, 2010 16:06
-
-
Save pyropeter/543927 to your computer and use it in GitHub Desktop.
Otrtool, now continued at http://github.com/pyropeter/otrtool
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <stdlib.h> | |
#include <stdio.h> | |
#include <getopt.h> | |
#include <string.h> | |
#include <strings.h> | |
#include <unistd.h> | |
#include <sys/stat.h> | |
#include <fcntl.h> | |
#include <errno.h> | |
#include <sys/syscall.h> | |
#include <time.h> | |
#include <mcrypt.h> | |
#include <openssl/md5.h> | |
#include <curl/curl.h> | |
#include <curl/types.h> | |
#include <curl/easy.h> | |
/* | |
* gcc -g -Wall -o foo -lmcrypt -lssl -lcurl foo.c | |
* | |
* (-g is for debugging symbols) | |
* | |
* ##### Could be done | |
* * config in ~ | |
* * otrkey-cache for passphrases | |
* * twittelevision | |
* * read email + pass from stdin | |
* * pretty formatting for -i | |
* * upgrade to weapon of mass destruction | |
* | |
*/ | |
#define QUOTEME_(x) #x | |
#define QUOTEME(x) QUOTEME_(x) | |
#define ERROR(...) \ | |
({fprintf(stderr, __VA_ARGS__); \ | |
fprintf(stderr, "\n"); \ | |
exit(EXIT_FAILURE); }) | |
#ifndef VERSION | |
#define VERSION 0.2.2 | |
#endif | |
#define LINE_LENGTH 80 | |
#define CHUNK_SIZE 2097152 // 2M, must be multiple of 8 | |
#define VERB_INFO 1 | |
#define VERB_DEBUG 2 | |
static int verbosity = VERB_INFO; | |
#define ACTION_INFO 1 | |
#define ACTION_FETCHKEY 2 | |
#define ACTION_DECRYPT 3 | |
static int action = ACTION_INFO; | |
static char *email = NULL; | |
static char *password = NULL; | |
static char *keyphrase = NULL; | |
static char *filename = NULL; | |
static char *destfolder = NULL; | |
static char *destfilename = NULL; | |
static FILE *file = NULL; | |
static char *header = NULL; | |
static char *info = NULL; | |
// ######################## curl-stuff ####################### | |
struct MemoryStruct { | |
char *memory; | |
size_t size; | |
}; | |
static size_t WriteMemoryCallback(void *ptr, size_t size, | |
size_t nmemb, void *data) { | |
size_t realsize = size * nmemb; | |
struct MemoryStruct *mem = (struct MemoryStruct *)data; | |
mem->memory = realloc(mem->memory, mem->size + realsize + 1); | |
if (mem->memory) { | |
memcpy(&(mem->memory[mem->size]), ptr, realsize); | |
mem->size += realsize; | |
mem->memory[mem->size] = 0; | |
} | |
return realsize; | |
} | |
// ######################## generic functions #################### | |
void reverseWords(void *in_, int size) { | |
unsigned char *in = in_; | |
unsigned char *out = malloc(size); | |
int i; | |
for (i = 0; i < size; i++) { | |
out[i + 3 - (i%4 * 2)] = in[i]; | |
} | |
memcpy(in, out, size); | |
free(out); | |
} | |
char * bin2hex(void *data_, int len) { | |
unsigned char *data = data_; | |
unsigned char *result = malloc(sizeof(char) * len * 2 + 1); | |
result[len * 2] = 0; | |
int foo; | |
for (len-- ; len >= 0 ; len--) { | |
foo = data[len] % 16; | |
result[len*2 + 1] = foo > 9 ? 0x37 + foo : 0x30 + foo; | |
foo = data[len] >> 4; | |
result[len*2] = foo > 9 ? 0x37 + foo : 0x30 + foo; | |
} | |
return (char*)result; | |
} | |
void * hex2bin(char *data_) { | |
int len = strlen(data_); | |
unsigned char *data = (unsigned char*)data_; | |
// never tested with lowercase letters! | |
unsigned char *result = malloc(sizeof(char) * len + 1); | |
int foo, bar; | |
for (len-- ; len >= 0 ; len--) { | |
foo = data[len*2]; | |
if (foo < 0x41) { | |
// is a digit | |
bar = foo - 0x30; | |
} else if (foo < 0x61) { | |
// is a uppercase letter | |
bar = foo - 0x37; | |
} else { | |
// is a lowercase letter | |
bar = foo - 0x57; | |
} | |
result[len] = bar << 4; | |
foo = data[len*2 + 1]; | |
if (foo < 0x41) { | |
// is a digit | |
bar = foo - 0x30; | |
} else if (foo < 0x61) { | |
// is a uppercase letter | |
bar = foo - 0x37; | |
} else { | |
// is a lowercase letter | |
bar = foo - 0x57; | |
} | |
result[len] += bar; | |
} | |
result[len] = 0; | |
return (void*)result; | |
} | |
char * base64Encode(void *data_, int len) { | |
unsigned char *data = data_; | |
static const char b64[] = "\ | |
ABCDEFGHIJKLMNOPQRSTUVWXYZ\ | |
abcdefghijklmnopqrstuvwxyz\ | |
0123456789+/"; | |
int blocks = (len + 2) / 3; | |
int newlen = blocks * 4 + 1; | |
char *result = malloc(newlen); | |
char *resptr = result; | |
int i; | |
for (i = len / 3 ; i > 0 ; i--) { | |
resptr[0] = b64[ data[0] >> 2 ]; | |
resptr[1] = b64[ (data[0] & 0b11) << 4 | |
| data[1] >> 4 ]; | |
resptr[2] = b64[ (data[1] & 0b1111) << 2 | |
| data[2] >> 6 ]; | |
resptr[3] = b64[ data[2] & 0b111111 ]; | |
resptr += 4; | |
data += 3; | |
} | |
if (len < blocks * 3 - 1) { | |
resptr[0] = b64[ data[0] >> 2 ]; | |
resptr[1] = b64[ (data[0] & 0b11) << 4 ]; | |
resptr[2] = '='; | |
resptr[3] = '='; | |
resptr += 4; | |
} else if (len < blocks * 3) { | |
resptr[0] = b64[ data[0] >> 2 ]; | |
resptr[1] = b64[ (data[0] & 0b11) << 4 | |
| data[1] >> 4 ]; | |
resptr[2] = b64[ (data[1] & 0b1111) << 2 ]; | |
resptr[3] = '='; | |
resptr += 4; | |
} | |
*resptr = 0; | |
return result; | |
} | |
void * base64Decode(char *text, int *outlen) { | |
static const unsigned char b64dec[] = { | |
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //00 | |
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //10 | |
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 62, 0, 0, 0, 63, //20 | |
52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 0, 0, 0, 0, 0, 0, //30 | |
0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, //40 | |
15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 0, 0, 0, 0, 0, //50 | |
0, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, //60 | |
41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 0, 0, 0, 0, 0, //70 | |
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //80 | |
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //90 | |
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //a0 | |
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //b0 | |
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //c0 | |
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //d0 | |
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //e0 | |
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 //f0 | |
}; | |
// this functions treats invalid characters as 'A'. deal with it :-P | |
int inlen = (strlen(text) >> 2) << 2; | |
int blocks = inlen >> 2; | |
*outlen = blocks * 3 - (text[inlen-2] == '=' | |
? 2 : (text[inlen-1] == '=' ? 1 : 0)); | |
char *result = malloc(blocks * 3); | |
char *resptr = result; | |
u_int8_t *text_ = (u_int8_t*)text; | |
int i; | |
for (i = 0 ; i < blocks ; i++) { | |
resptr[0] = b64dec[text_[0]] << 2 | b64dec[text_[1]] >> 4; | |
resptr[1] = b64dec[text_[1]] << 4 | b64dec[text_[2]] >> 2; | |
resptr[2] = b64dec[text_[2]] << 6 | b64dec[text_[3]]; | |
text_ += 4; | |
resptr += 3; | |
} | |
return (void*)result; | |
} | |
char * queryGetParam(char *query, char *name) { | |
char *begin = index(query, '&'); | |
char *end; | |
int nameLen = strlen(name); | |
while (begin != NULL) { | |
begin++; | |
if (strncmp(begin, name, nameLen) == 0 && begin[nameLen] == '=') { | |
begin += nameLen + 1; | |
end = index(begin, '&'); | |
char *result = malloc(end - begin + 1); | |
strncpy(result, begin, end - begin); | |
result[end - begin] = 0; | |
return result; | |
} | |
begin = index(begin, '&'); | |
} | |
return NULL; | |
} | |
void quote(char *message) { | |
char line[LINE_LENGTH + 1]; | |
line[0] = '>'; | |
line[1] = ' '; | |
int index = 2; | |
while (*message != 0) { | |
if (*message < 0x20 || *message > 0x7E) { | |
line[index++] = ' '; | |
} else { | |
line[index++] = *message; | |
} | |
if (index == LINE_LENGTH) { | |
line[index++] = '\n'; | |
fwrite(line, index, 1, stdout); | |
line[0] = '>'; | |
line[1] = ' '; | |
index = 2; | |
} | |
} | |
line[index++] = '\n'; | |
if (index != 3) fwrite(line, index, 1, stdout); | |
} | |
void dumpQuerystring(char *query) { | |
int length = strlen(query); | |
char line[LINE_LENGTH + 1]; | |
int index = 0; | |
if (*query == '&') { | |
line[0] = '&'; | |
index++; | |
query++; | |
} | |
for (; length > 0 ; length --) { | |
if (*query == '&') { | |
line[index] = '\n'; | |
fwrite(line, index + 1, 1, stdout); | |
index = 0; | |
} | |
line[index] = *query; | |
index++; | |
if (index == LINE_LENGTH) { | |
line[index] = '\n'; | |
fwrite(line, index + 1, 1, stdout); | |
line[0] = ' '; | |
index = 1; | |
} | |
query++; | |
} | |
line[index] = '\n'; | |
if (index != LINE_LENGTH) fwrite(line, index + 1, 1, stdout); | |
} | |
void dumpHex(void *data_, int len) { | |
unsigned char *data = data_; | |
unsigned char *line = malloc(sizeof(char) * LINE_LENGTH + 1); | |
char *hexrep_orig = bin2hex(data, len); | |
char *hexrep = hexrep_orig; | |
int i, pos; | |
for (pos = 0 ; pos < len ; pos += 16) { | |
for (i = 0 ; i < 8 ; i++) { | |
line[i*3] = pos+i < len ? hexrep[i*2] : ' '; | |
line[i*3+1] = pos+i < len ? hexrep[i*2+1] : ' '; | |
line[i*3+2] = ' '; | |
} | |
line[24] = ' '; | |
for (i = 8 ; i < 16 ; i++) { | |
line[i*3+1] = pos+i < len ? hexrep[i*2] : ' '; | |
line[i*3+2] = pos+i < len ? hexrep[i*2+1] : ' '; | |
line[i*3+3] = ' '; | |
} | |
line[49] = ' '; | |
line[50] = '|'; | |
for (i = 0 ; i < 16 ; i++) { | |
if (data[pos+i] >= 0x20 && data[pos+i] < 0x7f) { | |
line[51+i] = pos+i < len ? data[pos+i] : ' '; | |
} else { | |
line[51+i] = pos+i < len ? '.' : ' '; | |
} | |
} | |
line[67] = '|'; | |
line[68] = 0; | |
printf("%08x %s\n", pos, line); | |
hexrep += 32; | |
} | |
printf("%08x\n", len); | |
free(line); | |
free(hexrep_orig); | |
} | |
// ###################### special functions #################### | |
char * getHeader() { | |
unsigned char *header = malloc(sizeof(char) * 513); | |
if (fread(header, 512, 1, file) < 1) | |
ERROR("Error reading file"); | |
MCRYPT blowfish; | |
blowfish = mcrypt_module_open("blowfish", NULL, "ecb", NULL); | |
unsigned char hardKey[] = { | |
0xEF, 0x3A, 0xB2, 0x9C, 0xD1, 0x9F, 0x0C, 0xAC, | |
0x57, 0x59, 0xC7, 0xAB, 0xD1, 0x2C, 0xC9, 0x2B, | |
0xA3, 0xFE, 0x0A, 0xFE, 0xBF, 0x96, 0x0D, 0x63, | |
0xFE, 0xBD, 0x0F, 0x45}; | |
mcrypt_generic_init(blowfish, hardKey, 28, NULL); | |
reverseWords(header, 512); | |
mdecrypt_generic(blowfish, header, 512); | |
reverseWords(header, 512); | |
mcrypt_generic_deinit(blowfish); | |
mcrypt_module_close(blowfish); | |
char *padding = strstr((char*)header, "&PD="); | |
if (padding == NULL) | |
ERROR("Corrupted header: could not find padding"); | |
*padding = 0; | |
if (verbosity >= VERB_DEBUG) { | |
printf("\nDumping decrypted header:\n"); | |
dumpQuerystring((char*)header); | |
printf("\n"); | |
} | |
header[512] = 0; | |
return (char*)header; | |
} | |
void * generateBigkey(char *date) { | |
char *mailhash = bin2hex(MD5( | |
(unsigned char*)email, strlen(email), NULL), 16); | |
char *passhash = bin2hex(MD5( | |
(unsigned char*)password, strlen(password), NULL), 16); | |
char *bigkey_hex = malloc(57 * sizeof(char)); | |
char *ptr = bigkey_hex; | |
strncpy(ptr, mailhash, 13); | |
ptr += 13; | |
strncpy(ptr, date, 4); | |
date += 4; | |
ptr += 4; | |
strncpy(ptr, passhash, 11); | |
ptr += 11; | |
strncpy(ptr, date, 2); | |
date += 2; | |
ptr += 2; | |
strncpy(ptr, mailhash + 21, 11); | |
ptr += 11; | |
strncpy(ptr, date, 2); | |
ptr += 2; | |
strncpy(ptr, passhash + 19, 13); | |
ptr += 13; | |
*ptr = 0; | |
if (verbosity >= VERB_DEBUG) { | |
printf("\nGenerated BigKey: %s\n\n", bigkey_hex); | |
} | |
void *res = hex2bin(bigkey_hex); | |
free(bigkey_hex); | |
free(mailhash); | |
free(passhash); | |
return res; | |
} | |
char * generateRequest(void *bigkey, char *date) { | |
char *filename = queryGetParam(header, "FN"); | |
char *thatohthing = queryGetParam(header, "OH"); | |
MCRYPT blowfish = mcrypt_module_open("blowfish", NULL, "cbc", NULL); | |
char *iv = malloc(mcrypt_enc_get_iv_size(blowfish)); | |
char *code = malloc(513); | |
char *dump = malloc(513); | |
char *result = malloc(1024); // base64-encoded code is 680 bytes | |
memset(iv, 0x42, mcrypt_enc_get_iv_size(blowfish)); | |
memset(dump, 'd', 512); | |
dump[512] = 0; | |
snprintf(code, 513, "FOOOOBAR\ | |
&OS=01677e4c0ae5468b9b8b823487f14524\ | |
&M=01677e4c0ae5468b9b8b823487f14524\ | |
&LN=EN\ | |
&VN=0.4.1132\ | |
&IR=TRUE\ | |
&IK=aFzW1tL7nP9vXd8yUfB5kLoSyATQ\ | |
&FN=%s\ | |
&OH=%s\ | |
&A=%s\ | |
&P=%s\ | |
&D=%s", filename, thatohthing, email, password, dump); | |
if (verbosity >= VERB_DEBUG) { | |
printf("\nGenerated request-'code':\n"); | |
dumpQuerystring(code); | |
printf("\n"); | |
} | |
mcrypt_generic_init(blowfish, bigkey, 28, iv); | |
reverseWords(code, 512); | |
mcrypt_generic(blowfish, code, 512); | |
reverseWords(code, 512); | |
mcrypt_generic_deinit(blowfish); | |
mcrypt_module_close(blowfish); | |
if (verbosity >= VERB_DEBUG) { | |
printf("\nEncrypted request-'code':\n"); | |
dumpHex(code, 512); | |
printf("\n"); | |
} | |
snprintf(result, 1024, "http://87.236.198.182/quelle_neu1.php\ | |
?code=%s\ | |
&AA=%s\ | |
&ZZ=%s", base64Encode(code, 512), email, date); | |
if (verbosity >= VERB_DEBUG) { | |
printf("\nRequest:\n%s\n\n", result); | |
} | |
free(code); | |
free(dump); | |
return result; | |
} | |
char * contactServer(char *request) { | |
// http://curl.haxx.se/libcurl/c/getinmemory.html | |
CURL *curl_handle; | |
struct MemoryStruct chunk; | |
chunk.memory=NULL; /* we expect realloc(NULL, size) to work */ | |
chunk.size = 0; /* no data at this point */ | |
curl_global_init(CURL_GLOBAL_ALL); | |
/* init the curl session */ | |
curl_handle = curl_easy_init(); | |
/* specify URL to get */ | |
curl_easy_setopt(curl_handle, CURLOPT_URL, request); | |
/* send all data to this function */ | |
curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, WriteMemoryCallback); | |
/* we pass our 'chunk' struct to the callback function */ | |
curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, (void *)&chunk); | |
/* some servers don't like requests that are made without a user-agent | |
field, so we provide one */ | |
curl_easy_setopt(curl_handle, CURLOPT_USERAGENT, "libcurl-agent/1.0"); | |
/* get it! */ | |
curl_easy_perform(curl_handle); | |
/* cleanup curl stuff */ | |
curl_easy_cleanup(curl_handle); | |
/* | |
* Now, our chunk.memory points to a memory block that is chunk.size | |
* bytes big and contains the remote file. | |
* | |
* Do something nice with it! | |
* | |
* You should be aware of the fact that at this point we might have an | |
* allocated data block, and nothing has yet deallocated that data. So when | |
* you're done with it, you should free() it as a nice application. | |
*/ | |
/* we're done with libcurl, so clean it up */ | |
curl_global_cleanup(); | |
// it seems like that curl-foo allocates one byte more than | |
// chunk.size and puts a \0. as I have to get some sleep, | |
// I will just rely on this. BAAAM! | |
if (verbosity >= VERB_DEBUG) { | |
printf("\nResponse:\n%s\n=====End of Response.\n\n", chunk.memory); | |
} | |
return chunk.memory; | |
} | |
char * decryptResponse(char *response, void *bigkey) { | |
MCRYPT blowfish = mcrypt_module_open("blowfish", NULL, "ecb", NULL); | |
char *result = malloc(512); | |
memcpy(result, response+8, 512); | |
mcrypt_generic_init(blowfish, bigkey, 28, NULL); | |
reverseWords(result, 512); | |
mdecrypt_generic(blowfish, result, 512); | |
reverseWords(result, 512); | |
mcrypt_generic_deinit(blowfish); | |
mcrypt_module_close(blowfish); | |
int i; | |
for (i = 0 ; i < 512 ; i++) { | |
result[i] ^= response[i]; | |
} | |
char *padding = strstr(result, "&D="); | |
if (padding == NULL) | |
ERROR("Corrupted response: could not find padding"); | |
*padding = 0; | |
if (verbosity >= VERB_DEBUG) { | |
printf("\nDecrypted response:\n"); | |
dumpQuerystring(result); | |
printf("\n"); | |
} | |
return result; | |
} | |
void fetchKeyphrase() { | |
time_t time_ = time(NULL); | |
char *date = malloc(9); | |
strftime(date, 9, "%Y%m%d", gmtime(&time_)); | |
if (email == NULL) | |
ERROR("Email unknown"); | |
if (password == NULL) | |
ERROR("Password unknown"); | |
char *bigkey = generateBigkey(date); | |
char *request = generateRequest(bigkey, date); | |
printf("Trying to contact server...\n"); | |
char *response = contactServer(request); | |
printf("Server responded.\n"); | |
if (strlen(response) != 696) { | |
if (strstr(response, "MessageToBePrintedInDecoder") == response) { | |
printf("Server tells us this sweet message:\n"); | |
quote(response + 27); | |
} else { | |
printf("Server sends us this ugly crap:\n"); | |
dumpHex(response, strlen(response)); | |
} | |
ERROR("Server does not like us :-("); | |
} | |
int info_len; | |
char *info_crypted = base64Decode(response, &info_len); | |
// check if len == 0x208 | |
if (info_len != 0x208) | |
ERROR("Programmer was getting tired and added a bug"); | |
info = decryptResponse(info_crypted, bigkey); | |
keyphrase = queryGetParam(info, "HP"); | |
if (keyphrase == NULL) | |
ERROR("Response lacks keyphrase"); | |
if (strlen(keyphrase) != 56) | |
ERROR("Keyphrase has wrong length"); | |
printf("Keyphrase: %s\n", keyphrase); | |
free(bigkey); | |
free(request); | |
free(response); | |
free(info_crypted); | |
} | |
void openFile() { | |
if (strcmp("-", filename) == 0) | |
file = stdin; | |
else | |
file = fopen(filename, "rb"); | |
if (file == NULL) | |
ERROR("Error opening file"); | |
char magic[11]; | |
magic[10] = 0; | |
if (fread(magic, 10, 1, file) < 1) | |
ERROR("Error reading file"); | |
if (strcmp(magic, "OTRKEYFILE") != 0) | |
ERROR("Wrong file format"); | |
header = getHeader(); | |
} | |
void decryptFile() { | |
int fd; | |
if (destfolder != NULL) | |
ERROR("Option -D is not implemented, yet"); | |
if (destfilename == NULL) { | |
// this leaks memory. 10 valuable bytes | |
destfilename = queryGetParam(header, "FN"); | |
} | |
fd = open(destfilename, O_WRONLY|O_CREAT|O_EXCL, | |
S_IWUSR|S_IRUSR|S_IRGRP|S_IROTH); | |
if (fd < 0 && errno == EEXIST) { | |
// TODO: offer to overwrite | |
ERROR("Destination file exists: %s", destfilename); | |
} | |
if (fd < 0) | |
ERROR("Error opening destination file: %s", destfilename); | |
// decrypt | |
void *key = hex2bin(keyphrase); | |
MCRYPT blowfish = mcrypt_module_open("blowfish", NULL, "ecb", NULL); | |
mcrypt_generic_init(blowfish, key, 28, NULL); | |
printf("Decrypting...\n"); | |
unsigned long long length = atol(queryGetParam(header, "SZ")) - 512; | |
unsigned long long position = 0; | |
int blocknum; | |
char *progressbar = malloc(41); | |
char rotatingFoo[4] = {'|', '/', '-', '\\'}; | |
int readsize; | |
int writesize; | |
char *buffer = malloc(CHUNK_SIZE); | |
for (blocknum = 0 ; 1 ; blocknum++) { | |
readsize = fread(buffer, 1, CHUNK_SIZE, file); | |
if (readsize <= 0) break; | |
reverseWords(buffer, CHUNK_SIZE); | |
mdecrypt_generic(blowfish, buffer, CHUNK_SIZE); | |
reverseWords(buffer, CHUNK_SIZE); | |
writesize = write(fd, buffer, readsize); | |
if (writesize != readsize) | |
ERROR("Error writing to destination file"); | |
position += writesize; | |
memset(progressbar, ' ', 40); | |
memset(progressbar, '=', (position*40)/length); | |
progressbar[40] = 0; | |
printf("[%s] %3lli%% %c\r", progressbar, (position*100)/length, | |
rotatingFoo[blocknum % 4]); | |
fflush(stdout); | |
} | |
printf("[========================================] 100%% \n"); | |
mcrypt_generic_deinit(blowfish); | |
mcrypt_module_close(blowfish); | |
if (close(fd) < 0) | |
ERROR("Error closing destination file."); | |
free(progressbar); | |
free(key); | |
free(buffer); | |
} | |
void usageError() { | |
printf("\n"); | |
printf("Usage: otrtool [-h] [-v] [-i|-f|-x] [-k <keyphrase>] [-e <email> -p <password>]\n"); | |
printf(" [-D <destfolder>] [-O <destfile>] <otrkey-file>\n"); | |
printf("\n"); | |
printf("MODES OF OPERATION\n"); | |
printf(" -i | Display information about file\n"); | |
printf(" -f | Fetch keyphrase for file\n"); | |
printf(" -x | Decrypt file\n"); | |
printf("\n"); | |
printf("OTHER ARGUMENTS\n"); | |
printf(" -h | Display help\n"); | |
printf(" -v | Be verbose\n"); | |
printf(" -k | Do not fetch keyphrase, use this one\n"); | |
printf(" -e | Use this eMail address\n"); | |
printf(" -p | Use this password\n"); | |
printf(" -D | Decrypt to this folder (but use default name)\n"); | |
printf(" -O | Decrypt to this file (overwrite default name)\n"); | |
printf("\n"); | |
} | |
int main(int argc, char *argv[]) { | |
int opt; | |
while ( (opt = getopt(argc, argv, "hvifxk:e:p:D:O:")) != -1) { | |
switch (opt) { | |
case 'h': | |
usageError(); | |
exit(EXIT_SUCCESS); | |
break; | |
case 'v': | |
verbosity = VERB_DEBUG; | |
break; | |
case 'i': | |
action = ACTION_INFO; | |
break; | |
case 'f': | |
action = ACTION_FETCHKEY; | |
break; | |
case 'x': | |
action = ACTION_DECRYPT; | |
break; | |
case 'k': | |
keyphrase = optarg; | |
break; | |
case 'e': | |
email = optarg; | |
break; | |
case 'p': | |
password = optarg; | |
break; | |
case 'D': | |
destfolder = optarg; | |
break; | |
case 'O': | |
destfilename = optarg; | |
break; | |
default: | |
usageError(); | |
exit(EXIT_FAILURE); | |
} | |
} | |
if (verbosity >= VERB_DEBUG) | |
printf("OTR-Tool %s\n", QUOTEME(VERSION)); | |
if (optind >= argc) { | |
fprintf(stderr, "Missing argument: otrkey-file\n"); | |
usageError(); | |
exit(EXIT_FAILURE); | |
} | |
filename = argv[optind]; | |
openFile(); | |
switch (action) { | |
case ACTION_INFO: | |
// TODO: output something nicer than just the querystring | |
dumpQuerystring(header); | |
break; | |
case ACTION_FETCHKEY: | |
fetchKeyphrase(); | |
break; | |
case ACTION_DECRYPT: | |
if (keyphrase == NULL) | |
fetchKeyphrase(); | |
errno = 0; | |
nice(10); | |
if (errno == 0) | |
printf("NICE was set to 10\n"); | |
// I am not sure if this really catches all errors | |
// If this causes problems, just delete the ionice-stuff | |
#ifdef __NR_ioprio_set | |
if (syscall(__NR_ioprio_set, 1, getpid(), 7 | 3 << 13) == 0) | |
printf("IONICE class was set to Idle\n"); | |
#endif | |
decryptFile(); | |
break; | |
} | |
free(header); | |
if (fclose(file) != 0) | |
ERROR("Error closing file. I don't care, I was going to exit anyway"); | |
exit(EXIT_SUCCESS); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment