Add new encryption scheme in CLI. Fix a bug : encrypt_domain doesn't add \0 on message returns leading to malformed server requests
This commit is contained in:
parent
36db5056a3
commit
da72cb46eb
169
cli/main.c
169
cli/main.c
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
Copyright (C) 2013-2016 Grégory Soutadé
|
||||
Copyright (C) 2013-2017 Grégory Soutadé
|
||||
|
||||
This file is part of gPass.
|
||||
|
||||
|
@ -23,6 +23,7 @@
|
|||
#include <string.h>
|
||||
|
||||
#include <curl/curl.h>
|
||||
#include <openssl/opensslv.h>
|
||||
#include <openssl/evp.h>
|
||||
|
||||
#include "ini.h"
|
||||
|
@ -33,6 +34,7 @@
|
|||
|
||||
#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
|
||||
|
@ -40,7 +42,7 @@
|
|||
#define MAX_SUBDOMAINS 10
|
||||
|
||||
struct gpass_parameters {
|
||||
unsigned pbkdf2_level;
|
||||
unsigned pbkdf2_level;
|
||||
char *server;
|
||||
char *salt;
|
||||
char *domain;
|
||||
|
@ -52,17 +54,49 @@ struct gpass_parameters {
|
|||
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)
|
||||
|
@ -112,10 +146,9 @@ static void hex_to_bin(unsigned char* bin, unsigned char* hex, long hex_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;
|
||||
|
||||
|
@ -133,10 +166,8 @@ static void encrypt_domain(struct gpass_parameters* params, char* domain,
|
|||
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);
|
||||
|
||||
|
@ -146,25 +177,66 @@ static void encrypt_domain(struct gpass_parameters* params, char* domain,
|
|||
free(tmp);
|
||||
}
|
||||
|
||||
static void append_to_request(char** request, char* new_req)
|
||||
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);
|
||||
|
||||
*out_size *= 2;
|
||||
|
||||
free(buffer);
|
||||
free(tmp);
|
||||
}
|
||||
|
||||
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++;
|
||||
|
@ -243,11 +315,10 @@ static int ask_server(struct gpass_parameters* params)
|
|||
{
|
||||
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];
|
||||
|
||||
|
@ -255,17 +326,32 @@ static int ask_server(struct gpass_parameters* params)
|
|||
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);
|
||||
|
||||
|
@ -331,13 +417,23 @@ static int ask_server(struct gpass_parameters* params)
|
|||
|
||||
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;
|
||||
|
@ -353,6 +449,12 @@ static int ask_server(struct gpass_parameters* params)
|
|||
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);
|
||||
|
@ -376,6 +478,7 @@ static void init_parameters(struct gpass_parameters* params)
|
|||
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)
|
||||
|
@ -387,6 +490,7 @@ 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)
|
||||
|
@ -556,6 +660,12 @@ int main(int argc, char** argv)
|
|||
}
|
||||
}
|
||||
|
||||
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: ");
|
||||
|
||||
|
@ -573,9 +683,12 @@ int main(int argc, char** argv)
|
|||
derive_master_key(¶ms);
|
||||
ask_server(¶ms);
|
||||
}
|
||||
|
||||
|
||||
end:
|
||||
release_parameters(¶ms);
|
||||
|
||||
if (s_md_ctx) EVP_MD_CTX_free(s_md_ctx);
|
||||
if (s_cipher_ctx) EVP_CIPHER_CTX_free(s_cipher_ctx);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user