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
163
cli/main.c
163
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.
|
This file is part of gPass.
|
||||||
|
|
||||||
|
@ -23,6 +23,7 @@
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#include <curl/curl.h>
|
#include <curl/curl.h>
|
||||||
|
#include <openssl/opensslv.h>
|
||||||
#include <openssl/evp.h>
|
#include <openssl/evp.h>
|
||||||
|
|
||||||
#include "ini.h"
|
#include "ini.h"
|
||||||
|
@ -33,6 +34,7 @@
|
||||||
|
|
||||||
#define DEFAULT_PBKDF2_LEVEL 1000
|
#define DEFAULT_PBKDF2_LEVEL 1000
|
||||||
#define MASTER_KEY_LENGTH (256/8)
|
#define MASTER_KEY_LENGTH (256/8)
|
||||||
|
#define GLOBAL_IV_LENGTH 16
|
||||||
#define BLOCK_SIZE (128/8)
|
#define BLOCK_SIZE (128/8)
|
||||||
#define DEFAULT_SERVER_PORT 443
|
#define DEFAULT_SERVER_PORT 443
|
||||||
#define SERVER_PROTOCOL 4
|
#define SERVER_PROTOCOL 4
|
||||||
|
@ -40,7 +42,7 @@
|
||||||
#define MAX_SUBDOMAINS 10
|
#define MAX_SUBDOMAINS 10
|
||||||
|
|
||||||
struct gpass_parameters {
|
struct gpass_parameters {
|
||||||
unsigned pbkdf2_level;
|
unsigned pbkdf2_level;
|
||||||
char *server;
|
char *server;
|
||||||
char *salt;
|
char *salt;
|
||||||
char *domain;
|
char *domain;
|
||||||
|
@ -52,17 +54,49 @@ struct gpass_parameters {
|
||||||
char *ca_path;
|
char *ca_path;
|
||||||
unsigned verify_ssl_peer;
|
unsigned verify_ssl_peer;
|
||||||
unsigned port_set;
|
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)
|
static void derive_master_key(struct gpass_parameters* params)
|
||||||
{
|
{
|
||||||
if (!params->derived_master_key)
|
if (!params->derived_master_key)
|
||||||
params->derived_master_key = malloc(MASTER_KEY_LENGTH);
|
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),
|
PKCS5_PBKDF2_HMAC(params->orig_master_key, strlen(params->orig_master_key),
|
||||||
(unsigned char*)params->salt, strlen(params->salt),
|
(unsigned char*)params->salt, strlen(params->salt),
|
||||||
params->pbkdf2_level, EVP_sha256(),
|
params->pbkdf2_level, EVP_sha256(),
|
||||||
MASTER_KEY_LENGTH, params->derived_master_key);
|
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 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)
|
unsigned char** res, unsigned* out_size)
|
||||||
{
|
{
|
||||||
EVP_CIPHER_CTX* evp_ctx;
|
|
||||||
unsigned size = 2+strlen(domain)+1+strlen(params->username);
|
unsigned size = 2+strlen(domain)+1+strlen(params->username);
|
||||||
unsigned char* buffer, *tmp;
|
unsigned char* buffer, *tmp;
|
||||||
|
|
||||||
|
@ -133,10 +166,8 @@ static void encrypt_domain(struct gpass_parameters* params, char* domain,
|
||||||
tmp = malloc(size);
|
tmp = malloc(size);
|
||||||
*res = malloc(size*2);
|
*res = malloc(size*2);
|
||||||
|
|
||||||
evp_ctx = EVP_CIPHER_CTX_new();
|
EVP_EncryptInit(s_cipher_ctx, EVP_aes_256_ecb(), params->derived_master_key, NULL);
|
||||||
EVP_EncryptInit(evp_ctx, EVP_aes_256_ecb(), params->derived_master_key, NULL);
|
EVP_CipherUpdate(s_cipher_ctx, tmp, (int*)out_size, buffer, size);
|
||||||
EVP_CipherUpdate(evp_ctx, tmp, (int*)out_size, buffer, size);
|
|
||||||
EVP_CIPHER_CTX_free(evp_ctx);
|
|
||||||
|
|
||||||
bin_to_hex(tmp, *res, size);
|
bin_to_hex(tmp, *res, size);
|
||||||
|
|
||||||
|
@ -146,25 +177,66 @@ static void encrypt_domain(struct gpass_parameters* params, char* domain,
|
||||||
free(tmp);
|
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;
|
static int cur_req_idx = 0;
|
||||||
int size_added;
|
int size_added;
|
||||||
|
|
||||||
if (!cur_req_idx)
|
if (!cur_req_idx)
|
||||||
{
|
{
|
||||||
*request = malloc(3+strlen(new_req)+1);
|
*request = malloc(3+new_req_size+1);
|
||||||
sprintf(*request, "k0=%s", new_req);
|
snprintf(*request, 3+new_req_size+1, "k0=%s", new_req);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
size_added = 4+strlen(new_req);
|
size_added = 4+new_req_size;
|
||||||
if (cur_req_idx >= 10)
|
if (cur_req_idx >= 10)
|
||||||
size_added++;
|
size_added++;
|
||||||
|
|
||||||
*request = realloc(*request, strlen(*request)+1+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++;
|
cur_req_idx++;
|
||||||
|
@ -243,11 +315,10 @@ static int ask_server(struct gpass_parameters* params)
|
||||||
{
|
{
|
||||||
char* wc_domain, *saveptr, *token, *cur_ptr;
|
char* wc_domain, *saveptr, *token, *cur_ptr;
|
||||||
unsigned char* enc_domain;
|
unsigned char* enc_domain;
|
||||||
unsigned enc_size;
|
unsigned enc_size, matched_key = 0, crypto_v1_index = 1;
|
||||||
char* request = NULL;
|
char* request = NULL;
|
||||||
int ret = -1, res;
|
int ret = -1, res, len;
|
||||||
CURL *curl;
|
CURL *curl;
|
||||||
EVP_CIPHER_CTX* evp_ctx;
|
|
||||||
char response[RESPONSE_SIZE];
|
char response[RESPONSE_SIZE];
|
||||||
unsigned char password[256];
|
unsigned char password[256];
|
||||||
|
|
||||||
|
@ -255,17 +326,32 @@ static int ask_server(struct gpass_parameters* params)
|
||||||
printf("Username: %s\n", params->username);
|
printf("Username: %s\n", params->username);
|
||||||
|
|
||||||
encrypt_domain(params, params->domain, &enc_domain, &enc_size);
|
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);
|
free(enc_domain);
|
||||||
|
|
||||||
wc_domain = wildcard_domain(params->domain);
|
wc_domain = wildcard_domain(params->domain);
|
||||||
if (wc_domain)
|
if (wc_domain)
|
||||||
{
|
{
|
||||||
|
crypto_v1_index++;
|
||||||
encrypt_domain(params, wc_domain, &enc_domain, &enc_size);
|
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);
|
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)
|
if (params->verbose)
|
||||||
printf("Request: %s\n", request);
|
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));
|
hex_to_bin(password, (unsigned char*)cur_ptr, strlen(cur_ptr));
|
||||||
|
|
||||||
evp_ctx = EVP_CIPHER_CTX_new();
|
if (matched_key >= crypto_v1_index)
|
||||||
EVP_DecryptInit(evp_ctx, EVP_aes_256_ecb(), params->derived_master_key, NULL);
|
{
|
||||||
EVP_CipherUpdate(evp_ctx, password, &res, password, strlen(cur_ptr)/2);
|
// Crypto v1
|
||||||
EVP_CIPHER_CTX_free(evp_ctx);
|
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
|
// Remove salt
|
||||||
password[strlen((char*)password)-3] = 0;
|
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);
|
printf("Password found: %s\n", password);
|
||||||
ret = 0;
|
ret = 0;
|
||||||
goto end;
|
goto end;
|
||||||
|
@ -353,6 +449,12 @@ static int ask_server(struct gpass_parameters* params)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if (!STRNCMP(token, "matched_key"))
|
||||||
|
{
|
||||||
|
cur_ptr += sizeof("matched_key"); // includes "="
|
||||||
|
|
||||||
|
matched_key = atoi(cur_ptr);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
fprintf(stderr, "Error: Unknown server response %s\n", token);
|
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->pbkdf2_level = DEFAULT_PBKDF2_LEVEL;
|
||||||
params->server_port = DEFAULT_SERVER_PORT;
|
params->server_port = DEFAULT_SERVER_PORT;
|
||||||
params->verify_ssl_peer = 1;
|
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)
|
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->orig_master_key) free(params->orig_master_key);
|
||||||
if (params->derived_master_key) free(params->derived_master_key);
|
if (params->derived_master_key) free(params->derived_master_key);
|
||||||
if( params->ca_path) free(params->ca_path);
|
if( params->ca_path) free(params->ca_path);
|
||||||
|
if (params->global_iv) free(params->global_iv);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int check_parameters(struct gpass_parameters* params)
|
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
|
// Let's go
|
||||||
tmp = getpass("Enter master key: ");
|
tmp = getpass("Enter master key: ");
|
||||||
|
|
||||||
|
@ -577,5 +687,8 @@ int main(int argc, char** argv)
|
||||||
end:
|
end:
|
||||||
release_parameters(¶ms);
|
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;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user