diff options
Diffstat (limited to 'src/key_derivation.c')
-rw-r--r-- | src/key_derivation.c | 213 |
1 files changed, 148 insertions, 65 deletions
diff --git a/src/key_derivation.c b/src/key_derivation.c index 5e3f2c5..49fb2a2 100644 --- a/src/key_derivation.c +++ b/src/key_derivation.c @@ -38,29 +38,39 @@ #include "log.h" +#include <stdlib.h> #include <string.h> #include <gmp.h> -int key_derivation_init(key_derivation_t* kd, const char* type, u_int8_t* key, u_int32_t key_len, u_int8_t* salt, u_int32_t salt_len) +int key_derivation_init(key_derivation_t* kd, const char* type, int8_t ld_kdr, u_int8_t* key, u_int32_t key_len, u_int8_t* salt, u_int32_t salt_len) { if(!kd) return -1; - kd->type_ = unknown; + kd->type_ = kd_unknown; if(!strcmp(type, "null")) - kd->type_ = null; + kd->type_ = kd_null; else if(!strcmp(type, "aes-ctr")) - kd->type_ = aes_ctr; + kd->type_ = kd_aes_ctr; else { log_printf(ERR, "unknown key derivation type"); return -1; } - kd->ld_kdr_ = -1; + kd->ld_kdr_ = ld_kdr; + if(ld_kdr > (sizeof(seq_nr_t) * 8)) + kd->ld_kdr_ = sizeof(seq_nr_t) * 8; + kd->key_length_ = key_len * sizeof(key[0]) * 8; kd->handle_ = 0; + int i; + for(i = 0; i<KD_LABEL_COUNT; ++i) { + kd->key_store_[i].buf_ = NULL; + kd->key_store_[i].length_ = 0; + } + if(!key) { kd->master_key_.buf_ = NULL; kd->master_key_.length_ = 0; @@ -89,8 +99,11 @@ int key_derivation_init(key_derivation_t* kd, const char* type, u_int8_t* key, u } int ret = 0; - if(kd->type_ == aes_ctr) - ret = key_derivation_aesctr_init(kd, key, key_len, salt, salt_len); + if(kd->type_ == kd_aes_ctr) + ret = key_derivation_aesctr_init(kd, kd->key_length_); + + if(ret) + key_derivation_close(kd); return ret; } @@ -100,53 +113,78 @@ void key_derivation_close(key_derivation_t* kd) if(!kd) return; - if(kd->type_ == aes_ctr) + if(kd->type_ == kd_aes_ctr) key_derivation_aesctr_close(kd); if(kd->master_key_.buf_) free(kd->master_key_.buf_); if(kd->master_salt_.buf_) free(kd->master_salt_.buf_); + + int i; + for(i = 0; i<KD_LABEL_COUNT; ++i) { + if(kd->key_store_[i].buf_) + free(kd->key_store_[i].buf_); + } } -void key_derivation_generate(key_derivation_t* kd, satp_prf_label_t label, seq_nr_t seq_nr, u_int8_t* key, u_int32_t len) +int key_derivation_generate(key_derivation_t* kd, satp_prf_label_t label, seq_nr_t seq_nr, u_int8_t* key, u_int32_t len) { - if(!kd) - return; + if(!kd || !key) + return -1; + + if(label >= KD_LABEL_COUNT) { + log_printf(ERR, "label 0x%02X out of range", label); + return -1; + } - if(kd->type_ == null) - key_derivation_null_generate(key, len); - else if(kd->type_ == aes_ctr) - key_derivation_aesctr_generate(kd, label, seq_nr, key, len); + int ret = 0; + if(kd->type_ == kd_null) + ret = key_derivation_null_generate(key, len); + else if(kd->type_ == kd_aes_ctr) + ret = key_derivation_aesctr_generate(kd, label, seq_nr, key, len); else { - log_printf(ERR, "unknown cipher type"); - return; + log_printf(ERR, "unknown key derivation type"); + return -1; } + return ret; } /* ---------------- NULL Key Derivation ---------------- */ -void key_derivation_null_generate(u_int8_t* key, u_int32_t len) +int key_derivation_null_generate(u_int8_t* key, u_int32_t len) { memset(key, 0, len); + return 0; } /* ---------------- AES-Ctr Key Derivation ---------------- */ -int key_derivation_aesctr_init(key_derivation_t* kd, u_int8_t* key, u_int32_t key_len, u_int8_t* salt, u_int32_t salt_len) +int key_derivation_aesctr_init(key_derivation_t* kd, u_int16_t key_length) { if(!kd) return -1; - gcry_error_t err = gcry_cipher_open(&kd->handle_, GCRY_CIPHER_AES128, GCRY_CIPHER_MODE_CTR, 0); + int algo; + switch(key_length) { + case 128: algo = GCRY_CIPHER_AES128; break; + case 192: algo = GCRY_CIPHER_AES192; break; + case 256: algo = GCRY_CIPHER_AES256; break; + default: { + log_printf(ERR, "key length of %d Bits is not supported", key_length); + return -1; + } + } + + gcry_error_t err = gcry_cipher_open(&kd->handle_, algo, GCRY_CIPHER_MODE_CTR, 0); if(err) { - log_printf(ERR, "failed to open cipher: %s/%s", gcry_strerror(err), gcry_strsource(err)); + log_printf(ERR, "failed to open key derivation cipher: %s/%s", gcry_strerror(err), gcry_strsource(err)); return -1; } err = gcry_cipher_setkey(kd->handle_, kd->master_key_.buf_, kd->master_key_.length_); if(err) { - log_printf(ERR, "failed to set cipher key: %s/%s", gcry_strerror(err), gcry_strsource(err)); + log_printf(ERR, "failed to set key derivation key: %s/%s", gcry_strerror(err), gcry_strsource(err)); return -1; } @@ -162,27 +200,21 @@ void key_derivation_aesctr_close(key_derivation_t* kd) gcry_cipher_close(kd->handle_); } -buffer_t key_derivation_aesctr_calc_ctr(key_derivation_t* kd, satp_prf_label_t label, seq_nr_t seq_nr) +int key_derivation_aesctr_calc_ctr(key_derivation_t* kd, buffer_t* result, satp_prf_label_t label, seq_nr_t seq_nr) { - buffer_t result; - result.buf_ = NULL; - result.length_ = 0; - - if(!kd) - return result; + if(!kd || !result) + return -1; - // see at: http://tools.ietf.org/html/rfc3711#section-4.3 - // * Let r = index DIV key_derivation_rate (with DIV as defined above). - // * Let key_id = <label> || r. - // * Let x = key_id XOR master_salt, where key_id and master_salt are - // aligned so that their least significant bits agree (right- - // alignment). - // + result->buf_ = NULL; + result->length_ = 0; - mpz_t ctr, key_id, r; + mpz_t ctr, key_id, r, seq; mpz_init2(ctr, 128); mpz_init2(key_id, 128); mpz_init2(r, 128); + mpz_init2(seq, (sizeof(seq_nr_t) * 8)); + + mpz_set_ui(seq, seq_nr); int faked_msb = 0; if(!kd->master_salt_.buf_[0]) @@ -190,19 +222,31 @@ buffer_t key_derivation_aesctr_calc_ctr(key_derivation_t* kd, satp_prf_label_t l if(kd->ld_kdr_ == -1) mpz_set_ui(r, 0); - else { - mpz_t seq; - mpz_init2(seq, 32); - mpz_set_ui(seq, seq_nr); - - mpz_set_ui(r, 1); - mpz_mul_2exp(r, r, kd->ld_kdr_); - - mpz_fdiv_q(r, seq, r); - - mpz_clear(seq); + else + mpz_fdiv_q_2exp(r, seq, kd->ld_kdr_); + + if(kd->key_store_[label].buf_ && seq_nr) { + if(!mpz_cmp_ui(r, 0)) { + mpz_clear(seq); + mpz_clear(ctr); + mpz_clear(key_id); + mpz_clear(r); + return 0; + } + + mpz_t mod; + mpz_init2(mod, (sizeof(seq_nr) * 8)); + mpz_fdiv_r(mod, seq, r); + if(mpz_cmp_ui(mod, 0)) { + mpz_clear(seq); + mpz_clear(mod); + mpz_clear(ctr); + mpz_clear(key_id); + mpz_clear(r); + return 0; + } + mpz_clear(mod); } -/* TODO: generate key only if index % r == 0, except it is the first time */ mpz_set_ui(key_id, label); mpz_mul_2exp(key_id, key_id, 48); @@ -213,49 +257,88 @@ buffer_t key_derivation_aesctr_calc_ctr(key_derivation_t* kd, satp_prf_label_t l mpz_xor(ctr, ctr, key_id); mpz_mul_2exp(ctr, ctr, 16); - result.buf_ = mpz_export(NULL, (size_t*)&result.length_, 1, 1, 0, 0, ctr); + if(result->buf_) + free(result->buf_); + result->buf_ = mpz_export(NULL, (size_t*)&(result->length_), 1, 1, 0, 0, ctr); if(faked_msb) { kd->master_salt_.buf_[0] = 0; - result.buf_[0] = 0; + result->buf_[0] = 0; } + mpz_clear(seq); mpz_clear(ctr); mpz_clear(key_id); mpz_clear(r); - return result; + return 1; } -void key_derivation_aesctr_generate(key_derivation_t* kd, satp_prf_label_t label, seq_nr_t seq_nr, u_int8_t* key, u_int32_t len) +int key_derivation_aesctr_generate(key_derivation_t* kd, satp_prf_label_t label, seq_nr_t seq_nr, u_int8_t* key, u_int32_t len) { if(!kd || !kd->master_key_.buf_ || !kd->master_salt_.buf_) { - log_printf(ERR, "cipher not initialized or no key or salt set"); - return; + log_printf(ERR, "key derivation not initialized or no key or salt set"); + return -1; } gcry_error_t err = gcry_cipher_reset(kd->handle_); if(err) { - log_printf(ERR, "failed to reset cipher: %s/%s", gcry_strerror(err), gcry_strsource(err)); - return; + log_printf(ERR, "failed to reset key derivation cipher: %s/%s", gcry_strerror(err), gcry_strsource(err)); + return -1; } - buffer_t ctr = key_derivation_aesctr_calc_ctr(kd, label, seq_nr); - if(!ctr.buf_) { - log_printf(ERR, "failed to calculate cipher CTR"); - return; + buffer_t ctr; + ctr.buf_ = NULL; + ctr.length_ = 0; + int ret = key_derivation_aesctr_calc_ctr(kd, &ctr, label, seq_nr); + if(ret < 0) { + log_printf(ERR, "failed to calculate key derivation CTR"); + return -1; } + else if(!ret) { + if(len > kd->key_store_[label].length_) { + log_printf(WARNING, "stored (old) key for label 0x%02X is to short, filling with zeros", label); + memset(key, 0, len); + len = kd->key_store_[label].length_; + } + memcpy(key, kd->key_store_[label].buf_, len); + return 0; + } + err = gcry_cipher_setctr(kd->handle_, ctr.buf_, ctr.length_); free(ctr.buf_); if(err) { - log_printf(ERR, "failed to set cipher CTR: %s/%s", gcry_strerror(err), gcry_strsource(err)); - return; + log_printf(ERR, "failed to set key derivation CTR: %s/%s", gcry_strerror(err), gcry_strsource(err)); + return -1; } memset(key, 0, len); err = gcry_cipher_encrypt(kd->handle_, key, len, NULL, 0); if(err) { - log_printf(ERR, "failed to generate cipher bitstream: %s/%s", gcry_strerror(err), gcry_strsource(err)); - return; + log_printf(ERR, "failed to generate key derivation bitstream: %s/%s", gcry_strerror(err), gcry_strsource(err)); + return -1; + } + + if(!kd->key_store_[label].buf_) { + kd->key_store_[label].length_ = 0; + kd->key_store_[label].buf_ = malloc(len); + if(!kd->key_store_[label].buf_) { + log_printf(ERR, "memory error at key derivation"); + return -2; + } + kd->key_store_[label].length_ = len; } + else if(kd->key_store_[label].length_ < len) { + u_int8_t* tmp = realloc(kd->key_store_[label].buf_, len); + if(!tmp) { + log_printf(ERR, "memory error at key derivation"); + return -2; + } + kd->key_store_[label].buf_ = tmp; + kd->key_store_[label].length_ = len; + } + + memcpy(kd->key_store_[label].buf_, key, len); + + return 0; } |