gPass

gPass Commit Details

Date:2017-04-17 20:39:53 (2 years 4 months ago)
Author:Grégory Soutadé
Branch:master
Commit:da72cb46ebe2b2ac8826822314fbeff9b0994cc2
Parents: 36db5056a3e36a1dd8e8e2588a59b0d620ddbbbf
Message:Add new encryption scheme in CLI. Fix a bug : encrypt_domain doesn't add \0 on message returns leading to malformed server requests

Changes:
Mcli/main.c (16 diffs)

File differences

cli/main.c
11
2
2
33
44
55
......
2323
2424
2525
26
2627
2728
2829
......
3334
3435
3536
37
3638
3739
3840
......
4042
4143
4244
43
45
4446
4547
4648
......
5254
5355
5456
57
58
5559
5660
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
5783
5884
5985
6086
61
87
88
89
90
6291
6392
6493
6594
95
96
97
98
99
66100
67101
68102
......
112146
113147
114148
115
149
116150
117151
118
119152
120153
121154
......
133166
134167
135168
136
137
138
139
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
140211
141212
142213
......
146217
147218
148219
149
220
150221
151222
152223
153224
154225
155226
156
157
227
228
158229
159230
160231
161
232
162233
163234
164235
165236
166237
167
238
239
168240
169241
170242
......
243315
244316
245317
246
318
247319
248
320
249321
250
251322
252323
253324
......
255326
256327
257328
258
329
259330
260
331
261332
262333
263334
335
264336
265
337
266338
267339
268340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
269355
270356
271357
......
331417
332418
333419
334
335
336
337
338
339
340
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
341437
342438
343439
......
353449
354450
355451
452
453
454
455
456
457
356458
357459
358460
......
376478
377479
378480
481
379482
380483
381484
......
387490
388491
389492
493
390494
391495
392496
......
556660
557661
558662
663
664
665
666
667
668
559669
560670
561671
......
573683
574684
575685
576
686
577687
578688
579689
690
691
692
580693
581694
/*
Copyright (C) 2013-2016 Grégory Soutadé
Copyright (C) 2013-2017 Grégory Soutadé
This file is part of gPass.
#include <string.h>
#include <curl/curl.h>
#include <openssl/opensslv.h>
#include <openssl/evp.h>
#include "ini.h"
#define DEFAULT_PBKDF2_LEVEL 1000
#define MASTER_KEY_LENGTH (256/8)
#define GLOBAL_IV_LENGTH 16
#define BLOCK_SIZE (128/8)
#define DEFAULT_SERVER_PORT 443
#define SERVER_PROTOCOL 4
#define MAX_SUBDOMAINS 10
struct gpass_parameters {
unsigned pbkdf2_level;
unsigned pbkdf2_level;
char *server;
char *salt;
char *domain;
char *ca_path;
unsigned verify_ssl_peer;
unsigned port_set;
unsigned crypto_v1_compatible;
unsigned char *global_iv;
} ;
#if OPENSSL_VERSION_NUMBER >= 0x10010000
// OpenSSL >= 1.1
static EVP_MD_CTX * s_md_ctx;
#else
static EVP_MD_CTX * s_md_ctx;
static EVP_MD_CTX ss_md_ctx;
#define EVP_MD_CTX_new(...) &ss_md_ctx
#define EVP_MD_CTX_free(...)
#endif
static const EVP_MD * s_md_256;
static EVP_CIPHER_CTX * s_cipher_ctx;
static int digest(unsigned char** out, unsigned char* in, unsigned size)
{
*out = NULL;
EVP_DigestInit(s_md_ctx, s_md_256);
EVP_DigestUpdate(s_md_ctx, in, size);
*out = malloc(32);
return EVP_DigestFinal(s_md_ctx, *out, NULL);
}
static void derive_master_key(struct gpass_parameters* params)
{
if (!params->derived_master_key)
params->derived_master_key = malloc(MASTER_KEY_LENGTH);
if (!params->global_iv)
params->global_iv = malloc(GLOBAL_IV_LENGTH);
PKCS5_PBKDF2_HMAC(params->orig_master_key, strlen(params->orig_master_key),
(unsigned char*)params->salt, strlen(params->salt),
params->pbkdf2_level, EVP_sha256(),
MASTER_KEY_LENGTH, params->derived_master_key);
PKCS5_PBKDF2_HMAC(params->salt, strlen(params->salt),
(unsigned char*)params->orig_master_key, strlen(params->orig_master_key),
params->pbkdf2_level, EVP_sha256(),
GLOBAL_IV_LENGTH, params->global_iv);
}
static void bin_to_hex(unsigned char* bin, unsigned char* hex, unsigned bin_size)
}
}
static void encrypt_domain(struct gpass_parameters* params, char* domain,
static void encrypt_domain_v1(struct gpass_parameters* params, char* domain,
unsigned char** res, unsigned* out_size)
{
EVP_CIPHER_CTX* evp_ctx;
unsigned size = 2+strlen(domain)+1+strlen(params->username);
unsigned char* buffer, *tmp;
tmp = malloc(size);
*res = malloc(size*2);
evp_ctx = EVP_CIPHER_CTX_new();
EVP_EncryptInit(evp_ctx, EVP_aes_256_ecb(), params->derived_master_key, NULL);
EVP_CipherUpdate(evp_ctx, tmp, (int*)out_size, buffer, size);
EVP_CIPHER_CTX_free(evp_ctx);
EVP_EncryptInit(s_cipher_ctx, EVP_aes_256_ecb(), params->derived_master_key, NULL);
EVP_CipherUpdate(s_cipher_ctx, tmp, (int*)out_size, buffer, size);
bin_to_hex(tmp, *res, size);
*out_size *= 2;
free(buffer);
free(tmp);
}
static void encrypt_domain(struct gpass_parameters* params, char* domain,
unsigned char** res, unsigned* out_size)
{
unsigned size = strlen(domain)+1+strlen(params->username);
unsigned padded_size;
unsigned char* buffer, *tmp;
if (params->verbose)
printf("%s: %s\n", __func__, domain);
if ((size % BLOCK_SIZE))
size = ((size/BLOCK_SIZE)+1)*BLOCK_SIZE;
padded_size = size;
size += 16; // For digest
buffer = malloc(size);
memset(buffer, 0, size);
snprintf((char*)buffer, size, "%s;%s", domain, params->username);
// Append digest
digest(&tmp, buffer, padded_size);
memcpy(&buffer[padded_size], &tmp[8], 16);
free(tmp);
tmp = malloc(size);
*res = malloc(size*2);
EVP_EncryptInit(s_cipher_ctx, EVP_aes_256_cbc(), params->derived_master_key, params->global_iv);
EVP_CipherUpdate(s_cipher_ctx, tmp, (int*)out_size, buffer, size);
bin_to_hex(tmp, *res, size);
free(tmp);
}
static void append_to_request(char** request, char* new_req)
static void append_to_request(char** request, char* new_req, unsigned new_req_size)
{
static int cur_req_idx = 0;
int size_added;
if (!cur_req_idx)
{
*request = malloc(3+strlen(new_req)+1);
sprintf(*request, "k0=%s", new_req);
*request = malloc(3+new_req_size+1);
snprintf(*request, 3+new_req_size+1, "k0=%s", new_req);
}
else
{
size_added = 4+strlen(new_req);
size_added = 4+new_req_size;
if (cur_req_idx >= 10)
size_added++;
*request = realloc(*request, strlen(*request)+1+size_added);
sprintf(&((*request)[strlen(*request)]), "&k%d=%s", cur_req_idx, new_req);
snprintf(&((*request)[strlen(*request)]), size_added+1, "&k%d=%s",
cur_req_idx, new_req);
}
cur_req_idx++;
{
char* wc_domain, *saveptr, *token, *cur_ptr;
unsigned char* enc_domain;
unsigned enc_size;
unsigned enc_size, matched_key = 0, crypto_v1_index = 1;
char* request = NULL;
int ret = -1, res;
int ret = -1, res, len;
CURL *curl;
EVP_CIPHER_CTX* evp_ctx;
char response[RESPONSE_SIZE];
unsigned char password[256];
printf("Username: %s\n", params->username);
encrypt_domain(params, params->domain, &enc_domain, &enc_size);
append_to_request(&request, (char*)enc_domain);
append_to_request(&request, (char*)enc_domain, enc_size);
free(enc_domain);
wc_domain = wildcard_domain(params->domain);
if (wc_domain)
{
crypto_v1_index++;
encrypt_domain(params, wc_domain, &enc_domain, &enc_size);
append_to_request(&request, (char*)enc_domain);
append_to_request(&request, (char*)enc_domain, enc_size);
free(enc_domain);
}
if (params->crypto_v1_compatible)
{
encrypt_domain_v1(params, params->domain, &enc_domain, &enc_size);
append_to_request(&request, (char*)enc_domain, enc_size);
free(enc_domain);
if (wc_domain)
{
encrypt_domain_v1(params, wc_domain, &enc_domain, &enc_size);
append_to_request(&request, (char*)enc_domain, enc_size);
free(enc_domain);
}
}
if (params->verbose)
printf("Request: %s\n", request);
hex_to_bin(password, (unsigned char*)cur_ptr, strlen(cur_ptr));
evp_ctx = EVP_CIPHER_CTX_new();
EVP_DecryptInit(evp_ctx, EVP_aes_256_ecb(), params->derived_master_key, NULL);
EVP_CipherUpdate(evp_ctx, password, &res, password, strlen(cur_ptr)/2);
EVP_CIPHER_CTX_free(evp_ctx);
// Remove salt
password[strlen((char*)password)-3] = 0;
if (matched_key >= crypto_v1_index)
{
// Crypto v1
EVP_DecryptInit(s_cipher_ctx, EVP_aes_256_ecb(), params->derived_master_key, NULL);
EVP_CipherUpdate(s_cipher_ctx, password, &res, password, strlen(cur_ptr)/2);
// Remove salt
password[strlen((char*)password)-3] = 0;
}
else
{
EVP_DecryptInit(s_cipher_ctx, EVP_aes_256_cbc(), params->derived_master_key, params->global_iv);
EVP_CipherUpdate(s_cipher_ctx, password, &res, password, strlen(cur_ptr)/2);
// Remove salt
len = strlen((char*)password);
memmove(password, &password[3], len-3);
password[len-3] = 0;
}
printf("Password found: %s\n", password);
ret = 0;
goto end;
break;
}
}
else if (!STRNCMP(token, "matched_key"))
{
cur_ptr += sizeof("matched_key"); // includes "="
matched_key = atoi(cur_ptr);
}
else
{
fprintf(stderr, "Error: Unknown server response %s\n", token);
params->pbkdf2_level = DEFAULT_PBKDF2_LEVEL;
params->server_port = DEFAULT_SERVER_PORT;
params->verify_ssl_peer = 1;
params->crypto_v1_compatible = 1; // For now, in the next version it must a command line parameter
}
static void release_parameters(struct gpass_parameters* params)
if (params->orig_master_key) free(params->orig_master_key);
if (params->derived_master_key) free(params->derived_master_key);
if( params->ca_path) free(params->ca_path);
if (params->global_iv) free(params->global_iv);
}
static int check_parameters(struct gpass_parameters* params)
}
}
s_md_ctx = EVP_MD_CTX_new();
s_md_256 = EVP_sha256();
EVP_DigestInit(s_md_ctx, s_md_256);
s_cipher_ctx = EVP_CIPHER_CTX_new();
// Let's go
tmp = getpass("Enter master key: ");
derive_master_key(&params);
ask_server(&params);
}
end:
release_parameters(&params);
if (s_md_ctx) EVP_MD_CTX_free(s_md_ctx);
if (s_cipher_ctx) EVP_CIPHER_CTX_free(s_cipher_ctx);
return ret;
}

Archive Download the corresponding diff file